add file.read only. raw encoding right now.
authorRyan <ry@tinyclouds.org>
Thu, 16 Apr 2009 19:05:26 +0000 (21:05 +0200)
committerRyan <ry@tinyclouds.org>
Thu, 16 Apr 2009 19:05:41 +0000 (21:05 +0200)
src/file.cc
src/file.js
src/node.h
test/simple.js

index 578e3cd..6d4ff15 100644 (file)
@@ -158,7 +158,7 @@ public:
   File (Handle<Object> handle);
   ~File ();
 
-  static File* Unwrap (Handle<Object> obj);
+  static File* Unwrap (Handle<Object> handle);
 
   static Handle<Value> Open (const Arguments& args);
   static int AfterOpen (eio_req *req);
@@ -169,8 +169,12 @@ public:
   static Handle<Value> Write (const Arguments& args);
   static int AfterWrite (eio_req *req);
 
+  static Handle<Value> Read (const Arguments& args);
+  static int AfterRead (eio_req *req);
 
 private:
+  bool HasUtf8Encoding (void);
+  int GetFD (void);
   static void MakeWeak (Persistent<Value> _, void *data);
   void CallTopCallback (const int argc, Handle<Value> argv[]);
   Persistent<Object> handle_;
@@ -197,36 +201,65 @@ File::~File ()
 }
 
 File*
-File::Unwrap (Handle<Object> obj)
+File::Unwrap (Handle<Object> handle)
 {
   HandleScope scope;
-  Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
+  Handle<External> field = Handle<External>::Cast(handle->GetInternalField(0));
   File* file = static_cast<File*>(field->Value());
   return file;
 }
 
-void
-File::MakeWeak (Persistent<Value> _, void *data)
+bool
+File::HasUtf8Encoding (void)
 {
-  File *file = static_cast<File*> (data);
-  delete file;
+  return false;
 }
 
 int
-File::AfterClose (eio_req *req)
+File::GetFD (void)
 {
-  File *file = static_cast<File*>(req->data);
+  Handle<Value> fd_value = handle_->Get(FD_SYMBOL);
+  int fd = fd_value->IntegerValue();
+}
 
-  if (req->result == 0) {
-    file->handle_->Delete(FD_SYMBOL);
+void
+File::CallTopCallback (const int argc, Handle<Value> argv[])
+{
+  HandleScope scope;
+
+  Local<Value> queue_value = handle_->Get(ACTION_QUEUE_SYMBOL);
+  assert(queue_value->IsArray());
+
+  Local<Array> queue = Local<Array>::Cast(queue_value);
+  Local<Value> top_value = queue->Get(Integer::New(0));
+  if (top_value->IsObject()) {
+    Local<Object> top = top_value->ToObject();
+    Local<Value> callback_value = top->Get(String::NewSymbol("callback"));
+    if (callback_value->IsFunction()) {
+      Handle<Function> callback = Handle<Function>::Cast(callback_value);
+
+      TryCatch try_catch;
+      callback->Call(handle_, argc, argv);
+      if(try_catch.HasCaught()) {
+        node_fatal_exception(try_catch);
+        return;
+      }
+    }
   }
 
-  const int argc = 1;
-  Local<Value> argv[argc];
-  argv[0] = Integer::New(req->errorno);
-  file->CallTopCallback(argc, argv);
+  // poll_actions
+  Local<Value> poll_actions_value = handle_->Get(String::NewSymbol("_pollActions"));
+  assert(poll_actions_value->IsFunction());  
+  Handle<Function> poll_actions = Handle<Function>::Cast(poll_actions_value);
 
-  return 0;
+  poll_actions->Call(handle_, 0, NULL);
+}
+
+void
+File::MakeWeak (Persistent<Value> _, void *data)
+{
+  File *file = static_cast<File*> (data);
+  delete file;
 }
 
 Handle<Value>
@@ -236,8 +269,7 @@ File::Close (const Arguments& args)
 
   File *file = File::Unwrap(args.Holder());  
 
-  Handle<Value> fd_value = file->handle_->Get(FD_SYMBOL);
-  int fd = fd_value->IntegerValue();
+  int fd = file->GetFD();
 
   eio_req *req = eio_close (fd, EIO_PRI_DEFAULT, File::AfterClose, file);
   node_eio_submit(req);
@@ -246,17 +278,16 @@ File::Close (const Arguments& args)
 }
 
 int
