Revision 63a9cd38

View differences:

configure
1
#! /bin/sh
2

  
3
# waf configure wrapper
4

  
5
# Fancy colors used to beautify the output a bit.
6
#
7
if [ "$NOCOLOR" ] ; then
8
    NORMAL=""
9
    BOLD=""
10
    RED=""
11
    YELLOW=""
12
    GREEN=""
13
else
14
    NORMAL='\\033[0m'
15
    BOLD='\\033[01;1m'
16
    RED='\\033[01;91m'
17
    YELLOW='\\033[00;33m'
18
    GREEN='\\033[01;92m'
19
fi
20

  
21
EXIT_SUCCESS=0
22
EXIT_FAILURE=1
23
EXIT_ERROR=2
24
EXIT_BUG=10
25

  
26
CUR_DIR=$PWD
27

  
28
#possible relative path
29
WORKINGDIR=`dirname $0`
30
cd $WORKINGDIR
31
#abs path
32
WORKINGDIR=`pwd`
33
cd $CUR_DIR
34

  
35
# Checks for WAF. Honours $WAF if set. Stores path to 'waf' in $WAF.
36
# Requires that $PYTHON is set.
37
#
38
checkWAF()
39
{
40
	printf "Checking for WAF\t\t\t:  "
41
	#installed miniwaf in sourcedir
42
	if [ -z "$WAF" ] ; then
43
	    if [ -f "${WORKINGDIR}/waf" ] ; then
44
		WAF="${WORKINGDIR}/waf"
45
		if [ ! -x "$WAF" ] ; then
46
		    chmod +x $WAF
47
		fi
48
	    fi
49
	fi
50
	if [ -z "$WAF" ] ; then
51
	    if [ -f "${WORKINGDIR}/waf-light" ] ; then
52
		${WORKINGDIR}/waf-light --make-waf
53
	        WAF="${WORKINGDIR}/waf"
54
	    fi
55
	fi
56
	#global installed waf with waf->waf.py link
57
	if [ -z "$WAF" ] ; then
58
	    WAF=`which waf 2>/dev/null`
59
	fi
60
	# neither waf nor miniwaf could be found
61
	if [ ! -x "$WAF" ] ; then
62
	    printf $RED"not found"$NORMAL"\n"
63
	    echo "Go to http://code.google.com/p/waf/"
64
	    echo "and download a waf version"
65
	    exit $EXIT_FAILURE
66
	else
67
	  printf $GREEN"$WAF"$NORMAL"\n"
68
	fi
69
}
70

  
71
# Generates a Makefile. Requires that $WAF is set.
72
#
73
generateMakefile()
74
{
75
	cat > Makefile << EOF
76
#!/usr/bin/make -f
77
# Waf Makefile wrapper
78
WAF_HOME=$CUR_DIR
79

  
80
all:
81
	@$WAF build
82

  
83
all-debug:
84
	@$WAF -v build
85

  
86
all-progress:
87
	@$WAF -p build
88

  
89
install:
90
	if test -n "\$(DESTDIR)"; then \\
91
	    $WAF install --yes --destdir="\$(DESTDIR)" --prefix="$PREFIX"; \\
92
	else \\
93
	    $WAF install --yes --prefix="$PREFIX"; \\
94
	fi;
95

  
96
uninstall:
97
	@if test -n "\$(DESTDIR)"; then \\
98
	    $WAF uninstall --destdir="\$(DESTDIR)" --prefix="$PREFIX"; \\
99
	else \\
100
	    $WAF uninstall --prefix="$PREFIX"; \\
101
	fi;
102

  
103
clean:
104
	@$WAF clean
105

  
106
distclean:
107
	@$WAF distclean
108
	@-rm -rf _build_
109
	@-rm -f Makefile
110

  
111
check:
112
	@$WAF check
113

  
114
dist:
115
	@$WAF dist
116

  
117
.PHONY: clean dist distclean check uninstall install all
118

  
119
EOF
120
}
121

  
122
checkWAF
123

  
124
PREFIX=/usr/local
125
case $1 in
126
    --prefix)
127
        PREFIX=$2
128
        ;;
129
esac
130

  
131
export PREFIX
132
generateMakefile
133

  
134

  
135
"${WAF}" configure --prefix "${PREFIX}"
136

  
137
exit $?
js2c.py
1
#!/usr/bin/env python
2
#
3
# Copyright 2006-2008 the V8 project authors. All rights reserved.
4
# Redistribution and use in source and binary forms, with or without
5
# modification, are permitted provided that the following conditions are
6
# met:
7
#
8
#     * Redistributions of source code must retain the above copyright
9
#       notice, this list of conditions and the following disclaimer.
10
#     * Redistributions in binary form must reproduce the above
11
#       copyright notice, this list of conditions and the following
12
#       disclaimer in the documentation and/or other materials provided
13
#       with the distribution.
14
#     * Neither the name of Google Inc. nor the names of its
15
#       contributors may be used to endorse or promote products derived
16
#       from this software without specific prior written permission.
17
#
18
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29

  
30
# This is a utility for converting JavaScript source code into C-style
31
# char arrays. It is used for embedded JavaScript code in the V8
32
# library.
33

  
34
import os, re, sys, string
35
import jsmin
36

  
37

  
38
def ToCArray(lines):
39
  result = []
40
  for chr in lines:
41
    value = ord(chr)
42
    assert value < 128
43
    result.append(str(value))
44
  result.append("0")
45
  return ", ".join(result)
46

  
47

  
48
def CompressScript(lines, do_jsmin):
49
  # If we're not expecting this code to be user visible, we can run it through
50
  # a more aggressive minifier.
51
  if do_jsmin:
52
    return jsmin.jsmin(lines)
53

  
54
  # Remove stuff from the source that we don't want to appear when
55
  # people print the source code using Function.prototype.toString().
56
  # Note that we could easily compress the scripts mode but don't
57
  # since we want it to remain readable.
