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