-File::AfterOpen (eio_req *req)
+File::AfterClose (eio_req *req)
 {
   File *file = static_cast<File*>(req->data);
-  HandleScope scope;
 
-  if(req->result >= 0) {
-    file->handle_->Set(FD_SYMBOL, Integer::New(req->result));
+  if (req->result == 0) {
+    file->handle_->Delete(FD_SYMBOL);
   }
 
   const int argc = 1;
-  Handle<Value> argv[argc];
+  Local<Value> argv[argc];
   argv[0] = Integer::New(req->errorno);
   file->CallTopCallback(argc, argv);
 
@@ -310,55 +341,19 @@ File::Open (const Arguments& args)
   return Undefined();
 }
 
-void
-File::CallTopCallback (const int argc, Handle<Value> argv[])
-{
-  HandleScope scope;
-
-  Local<Value> queue_value = handle_->Get(ACTION_QUEUE_SYMBOL);
-  assert(queue_value->IsArray());
-
-  Local<Array> queue = Local<Array>::Cast(queue_value);
-  Local<Value> top_value = queue->Get(Integer::New(0));
-  if (top_value->IsObject()) {
-    Local<Object> top = top_value->ToObject();
-    Local<Value> callback_value = top->Get(String::NewSymbol("callback"));
-    if (callback_value->IsFunction()) {
-      Handle<Function> callback = Handle<Function>::Cast(callback_value);
-
-      TryCatch try_catch;
-      callback->Call(handle_, argc, argv);
-      if(try_catch.HasCaught()) {
-        node_fatal_exception(try_catch);
-        return;
-      }
-    }
-  }
-
-  // poll_actions
-  Local<Value> poll_actions_value = handle_->Get(String::NewSymbol("_pollActions"));
-  assert(poll_actions_value->IsFunction());  
-  Handle<Function> poll_actions = Handle<Function>::Cast(poll_actions_value);
-
-  poll_actions->Call(handle_, 0, NULL);
-}
-
-
 int
-File::AfterWrite (eio_req *req)
+File::AfterOpen (eio_req *req)
 {
   File *file = static_cast<File*>(req->data);
-
-  char *buf = static_cast<char*>(req->ptr2);
-  delete buf;
-  size_t written = req->result;
-
   HandleScope scope;
 
-  const int argc = 2;
-  Local<Value> argv[argc];
+  if(req->result >= 0) {
+    file->handle_->Set(FD_SYMBOL, Integer::New(req->result));
+  }
+
+  const int argc = 1;
+  Handle<Value> argv[argc];
   argv[0] = Integer::New(req->errorno);
-  argv[1] = written >= 0 ? Integer::New(written) : Integer::New(0);
   file->CallTopCallback(argc, argv);
 
   return 0;
@@ -403,8 +398,8 @@ File::Write (const Arguments& args)
     printf("trying to write to a bad fd!\n");  
     return Undefined();
   }
-  Handle<Value> fd_value = file->handle_->Get(FD_SYMBOL);
-  int fd = fd_value->IntegerValue();
+
+  int fd = file->GetFD();
 
   // NOTE: -1 offset in eio_write() invokes write() instead of pwrite()
   eio_req *req = eio_write(fd, buf, length, -1, EIO_PRI_DEFAULT, File::AfterWrite, file);
@@ -413,6 +408,76 @@ File::Write (const Arguments& args)
   return Undefined();
 }
 