58
  #lines = re.sub('//.*\n', '\n', lines) # end-of-line comments
59
  #lines = re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', lines) # comments.
60
  #lines = re.sub('\s+\n+', '\n', lines) # trailing whitespace
61
  return lines
62

  
63

  
64
def ReadFile(filename):
65
  file = open(filename, "rt")
66
  try:
67
    lines = file.read()
68
  finally:
69
    file.close()
70
  return lines
71

  
72

  
73
def ReadLines(filename):
74
  result = []
75
  for line in open(filename, "rt"):
76
    if '#' in line:
77
      line = line[:line.index('#')]
78
    line = line.strip()
79
    if len(line) > 0:
80
      result.append(line)
81
  return result
82

  
83

  
84
def LoadConfigFrom(name):
85
  import ConfigParser
86
  config = ConfigParser.ConfigParser()
87
  config.read(name)
88
  return config
89

  
90

  
91
def ParseValue(string):
92
  string = string.strip()
93
  if string.startswith('[') and string.endswith(']'):
94
    return string.lstrip('[').rstrip(']').split()
95
  else:
96
    return string
97

  
98

  
99
def ExpandConstants(lines, constants):
100
  for key, value in constants.items():
101
    lines = lines.replace(key, str(value))
102
  return lines
103

  
104

  
105
def ExpandMacros(lines, macros):
106
  for name, macro in macros.items():
107
    start = lines.find(name + '(', 0)
108
    while start != -1:
109
      # Scan over the arguments
110
      assert lines[start + len(name)] == '('
111
      height = 1
112
      end = start + len(name) + 1
113
      last_match = end
114
      arg_index = 0
115
      mapping = { }
116
      def add_arg(str):
117
        # Remember to expand recursively in the arguments
118
        replacement = ExpandMacros(str.strip(), macros)
119
        mapping[macro.args[arg_index]] = replacement
120
      while end < len(lines) and height > 0:
121
        # We don't count commas at higher nesting levels.
122
        if lines[end] == ',' and height == 1:
123
          add_arg(lines[last_match:end])
124
          last_match = end + 1
125
        elif lines[end] in ['(', '{', '[']:
126
          height = height + 1
127
        elif lines[end] in [')', '}', ']']:
128
          height = height - 1
129
        end = end + 1
130
      # Remember to add the last match.
131
      add_arg(lines[last_match:end-1])
132
      result = macro.expand(mapping)
133
      # Replace the occurrence of the macro with the expansion
134
      lines = lines[:start] + result + lines[end:]
135
      start = lines.find(name + '(', end)
136
  return lines
137

  
138
class TextMacro:
139
  def __init__(self, args, body):
140
    self.args = args
141
    self.body = body
142
  def expand(self, mapping):
143
    result = self.body
144
    for key, value in mapping.items():
145
        result = result.replace(key, value)
146
    return result
147

  
148
class PythonMacro:
149
  def __init__(self, args, fun):
150
    self.args = args
151
    self.fun = fun
152
  def expand(self, mapping):
153
    args = []
154
    for arg in self.args:
155
      args.append(mapping[arg])
156
    return str(self.fun(*args))
157

  
158
CONST_PATTERN = re.compile('^const\s+([a-zA-Z0-9_]+)\s*=\s*([^;]*);$')
159
MACRO_PATTERN = re.compile('^macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
160
PYTHON_MACRO_PATTERN = re.compile('^python\s+macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
161

  
162
def ReadMacros(lines):
163
  constants = { }
164
  macros = { }
165
  for line in lines:
166
    hash = line.find('#')
167
    if hash != -1: line = line[:hash]
168
    line = line.strip()
169
    if len(line) is 0: continue
170
    const_match = CONST_PATTERN.match(line)
171
    if const_match:
172
      name = const_match.group(1)
173
      value = const_match.group(2).strip()
174
      constants[name] = value
175
    else:
176
      macro_match = MACRO_PATTERN.match(line)
177
      if macro_match:
178
        name = macro_match.group(1)
179
        args = map(string.strip, macro_match.group(2).split(','))
180
        body = macro_match.group(3).strip()
181
        macros[name] = TextMacro(args, body)
182
      else:
183
        python_match = PYTHON_MACRO_PATTERN.match(line)
184
        if python_match:
185
          name = python_match.group(1)
186
          args = map(string.strip, python_match.group(2).split(','))
187
          body = python_match.group(3).strip()
188
          fun = eval("lambda " + ",".join(args) + ': ' + body)
189
          macros[name] = PythonMacro(args, fun)
190
        else:
191
          raise ("Illegal line: " + line)
192
  return (constants, macros)
193

  
194

  
195
HEADER_TEMPLATE = """\
196
#ifndef node_natives_h
197
#define node_natives_h
198
namespace node {
199

  
200
%(source_lines)s\
201

  
202
}
203
#endif
204
"""
205

  
206

  
207
SOURCE_DECLARATION = """\
208
  static const char native_%(id)s[] = { %(data)s };
209
"""
210

  
211

  
212
GET_DELAY_INDEX_CASE = """\
213
    if (strcmp(name, "%(id)s") == 0) return %(i)i;
214
"""
215

  
216

  
217
GET_DELAY_SCRIPT_SOURCE_CASE = """\
218
    if (index == %(i)i) return Vector<const char>(%(id)s, %(length)i);
219
"""
220

  
221

  
222
GET_DELAY_SCRIPT_NAME_CASE = """\
223
    if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i);
224
"""
225

  
226
def JS2C(source, target):
227
  ids = []
228
  delay_ids = []
229
  modules = []
230
  # Locate the macros file name.
231
  consts = {}
232
  macros = {}
233
  for s in source:
234
    if 'macros.py' == (os.path.split(str(s))[1]):
235
      (consts, macros) = ReadMacros(ReadLines(str(s)))
236
    else:
237
      modules.append(s)
238

  
239
  # Build source code lines
240
  source_lines = [ ]
241
  source_lines_empty = []
242
  for s in modules:
243
    delay = str(s).endswith('-delay.js')
244
    lines = ReadFile(str(s))
245
    do_jsmin = lines.find('// jsminify this file, js2c: jsmin') != -1
246
    lines = ExpandConstants(lines, consts)
247
    lines = ExpandMacros(lines, macros)
248
    lines = CompressScript(lines, do_jsmin)
249
    data = ToCArray(lines)
250
    id = (os.path.split(str(s))[1])[:-3]
251
    if delay: id = id[:-6]
252
    if delay:
253
      delay_ids.append((id, len(lines)))
254
    else:
255
      ids.append((id, len(lines)))
256
    source_lines.append(SOURCE_DECLARATION % { 'id': id, 'data': data })
257
    source_lines_empty.append(SOURCE_DECLARATION % { 'id': id, 'data': 0 })
258
  
259
  # Build delay support functions
260
  get_index_cases = [ ]
261
  get_script_source_cases = [ ]
262
  get_script_name_cases = [ ]
263

  
264
  i = 0
265
  for (id, length) in delay_ids:
266
    native_name = "native %s.js" % id
267
    get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i })
