mirror of https://github.com/lukechilds/node.git
Ryan
16 years ago
17 changed files with 1759 additions and 496 deletions
@ -0,0 +1,137 @@ |
|||||
|
#! /bin/sh |
||||
|
|
||||
|
# waf configure wrapper |
||||
|
|
||||
|
# Fancy colors used to beautify the output a bit. |
||||
|
# |
||||
|
if [ "$NOCOLOR" ] ; then |
||||
|
NORMAL="" |
||||
|
BOLD="" |
||||
|
RED="" |
||||
|
YELLOW="" |
||||
|
GREEN="" |
||||
|
else |
||||
|
NORMAL='\\033[0m' |
||||
|
BOLD='\\033[01;1m' |
||||
|
RED='\\033[01;91m' |
||||
|
YELLOW='\\033[00;33m' |
||||
|
GREEN='\\033[01;92m' |
||||
|
fi |
||||
|
|
||||
|
EXIT_SUCCESS=0 |
||||
|
EXIT_FAILURE=1 |
||||
|
EXIT_ERROR=2 |
||||
|
EXIT_BUG=10 |
||||
|
|
||||
|
CUR_DIR=$PWD |
||||
|
|
||||
|
#possible relative path |
||||
|
WORKINGDIR=`dirname $0` |
||||
|
cd $WORKINGDIR |
||||
|
#abs path |
||||
|
WORKINGDIR=`pwd` |
||||
|
cd $CUR_DIR |
||||
|
|
||||
|
# Checks for WAF. Honours $WAF if set. Stores path to 'waf' in $WAF. |
||||
|
# Requires that $PYTHON is set. |
||||
|
# |
||||
|
checkWAF() |
||||
|
{ |
||||
|
printf "Checking for WAF\t\t\t: " |
||||
|
#installed miniwaf in sourcedir |
||||
|
if [ -z "$WAF" ] ; then |
||||
|
if [ -f "${WORKINGDIR}/waf" ] ; then |
||||
|
WAF="${WORKINGDIR}/waf" |
||||
|
if [ ! -x "$WAF" ] ; then |
||||
|
chmod +x $WAF |
||||
|
fi |
||||
|
fi |
||||
|
fi |
||||
|
if [ -z "$WAF" ] ; then |
||||
|
if [ -f "${WORKINGDIR}/waf-light" ] ; then |
||||
|
${WORKINGDIR}/waf-light --make-waf |
||||
|
WAF="${WORKINGDIR}/waf" |
||||
|
fi |
||||
|
fi |
||||
|
#global installed waf with waf->waf.py link |
||||
|
if [ -z "$WAF" ] ; then |
||||
|
WAF=`which waf 2>/dev/null` |
||||
|
fi |
||||
|
# neither waf nor miniwaf could be found |
||||
|
if [ ! -x "$WAF" ] ; then |
||||
|
printf $RED"not found"$NORMAL"\n" |
||||
|
echo "Go to http://code.google.com/p/waf/" |
||||
|
echo "and download a waf version" |
||||
|
exit $EXIT_FAILURE |
||||
|
else |
||||
|
printf $GREEN"$WAF"$NORMAL"\n" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Generates a Makefile. Requires that $WAF is set. |
||||
|
# |
||||
|
generateMakefile() |
||||
|
{ |
||||
|
cat > Makefile << EOF |
||||
|
#!/usr/bin/make -f |
||||
|
# Waf Makefile wrapper |
||||
|
WAF_HOME=$CUR_DIR |
||||
|
|
||||
|
all: |
||||
|
@$WAF build |
||||
|
|
||||
|
all-debug: |
||||
|
@$WAF -v build |
||||
|
|
||||
|
all-progress: |
||||
|
@$WAF -p build |
||||
|
|
||||
|
install: |
||||
|
if test -n "\$(DESTDIR)"; then \\ |
||||
|
$WAF install --yes --destdir="\$(DESTDIR)" --prefix="$PREFIX"; \\ |
||||
|
else \\ |
||||
|
$WAF install --yes --prefix="$PREFIX"; \\ |
||||
|
fi; |
||||
|
|
||||
|
uninstall: |
||||
|
@if test -n "\$(DESTDIR)"; then \\ |
||||
|
$WAF uninstall --destdir="\$(DESTDIR)" --prefix="$PREFIX"; \\ |
||||
|
else \\ |
||||
|
$WAF uninstall --prefix="$PREFIX"; \\ |
||||
|
fi; |
||||
|
|
||||
|
clean: |
||||
|
@$WAF clean |
||||
|
|
||||
|
distclean: |
||||
|
@$WAF distclean |
||||
|
@-rm -rf _build_ |
||||
|
@-rm -f Makefile |
||||
|
|
||||
|
check: |
||||
|
@$WAF check |
||||
|
|
||||
|
dist: |
||||
|
@$WAF dist |
||||
|
|
||||
|
.PHONY: clean dist distclean check uninstall install all |
||||
|
|
||||
|
EOF |
||||
|
} |
||||
|
|
||||
|
checkWAF |
||||
|
|
||||
|
PREFIX=/usr/local |
||||
|
case $1 in |
||||
|
--prefix) |
||||
|
PREFIX=$2 |
||||
|
;; |
||||
|
esac |
||||
|
|
||||
|
export PREFIX |
||||
|
generateMakefile |
||||
|
|
||||
|
|
||||
|
"${WAF}" configure --prefix "${PREFIX}" |
||||
|
|
||||
|
exit $? |
@ -0,0 +1,317 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
# |
||||
|
# Copyright 2006-2008 the V8 project authors. 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 Google 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. |
||||
|
|
||||
|
# This is a utility for converting JavaScript source code into C-style |
||||
|
# char arrays. It is used for embedded JavaScript code in the V8 |
||||
|
# library. |
||||
|
|
||||
|
import os, re, sys, string |
||||
|
import jsmin |
||||
|
|
||||
|
|
||||
|
def ToCArray(lines): |
||||
|
result = [] |
||||
|
for chr in lines: |
||||
|
value = ord(chr) |
||||
|
assert value < 128 |
||||
|
result.append(str(value)) |
||||
|
result.append("0") |
||||
|
return ", ".join(result) |
||||
|
|
||||
|
|
||||
|
def CompressScript(lines, do_jsmin): |
||||
|
# If we're not expecting this code to be user visible, we can run it through |
||||
|
# a more aggressive minifier. |
||||
|
if do_jsmin: |
||||
|
return jsmin.jsmin(lines) |
||||
|
|
||||
|
# Remove stuff from the source that we don't want to appear when |
||||
|
# people print the source code using Function.prototype.toString(). |
||||
|
# Note that we could easily compress the scripts mode but don't |
||||
|
# since we want it to remain readable. |
||||
|
#lines = re.sub('//.*\n', '\n', lines) # end-of-line comments |
||||
|
#lines = re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', lines) # comments. |
||||
|
#lines = re.sub('\s+\n+', '\n', lines) # trailing whitespace |
||||
|
return lines |
||||
|
|
||||
|
|
||||
|
def ReadFile(filename): |
||||
|
file = open(filename, "rt") |
||||
|
try: |
||||
|
lines = file.read() |
||||
|
finally: |
||||
|
file.close() |
||||
|
return lines |
||||
|
|
||||
|
|
||||
|
def ReadLines(filename): |
||||
|
result = [] |
||||
|
for line in open(filename, "rt"): |
||||
|
if '#' in line: |
||||
|
line = line[:line.index('#')] |
||||
|
line = line.strip() |
||||
|
if len(line) > 0: |
||||
|
result.append(line) |
||||
|
return result |
||||
|
|
||||
|
|
||||
|
def LoadConfigFrom(name): |
||||
|
import ConfigParser |
||||
|
config = ConfigParser.ConfigParser() |
||||
|
config.read(name) |
||||
|
return config |
||||
|
|
||||
|
|
||||
|
def ParseValue(string): |
||||
|
string = string.strip() |
||||
|
if string.startswith('[') and string.endswith(']'): |
||||
|
return string.lstrip('[').rstrip(']').split() |
||||
|
else: |
||||
|
return string |
||||
|
|
||||
|
|
||||
|
def ExpandConstants(lines, constants): |
||||
|
for key, value in constants.items(): |
||||
|
lines = lines.replace(key, str(value)) |
||||
|
return lines |
||||
|
|
||||
|
|
||||
|
def ExpandMacros(lines, macros): |
||||
|
for name, macro in macros.items(): |
||||
|
start = lines.find(name + '(', 0) |
||||
|
while start != -1: |
||||
|
# Scan over the arguments |
||||
|
assert lines[start + len(name)] == '(' |
||||
|
height = 1 |
||||
|
end = start + len(name) + 1 |
||||
|
last_match = end |
||||
|
arg_index = 0 |
||||
|
mapping = { } |
||||
|
def add_arg(str): |
||||
|
# Remember to expand recursively in the arguments |
||||
|
replacement = ExpandMacros(str.strip(), macros) |
||||
|
mapping[macro.args[arg_index]] = replacement |
||||
|
while end < len(lines) and height > 0: |
||||
|
# We don't count commas at higher nesting levels. |
||||
|
if lines[end] == ',' and height == 1: |
||||
|
add_arg(lines[last_match:end]) |
||||
|
last_match = end + 1 |
||||
|
elif lines[end] in ['(', '{', '[']: |
||||
|
height = height + 1 |
||||
|
elif lines[end] in [')', '}', ']']: |
||||
|
height = height - 1 |
||||
|
end = end + 1 |
||||
|
# Remember to add the last match. |
||||
|
add_arg(lines[last_match:end-1]) |
||||
|
result = macro.expand(mapping) |
||||
|
# Replace the occurrence of the macro with the expansion |
||||
|
lines = lines[:start] + result + lines[end:] |
||||
|
start = lines.find(name + '(', end) |
||||
|
return lines |
||||
|
|
||||
|
class TextMacro: |
||||
|
def __init__(self, args, body): |
||||
|
self.args = args |
||||
|
self.body = body |
||||
|
def expand(self, mapping): |
||||
|
result = self.body |
||||
|
for key, value in mapping.items(): |
||||
|
result = result.replace(key, value) |
||||
|
return result |
||||
|
|
||||
|
class PythonMacro: |
||||
|
def __init__(self, args, fun): |
||||
|
self.args = args |
||||
|
self.fun = fun |
||||
|
def expand(self, mapping): |
||||
|
args = [] |
||||
|
for arg in self.args: |
||||
|
args.append(mapping[arg]) |
||||
|
return str(self.fun(*args)) |
||||
|
|
||||
|
CONST_PATTERN = re.compile('^const\s+([a-zA-Z0-9_]+)\s*=\s*([^;]*);$') |
||||
|
MACRO_PATTERN = re.compile('^macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$') |
||||
|
PYTHON_MACRO_PATTERN = re.compile('^python\s+macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$') |
||||
|
|
||||
|
def ReadMacros(lines): |
||||
|
constants = { } |
||||
|
macros = { } |
||||
|
for line in lines: |
||||
|
hash = line.find('#') |
||||
|
if hash != -1: line = line[:hash] |
||||
|
line = line.strip() |
||||
|
if len(line) is 0: continue |
||||
|
const_match = CONST_PATTERN.match(line) |
||||
|
if const_match: |
||||
|
name = const_match.group(1) |
||||
|
value = const_match.group(2).strip() |
||||
|
constants[name] = value |
||||
|
else: |
||||
|
macro_match = MACRO_PATTERN.match(line) |
||||
|
if macro_match: |
||||
|
name = macro_match.group(1) |
||||
|
args = map(string.strip, macro_match.group(2).split(',')) |
||||
|
body = macro_match.group(3).strip() |
||||
|
macros[name] = TextMacro(args, body) |
||||
|
else: |
||||
|
python_match = PYTHON_MACRO_PATTERN.match(line) |
||||
|
if python_match: |
||||
|
name = python_match.group(1) |
||||
|
args = map(string.strip, python_match.group(2).split(',')) |
||||
|
body = python_match.group(3).strip() |
||||
|
fun = eval("lambda " + ",".join(args) + ': ' + body) |
||||
|
macros[name] = PythonMacro(args, fun) |
||||
|
else: |
||||
|
raise ("Illegal line: " + line) |
||||
|
return (constants, macros) |
||||
|
|
||||
|
|
||||
|
HEADER_TEMPLATE = """\ |
||||
|
#ifndef node_natives_h |
||||
|
#define node_natives_h |
||||
|
namespace node { |
||||
|
|
||||
|
%(source_lines)s\ |
||||
|
|
||||
|
} |
||||
|
#endif |
||||
|
""" |
||||
|
|
||||
|
|
||||
|
SOURCE_DECLARATION = """\ |
||||
|
static const char native_%(id)s[] = { %(data)s }; |
||||
|
""" |
||||
|
|
||||
|
|
||||
|
GET_DELAY_INDEX_CASE = """\ |
||||
|
if (strcmp(name, "%(id)s") == 0) return %(i)i; |
||||
|
""" |
||||
|
|
||||
|
|
||||
|
GET_DELAY_SCRIPT_SOURCE_CASE = """\ |
||||
|
if (index == %(i)i) return Vector<const char>(%(id)s, %(length)i); |
||||
|
""" |
||||
|
|
||||
|
|
||||
|
GET_DELAY_SCRIPT_NAME_CASE = """\ |
||||
|
if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i); |
||||
|
""" |
||||
|
|
||||
|
def JS2C(source, target): |
||||
|
ids = [] |
||||
|
delay_ids = [] |
||||
|
modules = [] |
||||
|
# Locate the macros file name. |
||||
|
consts = {} |
||||
|
macros = {} |
||||
|
for s in source: |
||||
|
if 'macros.py' == (os.path.split(str(s))[1]): |
||||
|
(consts, macros) = ReadMacros(ReadLines(str(s))) |
||||
|
else: |
||||
|
modules.append(s) |
||||
|
|
||||
|
# Build source code lines |
||||
|
source_lines = [ ] |
||||
|
source_lines_empty = [] |
||||
|
for s in modules: |
||||
|
delay = str(s).endswith('-delay.js') |
||||
|
lines = ReadFile(str(s)) |
||||
|
do_jsmin = lines.find('// jsminify this file, js2c: jsmin') != -1 |
||||
|
lines = ExpandConstants(lines, consts) |
||||
|
lines = ExpandMacros(lines, macros) |
||||
|
lines = CompressScript(lines, do_jsmin) |
||||
|
data = ToCArray(lines) |
||||
|
id = (os.path.split(str(s))[1])[:-3] |
||||
|
if delay: id = id[:-6] |
||||
|
if delay: |
||||
|
delay_ids.append((id, len(lines))) |
||||
|
else: |
||||
|
ids.append((id, len(lines))) |
||||
|
source_lines.append(SOURCE_DECLARATION % { 'id': id, 'data': data }) |
||||
|
source_lines_empty.append(SOURCE_DECLARATION % { 'id': id, 'data': 0 }) |
||||
|
|
||||
|
# Build delay support functions |
||||
|
get_index_cases = [ ] |
||||
|
get_script_source_cases = [ ] |
||||
|
get_script_name_cases = [ ] |
||||
|
|
||||
|
i = 0 |
||||
|
for (id, length) in delay_ids: |
||||
|
native_name = "native %s.js" % id |
||||
|
get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i }) |
||||
|
get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % { |
||||
|
'id': id, |
||||
|
'length': length, |
||||
|
'i': i |
||||
|
}) |
||||
|
get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % { |
||||
|
'name': native_name, |
||||
|
'length': len(native_name), |
||||
|
'i': i |
||||
|
}); |
||||
|
i = i + 1 |
||||
|
|
||||
|
for (id, length) in ids: |
||||
|
native_name = "native %s.js" % id |
||||
|
get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i }) |
||||
|
get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % { |
||||
|
'id': id, |
||||
|
'length': length, |
||||
|
'i': i |
||||
|
}) |
||||
|
get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % { |
||||
|
'name': native_name, |
||||
|
'length': len(native_name), |
||||
|
'i': i |
||||
|
}); |
||||
|
i = i + 1 |
||||
|
|
||||
|
# Emit result |
||||
|
output = open(str(target[0]), "w") |
||||
|
output.write(HEADER_TEMPLATE % { |
||||
|
'builtin_count': len(ids) + len(delay_ids), |
||||
|
'delay_count': len(delay_ids), |
||||
|
'source_lines': "\n".join(source_lines), |
||||
|
'get_index_cases': "".join(get_index_cases), |
||||
|
'get_script_source_cases': "".join(get_script_source_cases), |
||||
|
'get_script_name_cases': "".join(get_script_name_cases) |
||||
|
}) |
||||
|
output.close() |
||||
|
|
||||
|
if len(target) > 1: |
||||
|
output = open(str(target[1]), "w") |
||||
|
output.write(HEADER_TEMPLATE % { |
||||
|
'builtin_count': len(ids) + len(delay_ids), |
||||
|
'delay_count': len(delay_ids), |
||||
|
'source_lines': "\n".join(source_lines_empty), |
||||
|
'get_index_cases': "".join(get_index_cases), |
||||
|
'get_script_source_cases': "".join(get_script_source_cases), |
||||
|
'get_script_name_cases': "".join(get_script_name_cases) |
||||
|
}) |
||||
|
output.close() |
@ -0,0 +1,218 @@ |
|||||
|
#!/usr/bin/python |
||||
|
|
||||
|
# This code is original from jsmin by Douglas Crockford, it was translated to |
||||
|
# Python by Baruch Even. The original code had the following copyright and |
||||
|
# license. |
||||
|
# |
||||
|
# /* jsmin.c |
||||
|
# 2007-05-22 |
||||
|
# |
||||
|
# Copyright (c) 2002 Douglas Crockford (www.crockford.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 shall be used for Good, not Evil. |
||||
|
# |
||||
|
# 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. |
||||
|
# */ |
||||
|
|
||||
|
from StringIO import StringIO |
||||
|
|
||||
|
def jsmin(js): |
||||
|
ins = StringIO(js) |
||||
|
outs = StringIO() |
||||
|
JavascriptMinify().minify(ins, outs) |
||||
|
str = outs.getvalue() |
||||
|
if len(str) > 0 and str[0] == '\n': |
||||
|
str = str[1:] |
||||
|
return str |
||||
|
|
||||
|
def isAlphanum(c): |
||||
|
"""return true if the character is a letter, digit, underscore, |
||||
|
dollar sign, or non-ASCII character. |
||||
|
""" |
||||
|
return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or |
||||
|
(c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126)); |
||||
|
|
||||
|
class UnterminatedComment(Exception): |
||||
|
pass |
||||
|
|
||||
|
class UnterminatedStringLiteral(Exception): |
||||
|
pass |
||||
|
|
||||
|
class UnterminatedRegularExpression(Exception): |
||||
|
pass |
||||
|
|
||||
|
class JavascriptMinify(object): |
||||
|
|
||||
|
def _outA(self): |
||||
|
self.outstream.write(self.theA) |
||||
|
def _outB(self): |
||||
|
self.outstream.write(self.theB) |
||||
|
|
||||
|
def _get(self): |
||||
|
"""return the next character from stdin. Watch out for lookahead. If |
||||
|
the character is a control character, translate it to a space or |
||||
|
linefeed. |
||||
|
""" |
||||
|
c = self.theLookahead |
||||
|
self.theLookahead = None |
||||
|
if c == None: |
||||
|
c = self.instream.read(1) |
||||
|
if c >= ' ' or c == '\n': |
||||
|
return c |
||||
|
if c == '': # EOF |
||||
|
return '\000' |
||||
|
if c == '\r': |
||||
|
return '\n' |
||||
|
return ' ' |
||||
|
|
||||
|
def _peek(self): |
||||
|
self.theLookahead = self._get() |
||||
|
return self.theLookahead |
||||
|
|
||||
|
def _next(self): |
||||
|
"""get the next character, excluding comments. peek() is used to see |
||||
|
if an unescaped '/' is followed by a '/' or '*'. |
||||
|
""" |
||||
|
c = self._get() |
||||
|
if c == '/' and self.theA != '\\': |
||||
|
p = self._peek() |
||||
|
if p == '/': |
||||
|
c = self._get() |
||||
|
while c > '\n': |
||||
|
c = self._get() |
||||
|
return c |
||||
|
if p == '*': |
||||
|
c = self._get() |
||||
|
while 1: |
||||
|
c = self._get() |
||||
|
if c == '*': |
||||
|
if self._peek() == '/': |
||||
|
self._get() |
||||
|
return ' ' |
||||
|
if c == '\000': |
||||
|
raise UnterminatedComment() |
||||
|
|
||||
|
return c |
||||
|
|
||||
|
def _action(self, action): |
||||
|
"""do something! What you do is determined by the argument: |
||||
|
1 Output A. Copy B to A. Get the next B. |
||||
|
2 Copy B to A. Get the next B. (Delete A). |
||||
|
3 Get the next B. (Delete B). |
||||
|
action treats a string as a single character. Wow! |
||||
|
action recognizes a regular expression if it is preceded by ( or , or =. |
||||
|
""" |
||||
|
if action <= 1: |
||||
|
self._outA() |
||||
|
|
||||
|
if action <= 2: |
||||
|
self.theA = self.theB |
||||
|
if self.theA == "'" or self.theA == '"': |
||||
|
while 1: |
||||
|
self._outA() |
||||
|
self.theA = self._get() |
||||
|
if self.theA == self.theB: |
||||
|
break |
||||
|
if self.theA <= '\n': |
||||
|
raise UnterminatedStringLiteral() |
||||
|
if self.theA == '\\': |
||||
|
self._outA() |
||||
|
self.theA = self._get() |
||||
|
|
||||
|
|
||||
|
if action <= 3: |
||||
|
self.theB = self._next() |
||||
|
if self.theB == '/' and (self.theA == '(' or self.theA == ',' or |
||||
|
self.theA == '=' or self.theA == ':' or |
||||
|
self.theA == '[' or self.theA == '?' or |
||||
|
self.theA == '!' or self.theA == '&' or |
||||
|
self.theA == '|' or self.theA == ';' or |
||||
|
self.theA == '{' or self.theA == '}' or |
||||
|
self.theA == '\n'): |
||||
|
self._outA() |
||||
|
self._outB() |
||||
|
while 1: |
||||
|
self.theA = self._get() |
||||
|
if self.theA == '/': |
||||
|
break |
||||
|
elif self.theA == '\\': |
||||
|
self._outA() |
||||
|
self.theA = self._get() |
||||
|
elif self.theA <= '\n': |
||||
|
raise UnterminatedRegularExpression() |
||||
|
self._outA() |
||||
|
self.theB = self._next() |
||||
|
|
||||
|
|
||||
|
def _jsmin(self): |
||||
|
"""Copy the input to the output, deleting the characters which are |
||||
|
insignificant to JavaScript. Comments will be removed. Tabs will be |
||||
|
replaced with spaces. Carriage returns will be replaced with linefeeds. |
||||
|
Most spaces and linefeeds will be removed. |
||||
|
""" |
||||
|
self.theA = '\n' |
||||
|
self._action(3) |
||||
|
|
||||
|
while self.theA != '\000': |
||||
|
if self.theA == ' ': |
||||
|
if isAlphanum(self.theB): |
||||
|
self._action(1) |
||||
|
else: |
||||
|
self._action(2) |
||||
|
elif self.theA == '\n': |
||||
|
if self.theB in ['{', '[', '(', '+', '-']: |
||||
|
self._action(1) |
||||
|
elif self.theB == ' ': |
||||
|
self._action(3) |
||||
|
else: |
||||
|
if isAlphanum(self.theB): |
||||
|
self._action(1) |
||||
|
else: |
||||
|
self._action(2) |
||||
|
else: |
||||
|
if self.theB == ' ': |
||||
|
if isAlphanum(self.theA): |
||||
|
self._action(1) |
||||
|
else: |
||||
|
self._action(3) |
||||
|
elif self.theB == '\n': |
||||
|
if self.theA in ['}', ']', ')', '+', '-', '"', '\'']: |
||||
|
self._action(1) |
||||
|
else: |
||||
|
if isAlphanum(self.theA): |
||||
|
self._action(1) |
||||
|
else: |
||||
|
self._action(3) |
||||
|
else: |
||||
|
self._action(1) |
||||
|
|
||||
|
def minify(self, instream, outstream): |
||||
|
self.instream = instream |
||||
|
self.outstream = outstream |
||||
|
self.theA = '\n' |
||||
|
self.theB = None |
||||
|
self.theLookahead = None |
||||
|
|
||||
|
self._jsmin() |
||||
|
self.instream.close() |
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
import sys |
||||
|
jsm = JavascriptMinify() |
||||
|
jsm.minify(sys.stdin, sys.stdout) |
@ -0,0 +1,153 @@ |
|||||
|
#include "node.h" |
||||
|
#include <string.h> |
||||
|
|
||||
|
using namespace v8; |
||||
|
|
||||
|
class Callback { |
||||
|
public: |
||||
|
Callback(Handle<Value> v); |
||||
|
~Callback(); |
||||
|
Local<Value> Call(Handle<Object> recv, int argc, Handle<Value> argv[]); |
||||
|
private: |
||||
|
Persistent<Function> handle; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
Callback::Callback (Handle<Value> v) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
Handle<Function> f = Handle<Function>::Cast(v); |
||||
|
handle = Persistent<Function>::New(f); |
||||
|
} |
||||
|
|
||||
|
Callback::~Callback () |
||||
|
{ |
||||
|
handle.Dispose(); |
||||
|
handle.Clear(); // necessary?
|
||||
|
} |
||||
|
|
||||
|
Local<Value> |
||||
|
Callback::Call (Handle<Object> recv, int argc, Handle<Value> argv[]) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
Local<Value> r = handle->Call(recv, argc, argv); |
||||
|
return scope.Close(r); |
||||
|
} |
||||
|
|
||||
|
static int |
||||
|
after_rename (eio_req *req) |
||||
|
{ |
||||
|
Callback *callback = static_cast<Callback*>(req->data); |
||||
|
if (callback != NULL) { |
||||
|
HandleScope scope; |
||||
|
const int argc = 2; |
||||
|
Local<Value> argv[argc]; |
||||
|
|
||||
|
argv[0] = Integer::New(req->errorno); |
||||
|
argv[1] = String::New(strerror(req->errorno)); |
||||
|
|
||||
|
callback->Call(Context::GetCurrent()->Global(), argc, argv); |
||||
|
delete callback; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
JS_METHOD(rename) |
||||
|
{ |
||||
|
if (args.Length() < 2) |
||||
|
return Undefined(); |
||||
|
|
||||
|
HandleScope scope; |
||||
|
|
||||
|
String::Utf8Value path(args[0]->ToString()); |
||||
|
String::Utf8Value new_path(args[1]->ToString()); |
||||
|
|
||||
|
Callback *callback = NULL; |
||||
|
if (!args[2]->IsUndefined()) callback = new Callback(args[2]); |
||||
|
|
||||
|
eio_req *req = eio_rename(*path, *new_path, EIO_PRI_DEFAULT, after_rename, callback); |
||||
|
node_eio_submit(req); |
||||
|
|
||||
|
return Undefined(); |
||||
|
} |
||||
|
|
||||
|
static int |
||||
|
after_stat (eio_req *req) |
||||
|
{ |
||||
|
Callback *callback = static_cast<Callback*>(req->data); |
||||
|
if (callback != NULL) { |
||||
|
HandleScope scope; |
||||
|
const int argc = 3; |
||||
|
Local<Value> argv[argc]; |
||||
|
|
||||
|
Local<Object> stats = Object::New(); |
||||
|
argv[0] = stats; |
||||
|
argv[1] = Integer::New(req->errorno); |
||||
|
argv[2] = String::New(strerror(req->errorno)); |
||||
|
|
||||
|
if (req->result == 0) { |
||||
|
struct stat *s = static_cast<struct stat*>(req->ptr2); |
||||
|
|
||||
|
/* ID of device containing file */ |
||||
|
stats->Set(JS_SYMBOL("dev"), Integer::New(s->st_dev)); |
||||
|
/* inode number */ |
||||
|
stats->Set(JS_SYMBOL("ino"), Integer::New(s->st_ino)); |
||||
|
/* protection */ |
||||
|
stats->Set(JS_SYMBOL("mode"), Integer::New(s->st_mode)); |
||||
|
/* number of hard links */ |
||||
|
stats->Set(JS_SYMBOL("nlink"), Integer::New(s->st_nlink)); |
||||
|
/* user ID of owner */ |
||||
|
stats->Set(JS_SYMBOL("uid"), Integer::New(s->st_uid)); |
||||
|
/* group ID of owner */ |
||||
|
stats->Set(JS_SYMBOL("gid"), Integer::New(s->st_gid)); |
||||
|
/* device ID (if special file) */ |
||||
|
stats->Set(JS_SYMBOL("rdev"), Integer::New(s->st_rdev)); |
||||
|
/* total size, in bytes */ |
||||
|
stats->Set(JS_SYMBOL("size"), Integer::New(s->st_size)); |
||||
|
/* blocksize for filesystem I/O */ |
||||
|
stats->Set(JS_SYMBOL("blksize"), Integer::New(s->st_blksize)); |
||||
|
/* number of blocks allocated */ |
||||
|
stats->Set(JS_SYMBOL("blocks"), Integer::New(s->st_blocks)); |
||||
|
/* time of last access */ |
||||
|
stats->Set(JS_SYMBOL("atime"), Date::New(1000*static_cast<double>(s->st_atime))); |
||||
|
/* time of last modification */ |
||||
|
stats->Set(JS_SYMBOL("mtime"), Date::New(1000*static_cast<double>(s->st_mtime))); |
||||
|
/* time of last status change */ |
||||
|
stats->Set(JS_SYMBOL("ctime"), Date::New(1000*static_cast<double>(s->st_ctime))); |
||||
|
} |
||||
|
|
||||
|
callback->Call(Context::GetCurrent()->Global(), argc, argv); |
||||
|
delete callback; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
JS_METHOD(stat) |
||||
|
{ |
||||
|
if (args.Length() < 1) |
||||
|
return v8::Undefined(); |
||||
|
|
||||
|
HandleScope scope; |
||||
|
|
||||
|
String::Utf8Value path(args[0]->ToString()); |
||||
|
|
||||
|
Callback *callback = NULL; |
||||
|
if (!args[1]->IsUndefined()) callback = new Callback(args[1]); |
||||
|
|
||||
|
eio_req *req = eio_stat(*path, EIO_PRI_DEFAULT, after_stat, callback); |
||||
|
node_eio_submit(req); |
||||
|
|
||||
|
return Undefined(); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
NodeInit_file (Handle<Object> target) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
|
||||
|
Local<Object> fs = Object::New(); |
||||
|
target->Set(String::NewSymbol("fs"), fs); |
||||
|
|
||||
|
JS_SET_METHOD(fs, "rename", rename); |
||||
|
JS_SET_METHOD(fs, "stat", stat); |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
#ifndef node_file_h |
||||
|
#define node_file_h |
||||
|
|
||||
|
#include <v8.h> |
||||
|
|
||||
|
void NodeInit_file (v8::Handle<v8::Object> target); |
||||
|
|
||||
|
#endif |
@ -0,0 +1,85 @@ |
|||||
|
// module search paths
|
||||
|
node.includes = ["."]; |
||||
|
|
||||
|
node.path = new function () { |
||||
|
this.join = function () { |
||||
|
var joined = ""; |
||||
|
for (var i = 0; i < arguments.length; i++) { |
||||
|
var part = arguments[i].toString(); |
||||
|
if (i === 0) { |
||||
|
part = part.replace(/\/*$/, "/"); |
||||
|
} else if (i === arguments.length - 1) { |
||||
|
part = part.replace(/^\/*/, ""); |
||||
|
} else { |
||||
|
part = part.replace(/^\/*/, "") |
||||
|
.replace(/\/*$/, "/"); |
||||
|
} |
||||
|
joined += part; |
||||
|
} |
||||
|
return joined; |
||||
|
}; |
||||
|
|
||||
|
this.dirname = function (path) { |
||||
|
var parts = path.split("/"); |
||||
|
return parts.slice(0, parts.length-1); |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
function __include (module, path) { |
||||
|
var export = module.require(path); |
||||
|
for (var i in export) { |
||||
|
if (export.hasOwnProperty(i)) |
||||
|
module[i] = export[i]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
function __require (path, loading_file) { |
||||
|
|
||||
|
var filename = path; |
||||
|
// relative path
|
||||
|
// absolute path
|
||||
|
if (path.slice(0,1) === "/") { |
||||
|
} else { |
||||
|
filename = node.path.join(node.path.dirname(loading_file), path); |
||||
|
} |
||||
|
node.blocking.print("require: " + filename); |
||||
|
|
||||
|
/* |
||||
|
for (var i = 0; i < suffixes.length; i++) { |
||||
|
var f = filename + "." + suffixes[i]; |
||||
|
|
||||
|
var stats = node.blocking.stat(f); |
||||
|
for (var j in stats) { |
||||
|
node.blocking.print("stats." + j + " = " + stats[j].toString()); |
||||
|
} |
||||
|
} |
||||
|
*/ |
||||
|
|
||||
|
var source = node.blocking.cat(filename); |
||||
|
|
||||
|
// wrap the source in a function
|
||||
|
source = "function (__file__, __dir__) { " |
||||
|
+ " var exports = {};" |
||||
|
+ " function require (m) { return __require(m, __file__); }" |
||||
|
+ " function include (m) { return __include(this, m); }" |
||||
|
+ source |
||||
|
+ " return exports;" |
||||
|
+ "};" |
||||
|
; |
||||
|
var create_module = node.blocking.exec(source, filename); |
||||
|
|
||||
|
// execute the function wrap
|
||||
|
return create_module(filename, node.path.dirname(filename)); |
||||
|
} |
||||
|
|
||||
|
// main script execution.
|
||||
|
//__require(ARGV[1], ARGV[1]);
|
||||
|
//
|
||||
|
fs.stat("/tmp/world", function (stat, status, msg) { |
||||
|
for ( var i in stat ) { |
||||
|
node.blocking.print(i + ": " + stat[i]); |
||||
|
} |
||||
|
node.blocking.print("done: " + status.toString() + " " + msg.toString()); |
||||
|
}); |
@ -0,0 +1,425 @@ |
|||||
|
#include "net.h" |
||||
|
#include "node.h" |
||||
|
|
||||
|
#include <oi_socket.h> |
||||
|
#include <oi_buf.h> |
||||
|
|
||||
|
#include <assert.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <netdb.h> |
||||
|
#include <strings.h> |
||||
|
|
||||
|
using namespace v8; |
||||
|
|
||||
|
static Persistent<String> readyState_str; |
||||
|
|
||||
|
static Persistent<Integer> readyStateCONNECTING; |
||||
|
static Persistent<Integer> readyStateOPEN; |
||||
|
static Persistent<Integer> readyStateCLOSED; |
||||
|
|
||||
|
enum encoding {UTF8, RAW}; |
||||
|
|
||||
|
class Socket { |
||||
|
public: |
||||
|
Socket (Handle<Object> obj, double timeout); |
||||
|
~Socket (); |
||||
|
|
||||
|
int ConnectTCP (char *port, char *host); |
||||
|
void Write (Handle<Value> arg); |
||||
|
void Disconnect (); |
||||
|
|
||||
|
void SetEncoding (enum encoding); |
||||
|
void SetTimeout (double); |
||||
|
|
||||
|
void OnConnect (); |
||||
|
void OnRead (const void *buf, size_t count); |
||||
|
void OnDrain (); |
||||
|
void OnError (oi_error e); |
||||
|
void OnClose (); |
||||
|
|
||||
|
private: |
||||
|
oi_socket socket_; |
||||
|
struct addrinfo *address_; |
||||
|
Persistent<Object> js_object_; |
||||
|
}; |
||||
|
|
||||
|
static void |
||||
|
on_connect (oi_socket *socket) |
||||
|
{ |
||||
|
Socket *s = static_cast<Socket*> (socket->data); |
||||
|
s->OnConnect(); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
on_read (oi_socket *socket, const void *buf, size_t count) |
||||
|
{ |
||||
|
Socket *s = static_cast<Socket*> (socket->data); |
||||
|
s->OnRead(buf, count); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
on_drain (oi_socket *socket) |
||||
|
{ |
||||
|
Socket *s = static_cast<Socket*> (socket->data); |
||||
|
s->OnDrain(); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
on_error (oi_socket *socket, oi_error e) |
||||
|
{ |
||||
|
Socket *s = static_cast<Socket*> (socket->data); |
||||
|
s->OnError(e); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
on_timeout (oi_socket *socket) |
||||
|
{ |
||||
|
Socket *s = static_cast<Socket*> (socket->data); |
||||
|
s->OnTimeout(e); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
on_close (oi_socket *socket) |
||||
|
{ |
||||
|
Socket *s = static_cast<Socket*> (socket->data); |
||||
|
s->OnClose(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static Handle<Value> |
||||
|
NewSocket (const Arguments& args) |
||||
|
{ |
||||
|
if (args.Length() > 1) |
||||
|
return Undefined(); |
||||
|
|
||||
|
HandleScope scope; |
||||
|
|
||||
|
// Default options
|
||||
|
double timeout = 60.0; // in seconds
|
||||
|
enum {RAW, UTF8} encoding = RAW; |
||||
|
|
||||
|
// Set options from argument.
|
||||
|
if (args.Length() == 1 && args[0]->IsObject()) { |
||||
|
Local<Object> options = args[0]->ToObject(); |
||||
|
Local<Value> timeout_value = options->Get(String::NewSymbol("timeout")); |
||||
|
Local<Value> encoding_value = options->Get(String::NewSymbol("encoding")); |
||||
|
|
||||
|
if (timeout_value->IsNumber()) { |
||||
|
// timeout is specified in milliseconds like other time
|
||||
|
// values in javascript
|
||||
|
timeout = timeout_value->NumberValue() / 1000; |
||||
|
} |
||||
|
|
||||
|
if (encoding_value->IsString()) { |
||||
|
Local<String> encoding_string = encoding_value->ToString(); |
||||
|
char buf[5]; // need enough room for "utf8" or "raw"
|
||||
|
encoding_string->WriteAscii(buf, 0, 4); |
||||
|
buf[4] = '\0'; |
||||
|
if(strcasecmp(buf, "utf8") == 0) encoding = UTF8; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
Socket *s = new Socket(args.This(), timeout); |
||||
|
if(s == NULL) |
||||
|
return Undefined(); // XXX raise error?
|
||||
|
|
||||
|
return args.This(); |
||||
|
} |
||||
|
|
||||
|
static Socket* |
||||
|
Unwrapsocket (Handle<Object> obj) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0)); |
||||
|
Socket* socket = static_cast<Socket*>(field->Value()); |
||||
|
return socket; |
||||
|
} |
||||
|
|
||||
|
static Handle<Value> |
||||
|
SocketConnectTCPCallback (const Arguments& args) |
||||
|
{ |
||||
|
if (args.Length() < 1) |
||||
|
return Undefined(); |
||||
|
|
||||
|
HandleScope scope; |
||||
|
Socket *socket = Unwrapsocket(args.Holder()); |
||||
|
|
||||
|
String::AsciiValue port(args[0]); |
||||
|
|
||||
|
char *host = NULL; |
||||
|
String::AsciiValue host_v(args[1]->ToString()); |
||||
|
if(args[1]->IsString()) { |
||||
|
host = *host_v; |
||||
|
} |
||||
|
|
||||
|
int r = socket->ConnectTCP(*port, host); |
||||
|
// TODO raise error if r != 0
|
||||
|
|
||||
|
return Undefined(); |
||||
|
} |
||||
|
|
||||
|
static Handle<Value> |
||||
|
SocketWriteCallback (const Arguments& args) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
Socket *socket = Unwrapsocket(args.Holder()); |
||||
|
socket->Write(args[0]); |
||||
|
return Undefined(); |
||||
|
} |
||||
|
|
||||
|
static Handle<Value> |
||||
|
SocketCloseCallback (const Arguments& args) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
Socket *socket = Unwrapsocket(args.Holder()); |
||||
|
socket->Disconnect(); |
||||
|
return Undefined(); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
DestroySocket (Persistent<Value> _, void *data) |
||||
|
{ |
||||
|
Socket *s = static_cast<Socket*> (data); |
||||
|
delete s; |
||||
|
} |
||||
|
|
||||
|
Socket::Socket(Handle<Object> js_object, double timeout) |
||||
|
{ |
||||
|
oi_socket_init(&socket_, timeout); |
||||
|
socket_.on_connect = on_connect; |
||||
|
socket_.on_read = on_read; |
||||
|
socket_.on_drain = on_drain; |
||||
|
socket_.on_error = on_error; |
||||
|
socket_.on_close = on_close; |
||||
|
socket_.on_timeout = on_timeout; |
||||
|
socket_.data = this; |
||||
|
|
||||
|
HandleScope scope; |
||||
|
js_object_ = Persistent<Object>::New(js_object); |
||||
|
js_object_->SetInternalField (0, External::New(this)); |
||||
|
js_object_.MakeWeak (this, DestroySocket); |
||||
|
} |
||||
|
|
||||
|
Socket::~Socket () |
||||
|
{ |
||||
|
Disconnect(); |
||||
|
oi_socket_detach(&socket_); |
||||
|
js_object_.Dispose(); |
||||
|
js_object_.Clear(); // necessary?
|
||||
|
} |
||||
|
|
||||
|
static struct addrinfo tcp_hints = |
||||
|
/* ai_flags */ { AI_PASSIVE |
||||
|
/* ai_family */ , AF_UNSPEC |
||||
|
/* ai_socktype */ , SOCK_STREAM |
||||
|
/* ai_protocol */ , 0 |
||||
|
/* ai_addrlen */ , 0 |
||||
|
/* ai_addr */ , 0 |
||||
|
/* ai_canonname */ , 0 |
||||
|
/* ai_next */ , 0 |
||||
|
}; |
||||
|
|
||||
|
int |
||||
|
Socket::ConnectTCP(char *port, char *host) |
||||
|
{ |
||||
|
int r; |
||||
|
|
||||
|
HandleScope scope; |
||||
|
|
||||
|
js_object_->Set(readyState_str, readyStateCONNECTING); |
||||
|
|
||||
|
/* FIXME Blocking DNS resolution. */ |
||||
|
printf("resolving host: %s, port: %s\n", host, port); |
||||
|
r = getaddrinfo (host, port, &tcp_hints, &address); |
||||
|
if(r != 0) { |
||||
|
perror("getaddrinfo"); |
||||
|
return r; |
||||
|
} |
||||
|
|
||||
|
r = oi_socket_connect (&socket, address); |
||||
|
if(r != 0) { |
||||
|
perror("oi_socket_connect"); |
||||
|
return r; |
||||
|
} |
||||
|
oi_socket_attach (&socket, node_loop()); |
||||
|
|
||||
|
freeaddrinfo(address); |
||||
|
address = NULL; |
||||
|
} |
||||
|
|
||||
|
void Socket::Write (Handle<Value> arg) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
|
||||
|
if (arg == Null()) { |
||||
|
|
||||
|
oi_socket_write_eof(&socket); |
||||
|
|
||||
|
} else if (arg->IsString()) { |
||||
|
Local<String> s = arg->ToString(); |
||||
|
|
||||
|
size_t l1 = s->Utf8Length(), l2; |
||||
|
oi_buf *buf = oi_buf_new2(l1); |
||||
|
l2 = s->WriteUtf8(buf->base, l1); |
||||
|
assert(l1 == l2); |
||||
|
|
||||
|
oi_socket_write(&socket, buf); |
||||
|
|
||||
|
} else if (arg->IsArray()) { |
||||
|
size_t length = array->Length(); |
||||
|
Handle<Array> array = Handle<Array>::Cast(arg); |
||||
|
oi_buf *buf = oi_buf_new2(length); |
||||
|
for (int i = 0; i < length; i++) { |
||||
|
Local<Value> int_value = array->Get(Integer::New(i)); |
||||
|
buf[i] = int_value->Int32Value(); |
||||
|
} |
||||
|
|
||||
|
oi_socket_write(&socket, buf); |
||||
|
|
||||
|
} else { |
||||
|
// raise error bad argument.
|
||||
|
assert(0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
Socket::Disconnect() |
||||
|
{ |
||||
|
oi_socket_close(&socket); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
Socket::OnConnect() |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
|
||||
|
assert(READY_STATE_CONNECTING == ReadyState()); |
||||
|
js_object_->Set(readyState_str, readyStateOPEN); |
||||
|
|
||||
|
Handle<Value> on_connect_value = js_object_->Get( String::NewSymbol("on_connect") ); |
||||
|
if (!on_connect_value->IsFunction()) |
||||
|
return; |
||||
|
Handle<Function> on_connect = Handle<Function>::Cast(on_connect_value); |
||||
|
|
||||
|
TryCatch try_catch; |
||||
|
|
||||
|
Handle<Value> r = on_connect->Call(js_object_, 0, NULL); |
||||
|
|
||||
|
if(try_catch.HasCaught()) |
||||
|
node_fatal_exception(try_catch); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
Socket::OnRead (const void *buf, size_t count) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
|
||||
|
assert(READY_STATE_OPEN == ReadyState()); |
||||
|
|
||||
|
Handle<Value> onread_value = js_object_->Get( String::NewSymbol("on_read") ); |
||||
|
if (!onread_value->IsFunction()) return; |
||||
|
Handle<Function> onread = Handle<Function>::Cast(onread_value); |
||||
|
|
||||
|
const int argc = 1; |
||||
|
Handle<Value> argv[argc]; |
||||
|
|
||||
|
if(count) { |
||||
|
Handle<String> chunk = String::New((const char*)buf, count); // TODO binary data?
|
||||
|
argv[0] = chunk; |
||||
|
} else { |
||||
|
// TODO eof? delete write method?
|
||||
|
argv[0] = Null(); |
||||
|
} |
||||
|
|
||||
|
TryCatch try_catch; |
||||
|
|
||||
|
Handle<Value> r = onread->Call(js_object_, argc, argv); |
||||
|
|
||||
|
if(try_catch.HasCaught()) |
||||
|
node_fatal_exception(try_catch); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
Socket::OnClose () |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
|
||||
|
printf("onclose readyState %d\n", ReadyState()); |
||||
|
|
||||
|
assert(READY_STATE_OPEN == ReadyState()); |
||||
|
js_object_->Set(readyState_str, readyStateCLOSED); |
||||
|
|
||||
|
Handle<Value> onclose_value = js_object_->Get( String::NewSymbol("on_close") ); |
||||
|
if (!onclose_value->IsFunction()) return; |
||||
|
Handle<Function> onclose = Handle<Function>::Cast(onclose_value); |
||||
|
|
||||
|
TryCatch try_catch; |
||||
|
|
||||
|
Handle<Value> r = onclose->Call(js_object_, 0, NULL); |
||||
|
|
||||
|
if(try_catch.HasCaught()) |
||||
|
node_fatal_exception(try_catch); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
NodeInit_net (Handle<Object> target) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
|
||||
|
//
|
||||
|
// Socket
|
||||
|
//
|
||||
|
Local<FunctionTemplate> socket_template = FunctionTemplate::New(NewSocket); |
||||
|
target->Set(String::NewSymbol("Socket"), socket_template->GetFunction()); |
||||
|
socket_template->InstanceTemplate()->SetInternalFieldCount(1); |
||||
|
|
||||
|
// socket.connectTCP()
|
||||
|
Local<FunctionTemplate> socket_connect_tcp = |
||||
|
FunctionTemplate::New(SocketConnectTCPCallback); |
||||
|
socket_template->InstanceTemplate()->Set(String::NewSymbol("connectTCP"), |
||||
|
socket_connect_tcp->GetFunction()); |
||||
|
|
||||
|
// socket.connectUNIX()
|
||||
|
Local<FunctionTemplate> socket_connect_unix = |
||||
|
FunctionTemplate::New(SocketConnectUNIXCallback); |
||||
|
socket_template->InstanceTemplate()->Set(String::NewSymbol("connectUNIX"), |
||||
|
socket_connect_unix->GetFunction()); |
||||
|
|
||||
|
// socket.write()
|
||||
|
Local<FunctionTemplate> socket_write = |
||||
|
FunctionTemplate::New(SocketWriteCallback); |
||||
|
socket_template->InstanceTemplate()->Set(String::NewSymbol("write"), |
||||
|
socket_write->GetFunction()); |
||||
|
|
||||
|
// socket.close()
|
||||
|
Local<FunctionTemplate> socket_close = |
||||
|
FunctionTemplate::New(SocketCloseCallback); |
||||
|
socket_template->InstanceTemplate()->Set(String::NewSymbol("close"), |
||||
|
socket_close->GetFunction()); |
||||
|
|
||||
|
//
|
||||
|
// Server
|
||||
|
//
|
||||
|
Local<FunctionTemplate> server_template = FunctionTemplate::New(NewServer); |
||||
|
target->Set(String::NewSymbol("Server"), server_template->GetFunction()); |
||||
|
server_template->InstanceTemplate()->SetInternalFieldCount(1); |
||||
|
|
||||
|
// server.listenTCP()
|
||||
|
Local<FunctionTemplate> server_listenTCP = |
||||
|
FunctionTemplate::New(ServerListenTCPCallback); |
||||
|
server_template->InstanceTemplate()->Set(String::NewSymbol("listenTCP"), |
||||
|
server_listenTCP->GetFunction()); |
||||
|
|
||||
|
// server.listenUNIX()
|
||||
|
Local<FunctionTemplate> server_listenUNIX = |
||||
|
FunctionTemplate::New(ServerListenUNIXCallback); |
||||
|
server_template->InstanceTemplate()->Set(String::NewSymbol("listenUNIX"), |
||||
|
server_listenTCP->GetFunction()); |
||||
|
|
||||
|
// server.close()
|
||||
|
Local<FunctionTemplate> server_close = FunctionTemplate::New(ServerCloseCallback); |
||||
|
server_template->InstanceTemplate()->Set(String::NewSymbol("close"), |
||||
|
server_close->GetFunction()); |
||||
|
} |
||||
|
|
@ -0,0 +1,8 @@ |
|||||
|
#ifndef node_net_h |
||||
|
#define node_net_h |
||||
|
|
||||
|
#include <v8.h> |
||||
|
|
||||
|
void NodeInit_net (v8::Handle<v8::Object> target); |
||||
|
|
||||
|
#endif |
@ -1,341 +0,0 @@ |
|||||
#include "node_tcp.h" |
|
||||
#include "node.h" |
|
||||
|
|
||||
#include <oi_socket.h> |
|
||||
#include <oi_buf.h> |
|
||||
|
|
||||
#include <assert.h> |
|
||||
#include <sys/types.h> |
|
||||
#include <sys/socket.h> |
|
||||
#include <netdb.h> |
|
||||
|
|
||||
using namespace v8; |
|
||||
|
|
||||
static Persistent<String> readyState_str; |
|
||||
|
|
||||
static Persistent<Integer> readyState_CONNECTING; |
|
||||
static Persistent<Integer> readyState_OPEN; |
|
||||
static Persistent<Integer> readyState_CLOSED; |
|
||||
|
|
||||
enum readyState { READY_STATE_CONNECTING = 0 |
|
||||
, READY_STATE_OPEN = 1 |
|
||||
, READY_STATE_CLOSED = 2 |
|
||||
} ; |
|
||||
|
|
||||
class TCPClient { |
|
||||
public: |
|
||||
TCPClient(Handle<Object> obj); |
|
||||
~TCPClient(); |
|
||||
|
|
||||
int Connect(char *host, char *port); |
|
||||
void Write (Handle<Value> arg); |
|
||||
void Disconnect(); |
|
||||
|
|
||||
void OnOpen(); |
|
||||
void OnRead(const void *buf, size_t count); |
|
||||
void OnClose(); |
|
||||
|
|
||||
private: |
|
||||
int ReadyState(); |
|
||||
oi_socket socket; |
|
||||
struct addrinfo *address; |
|
||||
Persistent<Object> js_client; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
static void |
|
||||
on_connect (oi_socket *socket) |
|
||||
{ |
|
||||
TCPClient *client = static_cast<TCPClient*> (socket->data); |
|
||||
client->OnOpen(); |
|
||||
} |
|
||||
|
|
||||
static void |
|
||||
on_close (oi_socket *socket) |
|
||||
{ |
|
||||
TCPClient *client = static_cast<TCPClient*> (socket->data); |
|
||||
client->OnClose(); |
|
||||
} |
|
||||
|
|
||||
static void |
|
||||
on_read (oi_socket *socket, const void *buf, size_t count) |
|
||||
{ |
|
||||
TCPClient *client = static_cast<TCPClient*> (socket->data); |
|
||||
client->OnRead(buf, count); |
|
||||
} |
|
||||
|
|
||||
static struct addrinfo tcp_hints = |
|
||||
/* ai_flags */ { AI_PASSIVE |
|
||||
/* ai_family */ , AF_UNSPEC |
|
||||
/* ai_socktype */ , SOCK_STREAM |
|
||||
/* ai_protocol */ , 0 |
|
||||
/* ai_addrlen */ , 0 |
|
||||
/* ai_addr */ , 0 |
|
||||
/* ai_canonname */ , 0 |
|
||||
/* ai_next */ , 0 |
|
||||
}; |
|
||||
|
|
||||
static Handle<Value> newTCPClient |
|
||||
( const Arguments& args |
|
||||
) |
|
||||
{ |
|
||||
if (args.Length() < 1) |
|
||||
return Undefined(); |
|
||||
|
|
||||
HandleScope scope; |
|
||||
|
|
||||
char *host = NULL; |
|
||||
String::AsciiValue host_v(args[0]->ToString()); |
|
||||
if(args[0]->IsString()) { |
|
||||
host = *host_v; |
|
||||
} |
|
||||
String::AsciiValue port(args[1]); |
|
||||
|
|
||||
TCPClient *client = new TCPClient(args.This()); |
|
||||
if(client == NULL) |
|
||||
return Undefined(); // XXX raise error?
|
|
||||
|
|
||||
int r = client->Connect(host, *port); |
|
||||
if (r != 0) |
|
||||
return Undefined(); // XXX raise error?
|
|
||||
|
|
||||
|
|
||||
return args.This(); |
|
||||
} |
|
||||
|
|
||||
static TCPClient* |
|
||||
UnwrapClient (Handle<Object> obj) |
|
||||
{ |
|
||||
HandleScope scope; |
|
||||
Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0)); |
|
||||
TCPClient* client = static_cast<TCPClient*>(field->Value()); |
|
||||
return client; |
|
||||
} |
|
||||
|
|
||||
static Handle<Value> |
|
||||
WriteCallback (const Arguments& args) |
|
||||
{ |
|
||||
HandleScope scope; |
|
||||
TCPClient *client = UnwrapClient(args.Holder()); |
|
||||
client->Write(args[0]); |
|
||||
return Undefined(); |
|
||||
} |
|
||||
|
|
||||
static Handle<Value> |
|
||||
DisconnectCallback (const Arguments& args) |
|
||||
{ |
|
||||
HandleScope scope; |
|
||||
TCPClient *client = UnwrapClient(args.Holder()); |
|
||||
client->Disconnect(); |
|
||||
return Undefined(); |
|
||||
} |
|
||||
|
|
||||
static void |
|
||||
client_destroy (Persistent<Value> _, void *data) |
|
||||
{ |
|
||||
TCPClient *client = static_cast<TCPClient *> (data); |
|
||||
delete client; |
|
||||
} |
|
||||
|
|
||||
TCPClient::TCPClient(Handle<Object> _js_client) |
|
||||
{ |
|
||||
oi_socket_init(&socket, 300.0); // TODO adjustable timeout
|
|
||||
socket.on_connect = on_connect; |
|
||||
socket.on_read = on_read; |
|
||||
socket.on_drain = NULL; |
|
||||
socket.on_error = NULL; |
|
||||
socket.on_close = on_close; |
|
||||
socket.on_timeout = on_close; |
|
||||
socket.data = this; |
|
||||
|
|
||||
HandleScope scope; |
|
||||
js_client = Persistent<Object>::New(_js_client); |
|
||||
js_client->SetInternalField (0, External::New(this)); |
|
||||
js_client.MakeWeak (this, client_destroy); |
|
||||
} |
|
||||
|
|
||||
TCPClient::~TCPClient () |
|
||||
{ |
|
||||
Disconnect(); |
|
||||
oi_socket_detach (&socket); |
|
||||
js_client.Dispose(); |
|
||||
js_client.Clear(); // necessary?
|
|
||||
} |
|
||||
|
|
||||
int |
|
||||
TCPClient::Connect(char *host, char *port) |
|
||||
{ |
|
||||
int r; |
|
||||
|
|
||||
HandleScope scope; |
|
||||
|
|
||||
js_client->Set(readyState_str, readyState_CONNECTING); |
|
||||
|
|
||||
/* FIXME Blocking DNS resolution. Use oi_async. */ |
|
||||
printf("resolving host: %s, port: %s\n", host, port); |
|
||||
r = getaddrinfo (host, port, &tcp_hints, &address); |
|
||||
if(r != 0) { |
|
||||
perror("getaddrinfo"); |
|
||||
return r; |
|
||||
} |
|
||||
|
|
||||
r = oi_socket_connect (&socket, address); |
|
||||
if(r != 0) { |
|
||||
perror("oi_socket_connect"); |
|
||||
return r; |
|
||||
} |
|
||||
oi_socket_attach (&socket, node_loop()); |
|
||||
|
|
||||
freeaddrinfo(address); |
|
||||
address = NULL; |
|
||||
} |
|
||||
|
|
||||
void TCPClient::Write (Handle<Value> arg) |
|
||||
{ |
|
||||
HandleScope scope; |
|
||||
|
|
||||
//
|
|
||||
// TODO if ReadyState() is not READY_STATE_OPEN then raise INVALID_STATE_ERR
|
|
||||
//
|
|
||||
|
|
||||
if(arg == Null()) { |
|
||||
|
|
||||
oi_socket_write_eof(&socket); |
|
||||
|
|
||||
} else { |
|
||||
Local<String> s = arg->ToString(); |
|
||||
|
|
||||
size_t l1 = s->Utf8Length(), l2; |
|
||||
oi_buf *buf = oi_buf_new2(l1); |
|
||||
l2 = s->WriteUtf8(buf->base, l1); |
|
||||
assert(l1 == l2); |
|
||||
|
|
||||
oi_socket_write(&socket, buf); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
int |
|
||||
TCPClient::ReadyState() |
|
||||
{ |
|
||||
return js_client->Get(readyState_str)->IntegerValue(); |
|
||||
} |
|
||||
|
|
||||
void |
|
||||
TCPClient::Disconnect() |
|
||||
{ |
|
||||
oi_socket_close(&socket); |
|
||||
} |
|
||||
|
|
||||
void |
|
||||
TCPClient::OnOpen() |
|
||||
{ |
|
||||
HandleScope scope; |
|
||||
|
|
||||
assert(READY_STATE_CONNECTING == ReadyState()); |
|
||||
js_client->Set(readyState_str, readyState_OPEN); |
|
||||
|
|
||||
Handle<Value> onopen_value = js_client->Get( String::NewSymbol("onopen") ); |
|
||||
if (!onopen_value->IsFunction()) |
|
||||
return; |
|
||||
Handle<Function> onopen = Handle<Function>::Cast(onopen_value); |
|
||||
|
|
||||
TryCatch try_catch; |
|
||||
|
|
||||
Handle<Value> r = onopen->Call(js_client, 0, NULL); |
|
||||
|
|
||||
if(try_catch.HasCaught()) |
|
||||
node_fatal_exception(try_catch); |
|
||||
} |
|
||||
|
|
||||
void |
|
||||
TCPClient::OnRead(const void *buf, size_t count) |
|
||||
{ |
|
||||
HandleScope scope; |
|
||||
|
|
||||
assert(READY_STATE_OPEN == ReadyState()); |
|
||||
|
|
||||
Handle<Value> onread_value = js_client->Get( String::NewSymbol("onread") ); |
|
||||
if (!onread_value->IsFunction()) return; |
|
||||
Handle<Function> onread = Handle<Function>::Cast(onread_value); |
|
||||
|
|
||||
const int argc = 1; |
|
||||
Handle<Value> argv[argc]; |
|
||||
|
|
||||
if(count) { |
|
||||
Handle<String> chunk = String::New((const char*)buf, count); // TODO binary data?
|
|
||||
argv[0] = chunk; |
|
||||
} else { |
|
||||
// TODO eof? delete write method?
|
|
||||
argv[0] = Null(); |
|
||||
} |
|
||||
|
|
||||
TryCatch try_catch; |
|
||||
|
|
||||
Handle<Value> r = onread->Call(js_client, argc, argv); |
|
||||
|
|
||||
if(try_catch.HasCaught()) |
|
||||
node_fatal_exception(try_catch); |
|
||||
} |
|
||||
|
|
||||
void |
|
||||
TCPClient::OnClose() |
|
||||
{ |
|
||||
HandleScope scope; |
|
||||
|
|
||||
printf("onclose readyState %d\n", ReadyState()); |
|
||||
|
|
||||
assert(READY_STATE_OPEN == ReadyState()); |
|
||||
js_client->Set(readyState_str, readyState_CLOSED); |
|
||||
|
|
||||
Handle<Value> onclose_value = js_client->Get( String::NewSymbol("onclose") ); |
|
||||
if (!onclose_value->IsFunction()) return; |
|
||||
Handle<Function> onclose = Handle<Function>::Cast(onclose_value); |
|
||||
|
|
||||
TryCatch try_catch; |
|
||||
|
|
||||
Handle<Value> r = onclose->Call(js_client, 0, NULL); |
|
||||
|
|
||||
if(try_catch.HasCaught()) |
|
||||
node_fatal_exception(try_catch); |
|
||||
} |
|
||||
|
|
||||
void |
|
||||
Init_tcp (Handle<Object> target) |
|
||||
{ |
|
||||
HandleScope scope; |
|
||||
readyState_str = Persistent<String>::New(String::NewSymbol("readyState")); |
|
||||
|
|
||||
Local<FunctionTemplate> client_t = FunctionTemplate::New(newTCPClient); |
|
||||
|
|
||||
client_t->InstanceTemplate()->SetInternalFieldCount(1); |
|
||||
|
|
||||
/* readyState constants */ |
|
||||
|
|
||||
readyState_CONNECTING = Persistent<Integer>::New(Integer::New(READY_STATE_CONNECTING)); |
|
||||
client_t->Set ("CONNECTING", readyState_CONNECTING); |
|
||||
|
|
||||
readyState_OPEN = Persistent<Integer>::New(Integer::New(READY_STATE_OPEN)); |
|
||||
client_t->Set ("OPEN", readyState_OPEN); |
|
||||
|
|
||||
readyState_CLOSED = Persistent<Integer>::New(Integer::New(READY_STATE_CLOSED)); |
|
||||
client_t->Set ("CLOSED", readyState_CLOSED); |
|
||||
|
|
||||
/* write callback */ |
|
||||
|
|
||||
Local<FunctionTemplate> write_t = FunctionTemplate::New(WriteCallback); |
|
||||
|
|
||||
client_t->InstanceTemplate()->Set ( String::NewSymbol("write") |
|
||||
, write_t->GetFunction() |
|
||||
); |
|
||||
|
|
||||
/* disconnect callback */ |
|
||||
|
|
||||
Local<FunctionTemplate> disconnect_t = FunctionTemplate::New(DisconnectCallback); |
|
||||
|
|
||||
client_t->InstanceTemplate()->Set ( String::NewSymbol("disconnect") |
|
||||
, disconnect_t->GetFunction() |
|
||||
); |
|
||||
|
|
||||
target->Set(String::NewSymbol("TCPClient"), client_t->GetFunction()); |
|
||||
} |
|
||||
|
|
@ -1,8 +0,0 @@ |
|||||
#ifndef node_tcp_h |
|
||||
#define node_tcp_h |
|
||||
|
|
||||
#include <v8.h> |
|
||||
|
|
||||
void Init_tcp (v8::Handle<v8::Object> target); |
|
||||
|
|
||||
#endif |
|
@ -0,0 +1,39 @@ |
|||||
|
#include "process.h" |
||||
|
#include "node.h" |
||||
|
#include <v8.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
using namespace v8; |
||||
|
|
||||
|
static Handle<Value> |
||||
|
ExitCallback (const Arguments& args) |
||||
|
{ |
||||
|
int exit_code = 0; |
||||
|
if (args.Length() > 0) exit_code = args[0]->IntegerValue(); |
||||
|
exit(exit_code); |
||||
|
return Undefined(); |
||||
|
} |
||||
|
|
||||
|
static Handle<Value> |
||||
|
OnCallback (const Arguments& args) |
||||
|
{ |
||||
|
return Undefined(); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
NodeInit_process (Handle<Object> target) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
|
||||
|
Local<Object> process = ObjectTemplate::New()->NewInstance(); |
||||
|
|
||||
|
target->Set(String::NewSymbol("process"), process); |
||||
|
|
||||
|
// process.exit()
|
||||
|
Local<FunctionTemplate> process_exit = FunctionTemplate::New(ExitCallback); |
||||
|
process->Set(String::NewSymbol("exit"), process_exit->GetFunction()); |
||||
|
|
||||
|
// process.on()
|
||||
|
Local<FunctionTemplate> process_on = FunctionTemplate::New(OnCallback); |
||||
|
process->Set(String::NewSymbol("on"), process_exit->GetFunction()); |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
#ifndef node_process_h |
||||
|
#define node_process_h |
||||
|
|
||||
|
#include <v8.h> |
||||
|
|
||||
|
void NodeInit_process (v8::Handle<v8::Object> target); |
||||
|
|
||||
|
#endif |
@ -0,0 +1,165 @@ |
|||||
|
// Copyright 2008 the V8 project authors. 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 Google 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.
|
||||
|
//
|
||||
|
//
|
||||
|
|
||||
|
/*jslint |
||||
|
evil: true |
||||
|
*/ |
||||
|
|
||||
|
function MjsUnitAssertionError(message) { |
||||
|
this.message = message; |
||||
|
} |
||||
|
|
||||
|
MjsUnitAssertionError.prototype.toString = function () { |
||||
|
return this.message; |
||||
|
}; |
||||
|
|
||||
|
/* |
||||
|
* This file is included in all mini jsunit test cases. The test |
||||
|
* framework expects lines that signal failed tests to start with |
||||
|
* the f-word and ignore all other lines. |
||||
|
*/ |
||||
|
|
||||
|
function fail (expected, found, name_opt) { |
||||
|
var start; |
||||
|
if (name_opt) { |
||||
|
// Fix this when we ditch the old test runner.
|
||||
|
start = "Fail" + "ure (" + name_opt + "): "; |
||||
|
} else { |
||||
|
start = "Fail" + "ure:"; |
||||
|
} |
||||
|
throw new MjsUnitAssertionError(start + " expected <" + expected + "> found <" + found + ">"); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
function deepEquals (a, b) { |
||||
|
if (a == b) { |
||||
|
return true; |
||||
|
} |
||||
|
if ((typeof a) !== 'object' || (typeof b) !== 'object' || |
||||
|
(a === null) || (b === null)) { |
||||
|
return false; |
||||
|
} |
||||
|
if (a.constructor === Array) { |
||||
|
if (b.constructor !== Array) { |
||||
|
return false; |
||||
|
} |
||||
|
if (a.length != b.length) { |
||||
|
return false; |
||||
|
} |
||||
|
for (var i = 0; i < a.length; i++) { |
||||
|
if (i in a) { |
||||
|
if (!(i in b) || !(deepEquals(a[i], b[i]))) { |
||||
|
return false; |
||||
|
} |
||||
|
} else if (i in b) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
exports.assertEquals = function (expected, found, name_opt) { |
||||
|
if (!deepEquals(found, expected)) { |
||||
|
fail(expected, found, name_opt); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
exports.assertArrayEquals = function (expected, found, name_opt) { |
||||
|
var start = ""; |
||||
|
if (name_opt) { |
||||
|
start = name_opt + " - "; |
||||
|
} |
||||
|
exports.assertEquals(expected.length, found.length, start + "array length"); |
||||
|
if (expected.length == found.length) { |
||||
|
for (var i = 0; i < expected.length; ++i) { |
||||
|
exports.assertEquals(expected[i], found[i], start + "array element at index " + i); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
exports.assertTrue = function (value, name_opt) { |
||||
|
exports.assertEquals(true, value, name_opt); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
exports.assertFalse = function (value, name_opt) { |
||||
|
exports.assertEquals(false, value, name_opt); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
exports.assertNaN = function (value, name_opt) { |
||||
|
if (!isNaN(value)) { |
||||
|
fail("NaN", value, name_opt); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
exports.assertThrows = function (code) { |
||||
|
var threwException = true; |
||||
|
try { |
||||
|
eval(code); |
||||
|
threwException = false; |
||||
|
} catch (e) { |
||||
|
// Do nothing.
|
||||
|
} |
||||
|
if (!threwException) { |
||||
|
exports.assertTrue(false, "did not throw exception"); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
exports.assertInstanceof = function (obj, type) { |
||||
|
if (!(obj instanceof type)) { |
||||
|
exports.assertTrue(false, "Object <" + obj + "> is not an instance of <" + type + ">"); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
exports.assertDoesNotThrow = function (code) { |
||||
|
try { |
||||
|
eval(code); |
||||
|
} catch (e) { |
||||
|
exports.assertTrue(false, "threw an exception"); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
exports.assertUnreachable = function (name_opt) { |
||||
|
// Fix this when we ditch the old test runner.
|
||||
|
var message = "Fail" + "ure: unreachable"; |
||||
|
if (name_opt) { |
||||
|
message += " - " + name_opt; |
||||
|
} |
||||
|
throw new MjsUnitAssertionError(message); |
||||
|
}; |
@ -0,0 +1,12 @@ |
|||||
|
node.blocking.print(__file__); |
||||
|
/* |
||||
|
if (node.path.dirname(__file__) !== "test-test.js") { |
||||
|
throw "wrong __file__ argument"; |
||||
|
} |
||||
|
*/ |
||||
|
|
||||
|
var mjsunit = require("./mjsunit.js"); |
||||
|
node.blocking.print(__file__); |
||||
|
|
||||
|
mjsunit.assertFalse(false, "testing the test program."); |
||||
|
//mjsunit.assertEquals("test-test.js", __file__);
|
Loading…
Reference in new issue