#include "node.h"
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
using namespace v8;
class Callback {
~Callback();
Local<Value> Call(Handle<Object> recv, int argc, Handle<Value> argv[]);
private:
- Persistent<Function> handle;
+ Persistent<Function> handle_;
};
-
Callback::Callback (Handle<Value> v)
{
HandleScope scope;
Handle<Function> f = Handle<Function>::Cast(v);
- handle = Persistent<Function>::New(f);
+ handle_ = Persistent<Function>::New(f);
}
Callback::~Callback ()
{
- handle.Dispose();
- handle.Clear(); // necessary?
+ 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);
+ Local<Value> r = handle_->Call(recv, argc, argv);
return scope.Close(r);
}
static int
-after_rename (eio_req *req)
+AfterRename (eio_req *req)
{
Callback *callback = static_cast<Callback*>(req->data);
if (callback != NULL) {
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);
+ eio_req *req = eio_rename(*path, *new_path, EIO_PRI_DEFAULT, AfterRename, callback);
node_eio_submit(req);
return Undefined();
}
static int
-after_stat (eio_req *req)
+AfterStat (eio_req *req)
{
Callback *callback = static_cast<Callback*>(req->data);
if (callback != NULL) {
Callback *callback = NULL;
if (!args[1]->IsUndefined()) callback = new Callback(args[1]);
- eio_req *req = eio_stat(*path, EIO_PRI_DEFAULT, after_stat, callback);
+ eio_req *req = eio_stat(*path, EIO_PRI_DEFAULT, AfterStat, callback);
node_eio_submit(req);
return Undefined();
}
+///////////////////// FILE /////////////////////
+
+class File {
+public:
+ File (Handle<Object> handle);
+ ~File ();
+
+ static File* Unwrap (Handle<Object> obj);
+
+ void Open (const char *path, const char *mode);
+ static int AfterOpen (eio_req *req);
+
+ void Close ();
+ static int AfterClose (eio_req *req);
+
+
+private:
+ static void MakeWeak (Persistent<Value> _, void *data);
+ int fd_;
+ Persistent<Object> handle_;
+};
+
+File::File (Handle<Object> handle)
+{
+ HandleScope scope;
+ fd_ = -1;
+ handle_ = Persistent<Object>::New(handle);
+ Handle<External> external = External::New(this);
+ handle_->SetInternalField(0, external);
+ handle_.MakeWeak(this, File::MakeWeak);
+}
+
+File::~File ()
+{
+ Close();
+ handle_->SetInternalField(0, Undefined());
+ handle_.Dispose();
+ handle_.Clear();
+}
+
+File*
+File::Unwrap (Handle<Object> obj)
+{
+ HandleScope scope;
+ Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
+ File* file = static_cast<File*>(field->Value());
+ return file;
+}
+
+void
+File::MakeWeak (Persistent<Value> _, void *data)
+{
+ File *file = static_cast<File*> (data);
+ delete file;
+}
+
+
+int
+File::AfterClose (eio_req *req)
+{
+ File *file = static_cast<File*>(req->data);
+
+ // TODO
+ printf("after close\n");
+ return 0;
+}
+
+void
+File::Close ()
+{
+ eio_req *req = eio_close (fd_, EIO_PRI_DEFAULT, File::AfterClose, this);
+ node_eio_submit(req);
+}
+
+int
+File::AfterOpen (eio_req *req)
+{
+ File *file = static_cast<File*>(req->data);
+
+ HandleScope scope;
+ TryCatch try_catch;
+
+ if(req->result < 0) {
+ // TODO
+ /*
+ const int argc = 2;
+ Local<Value> argv[argc];
+
+ argv[0] = Integer::New(errorno);
+ argv[1] = String::New(strerror(errorno));
+ */
+ printf("error opening file...handle me\n");
+ return 0;
+ }
+
+ file->fd_ = static_cast<int>(req->result);
+
+ file->handle_->Set(String::NewSymbol("fd"), Integer::New(req->result));
+ Handle<Value> on_open_value = file->handle_->Get( String::NewSymbol("onOpen") );
+ if (!on_open_value->IsFunction())
+ return 0;
+ Handle<Function> on_open = Handle<Function>::Cast(on_open_value);
+
+ on_open->Call(file->handle_, 0, NULL);
+
+ if(try_catch.HasCaught())
+ node_fatal_exception(try_catch);
+
+ return 0;
+}
+
+void
+File::Open (const char *path, const char *mode)
+{
+ mode_t mask = umask(0x0700);
+ umask(mask);
+
+ int flags = O_RDONLY; // default
+ // XXX is this interpretation correct?
+ // I don't want to to use fopen() because eio doesn't support it.
+ switch(mode[0]) {
+ case 'r':
+ if (mode[1] == '+')
+ flags = O_RDWR;
+ else
+ flags = O_RDONLY;
+ break;
+
+ case 'w':
+ if (mode[1] == '+')
+ flags = O_RDWR | O_CREAT | O_TRUNC;
+ else
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+
+ case 'a':
+ if (mode[1] == '+')
+ flags = O_RDWR | O_APPEND | O_CREAT;
+ else
+ flags = O_WRONLY | O_APPEND | O_CREAT;
+ break;
+ }
+
+ eio_req *req = eio_open (path, flags, mask, EIO_PRI_DEFAULT, File::AfterOpen, this);
+ node_eio_submit(req);
+}
+
+static Handle<Value>
+NewFile (const Arguments& args)
+{
+ HandleScope scope;
+ File *file = new File(args.Holder());
+ if(file == NULL)
+ return Undefined(); // XXX raise error?
+
+ return args.This();
+}
+
+JS_METHOD(file_open)
+{
+ if (args.Length() < 1) return Undefined();
+ if (!args[0]->IsString()) return Undefined();
+
+ HandleScope scope;
+
+ File *file = File::Unwrap(args.Holder());
+ String::Utf8Value path(args[0]->ToString());
+ if (args[1]->IsString()) {
+ String::AsciiValue mode(args[1]->ToString());
+ file->Open(*path, *mode);
+ } else {
+ file->Open(*path, "r");
+ }
+
+ return Undefined();
+}
+
+JS_METHOD(file_close)
+{
+ HandleScope scope;
+
+ File *file = File::Unwrap(args.Holder());
+ file->Close();
+
+ return Undefined();
+}
+
void
NodeInit_file (Handle<Object> target)
{
JS_SET_METHOD(fs, "rename", rename);
JS_SET_METHOD(fs, "stat", stat);
+
+ Local<FunctionTemplate> file_template = FunctionTemplate::New(NewFile);
+ file_template->InstanceTemplate()->SetInternalFieldCount(1);
+ target->Set(String::NewSymbol("File"), file_template->GetFunction());
+
+ JS_SET_METHOD(file_template->InstanceTemplate(), "open", file_open);
+ JS_SET_METHOD(file_template->InstanceTemplate(), "close", file_close);
}