268
    get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % {
269
      'id': id,
270
      'length': length,
271
      'i': i
272
    })
273
    get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % {
274
      'name': native_name,
275
      'length': len(native_name),
276
      'i': i
277
    });
278
    i = i + 1
279

  
280
  for (id, length) in ids:
281
    native_name = "native %s.js" % id
282
    get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i })
283
    get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % {
284
      'id': id,
285
      'length': length,
286
      'i': i
287
    })
288
    get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % {
289
      'name': native_name,
290
      'length': len(native_name),
291
      'i': i
292
    });
293
    i = i + 1
294

  
295
  # Emit result
296
  output = open(str(target[0]), "w")
297
  output.write(HEADER_TEMPLATE % {
298
    'builtin_count': len(ids) + len(delay_ids),
299
    'delay_count': len(delay_ids),
300
    'source_lines': "\n".join(source_lines),
301
    'get_index_cases': "".join(get_index_cases),
302
    'get_script_source_cases': "".join(get_script_source_cases),
303
    'get_script_name_cases': "".join(get_script_name_cases)
304
  })
305
  output.close()
306

  
307
  if len(target) > 1:
308
    output = open(str(target[1]), "w")
309
    output.write(HEADER_TEMPLATE % {
310
      'builtin_count': len(ids) + len(delay_ids),
311
      'delay_count': len(delay_ids),
312
      'source_lines': "\n".join(source_lines_empty),
313
      'get_index_cases': "".join(get_index_cases),
314
      'get_script_source_cases': "".join(get_script_source_cases),
315
      'get_script_name_cases': "".join(get_script_name_cases)
316
    })
317
    output.close()
jsmin.py
1
#!/usr/bin/python
2

  
3
# This code is original from jsmin by Douglas Crockford, it was translated to
4
# Python by Baruch Even. The original code had the following copyright and
5
# license.
6
#
7
# /* jsmin.c
8
#    2007-05-22
9
#
10
# Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
11
#
12
# Permission is hereby granted, free of charge, to any person obtaining a copy of
13
# this software and associated documentation files (the "Software"), to deal in
14
# the Software without restriction, including without limitation the rights to
15
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
16
# of the Software, and to permit persons to whom the Software is furnished to do
17
# so, subject to the following conditions:
18
#
19
# The above copyright notice and this permission notice shall be included in all
20
# copies or substantial portions of the Software.
21
#
22
# The Software shall be used for Good, not Evil.
23
#
24
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
# SOFTWARE.
31
# */
32

  
33
from StringIO import StringIO
34

  
35
def jsmin(js):
36
    ins = StringIO(js)
37
    outs = StringIO()
38
    JavascriptMinify().minify(ins, outs)
39
    str = outs.getvalue()
40
    if len(str) > 0 and str[0] == '\n':
41
        str = str[1:]
42
    return str
43

  
44
def isAlphanum(c):
45
    """return true if the character is a letter, digit, underscore,
46
           dollar sign, or non-ASCII character.
47
    """
48
    return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or
49
            (c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126));
50

  
51
class UnterminatedComment(Exception):
52
    pass
53

  
54
class UnterminatedStringLiteral(Exception):
55
    pass
56

  
57
class UnterminatedRegularExpression(Exception):
58
    pass
59

  
60
class JavascriptMinify(object):
61

  
62
    def _outA(self):
63
        self.outstream.write(self.theA)
64
    def _outB(self):
65
        self.outstream.write(self.theB)
66

  
67
    def _get(self):
68
        """return the next character from stdin. Watch out for lookahead. If
69
           the character is a control character, translate it to a space or
70
           linefeed.
71
        """
72
        c = self.theLookahead
73
        self.theLookahead = None
74
        if c == None:
75
            c = self.instream.read(1)
76
        if c >= ' ' or c == '\n':
77
            return c
78
        if c == '': # EOF
79
            return '\000'
80
        if c == '\r':
81
            return '\n'
82
        return ' '
83

  
84
    def _peek(self):
85
        self.theLookahead = self._get()
86
        return self.theLookahead
87

  
88
    def _next(self):
89
        """get the next character, excluding comments. peek() is used to see
90
           if an unescaped '/' is followed by a '/' or '*'.
91
        """
92
        c = self._get()
93
        if c == '/' and self.theA != '\\':
94
            p = self._peek()
95
            if p == '/':
96
                c = self._get()
97
                while c > '\n':
98
                    c = self._get()
99
                return c
100
            if p == '*':
101
                c = self._get()
102
                while 1:
103
                    c = self._get()
104
                    if c == '*':
105
                        if self._peek() == '/':
106
                            self._get()
107
                            return ' '
108
                    if c == '\000':
109
                        raise UnterminatedComment()
110

  
111
        return c
112

  
113
    def _action(self, action):
