add file open/close
authorRyan <ry@tinyclouds.org>
Wed, 15 Apr 2009 19:23:10 +0000 (21:23 +0200)
committerRyan <ry@tinyclouds.org>
Wed, 15 Apr 2009 19:23:10 +0000 (21:23 +0200)
src/file.cc
src/main.js
src/node.cc

index 6638f07..e01fa71 100644 (file)
@@ -1,6 +1,11 @@
 #include "node.h"
 #include <string.h>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
 using namespace v8;
 
 class Callback {
@@ -9,33 +14,32 @@ 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) {
@@ -65,14 +69,14 @@ JS_METHOD(rename)
   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) {
@@ -134,12 +138,199 @@ JS_METHOD(stat)
   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)
 {
@@ -150,4 +341,11 @@ 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);
 }
index ae847e7..63be09f 100644 (file)
@@ -42,7 +42,7 @@ function __require (path, loading_file) {
     // absolute path
     if (path.slice(0,1) === "/") {
     } else {
-        filename = node.path.join(node.path.dirname(loading_file), path);
+        //filename = node.path.join(node.path.dirname(loading_file), path);
     }
     node.blocking.print("require: " + filename);
 
@@ -75,11 +75,16 @@ function __require (path, loading_file) {
 }
 
 // main script execution.
-//__require(ARGV[1], ARGV[1]);
-//
+__require(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());
+
 });
+*/
+
+//var f = new File();
index 07d31b2..d125126 100644 (file)
@@ -168,7 +168,7 @@ JS_METHOD(exec)
 static void
 OnFatalError (const char* location, const char* message)
 {
-  fprintf(stderr, "Fatal error. %s %s\n", location, message);
+  fprintf(stderr, "Fatal error: %s %s\n", location, message);
   ev_unloop(node_loop(), EVUNLOOP_ALL);
 }