+int
+File::AfterWrite (eio_req *req)
+{
+  File *file = static_cast<File*>(req->data);
+
+  char *buf = static_cast<char*>(req->ptr2);
+  delete buf;
+  size_t written = req->result;
+
+  HandleScope scope;
+
+  const int argc = 2;
+  Local<Value> argv[argc];
+  argv[0] = Integer::New(req->errorno);
+  argv[1] = written >= 0 ? Integer::New(written) : Integer::New(0);
+  file->CallTopCallback(argc, argv);
+
+  return 0;
+}
+
+Handle<Value>
+File::Read (const Arguments& args)
+{
+  if (args.Length() < 1) return Undefined();
+  if (!args[0]->IsNumber()) return Undefined();
+
+  HandleScope scope;
+  File *file = File::Unwrap(args.Holder());
+  size_t length = args[0]->IntegerValue();
+
+  int fd = file->GetFD();
+
+  // NOTE: -1 offset in eio_read() invokes read() instead of pread()
+  //       NULL pointer tells eio to allocate it itself
+  eio_req *req = eio_read(fd, NULL, length, -1, EIO_PRI_DEFAULT, File::AfterRead, file);
+  node_eio_submit(req);
+
+  return Undefined();
+}
+
+int
+File::AfterRead (eio_req *req)
+{
+  File *file = static_cast<File*>(req->data);
+  HandleScope scope;
+
+  const int argc = 2;
+  Local<Value> argv[argc];
+  argv[0] = Integer::New(req->errorno);
+
+  Local<String> buffer;
+  size_t length = req->result;
+  char *buf = static_cast<char*>(req->ptr2);
+
+  if (file->HasUtf8Encoding()) {
+    argv[1] = String::New(buf, req->result);
+  } else {
+    // raw encoding
+    Local<Array> array = Array::New(length);
+    for (int i = 0; i < length; i++) {
+      array->Set(Integer::New(i), Integer::New(buf[i]));
+    }
+    argv[1] = array;
+  }
+
+  file->CallTopCallback(argc, argv);
+
+  return 0;
+}
+
 static Handle<Value>
 NewFile (const Arguments& args)
 {
@@ -452,4 +517,5 @@ NodeInit_file (Handle<Object> target)
   JS_SET_METHOD(file_template->InstanceTemplate(), "_ffi_open", File::Open);
   JS_SET_METHOD(file_template->InstanceTemplate(), "_ffi_close", File::Close);
   JS_SET_METHOD(file_template->InstanceTemplate(), "_ffi_write", File::Write);
+  JS_SET_METHOD(file_template->InstanceTemplate(), "_ffi_read", File::Read);
 }
index 8bd0045..b291fc7 100644 (file)
@@ -37,6 +37,10 @@ File.prototype.write = function (buf, callback) {
   this._addAction("write", [buf], callback);
 };
 
+File.prototype.read = function (length, callback) {
+  this._addAction("read", [length], callback);
+};
+
 File.prototype._addAction = function (method, args, callback) {
   this._actionQueue.push({ method: method 
                          , callback: callback
@@ -63,3 +67,9 @@ stdout.fd = File.STDOUT_FILENO;
 
 var stderr = new File();
 stderr.fd = File.STDERR_FILENO;
+
+
+
+Array.prototype.encodeUtf8 = function () {
+  return String.fromCharCode.apply(String, this);
+}
index 15de1b1..28968ea 100644 (file)
@@ -10,6 +10,7 @@
 #define JS_SET_METHOD(obj, name, callback) \
   obj->Set(JS_SYMBOL(name), v8::FunctionTemplate::New(callback)->GetFunction())
 
+enum encoding {UTF8, RAW};
 
 void node_fatal_exception (v8::TryCatch &try_catch); 
 #define node_loop() ev_default_loop(0)
index 0440065..7179d6c 100644 (file)
@@ -1,18 +1,18 @@
 var f = new File;
 
-f.open("/tmp/world", "a+", function (status) {
+f.open("/tmp/world", "r+", function (status) {
   if (status == 0) {
     stdout.puts("file open");
-    f.write("hello world\n", function (status, written) {
-
-      stdout.puts("written. status: " 
-                 + status.toString() 
-                 + " written: " 
-                 + written.toString()
-                 );
-      f.close();
+    f.write("hello world\n")
+    f.write("something else.\n", function () {
+      stdout.puts("written. ");
+    });
+    f.read(100, function (status, buf) {
+      stdout.puts("read: >>" + buf.encodeUtf8() + "<<");
     });
   } else {
     stdout.puts("file open failed: " + status.toString());
   }
+
+  f.close(function () { stdout.puts("closed.") });
 });