114
        """do something! What you do is determined by the argument:
115
           1   Output A. Copy B to A. Get the next B.
116
           2   Copy B to A. Get the next B. (Delete A).
117
           3   Get the next B. (Delete B).
118
           action treats a string as a single character. Wow!
119
           action recognizes a regular expression if it is preceded by ( or , or =.
120
        """
121
        if action <= 1:
122
            self._outA()
123

  
124
        if action <= 2:
125
            self.theA = self.theB
126
            if self.theA == "'" or self.theA == '"':
127
                while 1:
128
                    self._outA()
129
                    self.theA = self._get()
130
                    if self.theA == self.theB:
131
                        break
132
                    if self.theA <= '\n':
133
                        raise UnterminatedStringLiteral()
134
                    if self.theA == '\\':
135
                        self._outA()
136
                        self.theA = self._get()
137

  
138

  
139
        if action <= 3:
140
            self.theB = self._next()
141
            if self.theB == '/' and (self.theA == '(' or self.theA == ',' or
142
                                     self.theA == '=' or self.theA == ':' or
143
                                     self.theA == '[' or self.theA == '?' or
144
                                     self.theA == '!' or self.theA == '&' or
145
                                     self.theA == '|' or self.theA == ';' or
146
                                     self.theA == '{' or self.theA == '}' or
147
                                     self.theA == '\n'):
148
                self._outA()
149
                self._outB()
150
                while 1:
151
                    self.theA = self._get()
152
                    if self.theA == '/':
153
                        break
154
                    elif self.theA == '\\':
155
                        self._outA()
156
                        self.theA = self._get()
157
                    elif self.theA <= '\n':
158
                        raise UnterminatedRegularExpression()
159
                    self._outA()
160
                self.theB = self._next()
161

  
162

  
163
    def _jsmin(self):
164
        """Copy the input to the output, deleting the characters which are
165
           insignificant to JavaScript. Comments will be removed. Tabs will be
166
           replaced with spaces. Carriage returns will be replaced with linefeeds.
167
           Most spaces and linefeeds will be removed.
168
        """
169
        self.theA = '\n'
170
        self._action(3)
171

  
172
        while self.theA != '\000':
173
            if self.theA == ' ':
174
                if isAlphanum(self.theB):
175
                    self._action(1)
176
                else:
177
                    self._action(2)
178
            elif self.theA == '\n':
179
                if self.theB in ['{', '[', '(', '+', '-']:
180
                    self._action(1)
181
                elif self.theB == ' ':
182
                    self._action(3)
183
                else:
184
                    if isAlphanum(self.theB):
185
                        self._action(1)
186
                    else:
187
                        self._action(2)
188
            else:
189
                if self.theB == ' ':
190
                    if isAlphanum(self.theA):
191
                        self._action(1)
192
                    else:
193
                        self._action(3)
194
                elif self.theB == '\n':
195
                    if self.theA in ['}', ']', ')', '+', '-', '"', '\'']:
196
                        self._action(1)
197
                    else:
198
                        if isAlphanum(self.theA):
199
                            self._action(1)
200
                        else:
201
                            self._action(3)
202
                else:
203
                    self._action(1)
204

  
205
    def minify(self, instream, outstream):
206
        self.instream = instream
207
        self.outstream = outstream
208
        self.theA = '\n'
209
        self.theB = None
210
        self.theLookahead = None
211

  
212
        self._jsmin()
213
        self.instream.close()
214

  
215
if __name__ == '__main__':
216
    import sys
217
    jsm = JavascriptMinify()
218
    jsm.minify(sys.stdin, sys.stdout)
