mirror of
https://github.com/nodejs/node.git
synced 2025-12-28 07:50:41 +00:00
everything is changed. i've waited much too long to commit.
this is awful. i'm sorry for being so messy.
This commit is contained in:
parent
0e9e927fcb
commit
63a9cd3897
137
configure
vendored
Executable file
137
configure
vendored
Executable file
@ -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 $?
|
||||
317
js2c.py
Executable file
317
js2c.py
Executable file
@ -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()
|
||||
218
jsmin.py
Normal file
218
jsmin.py
Normal file
@ -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)
|
||||
153
src/file.cc
Normal file
153
src/file.cc
Normal file
@ -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);
|
||||
}
|
||||
8
src/file.h
Normal file
8
src/file.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef node_file_h
|
||||
#define node_file_h
|
||||
|
||||
#include <v8.h>
|
||||
|
||||
void NodeInit_file (v8::Handle<v8::Object> target);
|
||||
|
||||
#endif
|
||||
85
src/main.js
Normal file
85
src/main.js
Normal file
@ -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());
|
||||
});
|
||||
425
src/net.cc
Normal file
425
src/net.cc
Normal file
@ -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());
|
||||
}
|
||||
|
||||
8
src/net.h
Normal file
8
src/net.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef node_net_h
|
||||
#define node_net_h
|
||||
|
||||
#include <v8.h>
|
||||
|
||||
void NodeInit_net (v8::Handle<v8::Object> target);
|
||||
|
||||
#endif
|
||||
304
src/node.cc
304
src/node.cc
@ -1,9 +1,13 @@
|
||||
#include "node.h"
|
||||
|
||||
#include "node_tcp.h"
|
||||
//#include "net.h"
|
||||
#include "file.h"
|
||||
#include "process.h"
|
||||
#include "node_http.h"
|
||||
#include "node_timer.h"
|
||||
|
||||
#include "natives.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
@ -12,85 +16,21 @@
|
||||
#include <map>
|
||||
|
||||
using namespace v8;
|
||||
using namespace node;
|
||||
using namespace std;
|
||||
|
||||
static int exit_code = 0;
|
||||
|
||||
// Reads a file into a v8 string.
|
||||
static Handle<String>
|
||||
ReadFile (const string& name)
|
||||
{
|
||||
|
||||
FILE* file = fopen(name.c_str(), "rb");
|
||||
if (file == NULL) return Handle<String>();
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
int size = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
char chars[size+1];
|
||||
chars[size] = '\0';
|
||||
for (int i = 0; i < size;) {
|
||||
int read = fread(&chars[i], 1, size - i, file);
|
||||
if(read <= 0) {
|
||||
perror("read()");
|
||||
}
|
||||
i += read;
|
||||
}
|
||||
|
||||
uint16_t expanded_base[size+1];
|
||||
expanded_base[size] = '\0';
|
||||
for(int i = 0; i < size; i++)
|
||||
expanded_base[i] = chars[i];
|
||||
|
||||
fclose(file);
|
||||
|
||||
HandleScope scope;
|
||||
Local<String> result = String::New(expanded_base, size);
|
||||
|
||||
return scope.Close(result);
|
||||
}
|
||||
|
||||
static Handle<Value>
|
||||
Log (const Arguments& args)
|
||||
{
|
||||
if (args.Length() < 1) return v8::Undefined();
|
||||
HandleScope scope;
|
||||
Handle<Value> arg = args[0];
|
||||
String::Utf8Value value(arg);
|
||||
|
||||
printf("%s\n", *value);
|
||||
fflush(stdout);
|
||||
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
|
||||
static Handle<Value>
|
||||
BlockingFileRead (const Arguments& args)
|
||||
{
|
||||
if (args.Length() < 1) return v8::Undefined();
|
||||
HandleScope scope;
|
||||
|
||||
String::Utf8Value filename(args[0]);
|
||||
Handle<String> output = ReadFile (*filename);
|
||||
return scope.Close(output);
|
||||
}
|
||||
|
||||
static void
|
||||
OnFatalError (const char* location, const char* message)
|
||||
{
|
||||
fprintf(stderr, "Fatal error. %s %s\n", location, message);
|
||||
ev_unloop(node_loop(), EVUNLOOP_ALL);
|
||||
}
|
||||
|
||||
|
||||
// Extracts a C string from a V8 Utf8Value.
|
||||
const char* ToCString(const v8::String::Utf8Value& value) {
|
||||
const char*
|
||||
ToCString(const v8::String::Utf8Value& value)
|
||||
{
|
||||
return *value ? *value : "<string conversion failed>";
|
||||
}
|
||||
|
||||
void ReportException(v8::TryCatch* try_catch) {
|
||||
void
|
||||
ReportException(v8::TryCatch* try_catch)
|
||||
{
|
||||
v8::HandleScope handle_scope;
|
||||
v8::String::Utf8Value exception(try_catch->Exception());
|
||||
const char* exception_string = ToCString(exception);
|
||||
@ -124,6 +64,115 @@ void ReportException(v8::TryCatch* try_catch) {
|
||||
}
|
||||
}
|
||||
|
||||
// Executes a string within the current v8 context.
|
||||
Handle<Value>
|
||||
ExecuteString(v8::Handle<v8::String> source,
|
||||
v8::Handle<v8::Value> filename)
|
||||
{
|
||||
HandleScope scope;
|
||||
Handle<Script> script = Script::Compile(source, filename);
|
||||
if (script.IsEmpty()) {
|
||||
return ThrowException(String::New("Error compiling string"));
|
||||
}
|
||||
|
||||
Handle<Value> result = script->Run();
|
||||
if (result.IsEmpty()) {
|
||||
return ThrowException(String::New("Error running string"));
|
||||
}
|
||||
|
||||
return scope.Close(result);
|
||||
}
|
||||
|
||||
JS_METHOD(print)
|
||||
{
|
||||
if (args.Length() < 1) return v8::Undefined();
|
||||
HandleScope scope;
|
||||
Handle<Value> arg = args[0];
|
||||
String::Utf8Value value(arg);
|
||||
|
||||
printf("%s\n", *value);
|
||||
fflush(stdout);
|
||||
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
|
||||
JS_METHOD(cat)
|
||||
{
|
||||
if (args.Length() < 1) return v8::Undefined();
|
||||
HandleScope scope;
|
||||
|
||||
String::Utf8Value filename(args[0]);
|
||||
|
||||
Local<String> error_msg = String::New("File I/O error");
|
||||
|
||||
FILE* file = fopen(*filename, "rb");
|
||||
if (file == NULL) {
|
||||
// Raise error
|
||||
perror("fopen()");
|
||||
return ThrowException(error_msg);
|
||||
}
|
||||
|
||||
int r = fseek(file, 0, SEEK_END);
|
||||
if (r < 0) {
|
||||
perror("fseek()");
|
||||
return ThrowException(error_msg);
|
||||
}
|
||||
|
||||
int size = ftell(file);
|
||||
if (size < 0) {
|
||||
perror("ftell()");
|
||||
return ThrowException(error_msg);
|
||||
}
|
||||
rewind(file);
|
||||
|
||||
char chars[size+1];
|
||||
chars[size] = '\0';
|
||||
for (int i = 0; i < size;) {
|
||||
int read = fread(&chars[i], 1, size - i, file);
|
||||
if(read <= 0) {
|
||||
perror("read()");
|
||||
return ThrowException(error_msg);
|
||||
}
|
||||
i += read;
|
||||
}
|
||||
|
||||
uint16_t expanded_base[size+1];
|
||||
expanded_base[size] = '\0';
|
||||
for(int i = 0; i < size; i++)
|
||||
expanded_base[i] = chars[i];
|
||||
|
||||
fclose(file);
|
||||
|
||||
Local<String> contents = String::New(expanded_base, size);
|
||||
|
||||
return scope.Close(contents);
|
||||
}
|
||||
|
||||
JS_METHOD(exec)
|
||||
{
|
||||
if (args.Length() < 2)
|
||||
return Undefined();
|
||||
|
||||
HandleScope scope;
|
||||
|
||||
Local<String> source = args[0]->ToString();
|
||||
Local<String> filename = args[1]->ToString();
|
||||
|
||||
Handle<Value> result = ExecuteString(source, filename);
|
||||
|
||||
return scope.Close(result);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
OnFatalError (const char* location, const char* message)
|
||||
{
|
||||
fprintf(stderr, "Fatal error. %s %s\n", location, message);
|
||||
ev_unloop(node_loop(), EVUNLOOP_ALL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
node_fatal_exception (TryCatch &try_catch)
|
||||
{
|
||||
@ -132,60 +181,12 @@ node_fatal_exception (TryCatch &try_catch)
|
||||
exit_code = 1;
|
||||
}
|
||||
|
||||
|
||||
// Executes a string within the current v8 context.
|
||||
bool ExecuteString(v8::Handle<v8::String> source,
|
||||
v8::Handle<v8::Value> name,
|
||||
bool print_result,
|
||||
bool report_exceptions) {
|
||||
v8::HandleScope handle_scope;
|
||||
v8::TryCatch try_catch;
|
||||
v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
|
||||
if (script.IsEmpty()) {
|
||||
// Print errors that happened during compilation.
|
||||
if (report_exceptions)
|
||||
ReportException(&try_catch);
|
||||
return false;
|
||||
} else {
|
||||
v8::Handle<v8::Value> result = script->Run();
|
||||
if (result.IsEmpty()) {
|
||||
// Print errors that happened during execution.
|
||||
if (report_exceptions)
|
||||
ReportException(&try_catch);
|
||||
return false;
|
||||
} else {
|
||||
if (print_result && !result->IsUndefined()) {
|
||||
// If all went well and the result wasn't undefined then print
|
||||
// the returned value.
|
||||
v8::String::Utf8Value str(result);
|
||||
const char* cstr = ToCString(str);
|
||||
printf("%s\n", cstr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
void node_exit (int code)
|
||||
{
|
||||
exit_code = code;
|
||||
ev_unloop(node_loop(), EVUNLOOP_ALL);
|
||||
}
|
||||
|
||||
// The callback that is invoked by v8 whenever the JavaScript 'load'
|
||||
// function is called. Loads, compiles and executes its argument
|
||||
// JavaScript file.
|
||||
v8::Handle<v8::Value> Load(const v8::Arguments& args) {
|
||||
for (int i = 0; i < args.Length(); i++) {
|
||||
v8::HandleScope handle_scope;
|
||||
v8::String::Utf8Value file(args[i]);
|
||||
if (*file == NULL) {
|
||||
return v8::ThrowException(v8::String::New("Error loading file"));
|
||||
}
|
||||
v8::Handle<v8::String> source = ReadFile(*file);
|
||||
if (source.IsEmpty()) {
|
||||
return v8::ThrowException(v8::String::New("Error loading file"));
|
||||
}
|
||||
if (!ExecuteString(source, v8::String::New(*file), false, true)) {
|
||||
return v8::ThrowException(v8::String::New("Error executing file"));
|
||||
}
|
||||
}
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
static ev_async thread_pool_watcher;
|
||||
|
||||
@ -212,49 +213,59 @@ node_eio_submit(eio_req *req)
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
// start eio thread pool
|
||||
ev_async_init(&thread_pool_watcher, thread_pool_cb);
|
||||
eio_init(thread_pool_want_poll, NULL);
|
||||
|
||||
V8::SetFlagsFromCommandLine(&argc, argv, true);
|
||||
|
||||
if(argc != 2) {
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "No script was specified.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
string filename(argv[1]);
|
||||
|
||||
HandleScope handle_scope;
|
||||
|
||||
Persistent<Context> context = Context::New(NULL, ObjectTemplate::New());
|
||||
Context::Scope context_scope(context);
|
||||
V8::SetFatalErrorHandler(OnFatalError);
|
||||
|
||||
Local<Object> g = Context::GetCurrent()->Global();
|
||||
|
||||
g->Set ( String::New("log")
|
||||
, FunctionTemplate::New(Log)->GetFunction()
|
||||
);
|
||||
Local<Object> node = Object::New();
|
||||
g->Set(String::New("node"), node);
|
||||
|
||||
g->Set ( String::New("load")
|
||||
, FunctionTemplate::New(Load)->GetFunction()
|
||||
);
|
||||
Local<Object> blocking = Object::New();
|
||||
node->Set(String::New("blocking"), blocking);
|
||||
|
||||
g->Set ( String::New("blockingFileRead")
|
||||
, FunctionTemplate::New(BlockingFileRead)->GetFunction()
|
||||
);
|
||||
JS_SET_METHOD(blocking, "exec", exec);
|
||||
JS_SET_METHOD(blocking, "cat", cat);
|
||||
JS_SET_METHOD(blocking, "print", print);
|
||||
|
||||
Local<Array> arguments = Array::New(argc);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
Local<String> arg = String::New(argv[i]);
|
||||
arguments->Set(Integer::New(i), arg);
|
||||
}
|
||||
g->Set(String::New("ARGV"), arguments);
|
||||
|
||||
// BUILT-IN MODULES
|
||||
Init_timer(g);
|
||||
Init_tcp(g);
|
||||
//NodeInit_net(g);
|
||||
NodeInit_process(g);
|
||||
NodeInit_file(g);
|
||||
Init_http(g);
|
||||
|
||||
V8::SetFatalErrorHandler(OnFatalError);
|
||||
|
||||
v8::Handle<v8::String> source = ReadFile(filename);
|
||||
|
||||
// start eio thread pool
|
||||
ev_async_init(&thread_pool_watcher, thread_pool_cb);
|
||||
ev_async_start(EV_DEFAULT_ &thread_pool_watcher);
|
||||
eio_init(thread_pool_want_poll, NULL);
|
||||
|
||||
ExecuteString(source, String::New(filename.c_str()), false, true);
|
||||
// NATIVE JAVASCRIPT MODULES
|
||||
TryCatch try_catch;
|
||||
Handle<Value> result = ExecuteString(String::New(native_main),
|
||||
String::New("main.js"));
|
||||
if (try_catch.HasCaught()) {
|
||||
ReportException(&try_catch);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ev_loop(node_loop(), 0);
|
||||
|
||||
@ -262,4 +273,3 @@ main (int argc, char *argv[])
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
|
||||
@ -5,8 +5,15 @@
|
||||
#include <eio.h>
|
||||
#include <v8.h>
|
||||
|
||||
#define JS_SYMBOL(name) v8::String::NewSymbol(name)
|
||||
#define JS_METHOD(name) v8::Handle<v8::Value> jsmethod_##name (const v8::Arguments& args)
|
||||
#define JS_SET_METHOD(obj, name, callback) \
|
||||
obj->Set(JS_SYMBOL(name), v8::FunctionTemplate::New(jsmethod_##callback)->GetFunction())
|
||||
|
||||
|
||||
void node_fatal_exception (v8::TryCatch &try_catch);
|
||||
#define node_loop() ev_default_loop(0)
|
||||
void node_exit (int code);
|
||||
|
||||
// call this after creating a new eio event.
|
||||
void node_eio_submit(eio_req *req);
|
||||
|
||||
341
src/node_tcp.cc
341
src/node_tcp.cc
@ -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
|
||||
39
src/process.cc
Normal file
39
src/process.cc
Normal file
@ -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());
|
||||
}
|
||||
8
src/process.h
Normal file
8
src/process.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef node_process_h
|
||||
#define node_process_h
|
||||
|
||||
#include <v8.h>
|
||||
|
||||
void NodeInit_process (v8::Handle<v8::Object> target);
|
||||
|
||||
#endif
|
||||
165
test/mjsunit.js
Normal file
165
test/mjsunit.js
Normal file
@ -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);
|
||||
};
|
||||
12
test/test-test.js
Normal file
12
test/test-test.js
Normal file
@ -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__);
|
||||
28
wscript
28
wscript
@ -1,8 +1,11 @@
|
||||
#! /usr/bin/env python
|
||||
import Options
|
||||
import sys
|
||||
import os
|
||||
from os.path import join, dirname, abspath
|
||||
|
||||
import js2c
|
||||
|
||||
VERSION='0.0.1'
|
||||
APPNAME='node'
|
||||
|
||||
@ -13,12 +16,12 @@ def set_options(opt):
|
||||
# the gcc module provides a --debug-level option
|
||||
opt.tool_options('compiler_cxx')
|
||||
opt.tool_options('compiler_cc')
|
||||
opt.tool_options('ragel', tdir = '.')
|
||||
opt.tool_options('ragel', tdir=".")
|
||||
|
||||
def configure(conf):
|
||||
conf.check_tool('compiler_cxx')
|
||||
conf.check_tool('compiler_cc')
|
||||
conf.check_tool('ragel', tooldir = '.')
|
||||
conf.check_tool('ragel', tooldir=".")
|
||||
|
||||
conf.sub_config('deps/libeio')
|
||||
conf.sub_config('deps/libev')
|
||||
@ -42,6 +45,7 @@ def configure(conf):
|
||||
conf.define("HAVE_CONFIG_H", 1)
|
||||
conf.write_config_header('config.h')
|
||||
|
||||
|
||||
def build(bld):
|
||||
bld.add_subdirs('deps/libeio deps/libev')
|
||||
|
||||
@ -53,7 +57,7 @@ def build(bld):
|
||||
v8lib = bld.env["staticlib_PATTERN"] % "v8"
|
||||
v8 = bld.new_task_gen(
|
||||
target=join("deps/v8",v8lib),
|
||||
rule='cp -rf %s %s && cd %s && scons library=static'
|
||||
rule='cp -rf %s %s && cd %s && scons -Q library=static snapshot=on'
|
||||
% ( v8dir_src
|
||||
, deps_tgt
|
||||
, v8dir_tgt
|
||||
@ -80,13 +84,29 @@ def build(bld):
|
||||
ebb.name = "ebb"
|
||||
ebb.target = "ebb"
|
||||
|
||||
### src/native.cc
|
||||
def javascript_in_c(task):
|
||||
env = task.env
|
||||
source = map(lambda x: x.srcpath(env), task.inputs)
|
||||
targets = map(lambda x: x.srcpath(env), task.outputs)
|
||||
js2c.JS2C(source, targets)
|
||||
|
||||
native_cc = bld.new_task_gen(
|
||||
source="src/main.js",
|
||||
target="src/natives.h",
|
||||
rule=javascript_in_c,
|
||||
before="cxx"
|
||||
)
|
||||
|
||||
|
||||
### node
|
||||
node = bld.new_task_gen("cxx", "program")
|
||||
node.target = 'node'
|
||||
node.source = """
|
||||
src/node.cc
|
||||
src/node_http.cc
|
||||
src/node_tcp.cc
|
||||
src/process.cc
|
||||
src/file.cc
|
||||
src/node_timer.cc
|
||||
"""
|
||||
node.includes = """
|
||||
|
||||
Loading…
Reference in New Issue
Block a user