src/file.cc
1
#include "node.h"
2
#include <string.h>
3

  
4
using namespace v8;
5

  
6
class Callback {
7
  public:
8
    Callback(Handle<Value> v);
9
    ~Callback();
10
    Local<Value> Call(Handle<Object> recv, int argc, Handle<Value> argv[]);
11
  private:
12
    Persistent<Function> handle;
13
};
14

  
15

  
16
Callback::Callback (Handle<Value> v)
17
{
18
  HandleScope scope;
19
  Handle<Function> f = Handle<Function>::Cast(v);
20
  handle = Persistent<Function>::New(f);
21
}
22

  
23
Callback::~Callback ()
24
{
25
  handle.Dispose();
26
  handle.Clear(); // necessary? 
27
}
28

  
29
Local<Value>
30
Callback::Call (Handle<Object> recv, int argc, Handle<Value> argv[])
31
{
32
  HandleScope scope;
33
  Local<Value> r = handle->Call(recv, argc, argv);
34
  return scope.Close(r);
35
}
36

  
37
static int
38
after_rename (eio_req *req)
39
{
40
  Callback *callback = static_cast<Callback*>(req->data);
41
  if (callback != NULL) {
42
    HandleScope scope;
43
    const int argc = 2;
44
    Local<Value> argv[argc];
45

  
46
    argv[0] = Integer::New(req->errorno);
47
    argv[1] = String::New(strerror(req->errorno));
48
    
49
    callback->Call(Context::GetCurrent()->Global(), argc, argv);
50
    delete callback;
51
  }
52
  return 0;
53
}
54

  
55
JS_METHOD(rename) 
56
{
57
  if (args.Length() < 2)
58
    return Undefined();
59

  
60
  HandleScope scope;
61

  
62
  String::Utf8Value path(args[0]->ToString());
63
  String::Utf8Value new_path(args[1]->ToString());
64

  
65
  Callback *callback = NULL;
66
  if (!args[2]->IsUndefined()) callback = new Callback(args[2]);
67

  
68
  eio_req *req = eio_rename(*path, *new_path, EIO_PRI_DEFAULT, after_rename, callback);
69
  node_eio_submit(req);
70

  
71
  return Undefined();
72
}
73

  
74
static int
75
after_stat (eio_req *req)
76
{
77
  Callback *callback = static_cast<Callback*>(req->data);
78
  if (callback != NULL) {
79
    HandleScope scope;
80
    const int argc = 3;
81
    Local<Value> argv[argc];
82

  
83
    Local<Object> stats = Object::New();
84
    argv[0] = stats;
85
    argv[1] = Integer::New(req->errorno);
86
    argv[2] = String::New(strerror(req->errorno));
87

  
88
    if (req->result == 0) {
89
      struct stat *s = static_cast<struct stat*>(req->ptr2);
90

  
91
      /* ID of device containing file */
92
      stats->Set(JS_SYMBOL("dev"), Integer::New(s->st_dev));
93
      /* inode number */
94
      stats->Set(JS_SYMBOL("ino"), Integer::New(s->st_ino));
95
      /* protection */
96
      stats->Set(JS_SYMBOL("mode"), Integer::New(s->st_mode));
97
      /* number of hard links */
98
      stats->Set(JS_SYMBOL("nlink"), Integer::New(s->st_nlink));
99
      /* user ID of owner */
100
      stats->Set(JS_SYMBOL("uid"), Integer::New(s->st_uid));
101
      /* group ID of owner */
102
      stats->Set(JS_SYMBOL("gid"), Integer::New(s->st_gid));
103
      /* device ID (if special file) */
104
      stats->Set(JS_SYMBOL("rdev"), Integer::New(s->st_rdev));
105
      /* total size, in bytes */
106
      stats->Set(JS_SYMBOL("size"), Integer::New(s->st_size));
107
      /* blocksize for filesystem I/O */
108
      stats->Set(JS_SYMBOL("blksize"), Integer::New(s->st_blksize));
109
      /* number of blocks allocated */
110
      stats->Set(JS_SYMBOL("blocks"), Integer::New(s->st_blocks));
111
      /* time of last access */
112
      stats->Set(JS_SYMBOL("atime"), Date::New(1000*static_cast<double>(s->st_atime)));
113
      /* time of last modification */
114
      stats->Set(JS_SYMBOL("mtime"), Date::New(1000*static_cast<double>(s->st_mtime)));
115
      /* time of last status change */
116
      stats->Set(JS_SYMBOL("ctime"), Date::New(1000*static_cast<double>(s->st_ctime)));
117
    }
118
    
119
    callback->Call(Context::GetCurrent()->Global(), argc, argv);
120
    delete callback;
121
  }
122
  return 0;
123
}
124

  
125
JS_METHOD(stat) 
126
{
127
  if (args.Length() < 1)
128
    return v8::Undefined();
129

  
130
  HandleScope scope;
131

  
132
  String::Utf8Value path(args[0]->ToString());
133

  
134
  Callback *callback = NULL;
135
  if (!args[1]->IsUndefined()) callback = new Callback(args[1]);
136

  
137
  eio_req *req = eio_stat(*path, EIO_PRI_DEFAULT, after_stat, callback);
138
  node_eio_submit(req);
139

  
140
  return Undefined();
141
}
142

  
143
void
144
NodeInit_file (Handle<Object> target)
145
{
146
  HandleScope scope;
147

  
148
  Local<Object> fs = Object::New();
149
  target->Set(String::NewSymbol("fs"), fs);
150
  
151
  JS_SET_METHOD(fs, "rename", rename);
152
  JS_SET_METHOD(fs, "stat", stat);
153
}
src/file.h
1
#ifndef node_file_h
2
#define node_file_h
3

  
4
#include <v8.h>
5

  
6
void NodeInit_file (v8::Handle<v8::Object> target);
7

  
8
#endif
src/main.js
1
// module search paths
2
node.includes = ["."];
3

  
4
node.path = new function () {
5
    this.join = function () {
6
        var joined = "";
7
        for (var i = 0; i < arguments.length; i++) {
8
            var part = arguments[i].toString();
9
            if (i === 0) {
10
                part = part.replace(/\/*$/, "/");
11
            } else if (i === arguments.length - 1) {
12
                part = part.replace(/^\/*/, "");
13
            } else {
14
                part = part.replace(/^\/*/, "")
15
                           .replace(/\/*$/, "/");
16
            }
17
            joined += part;
18
        }
19
        return joined;
20
    };
21

  
22
    this.dirname = function (path) {
23
        var parts = path.split("/");
24
        return parts.slice(0, parts.length-1);
25
    };
26
};
27

  
28
function __include (module, path) {
29
    var export = module.require(path);
30
    for (var i in export) {
31
        if (export.hasOwnProperty(i))
32
            module[i] = export[i];
33
    }
34
}
35

  
36

  
37

  
38
function __require (path, loading_file) {
39

  
40
    var filename = path;
41
    // relative path
42
    // absolute path
43
    if (path.slice(0,1) === "/") {
44
    } else {
45
        filename = node.path.join(node.path.dirname(loading_file), path);
46
    }
47
    node.blocking.print("require: " + filename);
48

  
49
    /*
50
    for (var i = 0; i < suffixes.length; i++) {
51
        var f = filename + "." + suffixes[i];
52
         
53
        var stats = node.blocking.stat(f);
54
        for (var j in stats) {
55
            node.blocking.print("stats." + j + " = " + stats[j].toString());
56
        }
57
    }
58
    */
59
    
60
    var source = node.blocking.cat(filename);
61

  
62
    // wrap the source in a function 
63
    source = "function (__file__, __dir__) { " 
64
           + "  var exports = {};"
65
           + "  function require (m) { return __require(m, __file__); }"
66
           + "  function include (m) { return __include(this, m); }"
67
           +    source 
68
           + "  return exports;"
69
           + "};"
70
           ;
71
    var create_module = node.blocking.exec(source, filename);
72

  
73
    // execute the function wrap
74
    return create_module(filename, node.path.dirname(filename));
75
}
76

  
77
// main script execution.
78
//__require(ARGV[1], ARGV[1]);
79
//
80
fs.stat("/tmp/world", function (stat, status, msg) {
81
  for ( var i in stat ) {
82
    node.blocking.print(i + ": " + stat[i]);
83
  }
84
  node.blocking.print("done: " + status.toString() + " " + msg.toString());
85
});
src/net.cc
1
#include "net.h"
2
#include "node.h"
3

  
4
#include <oi_socket.h>
5
#include <oi_buf.h>
6

  
7
#include <assert.h>
8
#include <sys/types.h>
9
#include <sys/socket.h>
10
#include <netdb.h>
11
#include <strings.h>
12

  
13
using namespace v8;
14

  
15
static Persistent<String> readyState_str; 
16

  
17
static Persistent<Integer> readyStateCONNECTING; 
18
static Persistent<Integer> readyStateOPEN; 
19
static Persistent<Integer> readyStateCLOSED; 
20

  
21
enum encoding {UTF8, RAW};
22

  
23
class Socket {
24
public:
25
  Socket (Handle<Object> obj, double timeout);
26
  ~Socket ();
27

  
28
  int ConnectTCP (char *port, char *host);
29
  void Write (Handle<Value> arg);
30
  void Disconnect ();
31

  
32
  void SetEncoding (enum encoding);
33
  void SetTimeout (double);
34

  
35
  void OnConnect ();
36
  void OnRead (const void *buf, size_t count);
37
  void OnDrain ();
38
  void OnError (oi_error e);
39
  void OnClose ();
40

  
41
private:
42
  oi_socket socket_;
43
  struct addrinfo *address_;
44
  Persistent<Object> js_object_;
45
};
46

  
47
static void
48
on_connect (oi_socket *socket)
49
{
50
  Socket *s = static_cast<Socket*> (socket->data);
51
  s->OnConnect();
52
}
53

  
54
static void
55
on_read (oi_socket *socket, const void *buf, size_t count)
56
{
57
  Socket *s = static_cast<Socket*> (socket->data);
58
  s->OnRead(buf, count);
59
}
60

  
61
static void
62
on_drain (oi_socket *socket)
63
{
64
  Socket *s = static_cast<Socket*> (socket->data);
65
  s->OnDrain();
66
}
67

  
68
static void
69
on_error (oi_socket *socket, oi_error e)
70
{
71
  Socket *s = static_cast<Socket*> (socket->data);
72
  s->OnError(e);
73
}
74

  
75
static void
76
on_timeout (oi_socket *socket)
77
{
78
  Socket *s = static_cast<Socket*> (socket->data);
79
  s->OnTimeout(e);
80
}
81

  
82
static void
83
on_close (oi_socket *socket)
84
{
85
  Socket *s = static_cast<Socket*> (socket->data);
86
  s->OnClose();
87
}
88

  
89

  
90
static Handle<Value>
91
NewSocket (const Arguments& args)
92
{
93
  if (args.Length() > 1)
94
    return Undefined();
95

  
96
  HandleScope scope;
97

  
98
  // Default options 
99
  double timeout = 60.0; // in seconds
100
  enum {RAW, UTF8} encoding = RAW;
101

  
102
  // Set options from argument.
103
  if (args.Length() == 1 && args[0]->IsObject()) {
104
    Local<Object> options = args[0]->ToObject();
105
    Local<Value> timeout_value = options->Get(String::NewSymbol("timeout"));
106
    Local<Value> encoding_value = options->Get(String::NewSymbol("encoding"));
107

  
108
    if (timeout_value->IsNumber()) {
109
      // timeout is specified in milliseconds like other time
110
      // values in javascript
111
      timeout = timeout_value->NumberValue() / 1000;
112
    }
113

  
114
    if (encoding_value->IsString()) {
115
      Local<String> encoding_string = encoding_value->ToString();
116
      char buf[5]; // need enough room for "utf8" or "raw"
117
      encoding_string->WriteAscii(buf, 0, 4);
118
      buf[4] = '\0';
119
      if(strcasecmp(buf, "utf8") == 0) encoding = UTF8;
120
    }
121
  }
122

  
123
  Socket *s = new Socket(args.This(), timeout);
124
  if(s == NULL)
125
    return Undefined(); // XXX raise error?
126

  
127
  return args.This();
128
}
129

  
130
static Socket*
131
Unwrapsocket (Handle<Object> obj) 
132
{
133
  HandleScope scope;
134
  Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
135
  Socket* socket = static_cast<Socket*>(field->Value());
136
  return socket;
137
}
138

  
139
static Handle<Value>
140
SocketConnectTCPCallback (const Arguments& args)
141
{
142
  if (args.Length() < 1)
143
    return Undefined();
144

  
145
  HandleScope scope;
146
  Socket *socket = Unwrapsocket(args.Holder());
147

  
148
  String::AsciiValue port(args[0]);
149

  
150
  char *host = NULL; 
151
  String::AsciiValue host_v(args[1]->ToString());
152
  if(args[1]->IsString()) {
153
    host = *host_v;
154
  }
155

  
156
  int r = socket->ConnectTCP(*port, host);
157
  // TODO raise error if r != 0
158
    
159
  return Undefined(); 
160
}
161

  
162
static Handle<Value>
163
SocketWriteCallback (const Arguments& args) 
164
{
165
  HandleScope scope;
166
  Socket *socket = Unwrapsocket(args.Holder());
167
  socket->Write(args[0]);
168
  return Undefined();
169
}
170

  
171
static Handle<Value>
172
SocketCloseCallback (const Arguments& args) 
173
{
174
  HandleScope scope;
175
  Socket *socket = Unwrapsocket(args.Holder());
176
  socket->Disconnect();
177
  return Undefined();
178
}
179

  
180
static void
181
DestroySocket (Persistent<Value> _, void *data)
182
{
183
  Socket *s = static_cast<Socket*> (data);
184
  delete s;
185
}
186

  
187
Socket::Socket(Handle<Object> js_object, double timeout)
188
{
189
  oi_socket_init(&socket_, timeout);
190
  socket_.on_connect = on_connect;
191
  socket_.on_read    = on_read;
192
  socket_.on_drain   = on_drain;
193
  socket_.on_error   = on_error;
194
  socket_.on_close   = on_close;
195
  socket_.on_timeout = on_timeout;
196
  socket_.data = this;
197

  
198
  HandleScope scope;
199
  js_object_ = Persistent<Object>::New(js_object);
200
  js_object_->SetInternalField (0, External::New(this));
201
  js_object_.MakeWeak (this, DestroySocket);
202
}
203

  
204
Socket::~Socket ()
205
{
206
  Disconnect();
207
  oi_socket_detach(&socket_);
208
  js_object_.Dispose();
209
  js_object_.Clear(); // necessary? 
210
}
211

  
212
static struct addrinfo tcp_hints = 
213
/* ai_flags      */ { AI_PASSIVE
214
/* ai_family     */ , AF_UNSPEC
215
/* ai_socktype   */ , SOCK_STREAM
216
/* ai_protocol   */ , 0
217
/* ai_addrlen    */ , 0
218
/* ai_addr       */ , 0
219
/* ai_canonname  */ , 0
220
/* ai_next       */ , 0
221
                    };
222

  
223
int
224
Socket::ConnectTCP(char *port, char *host)
225
{
226
  int r;
227

  
228
  HandleScope scope;
229

  
230
  js_object_->Set(readyState_str, readyStateCONNECTING);
231

  
232
  /* FIXME Blocking DNS resolution. */
233
  printf("resolving host: %s, port: %s\n", host, port);
234
  r = getaddrinfo (host, port, &tcp_hints, &address);
235
  if(r != 0)  {
236
    perror("getaddrinfo");
237
    return r;
238
  }
239

  
240
  r = oi_socket_connect (&socket, address);
241
  if(r != 0)  {
242
    perror("oi_socket_connect");
243
    return r;
244
  }
245
  oi_socket_attach (&socket, node_loop());
246

  
247
  freeaddrinfo(address);
248
  address = NULL;
249
}
250

  
251
void Socket::Write (Handle<Value> arg)
252
{
253
  HandleScope scope;
254
 
255
  if (arg == Null()) {
256

  
257
    oi_socket_write_eof(&socket);
258

  
259
  } else if (arg->IsString()) {
260
    Local<String> s = arg->ToString();
261

  
262
    size_t l1 = s->Utf8Length(), l2;
263
    oi_buf *buf = oi_buf_new2(l1);
264
    l2 = s->WriteUtf8(buf->base, l1);
265
    assert(l1 == l2);
266

  
267
    oi_socket_write(&socket, buf);
268

  
269
  } else if (arg->IsArray()) {
270
    size_t length = array->Length();
271
    Handle<Array> array = Handle<Array>::Cast(arg);
272
    oi_buf *buf = oi_buf_new2(length);
273
    for (int i = 0; i < length; i++) {
274
      Local<Value> int_value = array->Get(Integer::New(i));
275
      buf[i] = int_value->Int32Value();
276
    }
277

  
278
    oi_socket_write(&socket, buf);
279

  
280
  } else {
281
    // raise error bad argument.
282
    assert(0);
283
  }
284
}
285
 
286
void
287
Socket::Disconnect()
288
{
289
  oi_socket_close(&socket);
290
}
291

  
292
void
293
Socket::OnConnect()
294
{
295
  HandleScope scope;
296

  
297
  assert(READY_STATE_CONNECTING == ReadyState());
298
  js_object_->Set(readyState_str, readyStateOPEN);
299

  
300
  Handle<Value> on_connect_value = js_object_->Get( String::NewSymbol("on_connect") );
301
  if (!on_connect_value->IsFunction())
302
    return; 
303
  Handle<Function> on_connect = Handle<Function>::Cast(on_connect_value);
304

  
305
  TryCatch try_catch;
306

  
307
  Handle<Value> r = on_connect->Call(js_object_, 0, NULL);
308

  
309
  if(try_catch.HasCaught())
310
    node_fatal_exception(try_catch);
311
}
312

  
313
void
314
Socket::OnRead (const void *buf, size_t count)
315
{
316
  HandleScope scope;
317

  
318
  assert(READY_STATE_OPEN == ReadyState());
319

  
320
  Handle<Value> onread_value = js_object_->Get( String::NewSymbol("on_read") );
321
  if (!onread_value->IsFunction()) return; 
322
  Handle<Function> onread = Handle<Function>::Cast(onread_value);
323

  
324
  const int argc = 1;
325
  Handle<Value> argv[argc];
326

  
327
  if(count) {
328
    Handle<String> chunk = String::New((const char*)buf, count); // TODO binary data?
329
    argv[0] = chunk;
330
  } else {
331
    // TODO eof? delete write method?
332
    argv[0] = Null();
333
  }
334

  
335
  TryCatch try_catch;
336

  
337
  Handle<Value> r = onread->Call(js_object_, argc, argv);
338

  
339
  if(try_catch.HasCaught())
340
    node_fatal_exception(try_catch);
341
}
342

  
343
void
344
Socket::OnClose ()
345
{
346
  HandleScope scope;
347

  
348
  printf("onclose readyState %d\n", ReadyState());
349

  
350
  assert(READY_STATE_OPEN == ReadyState());
351
  js_object_->Set(readyState_str, readyStateCLOSED);
352

  
353
  Handle<Value> onclose_value = js_object_->Get( String::NewSymbol("on_close") );
354
  if (!onclose_value->IsFunction()) return; 
355
  Handle<Function> onclose = Handle<Function>::Cast(onclose_value);
356

  
357
  TryCatch try_catch;
358

  
359
  Handle<Value> r = onclose->Call(js_object_, 0, NULL);
360

  
361
  if(try_catch.HasCaught())
362
    node_fatal_exception(try_catch);
363
}
364

  
365
void
366
NodeInit_net (Handle<Object> target)
367
{
368
  HandleScope scope;
369

  
370
  //
371
  // Socket
372
  //
373
  Local<FunctionTemplate> socket_template = FunctionTemplate::New(NewSocket);
374
  target->Set(String::NewSymbol("Socket"), socket_template->GetFunction());
375
  socket_template->InstanceTemplate()->SetInternalFieldCount(1);
376

  
377
  // socket.connectTCP()
378
  Local<FunctionTemplate> socket_connect_tcp = 
379
      FunctionTemplate::New(SocketConnectTCPCallback);
380
  socket_template->InstanceTemplate()->Set(String::NewSymbol("connectTCP"), 
381
                                           socket_connect_tcp->GetFunction());
382

  
383
  // socket.connectUNIX()
384
  Local<FunctionTemplate> socket_connect_unix = 
385
      FunctionTemplate::New(SocketConnectUNIXCallback);
386
  socket_template->InstanceTemplate()->Set(String::NewSymbol("connectUNIX"), 
387
                                           socket_connect_unix->GetFunction());
388

  
389
  // socket.write()
390
  Local<FunctionTemplate> socket_write =
391
      FunctionTemplate::New(SocketWriteCallback);
392
  socket_template->InstanceTemplate()->Set(String::NewSymbol("write"), 
393
                                           socket_write->GetFunction());
394

  
395
  // socket.close()
396
  Local<FunctionTemplate> socket_close = 
397
      FunctionTemplate::New(SocketCloseCallback);
398
  socket_template->InstanceTemplate()->Set(String::NewSymbol("close"), 
399
                                           socket_close->GetFunction());
400

  
401
  //
402
  // Server
403
  //
404
  Local<FunctionTemplate> server_template = FunctionTemplate::New(NewServer);
405
  target->Set(String::NewSymbol("Server"), server_template->GetFunction());
406
  server_template->InstanceTemplate()->SetInternalFieldCount(1);
407

  
408
  // server.listenTCP()
409
  Local<FunctionTemplate> server_listenTCP =
410
      FunctionTemplate::New(ServerListenTCPCallback);
411
  server_template->InstanceTemplate()->Set(String::NewSymbol("listenTCP"), 
412
                                           server_listenTCP->GetFunction());
413

  
414
  // server.listenUNIX()
415
  Local<FunctionTemplate> server_listenUNIX =
416
      FunctionTemplate::New(ServerListenUNIXCallback);
417
  server_template->InstanceTemplate()->Set(String::NewSymbol("listenUNIX"), 
418
                                           server_listenTCP->GetFunction());
419

  
420
  // server.close()
421
  Local<FunctionTemplate> server_close = FunctionTemplate::New(ServerCloseCallback);
422
  server_template->InstanceTemplate()->Set(String::NewSymbol("close"), 
423
                                           server_close->GetFunction());
424
}
425

  
src/net.h
1
#ifndef node_net_h
2
#define node_net_h
3

  
4
#include <v8.h>
5

  
6
void NodeInit_net (v8::Handle<v8::Object> target);
7

  
8
#endif
src/node.cc
1 1
#include "node.h"
2 2

  
3
#include "node_tcp.h"
3
//#include "net.h"
4
#include "file.h"
5
#include "process.h"
4 6
#include "node_http.h"
5 7
#include "node_timer.h"
6 8

  
9
#include "natives.h" 
10

  
7 11
#include <stdio.h>
8 12
#include <assert.h>
9 13

  
......
12 16
#include <map>
13 17

  
14 18
using namespace v8;
19
using namespace node;
15 20
using namespace std;
16 21

  
17 22
static int exit_code = 0;
18 23

  
19
// Reads a file into a v8 string.
20
static Handle<String>
21
ReadFile (const string& name) 
24
// Extracts a C string from a V8 Utf8Value.
25
const char*
26
ToCString(const v8::String::Utf8Value& value)
22 27
{
28
  return *value ? *value : "<string conversion failed>";
29
}
23 30

  
24
  FILE* file = fopen(name.c_str(), "rb");
25
  if (file == NULL) return Handle<String>();
31
void
32
ReportException(v8::TryCatch* try_catch)
33
{
34
  v8::HandleScope handle_scope;
35
  v8::String::Utf8Value exception(try_catch->Exception());
36
  const char* exception_string = ToCString(exception);
37
  v8::Handle<v8::Message> message = try_catch->Message();
38
  if (message.IsEmpty()) {
39
    // V8 didn't provide any extra information about this error; just
40
    // print the exception.
41
    printf("%s\n", exception_string);
42
  } else {
43
    message->PrintCurrentStackTrace(stdout);
44

  
45
    // Print (filename):(line number): (message).
46
    v8::String::Utf8Value filename(message->GetScriptResourceName());
47
    const char* filename_string = ToCString(filename);
48
    int linenum = message->GetLineNumber();
49
    printf("%s:%i: %s\n", filename_string, linenum, exception_string);
50
    // Print line of source code.
51
    v8::String::Utf8Value sourceline(message->GetSourceLine());
52
    const char* sourceline_string = ToCString(sourceline);
53
    printf("%s\n", sourceline_string);
54
    // Print wavy underline (GetUnderline is deprecated).
55
    int start = message->GetStartColumn();
56
    for (int i = 0; i < start; i++) {
57
      printf(" ");
58
    }
59
    int end = message->GetEndColumn();
60
    for (int i = start; i < end; i++) {
61
      printf("^");
62
    }
63
    printf("\n");
64
  }
65
}
66

  
67
// Executes a string within the current v8 context.
68
Handle<Value>
69
ExecuteString(v8::Handle<v8::String> source,
70
              v8::Handle<v8::Value> filename)
71
{
72
  HandleScope scope;
73
  Handle<Script> script = Script::Compile(source, filename);
74
  if (script.IsEmpty()) {
75
    return ThrowException(String::New("Error compiling string"));
76
  }
77

  
78
  Handle<Value> result = script->Run();
79
  if (result.IsEmpty()) {
80
    return ThrowException(String::New("Error running string"));
81
  }
82

  
83
  return scope.Close(result);
84
}
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff