Index: EcnlProtoTool/trunk/mrbgems/.project
===================================================================
--- EcnlProtoTool/trunk/mrbgems/.project	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/.project	(revision 279)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>mrbgems</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+	</buildSpec>
+	<natures>
+	</natures>
+</projectDescription>
Index: EcnlProtoTool/trunk/mrbgems/mruby-dir/.gitignore
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-dir/.gitignore	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-dir/.gitignore	(revision 279)
@@ -0,0 +1,5 @@
+gem_*
+gem-*
+mrb-*.a
+src/*.o
+/tmp
Index: EcnlProtoTool/trunk/mrbgems/mruby-dir/.travis.yml
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-dir/.travis.yml	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-dir/.travis.yml	(revision 279)
@@ -0,0 +1,2 @@
+script:
+  - "ruby run_test.rb all test"
Index: EcnlProtoTool/trunk/mrbgems/mruby-dir/README.md
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-dir/README.md	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-dir/README.md	(revision 279)
@@ -0,0 +1,56 @@
+mruby-dir
+=========
+
+Dir class for mruby.  Supported methods are:
+
+`.chdir`
+`.delete`
+`.entries`
+`.exist?`
+`.foreach`
+`.getwd`
+`.mkdir`
+`.open`
+`#close`
+`#each`
+`#read`
+`#rewind`
+`#seek`
+`#tell`
+
+
+## License
+
+Copyright (c) 2012 Internet Initiative Japan Inc.
+
+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 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.
+
+
+- On Windows platforms, you must agree on addional license too:
+
+Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose is hereby granted without fee, provided
+that this copyright and permissions notice appear in all copies and
+derivatives.
+
+This software is supplied "as is" without express or implied warranty.
+
+But that said, if there are any problems please get in touch.
Index: EcnlProtoTool/trunk/mrbgems/mruby-dir/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-dir/mrbgem.rake	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-dir/mrbgem.rake	(revision 279)
@@ -0,0 +1,6 @@
+MRuby::Gem::Specification.new('mruby-dir') do |spec|
+  spec.license = 'MIT and MIT-like license'
+  spec.authors = [ 'Internet Initiative Japan Inc.', 'Kevlin Henney']
+
+  spec.cc.include_paths << "#{build.root}/src"
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-dir/mrblib/dir.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-dir/mrblib/dir.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-dir/mrblib/dir.rb	(revision 279)
@@ -0,0 +1,64 @@
+class Dir
+  def each(&block)
+    while s = self.read
+      block.call(s)
+    end
+    self
+  end
+
+  alias pos tell
+  alias pos= seek
+
+  def self.entries(path)
+    a = []
+      self.open(path) { |d|
+      while s = d.read
+        a << s
+      end
+    }
+    a
+  end
+
+  def self.foreach(path, &block)
+    if block
+      self.open(path).each { |f| block.call(f) }
+    else
+      self.open(path).each
+    end
+  end
+
+  def self.open(path, &block)
+    if block
+      d = self.new(path)
+      begin
+        block.call(d)
+      ensure
+        d.close
+      end
+    else
+      self.new(path)
+    end
+  end
+
+  def self.chdir(path, &block)
+    my = self # workaround for https://github.com/mruby/mruby/issues/1579
+    if block
+      wd = self.getwd
+      begin
+        self._chdir(path)
+        block.call(path)
+      ensure
+        my._chdir(wd)
+      end
+    else
+      self._chdir(path)
+    end
+  end
+
+  class << self
+    alias exists? exist?
+    alias pwd getwd
+    alias rmdir delete
+    alias unlink delete
+  end
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-dir/run_test.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-dir/run_test.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-dir/run_test.rb	(revision 279)
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+#
+# mrbgems test runner
+#
+
+gemname = File.basename(File.dirname(File.expand_path __FILE__))
+
+if __FILE__ == $0
+  repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby'
+  build_args = ARGV
+  build_args = ['all', 'test']  if build_args.nil? or build_args.empty?
+
+  Dir.mkdir 'tmp'  unless File.exist?('tmp')
+  unless File.exist?(dir)
+    system "git clone #{repository} #{dir}"
+  end
+
+  exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}])
+end
+
+MRuby::Build.new do |conf|
+  toolchain :gcc
+  conf.gembox 'default'
+  conf.enable_test
+
+  conf.gem File.expand_path(File.dirname(__FILE__))
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-dir/src/Win/dirent.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-dir/src/Win/dirent.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-dir/src/Win/dirent.c	(revision 279)
@@ -0,0 +1,154 @@
+/*
+
+    Implementation of POSIX directory browsing functions and types for Win32.
+
+    Author:  Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
+    History: Created March 1997. Updated June 2003 and July 2012.
+    Rights:  See end of file.
+
+*/
+
+#include <errno.h>
+#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */
+
+struct dirent
+{
+    char *d_name;
+};
+
+struct DIR
+{
+    handle_type         handle; /* -1 for failed rewind */
+    struct _finddata_t  info;
+    struct dirent       result; /* d_name null iff first time */
+    char                *name;  /* null-terminated char string */
+};
+
+typedef struct DIR DIR;
+
+DIR *opendir(const char *name)
+{
+    DIR *dir = 0;
+
+    if(name && name[0])
+    {
+        size_t base_length = strlen(name);
+        const char *all = /* search pattern must end with suitable wildcard */
+            strchr("/\\", name[base_length - 1]) ? "*" : "/*";
+
+        if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
+           (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
+        {
+            strcat(strcpy(dir->name, name), all);
+
+            if((dir->handle =
+                (handle_type) _findfirst(dir->name, &dir->info)) != -1)
+            {
+                dir->result.d_name = 0;
+            }
+            else /* rollback */
+            {
+                free(dir->name);
+                free(dir);
+                dir = 0;
+            }
+        }
+        else /* rollback */
+        {
+            free(dir);
+            dir   = 0;
+            errno = ENOMEM;
+        }
+    }
+    else
+    {
+        errno = EINVAL;
+    }
+
+    return dir;
+}
+
+int closedir(DIR *dir)
+{
+    int result = -1;
+
+    if(dir)
+    {
+        if(dir->handle != -1)
+        {
+            result = _findclose(dir->handle);
+        }
+
+        free(dir->name);
+        free(dir);
+    }
+
+    if(result == -1) /* map all errors to EBADF */
+    {
+        errno = EBADF;
+    }
+
+    return result;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+    struct dirent *result = 0;
+
+    if(dir && dir->handle != -1)
+    {
+        if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
+        {
+            result         = &dir->result;
+            result->d_name = dir->info.name;
+        }
+    }
+    else
+    {
+        errno = EBADF;
+    }
+
+    return result;
+}
+
+void rewinddir(DIR *dir)
+{
+    if(dir && dir->handle != -1)
+    {
+        _findclose(dir->handle);
+        dir->handle = (handle_type) _findfirst(dir->name, &dir->info);
+        dir->result.d_name = 0;
+    }
+    else
+    {
+        errno = EBADF;
+    }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*
+
+    Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved.
+
+    Permission to use, copy, modify, and distribute this software and its
+    documentation for any purpose is hereby granted without fee, provided
+    that this copyright and permissions notice appear in all copies and
+    derivatives.
+    
+    This software is supplied "as is" without express or implied warranty.
+
+    But that said, if there are any problems please get in touch.
+
+*/
Index: EcnlProtoTool/trunk/mrbgems/mruby-dir/src/dir.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-dir/src/dir.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-dir/src/dir.c	(revision 279)
@@ -0,0 +1,308 @@
+/*
+** dir.c - Dir
+**
+** See Copyright Notice in mruby.h
+*/
+
+#include "mruby.h"
+#include "mruby/class.h"
+#include "mruby/data.h"
+#include "mruby/string.h"
+#include "error.h"
+#include <sys/types.h>
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(MUSL_LIBC)
+  #define MAXPATHLEN 1024
+ #if !defined(PATH_MAX)
+  #define PATH_MAX MAX_PATH
+ #endif
+  #define S_ISDIR(B) ((B)&_S_IFDIR)
+  #include "Win/dirent.c"
+  #include <direct.h>
+  #define rmdir _rmdir
+  #define getcwd _getcwd
+  #define mkdir _mkdir
+  #define chdir _chdir
+#elif defined(__NEWLIB__)
+  #include <sys/param.h>
+  #include "_dirent.h"
+  #include <unistd.h>
+#else
+  #include <sys/param.h>
+  #include <dirent.h>
+  #include <unistd.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+
+/* with/without IO module */
+#ifdef ENABLE_IO
+#include "mruby/ext/io.h"
+#else
+#define E_IO_ERROR E_RUNTIME_ERROR
+#endif
+
+struct mrb_dir {
+  DIR *dir;
+};
+
+void
+mrb_dir_free(mrb_state *mrb, void *ptr)
+{
+  struct mrb_dir *mdir = (struct mrb_dir *)ptr;
+
+  if (mdir->dir) {
+    closedir(mdir->dir);
+    mdir->dir = NULL;
+  }
+  mrb_free(mrb, mdir);
+}
+
+static struct mrb_data_type mrb_dir_type = { "DIR", mrb_dir_free };
+
+mrb_value
+mrb_dir_close(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_dir *mdir;
+  mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type);
+  if (!mdir) return mrb_nil_value();
+  if (!mdir->dir) {
+    mrb_raise(mrb, E_IO_ERROR, "closed directory");
+  }
+  if (closedir(mdir->dir) == -1) {
+    mrb_sys_fail(mrb, "closedir");
+  }
+  mdir->dir = NULL;
+  return mrb_nil_value();
+}
+
+mrb_value
+mrb_dir_init(mrb_state *mrb, mrb_value self)
+{
+  DIR *dir;
+  struct mrb_dir *mdir;
+  mrb_value path;
+  char *cpath;
+
+  mdir = (struct mrb_dir *)DATA_PTR(self);
+  if (mdir) {
+    mrb_dir_free(mrb, mdir);
+  }
+  DATA_TYPE(self) = &mrb_dir_type;
+  DATA_PTR(self) = NULL;
+
+  mdir = (struct mrb_dir *)mrb_malloc(mrb, sizeof(*mdir));
+  mdir->dir = NULL;
+  DATA_PTR(self) = mdir;
+
+  mrb_get_args(mrb, "S", &path);
+  cpath = mrb_str_to_cstr(mrb, path);
+  if ((dir = opendir(cpath)) == NULL) {
+    mrb_sys_fail(mrb, cpath);
+  }
+  mdir->dir = dir;
+  return self;
+}
+
+mrb_value
+mrb_dir_delete(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value path;
+  char *cpath;
+
+  mrb_get_args(mrb, "S", &path);
+  cpath = mrb_str_to_cstr(mrb, path);
+  if (rmdir(cpath) == -1) {
+    mrb_sys_fail(mrb, cpath);
+  }
+  return mrb_fixnum_value(0);
+}
+
+mrb_value
+mrb_dir_existp(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value path;
+  struct stat sb;
+  char *cpath;
+
+  mrb_get_args(mrb, "S", &path);
+  cpath = mrb_str_to_cstr(mrb, path);
+  if (stat(cpath, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+    return mrb_true_value();
+  } else {
+    return mrb_false_value();
+  }
+}
+
+mrb_value
+mrb_dir_getwd(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value path;
+
+  path = mrb_str_buf_new(mrb, MAXPATHLEN);
+  if (getcwd(RSTRING_PTR(path), MAXPATHLEN) == NULL) {
+    mrb_sys_fail(mrb, "getcwd(2)");
+  }
+  mrb_str_resize(mrb, path, strlen(RSTRING_PTR(path)));
+  return path;
+}
+
+mrb_value
+mrb_dir_mkdir(mrb_state *mrb, mrb_value klass)
+{
+  mrb_int mode;
+  mrb_value spath;
+  char *path;
+
+  mode = 0777;
+  mrb_get_args(mrb, "S|i", &spath, &mode);
+  path = mrb_str_to_cstr(mrb, spath);
+#if (!defined(_WIN32) && !defined(_WIN64)) || defined(MUSL_LIBC)
+  if (mkdir(path, mode) == -1) {
+#else
+  if (mkdir(path) == -1) {
+#endif
+    mrb_sys_fail(mrb, path);
+  }
+  return mrb_fixnum_value(0);
+}
+
+mrb_value
+mrb_dir_chdir(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value spath;
+  char *path;
+
+  mrb_get_args(mrb, "S", &spath);
+  path = mrb_str_to_cstr(mrb, spath);
+  if (chdir(path) == -1) {
+    mrb_sys_fail(mrb, path);
+  }
+  return mrb_fixnum_value(0);
+}
+
+mrb_value
+mrb_dir_chroot(mrb_state *mrb, mrb_value self)
+{
+  #if defined(_WIN32) || defined(_WIN64) || defined(__android__)
+  mrb_raise(mrb, E_NOTIMP_ERROR, "chroot() unreliable on Win platforms");
+  return mrb_fixnum_value(0);
+  #else
+  mrb_value spath;
+  char *path;
+  int res;
+
+  mrb_get_args(mrb, "S", &spath);
+  path = mrb_str_to_cstr(mrb, spath);
+  res = chroot(path);
+  if (res == -1) {
+    mrb_sys_fail(mrb, path);
+  }
+
+  return mrb_fixnum_value(res);
+  #endif
+}
+
+mrb_value
+mrb_dir_read(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_dir *mdir;
+  struct dirent *dp;
+
+  mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type);
+  if (!mdir) return mrb_nil_value();
+  if (!mdir->dir) {
+    mrb_raise(mrb, E_IO_ERROR, "closed directory");
+  }
+  dp = readdir(mdir->dir);
+  if (dp != NULL) {
+    return mrb_str_new_cstr(mrb, dp->d_name);
+  } else {
+    return mrb_nil_value();
+  }
+}
+
+mrb_value
+mrb_dir_rewind(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_dir *mdir;
+
+  mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type);
+  if (!mdir) return mrb_nil_value();
+  if (!mdir->dir) {
+    mrb_raise(mrb, E_IO_ERROR, "closed directory");
+  }
+  rewinddir(mdir->dir);
+  return self;
+}
+
+mrb_value
+mrb_dir_seek(mrb_state *mrb, mrb_value self)
+{
+  #if defined(_WIN32) || defined(_WIN64) || defined(__android__)
+  mrb_raise(mrb, E_NOTIMP_ERROR, "dirseek() unreliable on Win platforms");
+  return self;
+  #else
+  struct mrb_dir *mdir;
+  mrb_int pos;
+
+  mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type);
+  if (!mdir) return mrb_nil_value();
+  if (!mdir->dir) {
+    mrb_raise(mrb, E_IO_ERROR, "closed directory");
+  }
+  mrb_get_args(mrb, "i", &pos);
+  seekdir(mdir->dir, (long)pos);
+  return self;
+  #endif
+}
+
+mrb_value
+mrb_dir_tell(mrb_state *mrb, mrb_value self)
+{
+  #if defined(_WIN32) || defined(_WIN64) || defined(__android__)
+  mrb_raise(mrb, E_NOTIMP_ERROR, "dirtell() unreliable on Win platforms");
+  return mrb_fixnum_value(0);
+  #else
+  struct mrb_dir *mdir;
+  mrb_int pos;
+
+  mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type);
+  if (!mdir) return mrb_nil_value();
+  if (!mdir->dir) {
+    mrb_raise(mrb, E_IO_ERROR, "closed directory");
+  }
+  pos = (mrb_int)telldir(mdir->dir);
+  return mrb_fixnum_value(pos);
+  #endif
+}
+
+void
+mrb_mruby_dir_gem_init(mrb_state *mrb)
+{
+  struct RClass *d;
+
+  d = mrb_define_class(mrb, "Dir", mrb->object_class);
+  MRB_SET_INSTANCE_TT(d, MRB_TT_DATA);
+  mrb_define_class_method(mrb, d, "delete", mrb_dir_delete, MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, d, "exist?", mrb_dir_existp, MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, d, "getwd",  mrb_dir_getwd,  MRB_ARGS_NONE());
+  mrb_define_class_method(mrb, d, "mkdir",  mrb_dir_mkdir,  MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  mrb_define_class_method(mrb, d, "_chdir", mrb_dir_chdir,  MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, d, "chroot", mrb_dir_chroot, MRB_ARGS_REQ(1));
+
+  mrb_define_method(mrb, d, "close",      mrb_dir_close,  MRB_ARGS_NONE());
+  mrb_define_method(mrb, d, "initialize", mrb_dir_init,   MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, d, "read",       mrb_dir_read,   MRB_ARGS_NONE());
+  mrb_define_method(mrb, d, "rewind",     mrb_dir_rewind, MRB_ARGS_NONE());
+  mrb_define_method(mrb, d, "seek",       mrb_dir_seek,   MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, d, "tell",       mrb_dir_tell,   MRB_ARGS_NONE());
+}
+
+void
+mrb_mruby_dir_gem_final(mrb_state *mrb)
+{
+}
Index: EcnlProtoTool/trunk/mrbgems/mruby-dir/test/dir.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-dir/test/dir.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-dir/test/dir.rb	(revision 279)
@@ -0,0 +1,136 @@
+assert('Dir') do
+  assert_equal(Class, Dir.class)
+end
+
+assert('DirTest.setup') do
+  DirTest.setup
+end
+
+assert('Dir.chdir') do
+  assert_equal 0, Dir.chdir(DirTest.sandbox)
+end
+
+assert('Dir.entries') do
+  a = Dir.entries(DirTest.sandbox)
+  assert_true a.include? "a"
+  assert_true a.include? "b"
+end
+
+assert('Dir.exist?') do
+  assert_true Dir.exist?(DirTest.sandbox)
+  assert_false Dir.exist?(DirTest.sandbox + "/nosuchdir")
+end
+
+assert('Dir.foreach') do
+  a = []
+  Dir.foreach(DirTest.sandbox) { |s| a << s }
+  assert_true a.include? "a"
+  assert_true a.include? "b"
+end
+
+assert('Dir.getwd') do
+  s = Dir.getwd
+  assert_true s.kind_of? String
+end
+
+assert('Dir.mkdir') do
+  m1 = DirTest.sandbox + "/mkdir1"
+  m2 = DirTest.sandbox + "/mkdir2"
+  assert_equal 0, Dir.mkdir(m1)
+  assert_equal 0, Dir.mkdir(m2, 0765)
+end
+
+assert('Dir.delete') do
+  s = DirTest.sandbox + "/delete"
+  Dir.mkdir(s)
+  assert_true Dir.exist?(s)
+
+  Dir.delete(s)
+  assert_false Dir.exist?(s)
+end
+
+assert('Dir.open') do
+  a = []
+  Dir.open(DirTest.sandbox) { |d|
+    d.each { |s| a << s }
+  }
+  assert_true a.include? "a"
+  assert_true a.include? "b"
+end
+
+assert('Dir#initialize and Dir#close') do
+  d = Dir.new(".")
+  assert_true d.instance_of? Dir
+  assert_nil d.close
+end
+
+assert('Dir#close') do
+  d = Dir.new(".")
+end
+
+assert('Dir#each') do
+  a = []
+  d = Dir.open(DirTest.sandbox)
+  d.each { |s| a << s }
+  d.close
+  assert_true a.include? "a"
+  assert_true a.include? "b"
+end
+
+assert('Dir#read') do
+  a = []
+  d = Dir.open(DirTest.sandbox)
+  while s = d.read
+    a << s
+  end
+  d.close
+  assert_true a.include? "a"
+  assert_true a.include? "b"
+end
+
+assert('Dir#rewind') do
+  d = Dir.open(DirTest.sandbox)
+  while d.read; end
+
+  assert_equal d, d.rewind
+
+  a = []
+  while s = d.read
+    a << s
+  end
+  d.close
+  assert_true a.include? "a"
+  assert_true a.include? "b"
+end
+
+# Note: behaviors of seekdir(3) and telldir(3) are so platform-dependent
+# that we cannot write portable tests here.
+
+assert('Dir#tell') do
+  n = nil
+  begin
+    Dir.open(DirTest.sandbox) { |d|
+      n = d.tell
+    }
+    assert_true n.is_a? Integer
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert('Dir#seek') do
+  d1 = Dir.open(DirTest.sandbox)
+  d1.read
+  begin
+    n = d1.tell
+    d1.read
+    d2 = d1.seek(n)
+    assert_equal d1, d2
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert('DirTest.teardown') do
+  DirTest.teardown
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-dir/test/dirtest.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-dir/test/dirtest.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-dir/test/dirtest.c	(revision 279)
@@ -0,0 +1,129 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <unistd.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mruby.h"
+#include "mruby/string.h"
+#include "mruby/variable.h"
+
+
+mrb_value
+mrb_dirtest_setup(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value s;
+  char buf[1024];
+  const char *aname = "a";
+  const char *bname = "b";
+
+  /* save current working directory */
+  if (getcwd(buf, sizeof(buf)) == NULL) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "getcwd() failed");
+  }
+  mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "pwd"), mrb_str_new_cstr(mrb, buf));
+
+  /* create sandbox */
+#if defined(_WIN32) || defined(_WIN64)
+  snprintf(buf, sizeof(buf), "%s\\mruby-dir-test.XXXXXX", _getcwd(NULL,0));
+  if ((mktemp(buf) == NULL) || mkdir(buf) != 0) {
+    mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdtemp(%S) failed", mrb_str_new_cstr(mrb, buf));
+  }
+#else
+  snprintf(buf, sizeof(buf), "%s/mruby-dir-test.XXXXXX", P_tmpdir);
+  if (mkdtemp(buf) == NULL) {
+    mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdtemp(%S) failed", mrb_str_new_cstr(mrb, buf));
+  }
+#endif
+  s = mrb_str_new_cstr(mrb, buf);
+  mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "sandbox"), s);
+
+  /* go to sandbox */
+  if (chdir(buf) == -1) {
+    rmdir(buf);
+    mrb_raisef(mrb, E_RUNTIME_ERROR, "chdir(%S) failed", s);
+  }
+  
+  /* make some directories in the sandbox */
+#if defined(_WIN32) || defined(_WIN64)
+  if (mkdir(aname) == -1) {
+#else
+  if (mkdir(aname, 0) == -1) {
+#endif
+    chdir("..");
+    rmdir(buf);
+    mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdir(%S) failed", mrb_str_new_cstr(mrb, aname));
+  }
+#if defined(_WIN32) || defined(_WIN64)
+  if (mkdir(bname) == -1) {
+#else
+  if (mkdir(bname, 0) == -1) {
+#endif
+    rmdir(aname);
+    chdir("..");
+    rmdir(buf);
+    mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdir(%S) failed", mrb_str_new_cstr(mrb, bname));
+  }
+
+  return mrb_true_value();
+}
+
+mrb_value
+mrb_dirtest_teardown(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value d, sandbox;
+  DIR *dirp;
+  struct dirent *dp;
+  const char *path;
+
+  /* cleanup sandbox */
+  sandbox = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "sandbox"));
+  path = mrb_str_to_cstr(mrb, sandbox);
+
+  dirp = opendir(path);
+  while ((dp = readdir(dirp)) != NULL) {
+    if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
+      continue;
+    if (rmdir(dp->d_name) == -1) {
+      mrb_raisef(mrb, E_RUNTIME_ERROR, "rmdir(%S) failed", mrb_str_new_cstr(mrb, dp->d_name));
+    }
+  }
+  closedir(dirp);
+
+  /* back to original pwd */
+  d = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "pwd"));
+  path = mrb_str_to_cstr(mrb, d);
+  if (chdir(path) == -1) {
+    mrb_raisef(mrb, E_RUNTIME_ERROR, "chdir(%S) failed", d);
+  }
+
+  /* remove sandbox directory */
+  sandbox = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "sandbox"));
+  path = mrb_str_to_cstr(mrb, sandbox);
+  if (rmdir(path) == -1) {
+    mrb_raisef(mrb, E_RUNTIME_ERROR, "rmdir(%S) failed", sandbox);
+  }
+
+  return mrb_true_value();
+}
+
+mrb_value
+mrb_dirtest_sandbox(mrb_state *mrb, mrb_value klass)
+{
+  return mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "sandbox"));
+}
+
+void
+mrb_mruby_dir_gem_test(mrb_state *mrb)
+{
+  struct RClass *c = mrb_define_module(mrb, "DirTest");
+
+  mrb_define_class_method(mrb, c, "sandbox", mrb_dirtest_sandbox, MRB_ARGS_NONE());
+  mrb_define_class_method(mrb, c, "setup", mrb_dirtest_setup, MRB_ARGS_NONE());
+  mrb_define_class_method(mrb, c, "teardown", mrb_dirtest_teardown, MRB_ARGS_NONE());
+}
+
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/.gitignore
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/.gitignore	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/.gitignore	(revision 279)
@@ -0,0 +1,1 @@
+/tmp
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/.travis.yml
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/.travis.yml	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/.travis.yml	(revision 279)
@@ -0,0 +1,2 @@
+script:
+  - "ruby run_test.rb all test"
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/README.md
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/README.md	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/README.md	(revision 279)
@@ -0,0 +1,191 @@
+mruby-io
+========
+
+IO, File module for mruby
+
+## Installation
+Add the line below to your `build_config.rb`:
+
+```
+  conf.gem :github => 'iij/mruby-io'
+```
+
+## Implemented methods
+
+### IO
+ - http://doc.ruby-lang.org/ja/1.9.3/class/IO.html
+
+| method                     | mruby-io | memo |
+| -------------------------  | -------- | ---- |
+| IO.binread                 |          |      |
+| IO.binwrite                |          |      |
+| IO.copy_stream             |          |      |
+| IO.new, IO.for_fd, IO.open |  o  |     |
+| IO.foreach                 |          |      |
+| IO.pipe                    |    o     |      |
+| IO.popen                   |    o     |      |
+| IO.read                    |    o     |      |
+| IO.readlines               |          |      |
+| IO.select                  |    o     |      |
+| IO.sysopen                 |    o     |      |
+| IO.try_convert             |          |      |
+| IO.write                   |          |      |
+| IO#<<                      |          |      |
+| IO#advise                  |          |      |
+| IO#autoclose=              |          |      |
+| IO#autoclose?              |          |      |
+| IO#binmode                 |          |      |
+| IO#binmode?                |          |      |
+| IO#bytes                   |          | obsolete |
+| IO#chars                   |          | obsolete |
+| IO#clone, IO#dup           |          |      |
+| IO#close                   |    o     |      |
+| IO#close_on_exec=          |    o     |      |
+| IO#close_on_exec?          |    o     |      |
+| IO#close_read              |          |      |
+| IO#close_write             |          |      |
+| IO#closed?                 |    o     |      |
+| IO#codepoints              |          | obsolete |
+| IO#each_byte               |    o     |      |
+| IO#each_char               |    o     |      |
+| IO#each_codepoint          |          |      |
+| IO#each_line               |    o     |      |
+| IO#eof, IO#eof?            |    o     |      |
+| IO#external_encoding       |          |      |
+| IO#fcntl                   |          |      |
+| IO#fdatasync               |          |      |
+| IO#fileno, IO#to_i         |    o     |      |
+| IO#flush                   |    o     |      |
+| IO#fsync                   |          |      |
+| IO#getbyte                 |          |      |
+| IO#getc                    |    o     |      |
+| IO#gets                    |    o     |      |
+| IO#internal_encoding       |          |      |
+| IO#ioctl                   |          |      |
+| IO#isatty, IO#tty?         |          |      |
+| IO#lineno                  |          |      |
+| IO#lineno=                 |          |      |
+| IO#lines                   |          | obsolete |
+| IO#pid                     |    o     |      |
+| IO#pos, IO#tell            |    o     |      |
+| IO#pos=                    |    o     |      |
+| IO#print                   |    o     |      |
+| IO#printf                  |    o     |      |
+| IO#putc                    |          |      |
+| IO#puts                    |    o     |      |
+| IO#read                    |    o     |      |
+| IO#read_nonblock           |          |      |
+| IO#readbyte                |          |      |
+| IO#readchar                |    o     |      |
+| IO#readline                |    o     |      |
+| IO#readlines               |    o     |      |
+| IO#readpartial             |          |      |
+| IO#reopen                  |          |      |
+| IO#rewind                  |          |      |
+| IO#seek                    |    o     |      |
+| IO#set_encoding            |          |      |
+| IO#stat                    |          |      |
+| IO#sync                    |    o     |      |
+| IO#sync=                   |    o     |      |
+| IO#sysread                 |    o     |      |
+| IO#sysseek                 |    o     |      |
+| IO#syswrite                |    o     |      |
+| IO#to_io                   |          |      |
+| IO#ungetbyte               |          |      |
+| IO#ungetc                  |    o     |      |
+| IO#write                   |    o     |      |
+| IO#write_nonblock          |          |      |
+
+### File
+ - http://doc.ruby-lang.org/ja/1.9.3/class/File.html
+
+| method                      | mruby-io | memo |
+| --------------------------- | -------- | ---- |
+| File.absolute_path          |          |      |
+| File.atime                  |          |      |
+| File.basename               |   o      |      |
+| File.blockdev?              |          | FileTest |
+| File.chardev?               |          | FileTest |
+| File.chmod                  |          |      |
+| File.chown                  |          |      |
+| File.ctime                  |          |      |
+| File.delete, File.unlink    |   o      |      |
+| File.directory?             |   o      | FileTest |
+| File.dirname                |   o      |      |
+| File.executable?            |          | FileTest |
+| File.executable_real?       |          | FileTest |
+| File.exist?, exists?        |   o      | FileTest |
+| File.expand_path            |   o      |      |
+| File.extname                |   o      |      |
+| File.file?                  |   o      | FileTest |
+| File.fnmatch, File.fnmatch? |          |      |
+| File.ftype                  |          |      |
+| File.grpowned?              |          | FileTest |
+| File.identical?             |          | FileTest |
+| File.join                   |   o      |      |
+| File.lchmod                 |          |      |
+| File.lchown                 |          |      |
+| File.link                   |          |      |
+| File.lstat                  |          |      |
+| File.mtime                  |          |      |
+| File.new, File.open         |   o      |      |
+| File.owned?                 |          | FileTest |
+| File.path                   |          |      |
+| File.pipe?                  |   o      | FileTest |
+| File.readable?              |          | FileTest |
+| File.readable_real?         |          | FileTest |
+| File.readlink               |          |      |
+| File.realdirpath            |          |      |
+| File.realpath               |   o      |      |
+| File.rename                 |   o      |      |
+| File.setgid?                |          | FileTest |
+| File.setuid?                |          | FileTest |
+| File.size                   |   o      |      |
+| File.size?                  |   o      | FileTest |
+| File.socket?                |   o      | FileTest |
+| File.split                  |          |      |
+| File.stat                   |          |      |
+| File.sticky?                |          | FileTest |
+| File.symlink                |          |      |
+| File.symlink?               |   o      | FileTest |
+| File.truncate               |          |      |
+| File.umask                  |   o      |      |
+| File.utime                  |          |      |
+| File.world_readable?        |          |      |
+| File.world_writable?        |          |      |
+| File.writable?              |          | FileTest |
+| File.writable_real?         |          | FileTest |
+| File.zero?                  |   o      | FileTest |
+| File#atime                  |          |      |
+| File#chmod                  |          |      |
+| File#chown                  |          |      |
+| File#ctime                  |          |      |
+| File#flock                  |   o      |      |
+| File#lstat                  |          |      |
+| File#mtime                  |          |      |
+| File#path, File#to_path     |   o      |      |
+| File#size                   |          |      |
+| File#truncate               |          |      |
+
+
+## License
+
+Copyright (c) 2013 Internet Initiative Japan Inc.
+
+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 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.
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/include/mruby/ext/io.h
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/include/mruby/ext/io.h	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/include/mruby/ext/io.h	(revision 279)
@@ -0,0 +1,37 @@
+/*
+** io.h - IO class
+*/
+
+#ifndef MRUBY_IO_H
+#define MRUBY_IO_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct mrb_io {
+  int fd;   /* file descriptor, or -1 */
+  int fd2;  /* file descriptor to write if it's different from fd, or -1 */
+  int pid;  /* child's pid (for pipes)  */
+  unsigned int readable:1,
+               writable:1,
+               sync:1;
+};
+
+#define FMODE_READABLE             0x00000001
+#define FMODE_WRITABLE             0x00000002
+#define FMODE_READWRITE            (FMODE_READABLE|FMODE_WRITABLE)
+#define FMODE_BINMODE              0x00000004
+#define FMODE_APPEND               0x00000040
+#define FMODE_CREATE               0x00000080
+#define FMODE_TRUNC                0x00000800
+
+#define E_IO_ERROR                 (mrb_class_get(mrb, "IOError"))
+#define E_EOF_ERROR                (mrb_class_get(mrb, "EOFError"))
+
+mrb_value mrb_io_fileno(mrb_state *mrb, mrb_value io);
+
+#if defined(__cplusplus)
+} /* extern "C" { */
+#endif
+#endif /* MRUBY_IO_H */
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/mrbgem.rake	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/mrbgem.rake	(revision 279)
@@ -0,0 +1,16 @@
+MRuby::Gem::Specification.new('mruby-io') do |spec|
+  spec.license = 'MIT'
+  spec.authors = 'Internet Initiative Japan Inc.'
+
+  spec.cc.include_paths << "#{build.root}/src"
+  
+  case RUBY_PLATFORM
+  when /mingw|mswin/
+    spec.linker.libraries += ['Ws2_32']
+    #spec.cc.include_paths += ["C:/Windows/system/include"]
+    spec.linker.library_paths += ["C:/Windows/system"]
+  end
+  if build.kind_of?(MRuby::CrossBuild) && %w(x86_64-w64-mingw32 i686-w64-mingw32).include?(build.host_target)
+    spec.linker.libraries += ['ws2_32']
+  end
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/file.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/file.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/file.rb	(revision 279)
@@ -0,0 +1,208 @@
+class File < IO
+  class FileError < Exception; end
+  class NoFileError < FileError; end
+  class UnableToStat < FileError; end
+  class PermissionError < FileError; end
+
+  attr_accessor :path
+
+  def initialize(fd_or_path, mode = "r", perm = 0666)
+    if fd_or_path.kind_of? Fixnum
+      super(fd_or_path, mode)
+    else
+      @path = fd_or_path
+      fd = IO.sysopen(@path, mode, perm)
+      super(fd, mode)
+    end
+  end
+
+  def self.join(*names)
+    return "" if names.empty?
+
+    names.map! do |name|
+      case name
+      when String
+        name
+      when Array
+        if names == name
+          raise ArgumentError, "recursive array"
+        end
+        join(*name)
+      else
+        raise TypeError, "no implicit conversion of #{name.class} into String"
+      end
+    end
+
+    return names[0] if names.size == 1
+
+    if names[0][-1] == File::SEPARATOR
+      s = names[0][0..-2]
+    else
+      s = names[0].dup
+    end
+
+    (1..names.size-2).each { |i|
+      t = names[i]
+      if t[0] == File::SEPARATOR and t[-1] == File::SEPARATOR
+        t = t[1..-2]
+      elsif t[0] == File::SEPARATOR
+        t = t[1..-1]
+      elsif t[-1] == File::SEPARATOR
+        t = t[0..-2]
+      end
+      s += File::SEPARATOR + t if t != ""
+    }
+    if names[-1][0] == File::SEPARATOR
+      s += File::SEPARATOR + names[-1][1..-1]
+    else
+      s += File::SEPARATOR + names[-1]
+    end
+    s
+  end
+
+  def self.expand_path(path, default_dir = '.')
+    def concat_path(path, base_path)
+      if path[0] == "/" || path[1] == ':' # Windows root!
+        expanded_path = path
+      elsif path[0] == "~"
+        if (path[1] == "/" || path[1] == nil)
+          dir = path[1, path.size]
+          home_dir = _gethome
+
+          unless home_dir
+            raise ArgumentError, "couldn't find HOME environment -- expanding '~'"
+          end
+
+          expanded_path = home_dir
+          expanded_path += dir if dir
+          expanded_path += "/"
+        else
+          splitted_path = path.split("/")
+          user = splitted_path[0][1, splitted_path[0].size]
+          dir = "/" + splitted_path[1, splitted_path.size].join("/")
+
+          home_dir = _gethome(user)
+
+          unless home_dir
+            raise ArgumentError, "user #{user} doesn't exist"
+          end
+
+          expanded_path = home_dir
+          expanded_path += dir if dir
+          expanded_path += "/"
+        end
+      else
+        expanded_path = concat_path(base_path, _getwd)
+        expanded_path += "/" + path
+      end
+
+      expanded_path
+    end
+
+    expanded_path = concat_path(path, default_dir)
+    drive_prefix = ""
+    if File::ALT_SEPARATOR && expanded_path.size > 2 &&
+        ("A".."Z").include?(expanded_path[0].upcase) && expanded_path[1] == ":"
+      drive_prefix = expanded_path[0, 2]
+      expanded_path = expanded_path[2, expanded_path.size]
+    end
+    expand_path_array = []
+    if File::ALT_SEPARATOR && expanded_path.include?(File::ALT_SEPARATOR)
+      expanded_path.gsub!(File::ALT_SEPARATOR, '/')
+    end
+    while expanded_path.include?('//')
+      expanded_path = expanded_path.gsub('//', '/')
+    end
+
+    if expanded_path != "/"
+      expanded_path.split('/').each do |path_token|
+        if path_token == '..'
+          if expand_path_array.size > 1
+            expand_path_array.pop
+          end
+        elsif path_token == '.'
+          # nothing to do.
+        else
+          expand_path_array << path_token
+        end
+      end
+
+      expanded_path = expand_path_array.join("/")
+      if expanded_path.empty?
+        expanded_path = '/'
+      end
+    end
+    if drive_prefix.empty?
+      expanded_path
+    else
+      drive_prefix + expanded_path.gsub("/", File::ALT_SEPARATOR)
+    end
+  end
+
+  def self.foreach(file)
+    if block_given?
+      self.open(file) do |f|
+        f.each {|l| yield l}
+      end
+    else
+      return self.new(file)
+    end
+  end
+
+  def self.directory?(file)
+    FileTest.directory?(file)
+  end
+
+  def self.exist?(file)
+    FileTest.exist?(file)
+  end
+
+  def self.exists?(file)
+    FileTest.exists?(file)
+  end
+
+  def self.file?(file)
+    FileTest.file?(file)
+  end
+
+  def self.pipe?(file)
+    FileTest.pipe?(file)
+  end
+
+  def self.size(file)
+    FileTest.size(file)
+  end
+
+  def self.size?(file)
+    FileTest.size?(file)
+  end
+
+  def self.socket?(file)
+    FileTest.socket?(file)
+  end
+
+  def self.symlink?(file)
+    FileTest.symlink?(file)
+  end
+
+  def self.zero?(file)
+    FileTest.zero?(file)
+  end
+
+  def self.extname(filename)
+    fname = self.basename(filename)
+    return '' if fname[0] == '.' || fname.index('.').nil?
+    ext = fname.split('.').last
+    ext.empty? ? '' : ".#{ext}"
+  end
+
+  def self.path(filename)
+    if filename.kind_of?(String)
+      filename
+    elsif filename.respond_to?(:to_path)
+      filename.to_path
+    else
+      raise TypeError, "no implicit conversion of #{filename.class} into String"
+    end
+  end
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/file_constants.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/file_constants.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/file_constants.rb	(revision 279)
@@ -0,0 +1,29 @@
+class File
+  module Constants
+    RDONLY   = 0
+    WRONLY   = 1
+    RDWR     = 2
+    NONBLOCK = 4
+    APPEND   = 8
+
+    BINARY   = 0
+    SYNC     = 128
+    NOFOLLOW = 256
+    CREAT    = 512
+    TRUNC    = 1024
+    EXCL     = 2048
+
+    NOCTTY   = 131072
+    DSYNC    = 4194304
+
+    FNM_SYSCASE  = 0
+    FNM_NOESCAPE = 1
+    FNM_PATHNAME = 2
+    FNM_DOTMATCH = 4
+    FNM_CASEFOLD = 8
+  end
+end
+
+class File
+  include File::Constants
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/io.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/io.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/io.rb	(revision 279)
@@ -0,0 +1,393 @@
+##
+# IO
+
+class IOError < StandardError; end
+class EOFError < IOError; end
+
+class IO
+  SEEK_SET = 0
+  SEEK_CUR = 1
+  SEEK_END = 2
+
+  BUF_SIZE = 4096
+
+  def self.open(*args, &block)
+    io = self.new(*args)
+
+    return io unless block
+
+    begin
+      yield io
+    ensure
+      begin
+        io.close unless io.closed?
+      rescue StandardError
+      end
+    end
+  end
+
+  def self.popen(command, mode = 'r', opts={}, &block)
+    if !self.respond_to?(:_popen)
+      raise NotImplementedError, "popen is not supported on this platform"
+    end
+    io = self._popen(command, mode, opts)
+    return io unless block
+
+    begin
+      yield io
+    ensure
+      begin
+        io.close unless io.closed?
+      rescue IOError
+        # nothing
+      end
+    end
+  end
+
+  def self.pipe(&block)
+    if !self.respond_to?(:_pipe)
+      raise NotImplementedError, "pipe is not supported on this platform"
+    end
+    if block
+      begin
+        r, w = IO._pipe
+        yield r, w
+      ensure
+        r.close unless r.closed?
+        w.close unless w.closed?
+      end
+    else
+      IO._pipe
+    end
+  end
+
+  def self.read(path, length=nil, offset=nil, opt=nil)
+    if not opt.nil?        # 4 arguments
+      offset ||= 0
+    elsif not offset.nil?  # 3 arguments
+      if offset.is_a? Hash
+        opt = offset
+        offset = 0
+      else
+        opt = {}
+      end
+    elsif not length.nil?  # 2 arguments
+      if length.is_a? Hash
+        opt = length
+        offset = 0
+        length = nil
+      else
+        offset = 0
+        opt = {}
+      end
+    else                   # only 1 argument
+      opt = {}
+      offset = 0
+      length = nil
+    end
+
+    str = ""
+    fd = -1
+    io = nil
+    begin
+      if path[0] == "|"
+        io = IO.popen(path[1..-1], (opt[:mode] || "r"))
+      else
+        fd = IO.sysopen(path)
+        io = IO.open(fd, opt[:mode] || "r")
+      end
+      io.seek(offset) if offset > 0
+      str = io.read(length)
+    ensure
+      if io
+        io.close
+      elsif fd != -1
+        IO._sysclose(fd)
+      end
+    end
+    str
+  end
+
+  def flush
+    # mruby-io always writes immediately (no output buffer).
+    raise IOError, "closed stream" if self.closed?
+    self
+  end
+
+  def hash
+    # We must define IO#hash here because IO includes Enumerable and
+    # Enumerable#hash will call IO#read...
+    self.__id__
+  end
+
+  def write(string)
+    str = string.is_a?(String) ? string : string.to_s
+    return str.size unless str.size > 0
+
+    len = syswrite(str)
+    if len != -1
+      @pos += len
+      return len
+    end
+
+    raise IOError
+  end
+
+  def <<(str)
+    write(str)
+    self
+  end
+
+  def eof?
+    _check_readable
+    begin
+      buf = _read_buf
+      return buf.size == 0
+    rescue EOFError
+      return true
+    end
+  end
+  alias_method :eof, :eof?
+
+  def pos
+    raise IOError if closed?
+    @pos
+  end
+  alias_method :tell, :pos
+
+  def pos=(i)
+    seek(i, SEEK_SET)
+  end
+
+  def rewind
+    seek(0, SEEK_SET)
+  end
+
+  def seek(i, whence = SEEK_SET)
+    raise IOError if closed?
+    @pos = sysseek(i, whence)
+    @buf = ''
+    0
+  end
+
+  def _read_buf
+    return @buf if @buf && @buf.size > 0
+    @buf = sysread(BUF_SIZE)
+  end
+
+  def ungetc(substr)
+    raise TypeError.new "expect String, got #{substr.class}" unless substr.is_a?(String)
+    @pos -= substr.size
+    if @buf.empty?
+      @buf = substr.dup
+    else
+      @buf = substr + @buf
+    end
+    nil
+  end
+
+  def read(length = nil)
+    unless length.nil?
+      unless length.is_a? Fixnum
+        raise TypeError.new "can't convert #{length.class} into Integer"
+      end
+      if length < 0
+        raise ArgumentError.new "negative length: #{length} given"
+      end
+      if length == 0
+        return ""   # easy case
+      end
+    end
+
+    array = []
+    start_pos = @pos
+    while 1
+      begin
+        _read_buf
+      rescue EOFError => e
+        array = nil if array.empty? and (not length.nil?) and length != 0
+        break
+      end
+
+      if length && (@pos - start_pos + @buf.size) >= length
+        len = length - (@pos - start_pos)
+        array.push @buf[0, len]
+        @pos += len
+        @buf = @buf[len, @buf.size - len]
+        break
+      else
+        array.push @buf
+        @pos += @buf.size
+        @buf = ''
+      end
+    end
+
+    array && array.join
+  end
+
+  def readline(arg = $/, limit = nil)
+    case arg
+    when String
+      rs = arg
+    when Fixnum
+      rs = $/
+      limit = arg
+    else
+      raise ArgumentError
+    end
+
+    if rs.nil?
+      return read
+    end
+
+    if rs == ""
+      rs = $/ + $/
+    end
+
+    array = []
+    start_pos = @pos
+    while 1
+      begin
+        _read_buf
+      rescue EOFError => e
+        array = nil if array.empty?
+        break
+      end
+
+      if limit && (@pos - start_pos + @buf.size) >= limit
+        len = limit - (@pos - start_pos)
+        array.push @buf[0, len]
+        @pos += len
+        @buf = @buf[len, @buf.size - len]
+        break
+      elsif idx = @buf.index(rs)
+        len = idx + rs.size
+        array.push @buf[0, len]
+        @pos += len
+        @buf = @buf[len, @buf.size - len]
+        break
+      else
+        array.push @buf
+        @pos += @buf.size
+        @buf = ''
+      end
+    end
+
+    raise EOFError.new "end of file reached" if array.nil?
+
+    array.join
+  end
+
+  def gets(*args)
+    begin
+      readline(*args)
+    rescue EOFError => e
+      nil
+    end
+  end
+
+  def readchar
+    _read_buf
+    c = @buf[0]
+    @buf = @buf[1, @buf.size]
+    @pos += 1
+    c
+  end
+
+  def getc
+    begin
+      readchar
+    rescue EOFError => e
+      nil
+    end
+  end
+
+  # 15.2.20.5.3
+  def each(&block)
+    while line = self.gets
+      block.call(line)
+    end
+    self
+  end
+
+  # 15.2.20.5.4
+  def each_byte(&block)
+    while char = self.getc
+      block.call(char)
+    end
+    self
+  end
+
+  # 15.2.20.5.5
+  alias each_line each
+
+  alias each_char each_byte
+
+  def readlines
+    ary = []
+    while (line = gets)
+      ary << line
+    end
+    ary
+  end
+
+  def puts(*args)
+    i = 0
+    len = args.size
+    while i < len
+      s = args[i].to_s
+      write s
+      write "\n" if (s[-1] != "\n")
+      i += 1
+    end
+    write "\n" if len == 0
+    nil
+  end
+
+  def print(*args)
+    i = 0
+    len = args.size
+    while i < len
+      write args[i].to_s
+      i += 1
+    end
+  end
+
+  def printf(*args)
+    write sprintf(*args)
+    nil
+  end
+
+  alias_method :to_i, :fileno
+  alias_method :tty?, :isatty
+end
+
+STDIN  = IO.open(0, "r")
+STDOUT = IO.open(1, "w")
+STDERR = IO.open(2, "w")
+
+$stdin  = STDIN
+$stdout = STDOUT
+$stderr = STDERR
+
+module Kernel
+  def print(*args)
+    $stdout.print(*args)
+  end
+
+  def puts(*args)
+    $stdout.puts(*args)
+  end
+
+  def printf(*args)
+    $stdout.printf(*args)
+  end
+
+  def gets(*args)
+    $stdin.gets(*args)
+  end
+
+  def getc(*args)
+    $stdin.getc(*args)
+  end
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/kernel.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/kernel.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/mrblib/kernel.rb	(revision 279)
@@ -0,0 +1,15 @@
+module Kernel
+  def `(cmd)
+    IO.popen(cmd) { |io| io.read }
+  end
+
+  def open(file, *rest, &block)
+    raise ArgumentError unless file.is_a?(String)
+
+    if file[0] == "|"
+      IO.popen(file[1..-1], *rest, &block)
+    else
+      File.open(file, *rest, &block)
+    end
+  end
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/run_test.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/run_test.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/run_test.rb	(revision 279)
@@ -0,0 +1,26 @@
+#!/usr/bin/env ruby
+#
+# mrbgems test runner
+#
+
+if __FILE__ == $0
+  repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby'
+  build_args = ARGV
+
+  Dir.mkdir 'tmp'  unless File.exist?('tmp')
+  unless File.exist?(dir)
+    system "git clone #{repository} #{dir}"
+  end
+
+  exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}])
+end
+
+MRuby::Build.new do |conf|
+  toolchain :gcc
+  conf.gembox 'default'
+
+  conf.gem :git => 'https://github.com/iij/mruby-env.git'
+  conf.enable_test
+
+  conf.gem File.expand_path(File.dirname(__FILE__))
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/src/file.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/src/file.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/src/file.c	(revision 279)
@@ -0,0 +1,431 @@
+/*
+** file.c - File class
+*/
+
+#include "mruby.h"
+#include "mruby/class.h"
+#include "mruby/data.h"
+#include "mruby/string.h"
+#include "mruby/ext/io.h"
+
+#if MRUBY_RELEASE_NO < 10000
+#include "error.h"
+#else
+#include "mruby/error.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <limits.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_WIN32) || defined(_WIN64)
+  #define NULL_FILE "NUL"
+  #define UNLINK _unlink
+  #define GETCWD _getcwd
+  #define CHMOD(a, b) 0
+  #define MAXPATHLEN 1024
+ #if !defined(PATH_MAX)
+  #define PATH_MAX _MAX_PATH
+ #endif
+  #define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
+  #include <direct.h>
+#else
+  #define NULL_FILE "/dev/null"
+  #include <unistd.h>
+  #define UNLINK unlink
+  #define GETCWD getcwd
+  #define CHMOD(a, b) chmod(a,b)
+  #include <sys/file.h>
+  #include <libgen.h>
+  #include <sys/param.h>
+  #include <pwd.h>
+#endif
+#if defined(__NEWLIB__)
+  #define _MAX_DIR		253
+  #define _MAX_DRIVE	2
+  #define PATH_MAX		(_MAX_DRIVE + _MAX_DIR)
+  #define MAXPATHLEN	(_MAX_DRIVE + _MAX_DIR)
+#endif
+
+#define FILE_SEPARATOR "/"
+
+#if defined(_WIN32) || defined(_WIN64)
+  #define PATH_SEPARATOR ";"
+  #define FILE_ALT_SEPARATOR "\\"
+#else
+  #define PATH_SEPARATOR ":"
+#endif
+
+#ifndef LOCK_SH
+#define LOCK_SH 1
+#endif
+#ifndef LOCK_EX
+#define LOCK_EX 2
+#endif
+#ifndef LOCK_NB
+#define LOCK_NB 4
+#endif
+#ifndef LOCK_UN
+#define LOCK_UN 8
+#endif
+
+#define STAT(p, s)        stat(p, s)
+
+
+mrb_value
+mrb_file_s_umask(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64) || defined(__NEWLIB__)
+  /* nothing to do on windows */
+  return mrb_fixnum_value(0);
+
+#else
+  mrb_int mask, omask;
+  if (mrb_get_args(mrb, "|i", &mask) == 0) {
+    omask = umask(0);
+    umask(omask);
+  } else {
+    omask = umask(mask);
+  }
+  return mrb_fixnum_value(omask);
+#endif
+}
+
+static mrb_value
+mrb_file_s_unlink(mrb_state *mrb, mrb_value obj)
+{
+  mrb_value *argv;
+  mrb_value pathv;
+  mrb_int argc, i;
+  const char *path;
+
+  mrb_get_args(mrb, "*", &argv, &argc);
+  for (i = 0; i < argc; i++) {
+    pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str");
+    path = mrb_string_value_cstr(mrb, &pathv);
+    if (UNLINK(path) < 0) {
+      mrb_sys_fail(mrb, path);
+    }
+  }
+  return mrb_fixnum_value(argc);
+}
+
+static mrb_value
+mrb_file_s_rename(mrb_state *mrb, mrb_value obj)
+{
+  mrb_value from, to;
+  const char *src, *dst;
+
+  mrb_get_args(mrb, "SS", &from, &to);
+  src = mrb_string_value_cstr(mrb, &from);
+  dst = mrb_string_value_cstr(mrb, &to);
+  if (rename(src, dst) < 0) {
+    if (CHMOD(dst, 0666) == 0 && UNLINK(dst) == 0 && rename(src, dst) == 0) {
+      return mrb_fixnum_value(0);
+    }
+    mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to)));
+  }
+  return mrb_fixnum_value(0);
+}
+
+static mrb_value
+mrb_file_dirname(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+  char dname[_MAX_DIR], vname[_MAX_DRIVE];
+  char buffer[_MAX_DRIVE + _MAX_DIR];
+  char *path;
+  size_t ridx;
+  mrb_value s;
+  mrb_get_args(mrb, "S", &s);
+  path = mrb_str_to_cstr(mrb, s);
+  _splitpath((const char*)path, vname, dname, NULL, NULL);
+  snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname);
+  ridx = strlen(buffer);
+  if (ridx == 0) {
+    strncpy(buffer, ".", 2);  /* null terminated */
+  } else if (ridx > 1) {
+    ridx--;
+    while (ridx > 0 && (buffer[ridx] == '/' || buffer[ridx] == '\\')) {
+      buffer[ridx] = '\0';  /* remove last char */
+      ridx--;
+    }
+  }
+  return mrb_str_new_cstr(mrb, buffer);
+#else
+  char *dname, *path;
+  mrb_value s;
+  mrb_get_args(mrb, "S", &s);
+  path = mrb_str_to_cstr(mrb, s);
+
+  if ((dname = dirname(path)) == NULL) {
+    mrb_sys_fail(mrb, "dirname");
+  }
+#endif
+  return mrb_str_new_cstr(mrb, dname);
+}
+
+static mrb_value
+mrb_file_basename(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+  char bname[_MAX_DIR];
+  char extname[_MAX_EXT];
+  char *path;
+  size_t ridx;
+  char buffer[_MAX_DIR + _MAX_EXT];
+  mrb_value s;
+  mrb_get_args(mrb, "S", &s);
+  path = mrb_str_to_cstr(mrb, s);
+  ridx = strlen(path);
+  if (ridx > 0) {
+    ridx--;
+    while (ridx > 0 && (path[ridx] == '/' || path[ridx] == '\\')) {
+      path[ridx] = '\0';
+      ridx--;
+    }
+    if (strncmp(path, "/", 2) == 0) {
+      return mrb_str_new_cstr(mrb, path);
+    }
+  }
+  _splitpath((const char*)path, NULL, NULL, bname, extname);
+  snprintf(buffer, _MAX_DIR + _MAX_EXT, "%s%s", bname, extname);
+  return mrb_str_new_cstr(mrb, buffer);
+#else
+  char *bname, *path;
+  mrb_value s;
+  mrb_get_args(mrb, "S", &s);
+  path = mrb_str_to_cstr(mrb, s);
+  if ((bname = basename(path)) == NULL) {
+    mrb_sys_fail(mrb, "basename");
+  }
+  return mrb_str_new_cstr(mrb, bname);
+#endif
+}
+
+static mrb_value
+mrb_file_realpath(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value pathname, dir_string, s, result;
+  int argc;
+  char *cpath;
+
+  argc = mrb_get_args(mrb, "S|S", &pathname, &dir_string);
+  if (argc == 2) {
+    s = mrb_str_dup(mrb, dir_string);
+    s = mrb_str_append(mrb, s, mrb_str_new_cstr(mrb, FILE_SEPARATOR));
+    s = mrb_str_append(mrb, s, pathname);
+    pathname = s;
+  }
+  cpath = mrb_str_to_cstr(mrb, pathname);
+  result = mrb_str_buf_new(mrb, PATH_MAX);
+  if (realpath(cpath, RSTRING_PTR(result)) == NULL)
+    mrb_sys_fail(mrb, cpath);
+  mrb_str_resize(mrb, result, strlen(RSTRING_PTR(result)));
+  return result;
+}
+
+mrb_value
+mrb_file__getwd(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value path;
+
+  path = mrb_str_buf_new(mrb, MAXPATHLEN);
+  if (GETCWD(RSTRING_PTR(path), MAXPATHLEN) == NULL) {
+    mrb_sys_fail(mrb, "getcwd(2)");
+  }
+  mrb_str_resize(mrb, path, strlen(RSTRING_PTR(path)));
+  return path;
+}
+
+static int
+mrb_file_is_absolute_path(const char *path)
+{
+  return (path[0] == '/');
+}
+
+static mrb_value
+mrb_file__gethome(mrb_state *mrb, mrb_value klass)
+{
+#if !defined(_WIN32) && !defined(_WIN64) && !defined(__NEWLIB__)
+  mrb_value username;
+  int argc;
+  char *home;
+
+  argc = mrb_get_args(mrb, "|S", &username);
+  if (argc == 0) {
+    home = getenv("HOME");
+    if (home == NULL) {
+      return mrb_nil_value();
+    }
+    if (!mrb_file_is_absolute_path(home)) {
+      mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home");
+    }
+  } else {
+    const char *cuser = mrb_str_to_cstr(mrb, username);
+    struct passwd *pwd = getpwnam(cuser);
+    if (pwd == NULL) {
+      return mrb_nil_value();
+    }
+    home = pwd->pw_dir;
+    if (!mrb_file_is_absolute_path(home)) {
+      mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%S", username);
+    }
+  }
+  return mrb_str_new_cstr(mrb, home);
+#else
+
+  return mrb_nil_value();
+#endif
+}
+
+mrb_value
+mrb_file_flock(mrb_state *mrb, mrb_value self)
+{
+#if defined(_WIN32) || defined(_WIN64) || defined(sun) || defined(__NEWLIB__)
+  mrb_raise(mrb, E_NOTIMP_ERROR, "flock is not supported on Illumos/Solaris/Windows");
+#else
+  mrb_int operation;
+  int fd;
+
+  mrb_get_args(mrb, "i", &operation);
+  fd = mrb_fixnum(mrb_io_fileno(mrb, self));
+
+  while (flock(fd, operation) == -1) {
+    switch (errno) {
+      case EINTR:
+        /* retry */
+        break;
+      case EAGAIN:      /* NetBSD */
+#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
+      case EWOULDBLOCK: /* FreeBSD OpenBSD Linux */
+#endif
+        if (operation & LOCK_NB) {
+          return mrb_false_value();
+        }
+        /* FALLTHRU - should not happen */
+      default:
+        mrb_sys_fail(mrb, "flock failed");
+        break;
+    }
+  }
+#endif
+  return mrb_fixnum_value(0);
+}
+
+static mrb_value
+mrb_file_s_symlink(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64) || defined(__NEWLIB__)
+  mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform");
+#else
+  mrb_value from, to;
+  const char *src, *dst;
+  int ai = mrb_gc_arena_save(mrb);
+
+  mrb_get_args(mrb, "SS", &from, &to);
+  src = mrb_str_to_cstr(mrb, from);
+  dst = mrb_str_to_cstr(mrb, to);
+
+  if (symlink(src, dst) == -1) {
+    mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to)));
+  }
+  mrb_gc_arena_restore(mrb, ai);
+#endif
+  return mrb_fixnum_value(0);
+}
+
+static mrb_value
+mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) {
+  mrb_int mode;
+  mrb_int argc, i;
+  mrb_value *filenames;
+  int ai = mrb_gc_arena_save(mrb);
+
+  mrb_get_args(mrb, "i*", &mode, &filenames, &argc);
+  for (i = 0; i < argc; i++) {
+    char *path = mrb_str_to_cstr(mrb, filenames[i]);
+    if (CHMOD(path, mode) == -1) {
+      mrb_sys_fail(mrb, path);
+    }
+  }
+
+  mrb_gc_arena_restore(mrb, ai);
+  return mrb_fixnum_value(argc);
+}
+
+static mrb_value
+mrb_file_s_readlink(mrb_state *mrb, mrb_value klass) {
+#if defined(_WIN32) || defined(_WIN64) || defined(__NEWLIB__)
+  mrb_raise(mrb, E_NOTIMP_ERROR, "readlink is not supported on this platform");
+  return mrb_nil_value(); // unreachable
+#else
+  char *path, *buf;
+  size_t bufsize = 100;
+  ssize_t rc;
+  mrb_value ret;
+  int ai = mrb_gc_arena_save(mrb);
+
+  mrb_get_args(mrb, "z", &path);
+
+  buf = (char *)mrb_malloc(mrb, bufsize);
+  while ((rc = readlink(path, buf, bufsize)) == bufsize && rc != -1) {
+    bufsize *= 2;
+    buf = (char *)mrb_realloc(mrb, buf, bufsize);
+  }
+  if (rc == -1) {
+    mrb_free(mrb, buf);
+    mrb_sys_fail(mrb, path);
+  }
+  ret = mrb_str_new(mrb, buf, rc);
+  mrb_free(mrb, buf);
+
+  mrb_gc_arena_restore(mrb, ai);
+  return ret;
+#endif
+}
+
+void
+mrb_init_file(mrb_state *mrb)
+{
+  struct RClass *io, *file, *cnst;
+
+  io   = mrb_class_get(mrb, "IO");
+  file = mrb_define_class(mrb, "File", io);
+  MRB_SET_INSTANCE_TT(file, MRB_TT_DATA);
+  mrb_define_class_method(mrb, file, "umask",  mrb_file_s_umask, MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, file, "delete", mrb_file_s_unlink, MRB_ARGS_ANY());
+  mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, MRB_ARGS_ANY());
+  mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, MRB_ARGS_REQ(2));
+  mrb_define_class_method(mrb, file, "symlink", mrb_file_s_symlink, MRB_ARGS_REQ(2));
+  mrb_define_class_method(mrb, file, "chmod", mrb_file_s_chmod, MRB_ARGS_REQ(1) | MRB_ARGS_REST());
+  mrb_define_class_method(mrb, file, "readlink", mrb_file_s_readlink, MRB_ARGS_REQ(1));
+
+  mrb_define_class_method(mrb, file, "dirname",   mrb_file_dirname,    MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, file, "basename",  mrb_file_basename,   MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, file, "realpath",  mrb_file_realpath,   MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  mrb_define_class_method(mrb, file, "_getwd",    mrb_file__getwd,     MRB_ARGS_NONE());
+  mrb_define_class_method(mrb, file, "_gethome",  mrb_file__gethome,   MRB_ARGS_OPT(1));
+
+  mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1));
+
+  cnst = mrb_define_module_under(mrb, file, "Constants");
+  mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH));
+  mrb_define_const(mrb, cnst, "LOCK_EX", mrb_fixnum_value(LOCK_EX));
+  mrb_define_const(mrb, cnst, "LOCK_UN", mrb_fixnum_value(LOCK_UN));
+  mrb_define_const(mrb, cnst, "LOCK_NB", mrb_fixnum_value(LOCK_NB));
+  mrb_define_const(mrb, cnst, "SEPARATOR", mrb_str_new_cstr(mrb, FILE_SEPARATOR));
+  mrb_define_const(mrb, cnst, "PATH_SEPARATOR", mrb_str_new_cstr(mrb, PATH_SEPARATOR));
+#if defined(_WIN32) || defined(_WIN64)
+  mrb_define_const(mrb, cnst, "ALT_SEPARATOR", mrb_str_new_cstr(mrb, FILE_ALT_SEPARATOR));
+#else
+  mrb_define_const(mrb, cnst, "ALT_SEPARATOR", mrb_nil_value());
+#endif
+  mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, NULL_FILE));
+
+}
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/src/file_test.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/src/file_test.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/src/file_test.c	(revision 279)
@@ -0,0 +1,378 @@
+/*
+** file.c - File class
+*/
+
+#include "mruby.h"
+#include "mruby/class.h"
+#include "mruby/data.h"
+#include "mruby/string.h"
+#include "mruby/ext/io.h"
+
+#if MRUBY_RELEASE_NO < 10000
+#include "error.h"
+#else
+#include "mruby/error.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(_WIN32) || defined(_WIN64)
+  #define LSTAT stat
+  #include <winsock.h>
+#else
+  //#define LSTAT lstat
+  #define LSTAT stat
+  #include <sys/file.h>
+  #include <sys/param.h>
+  #include <sys/wait.h>
+  #include <libgen.h>
+  #include <pwd.h>
+  #include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern struct mrb_data_type mrb_io_type;
+
+static int
+mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat)
+{
+  mrb_value tmp;
+  mrb_value io_klass, str_klass;
+
+  io_klass  = mrb_obj_value(mrb_class_get(mrb, "IO"));
+  str_klass = mrb_obj_value(mrb_class_get(mrb, "String"));
+
+  tmp = mrb_funcall(mrb, obj, "is_a?", 1, io_klass);
+  if (mrb_test(tmp)) {
+    struct mrb_io *fptr;
+    fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type);
+
+    if (fptr && fptr->fd >= 0) {
+      return fstat(fptr->fd, st);
+    }
+
+    mrb_raise(mrb, E_IO_ERROR, "closed stream");
+    return -1;
+  }
+
+  tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass);
+  if (mrb_test(tmp)) {
+    if (do_lstat) {
+      return LSTAT(mrb_str_to_cstr(mrb, obj), st);
+    } else {
+      return stat(mrb_str_to_cstr(mrb, obj), st);
+    }
+  }
+
+  return -1;
+}
+
+static int
+mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st)
+{
+  return mrb_stat0(mrb, obj, st, 0);
+}
+
+static int
+mrb_lstat(mrb_state *mrb, mrb_value obj, struct stat *st)
+{
+  return mrb_stat0(mrb, obj, st, 1);
+}
+
+/*
+ * Document-method: directory?
+ *
+ * call-seq:
+ *   File.directory?(file_name)   ->  true or false
+ *
+ * Returns <code>true</code> if the named file is a directory,
+ * or a symlink that points at a directory, and <code>false</code>
+ * otherwise.
+ *
+ *    File.directory?(".")
+ */
+
+mrb_value
+mrb_filetest_s_directory_p(mrb_state *mrb, mrb_value klass)
+{
+#ifndef S_ISDIR
+#   define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+  struct stat st;
+  mrb_value obj;
+
+  mrb_get_args(mrb, "o", &obj);
+
+  if (mrb_stat(mrb, obj, &st) < 0)
+    return mrb_false_value();
+  if (S_ISDIR(st.st_mode))
+    return mrb_true_value();
+
+  return mrb_false_value();
+}
+
+/*
+ * call-seq:
+ *   File.pipe?(file_name)   ->  true or false
+ *
+ * Returns <code>true</code> if the named file is a pipe.
+ */
+
+mrb_value
+mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+  mrb_raise(mrb, E_NOTIMP_ERROR, "pipe is not supported on this platform");
+#else
+#ifdef S_IFIFO
+#  ifndef S_ISFIFO
+#    define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#  endif
+
+  struct stat st;
+  mrb_value obj;
+
+  mrb_get_args(mrb, "o", &obj);
+
+  if (mrb_stat(mrb, obj, &st) < 0)
+    return mrb_false_value();
+  if (S_ISFIFO(st.st_mode))
+    return mrb_true_value();
+
+#endif
+  return mrb_false_value();
+#endif
+}
+
+/*
+ * call-seq:
+ *   File.symlink?(file_name)   ->  true or false
+ *
+ * Returns <code>true</code> if the named file is a symbolic link.
+ */
+
+mrb_value
+mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+  mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform");
+#else
+#ifndef S_ISLNK
+#  ifdef _S_ISLNK
+#    define S_ISLNK(m) _S_ISLNK(m)
+#  else
+#    ifdef _S_IFLNK
+#      define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK)
+#    else
+#      ifdef S_IFLNK
+#        define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef S_ISLNK
+  struct stat st;
+  mrb_value obj;
+
+  mrb_get_args(mrb, "o", &obj);
+
+  if (mrb_lstat(mrb, obj, &st) == -1)
+    return mrb_false_value();
+  if (S_ISLNK(st.st_mode))
+    return mrb_true_value();
+#endif
+
+  return mrb_false_value();
+#endif
+}
+
+/*
+ * call-seq:
+ *   File.socket?(file_name)   ->  true or false
+ *
+ * Returns <code>true</code> if the named file is a socket.
+ */
+
+mrb_value
+mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+  mrb_raise(mrb, E_NOTIMP_ERROR, "socket is not supported on this platform");
+#else
+#ifndef S_ISSOCK
+#  ifdef _S_ISSOCK
+#    define S_ISSOCK(m) _S_ISSOCK(m)
+#  else
+#    ifdef _S_IFSOCK
+#      define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
+#    else
+#      ifdef S_IFSOCK
+#        define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef S_ISSOCK
+  struct stat st;
+  mrb_value obj;
+
+  mrb_get_args(mrb, "o", &obj);
+
+  if (mrb_stat(mrb, obj, &st) < 0)
+    return mrb_false_value();
+  if (S_ISSOCK(st.st_mode))
+    return mrb_true_value();
+#endif
+
+  return mrb_false_value();
+#endif
+}
+
+/*
+ * call-seq:
+ *    File.exist?(file_name)    ->  true or false
+ *    File.exists?(file_name)   ->  true or false
+ *
+ * Return <code>true</code> if the named file exists.
+ */
+
+mrb_value
+mrb_filetest_s_exist_p(mrb_state *mrb, mrb_value klass)
+{
+  struct stat st;
+  mrb_value obj;
+
+  mrb_get_args(mrb, "o", &obj);
+  if (mrb_stat(mrb, obj, &st) < 0)
+    return mrb_false_value();
+
+  return mrb_true_value();
+}
+
+/*
+ * call-seq:
+ *    File.file?(file_name)   -> true or false
+ *
+ * Returns <code>true</code> if the named file exists and is a
+ * regular file.
+ */
+
+mrb_value
+mrb_filetest_s_file_p(mrb_state *mrb, mrb_value klass)
+{
+#ifndef S_ISREG
+#   define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+  struct stat st;
+  mrb_value obj;
+
+  mrb_get_args(mrb, "o", &obj);
+
+  if (mrb_stat(mrb, obj, &st) < 0)
+    return mrb_false_value();
+  if (S_ISREG(st.st_mode))
+    return mrb_true_value();
+
+  return mrb_false_value();
+}
+
+/*
+ * call-seq:
+ *    File.zero?(file_name)   -> true or false
+ *
+ * Returns <code>true</code> if the named file exists and has
+ * a zero size.
+ */
+
+mrb_value
+mrb_filetest_s_zero_p(mrb_state *mrb, mrb_value klass)
+{
+  struct stat st;
+  mrb_value obj;
+
+  mrb_get_args(mrb, "o", &obj);
+
+  if (mrb_stat(mrb, obj, &st) < 0)
+    return mrb_false_value();
+  if (st.st_size == 0)
+    return mrb_true_value();
+
+  return mrb_false_value();
+}
+
+/*
+ * call-seq:
+ *    File.size(file_name)   -> integer
+ *
+ * Returns the size of <code>file_name</code>.
+ *
+ * _file_name_ can be an IO object.
+ */
+
+mrb_value
+mrb_filetest_s_size(mrb_state *mrb, mrb_value klass)
+{
+  struct stat st;
+  mrb_value obj;
+
+  mrb_get_args(mrb, "o", &obj);
+
+  if (mrb_stat(mrb, obj, &st) < 0)
+    mrb_sys_fail(mrb, "mrb_stat");
+
+  return mrb_fixnum_value(st.st_size);
+}
+
+/*
+ * call-seq:
+ *    File.size?(file_name)   -> Integer or nil
+ *
+ * Returns +nil+ if +file_name+ doesn't exist or has zero size, the size of the
+ * file otherwise.
+ */
+
+mrb_value
+mrb_filetest_s_size_p(mrb_state *mrb, mrb_value klass)
+{
+  struct stat st;
+  mrb_value obj;
+
+  mrb_get_args(mrb, "o", &obj);
+
+  if (mrb_stat(mrb, obj, &st) < 0)
+    return mrb_nil_value();
+  if (st.st_size == 0)
+    return mrb_nil_value();
+
+  return mrb_fixnum_value(st.st_size);
+}
+
+void
+mrb_init_file_test(mrb_state *mrb)
+{
+  struct RClass *f;
+
+  f = mrb_define_class(mrb, "FileTest", mrb->object_class);
+
+  mrb_define_class_method(mrb, f, "directory?", mrb_filetest_s_directory_p, MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, f, "exist?",     mrb_filetest_s_exist_p,     MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, f, "exists?",    mrb_filetest_s_exist_p,     MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, f, "file?",      mrb_filetest_s_file_p,      MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, f, "pipe?",      mrb_filetest_s_pipe_p,      MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, f, "size",       mrb_filetest_s_size,        MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, f, "size?",      mrb_filetest_s_size_p,      MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, f, "socket?",    mrb_filetest_s_socket_p,    MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, f, "symlink?",   mrb_filetest_s_symlink_p,   MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, f, "zero?",      mrb_filetest_s_zero_p,      MRB_ARGS_REQ(1));
+}
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/src/io.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/src/io.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/src/io.c	(revision 279)
@@ -0,0 +1,1102 @@
+/*
+** io.c - IO class
+*/
+
+#include "mruby.h"
+#include "mruby/array.h"
+#include "mruby/class.h"
+#include "mruby/data.h"
+#include "mruby/hash.h"
+#include "mruby/string.h"
+#include "mruby/variable.h"
+#include "mruby/ext/io.h"
+
+#if MRUBY_RELEASE_NO < 10000
+#include "error.h"
+#else
+#include "mruby/error.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(_WIN32) || defined(_WIN64)
+  #include <winsock.h>
+  #include <io.h>
+  #define open  _open
+  #define close _close
+  #define read  _read
+  #define write _write
+  #define lseek _lseek
+#else
+  #include <sys/wait.h>
+  #include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static void mrb_io_free(mrb_state *mrb, void *ptr);
+struct mrb_data_type mrb_io_type = { "IO", mrb_io_free };
+
+
+static struct mrb_io *io_get_open_fptr(mrb_state *mrb, mrb_value self);
+static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr);
+static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags);
+static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet);
+
+#if MRUBY_RELEASE_NO < 10000
+static struct RClass *
+mrb_module_get(mrb_state *mrb, const char *name)
+{
+  return mrb_class_get(mrb, name);
+}
+#endif
+
+static struct mrb_io *
+io_get_open_fptr(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_io *fptr;
+
+  fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type);
+  if (fptr->fd < 0) {
+    mrb_raise(mrb, E_IO_ERROR, "closed stream.");
+  }
+  return fptr;
+}
+
+#if !defined(_WIN32) && !defined(_WIN64)
+static void
+io_set_process_status(mrb_state *mrb, pid_t pid, int status)
+{
+  struct RClass *c_process, *c_status;
+  mrb_value v;
+
+  c_status = NULL;
+  if (mrb_class_defined(mrb, "Process")) {
+    c_process = mrb_module_get(mrb, "Process");
+    if (mrb_const_defined(mrb, mrb_obj_value(c_process), mrb_intern_cstr(mrb, "Status"))) {
+      c_status = mrb_class_get_under(mrb, c_process, "Status");
+    }
+  }
+  if (c_status != NULL) {
+    v = mrb_funcall(mrb, mrb_obj_value(c_status), "new", 2, mrb_fixnum_value(pid), mrb_fixnum_value(status));
+  } else {
+    v = mrb_fixnum_value(WEXITSTATUS(status));
+  }
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$?"), v);
+}
+#endif
+
+static int
+mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode)
+{
+  int flags = 0;
+  const char *m = mode;
+
+  switch (*m++) {
+    case 'r':
+      flags |= FMODE_READABLE;
+      break;
+    case 'w':
+      flags |= FMODE_WRITABLE | FMODE_CREATE | FMODE_TRUNC;
+      break;
+    case 'a':
+      flags |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
+      break;
+    default:
+      mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode));
+  }
+
+  while (*m) {
+    switch (*m++) {
+      case 'b':
+        flags |= FMODE_BINMODE;
+        break;
+      case '+':
+        flags |= FMODE_READWRITE;
+        break;
+      case ':':
+        /* XXX: PASSTHROUGH*/
+      default:
+        mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode));
+    }
+  }
+
+  return flags;
+}
+
+static int
+mrb_io_flags_to_modenum(mrb_state *mrb, int flags)
+{
+  int modenum = 0;
+
+  switch(flags & (FMODE_READABLE|FMODE_WRITABLE|FMODE_READWRITE)) {
+    case FMODE_READABLE:
+      modenum = O_RDONLY;
+      break;
+    case FMODE_WRITABLE:
+      modenum = O_WRONLY;
+      break;
+    case FMODE_READWRITE:
+      modenum = O_RDWR;
+      break;
+  }
+
+  if (flags & FMODE_APPEND) {
+    modenum |= O_APPEND;
+  }
+  if (flags & FMODE_TRUNC) {
+    modenum |= O_TRUNC;
+  }
+  if (flags & FMODE_CREATE) {
+    modenum |= O_CREAT;
+  }
+#ifdef O_BINARY
+  if (flags & FMODE_BINMODE) {
+    modenum |= O_BINARY;
+  }
+#endif
+
+  return modenum;
+}
+
+void
+mrb_fd_cloexec(mrb_state *mrb, int fd)
+{
+#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
+  int flags, flags2;
+
+  flags = fcntl(fd, F_GETFD);
+  if (flags == -1) {
+    mrb_sys_fail(mrb, "fcntl");
+  }
+  if (fd <= 2) {
+    flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
+  }
+  else {
+    flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
+  }
+  if (flags != flags2) {
+    if (fcntl(fd, F_SETFD, flags2) == -1) {
+      mrb_sys_fail(mrb, "fcntl");
+    }
+  }
+#endif
+}
+
+#if !defined(_WIN32) && !defined(_WIN64) && !defined(__NEWLIB__)
+static int
+mrb_cloexec_pipe(mrb_state *mrb, int fildes[2])
+{
+  int ret;
+  ret = pipe(fildes);
+  if (ret == -1)
+    return -1;
+  mrb_fd_cloexec(mrb, fildes[0]);
+  mrb_fd_cloexec(mrb, fildes[1]);
+  return ret;
+}
+
+static int
+mrb_pipe(mrb_state *mrb, int pipes[2])
+{
+  int ret;
+  ret = mrb_cloexec_pipe(mrb, pipes);
+  if (ret == -1) {
+    if (errno == EMFILE || errno == ENFILE) {
+      mrb_garbage_collect(mrb);
+      ret = mrb_cloexec_pipe(mrb, pipes);
+    }
+  }
+  return ret;
+}
+
+static int
+mrb_proc_exec(const char *pname)
+{
+  const char *s;
+  s = pname;
+
+  while (*s == ' ' || *s == '\t' || *s == '\n')
+    s++;
+
+  if (!*s) {
+    errno = ENOENT;
+    return -1;
+  }
+
+  execl("/bin/sh", "sh", "-c", pname, (char *)NULL);
+  return -1;
+}
+#endif
+
+static void
+mrb_io_free(mrb_state *mrb, void *ptr)
+{
+  struct mrb_io *io = (struct mrb_io *)ptr;
+  if (io != NULL) {
+    fptr_finalize(mrb, io, TRUE);
+    mrb_free(mrb, io);
+  }
+}
+
+static struct mrb_io *
+mrb_io_alloc(mrb_state *mrb)
+{
+  struct mrb_io *fptr;
+
+  fptr = (struct mrb_io *)mrb_malloc(mrb, sizeof(struct mrb_io));
+  fptr->fd = -1;
+  fptr->fd2 = -1;
+  fptr->pid = 0;
+  fptr->readable = 0;
+  fptr->writable = 0;
+  fptr->sync = 0;
+  return fptr;
+}
+
+#ifndef NOFILE
+#define NOFILE 64
+#endif
+
+#if !defined(_WIN32) && !defined(_WIN64) && !defined(__NEWLIB__)
+static int
+option_to_fd(mrb_state *mrb, mrb_value obj, const char *key)
+{
+  mrb_value opt = mrb_funcall(mrb, obj, "[]", 1, mrb_symbol_value(mrb_intern_static(mrb, key, strlen(key))));
+  if (mrb_nil_p(opt)) {
+    return -1;
+  }
+
+  switch (mrb_type(opt)) {
+    case MRB_TT_DATA: /* IO */
+      return mrb_fixnum(mrb_io_fileno(mrb, opt));
+    case MRB_TT_FIXNUM:
+      return mrb_fixnum(opt);
+    default:
+      mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong exec redirect action");
+      break;
+  }
+  return -1; /* never reached */
+}
+
+mrb_value
+mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value cmd, io, result;
+  mrb_value mode = mrb_str_new_cstr(mrb, "r");
+  mrb_value opt  = mrb_hash_new(mrb);
+
+  struct mrb_io *fptr;
+  const char *pname;
+  int pid, flags, fd, write_fd = -1;
+  int pr[2] = { -1, -1 };
+  int pw[2] = { -1, -1 };
+  int doexec;
+  int saved_errno;
+  int opt_in, opt_out, opt_err;
+
+  mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt);
+  io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
+
+  pname = mrb_string_value_cstr(mrb, &cmd);
+  flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
+
+  doexec = (strcmp("-", pname) != 0);
+  opt_in = option_to_fd(mrb, opt, "in");
+  opt_out = option_to_fd(mrb, opt, "out");
+  opt_err = option_to_fd(mrb, opt, "err");
+
+  if (flags & FMODE_READABLE) {
+    if (pipe(pr) == -1) {
+      mrb_sys_fail(mrb, "pipe");
+    }
+    mrb_fd_cloexec(mrb, pr[0]);
+    mrb_fd_cloexec(mrb, pr[1]);
+  }
+
+  if (flags & FMODE_WRITABLE) {
+    if (pipe(pw) == -1) {
+      if (pr[0] != -1) close(pr[0]);
+      if (pr[1] != -1) close(pr[1]);
+      mrb_sys_fail(mrb, "pipe");
+    }
+    mrb_fd_cloexec(mrb, pw[0]);
+    mrb_fd_cloexec(mrb, pw[1]);
+  }
+
+  if (!doexec) {
+    // XXX
+    fflush(stdin);
+    fflush(stdout);
+    fflush(stderr);
+  }
+
+  result = mrb_nil_value();
+  switch (pid = fork()) {
+    case 0: /* child */
+      if (opt_in != -1) {
+        dup2(opt_in, 0);
+      }
+      if (opt_out != -1) {
+        dup2(opt_out, 1);
+      }
+      if (opt_err != -1) {
+        dup2(opt_err, 2);
+      }
+      if (flags & FMODE_READABLE) {
+        close(pr[0]);
+        if (pr[1] != 1) {
+          dup2(pr[1], 1);
+          close(pr[1]);
+        }
+      }
+      if (flags & FMODE_WRITABLE) {
+        close(pw[1]);
+        if (pw[0] != 0) {
+          dup2(pw[0], 0);
+          close(pw[0]);
+        }
+      }
+      if (doexec) {
+        for (fd = 3; fd < NOFILE; fd++) {
+          close(fd);
+        }
+        mrb_proc_exec(pname);
+        mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd);
+        _exit(127);
+      }
+      result = mrb_nil_value();
+      break;
+
+    default: /* parent */
+      if ((flags & FMODE_READABLE) && (flags & FMODE_WRITABLE)) {
+        close(pr[1]);
+        fd = pr[0];
+        close(pw[0]);
+        write_fd = pw[1];
+      } else if (flags & FMODE_READABLE) {
+        close(pr[1]);
+        fd = pr[0];
+      } else {
+        close(pw[0]);
+        fd = pw[1];
+      }
+
+      mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
+      mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0));
+
+      fptr = mrb_io_alloc(mrb);
+      fptr->fd = fd;
+      fptr->fd2 = write_fd;
+      fptr->pid = pid;
+      fptr->readable = ((flags & FMODE_READABLE) != 0);
+      fptr->writable = ((flags & FMODE_WRITABLE) != 0);
+      fptr->sync = 0;
+
+      DATA_TYPE(io) = &mrb_io_type;
+      DATA_PTR(io)  = fptr;
+      result = io;
+      break;
+
+    case -1: /* error */
+      saved_errno = errno;
+      if (flags & FMODE_READABLE) {
+        close(pr[0]);
+        close(pr[1]);
+      }
+      if (flags & FMODE_WRITABLE) {
+        close(pw[0]);
+        close(pw[1]);
+      }
+      errno = saved_errno;
+      mrb_sys_fail(mrb, "pipe_open failed.");
+      break;
+  }
+  return result;
+}
+#endif
+
+mrb_value
+mrb_io_initialize(mrb_state *mrb, mrb_value io)
+{
+  struct mrb_io *fptr;
+  mrb_int fd;
+  mrb_value mode, opt;
+  int flags;
+
+  mode = opt = mrb_nil_value();
+
+  mrb_get_args(mrb, "i|So", &fd, &mode, &opt);
+  if (mrb_nil_p(mode)) {
+    mode = mrb_str_new_cstr(mrb, "r");
+  }
+  if (mrb_nil_p(opt)) {
+    opt = mrb_hash_new(mrb);
+  }
+
+  flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
+
+  mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
+  mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0));
+
+  fptr = (struct mrb_io *)DATA_PTR(io);
+  if (fptr != NULL) {
+    fptr_finalize(mrb, fptr, TRUE);
+    mrb_free(mrb, fptr);
+  }
+  fptr = mrb_io_alloc(mrb);
+
+  DATA_TYPE(io) = &mrb_io_type;
+  DATA_PTR(io) = fptr;
+
+  fptr->fd = fd;
+  fptr->readable = ((flags & FMODE_READABLE) != 0);
+  fptr->writable = ((flags & FMODE_WRITABLE) != 0);
+  fptr->sync = 0;
+  return io;
+}
+
+static void
+fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet)
+{
+  int saved_errno = 0;
+
+  if (fptr == NULL) {
+    return;
+  }
+
+  if (fptr->fd > 2) {
+    if (close(fptr->fd) == -1) {
+      saved_errno = errno;
+    }
+    fptr->fd = -1;
+  }
+
+  if (fptr->fd2 > 2) {
+    if (close(fptr->fd2) == -1) {
+      if (saved_errno == 0) {
+        saved_errno = errno;
+      }
+    }
+    fptr->fd2 = -1;
+  }
+
+#if !defined(_WIN32) && !defined(_WIN64) && !defined(__NEWLIB__)
+  if (fptr->pid != 0) {
+    pid_t pid;
+    int status;
+    do {
+      pid = waitpid(fptr->pid, &status, 0);
+    } while (pid == -1 && errno == EINTR);
+    if (!quiet && pid == fptr->pid) {
+      io_set_process_status(mrb, pid, status);
+    }
+    fptr->pid = 0;
+    /* Note: we don't raise an exception when waitpid(3) fails */
+  }
+#endif
+
+  if (!quiet && saved_errno != 0) {
+    errno = saved_errno;
+    mrb_sys_fail(mrb, "fptr_finalize failed.");
+  }
+}
+
+mrb_value
+mrb_io_check_readable(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_io *fptr = io_get_open_fptr(mrb, self);
+  if (! fptr->readable) {
+    mrb_raise(mrb, E_IO_ERROR, "not opened for reading");
+  }
+  return mrb_nil_value();
+}
+
+mrb_value
+mrb_io_isatty(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_io *fptr;
+
+  fptr = io_get_open_fptr(mrb, self);
+  if (isatty(fptr->fd) == 0)
+    return mrb_false_value();
+  return mrb_true_value();
+}
+
+mrb_value
+mrb_io_s_for_fd(mrb_state *mrb, mrb_value klass)
+{
+  struct RClass *c = mrb_class_ptr(klass);
+  enum mrb_vtype ttype = MRB_INSTANCE_TT(c);
+  mrb_value obj;
+
+  /* copied from mrb_instance_alloc() */
+  if (ttype == 0) ttype = MRB_TT_OBJECT;
+  obj = mrb_obj_value((struct RObject*)mrb_obj_alloc(mrb, ttype, c));
+  return mrb_io_initialize(mrb, obj);
+}
+
+mrb_value
+mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass)
+{
+  mrb_int fd;
+  mrb_get_args(mrb, "i", &fd);
+  if (close(fd) == -1) {
+    mrb_sys_fail(mrb, "close");
+  }
+  return mrb_fixnum_value(0);
+}
+
+int
+mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode)
+{
+  int fd, retry = FALSE;
+
+#ifdef O_CLOEXEC
+  /* O_CLOEXEC is available since Linux 2.6.23.  Linux 2.6.18 silently ignore it. */
+  flags |= O_CLOEXEC;
+#elif defined O_NOINHERIT
+  flags |= O_NOINHERIT;
+#endif
+reopen:
+  fd = open(pathname, flags, mode);
+  if (fd == -1) {
+    if (!retry) {
+      switch (errno) {
+        case ENFILE:
+        case EMFILE:
+        mrb_garbage_collect(mrb);
+        retry = TRUE;
+        goto reopen;
+      }
+    }
+    mrb_sys_fail(mrb, "open");
+  }
+
+  if (fd <= 2) {
+    mrb_fd_cloexec(mrb, fd);
+  }
+  return fd;
+}
+
+mrb_value
+mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value path = mrb_nil_value();
+  mrb_value mode = mrb_nil_value();
+  mrb_int fd, flags, perm = -1;
+  const char *pat;
+  int modenum;
+
+  mrb_get_args(mrb, "S|Si", &path, &mode, &perm);
+  if (mrb_nil_p(mode)) {
+    mode = mrb_str_new_cstr(mrb, "r");
+  }
+  if (perm < 0) {
+    perm = 0666;
+  }
+
+  pat = mrb_string_value_cstr(mrb, &path);
+  flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
+  modenum = mrb_io_flags_to_modenum(mrb, flags);
+  fd = mrb_cloexec_open(mrb, pat, modenum, perm);
+  return mrb_fixnum_value(fd);
+}
+
+mrb_value
+mrb_io_sysread(mrb_state *mrb, mrb_value io)
+{
+  struct mrb_io *fptr;
+  mrb_value buf = mrb_nil_value();
+  mrb_int maxlen;
+  int ret;
+
+  mrb_get_args(mrb, "i|S", &maxlen, &buf);
+  if (maxlen < 0) {
+    return mrb_nil_value();
+  }
+
+  if (mrb_nil_p(buf)) {
+    buf = mrb_str_new(mrb, NULL, maxlen);
+  }
+  if (RSTRING_LEN(buf) != maxlen) {
+    buf = mrb_str_resize(mrb, buf, maxlen);
+  }
+
+  fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
+  ret = read(fptr->fd, RSTRING_PTR(buf), maxlen);
+  switch (ret) {
+    case 0: /* EOF */
+      if (maxlen == 0) {
+        buf = mrb_str_new_cstr(mrb, "");
+      } else {
+        mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File");
+      }
+      break;
+    case -1: /* Error */
+      mrb_sys_fail(mrb, "sysread failed");
+      break;
+    default:
+      if (RSTRING_LEN(buf) != ret) {
+        buf = mrb_str_resize(mrb, buf, ret);
+      }
+      break;
+  }
+
+  return buf;
+}
+
+mrb_value
+mrb_io_sysseek(mrb_state *mrb, mrb_value io)
+{
+  struct mrb_io *fptr;
+  off_t pos;
+  mrb_int offset, whence = -1;
+
+  mrb_get_args(mrb, "i|i", &offset, &whence);
+  if (whence < 0) {
+    whence = 0;
+  }
+
+  fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
+  pos = lseek(fptr->fd, offset, whence);
+  if (pos == -1) {
+    mrb_sys_fail(mrb, "sysseek");
+  }
+  if (pos > MRB_INT_MAX) {
+    return mrb_float_value(mrb, (mrb_float)pos);
+  } else {
+    return mrb_fixnum_value(pos);
+  }
+}
+
+mrb_value
+mrb_io_syswrite(mrb_state *mrb, mrb_value io)
+{
+  struct mrb_io *fptr;
+  mrb_value str, buf;
+  int fd, length;
+
+  fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
+  if (! fptr->writable) {
+    mrb_raise(mrb, E_IO_ERROR, "not opened for writing");
+  }
+
+  mrb_get_args(mrb, "S", &str);
+  if (mrb_type(str) != MRB_TT_STRING) {
+    buf = mrb_funcall(mrb, str, "to_s", 0);
+  } else {
+    buf = str;
+  }
+
+  if (fptr->fd2 == -1) {
+    fd = fptr->fd;
+  } else {
+    fd = fptr->fd2;
+  }
+  length = write(fd, RSTRING_PTR(buf), RSTRING_LEN(buf));
+
+  return mrb_fixnum_value(length);
+}
+
+mrb_value
+mrb_io_close(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_io *fptr;
+  fptr = io_get_open_fptr(mrb, self);
+  fptr_finalize(mrb, fptr, FALSE);
+  return mrb_nil_value();
+}
+
+mrb_value
+mrb_io_closed(mrb_state *mrb, mrb_value io)
+{
+  struct mrb_io *fptr;
+  fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
+  if (fptr->fd >= 0) {
+    return mrb_false_value();
+  }
+
+  return mrb_true_value();
+}
+
+mrb_value
+mrb_io_pid(mrb_state *mrb, mrb_value io)
+{
+  struct mrb_io *fptr;
+  fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
+
+  if (fptr->pid > 0) {
+    return mrb_fixnum_value(fptr->pid);
+  }
+
+  return mrb_nil_value();
+}
+
+static struct timeval
+time2timeval(mrb_state *mrb, mrb_value time)
+{
+  struct timeval t = { 0, 0 };
+
+  switch (mrb_type(time)) {
+    case MRB_TT_FIXNUM:
+      t.tv_sec = mrb_fixnum(time);
+      t.tv_usec = 0;
+      break;
+
+    case MRB_TT_FLOAT:
+      t.tv_sec = mrb_float(time);
+      t.tv_usec = (mrb_float(time) - t.tv_sec) * 1000000.0;
+      break;
+
+    default:
+      mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
+  }
+
+  return t;
+}
+
+static int
+mrb_io_read_data_pending(mrb_state *mrb, mrb_value io)
+{
+  mrb_value buf = mrb_iv_get(mrb, io, mrb_intern_cstr(mrb, "@buf"));
+  if (mrb_type(buf) == MRB_TT_STRING && RSTRING_LEN(buf) > 0) {
+    return 1;
+  }
+  return 0;
+}
+
+#if !defined(_WIN32) && !defined(_WIN64) && !defined(__NEWLIB__)
+static mrb_value
+mrb_io_s_pipe(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value r = mrb_nil_value();
+  mrb_value w = mrb_nil_value();
+  struct mrb_io *fptr_r;
+  struct mrb_io *fptr_w;
+  int pipes[2];
+
+  if (mrb_pipe(mrb, pipes) == -1) {
+    mrb_sys_fail(mrb, "pipe");
+  }
+
+  r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
+  mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
+  mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0));
+  fptr_r = mrb_io_alloc(mrb);
+  fptr_r->fd = pipes[0];
+  fptr_r->readable = 1;
+  fptr_r->writable = 0;
+  fptr_r->sync = 0;
+  DATA_TYPE(r) = &mrb_io_type;
+  DATA_PTR(r)  = fptr_r;
+
+  w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
+  mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
+  mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0));
+  fptr_w = mrb_io_alloc(mrb);
+  fptr_w->fd = pipes[1];
+  fptr_w->readable = 0;
+  fptr_w->writable = 1;
+  fptr_w->sync = 1;
+  DATA_TYPE(w) = &mrb_io_type;
+  DATA_PTR(w)  = fptr_w;
+
+  return mrb_assoc_new(mrb, r, w);
+}
+#endif
+
+static mrb_value
+mrb_io_s_select(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value *argv;
+  mrb_int argc;
+  mrb_value read, read_io, write, except, timeout, list;
+  struct timeval *tp, timerec;
+  fd_set pset, rset, wset, eset;
+  fd_set *rp, *wp, *ep;
+  struct mrb_io *fptr;
+  int pending = 0;
+  mrb_value result;
+  int max = 0;
+  int interrupt_flag = 0;
+  int i, n;
+
+  mrb_get_args(mrb, "*", &argv, &argc);
+
+  if (argc < 1 || argc > 4) {
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1..4)", mrb_fixnum_value(argc));
+  }
+
+  timeout = mrb_nil_value();
+  except = mrb_nil_value();
+  write = mrb_nil_value();
+  if (argc > 3)
+    timeout = argv[3];
+  if (argc > 2)
+    except = argv[2];
+  if (argc > 1)
+    write = argv[1];
+  read = argv[0];
+
+  if (mrb_nil_p(timeout)) {
+    tp = NULL;
+  } else {
+    timerec = time2timeval(mrb, timeout);
+    tp = &timerec;
+  }
+
+  FD_ZERO(&pset);
+  if (!mrb_nil_p(read)) {
+    mrb_check_type(mrb, read, MRB_TT_ARRAY);
+    rp = &rset;
+    FD_ZERO(rp);
+    for (i = 0; i < RARRAY_LEN(read); i++) {
+      read_io = RARRAY_PTR(read)[i];
+      fptr = (struct mrb_io *)mrb_get_datatype(mrb, read_io, &mrb_io_type);
+      FD_SET(fptr->fd, rp);
+      if (mrb_io_read_data_pending(mrb, read_io)) {
+        pending++;
+        FD_SET(fptr->fd, &pset);
+      }
+      if (max < fptr->fd)
+        max = fptr->fd;
+    }
+    if (pending) {
+      timerec.tv_sec = timerec.tv_usec = 0;
+      tp = &timerec;
+    }
+  } else {
+    rp = NULL;
+  }
+
+  if (!mrb_nil_p(write)) {
+    mrb_check_type(mrb, write, MRB_TT_ARRAY);
+    wp = &wset;
+    FD_ZERO(wp);
+    for (i = 0; i < RARRAY_LEN(write); i++) {
+      fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(write)[i], &mrb_io_type);
+      FD_SET(fptr->fd, wp);
+      if (max < fptr->fd)
+        max = fptr->fd;
+      if (fptr->fd2 >= 0) {
+        FD_SET(fptr->fd2, wp);
+        if (max < fptr->fd2)
+          max = fptr->fd2;
+      }
+    }
+  } else {
+    wp = NULL;
+  }
+
+  if (!mrb_nil_p(except)) {
+    mrb_check_type(mrb, except, MRB_TT_ARRAY);
+    ep = &eset;
+    FD_ZERO(ep);
+    for (i = 0; i < RARRAY_LEN(except); i++) {
+      fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(except)[i], &mrb_io_type);
+      FD_SET(fptr->fd, ep);
+      if (max < fptr->fd)
+        max = fptr->fd;
+      if (fptr->fd2 >= 0) {
+        FD_SET(fptr->fd2, ep);
+        if (max < fptr->fd2)
+          max = fptr->fd2;
+      }
+    }
+  } else {
+    ep = NULL;
+  }
+
+  max++;
+
+retry:
+  n = select(max, rp, wp, ep, tp);
+  if (n < 0) {
+    if (errno != EINTR)
+      mrb_sys_fail(mrb, "select failed");
+    if (tp == NULL)
+      goto retry;
+    interrupt_flag = 1;
+  }
+
+  if (!pending && n == 0)
+    return mrb_nil_value();
+
+  result = mrb_ary_new_capa(mrb, 3);
+  mrb_ary_push(mrb, result, rp? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0));
+  mrb_ary_push(mrb, result, wp? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0));
+  mrb_ary_push(mrb, result, ep? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0));
+
+  if (interrupt_flag == 0) {
+    if (rp) {
+      list = RARRAY_PTR(result)[0];
+      for (i = 0; i < RARRAY_LEN(read); i++) {
+        fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(read)[i], &mrb_io_type);
+        if (FD_ISSET(fptr->fd, rp) ||
+            FD_ISSET(fptr->fd, &pset)) {
+          mrb_ary_push(mrb, list, RARRAY_PTR(read)[i]);
+        }
+      }
+    }
+
+    if (wp) {
+      list = RARRAY_PTR(result)[1];
+      for (i = 0; i < RARRAY_LEN(write); i++) {
+        fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(write)[i], &mrb_io_type);
+        if (FD_ISSET(fptr->fd, wp)) {
+          mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]);
+        } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, wp)) {
+          mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]);
+        }
+      }
+    }
+
+    if (ep) {
+      list = RARRAY_PTR(result)[2];
+      for (i = 0; i < RARRAY_LEN(except); i++) {
+        fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(except)[i], &mrb_io_type);
+        if (FD_ISSET(fptr->fd, ep)) {
+          mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]);
+        } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, ep)) {
+          mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]);
+        }
+      }
+    }
+  }
+
+  return result;
+}
+
+mrb_value
+mrb_io_fileno(mrb_state *mrb, mrb_value io)
+{
+  struct mrb_io *fptr;
+  fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
+  return mrb_fixnum_value(fptr->fd);
+}
+
+mrb_value
+mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value self)
+{
+#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
+  struct mrb_io *fptr;
+  int ret;
+
+  fptr = io_get_open_fptr(mrb, self);
+
+  if (fptr->fd2 >= 0) {
+    if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
+    if (!(ret & FD_CLOEXEC)) return mrb_false_value();
+  }
+
+  if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
+  if (!(ret & FD_CLOEXEC)) return mrb_false_value();
+  return mrb_true_value();
+
+#else
+  mrb_raise(mrb, E_NOTIMP_ERROR, "IO#close_on_exec? is not supported on the platform");
+  return mrb_false_value();
+#endif
+}
+
+mrb_value
+mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value self)
+{
+#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
+  struct mrb_io *fptr;
+  int flag, ret;
+  mrb_bool b;
+
+  fptr = io_get_open_fptr(mrb, self);
+  mrb_get_args(mrb, "b", &b);
+  flag = b ? FD_CLOEXEC : 0;
+
+  if (fptr->fd2 >= 0) {
+    if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
+    if ((ret & FD_CLOEXEC) != flag) {
+      ret = (ret & ~FD_CLOEXEC) | flag;
+      ret = fcntl(fptr->fd2, F_SETFD, ret);
+
+      if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed");
+    }
+  }
+
+  if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
+  if ((ret & FD_CLOEXEC) != flag) {
+    ret = (ret & ~FD_CLOEXEC) | flag;
+    ret = fcntl(fptr->fd, F_SETFD, ret);
+    if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed");
+  }
+
+  return mrb_bool_value(b);
+#else
+  mrb_raise(mrb, E_NOTIMP_ERROR, "IO#close_on_exec= is not supported on the platform");
+  return mrb_nil_value();
+#endif
+}
+
+mrb_value
+mrb_io_set_sync(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_io *fptr;
+  mrb_bool b;
+
+  fptr = io_get_open_fptr(mrb, self);
+  mrb_get_args(mrb, "b", &b);
+  fptr->sync = b;
+  return mrb_bool_value(b);
+}
+
+mrb_value
+mrb_io_sync(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_io *fptr;
+  fptr = io_get_open_fptr(mrb, self);
+  return mrb_bool_value(fptr->sync);
+}
+
+void
+mrb_init_io(mrb_state *mrb)
+{
+  struct RClass *io;
+
+  io      = mrb_define_class(mrb, "IO", mrb->object_class);
+  MRB_SET_INSTANCE_TT(io, MRB_TT_DATA);
+
+  mrb_include_module(mrb, io, mrb_module_get(mrb, "Enumerable")); /* 15.2.20.3 */
+#if !defined(_WIN32) && !defined(_WIN64) && !defined(__NEWLIB__)
+  mrb_define_class_method(mrb, io, "_popen",  mrb_io_s_popen,   MRB_ARGS_ANY());
+  mrb_define_class_method(mrb, io, "_sysclose",  mrb_io_s_sysclose, MRB_ARGS_REQ(1));
+#endif
+  mrb_define_class_method(mrb, io, "for_fd",  mrb_io_s_for_fd,   MRB_ARGS_ANY());
+  mrb_define_class_method(mrb, io, "select",  mrb_io_s_select,  MRB_ARGS_ANY());
+  mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY());
+#if !defined(_WIN32) && !defined(_WIN64) && !defined(__NEWLIB__)
+  mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE());
+#endif
+
+  mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY());    /* 15.2.20.5.21 (x)*/
+  mrb_define_method(mrb, io, "_check_readable", mrb_io_check_readable, MRB_ARGS_NONE());
+  mrb_define_method(mrb, io, "isatty",     mrb_io_isatty,     MRB_ARGS_NONE());
+  mrb_define_method(mrb, io, "sync",       mrb_io_sync,       MRB_ARGS_NONE());
+  mrb_define_method(mrb, io, "sync=",      mrb_io_set_sync,   MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, io, "sysread",    mrb_io_sysread,    MRB_ARGS_ANY());
+  mrb_define_method(mrb, io, "sysseek",    mrb_io_sysseek,    MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, io, "syswrite",   mrb_io_syswrite,   MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, io, "close",      mrb_io_close,      MRB_ARGS_NONE());   /* 15.2.20.5.1 */
+  mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, io, "close_on_exec?", mrb_io_close_on_exec_p,   MRB_ARGS_NONE());
+  mrb_define_method(mrb, io, "closed?",    mrb_io_closed,     MRB_ARGS_NONE());   /* 15.2.20.5.2 */
+  mrb_define_method(mrb, io, "pid",        mrb_io_pid,        MRB_ARGS_NONE());   /* 15.2.20.5.2 */
+  mrb_define_method(mrb, io, "fileno",     mrb_io_fileno,     MRB_ARGS_NONE());
+
+
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n"));
+}
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/src/mruby_io_gem.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/src/mruby_io_gem.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/src/mruby_io_gem.c	(revision 279)
@@ -0,0 +1,20 @@
+#include "mruby.h"
+
+void mrb_init_io(mrb_state *mrb);
+void mrb_init_file(mrb_state *mrb);
+void mrb_init_file_test(mrb_state *mrb);
+
+#define DONE mrb_gc_arena_restore(mrb, 0)
+
+void
+mrb_mruby_io_gem_init(mrb_state* mrb)
+{
+  mrb_init_io(mrb); DONE;
+  mrb_init_file(mrb); DONE;
+  mrb_init_file_test(mrb); DONE;
+}
+
+void
+mrb_mruby_io_gem_final(mrb_state* mrb)
+{
+}
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/test/file.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/test/file.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/test/file.rb	(revision 279)
@@ -0,0 +1,188 @@
+##
+# IO Test
+
+assert('File', '15.2.21') do
+  File.class == Class
+end
+
+assert('File', '15.2.21.2') do
+  File.superclass == IO
+end
+
+assert('File TEST SETUP') do
+  MRubyIOTestUtil.io_test_setup
+end
+
+assert('File#initialize', '15.2.21.4.1') do
+  io = File.open($mrbtest_io_rfname, "r")
+  assert_nil io.close
+  assert_raise IOError do
+    io.close
+  end
+end
+
+assert('File#path', '15.2.21.4.2') do
+  io = File.open($mrbtest_io_rfname, "r")
+  assert_equal $mrbtest_io_msg, io.read
+  assert_equal $mrbtest_io_rfname, io.path
+  io.close
+  assert_equal $mrbtest_io_rfname, io.path
+  io.closed?
+end
+
+assert('File.basename') do
+  assert_equal '/', File.basename('//')
+  assert_equal 'a', File.basename('/a/')
+  assert_equal 'b', File.basename('/a/b')
+  assert_equal 'b', File.basename('../a/b')
+end
+
+assert('File.dirname') do
+  assert_equal '.',    File.dirname('')
+  assert_equal '.',    File.dirname('a')
+  assert_equal '/',    File.dirname('/a')
+  assert_equal 'a',    File.dirname('a/b')
+  assert_equal '/a',   File.dirname('/a/b')
+end
+
+assert('File.extname') do
+  assert_equal '.txt', File.extname('foo/foo.txt')
+  assert_equal '.gz',  File.extname('foo/foo.tar.gz')
+  assert_equal '', File.extname('foo/bar')
+  assert_equal '', File.extname('foo/.bar')
+  assert_equal '', File.extname('foo.txt/bar')
+  assert_equal '', File.extname('.foo')
+end
+
+assert('IO#flock') do
+  f = File.open $mrbtest_io_rfname
+  begin
+    assert_equal(f.flock(File::LOCK_SH), 0)
+    assert_equal(f.flock(File::LOCK_UN), 0)
+    assert_equal(f.flock(File::LOCK_EX | File::LOCK_NB), 0)
+    assert_equal(f.flock(File::LOCK_UN), 0)
+  rescue NotImplementedError => e
+    skip e.message
+  ensure
+    f.close
+  end
+end
+
+assert('File.join') do
+  assert_equal "", File.join()
+  assert_equal "a", File.join("a")
+  assert_equal "/a", File.join("/a")
+  assert_equal "a/", File.join("a/")
+  assert_equal "a/b/c", File.join("a", "b", "c")
+  assert_equal "/a/b/c", File.join("/a", "b", "c")
+  assert_equal "a/b/c/", File.join("a", "b", "c/")
+  assert_equal "a/b/c", File.join("a/", "/b/", "/c")
+  assert_equal "a/b/c", File.join(["a", "b", "c"])
+  assert_equal "a/b/c", File.join("a", ["b", ["c"]])
+end
+
+assert('File.realpath') do
+  if File::ALT_SEPARATOR
+    readme_path = File._getwd + File::ALT_SEPARATOR + "README.md"
+    assert_equal readme_path, File.realpath("README.md")
+  else
+    dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX")
+    begin
+      dir1 = File.realpath($mrbtest_io_rfname)
+      dir2 = File.realpath("./#{dir}//./../#{$mrbtest_io_symlinkname}")
+      assert_equal dir1, dir2
+    ensure
+      MRubyIOTestUtil.rmdir dir
+    end
+  end
+end
+
+assert("File.readlink") do
+  begin
+    assert_equal $mrbtest_io_rfname, File.readlink($mrbtest_io_symlinkname)
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert("File.readlink fails with non-symlink") do
+  begin
+    assert_raise(RuntimeError) {
+      begin
+        File.readlink($mrbtest_io_rfname)
+      rescue => e
+        if Object.const_defined?(:SystemCallError) and e.kind_of?(SystemCallError)
+          raise RuntimeError, "SystemCallError converted to RuntimeError"
+        end
+        raise e
+      end
+    }
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert('File TEST CLEANUP') do
+  assert_nil MRubyIOTestUtil.io_test_cleanup
+end
+
+assert('File.expand_path') do
+  assert_equal "/",    File.expand_path("..", "/tmp"),       "parent path with base_dir (1)"
+  assert_equal "/tmp", File.expand_path("..", "/tmp/mruby"), "parent path with base_dir (2)"
+
+  assert_equal "/home", File.expand_path("/home"),      "absolute"
+  assert_equal "/home", File.expand_path("/home", "."), "absolute with base_dir"
+
+  assert_equal "/hoge", File.expand_path("/tmp/..//hoge")
+  assert_equal "/hoge", File.expand_path("////tmp/..///////hoge")
+
+  assert_equal "/", File.expand_path("../../../..", "/")
+  if File._getwd[1] == ":"
+    drive_letter = File._getwd[0]
+    assert_equal drive_letter + ":\\", File.expand_path(([".."] * 100).join("/"))
+  else
+    assert_equal "/", File.expand_path(([".."] * 100).join("/"))
+  end
+end
+
+assert('File.expand_path (with ENV)') do
+  skip unless Object.const_defined?(:ENV) && ENV['HOME']
+
+  assert_equal ENV['HOME'], File.expand_path("~/"),      "home"
+  assert_equal ENV['HOME'], File.expand_path("~/", "/"), "home with base_dir"
+
+  assert_equal "#{ENV['HOME']}/user", File.expand_path("user", ENV['HOME']), "relative with base_dir"
+end
+
+assert('File.path') do
+  assert_equal "", File.path("")
+  assert_equal "a/b/c", File.path("a/b/c")
+  assert_equal "a/../b/./c", File.path("a/../b/./c")
+  assert_raise(TypeError) { File.path(nil) }
+  assert_raise(TypeError) { File.path(123) }
+
+end
+
+assert('File.symlink') do
+  target_name = "/usr/bin"
+  symlink_name = "test-bin-dummy"
+  if !File.exist?(target_name)
+    skip("target directory of File.symlink is not found")
+  else
+    assert_equal 0, File.symlink(target_name, symlink_name)
+    begin
+      assert_equal true, File.symlink?(symlink_name)
+    ensure
+      File.delete symlink_name
+    end
+  end
+end
+
+assert('File.chmod') do
+  File.open('chmod-test', 'w') {}
+  begin
+    assert_equal 1, File.chmod(0400, 'chmod-test')
+  ensure
+    File.delete('chmod-test')
+  end
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/test/file_test.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/test/file_test.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/test/file_test.rb	(revision 279)
@@ -0,0 +1,117 @@
+##
+# FileTest
+
+assert('FileTest TEST SETUP') do
+  MRubyIOTestUtil.io_test_setup
+end
+
+assert("FileTest.directory?") do
+  dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX")
+  begin
+    assert_true  FileTest.directory?(dir)
+    assert_false FileTest.directory?($mrbtest_io_rfname)
+  ensure
+    MRubyIOTestUtil.rmdir dir
+  end
+end
+
+assert("FileTest.exist?") do
+  assert_equal true,  FileTest.exist?($mrbtest_io_rfname), "filename - exist"
+  assert_equal false, FileTest.exist?($mrbtest_io_rfname + "-"), "filename - not exist"
+  io = IO.new(IO.sysopen($mrbtest_io_rfname))
+  assert_equal true,  FileTest.exist?(io), "io obj - exist"
+  io.close
+  assert_equal true, io.closed?
+  assert_raise IOError do
+    FileTest.exist?(io)
+  end
+end
+
+assert("FileTest.file?") do
+  dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX")
+  begin
+    assert_true  FileTest.file?($mrbtest_io_rfname)
+    assert_false FileTest.file?(dir)
+  ensure
+    MRubyIOTestUtil.rmdir dir
+  end
+end
+
+assert("FileTest.pipe?") do
+  begin
+    assert_equal false, FileTest.pipe?("/tmp")
+    io = IO.popen("ls")
+    assert_equal true,  FileTest.pipe?(io)
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert('FileTest.size') do
+  assert_equal FileTest.size($mrbtest_io_rfname), $mrbtest_io_msg.size
+  assert_equal FileTest.size($mrbtest_io_wfname), 0
+end
+
+assert("FileTest.size?") do
+  assert_equal $mrbtest_io_msg.size, FileTest.size?($mrbtest_io_rfname)
+  assert_equal nil, FileTest.size?($mrbtest_io_wfname)
+  assert_equal nil, FileTest.size?("not-exist-test-target-file")
+
+  fp1 = File.open($mrbtest_io_rfname)
+  fp2 = File.open($mrbtest_io_wfname)
+  assert_equal $mrbtest_io_msg.size,  FileTest.size?(fp1)
+  assert_equal nil, FileTest.size?(fp2)
+  fp1.close
+  fp2.close
+
+  assert_raise IOError do
+    FileTest.size?(fp1)
+  end
+  assert_raise IOError do
+    FileTest.size?(fp2)
+  end
+
+  fp1.closed? && fp2.closed?
+end
+
+assert("FileTest.socket?") do
+  begin
+    assert_true FileTest.socket?($mrbtest_io_socketname)
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert("FileTest.symlink?") do
+  begin
+    assert_true FileTest.symlink?($mrbtest_io_symlinkname)
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert("FileTest.zero?") do
+  assert_equal false, FileTest.zero?($mrbtest_io_rfname)
+  assert_equal true,  FileTest.zero?($mrbtest_io_wfname)
+  assert_equal false, FileTest.zero?("not-exist-test-target-file")
+
+  fp1 = File.open($mrbtest_io_rfname)
+  fp2 = File.open($mrbtest_io_wfname)
+  assert_equal false, FileTest.zero?(fp1)
+  assert_equal true,  FileTest.zero?(fp2)
+  fp1.close
+  fp2.close
+
+  assert_raise IOError do
+    FileTest.zero?(fp1)
+  end
+  assert_raise IOError do
+    FileTest.zero?(fp2)
+  end
+
+  fp1.closed? && fp2.closed?
+end
+
+assert('FileTest TEST CLEANUP') do
+  assert_nil MRubyIOTestUtil.io_test_cleanup
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/test/gc_filedes.sh
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/test/gc_filedes.sh	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/test/gc_filedes.sh	(revision 279)
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+ulimit -n 20
+mruby -e '100.times { File.open "'$0'" }'
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/test/io.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/test/io.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/test/io.rb	(revision 279)
@@ -0,0 +1,578 @@
+##
+# IO Test
+
+unless Object.respond_to? :assert_nothing_raised
+  def assert_nothing_raised(*exp)
+    ret = true
+    if $mrbtest_assert
+      $mrbtest_assert_idx += 1
+      msg = exp.last.class == String ? exp.pop : ""
+      begin
+        yield
+      rescue Exception => e
+        msg = "#{msg} exception raised."
+        diff = "      Class: <#{e.class}>\n" +
+          "    Message: #{e.message}"
+        $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
+        ret = false
+      end
+    end
+    ret
+  end
+end
+
+assert('IO TEST SETUP') do
+  MRubyIOTestUtil.io_test_setup
+end
+
+assert('IO', '15.2.20') do
+  assert_equal(Class, IO.class)
+end
+
+assert('IO', '15.2.20.2') do
+  assert_equal(Object, IO.superclass)
+end
+
+assert('IO', '15.2.20.3') do
+  assert_include(IO.included_modules, Enumerable)
+end
+
+assert('IO.open', '15.2.20.4.1') do
+  fd = IO.sysopen $mrbtest_io_rfname
+  assert_equal Fixnum, fd.class
+  io = IO.open fd
+  assert_equal IO, io.class
+  assert_equal $mrbtest_io_msg, io.read
+  io.close
+
+  fd = IO.sysopen $mrbtest_io_rfname
+  IO.open(fd) do |io|
+    assert_equal $mrbtest_io_msg, io.read
+  end
+
+  true
+end
+
+assert('IO#close', '15.2.20.5.1') do
+  io = IO.new(IO.sysopen($mrbtest_io_rfname))
+  assert_nil io.close
+end
+
+assert('IO#closed?', '15.2.20.5.2') do
+  io = IO.new(IO.sysopen($mrbtest_io_rfname))
+  assert_false io.closed?
+  io.close
+  assert_true io.closed?
+end
+
+#assert('IO#each', '15.2.20.5.3') do
+#assert('IO#each_byte', '15.2.20.5.4') do
+#assert('IO#each_line', '15.2.20.5.5') do
+
+assert('IO#eof?', '15.2.20.5.6') do
+  io = IO.new(IO.sysopen($mrbtest_io_wfname, 'w'), 'w')
+  assert_raise(IOError) do
+    io.eof?
+  end
+  io.close
+
+  # empty file
+  io = IO.open(IO.sysopen($mrbtest_io_wfname, 'w'), 'w')
+  io.close
+  io = IO.open(IO.sysopen($mrbtest_io_wfname, 'r'), 'r')
+  assert_true io.eof?
+  io.close
+
+  # nonempty file
+  io = IO.new(IO.sysopen($mrbtest_io_rfname))
+  assert_false io.eof?
+  io.readchar
+  assert_false io.eof?
+  io.read
+  assert_true io.eof?
+  io.close
+
+  true
+end
+
+assert('IO#flush', '15.2.20.5.7') do
+  # Note: mruby-io does not have any buffer to be flushed now.
+  io = IO.new(IO.sysopen($mrbtest_io_wfname))
+  assert_equal io, io.flush
+  io.close
+  assert_raise(IOError) do
+    io.flush
+  end
+end
+
+assert('IO#getc', '15.2.20.5.8') do
+  io = IO.new(IO.sysopen($mrbtest_io_rfname))
+  $mrbtest_io_msg.each_char { |ch|
+    assert_equal ch, io.getc
+  }
+  assert_equal nil, io.getc
+  io.close
+  true
+end
+
+#assert('IO#gets', '15.2.20.5.9') do
+#assert('IO#initialize_copy', '15.2.20.5.10') do
+#assert('IO#print', '15.2.20.5.11') do
+#assert('IO#putc', '15.2.20.5.12') do
+#assert('IO#puts', '15.2.20.5.13') do
+
+assert('IO#read', '15.2.20.5.14') do
+  IO.open(IO.sysopen($mrbtest_io_rfname)) do |io|
+    assert_raise(ArgumentError) { io.read(-5) }
+    assert_raise(TypeError) { io.read("str") }
+
+    len = $mrbtest_io_msg.length
+    assert_equal '', io.read(0)
+    assert_equal 'mruby', io.read(5)
+    assert_equal $mrbtest_io_msg[5,len], io.read(len)
+
+    assert_equal "", io.read
+    assert_nil io.read(1)
+  end
+
+  IO.open(IO.sysopen($mrbtest_io_rfname)) do |io|
+    assert_equal $mrbtest_io_msg, io.read
+  end
+end
+
+assert('IO#readchar', '15.2.20.5.15') do
+  # almost same as IO#getc
+  IO.open(IO.sysopen($mrbtest_io_rfname)) do |io|
+    $mrbtest_io_msg.each_char { |ch|
+      assert_equal ch, io.readchar
+    }
+    assert_raise(EOFError) do
+      io.readchar
+    end
+  end
+end
+
+#assert('IO#readline', '15.2.20.5.16') do
+#assert('IO#readlines', '15.2.20.5.17') do
+
+assert('IO#sync', '15.2.20.5.18') do
+  io = IO.new(IO.sysopen($mrbtest_io_rfname))
+  s = io.sync
+  assert_true(s == true || s == false)
+  io.close
+  assert_raise(IOError) do
+    io.sync
+  end
+end
+
+assert('IO#sync=', '15.2.20.5.19') do
+  io = IO.new(IO.sysopen($mrbtest_io_rfname))
+  io.sync = true
+  assert_true io.sync
+  io.sync = false
+  assert_false io.sync
+  io.close
+  assert_raise(IOError) do
+    io.sync = true
+  end
+end
+
+assert('IO#write', '15.2.20.5.20') do
+  io = IO.open(IO.sysopen($mrbtest_io_wfname))
+  assert_equal 0, io.write("")
+  io.close
+  true
+end
+
+assert('IO#<<') do
+  io = IO.open(IO.sysopen($mrbtest_io_wfname))
+  io << "" << ""
+  assert_equal 0, io.pos
+  io.close
+  true
+end
+
+assert('IO.for_fd') do
+  fd = IO.sysopen($mrbtest_io_rfname)
+  io = IO.for_fd(fd)
+    assert_equal $mrbtest_io_msg, io.read
+  io.close
+  true
+end
+
+assert('IO.new') do
+  io = IO.new(0)
+  io.close
+  true
+end
+
+assert('IO gc check') do
+  100.times { IO.new(0) }
+end
+
+assert('IO.sysopen("./nonexistent")') do
+  if Object.const_defined? :Errno
+    eclass = Errno::ENOENT
+  else
+    eclass = RuntimeError
+  end
+  assert_raise eclass do
+    fd = IO.sysopen "./nonexistent"
+    IO._sysclose fd
+  end
+end
+
+assert('IO.sysopen, IO#sysread') do
+  fd = IO.sysopen $mrbtest_io_rfname
+  io = IO.new fd
+  str1 = "     "
+  str2 = io.sysread(5, str1)
+  assert_equal $mrbtest_io_msg[0,5], str1
+  assert_equal $mrbtest_io_msg[0,5], str2
+  assert_raise EOFError do
+    io.sysread(10000)
+    io.sysread(10000)
+  end
+  io.close
+  io.closed?
+end
+
+assert('IO.sysopen, IO#syswrite') do
+  fd = IO.sysopen $mrbtest_io_wfname, "w"
+  io = IO.new fd, "w"
+  str = "abcdefg"
+  len = io.syswrite(str)
+  assert_equal str.size, len
+  io.close
+
+  io = IO.new(IO.sysopen($mrbtest_io_rfname), "r")
+  assert_raise(IOError) { io.syswrite("a") }
+  io.close
+
+  true
+end
+
+assert('IO#_read_buf') do
+  fd = IO.sysopen $mrbtest_io_rfname
+  io = IO.new fd
+  def io._buf
+    @buf
+  end
+  msg_len = $mrbtest_io_msg.size
+  assert_equal '', io._buf
+  assert_equal $mrbtest_io_msg, io._read_buf
+  assert_equal $mrbtest_io_msg, io._buf
+  assert_equal 'mruby', io.read(5)
+  assert_equal 5, io.pos
+  assert_equal msg_len - 5, io._buf.size
+  assert_equal $mrbtest_io_msg[5,100], io.read
+  assert_equal 0, io._buf.size
+  assert_raise EOFError do
+    io._read_buf
+  end
+  assert_equal true, io.eof
+  assert_equal true, io.eof?
+  io.close
+  io.closed?
+end
+
+assert('IO#isatty') do
+  f1 = File.open("/dev/tty")
+  f2 = File.open($mrbtest_io_rfname)
+
+  assert_true  f1.isatty
+  assert_false f2.isatty
+
+  f1.close
+  f2.close
+  true
+end
+
+assert('IO#pos=, IO#seek') do
+  fd = IO.sysopen $mrbtest_io_rfname
+  io = IO.new fd
+  def io._buf
+    @buf
+  end
+  assert_equal 'm', io.getc
+  assert_equal 1, io.pos
+  assert_equal 0, io.seek(0)
+  assert_equal 0, io.pos
+  io.close
+  io.closed?
+end
+
+assert('IO#rewind') do
+  fd = IO.sysopen $mrbtest_io_rfname
+  io = IO.new fd
+  assert_equal 'm', io.getc
+  assert_equal 1, io.pos
+  assert_equal 0, io.rewind
+  assert_equal 0, io.pos
+  io.close
+  io.closed?
+end
+
+assert('IO#gets') do
+  fd = IO.sysopen $mrbtest_io_rfname
+  io = IO.new fd
+
+  # gets without arguments
+  assert_equal $mrbtest_io_msg, io.gets, "gets without arguments"
+  assert_equal nil, io.gets, "gets returns nil, when EOF"
+
+  # gets with limit
+  io.pos = 0
+  assert_equal $mrbtest_io_msg[0, 5], io.gets(5), "gets with limit"
+
+  # gets with rs
+  io.pos = 0
+  assert_equal $mrbtest_io_msg[0, 6], io.gets(' '), "gets with rs"
+
+  # gets with rs, limit
+  io.pos = 0
+  assert_equal $mrbtest_io_msg[0, 5], io.gets(' ', 5), "gets with rs, limit"
+  io.close
+  assert_equal true, io.closed?, "close success"
+
+  # reading many-lines file.
+  fd = IO.sysopen $mrbtest_io_wfname, "w"
+  io = IO.new fd, "w"
+  io.write "0123456789" * 2 + "\na"
+  assert_equal 22, io.pos
+  io.close
+  assert_equal true, io.closed?
+
+  fd = IO.sysopen $mrbtest_io_wfname
+  io = IO.new fd
+  line = io.gets
+
+  # gets first line
+  assert_equal "0123456789" * 2 + "\n", line, "gets first line"
+  assert_equal 21, line.size
+  assert_equal 21, io.pos
+
+  # gets second line
+  assert_equal "a", io.gets, "gets second line"
+
+  # gets third line
+  assert_equal nil, io.gets, "gets third line; returns nil"
+
+  io.close
+  io.closed?
+end
+
+assert('IO#gets - paragraph mode') do
+  fd = IO.sysopen $mrbtest_io_wfname, "w"
+  io = IO.new fd, "w"
+  io.write "0" * 10 + "\n"
+  io.write "1" * 10 + "\n\n"
+  io.write "2" * 10 + "\n"
+  assert_equal 34, io.pos
+  io.close
+  assert_equal true, io.closed?
+
+  fd = IO.sysopen $mrbtest_io_wfname
+  io = IO.new fd
+  para1 = "#{'0' * 10}\n#{'1' * 10}\n\n"
+  text1 = io.gets("")
+  assert_equal para1, text1
+  para2 = "#{'2' * 10}\n"
+  text2 = io.gets("")
+  assert_equal para2, text2
+  io.close
+  io.closed?
+end
+
+assert('IO.popen') do
+  begin
+    $? = nil
+    io = IO.popen("echo mruby-io")
+    assert_true io.close_on_exec?
+    assert_equal Fixnum, io.pid.class
+
+    out = io.read
+    assert_equal out.class, String
+    assert_include out, 'mruby-io'
+
+    io.close
+    if Object.const_defined? :Process
+      assert_true $?.success?
+    else
+      assert_equal 0, $?
+    end
+
+    assert_true io.closed?
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert('IO.popen with in option') do
+  begin
+    IO.pipe do |r, w|
+      w.write 'hello'
+      w.close
+      assert_equal "hello", IO.popen("cat", "r", in: r) { |i| i.read }
+      assert_equal "", r.read
+    end
+    assert_raise(ArgumentError) { IO.popen("hello", "r", in: Object.new) }
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert('IO.popen with out option') do
+  begin
+    IO.pipe do |r, w|
+      IO.popen("echo 'hello'", "w", out: w) {}
+      w.close
+      assert_equal "hello\n", r.read
+    end
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert('IO.popen with err option') do
+  begin
+    IO.pipe do |r, w|
+      assert_equal "", IO.popen("echo 'hello' 1>&2", "r", err: w) { |i| i.read }
+      w.close
+      assert_equal "hello\n", r.read
+    end
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert('IO.read') do
+  # empty file
+  fd = IO.sysopen $mrbtest_io_wfname, "w"
+  io = IO.new fd, "w"
+  io.close
+  assert_equal "",  IO.read($mrbtest_io_wfname)
+  assert_equal nil, IO.read($mrbtest_io_wfname, 1)
+
+  # one byte file
+  fd = IO.sysopen $mrbtest_io_wfname, "w"
+  io = IO.new fd, "w"
+  io.write "123"
+  io.close
+  assert_equal "123", IO.read($mrbtest_io_wfname)
+  assert_equal "",    IO.read($mrbtest_io_wfname, 0)
+  assert_equal "1",   IO.read($mrbtest_io_wfname, 1)
+  assert_equal "",    IO.read($mrbtest_io_wfname, 0, 10)
+  assert_equal "23",  IO.read($mrbtest_io_wfname, 2, 1)
+  assert_equal "23",  IO.read($mrbtest_io_wfname, 10, 1)
+  assert_equal "",    IO.read($mrbtest_io_wfname, nil, 10)
+  assert_equal nil,   IO.read($mrbtest_io_wfname, 1, 10)
+end
+
+assert('IO#fileno') do
+  fd = IO.sysopen $mrbtest_io_rfname
+  io = IO.new fd
+  assert_equal io.fileno, fd
+  assert_equal io.to_i, fd
+  io.close
+  io.closed?
+end
+
+assert('IO#close_on_exec') do
+  fd = IO.sysopen $mrbtest_io_wfname, "w"
+  io = IO.new fd, "w"
+  begin
+    # IO.sysopen opens a file descripter with O_CLOEXEC flag.
+    assert_true io.close_on_exec?
+  rescue ScriptError
+    skip "IO\#close_on_exec is not implemented."
+  end
+
+  io.close_on_exec = false
+  assert_equal(false, io.close_on_exec?)
+  io.close_on_exec = true
+  assert_equal(true, io.close_on_exec?)
+  io.close_on_exec = false
+  assert_equal(false, io.close_on_exec?)
+
+  io.close
+  io.closed?
+
+  begin
+    r, w = IO.pipe
+    assert_equal(true, r.close_on_exec?)
+    r.close_on_exec = false
+    assert_equal(false, r.close_on_exec?)
+    r.close_on_exec = true
+    assert_equal(true, r.close_on_exec?)
+
+    assert_equal(true, w.close_on_exec?)
+    w.close_on_exec = false
+    assert_equal(false, w.close_on_exec?)
+    w.close_on_exec = true
+    assert_equal(true, w.close_on_exec?)
+  ensure
+    r.close unless r.closed?
+    w.close unless w.closed?
+  end
+end
+
+assert('IO#sysseek') do
+  IO.open(IO.sysopen($mrbtest_io_rfname)) do |io|
+    assert_equal 2, io.sysseek(2)
+    assert_equal 5, io.sysseek(3, IO::SEEK_CUR) # 2 + 3 => 5
+    assert_equal $mrbtest_io_msg.size - 4, io.sysseek(-4, IO::SEEK_END)
+  end
+end
+
+assert('IO.pipe') do
+  begin
+    called = false
+    IO.pipe do |r, w|
+      assert_true r.kind_of?(IO)
+      assert_true w.kind_of?(IO)
+      assert_false r.closed?
+      assert_false w.closed?
+      assert_true FileTest.pipe?(r)
+      assert_true FileTest.pipe?(w)
+      assert_nil r.pid
+      assert_nil w.pid
+      assert_true 2 < r.fileno
+      assert_true 2 < w.fileno
+      assert_true r.fileno != w.fileno
+      assert_false r.sync
+      assert_true w.sync
+      assert_equal 8, w.write('test for')
+      assert_equal 'test', r.read(4)
+      assert_equal ' for', r.read(4)
+      assert_equal 5, w.write(' pipe')
+      assert_equal nil, w.close
+      assert_equal ' pipe', r.read
+      called = true
+      assert_raise(IOError) { r.write 'test' }
+      # TODO:
+      # This assert expect raise IOError but got RuntimeError
+      # Because mruby-io not have flag for I/O readable
+      # assert_raise(IOError) { w.read }
+    end
+    assert_true called
+
+    assert_nothing_raised do
+      IO.pipe { |r, w| r.close; w.close }
+    end
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert('`cmd`') do
+  begin
+    assert_equal `echo foo`, "foo\n"
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+assert('IO TEST CLEANUP') do
+  assert_nil MRubyIOTestUtil.io_test_cleanup
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-io/test/mruby_io_test.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-io/test/mruby_io_test.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-io/test/mruby_io_test.c	(revision 279)
@@ -0,0 +1,191 @@
+#include <sys/types.h>
+#include <errno.h>
+
+#if defined(_WIN32) || defined(_WIN64)
+  #include <winsock.h>
+  #include <io.h>
+#else
+  #include <sys/socket.h>
+  #include <unistd.h>
+  #include <sys/un.h>
+#endif
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mruby.h"
+#include "mruby/array.h"
+#include "mruby/error.h"
+#include "mruby/string.h"
+#include "mruby/variable.h"
+
+static mrb_value
+mrb_io_test_io_setup(mrb_state *mrb, mrb_value self)
+{
+  char rfname[]      = "tmp.mruby-io-test.XXXXXXXX";
+  char wfname[]      = "tmp.mruby-io-test.XXXXXXXX";
+  char symlinkname[] = "tmp.mruby-io-test.XXXXXXXX";
+  char socketname[]  = "/tmp/mruby-io-test.XXXXXXXX";
+  char msg[] = "mruby io test\n";
+  mode_t mask;
+  int fd0, fd1, fd2, fd3;
+  FILE *fp;
+
+#ifndef _WIN32
+  struct sockaddr_un sun0;
+#endif
+
+  mask = umask(077);
+  fd0 = mkstemp(rfname);
+  fd1 = mkstemp(wfname);
+#ifndef _WIN32
+  fd2 = mkstemp(symlinkname);
+  fd3 = mkstemp(socketname);
+#endif
+  if (fd0 == -1 || fd1 == -1 || fd2 == -1 || fd3 == -1) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file");
+    return mrb_nil_value();
+  }
+  umask(mask);
+
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_str_new_cstr(mrb, rfname));
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_str_new_cstr(mrb, wfname));
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_str_new_cstr(mrb, symlinkname));
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_str_new_cstr(mrb, socketname));
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg));
+
+  fp = fopen(rfname, "wb");
+  if (fp == NULL) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file");
+    return mrb_nil_value();
+  }
+  fputs(msg, fp);
+  fclose(fp);
+
+  fp = fopen(wfname, "wb");
+  if (fp == NULL) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file");
+    return mrb_nil_value();
+  }
+  fclose(fp);
+
+#ifndef _WIN32
+  unlink(symlinkname);
+  close(fd2);
+  if (symlink(rfname, symlinkname) == -1) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link");
+  }
+
+  unlink(socketname);
+  close(fd3);
+  fd3 = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (fd3 == -1) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a socket");
+  }
+  sun0.sun_family = AF_UNIX;
+  snprintf(sun0.sun_path, sizeof(sun0.sun_path), "%s", socketname);
+  if (bind(fd3, (struct sockaddr *)&sun0, sizeof(sun0)) == -1) {
+    mrb_raisef(mrb, E_RUNTIME_ERROR, "can't bind AF_UNIX socket to %S: %S",
+               mrb_str_new_cstr(mrb, sun0.sun_path),
+               mrb_fixnum_value(errno));
+  }
+  close(fd3);
+#endif
+
+  return mrb_true_value();
+}
+
+static mrb_value
+mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self)
+{
+  mrb_value rfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"));
+  mrb_value wfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"));
+  mrb_value symlinkname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"));
+  mrb_value socketname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"));
+
+  if (mrb_type(rfname) == MRB_TT_STRING) {
+    remove(RSTRING_PTR(rfname));
+  }
+  if (mrb_type(wfname) == MRB_TT_STRING) {
+    remove(RSTRING_PTR(wfname));
+  }
+  if (mrb_type(symlinkname) == MRB_TT_STRING) {
+    remove(RSTRING_PTR(symlinkname));
+  }
+  if (mrb_type(socketname) == MRB_TT_STRING) {
+    remove(RSTRING_PTR(socketname));
+  }
+
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_nil_value());
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_nil_value());
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_nil_value());
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_nil_value());
+  mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_nil_value());
+
+  return mrb_nil_value();
+}
+
+static mrb_value
+mrb_io_test_file_setup(mrb_state *mrb, mrb_value self)
+{
+  mrb_value ary = mrb_io_test_io_setup(mrb, self);
+#ifndef _WIN32
+  if (symlink("/usr/bin", "test-bin") == -1) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link");
+  }
+#endif
+
+  return ary;
+}
+
+static mrb_value
+mrb_io_test_file_cleanup(mrb_state *mrb, mrb_value self)
+{
+  mrb_io_test_io_cleanup(mrb, self);
+  remove("test-bin");
+
+  return mrb_nil_value();
+}
+
+static mrb_value
+mrb_io_test_mkdtemp(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value str;
+  char *cp;
+
+  mrb_get_args(mrb, "S", &str);
+  cp = mrb_str_to_cstr(mrb, str);
+  if (mkdtemp(cp) == NULL) {
+    mrb_sys_fail(mrb, "mkdtemp");
+  }
+  return mrb_str_new_cstr(mrb, cp);
+}
+
+static mrb_value
+mrb_io_test_rmdir(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value str;
+  char *cp;
+
+  mrb_get_args(mrb, "S", &str);
+  cp = mrb_str_to_cstr(mrb, str);
+  if (rmdir(cp) == -1) {
+    mrb_sys_fail(mrb, "rmdir");
+  }
+  return mrb_true_value();
+}
+
+void
+mrb_mruby_io_gem_test(mrb_state* mrb)
+{
+  struct RClass *io_test = mrb_define_module(mrb, "MRubyIOTestUtil");
+  mrb_define_class_method(mrb, io_test, "io_test_setup", mrb_io_test_io_setup, MRB_ARGS_NONE());
+  mrb_define_class_method(mrb, io_test, "io_test_cleanup", mrb_io_test_io_cleanup, MRB_ARGS_NONE());
+
+  mrb_define_class_method(mrb, io_test, "file_test_setup", mrb_io_test_file_setup, MRB_ARGS_NONE());
+  mrb_define_class_method(mrb, io_test, "file_test_cleanup", mrb_io_test_file_cleanup, MRB_ARGS_NONE());
+
+  mrb_define_class_method(mrb, io_test, "mkdtemp", mrb_io_test_mkdtemp, MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, io_test, "rmdir", mrb_io_test_rmdir, MRB_ARGS_REQ(1));
+}
Index: EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/.travis.yml
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/.travis.yml	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/.travis.yml	(revision 279)
@@ -0,0 +1,11 @@
+sudo: false
+addons:
+  apt:
+    packages:
+      - gperf
+      - libonig-dev
+script:
+  - export MRUBY_CONFIG="$TRAVIS_BUILD_DIR/.travis_config.rb"
+  - git clone --depth 1 "https://github.com/mruby/mruby.git"
+  - cd mruby
+  - ./minirake all test
Index: EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/.travis_config.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/.travis_config.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/.travis_config.rb	(revision 279)
@@ -0,0 +1,21 @@
+MRuby::Build.new do |conf|
+  toolchain :gcc
+  enable_debug
+  enable_test
+
+  gem :core => 'mruby-print'
+  gem :core => 'mruby-sprintf'
+  gem "#{MRUBY_ROOT}/.."
+end
+
+MRuby::Build.new("onigmo-bundled") do |conf|
+  toolchain :gcc
+  enable_debug
+  enable_test
+
+  gem :core => 'mruby-print'
+  gem :core => 'mruby-sprintf'
+  gem "#{MRUBY_ROOT}/.." do |g|
+    g.bundle_onigmo
+  end
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/mrbgem.rake	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/mrbgem.rake	(revision 279)
@@ -0,0 +1,5 @@
+MRuby::Gem::Specification.new('mruby-onig-regexp') do |spec|
+  spec.license = 'MIT'
+  spec.authors = 'mattn'
+  spec.summary = 'Onigmo Onigruma Regular expression'
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/mrblib/onig_regexp.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/mrblib/onig_regexp.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/mrblib/onig_regexp.rb	(revision 279)
@@ -0,0 +1,140 @@
+class OnigRegexp
+  @memo = {}
+
+  # ISO 15.2.15.6.1
+  def self.compile(*args)
+    as = args.to_s
+    unless @memo.key? as
+      @memo[as] = self.new(*args)
+    end
+    @memo[as]
+  end
+
+  # ISO 15.2.15.6.3
+  def self.last_match
+    @last_match
+  end
+
+  # ISO 15.2.15.7.2
+  def initialize_copy(other)
+    initialize(other.source, other.options)
+  end
+
+  # ISO 15.2.15.7.4
+  def ===(str)
+    not self.match(str).nil?
+  end
+
+  # ISO 15.2.15.7.5
+  def =~(str)
+    m = self.match(str)
+    m ? m.begin(0) : nil
+  end
+
+  # ISO 15.2.15.7.8
+  attr_reader :source
+end
+
+class String
+  # ISO 15.2.10.5.5
+  def =~(a)
+    begin
+      (a.class.to_s == 'String' ?  Regexp.new(a.to_s) : a) =~ self
+    rescue
+      false
+    end
+  end
+
+  # redefine methods with oniguruma regexp version
+  [:sub, :gsub, :split, :scan].each do |v|
+    alias_method "string_#{v}".to_sym, v
+    alias_method v, "onig_regexp_#{v}".to_sym
+  end
+
+  alias_method :old_slice, :slice
+  alias_method :old_square_brancket, :[]
+
+  def [](*args)
+    return old_square_brancket(*args) unless args[0].class == Regexp
+
+    if args.size == 2
+      match = args[0].match(self)
+      if match
+        if args[1] == 0
+          str = match[0]
+        else
+          str = match.captures[args[1] - 1]
+        end
+        return str
+      end
+    end
+
+    match_data = args[0].match(self)
+    if match_data
+      result = match_data.to_s
+      return result
+    end
+  end
+
+  alias_method :slice, :[]
+
+  def slice!(*args)
+    if args.size < 2
+      result = slice(*args)
+      nth = args[0]
+
+      if nth.class == Regexp
+        lm = Regexp.last_match
+        self[nth] = '' if result
+        Regexp.last_match = lm
+      else
+        self[nth] = '' if result
+      end
+    else
+      result = slice(*args)
+
+      nth = args[0]
+      len = args[1]
+
+      if nth.class == Regexp
+        lm = Regexp.last_match
+        self[nth, len] = '' if result
+        Regexp.last_match = lm
+      else
+        self[nth, len] = '' if result && nth != self.size
+      end
+    end
+
+    result
+  end
+
+  alias_method :old_index, :index
+
+  def index(pattern, pos=0)
+    if pattern.class == Regexp
+      str = self[pos..-1]
+      if str
+        if num = (pattern =~ str)
+          if pos < 0
+            num += self.size
+          end
+          return num + pos
+        end
+      end
+      nil
+    else
+      self.old_index(pattern, pos)
+    end
+  end
+end
+
+module Kernel
+  def =~(_)
+    nil
+  end
+end
+
+Regexp = OnigRegexp unless Object.const_defined?(:Regexp)
+MatchData = OnigMatchData unless Object.const_defined? :MatchData
+
+# This is based on https://github.com/masamitsu-murase/mruby-hs-regexp
Index: EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/src/mruby_onig_regexp.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/src/mruby_onig_regexp.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/src/mruby_onig_regexp.c	(revision 279)
@@ -0,0 +1,1021 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2015 mattn.
+
+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 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.
+*/
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/variable.h>
+#include <mruby/array.h>
+#include <mruby/string.h>
+#include <mruby/data.h>
+#include <mruby/variable.h>
+#ifdef _MSC_VER
+#define ONIG_EXTERN extern
+#endif
+#include "oniguruma.h"
+
+#ifdef MRUBY_VERSION
+#define mrb_args_int mrb_int
+#else
+#define mrb_args_int int
+#endif
+
+static void
+onig_regexp_free(mrb_state *mrb, void *p) {
+  onig_free((OnigRegex) p);
+}
+
+static struct mrb_data_type mrb_onig_regexp_type = {
+  "PosixRegexp", onig_regexp_free
+};
+
+static void
+match_data_free(mrb_state* mrb, void* p) {
+  (void)mrb;
+  onig_region_free((OnigRegion*)p, 1);
+}
+
+static struct mrb_data_type mrb_onig_region_type = {
+  "OnigRegion", match_data_free
+};
+
+static mrb_value
+onig_regexp_initialize(mrb_state *mrb, mrb_value self) {
+  mrb_value str, flag = mrb_nil_value(), code = mrb_nil_value();
+  mrb_get_args(mrb, "S|oo", &str, &flag, &code);
+
+  int cflag = 0;
+  OnigSyntaxType* syntax = ONIG_SYNTAX_RUBY;
+  OnigEncoding enc = ONIG_ENCODING_UTF8;
+  if(mrb_string_p(code)) {
+    char const* str_code = mrb_string_value_ptr(mrb, code);
+    if(strchr(str_code, 'n') || strchr(str_code, 'N')) {
+      enc = ONIG_ENCODING_ASCII;
+    }
+  }
+  if(mrb_nil_p(flag)) {
+  } else if(mrb_type(flag) == MRB_TT_TRUE) {
+    cflag |= ONIG_OPTION_IGNORECASE;
+  } else if(mrb_fixnum_p(flag)) {
+    int int_flags = mrb_fixnum(flag);
+    if(int_flags & 0x1) { cflag |= ONIG_OPTION_IGNORECASE; }
+    if(int_flags & 0x2) { cflag |= ONIG_OPTION_EXTEND; }
+    if(int_flags & 0x4) { cflag |= ONIG_OPTION_MULTILINE; }
+  } else if(mrb_string_p(flag)) {
+    char const* str_flags = mrb_string_value_ptr(mrb, flag);
+    if(strchr(str_flags, 'i')) { cflag |= ONIG_OPTION_IGNORECASE; }
+    if(strchr(str_flags, 'x')) { cflag |= ONIG_OPTION_EXTEND; }
+    if(strchr(str_flags, 'm')) { cflag |= ONIG_OPTION_MULTILINE; }
+  } else {
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown regexp flag: %S", flag);
+  }
+
+  OnigErrorInfo einfo;
+  OnigRegex reg;
+  int result = onig_new(&reg, (OnigUChar*)RSTRING_PTR(str), (OnigUChar*) RSTRING_PTR(str) + RSTRING_LEN(str),
+                        cflag, enc, syntax, &einfo);
+  if (result != ONIG_NORMAL) {
+    char err[ONIG_MAX_ERROR_MESSAGE_LEN] = "";
+    onig_error_code_to_str((OnigUChar*)err, result);
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%S' is an invalid regular expression because %S.",
+               str, mrb_str_new_cstr(mrb, err));
+  }
+  mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "@source"), str);
+
+  DATA_PTR(self) = reg;
+  DATA_TYPE(self) = &mrb_onig_regexp_type;
+
+  return self;
+}
+
+static mrb_value
+create_onig_region(mrb_state* mrb, mrb_value const str, mrb_value rex) {
+  mrb_assert(mrb_string_p(str));
+  mrb_assert(mrb_type(rex) == MRB_TT_DATA && DATA_TYPE(rex) == &mrb_onig_regexp_type);
+  mrb_value const c = mrb_obj_value(mrb_data_object_alloc(
+      mrb, mrb_class_get(mrb, "OnigMatchData"), onig_region_new(), &mrb_onig_region_type));
+  mrb_iv_set(mrb, c, mrb_intern_lit(mrb, "string"), mrb_str_dup(mrb, str));
+  mrb_iv_set(mrb, c, mrb_intern_lit(mrb, "regexp"), rex);
+  return c;
+}
+
+static int
+onig_match_common(mrb_state* mrb, OnigRegex reg, mrb_value match_value, mrb_value str, int pos) {
+  mrb_assert(mrb_string_p(str));
+  mrb_assert(DATA_TYPE(match_value) == &mrb_onig_region_type);
+  OnigRegion* const match = (OnigRegion*)DATA_PTR(match_value);
+  OnigUChar const* str_ptr = (OnigUChar const*)RSTRING_PTR(str);
+  int const result = onig_search(reg, str_ptr, str_ptr + RSTRING_LEN(str),
+                                 str_ptr + pos, str_ptr + RSTRING_LEN(str), match, 0);
+  if (result != ONIG_MISMATCH && result < 0) {
+    char err[ONIG_MAX_ERROR_MESSAGE_LEN] = "";
+    onig_error_code_to_str((OnigUChar*)err, result);
+    mrb_raise(mrb, E_REGEXP_ERROR, err);
+  }
+
+  struct RObject* const cls = (struct RObject*)mrb_class_get(mrb, "OnigRegexp");
+  mrb_obj_iv_set(mrb, cls, mrb_intern_lit(mrb, "@last_match"), match_value);
+
+  if (result != ONIG_MISMATCH &&
+      mrb_class_get(mrb, "Regexp") == (struct RClass*)cls &&
+      mrb_bool(mrb_obj_iv_get(mrb, (struct RObject*)cls, mrb_intern_lit(mrb, "@set_global_variables"))))
+  {
+    mrb_gv_set(mrb, mrb_intern_lit(mrb, "$~"), match_value);
+    mrb_gv_set(mrb, mrb_intern_lit(mrb, "$&"),
+               mrb_funcall(mrb, match_value, "[]", 1, mrb_fixnum_value(0)));
+    mrb_gv_set(mrb, mrb_intern_lit(mrb, "$`"), mrb_funcall(mrb, match_value, "pre_match", 0));
+    mrb_gv_set(mrb, mrb_intern_lit(mrb, "$'"), mrb_funcall(mrb, match_value, "post_match", 0));
+    mrb_gv_set(mrb, mrb_intern_lit(mrb, "$+"),
+               mrb_funcall(mrb, match_value, "[]", 1, mrb_fixnum_value(match->num_regs - 1)));
+
+    // $1 to $9
+    int idx = 1;
+    int const idx_max = match->num_regs > 10? 10 : match->num_regs;
+    for(; idx < idx_max; ++idx) {
+      char const n[] = { '$', '0' + idx };
+      mrb_gv_set(mrb, mrb_intern(mrb, n, 2),
+                 mrb_funcall(mrb, match_value, "[]", 1, mrb_fixnum_value(idx)));
+    }
+
+    for(; idx < 10; ++idx) {
+      char const n[] = { '$', '0' + idx };
+      mrb_gv_remove(mrb, mrb_intern(mrb, n, 2));
+    }
+  }
+
+  return result;
+}
+
+static mrb_value
+onig_regexp_match(mrb_state *mrb, mrb_value self) {
+  mrb_value str = mrb_nil_value();
+  OnigRegex reg;
+  mrb_int pos = 0;
+
+  mrb_get_args(mrb, "o|i", &str, &pos);
+  if (pos < 0 || (pos > 0 && pos >= RSTRING_LEN(str))) {
+    return mrb_nil_value();
+  }
+
+  if (mrb_nil_p(str)) {
+    return mrb_nil_value();
+  }
+  str = mrb_string_type(mrb, str);
+
+  Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, reg);
+
+  mrb_value const ret = create_onig_region(mrb, str, self);
+  return (onig_match_common(mrb, reg, ret, str, pos) == ONIG_MISMATCH)
+      ? mrb_nil_value() : ret;
+}
+
+static mrb_value
+onig_regexp_equal(mrb_state *mrb, mrb_value self) {
+  mrb_value other;
+  OnigRegex self_reg, other_reg;
+
+  mrb_get_args(mrb, "o", &other);
+  if (mrb_obj_equal(mrb, self, other)){
+    return mrb_true_value();
+  }
+  if (mrb_nil_p(other)) {
+    return mrb_false_value();
+  }
+  if (!mrb_obj_is_kind_of(mrb, other, mrb_class_get(mrb, "OnigRegexp"))) {
+    return mrb_false_value();
+  }
+  Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, self_reg);
+  Data_Get_Struct(mrb, other, &mrb_onig_regexp_type, other_reg);
+
+  if (!self_reg || !other_reg){
+      mrb_raise(mrb, E_RUNTIME_ERROR, "Invalid OnigRegexp");
+  }
+  if (onig_get_options(self_reg) != onig_get_options(other_reg)){
+      return mrb_false_value();
+  }
+  return mrb_str_equal(mrb, mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@source")), mrb_iv_get(mrb, other, mrb_intern_lit(mrb, "@source"))) ?
+      mrb_true_value() : mrb_false_value();
+}
+
+static mrb_value
+onig_regexp_casefold_p(mrb_state *mrb, mrb_value self) {
+  OnigRegex reg;
+
+  Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, reg);
+  return (onig_get_options(reg) & ONIG_OPTION_IGNORECASE) ? mrb_true_value() : mrb_false_value();
+}
+
+static mrb_value
+onig_regexp_options(mrb_state *mrb, mrb_value self) {
+  OnigRegex reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, reg);
+  return mrb_fixnum_value(onig_get_options(reg));
+}
+
+static char *
+option_to_str(char str[4], int options) {
+  char *p = str;
+  if (options & ONIG_OPTION_MULTILINE) *p++ = 'm';
+  if (options & ONIG_OPTION_IGNORECASE) *p++ = 'i';
+  if (options & ONIG_OPTION_EXTEND) *p++ = 'x';
+  *p = 0;
+  return str;
+}
+
+static mrb_value
+regexp_expr_str(mrb_state *mrb, mrb_value str, const char *p, int len) {
+  const char *pend;
+  char buf[5];
+
+  pend = (const char *) p + len;
+  for (;p < pend; p++) {
+    unsigned char c, cc;
+
+    c = *p;
+    if (c == '/'|| c == '\\') {
+      buf[0] = '\\'; buf[1] = c;
+      mrb_str_cat(mrb, str, buf, 2);
+      continue;
+    }
+    if (ISPRINT(c)) {
+      buf[0] = c;
+      mrb_str_cat(mrb, str, buf, 1);
+      continue;
+    }
+    switch (c) {
+      case '\n': cc = 'n'; break;
+      case '\r': cc = 'r'; break;
+      case '\t': cc = 't'; break;
+      default: cc = 0; break;
+    }
+    if (cc) {
+      buf[0] = '\\';
+      buf[1] = (char)cc;
+      mrb_str_cat(mrb, str, buf, 2);
+      continue;
+    }
+    else {
+      buf[0] = '\\';
+      buf[3] = '0' + c % 8; c /= 8;
+      buf[2] = '0' + c % 8; c /= 8;
+      buf[1] = '0' + c % 8;
+      mrb_str_cat(mrb, str, buf, 4);
+      continue;
+    }
+  }
+  return str;
+}
+
+static mrb_value
+onig_regexp_inspect(mrb_state *mrb, mrb_value self) {
+  OnigRegex reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, reg);
+  mrb_value str = mrb_str_new_lit(mrb, "/");
+  mrb_value src = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@source"));
+  regexp_expr_str(mrb, str, (const char *)RSTRING_PTR(src), RSTRING_LEN(src));
+  mrb_str_cat_lit(mrb, str, "/");
+  char opts[4];
+  if (*option_to_str(opts, onig_get_options(reg))) {
+    mrb_str_cat_cstr(mrb, str, opts);
+  }
+  if (onig_get_encoding(reg) == ONIG_ENCODING_ASCII) {
+    mrb_str_cat_lit(mrb, str, "n");
+  }
+  return str;
+}
+
+static mrb_value
+onig_regexp_to_s(mrb_state *mrb, mrb_value self) {
+  int options;
+  const int embeddable = ONIG_OPTION_MULTILINE|ONIG_OPTION_IGNORECASE|ONIG_OPTION_EXTEND;
+  long len;
+  const char* ptr;
+  mrb_value str = mrb_str_new_lit(mrb, "(?");
+  char optbuf[5];
+
+  OnigRegex reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_regexp_type, reg);
+  options = onig_get_options(reg);
+  mrb_value src = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@source"));
+  ptr = RSTRING_PTR(src);
+  len = RSTRING_LEN(src);
+
+ again:
+  if (len >= 4 && ptr[0] == '(' && ptr[1] == '?') {
+	int err = 1;
+	ptr += 2;
+	if ((len -= 2) > 0) {
+      do {
+        if(strchr(ptr, 'i')) { options |= ONIG_OPTION_IGNORECASE; }
+        if(strchr(ptr, 'x')) { options |= ONIG_OPTION_EXTEND; }
+        if(strchr(ptr, 'm')) { options |= ONIG_OPTION_MULTILINE; }
+		++ptr;
+      } while (--len > 0);
+	}
+	if (len > 1 && *ptr == '-') {
+      ++ptr;
+      --len;
+      do {
+        if(strchr(ptr, 'i')) { options &= ~ONIG_OPTION_IGNORECASE; }
+        if(strchr(ptr, 'x')) { options &= ~ONIG_OPTION_EXTEND; }
+        if(strchr(ptr, 'm')) { options &= ~ONIG_OPTION_MULTILINE; }
+		++ptr;
+      } while (--len > 0);
+	}
+	if (*ptr == ')') {
+      --len;
+      ++ptr;
+      goto again;
+	}
+	if (*ptr == ':' && ptr[len-1] == ')') {
+      OnigRegex rp;
+      ++ptr;
+      len -= 2;
+      err = onig_new(&rp, (OnigUChar*)ptr, (OnigUChar*)ptr + len, ONIG_OPTION_DEFAULT,
+                     ONIG_ENCODING_UTF8, OnigDefaultSyntax, NULL);
+      onig_free(rp);
+	}
+	if (err) {
+      options = onig_get_options(reg);
+      ptr = RSTRING_PTR(src);
+      len = RSTRING_LEN(src);
+	}
+  }
+
+  if (*option_to_str(optbuf, options)) mrb_str_cat_cstr(mrb, str, optbuf);
+
+  if ((options & embeddable) != embeddable) {
+	optbuf[0] = '-';
+	option_to_str(optbuf + 1, ~options);
+	mrb_str_cat_cstr(mrb, str, optbuf);
+  }
+
+  mrb_str_cat_cstr(mrb, str, ":");
+  regexp_expr_str(mrb, str, ptr, len);
+  mrb_str_cat_cstr(mrb, str, ")");
+  return str;
+}
+
+
+static mrb_value
+onig_regexp_version(mrb_state* mrb, mrb_value self) {
+  (void)self;
+  return mrb_str_new_cstr(mrb, onig_version());
+}
+
+static mrb_value
+match_data_to_a(mrb_state* mrb, mrb_value self);
+
+static mrb_int
+match_data_actual_index(mrb_state* mrb, mrb_value self, mrb_value idx_value) {
+  if(mrb_fixnum_p(idx_value)) { return mrb_fixnum(idx_value); }
+
+  char const* name = NULL;
+  char const* name_end = NULL;
+  if(mrb_symbol_p(idx_value)) {
+    mrb_int sym_len;
+    name = mrb_sym2name_len(mrb, mrb_symbol(idx_value), &sym_len);
+    name_end = name + sym_len;
+  } else if(mrb_string_p(idx_value)) {
+    name = mrb_string_value_ptr(mrb, idx_value);
+    name_end = name + strlen(name);
+  } else { mrb_assert(FALSE); }
+  mrb_assert(name && name_end);
+
+  mrb_value const regexp = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "regexp"));
+  mrb_assert(!mrb_nil_p(regexp));
+  mrb_assert(DATA_TYPE(regexp) == &mrb_onig_regexp_type);
+  mrb_assert(DATA_TYPE(self) == &mrb_onig_region_type);
+  int const idx = onig_name_to_backref_number(
+      (OnigRegex)DATA_PTR(regexp), (OnigUChar const*)name, (OnigUChar const*)name_end,
+      (OnigRegion*)DATA_PTR(self));
+  if (idx < 0) {
+    mrb_raisef(mrb, E_INDEX_ERROR, "undefined group name reference: %S", idx_value);
+  }
+  return idx;
+}
+
+// ISO 15.2.16.3.1
+static mrb_value
+match_data_index(mrb_state* mrb, mrb_value self) {
+  mrb_value src;
+  mrb_int argc; mrb_value *argv;
+
+  mrb_get_args(mrb, "*", &argv, &argc);
+
+  src = match_data_to_a(mrb, self);
+
+  if (argc == 1) {
+    switch (mrb_type(argv[0])) {
+    case MRB_TT_FIXNUM:
+    case MRB_TT_SYMBOL:
+    case MRB_TT_STRING:
+      return mrb_ary_entry(src, match_data_actual_index(mrb, self, argv[0]));
+    default: break;
+    }
+  }
+
+  return mrb_funcall_argv(mrb, src, mrb_intern_lit(mrb, "[]"), argc, argv);
+}
+
+#define match_data_check_index(idx) \
+  if(idx < 0 || reg->num_regs <= idx) \
+    mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of matches", mrb_fixnum_value(idx)) \
+
+// ISO 15.2.16.3.2
+static mrb_value
+match_data_begin(mrb_state* mrb, mrb_value self) {
+  mrb_value idx_value;
+  mrb_get_args(mrb, "o", &idx_value);
+  OnigRegion* reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg);
+  mrb_int const idx = match_data_actual_index(mrb, self, idx_value);
+  match_data_check_index(idx);
+  return mrb_fixnum_value(reg->beg[idx]);
+}
+
+// ISO 15.2.16.3.3
+static mrb_value
+match_data_captures(mrb_state* mrb, mrb_value self) {
+  mrb_value ary = match_data_to_a(mrb, self);
+  return mrb_ary_new_from_values(mrb, RARRAY_LEN(ary) - 1, RARRAY_PTR(ary) + 1);
+}
+
+// ISO 15.2.16.3.4
+static mrb_value
+match_data_end(mrb_state* mrb, mrb_value self) {
+  mrb_value idx_value;
+  mrb_get_args(mrb, "o", &idx_value);
+  OnigRegion* reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg);
+  mrb_int const idx = match_data_actual_index(mrb, self, idx_value);
+  match_data_check_index(idx);
+  return mrb_fixnum_value(reg->end[idx]);
+}
+
+// ISO 15.2.16.3.5
+static mrb_value
+match_data_copy(mrb_state* mrb, mrb_value self) {
+  mrb_value src_val;
+  mrb_get_args(mrb, "o", &src_val);
+
+  OnigRegion* src;
+  Data_Get_Struct(mrb, src_val, &mrb_onig_region_type, src);
+
+  OnigRegion* dst = onig_region_new();
+  onig_region_copy(dst, src);
+
+  DATA_PTR(self) = dst;
+  DATA_TYPE(self) = &mrb_onig_region_type;
+  mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "string"), mrb_iv_get(mrb, src_val, mrb_intern_lit(mrb, "string")));
+  mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "regexp"), mrb_iv_get(mrb, src_val, mrb_intern_lit(mrb, "regexp")));
+  return self;
+}
+
+// ISO 15.2.16.3.6
+// ISO 15.2.16.3.10
+static mrb_value
+match_data_length(mrb_state* mrb, mrb_value self) {
+  OnigRegion* reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg);
+  return mrb_fixnum_value(reg->num_regs);
+}
+
+// ISO 15.2.16.3.7
+static mrb_value
+match_data_offset(mrb_state* mrb, mrb_value self) {
+  mrb_value idx_value;
+  mrb_get_args(mrb, "o", &idx_value);
+  OnigRegion* reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg);
+  mrb_int const idx = match_data_actual_index(mrb, self, idx_value);
+  match_data_check_index(idx);
+  mrb_value ret = mrb_ary_new_capa(mrb, 2);
+  mrb_ary_push(mrb, ret, mrb_fixnum_value(reg->beg[idx]));
+  mrb_ary_push(mrb, ret, mrb_fixnum_value(reg->end[idx]));
+  return ret;
+}
+
+// ISO 15.2.16.3.8
+static mrb_value
+match_data_post_match(mrb_state* mrb, mrb_value self) {
+  OnigRegion* reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg);
+  mrb_value str = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "string"));
+  return mrb_str_substr(mrb, str, reg->end[0], RSTRING_LEN(str) - reg->end[0]);
+}
+
+// ISO 15.2.16.3.9
+static mrb_value
+match_data_pre_match(mrb_state* mrb, mrb_value self) {
+  OnigRegion* reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg);
+  mrb_value str = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "string"));
+  return mrb_str_substr(mrb, str, 0, reg->beg[0]);
+}
+
+// ISO 15.2.16.3.11
+static mrb_value
+match_data_string(mrb_state* mrb, mrb_value self) {
+  return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "string"));
+}
+
+static mrb_value
+match_data_regexp(mrb_state* mrb, mrb_value self) {
+  return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "regexp"));
+}
+
+// ISO 15.2.16.3.12
+static mrb_value
+match_data_to_a(mrb_state* mrb, mrb_value self) {
+  mrb_value cache = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "cache"));
+  if(!mrb_nil_p(cache)) {
+    return cache;
+  }
+
+  mrb_value str = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "string"));
+  OnigRegion* reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg);
+
+  mrb_value ret = mrb_ary_new_capa(mrb, reg->num_regs);
+  int i, ai = mrb_gc_arena_save(mrb);
+  for(i = 0; i < reg->num_regs; ++i) {
+    if(reg->beg[i] == ONIG_REGION_NOTPOS) {
+      mrb_ary_push(mrb, ret, mrb_nil_value());
+    } else {
+      mrb_ary_push(mrb, ret, mrb_str_substr(mrb, str, reg->beg[i], reg->end[i] - reg->beg[i]));
+    }
+    mrb_gc_arena_restore(mrb, ai);
+  }
+  return ret;
+}
+
+// ISO 15.2.16.3.13
+static mrb_value
+match_data_to_s(mrb_state* mrb, mrb_value self) {
+  mrb_value str = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "string"));
+  OnigRegion* reg;
+  Data_Get_Struct(mrb, self, &mrb_onig_region_type, reg);
+  return mrb_str_substr(mrb, str, reg->beg[0], reg->end[0] - reg->beg[0]);
+}
+
+static void
+append_replace_str(mrb_state* mrb, mrb_value result, mrb_value replace,
+                   mrb_value src, OnigRegex reg, OnigRegion* match)
+{
+  mrb_assert(mrb_string_p(replace));
+  char const* ch;
+  char const* const end = RSTRING_PTR(replace) + RSTRING_LEN(replace);
+  for(ch = RSTRING_PTR(replace); ch < end; ++ch) {
+    if (*ch != '\\' || (ch + 1) >= end) {
+      mrb_str_cat(mrb, result, ch, 1);
+      continue;
+    }
+
+    switch(*(++ch)) { // skip back slash and get next char
+      case 'k': { // group name
+        if ((ch + 2) >= end || ch[1] != '<') { goto replace_expr_error; }
+        char const* name_beg = ch += 2;
+        while (*ch != '>') { if(++ch == end) { goto replace_expr_error; } }
+        mrb_assert(ch < end);
+        mrb_assert(*ch == '>');
+        int const idx = onig_name_to_backref_number(
+            reg, (OnigUChar const*)name_beg, (OnigUChar const*)ch, match);
+        if (idx < 0) {
+          mrb_raisef(mrb, E_INDEX_ERROR, "undefined group name reference: %S",
+                     mrb_str_substr(mrb, replace, name_beg - RSTRING_PTR(replace), ch - name_beg));
+        }
+        mrb_str_cat(mrb, result, RSTRING_PTR(src) + match->beg[idx], match->end[idx] - match->beg[idx]);
+      } break;
+
+      case '\\': // escaped back slash
+        mrb_str_cat(mrb, result, ch, 1);
+        break;
+
+      default:
+        if (isdigit(*ch)) { // group number 0-9
+          int const idx = *ch - '0';
+          if (idx >= match->num_regs) {
+            mrb_raisef(mrb, E_INDEX_ERROR, "undefined group number reference: %S (max: %S)",
+                       mrb_fixnum_value(idx), mrb_fixnum_value(match->num_regs));
+          }
+          mrb_str_cat(mrb, result, RSTRING_PTR(src) + match->beg[idx], match->end[idx] - match->beg[idx]);
+        } else {
+          char const str[] = { '\\', *ch };
+          mrb_str_cat(mrb, result, str, 2);
+        }
+        break;
+    }
+  }
+
+  if(ch == end) { return; }
+
+replace_expr_error:
+  mrb_raisef(mrb, E_REGEXP_ERROR, "invalid replace expression: %S", replace);
+}
+
+// ISO 15.2.10.5.18
+static mrb_value
+string_gsub(mrb_state* mrb, mrb_value self) {
+  mrb_value blk, match_expr, replace_expr = mrb_nil_value();
+  int const argc = mrb_get_args(mrb, "&o|S", &blk, &match_expr, &replace_expr);
+
+  if(mrb_string_p(match_expr)) {
+    mrb_value argv[] = { match_expr, replace_expr };
+    return mrb_funcall_with_block(mrb, self, mrb_intern_lit(mrb, "string_gsub"), argc, argv, blk);
+  }
+
+  if(!mrb_nil_p(blk) && !mrb_nil_p(replace_expr)) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "both block and replace expression must not be passed");
+  }
+
+  OnigRegex reg;
+  Data_Get_Struct(mrb, match_expr, &mrb_onig_regexp_type, reg);
+  mrb_value const result = mrb_str_new(mrb, NULL, 0);
+  mrb_value const match_value = create_onig_region(mrb, self, match_expr);
+  OnigRegion* const match = (OnigRegion*)DATA_PTR(match_value);
+  int last_end_pos = 0;
+
+  while(1) {
+    if(onig_match_common(mrb, reg, match_value, self, last_end_pos) == ONIG_MISMATCH) { break; }
+
+    mrb_str_cat(mrb, result, RSTRING_PTR(self) + last_end_pos, match->beg[0] - last_end_pos);
+
+    if(mrb_nil_p(blk)) {
+      append_replace_str(mrb, result, replace_expr, self, reg, match);
+    } else {
+      mrb_value const tmp_str = mrb_str_to_str(mrb, mrb_yield(mrb, blk, mrb_str_substr(
+          mrb, self, match->beg[0], match->end[0] - match->beg[0])));
+      mrb_assert(mrb_string_p(tmp_str));
+      mrb_str_concat(mrb, result, tmp_str);
+    }
+
+    last_end_pos = match->end[0];
+  }
+
+  mrb_str_cat(mrb, result, RSTRING_PTR(self) + last_end_pos, RSTRING_LEN(self) - last_end_pos);
+  return result;
+}
+
+// ISO 15.2.10.5.32
+static mrb_value
+string_scan(mrb_state* mrb, mrb_value self) {
+  mrb_value blk, match_expr;
+  mrb_get_args(mrb, "&o", &blk, &match_expr);
+
+  if(mrb_string_p(match_expr)) {
+    return mrb_funcall_with_block(mrb, self, mrb_intern_lit(mrb, "string_scan"),
+                                  1, &match_expr, blk);
+  }
+
+  OnigRegex reg;
+  Data_Get_Struct(mrb, match_expr, &mrb_onig_regexp_type, reg);
+  mrb_value const result = mrb_nil_p(blk)? mrb_ary_new(mrb) : self;
+  mrb_value m_value = create_onig_region(mrb, self, match_expr);
+  OnigRegion* const m = (OnigRegion*)DATA_PTR(m_value);
+  int last_end_pos = 0;
+  int i;
+
+  while (1) {
+    if(onig_match_common(mrb, reg, m_value, self, last_end_pos) == ONIG_MISMATCH) { break; }
+
+    if(mrb_nil_p(blk)) {
+      mrb_assert(mrb_array_p(result));
+      if(m->num_regs == 1) {
+        mrb_ary_push(mrb, result, mrb_str_substr(mrb, self, m->beg[0], m->end[0] - m->beg[0]));
+      } else {
+        mrb_value const elem = mrb_ary_new_capa(mrb, m->num_regs - 1);
+        for(i = 1; i < m->num_regs; ++i) {
+          mrb_ary_push(mrb, elem, mrb_str_substr(mrb, self, m->beg[i], m->end[i] - m->beg[i]));
+        }
+        mrb_ary_push(mrb, result, elem);
+      }
+    } else { // call block
+      mrb_assert(mrb_string_p(result));
+      if(m->num_regs == 1) {
+        mrb_yield(mrb, blk, mrb_str_substr(mrb, self, m->beg[0], m->end[0] - m->beg[0]));
+      } else {
+        mrb_value argv = mrb_ary_new_capa(mrb, m->num_regs - 1);
+        for(i = 1; i < m->num_regs; ++i) {
+          mrb_ary_push(mrb, argv, mrb_str_substr(mrb, self, m->beg[i], m->end[i] - m->beg[i]));
+        }
+        mrb_yield(mrb, blk, argv);
+      }
+    }
+
+    last_end_pos = m->end[0];
+  }
+
+  return result;
+}
+
+// ISO 15.2.10.5.35
+static mrb_value
+string_split(mrb_state* mrb, mrb_value self) {
+  mrb_value pattern = mrb_nil_value(); mrb_int limit = 0;
+  int argc = mrb_get_args(mrb, "|oi", &pattern, &limit);
+
+  if(argc == 0) { // check $; global variable
+    pattern = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$;"));
+    if(!mrb_nil_p(pattern)) { argc = 1; }
+  }
+
+  if(mrb_nil_p(pattern) || mrb_string_p(pattern)) {
+    return mrb_funcall(mrb, self, "string_split", argc, pattern, mrb_fixnum_value(limit));
+  }
+
+  mrb_value const result = mrb_ary_new(mrb);
+  if(RSTRING_LEN(self) == 0) { return result; }
+
+  OnigRegex reg;
+  Data_Get_Struct(mrb, pattern, &mrb_onig_regexp_type, reg);
+  mrb_value const match_value = create_onig_region(mrb, self, pattern);
+  OnigRegion* const match = (OnigRegion*)DATA_PTR(match_value);
+  int last_end_pos = 0, next_match_pos = 0;
+  mrb_int num_matches = 0;
+
+  while (limit <= 0 || (limit - 1) > num_matches) {
+    int i;
+    if(next_match_pos >= RSTRING_LEN(self) ||
+       onig_match_common(mrb, reg, match_value, self, next_match_pos) == ONIG_MISMATCH) { break; }
+
+    if (last_end_pos == match->end[0]) {
+      ++next_match_pos;
+      // Remove this loop if not using UTF-8
+      for (; next_match_pos < RSTRING_LEN(self) && (RSTRING_PTR(self)[next_match_pos] & 0xC0) == 0x80;
+          ++next_match_pos) {}
+    } else {
+      mrb_ary_push(mrb, result, mrb_str_substr(
+          mrb, self, last_end_pos, match->beg[0] - last_end_pos));
+      // If there are captures, add them to the array
+      for (i = 1; i < match->num_regs; ++i) {
+        mrb_ary_push(mrb, result, mrb_str_substr(
+            mrb, self, match->beg[i], match->end[i] - match->beg[i]));
+      }
+      last_end_pos = match->end[0];
+      next_match_pos = last_end_pos;
+      ++num_matches;
+    }
+  }
+  if (last_end_pos <= RSTRING_LEN(self)) {
+    mrb_ary_push(mrb, result, mrb_str_substr(
+        mrb, self, last_end_pos, RSTRING_LEN(self) - last_end_pos));
+  }
+
+  if (limit == 0) { // remove empty trailing elements
+    int count = 0, i;
+    for (i = RARRAY_LEN(result); i > 0; --i) {
+      mrb_assert(mrb_string_p(RARRAY_PTR(result)[i - 1]));
+      if (RSTRING_LEN(RARRAY_PTR(result)[i - 1]) != 0) { break; }
+      else { ++count; }
+    }
+    if(count > 0) {
+      return mrb_ary_new_from_values(mrb, RARRAY_LEN(result) - count, RARRAY_PTR(result));
+    }
+  }
+
+  return result;
+}
+
+// ISO 15.2.10.5.36
+static mrb_value
+string_sub(mrb_state* mrb, mrb_value self) {
+  mrb_value blk, match_expr, replace_expr = mrb_nil_value();
+  int const argc = mrb_get_args(mrb, "&o|S", &blk, &match_expr, &replace_expr);
+
+  if(mrb_string_p(match_expr)) {
+    mrb_value argv[] = { match_expr, replace_expr };
+    return mrb_funcall_with_block(mrb, self, mrb_intern_lit(mrb, "string_sub"), argc, argv, blk);
+  }
+
+  if(!mrb_nil_p(blk) && !mrb_nil_p(replace_expr)) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "both block and replace expression must not be passed");
+  }
+
+  OnigRegex reg;
+  Data_Get_Struct(mrb, match_expr, &mrb_onig_regexp_type, reg);
+  mrb_value const result = mrb_str_new(mrb, NULL, 0);
+  mrb_value const match_value = create_onig_region(mrb, self, match_expr);
+  OnigRegion* const match = (OnigRegion*)DATA_PTR(match_value);
+
+  int const onig_result = onig_match_common(mrb, reg, match_value, self, 0);
+  if(onig_result == ONIG_MISMATCH) { return self; }
+
+  mrb_str_cat(mrb, result, RSTRING_PTR(self), match->beg[0]);
+
+  if(mrb_nil_p(blk)) {
+    append_replace_str(mrb, result, replace_expr, self, reg, match);
+  } else {
+    mrb_value const tmp_str = mrb_str_to_str(mrb, mrb_yield(mrb, blk, mrb_str_substr(
+        mrb, self, match->beg[0], match->end[0] - match->beg[0])));
+    mrb_assert(mrb_string_p(tmp_str));
+    mrb_str_concat(mrb, result, tmp_str);
+  }
+
+  int const last_end_pos = match->end[0];
+  mrb_str_cat(mrb, result, RSTRING_PTR(self) + last_end_pos, RSTRING_LEN(self) - last_end_pos);
+
+  return result;
+}
+
+static mrb_value
+onig_regexp_clear_global_variables(mrb_state* mrb, mrb_value self) {
+  mrb_gv_remove(mrb, mrb_intern_lit(mrb, "$~"));
+  mrb_gv_remove(mrb, mrb_intern_lit(mrb, "$&"));
+  mrb_gv_remove(mrb, mrb_intern_lit(mrb, "$`"));
+  mrb_gv_remove(mrb, mrb_intern_lit(mrb, "$'"));
+  mrb_gv_remove(mrb, mrb_intern_lit(mrb, "$+"));
+
+  int idx;
+  for(idx = 1; idx < 10; ++idx) {
+    char const n[] = { '$', '0' + idx };
+    mrb_gv_remove(mrb, mrb_intern(mrb, n, 2));
+  }
+
+  return self;
+}
+
+static mrb_value
+onig_regexp_does_set_global_variables(mrb_state* mrb, mrb_value self) {
+  (void)self;
+  return mrb_obj_iv_get(mrb, (struct RObject*)mrb_class_get(mrb, "OnigRegexp"),
+                        mrb_intern_lit(mrb, "@set_global_variables"));
+}
+static mrb_value
+onig_regexp_set_set_global_variables(mrb_state* mrb, mrb_value self) {
+  mrb_value arg;
+  mrb_get_args(mrb, "o", &arg);
+  mrb_value const ret = mrb_bool_value(mrb_bool(arg));
+  mrb_obj_iv_set(mrb, (struct RObject*)mrb_class_get(mrb, "OnigRegexp"),
+                 mrb_intern_lit(mrb, "@set_global_variables"), ret);
+  onig_regexp_clear_global_variables(mrb, self);
+  return ret;
+}
+
+// ISO 15.2.15.6.2
+static mrb_value
+onig_regexp_escape(mrb_state* mrb, mrb_value self) {
+  char* str_begin; mrb_args_int str_len;
+  mrb_get_args(mrb, "s", &str_begin, &str_len);
+
+  mrb_value const ret = mrb_str_new(mrb, NULL, 0);
+  char escaped_char = 0;
+  int substr_count = 0;
+  char const* str = str_begin;
+
+  for(; str < (str_begin + str_len); ++str) {
+    switch(*str) {
+      case '\n': escaped_char = 'n'; break;
+      case '\t': escaped_char = 't'; break;
+      case '\r': escaped_char = 'r'; break;
+      case '\f': escaped_char = 'f'; break;
+
+      case ' ':
+      case '#':
+      case '$':
+      case '(':
+      case ')':
+      case '*':
+      case '+':
+      case '-':
+      case '.':
+      case '?':
+      case '[':
+      case '\\':
+      case ']':
+      case '^':
+      case '{':
+      case '|':
+      case '}':
+        escaped_char = *str; break;
+
+      default: ++substr_count; continue;
+    }
+
+    mrb_str_cat(mrb, ret, str - substr_count, substr_count);
+    substr_count = 0;
+
+    char const c[] = { '\\', escaped_char };
+    mrb_str_cat(mrb, ret, c, 2);
+  }
+  mrb_str_cat(mrb, ret, str - substr_count, substr_count);
+  return ret;
+}
+
+void
+mrb_mruby_onig_regexp_gem_init(mrb_state* mrb) {
+  struct RClass *clazz;
+
+  clazz = mrb_define_class(mrb, "OnigRegexp", mrb->object_class);
+  MRB_SET_INSTANCE_TT(clazz, MRB_TT_DATA);
+
+  // enable global variables setting in onig_match_common by default
+  mrb_obj_iv_set(mrb, (struct RObject*)clazz, mrb_intern_lit(mrb, "@set_global_variables"), mrb_true_value());
+
+  mrb_define_const(mrb, clazz, "IGNORECASE", mrb_fixnum_value(ONIG_OPTION_IGNORECASE));
+  mrb_define_const(mrb, clazz, "EXTENDED", mrb_fixnum_value(ONIG_OPTION_EXTEND));
+  mrb_define_const(mrb, clazz, "MULTILINE", mrb_fixnum_value(ONIG_OPTION_MULTILINE));
+  mrb_define_const(mrb, clazz, "SINGLELINE", mrb_fixnum_value(ONIG_OPTION_SINGLELINE));
+  mrb_define_const(mrb, clazz, "FIND_LONGEST", mrb_fixnum_value(ONIG_OPTION_FIND_LONGEST));
+  mrb_define_const(mrb, clazz, "FIND_NOT_EMPTY", mrb_fixnum_value(ONIG_OPTION_FIND_NOT_EMPTY));
+  mrb_define_const(mrb, clazz, "NEGATE_SINGLELINE", mrb_fixnum_value(ONIG_OPTION_NEGATE_SINGLELINE));
+  mrb_define_const(mrb, clazz, "DONT_CAPTURE_GROUP", mrb_fixnum_value(ONIG_OPTION_DONT_CAPTURE_GROUP));
+  mrb_define_const(mrb, clazz, "CAPTURE_GROUP", mrb_fixnum_value(ONIG_OPTION_CAPTURE_GROUP));
+  mrb_define_const(mrb, clazz, "NOTBOL", mrb_fixnum_value(ONIG_OPTION_NOTBOL));
+  mrb_define_const(mrb, clazz, "NOTEOL", mrb_fixnum_value(ONIG_OPTION_NOTEOL));
+  mrb_define_const(mrb, clazz, "POSIX_REGION", mrb_fixnum_value(ONIG_OPTION_POSIX_REGION));
+#ifdef ONIG_OPTION_ASCII_RANGE
+  mrb_define_const(mrb, clazz, "ASCII_RANGE", mrb_fixnum_value(ONIG_OPTION_ASCII_RANGE));
+#endif
+#ifdef ONIG_OPTION_POSIX_BRACKET_ALL_RANGE
+  mrb_define_const(mrb, clazz, "POSIX_BRACKET_ALL_RANGE", mrb_fixnum_value(ONIG_OPTION_POSIX_BRACKET_ALL_RANGE));
+#endif
+#ifdef ONIG_OPTION_WORD_BOUND_ALL_RANGE
+  mrb_define_const(mrb, clazz, "WORD_BOUND_ALL_RANGE", mrb_fixnum_value(ONIG_OPTION_WORD_BOUND_ALL_RANGE));
+#endif
+#ifdef ONIG_OPTION_NEWLINE_CRLF
+  mrb_define_const(mrb, clazz, "NEWLINE_CRLF", mrb_fixnum_value(ONIG_OPTION_NEWLINE_CRLF));
+#endif
+#ifdef ONIG_OPTION_NOTBOS
+  mrb_define_const(mrb, clazz, "NOTBOS", mrb_fixnum_value(ONIG_OPTION_NOTBOS));
+#endif
+#ifdef ONIG_OPTION_NOTEOS
+  mrb_define_const(mrb, clazz, "NOTEOS", mrb_fixnum_value(ONIG_OPTION_NOTEOS));
+#endif
+
+  mrb_define_method(mrb, clazz, "initialize", onig_regexp_initialize, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(2));
+  mrb_define_method(mrb, clazz, "==", onig_regexp_equal, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, clazz, "match", onig_regexp_match, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, clazz, "casefold?", onig_regexp_casefold_p, MRB_ARGS_NONE());
+
+  mrb_define_method(mrb, clazz, "options", onig_regexp_options, MRB_ARGS_NONE());
+  mrb_define_method(mrb, clazz, "inspect", onig_regexp_inspect, MRB_ARGS_NONE());
+  mrb_define_method(mrb, clazz, "to_s", onig_regexp_to_s, MRB_ARGS_NONE());
+
+  mrb_define_module_function(mrb, clazz, "escape", onig_regexp_escape, MRB_ARGS_REQ(1));
+  mrb_define_module_function(mrb, clazz, "quote", onig_regexp_escape, MRB_ARGS_REQ(1));
+  mrb_define_module_function(mrb, clazz, "version", onig_regexp_version, MRB_ARGS_NONE());
+  mrb_define_module_function(mrb, clazz, "set_global_variables?", onig_regexp_does_set_global_variables, MRB_ARGS_NONE());
+  mrb_define_module_function(mrb, clazz, "set_global_variables=", onig_regexp_set_set_global_variables, MRB_ARGS_REQ(1));
+  mrb_define_module_function(mrb, clazz, "clear_global_variables", onig_regexp_clear_global_variables, MRB_ARGS_NONE());
+
+  struct RClass* match_data = mrb_define_class(mrb, "OnigMatchData", mrb->object_class);
+  MRB_SET_INSTANCE_TT(clazz, MRB_TT_DATA);
+  mrb_undef_class_method(mrb, match_data, "new");
+
+  // mrb_define_method(mrb, match_data, "==", &match_data_eq);
+  mrb_define_method(mrb, match_data, "[]", &match_data_index, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, match_data, "begin", &match_data_begin, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, match_data, "captures", &match_data_captures, MRB_ARGS_NONE());
+  mrb_define_method(mrb, match_data, "end", &match_data_end, MRB_ARGS_REQ(1));
+  // mrb_define_method(mrb, match_data, "eql?", &match_data_eq);
+  // mrb_define_method(mrb, match_data, "hash", &match_data_hash);
+  mrb_define_method(mrb, match_data, "initialize_copy", &match_data_copy, MRB_ARGS_REQ(1));
+  // mrb_define_method(mrb, match_data, "inspect", &match_data_inspect);
+  mrb_define_method(mrb, match_data, "length", &match_data_length, MRB_ARGS_NONE());
+  // mrb_define_method(mrb, match_data, "names", &match_data_names);
+  mrb_define_method(mrb, match_data, "offset", &match_data_offset, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, match_data, "post_match", &match_data_post_match, MRB_ARGS_NONE());
+  mrb_define_method(mrb, match_data, "pre_match", &match_data_pre_match, MRB_ARGS_NONE());
+  mrb_define_method(mrb, match_data, "regexp", &match_data_regexp, MRB_ARGS_NONE());
+  mrb_define_method(mrb, match_data, "size", &match_data_length, MRB_ARGS_NONE());
+  mrb_define_method(mrb, match_data, "string", &match_data_string, MRB_ARGS_NONE());
+  mrb_define_method(mrb, match_data, "to_a", &match_data_to_a, MRB_ARGS_NONE());
+  mrb_define_method(mrb, match_data, "to_s", &match_data_to_s, MRB_ARGS_NONE());
+  // mrb_define_method(mrb, match_data, "values_at", &match_data_values_at);
+
+  mrb_define_method(mrb, mrb->string_class, "onig_regexp_gsub", &string_gsub, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1) | MRB_ARGS_BLOCK());
+  mrb_define_method(mrb, mrb->string_class, "onig_regexp_sub", &string_sub, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1) | MRB_ARGS_BLOCK());
+  mrb_define_method(mrb, mrb->string_class, "onig_regexp_split", &string_split, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, mrb->string_class, "onig_regexp_scan", &string_scan, MRB_ARGS_REQ(1) | MRB_ARGS_BLOCK());
+}
+
+void
+mrb_mruby_onig_regexp_gem_final(mrb_state* mrb) {
+  (void)mrb;
+}
+
+// vim:set et:
Index: EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/test/mruby_onig_regexp.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/test/mruby_onig_regexp.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-onig-regexp/test/mruby_onig_regexp.rb	(revision 279)
@@ -0,0 +1,396 @@
+
+# Constant
+assert("OnigRegexp::CONSTANT") do
+  OnigRegexp::IGNORECASE == 1 and OnigRegexp::EXTENDED == 2 and OnigRegexp::MULTILINE == 4
+end
+
+
+# Class method
+assert('OnigRgexp.compile', '15.2.15.6.2') do
+  assert_equal OnigRegexp.compile('.*'), OnigRegexp.compile('.*')
+end
+
+assert('OnigRegexp.escape', '15.2.15.6.2') do
+  escaping_chars = "\n\t\r\f #$()*+-.?[\\]^{|}"
+  assert_equal '\n\t\r\f\\ \#\$\(\)\*\+\-\.\?\[\\\\\]\^\{\|\}', OnigRegexp.escape(escaping_chars)
+  assert_equal 'cute\nmruby\tcute', OnigRegexp.escape("cute\nmruby\tcute")
+end
+
+assert('OnigRegexp.last_match', '15.2.15.6.3') do
+  OnigRegexp.new('.*') =~ 'ginka'
+  assert_equal 'ginka', OnigRegexp.last_match[0]
+end
+
+assert('OnigRegexp.quote', '15.2.15.6.4') do
+  assert_equal '\n', OnigRegexp.quote("\n")
+end
+
+# Instance method
+assert('OnigRegexp#initialize', '15.2.15.7.1') do
+  OnigRegexp.new(".*") and OnigRegexp.new(".*", OnigRegexp::MULTILINE)
+end
+
+assert('OnigRegexp#initialize_copy', '15.2.15.7.2') do
+  r1 = OnigRegexp.new(".*")
+  r2 = r1.dup
+  assert_equal r1, r2
+  assert_equal 'kawa', r2.match('kawa')[0]
+end
+
+assert("OnigRegexp#==", '15.2.15.7.3') do
+  reg1 = reg2 = OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+")
+  reg3 = OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+")
+  reg4 = OnigRegexp.new("(https://[^/]+)[-a-zA-Z0-9./]+")
+
+  assert_true(reg1 == reg2 && reg1 == reg3 && !(reg1 == reg4))
+
+  assert_false(OnigRegexp.new("a") == "a")
+end
+
+assert("OnigRegexp#===", '15.2.15.7.4') do
+  reg = OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+")
+  assert_true reg === "http://example.com"
+  assert_false reg === "htt://example.com"
+end
+
+assert('OnigRegexp#=~', '15.2.15.7.5') do
+  assert_equal(0) { OnigRegexp.new('.*') =~ 'akari' }
+  assert_equal(nil) { OnigRegexp.new('t') =~ 'akari' }
+end
+
+assert("OnigRegexp#casefold?", '15.2.15.7.6') do
+  assert_false OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+", OnigRegexp::MULTILINE).casefold?
+  assert_true OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+", OnigRegexp::IGNORECASE | OnigRegexp::EXTENDED).casefold?
+  assert_true OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+", OnigRegexp::MULTILINE | OnigRegexp::IGNORECASE).casefold?
+  assert_false OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+").casefold?
+  assert_true OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+", true).casefold?
+end
+
+assert("OnigRegexp#match", '15.2.15.7.7') do
+  reg = OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+")
+  assert_false reg.match("http://masamitsu-murase.12345/hoge.html").nil?
+  assert_nil reg.match("http:///masamitsu-murase.12345/hoge.html")
+end
+
+assert("OnigRegexp#source", '15.2.15.7.8') do
+  str = "(https?://[^/]+)[-a-zA-Z0-9./]+"
+  reg = OnigRegexp.new(str)
+
+  reg.source == str
+end
+
+if OnigRegexp.const_defined? :ASCII_RANGE
+  assert('OnigRegexp#options (no options)') do
+    assert_equal OnigRegexp::ASCII_RANGE | OnigRegexp::POSIX_BRACKET_ALL_RANGE | OnigRegexp::WORD_BOUND_ALL_RANGE, OnigRegexp.new(".*").options
+  end
+
+  assert('OnigRegexp#options (multiline)') do
+    assert_equal OnigRegexp::MULTILINE | OnigRegexp::ASCII_RANGE | OnigRegexp::POSIX_BRACKET_ALL_RANGE | OnigRegexp::WORD_BOUND_ALL_RANGE, OnigRegexp.new(".*", OnigRegexp::MULTILINE).options
+  end
+end
+
+assert("OnigRegexp#inspect") do
+  reg = OnigRegexp.new("(https?://[^/]+)[-a-zA-Z0-9./]+")
+
+  assert_equal '/(https?:\/\/[^\/]+)[-a-zA-Z0-9.\/]+/', reg.inspect
+  assert_equal '/abc\nd\te/mi', OnigRegexp.new("abc\nd\te", OnigRegexp::MULTILINE | OnigRegexp::IGNORECASE).inspect
+  assert_equal '/abc/min', OnigRegexp.new("abc", OnigRegexp::MULTILINE | OnigRegexp::IGNORECASE, "none").inspect
+end
+
+assert("OnigRegexp#to_s") do
+  assert_equal '(?-mix:ab+c)', OnigRegexp.new("ab+c").to_s
+  assert_equal '(?-mix:ab+c)', /ab+c/.to_s
+  assert_equal '(?mx-i:ab+c)', OnigRegexp.new("ab+c", OnigRegexp::MULTILINE | OnigRegexp::EXTENDED).to_s
+  assert_equal '(?mi-x:ab+c)', /ab+c/im.to_s
+  assert_equal '(?mi-x:ab+c)', /ab+c/imn.to_s
+end
+
+assert("OnigRegexp#to_s (composition)") do
+  re1 = OnigRegexp.new("ab+c")
+  re2 = OnigRegexp.new("xy#{re1}z")
+  assert_equal '(?-mix:xy(?-mix:ab+c)z)', re2.to_s
+
+  re3 = OnigRegexp.new("ab.+c", OnigRegexp::MULTILINE)
+  re4 = OnigRegexp.new("xy#{re3}z", OnigRegexp::IGNORECASE)
+  assert_equal '(?i-mx:xy(?m-ix:ab.+c)z)', re4.to_s
+end
+
+# Extended patterns.
+assert("OnigRegexp#match (no flags)") do
+  [
+    [ ".*", "abcd\nefg", "abcd" ],
+    [ "^a.", "abcd\naefg", "ab" ],
+    [ "^a.", "bacd\naefg", "ae" ],
+    [ ".$", "bacd\naefg", "d" ]
+  ].each do |reg, str, result|
+    m = OnigRegexp.new(reg).match(str)
+    assert_equal result, m[0] if assert_false m.nil?
+  end
+end
+
+assert("OnigRegexp#match (multiline)") do
+  patterns = [
+    [ OnigRegexp.new(".*", OnigRegexp::MULTILINE), "abcd\nefg", "abcd\nefg" ]
+  ]
+
+  patterns.all?{ |reg, str, result| reg.match(str)[0] == result }
+end
+
+assert("OnigRegexp#match (ignorecase)") do
+  [
+    [ "aBcD", "00AbcDef", "AbcD" ],
+    [ "0x[a-f]+", "00XaBCdefG", "0XaBCdef" ],
+    [ "0x[^c-f]+", "00XaBCdefG", "0XaB" ]
+  ].each do |reg, str, result|
+    m = OnigRegexp.new(reg, OnigRegexp::IGNORECASE|OnigRegexp::EXTENDED).match(str)
+    assert_equal result, m[0] if assert_false m.nil?
+  end
+end
+
+assert("OnigRegexp#match (none encoding)") do
+  assert_equal 2, /\x82/n =~ "ã"
+end
+
+assert('OnigRegexp.version') do
+  OnigRegexp.version.kind_of? String
+end
+
+def onig_match_data_example
+  OnigRegexp.new('(\w+)(\w)').match('+aaabb-')
+end
+
+assert('OnigMatchData.new') do
+  assert_raise(NoMethodError) { OnigMatchData.new('aaa', 'i') }
+end
+
+assert('OnigMatchData#[]', '15.2.16.3.1') do
+  m = onig_match_data_example
+  assert_equal 'aaabb', m[0]
+  assert_equal 'aaab', m[1]
+  assert_equal 'b', m[2]
+  assert_nil m[3]
+
+  m = OnigRegexp.new('(?<name>\w\w)').match('aba')
+  assert_raise(TypeError) { m[[]] }
+  assert_raise(IndexError) { m['nam'] }
+  assert_equal 'ab', m[:name]
+  assert_equal 'ab', m['name']
+  assert_equal 'ab', m[1]
+
+  m = OnigRegexp.new('(\w) (\w) (\w) (\w)').match('a b c d')
+  assert_equal %w(a b c d), m[1..-1]
+end
+
+assert('OnigMatchData#begin', '15.2.16.3.2') do
+  m = onig_match_data_example
+  assert_equal 1, m.begin(0)
+  assert_equal 1, m.begin(1)
+  assert_raise(IndexError) { m.begin 3 }
+end
+
+assert('OnigMatchData#captures', '15.2.16.3.3') do
+  m = onig_match_data_example
+  assert_equal ['aaab', 'b'], m.captures
+
+  m = OnigRegexp.new('(\w+)(\d)?').match('+aaabb-')
+  assert_equal ['aaabb', nil], m.captures
+end
+
+assert('OnigMatchData#end', '15.2.16.3.4') do
+  m = onig_match_data_example
+  assert_equal 6, m.end(0)
+  assert_equal 5, m.end(1)
+  assert_raise(IndexError) { m.end 3 }
+end
+
+assert('OnigMatchData#initialize_copy', '15.2.16.3.5') do
+  m = onig_match_data_example
+  c = m.dup
+  assert_equal m.to_a, c.to_a
+end
+
+assert('OnigMatchData#length', '15.2.16.3.6') do
+  assert_equal 3, onig_match_data_example.length
+end
+
+assert('OnigMatchData#offset', '15.2.16.3.7') do
+  assert_equal [1, 6], onig_match_data_example.offset(0)
+  assert_equal [1, 5], onig_match_data_example.offset(1)
+end
+
+assert('OnigMatchData#post_match', '15.2.16.3.8') do
+  assert_equal '-', onig_match_data_example.post_match
+end
+
+assert('OnigMatchData#pre_match', '15.2.16.3.9') do
+  assert_equal '+', onig_match_data_example.pre_match
+end
+
+assert('OnigMatchData#size', '15.2.16.3.10') do
+  assert_equal 3, onig_match_data_example.length
+end
+
+assert('OnigMatchData#string', '15.2.16.3.11') do
+  assert_equal '+aaabb-', onig_match_data_example.string
+end
+
+assert('OnigMatchData#to_a', '15.2.16.3.12') do
+  assert_equal ['aaabb', 'aaab', 'b'], onig_match_data_example.to_a
+end
+
+assert('OnigMatchData#to_s', '15.2.16.3.13') do
+  assert_equal 'aaabb', onig_match_data_example.to_s
+end
+
+assert('OnigMatchData#regexp') do
+  assert_equal '(\w+)(\w)', onig_match_data_example.regexp.source
+end
+
+assert('Invalid regexp') do
+  assert_raise(ArgumentError) { OnigRegexp.new '[aio' }
+end
+
+assert('String#onig_regexp_gsub') do
+  test_str = 'hello mruby'
+  assert_equal 'h*ll* mr*by', test_str.onig_regexp_gsub(OnigRegexp.new('[aeiou]'), '*')
+  assert_equal 'h<e>ll<o> mr<u>by', test_str.onig_regexp_gsub(OnigRegexp.new('([aeiou])'), '<\1>')
+  assert_equal 'h e l l o  m r u b y ', test_str.onig_regexp_gsub(OnigRegexp.new('\w')) { |v| v + ' ' }
+  assert_equal 'h{e}ll{o} mr{u}by', test_str.onig_regexp_gsub(OnigRegexp.new('(?<hoge>[aeiou])'), '{\k<hoge>}')
+  assert_raise(IndexError) { test_str.onig_regexp_gsub(OnigRegexp.new('(mruby)'), '<\2>') }
+end
+
+assert('String#onig_regexp_scan') do
+  test_str = 'mruby world'
+  assert_equal ['mruby', 'world'], test_str.onig_regexp_scan(OnigRegexp.new('\w+'))
+  assert_equal ['mru', 'by ', 'wor'], test_str.onig_regexp_scan(OnigRegexp.new('...'))
+  assert_equal [['mru'], ['by '], ['wor']], test_str.onig_regexp_scan(OnigRegexp.new('(...)'))
+  assert_equal [['mr', 'ub'], ['y ', 'wo']], test_str.onig_regexp_scan(OnigRegexp.new('(..)(..)'))
+
+  result = []
+  assert_equal test_str, test_str.onig_regexp_scan(OnigRegexp.new('\w+')) { |v| result << "<<#{v}>>" }
+  assert_equal ['<<mruby>>', '<<world>>'], result
+
+  result = ''
+  assert_equal test_str, test_str.onig_regexp_scan(OnigRegexp.new('(.)(.)')) { |x, y| result += y; result += x }
+  assert_equal 'rmbu yowlr', result
+end
+
+assert('String#onig_regexp_sub') do
+  test_str = 'hello mruby'
+  assert_equal 'h*llo mruby', test_str.onig_regexp_sub(OnigRegexp.new('[aeiou]'), '*')
+  assert_equal 'h<e>llo mruby', test_str.onig_regexp_sub(OnigRegexp.new('([aeiou])'), '<\1>')
+  assert_equal 'h ello mruby', test_str.onig_regexp_sub(OnigRegexp.new('\w')) { |v| v + ' ' }
+  assert_equal 'h{e}llo mruby', test_str.onig_regexp_sub(OnigRegexp.new('(?<hoge>[aeiou])'), '{\k<hoge>}')
+end
+
+assert('String#onig_regexp_split') do
+  test_str = 'cute mruby cute'
+  assert_equal ['cute', 'mruby', 'cute'], test_str.onig_regexp_split
+  assert_equal ['cute', 'mruby', 'cute'], test_str.onig_regexp_split(OnigRegexp.new(' '))
+
+  prev_splitter = $;
+  $; = OnigRegexp.new ' \w'
+  assert_equal ['cute', 'ruby', 'ute'], test_str.onig_regexp_split
+  $; = 't'
+  assert_equal ['cu', 'e mruby cu', 'e'], test_str.onig_regexp_split
+  $; = prev_splitter
+
+  assert_equal ['h', 'e', 'l', 'l', 'o'], 'hello'.onig_regexp_split(OnigRegexp.new(''))
+  assert_equal ['h', 'e', 'llo'], 'hello'.onig_regexp_split(OnigRegexp.new(''), 3)
+  assert_equal ['h', 'i', 'd', 'a', 'd'], 'hi dad'.onig_regexp_split(OnigRegexp.new('\s*'))
+
+  test_str = '1, 2, 3, 4, 5,, 6'
+  assert_equal ['1', '2', '3', '4', '5', '', '6'], test_str.onig_regexp_split(OnigRegexp.new(',\s*'))
+
+  test_str = '1,,2,3,,4,,'
+  assert_equal ['1', '', '2', '3', '', '4'], test_str.onig_regexp_split(OnigRegexp.new(','))
+  assert_equal ['1', '', '2', '3,,4,,'], test_str.onig_regexp_split(OnigRegexp.new(','), 4)
+  assert_equal ['1', '', '2', '3', '', '4', '', ''], test_str.onig_regexp_split(OnigRegexp.new(','), -4)
+
+  assert_equal [], ''.onig_regexp_split(OnigRegexp.new(','), -1)
+end
+
+assert('String#index') do
+  assert_equal 0, 'abc'.index('a')
+  assert_nil 'abc'.index('d')
+  assert_equal 3, 'abcabc'.index('a', 1)
+  assert_equal 1, "hello".index(?e)
+
+  assert_equal 0, 'abcabc'.index(/a/)
+  assert_nil 'abc'.index(/d/)
+  assert_equal 3, 'abcabc'.index(/a/, 1)
+  assert_equal 4, "hello".index(/[aeiou]/, -3)
+  assert_equal 3, "regexpindex".index(/e.*x/, 2)
+end
+
+prev_regexp = Regexp
+
+Regexp = OnigRegexp
+
+# global variables
+assert('$~') do
+  m = onig_match_data_example
+  assert_equal m[0], $~[0]
+end
+
+assert('$&') do
+  m = onig_match_data_example
+  assert_equal m[0], $&
+end
+
+assert('$`') do
+  m = onig_match_data_example
+  assert_equal m.pre_match, $`
+end
+
+assert('$\'') do
+  m = onig_match_data_example
+  assert_equal m.post_match, $'
+end
+
+assert('$+') do
+  m = onig_match_data_example
+  assert_equal m[-1], $+
+end
+
+assert('$1 to $9') do
+  onig_match_data_example
+  assert_equal 'aaab', $1
+  assert_equal 'b', $2
+  assert_nil $3
+  assert_nil $4
+  assert_nil $5
+  assert_nil $6
+  assert_nil $7
+  assert_nil $8
+  assert_nil $9
+end
+
+assert('default OnigRegexp.set_global_variables?') do
+  assert_true OnigRegexp.set_global_variables?
+end
+
+assert('change set_global_variables') do
+  m = onig_match_data_example
+  assert_equal m[0], $~[0]
+
+  OnigRegexp.set_global_variables = false
+  assert_false OnigRegexp.set_global_variables?
+
+  # global variables must be cleared when OnigRegexp.set_global_variables gets change
+  assert_nil $~
+
+  onig_match_data_example
+  assert_nil $~
+
+  OnigRegexp.set_global_variables = true
+end
+
+Regexp = Object
+
+assert('OnigRegexp not default') do
+  onig_match_data_example
+  assert_nil $~
+end
+
+Regexp = prev_regexp
Index: EcnlProtoTool/trunk/mrbgems/mruby-pack/.gitignore
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-pack/.gitignore	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-pack/.gitignore	(revision 279)
@@ -0,0 +1,5 @@
+gem_*
+gem-*
+mrb-*.a
+src/*.o
+/tmp
Index: EcnlProtoTool/trunk/mrbgems/mruby-pack/.travis.yml
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-pack/.travis.yml	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-pack/.travis.yml	(revision 279)
@@ -0,0 +1,2 @@
+script:
+  - "ruby run_test.rb all test"
Index: EcnlProtoTool/trunk/mrbgems/mruby-pack/README.md
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-pack/README.md	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-pack/README.md	(revision 279)
@@ -0,0 +1,67 @@
+mruby-pack (pack / unpack)
+=========
+
+mruby-pack provides `Array#pack` and `String#unpack` for mruby.
+
+
+## Installation
+Add the line below into your `build_config.rb`:
+
+```
+  conf.gem :github => 'iij/mruby-pack'
+```
+
+There is no dependency on other mrbgems.
+
+
+## Supported template string
+ - A : arbitrary binary string (space padded, count is width)
+ - a : arbitrary binary string (null padded, count is width)
+ - C : 8-bit unsigned (unsigned char)
+ - c : 8-bit signed (signed char)
+ - D, d: 64-bit float, native format
+ - E : 64-bit float, little endian byte order
+ - e : 32-bit float, little endian byte order
+ - F, f: 32-bit float, native format
+ - G : 64-bit float, network (big-endian) byte order
+ - g : 32-bit float, network (big-endian) byte order
+ - H : hex string (high nibble first)
+ - h : hex string (low nibble first)
+ - I : unsigned integer, native endian (`unsigned int` in C)
+ - i : signed integer, native endian (`int` in C)
+ - L : 32-bit unsigned, native endian (`uint32_t`)
+ - l : 32-bit signed, native endian (`int32_t`)
+ - m : base64 encoded string (see RFC 2045, count is width)
+ - N : 32-bit unsigned, network (big-endian) byte order
+ - n : 16-bit unsigned, network (big-endian) byte order
+ - Q : 64-bit unsigned, native endian (`uint64_t`)
+ - q : 64-bit signed, native endian (`int64_t`)
+ - S : 16-bit unsigned, native endian (`uint16_t`)
+ - s : 16-bit signed, native endian (`int16_t`)
+ - V : 32-bit unsigned, VAX (little-endian) byte order
+ - v : 16-bit unsigned, VAX (little-endian) byte order
+ - Z : same as "a", except that null is added with *
+
+
+## License
+
+Copyright (c) 2012 Internet Initiative Japan Inc.
+
+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 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.
+
Index: EcnlProtoTool/trunk/mrbgems/mruby-pack/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-pack/mrbgem.rake	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-pack/mrbgem.rake	(revision 279)
@@ -0,0 +1,6 @@
+MRuby::Gem::Specification.new('mruby-pack') do |spec|
+  spec.license = 'MIT'
+  spec.authors = 'Internet Initiative Japan Inc.'
+
+  spec.cc.include_paths << "#{build.root}/src"
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-pack/packtest.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-pack/packtest.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-pack/packtest.rb	(revision 279)
@@ -0,0 +1,157 @@
+# encoding: ascii
+
+# a = Array, s = String, t = Template
+
+def packtest(a, s, t)
+  begin
+    r = a.pack(t)
+    return if r == s
+    puts "#{a.inspect}.pack(#{t.inspect}) -> #{r.inspect} should be #{s.inspect}"
+  rescue => r
+    unless r.is_a? s
+      puts "#{a.inspect}.pack(#{t.inspect}) -> #{r.inspect} should be #{s.inspect}"
+    end
+  end
+end
+
+def unpacktest(a, s, t)
+  r = s.unpack(t)
+  return if r == a
+  puts "#{s.inspect}.unpack(#{t.inspect}) -> #{r.inspect} should be #{a.inspect}"
+end
+
+def pptest(a, s, t)
+  packtest(a, s, t)
+  unpacktest(a, s, t)
+end
+
+pptest [1], "\x01", "C"
+
+packtest [1.1], "\x01", "C"
+packtest [-1], "\xff", "C"
+packtest [1,2], "\x01\x02", "C2"
+#packtest [1], "X", ArgumentError
+
+unpacktest [48, nil], "0", "CC"
+unpacktest [160, -96], "\xa0\xa0", "Cc"
+unpacktest [49, 50, 51], "123", "C*"
+
+pptest [12849], "12", "S"
+unpacktest [nil], "0", "S"
+unpacktest [12849, nil], "123", "SS"
+unpacktest [12849], "123", "S*"
+
+pptest [10000], "\x27\x10", "s>"
+pptest [-10000], "\xd8\xf0", "s>"
+pptest [50000], "\xc3\x50", "S>"
+
+pptest [10000], "\x10\x27", "s<"
+pptest [-10000], "\xf0\xd8", "s<"
+pptest [50000], "\x50\xc3", "S<"
+
+pptest [1000000000], "\x3b\x9a\xca\x00", "l>"
+pptest [-1000000000], "\xc4\x65\x36\x00", "l>"
+
+pptest [1], "\x01\x00\x00\x00", "L<"
+pptest [258], "\x02\x01\x00\x00", "L<"
+pptest [66051], "\x03\x02\x01\x00", "L<"
+pptest [16909060], "\x04\x03\x02\x01", "L<"
+pptest [16909060], "\x01\x02\x03\x04", "L>"
+
+packtest [-1], "\xff\xff\xff\xff", "L<"
+
+pptest [1000000000], "\x00\x00\x00\x00\x3b\x9a\xca\x00", "q>"
+pptest [-1000000000], "\xff\xff\xff\xff\xc4\x65\x36\x00", "q>"
+
+if (2**33).is_a? Fixnum
+  pptest [81985529216486895],    "\x01\x23\x45\x67\x89\xab\xcd\xef", "q>"
+  pptest [-1167088121787636991], "\x01\x23\x45\x67\x89\xab\xcd\xef", "q<"
+end
+
+pptest [16909060], "\x01\x02\x03\x04", "N"
+pptest [258], "\x01\x02", "n"
+pptest [32769], "\x80\x01", "n"
+
+pptest [16909060], "\x04\x03\x02\x01", "V"
+pptest [258], "\x02\x01", "v"
+
+packtest [""], "", "m"
+packtest ["a"], "YQ==\n", "m"
+packtest ["ab"], "YWI=\n", "m"
+packtest ["abc"], "YWJj\n", "m"
+packtest ["abcd"], "YWJjZA==\n", "m"
+
+unpacktest [""], "", "m"
+unpacktest ["a"], "YQ==\n", "m"
+unpacktest ["ab"], "YWI=\n", "m"
+unpacktest ["abc"], "YWJj\n", "m"
+unpacktest ["abcd"], "YWJjZA==\n", "m"
+
+packtest [""], "\0", "H"
+packtest ["3"], "0", "H"
+packtest ["34"], "", "H0"
+packtest ["34"], "0", "H"
+packtest ["34"], "4", "H2"
+packtest ["34"], "4\0", "H3"
+packtest ["3456"], "4P", "H3"
+packtest ["34563"], "4V0", "H*"
+packtest ["5a"], "Z", "H*"
+packtest ["5A"], "Z", "H*"
+
+unpacktest [""], "", "H"
+unpacktest [""], "0", "H0"
+unpacktest ["3"], "0", "H"
+unpacktest ["30"], "0", "H2"
+unpacktest ["30"], "0", "H3"
+unpacktest ["303"], "01", "H3"
+unpacktest ["303132"], "012", "H*"
+unpacktest ["3031", 50], "012", "H4C"
+unpacktest ["5a"], "Z", "H*"
+
+packtest [""], "\0", "h"
+packtest ["3"], "\03", "h"
+packtest ["34"], "", "h0"
+packtest ["34"], "\03", "h"
+packtest ["34"], "C", "h2"
+packtest ["34"], "C\0", "h3"
+packtest ["3456"], "C\05", "h3"
+packtest ["34563"], "Ce\03", "h*"
+
+packtest   [""],    " ",   "A"
+unpacktest [""],    "",    "A"
+pptest     ["1"],   "1",   "A"
+pptest     ["1"],   "1 ",  "A2"
+unpacktest ["1"],   "1",   "A2"
+unpacktest ["1"],   "1 ",  "A2"
+unpacktest ["1"],   "1\0", "A2"
+packtest   ["12"],  "1",   "A"
+unpacktest ["1"],   "12",  "A"
+pptest     ["123"], "123", "A*"
+packtest   ["1","2"], "2", "A0A"
+unpacktest ["","2"],  "2", "A0A"
+
+packtest   [""],    "\0",  "a"
+unpacktest [""],    "",    "a"
+pptest     ["1"],   "1",   "a"
+pptest     ["1 "],  "1 ",  "a2"
+pptest     ["1\0"], "1\0", "a2"
+packtest   ["1"],   "1\0", "a2"
+pptest     ["123"], "123", "a*"
+
+packtest   [""],    "\0",    "Z"
+unpacktest [""],    "",      "Z"
+pptest     ["1"],   "1",     "Z"
+pptest     ["1"],   "1\0",   "Z2"
+pptest     ["1 "],  "1 ",    "Z2"
+pptest     ["123"], "123\0", "Z*"
+pptest     ["1","2"], "12",      "ZZ"
+pptest     ["1","2"], "1\0002",  "Z*Z"
+unpacktest ["1","3"], "1\00023", "Z3Z"
+
+packtest   [1, 2], "\x01\x02", "CyC"
+
+packtest   [65], "A", 'U'
+packtest   [59411], "\xEE\xA0\x93", 'U'
+
+pptest     [1], "\x00\x01", "xC"
+unpacktest [2], "\xcc\x02", "xC"
Index: EcnlProtoTool/trunk/mrbgems/mruby-pack/run_test.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-pack/run_test.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-pack/run_test.rb	(revision 279)
@@ -0,0 +1,26 @@
+#!/usr/bin/env ruby
+#
+# mrbgems test runner
+#
+
+gemname = File.basename(File.dirname(File.expand_path __FILE__))
+
+if __FILE__ == $0
+  repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby'
+  build_args = ARGV
+  build_args = ['all', 'test']  if build_args.nil? or build_args.empty?
+
+  Dir.mkdir 'tmp'  unless File.exist?('tmp')
+  unless File.exist?(dir)
+    system "git clone #{repository} #{dir}"
+  end
+
+  exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}])
+end
+
+MRuby::Build.new do |conf|
+  toolchain :gcc
+  conf.gembox 'default'
+
+  conf.gem File.expand_path(File.dirname(__FILE__))
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-pack/src/pack.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-pack/src/pack.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-pack/src/pack.c	(revision 279)
@@ -0,0 +1,1173 @@
+/*
+ ** pack.c - Array#pack, String#unpack
+ */
+
+#include "mruby.h"
+#include "error.h"
+#include "mruby/array.h"
+#include "mruby/class.h"
+#include "mruby/numeric.h"
+#include "mruby/string.h"
+#include "mruby/variable.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+struct tmpl {
+  mrb_value str;
+  int idx;
+};
+
+enum {
+  PACK_DIR_CHAR,      /* C */
+  PACK_DIR_SHORT,     /* S */
+  PACK_DIR_LONG,      /* L */
+  PACK_DIR_QUAD,      /* Q */
+  //PACK_DIR_INT,     /* i */
+  //PACK_DIR_VAX,
+  PACK_DIR_UTF8,      /* U */
+  //PACK_DIR_BER,
+  PACK_DIR_DOUBLE,    /* E */
+  PACK_DIR_FLOAT,     /* f */
+  PACK_DIR_STR,       /* A */
+  PACK_DIR_HEX,       /* h */
+  PACK_DIR_BASE64,    /* m */
+  PACK_DIR_NUL,       /* x */
+  PACK_DIR_INVALID
+};
+
+enum {
+  PACK_TYPE_INTEGER,
+  PACK_TYPE_FLOAT,
+  PACK_TYPE_STRING,
+  PACK_TYPE_NONE
+};
+
+#define PACK_FLAG_s             0x00000001	/* native size ("_" "!") */
+#define PACK_FLAG_a             0x00000002	/* null padding ("a") */
+#define PACK_FLAG_Z             0x00000004	/* append nul char ("z") */
+#define PACK_FLAG_SIGNED        0x00000008	/* native size ("_" "!") */
+#define PACK_FLAG_GT            0x00000010	/* big endian (">") */
+#define PACK_FLAG_LT            0x00000020	/* little endian ("<") */
+#define PACK_FLAG_WIDTH         0x00000040	/* "count" is "width" */
+#define PACK_FLAG_LSB           0x00000080	/* LSB / low nibble first */
+#define PACK_FLAG_COUNT2        0x00000100	/* "count" is special... */
+#define PACK_FLAG_LITTLEENDIAN  0x00000200	/* little endian actually */
+
+#define PACK_BASE64_IGNORE	0xff
+#define PACK_BASE64_PADDING	0xfe
+
+static int littleendian = 0;
+
+const static unsigned char base64chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static signed char base64_dec_tab[128];
+
+
+static int
+check_little_endian(void)
+{
+  unsigned int n = 1;
+  return (*(unsigned char *)&n == 1);
+}
+
+static unsigned int
+hex2int(unsigned char ch)
+{
+  if (ch >= '0' && ch <= '9') 
+    return ch - '0';
+  else if (ch >= 'A' && ch <= 'F')
+    return 10 + (ch - 'A');
+  else if (ch >= 'a' && ch <= 'f')
+    return 10 + (ch - 'a');
+  else
+    return 0;
+}
+
+static void
+make_base64_dec_tab(void)
+{
+  int i;
+  memset(base64_dec_tab, PACK_BASE64_IGNORE, sizeof(base64_dec_tab));
+  for (i = 0; i < 26; i++)
+    base64_dec_tab['A' + i] = i;
+  for (i = 0; i < 26; i++)
+    base64_dec_tab['a' + i] = i + 26;
+  for (i = 0; i < 10; i++)
+    base64_dec_tab['0' + i] = i + 52;
+  base64_dec_tab['+'] = 62;
+  base64_dec_tab['/'] = 63;
+  base64_dec_tab['='] = PACK_BASE64_PADDING;
+}
+
+static mrb_value
+str_len_ensure(mrb_state *mrb, mrb_value str, int len)
+{
+  int n = RSTRING_LEN(str);
+  if (len > n) {
+    do {
+      n *= 2;
+    } while (len > n);
+    str = mrb_str_resize(mrb, str, n);
+  }
+  return str;
+}
+
+
+static int
+pack_c(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
+{
+  str = str_len_ensure(mrb, str, sidx + 1);
+  RSTRING_PTR(str)[sidx] = mrb_fixnum(o);
+  return 1;
+}
+
+static int
+unpack_c(mrb_state *mrb, const void *src, int srclen, mrb_value ary, unsigned int flags)
+{
+  if (flags & PACK_FLAG_SIGNED)
+    mrb_ary_push(mrb, ary, mrb_fixnum_value(*(signed char *)src));
+  else
+    mrb_ary_push(mrb, ary, mrb_fixnum_value(*(unsigned char *)src));
+  return 1;
+}
+
+static int
+pack_s(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
+{
+  unsigned short n;
+
+  str = str_len_ensure(mrb, str, sidx + 2);
+  n = mrb_fixnum(o);
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+    RSTRING_PTR(str)[sidx+0] = n % 256;
+    RSTRING_PTR(str)[sidx+1] = n / 256;
+  } else {
+    RSTRING_PTR(str)[sidx+0] = n / 256;
+    RSTRING_PTR(str)[sidx+1] = n % 256;
+  }
+  return 2;
+}
+
+static int
+unpack_s(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
+{
+  int n;
+
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+    n = src[1] * 256 + src[0];
+  } else {
+    n = src[0] * 256 + src[1];
+  }
+  if ((flags & PACK_FLAG_SIGNED) && (n >= 0x8000)) {
+    n -= 0x10000;
+  }
+  mrb_ary_push(mrb, ary, mrb_fixnum_value(n));
+  return 2;
+}
+
+static int
+pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
+{
+  unsigned long n;
+  str = str_len_ensure(mrb, str, sidx + 4);
+  n = mrb_fixnum(o);
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+    RSTRING_PTR(str)[sidx+0] = n & 0xff;
+    RSTRING_PTR(str)[sidx+1] = n >> 8;
+    RSTRING_PTR(str)[sidx+2] = n >> 16;
+    RSTRING_PTR(str)[sidx+3] = n >> 24;
+  } else {
+    RSTRING_PTR(str)[sidx+0] = n >> 24;
+    RSTRING_PTR(str)[sidx+1] = n >> 16;
+    RSTRING_PTR(str)[sidx+2] = n >> 8;
+    RSTRING_PTR(str)[sidx+3] = n & 0xff;
+  }
+  return 4;
+}
+
+static int
+unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
+{
+  char msg[60];
+  uint32_t ul;
+  mrb_int n;
+
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+    ul = (uint32_t)src[3] * 256*256*256;
+    ul += (uint32_t)src[2] *256*256;
+    ul += (uint32_t)src[1] *256;
+    ul += (uint32_t)src[0];
+  } else {
+    ul = (uint32_t)src[0] * 256*256*256;
+    ul += (uint32_t)src[1] *256*256;
+    ul += (uint32_t)src[2] *256;
+    ul += (uint32_t)src[3];
+  }
+  if (flags & PACK_FLAG_SIGNED) {
+    int32_t sl = ul;
+    if (!FIXABLE(sl)) {
+      snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %ld", (long)sl);
+      mrb_raise(mrb, E_RANGE_ERROR, msg);
+    }
+    n = sl;
+  } else {
+    if (!POSFIXABLE(ul)) {
+      snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %lu", (unsigned long)ul);
+      mrb_raise(mrb, E_RANGE_ERROR, msg);
+    }
+    n = ul;
+  }
+  mrb_ary_push(mrb, ary, mrb_fixnum_value(n));
+  return 4;
+}
+
+static int
+pack_q(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
+{
+  unsigned long long n;
+  str = str_len_ensure(mrb, str, sidx + 8);
+  n = mrb_fixnum(o);
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+    RSTRING_PTR(str)[sidx+0] = n & 0xff;
+    RSTRING_PTR(str)[sidx+1] = n >> 8;
+    RSTRING_PTR(str)[sidx+2] = n >> 16;
+    RSTRING_PTR(str)[sidx+3] = n >> 24;
+    RSTRING_PTR(str)[sidx+4] = n >> 32;
+    RSTRING_PTR(str)[sidx+5] = n >> 40;
+    RSTRING_PTR(str)[sidx+6] = n >> 48;
+    RSTRING_PTR(str)[sidx+7] = n >> 56;
+  } else {
+    RSTRING_PTR(str)[sidx+0] = n >> 56;
+    RSTRING_PTR(str)[sidx+1] = n >> 48;
+    RSTRING_PTR(str)[sidx+2] = n >> 40;
+    RSTRING_PTR(str)[sidx+3] = n >> 32;
+    RSTRING_PTR(str)[sidx+4] = n >> 24;
+    RSTRING_PTR(str)[sidx+5] = n >> 16;
+    RSTRING_PTR(str)[sidx+6] = n >> 8;
+    RSTRING_PTR(str)[sidx+7] = n & 0xff;
+  }
+  return 8;
+}
+
+static int
+unpack_q(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
+{
+  char msg[60];
+  uint64_t ull;
+  int i, pos, step;
+  mrb_int n;
+
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+    pos  = 7;
+    step = -1;
+  } else {
+    pos  = 0;
+    step = 1;
+  }
+  ull = 0;
+  for (i = 0; i < 8; i++) {
+    ull = ull * 256 + (uint64_t)src[pos];
+    pos += step;
+  }
+  if (flags & PACK_FLAG_SIGNED) {
+    int64_t sll = ull;
+    if (!FIXABLE(sll)) {
+      snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %lld", (long long)sll);
+      mrb_raise(mrb, E_RANGE_ERROR, msg);
+    }
+    n = sll;
+  } else {
+    if (!POSFIXABLE(ull)) {
+      snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %llu", (unsigned long long)ull);
+      mrb_raise(mrb, E_RANGE_ERROR, msg);
+    }
+    n = ull;
+  }
+  mrb_ary_push(mrb, ary, mrb_fixnum_value(n));
+  return 8;
+}
+
+static int
+pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
+{
+  int i;
+  double d;
+  uint8_t *buffer = (uint8_t *)&d;
+  str = str_len_ensure(mrb, str, sidx + 8);
+  d = mrb_float(o);
+
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+#ifdef MRB_ENDIAN_BIG
+    for (i = 0; i < 8; ++i) {
+      RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1];
+    }
+#else
+    memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
+#endif
+  } else {
+#ifdef MRB_ENDIAN_BIG
+    memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
+#else
+    for (i = 0; i < 8; ++i) {
+      RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1];
+    }
+#endif
+  }
+
+  return 8;
+}
+
+static int
+unpack_double(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ary, unsigned int flags)
+{
+  int i;
+  double d;
+  uint8_t *buffer = (uint8_t *)&d;
+
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+#ifdef MRB_ENDIAN_BIG
+    for (i = 0; i < 8; ++i) {
+      buffer[8 - i - 1] = src[i];
+    }
+#else
+    memcpy(buffer, src, 8);
+#endif
+  } else {
+#ifdef MRB_ENDIAN_BIG
+    memcpy(buffer, src, 8);
+#else
+    for (i = 0; i < 8; ++i) {
+      buffer[8 - i - 1] = src[i];
+    }
+#endif
+  }
+  mrb_ary_push(mrb, ary, mrb_float_value(mrb, d));
+
+  return 8;
+}
+
+static int
+pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int flags)
+{
+  int i;
+  float f;
+  uint8_t *buffer = (uint8_t *)&f;
+  str = str_len_ensure(mrb, str, sidx + 4);
+  f = mrb_float(o);
+
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+#ifdef MRB_ENDIAN_BIG
+    for (i = 0; i < 4; ++i) {
+      RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1];
+    }
+#else
+    memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
+#endif
+  } else {
+#ifdef MRB_ENDIAN_BIG
+    memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
+#else
+    for (i = 0; i < 4; ++i) {
+      RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1];
+    }
+#endif
+  }
+
+  return 4;
+}
+
+static int
+unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ary, unsigned int flags)
+{
+  int i;
+  float f;
+  uint8_t *buffer = (uint8_t *)&f;
+
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+#ifdef MRB_ENDIAN_BIG
+    for (i = 0; i < 4; ++i) {
+      buffer[4 - i - 1] = src[i];
+    }
+#else
+    memcpy(buffer, src, 4);
+#endif
+  } else {
+#ifdef MRB_ENDIAN_BIG
+    memcpy(buffer, src, 4);
+#else
+    for (i = 0; i < 4; ++i) {
+      buffer[4 - i - 1] = src[i];
+    }
+#endif
+  }
+  mrb_ary_push(mrb, ary, mrb_float_value(mrb, f));
+
+  return 4;
+}
+
+static int
+pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, unsigned int flags)
+{
+  char utf8[4];
+  int len;
+  
+  unsigned long c = mrb_fixnum(o);
+
+  /* Unicode character */
+  /* from mruby-compiler gem */
+  if (c < 0x80) {
+    utf8[0] = (char)c;
+    len = 1;
+  }
+  else if (c < 0x800) {
+    utf8[0] = (char)(0xC0 | (c >> 6));
+    utf8[1] = (char)(0x80 | (c & 0x3F));
+    len = 2;
+  }
+  else if (c < 0x10000) {
+    utf8[0] = (char)(0xE0 |  (c >> 12)        );
+    utf8[1] = (char)(0x80 | ((c >>  6) & 0x3F));
+    utf8[2] = (char)(0x80 | ( c        & 0x3F));
+    len = 3;
+  }
+  else {
+    utf8[0] = (char)(0xF0 |  (c >> 18)        );
+    utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F));
+    utf8[2] = (char)(0x80 | ((c >>  6) & 0x3F));
+    utf8[3] = (char)(0x80 | ( c        & 0x3F));
+    len = 4;
+  }
+  
+  str = str_len_ensure(mrb, str, sidx + len);
+  memcpy(RSTRING_PTR(str) + sidx, utf8, len);
+  
+  return len;
+}
+
+static int
+pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags)
+{
+  int copylen, slen, padlen;
+  char *dptr, *dptr0, pad, *sptr;
+
+  sptr = RSTRING_PTR(src);
+  slen = RSTRING_LEN(src);
+
+  if ((flags & PACK_FLAG_a) || (flags & PACK_FLAG_Z))
+    pad = '\0';
+  else
+    pad = ' ';
+
+  if (count == 0) {
+    return 0;
+  } else if (count == -1) {
+    copylen = slen;
+    padlen = (flags & PACK_FLAG_Z) ? 1 : 0;
+  } else if (count < slen) {
+    copylen = count;
+    padlen = 0;
+  } else {
+    copylen = slen;
+    padlen = count - slen;
+  }
+
+  dst = str_len_ensure(mrb, dst, didx + copylen + padlen);
+  dptr0 = dptr = RSTRING_PTR(dst) + didx;
+  memcpy(dptr, sptr, copylen);
+  dptr += copylen;
+  while (padlen-- > 0) {
+    *dptr++ = pad;
+  }
+ 
+  return dptr - dptr0;
+}
+
+static int
+unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, unsigned int flags)
+{
+  mrb_value dst;
+  const char *cp, *sptr;
+  long copylen;
+
+  sptr = (const char *)src;
+  if (count != -1 && count < slen)  {
+    slen = count;
+  }
+  copylen = slen;
+
+  if (flags & PACK_FLAG_Z) {  /* "Z" */
+    if ((cp = (const char *)memchr(sptr, '\0', slen)) != NULL) {
+      copylen = cp - sptr;
+      if (count == -1) {
+        slen = copylen + 1;
+      }
+    }
+  } else if (!(flags & PACK_FLAG_a)) {  /* "A" */
+    while (copylen > 0 && (sptr[copylen - 1] == '\0' || isspace(sptr[copylen - 1]))) {
+      copylen--;
+    }
+  }
+
+  dst = mrb_str_new(mrb, sptr, copylen);
+  mrb_ary_push(mrb, ary, dst);
+  return slen;
+}
+
+
+static int
+pack_h(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags)
+{
+  unsigned int a, ashift, b, bshift;
+  int slen;
+  char *dptr, *dptr0, *sptr;
+
+  sptr = RSTRING_PTR(src);
+  slen = RSTRING_LEN(src);
+
+  if (flags & PACK_FLAG_LSB) {
+    ashift = 0;
+    bshift = 4;
+  } else {
+    ashift = 4;
+    bshift = 0;
+  }
+
+  if (count == -1) {
+    count = slen;
+  } else if (slen > count) {
+    slen = count;
+  }
+    
+  dst = str_len_ensure(mrb, dst, didx + count);
+  dptr = RSTRING_PTR(dst) + didx;
+
+  dptr0 = dptr;
+  for (; count > 0; count -= 2) {
+    a = b = 0;
+    if (slen > 0) {
+      a = hex2int(*sptr++);
+      slen--;
+    }
+    if (slen > 0) {
+      b = hex2int(*sptr++);
+      slen--;
+    }
+    *dptr++ = (a << ashift) + (b << bshift);
+  }
+
+  return dptr - dptr0;
+}
+
+static int
+unpack_h(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
+{
+  mrb_value dst;
+  int a, ashift, b, bshift;
+  const char *sptr, *sptr0;
+  char *dptr, *dptr0;
+  const char hexadecimal[] = "0123456789abcdef";
+
+  if (flags & PACK_FLAG_LSB) {
+    ashift = 0;
+    bshift = 4;
+  } else {
+    ashift = 4;
+    bshift = 0;
+  }
+
+  sptr = (const char *)src;
+
+  if (count == -1)
+    count = slen * 2;
+
+  dst = mrb_str_new(mrb, NULL, count);
+  dptr = RSTRING_PTR(dst);
+
+  sptr0 = sptr;
+  dptr0 = dptr;
+  while (slen > 0 && count > 0) {
+    a = (*sptr >> ashift) & 0x0f;
+    b = (*sptr >> bshift) & 0x0f;
+    sptr++;
+    slen--;
+
+    *dptr++ = hexadecimal[a];
+    count--;
+
+    if (count > 0) {
+      *dptr++ = hexadecimal[b];
+      count--;
+    }
+  }
+
+  dst = mrb_str_resize(mrb, dst, dptr - dptr0);
+  mrb_ary_push(mrb, ary, dst);
+  return sptr - sptr0;
+}
+
+
+static int
+pack_m(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags)
+{
+  mrb_int dstlen;
+  unsigned long l;
+  int column, srclen;
+  char *srcptr, *dstptr, *dstptr0;
+
+  srcptr = RSTRING_PTR(src);
+  srclen = RSTRING_LEN(src);
+
+  if (srclen == 0)  /* easy case */
+    return 0;
+
+  if (count != 0 && count < 3) {  /* -1, 1 or 2 */
+    count = 45;
+  } else if (count >= 3) {
+    count -= count % 3;
+  }
+
+  dstlen = srclen / 3 * 4;
+  if (count > 0) {
+    dstlen += (srclen / count) + ((srclen % count) == 0 ? 0 : 1);
+  }
+  dst = str_len_ensure(mrb, dst, didx + dstlen);
+  dstptr = RSTRING_PTR(dst) + didx;
+
+  dstptr0 = dstptr;
+  for (column = 3; srclen >= 3; srclen -= 3, column += 3) {
+    l = (unsigned char)*srcptr++ << 16;
+    l += (unsigned char)*srcptr++ << 8;
+    l += (unsigned char)*srcptr++;
+
+    *dstptr++ = base64chars[(l >> 18) & 0x3f];
+    *dstptr++ = base64chars[(l >> 12) & 0x3f];
+    *dstptr++ = base64chars[(l >>  6) & 0x3f];
+    *dstptr++ = base64chars[ l        & 0x3f];
+
+    if (column == count) {
+      *dstptr++ = '\n';
+      column = 0;
+    }
+  }
+  if (srclen == 1) {
+    l = (unsigned char)*srcptr++ << 16;
+    *dstptr++ = base64chars[(l >> 18) & 0x3f];
+    *dstptr++ = base64chars[(l >> 12) & 0x3f];
+    *dstptr++ = '=';
+    *dstptr++ = '=';
+    column += 3;
+  } else if (srclen == 2) {
+    l = (unsigned char)*srcptr++ << 16;
+    l += (unsigned char)*srcptr++ << 8;
+    *dstptr++ = base64chars[(l >> 18) & 0x3f];
+    *dstptr++ = base64chars[(l >> 12) & 0x3f];
+    *dstptr++ = base64chars[(l >>  6) & 0x3f];
+    *dstptr++ = '=';
+    column += 3;
+  }
+  if (column > 0 && count > 0) {
+    *dstptr++ = '\n';
+  }
+
+  return dstptr - dstptr0;
+}
+
+static int
+unpack_m(mrb_state *mrb, const void *src, int slen, mrb_value ary, unsigned int flags)
+{
+  mrb_value dst;
+  int dlen;
+  unsigned long l;
+  int i, padding;
+  unsigned char c, ch[4];
+  const char *sptr, *sptr0;
+  char *dptr, *dptr0;
+
+  sptr0 = sptr = (const char *)src;
+
+  dlen = slen / 4 * 3;  /* an estimated value - may be shorter */
+  dst = mrb_str_new(mrb, NULL, dlen);
+  dptr0 = dptr = RSTRING_PTR(dst);
+
+  padding = 0;
+  while (slen >= 4) {
+    for (i = 0; i < 4; i++) {
+      do {
+        if (slen-- == 0)
+          goto done;
+        c = *sptr++;
+	if (c >= sizeof(base64_dec_tab))
+	  continue;
+	ch[i] = base64_dec_tab[c];
+	if (ch[i] == PACK_BASE64_PADDING) {
+	  ch[i] = 0;
+	  padding++;
+	}
+      } while (ch[i] == PACK_BASE64_IGNORE);
+    }
+
+    l = (ch[0] << 18) + (ch[1] << 12) + (ch[2] << 6) + ch[3];
+
+    if (padding == 0) {
+      *dptr++ = (l >> 16) & 0xff;
+      *dptr++ = (l >> 8) & 0xff;
+      *dptr++ = l & 0xff;
+    } else if (padding == 1) {
+      *dptr++ = (l >> 16) & 0xff;
+      *dptr++ = (l >> 8) & 0xff;
+      break;
+    } else {
+      *dptr++ = (l >> 16) & 0xff;
+      break;
+    }
+  }
+
+done:
+  dst = mrb_str_resize(mrb, dst, dptr - dptr0);
+  mrb_ary_push(mrb, ary, dst);
+  return sptr - sptr0;
+}
+
+static int
+pack_x(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags)
+{
+  long i;
+
+  dst = str_len_ensure(mrb, dst, didx + count);
+  for (i = 0; i < count; i++) {
+    RSTRING_PTR(dst)[didx] = '\0';
+  }
+  return count;
+}
+
+static int
+unpack_x(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
+{
+  if (slen < count) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "x outside of string");
+  }
+  return count;
+}
+
+static void
+prepare_tmpl(mrb_state *mrb, struct tmpl *tmpl)
+{
+  mrb_get_args(mrb, "S", &tmpl->str);
+  tmpl->idx = 0;
+}
+
+static int
+has_tmpl(const struct tmpl *tmpl)
+{
+  return (tmpl->idx < RSTRING_LEN(tmpl->str));
+}
+
+static void
+read_tmpl(mrb_state *mrb, struct tmpl *tmpl, int *dirp, int *typep, int *sizep, long *countp, unsigned int *flagsp)
+{
+  int ch, dir, t, tlen, type;
+  int size = 0;
+  long count = 1;
+  unsigned int flags = 0;
+  const char *tptr;
+
+  tptr = RSTRING_PTR(tmpl->str);
+  tlen = RSTRING_LEN(tmpl->str);
+
+  t = tptr[tmpl->idx++];
+alias:
+  switch (t) {
+  case 'A':
+    dir = PACK_DIR_STR;
+    type = PACK_TYPE_STRING;
+    flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2;
+    break;
+  case 'a':
+    dir = PACK_DIR_STR;
+    type = PACK_TYPE_STRING;
+    flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2 | PACK_FLAG_a;
+    break;
+  case 'C':
+    dir = PACK_DIR_CHAR;
+    type = PACK_TYPE_INTEGER;
+    size = 1;
+    break;
+  case 'c':
+    dir = PACK_DIR_CHAR;
+    type = PACK_TYPE_INTEGER;
+    size = 1;
+    flags |= PACK_FLAG_SIGNED;
+    break;
+  case 'D': case 'd':
+    dir = PACK_DIR_DOUBLE;
+    type = PACK_TYPE_FLOAT;
+    size = 8;
+    flags |= PACK_FLAG_SIGNED;
+    break;
+  case 'F': case 'f':
+    dir = PACK_DIR_FLOAT;
+    type = PACK_TYPE_FLOAT;
+    size = 4;
+    flags |= PACK_FLAG_SIGNED;
+    break;
+  case 'E':
+    dir = PACK_DIR_DOUBLE;
+    type = PACK_TYPE_FLOAT;
+    size = 8;
+    flags |= PACK_FLAG_SIGNED | PACK_FLAG_LT;
+    break;
+  case 'e':
+    dir = PACK_DIR_FLOAT;
+    type = PACK_TYPE_FLOAT;
+    size = 4;
+    flags |= PACK_FLAG_SIGNED | PACK_FLAG_LT;
+    break;
+  case 'G':
+    dir = PACK_DIR_DOUBLE;
+    type = PACK_TYPE_FLOAT;
+    size = 8;
+    flags |= PACK_FLAG_SIGNED | PACK_FLAG_GT;
+    break;
+  case 'g':
+    dir = PACK_DIR_FLOAT;
+    type = PACK_TYPE_FLOAT;
+    size = 4;
+    flags |= PACK_FLAG_SIGNED | PACK_FLAG_GT;
+    break;
+  case 'H':
+    dir = PACK_DIR_HEX;
+    type = PACK_TYPE_STRING;
+    flags |= PACK_FLAG_COUNT2;
+    break;
+  case 'h':
+    dir = PACK_DIR_HEX;
+    type = PACK_TYPE_STRING;
+    flags |= PACK_FLAG_COUNT2 | PACK_FLAG_LSB;
+    break;
+  case 'I':
+    switch (sizeof(int)) {
+      case 2: t = 'S'; goto alias;
+      case 4: t = 'L'; goto alias;
+      case 8: t = 'Q'; goto alias;
+      default:
+        mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %S", mrb_fixnum_value(sizeof(int)));
+    }
+    break;
+  case 'i':
+    switch (sizeof(int)) {
+      case 2: t = 's'; goto alias;
+      case 4: t = 'l'; goto alias;
+      case 8: t = 'q'; goto alias;
+      default:
+        mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %S", mrb_fixnum_value(sizeof(int)));
+    }
+    break;
+  case 'L':
+    dir = PACK_DIR_LONG;
+    type = PACK_TYPE_INTEGER;
+    size = 4;
+    break;
+  case 'l':
+    dir = PACK_DIR_LONG;
+    type = PACK_TYPE_INTEGER;
+    size = 4;
+    flags |= PACK_FLAG_SIGNED;
+    break;
+  case 'm':
+    dir = PACK_DIR_BASE64;
+    type = PACK_TYPE_STRING;
+    flags |= PACK_FLAG_WIDTH;
+    break;
+  case 'N':  /* = "L>" */
+    dir = PACK_DIR_LONG;
+    type = PACK_TYPE_INTEGER;
+    size = 4;
+    flags |= PACK_FLAG_GT;
+    break;
+  case 'n':  /* = "S>" */
+    dir = PACK_DIR_SHORT;
+    type = PACK_TYPE_INTEGER;
+    size = 2;
+    flags |= PACK_FLAG_GT;
+    break;
+  case 'Q':
+    dir = PACK_DIR_QUAD;
+    type = PACK_TYPE_INTEGER;
+    size = 8;
+    break;
+  case 'q':
+    dir = PACK_DIR_QUAD;
+    type = PACK_TYPE_INTEGER;
+    size = 8;
+    flags |= PACK_FLAG_SIGNED;
+    break;
+  case 'S':
+    dir = PACK_DIR_SHORT;
+    type = PACK_TYPE_INTEGER;
+    size = 2;
+    break;
+  case 's':
+    dir = PACK_DIR_SHORT;
+    type = PACK_TYPE_INTEGER;
+    size = 2;
+    flags |= PACK_FLAG_SIGNED;
+    break;
+  case 'U':
+    dir = PACK_DIR_UTF8;
+    type = PACK_TYPE_INTEGER;
+    break;
+  case 'V':  /* = "L<" */
+    dir = PACK_DIR_LONG;
+    type = PACK_TYPE_INTEGER;
+    size = 4;
+    flags |= PACK_FLAG_LT;
+    break;
+  case 'v':  /* = "S<" */
+    dir = PACK_DIR_SHORT;
+    type = PACK_TYPE_INTEGER;
+    size = 2;
+    flags |= PACK_FLAG_LT;
+    break;
+  case 'x':
+    dir = PACK_DIR_NUL;
+    type = PACK_TYPE_NONE;
+    break;
+  case 'Z':
+    dir = PACK_DIR_STR;
+    type = PACK_TYPE_STRING;
+    flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2 | PACK_FLAG_Z;
+    break;
+  default:
+    dir = PACK_DIR_INVALID;
+    type = PACK_TYPE_NONE;
+    break;
+  }
+
+  /* read suffix [0-9*_!<>] */
+  while (tmpl->idx < tlen) {
+    ch = tptr[tmpl->idx++];
+    if (isdigit(ch)) {
+      count = ch - '0';
+      while (tmpl->idx < tlen && isdigit(tptr[tmpl->idx])) {
+        count = count * 10 + (tptr[tmpl->idx++] - '0');
+      }
+      continue;  /* special case */
+    } else if (ch == '*')  {
+      count = -1;
+    } else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') {
+      if (strchr("sSiIlLqQ", t) == NULL) {
+        char ch_str = ch;
+        mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%S' allowed only after types sSiIlLqQ", mrb_str_new(mrb, &ch_str, 1));
+      }
+      if (ch == '_' || ch == '!') {
+        flags |= PACK_FLAG_s;
+      } else if (ch == '<') {
+        flags |= PACK_FLAG_LT;
+      } else if (ch == '>') {
+        flags |= PACK_FLAG_GT;
+      }
+    } else {
+      tmpl->idx--;
+      break;
+    }
+  }
+
+  if ((flags & PACK_FLAG_LT) || (!(flags & PACK_FLAG_GT) && littleendian)) {
+    flags |= PACK_FLAG_LITTLEENDIAN;
+  }
+
+  *dirp = dir;
+  *typep = type;
+  *sizep = size;
+  *countp = count;
+  *flagsp = flags;
+}
+
+static mrb_value
+mrb_pack_pack(mrb_state *mrb, mrb_value ary)
+{
+  mrb_value o, result;
+  mrb_int aidx;
+  struct tmpl tmpl;
+  long count;
+  unsigned int flags;
+  int dir, ridx, size, type;
+
+  prepare_tmpl(mrb, &tmpl);
+
+  result = mrb_str_new(mrb, NULL, 128);  /* allocate initial buffer */
+  aidx = 0;
+  ridx = 0;
+  while (has_tmpl(&tmpl)) {
+    read_tmpl(mrb, &tmpl, &dir, &type, &size, &count, &flags);
+
+    if (dir == PACK_DIR_INVALID)
+      continue;
+    else if (dir == PACK_DIR_NUL) {
+        ridx += pack_x(mrb, mrb_nil_value(), result, ridx, count, flags);
+        continue;
+    }
+
+    for (; aidx < RARRAY_LEN(ary); aidx++) {
+      if (count == 0 && !(flags & PACK_FLAG_WIDTH))
+        break;
+
+      o = mrb_ary_ref(mrb, ary, aidx);
+      if (type == PACK_TYPE_INTEGER) {
+        o = mrb_to_int(mrb, o);
+      } else if (type == PACK_TYPE_FLOAT) {
+        if (!mrb_float_p(o)) {
+          o = mrb_funcall(mrb, o, "to_f", 0);
+        }
+      } else if (type == PACK_TYPE_STRING) {
+        if (!mrb_string_p(o)) {
+          mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into String", mrb_class_path(mrb, mrb_obj_class(mrb, o)));
+        }
+      }
+
+      switch (dir) {
+      case PACK_DIR_CHAR:
+        ridx += pack_c(mrb, o, result, ridx, flags);
+        break;
+      case PACK_DIR_SHORT:
+        ridx += pack_s(mrb, o, result, ridx, flags);
+        break;
+      case PACK_DIR_LONG:
+        ridx += pack_l(mrb, o, result, ridx, flags);
+        break;
+      case PACK_DIR_QUAD:
+        ridx += pack_q(mrb, o, result, ridx, flags);
+        break;
+      case PACK_DIR_BASE64:
+        ridx += pack_m(mrb, o, result, ridx, count, flags);
+        break;
+      case PACK_DIR_HEX:
+        ridx += pack_h(mrb, o, result, ridx, count, flags);
+        break;
+      case PACK_DIR_STR:
+        ridx += pack_a(mrb, o, result, ridx, count, flags);
+        break;
+      case PACK_DIR_DOUBLE:
+        ridx += pack_double(mrb, o, result, ridx, flags);
+        break;
+      case PACK_DIR_FLOAT:
+        ridx += pack_float(mrb, o, result, ridx, flags);
+        break;
+      case PACK_DIR_UTF8:
+        ridx += pack_utf8(mrb, o, result, ridx, count, flags);
+        break;
+      default:
+        break;
+      }
+      if (dir == PACK_DIR_STR) { /* always consumes 1 entry */
+        aidx++;
+        break;
+      }
+      if (count > 0) {
+        count--;
+      }
+    }
+  }
+
+  mrb_str_resize(mrb, result, ridx);
+  return result;
+}
+
+static mrb_value
+mrb_pack_unpack(mrb_state *mrb, mrb_value str)
+{
+  mrb_value result;
+  struct tmpl tmpl;
+  long count;
+  unsigned int flags;
+  int dir, size, srcidx, srclen, type;
+  const unsigned char *sptr;
+
+  prepare_tmpl(mrb, &tmpl);
+
+  srcidx = 0;
+  srclen = RSTRING_LEN(str);
+
+  result = mrb_ary_new(mrb);
+  while (has_tmpl(&tmpl)) {
+    read_tmpl(mrb, &tmpl, &dir, &type, &size, &count, &flags);
+
+    if (dir == PACK_DIR_INVALID)
+      continue;
+    else if (dir == PACK_DIR_NUL) {
+      srcidx += unpack_x(mrb, sptr, srclen - srcidx, result, count, flags);
+      continue;
+    }
+
+    if (flags & PACK_FLAG_COUNT2) {
+      sptr = (const unsigned char *)RSTRING_PTR(str) + srcidx;
+      switch (dir) {
+      case PACK_DIR_HEX:
+        srcidx += unpack_h(mrb, sptr, srclen - srcidx, result, count, flags);
+        break;
+      case PACK_DIR_STR:
+        srcidx += unpack_a(mrb, sptr, srclen - srcidx, result, count, flags);
+        break;
+      }
+      continue;
+    }
+
+    while (count != 0) {
+      if (srclen - srcidx < size) {
+        while (count-- > 0) {
+          mrb_ary_push(mrb, result, mrb_nil_value());
+        }
+        break;
+      }
+
+      sptr = (const unsigned char *)RSTRING_PTR(str) + srcidx;
+      switch (dir) {
+      case PACK_DIR_CHAR:
+        srcidx += unpack_c(mrb, sptr, srclen - srcidx, result, flags);
+        break;
+      case PACK_DIR_SHORT:
+        srcidx += unpack_s(mrb, sptr, srclen - srcidx, result, flags);
+        break;
+      case PACK_DIR_LONG:
+        srcidx += unpack_l(mrb, sptr, srclen - srcidx, result, flags);
+        break;
+      case PACK_DIR_QUAD:
+        srcidx += unpack_q(mrb, sptr, srclen - srcidx, result, flags);
+        break;
+      case PACK_DIR_BASE64:
+        srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, flags);
+        break;
+      case PACK_DIR_FLOAT:
+        srcidx += unpack_float(mrb, sptr, srclen - srcidx, result, flags);
+        break;
+      case PACK_DIR_DOUBLE:
+        srcidx += unpack_double(mrb, sptr, srclen - srcidx, result, flags);
+        break;
+      }
+      if (count > 0) {
+        count--;
+      }
+    }
+  }
+
+  return result;
+}
+
+void
+mrb_mruby_pack_gem_init(mrb_state *mrb)
+{
+  littleendian = check_little_endian();
+  make_base64_dec_tab();
+
+  mrb_define_method(mrb, mrb->array_class, "pack", mrb_pack_pack, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, mrb->string_class, "unpack", mrb_pack_unpack, MRB_ARGS_REQ(1));
+}
+
+void
+mrb_mruby_pack_gem_final(mrb_state *mrb)
+{
+}
Index: EcnlProtoTool/trunk/mrbgems/mruby-pack/test/pack.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-pack/test/pack.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-pack/test/pack.rb	(revision 279)
@@ -0,0 +1,147 @@
+# pack & unpack 'm' (base64)
+assert('[""].pack("m")') do
+  ary = ""
+  str = ""
+  [ary].pack("m") == str and
+  str.unpack("m") == [ary]
+end
+
+assert('["\0"].pack("m")') do
+  ary = "\0"
+  str = "AA==\n"
+  [ary].pack("m") == str and
+  str.unpack("m") == [ary]
+end
+
+assert('["\0\0"].pack("m")') do
+  ary = "\0\0"
+  str = "AAA=\n"
+  [ary].pack("m") == str and
+  str.unpack("m") == [ary]
+end
+
+assert('["\0\0\0"].pack("m")') do
+  ary = "\0\0\0"
+  str = "AAAA\n"
+  [ary].pack("m") == str and
+  str.unpack("m") == [ary]
+end
+
+assert('["abc..xyzABC..XYZ"].pack("m")') do
+  ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"].pack("m") == "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n"
+end
+
+assert('"YWJ...".unpack("m") should "abc..xyzABC..XYZ"') do
+  str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+  "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n".unpack("m") == [str] and
+  "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m") == [str]
+end
+
+# pack & unpack 'H'
+assert('["3031"].pack("H*")') do
+  ary = "3031"
+  str = "01"
+  [ary].pack("H*") == str and
+  str.unpack("H*") == [ary]
+end
+
+assert('["10"].pack("H*")') do
+  ary = "10"
+  str = "\020"
+  [ary].pack("H*") == str and
+  str.unpack("H*") == [ary]
+end
+
+assert('[0,1,127,128,255].pack("C*")') do
+ ary = [ 0, 1, 127, 128, 255 ]
+ str = "\x00\x01\x7F\x80\xFF"
+ ary.pack("C*") == str and str.unpack("C*") == ary
+end
+
+# pack "a"
+assert('["abc"].pack("a")') do
+  ["abc"].pack("a") == "a" and
+  ["abc"].pack("a*") == "abc" and
+  ["abc"].pack("a4") == "abc\0"
+end
+
+# upack "a"
+assert('["abc"].pack("a")') do
+  "abc\0".unpack("a4") == ["abc\0"] and
+  "abc ".unpack("a4") == ["abc "]
+end
+
+# pack "A"
+assert('["abc"].pack("A")') do
+  ["abc"].pack("A") == "a" and
+  ["abc"].pack("A*") == "abc" and
+  ["abc"].pack("A4") == "abc "
+end
+
+# upack "A"
+assert('["abc"].pack("A")') do
+  "abc\0".unpack("A4") == ["abc"] and
+  "abc ".unpack("A4") == ["abc"]
+end
+
+# regression tests
+assert('issue #1') do
+  [1, 2].pack("nn") == "\000\001\000\002"
+end
+
+def assert_pack tmpl, packed, unpacked
+  assert_equal packed, unpacked.pack(tmpl)
+  assert_equal unpacked, packed.unpack(tmpl)
+end
+
+PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01
+
+assert 'pack float' do
+  assert_pack 'e', "\x00\x00@@", [3.0]
+  assert_pack 'g', "@@\x00\x00", [3.0]
+
+  if PACK_IS_LITTLE_ENDIAN
+    assert_pack 'f', "\x00\x00@@", [3.0]
+    assert_pack 'F', "\x00\x00@@", [3.0]
+  else
+    assert_pack 'f', "@@\x00\x00", [3.0]
+    assert_pack 'F', "@@\x00\x00", [3.0]
+  end
+end
+
+assert 'pack double' do
+  assert_pack 'E', "\x00\x00\x00\x00\x00\x00\b@", [3.0]
+  assert_pack 'G', "@\b\x00\x00\x00\x00\x00\x00", [3.0]
+
+  if PACK_IS_LITTLE_ENDIAN
+    assert_pack 'd', "\x00\x00\x00\x00\x00\x00\b@", [3.0]
+    assert_pack 'D', "\x00\x00\x00\x00\x00\x00\b@", [3.0]
+  else
+    assert_pack 'd', "@\b\x00\x00\x00\x00\x00\x00", [3.0]
+    assert_pack 'D', "@\b\x00\x00\x00\x00\x00\x00", [3.0]
+  end
+end
+
+assert 'pack/unpack "i"' do
+  int_size = [0].pack('i').size
+  raise "pack('i').size is too small (#{int_size})" if int_size < 2
+
+  if PACK_IS_LITTLE_ENDIAN
+    str = "\xC7\xCF" + "\xFF" * (int_size-2)
+  else
+    str = "\xFF" * (int_size-2) + "\xC7\xCF"
+  end
+  assert_pack 'i', str, [-12345]
+end
+
+assert 'pack/unpack "I"' do
+  uint_size = [0].pack('I').size
+  raise "pack('I').size is too small (#{uint_size})" if uint_size < 2
+
+  if PACK_IS_LITTLE_ENDIAN
+    str = "\x39\x30" + "\0" * (uint_size-2)
+  else
+    str = "\0" * (uint_size-2) + "\x39\x30"
+  end
+  assert_pack 'I', str, [12345]
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/.travis.yml
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/.travis.yml	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/.travis.yml	(revision 279)
@@ -0,0 +1,4 @@
+language: c
+sudo: false
+script:
+  - "ruby run_test.rb all test"
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/README.md
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/README.md	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/README.md	(revision 279)
@@ -0,0 +1,55 @@
+mruby-socket
+============
+
+"mruby-socket" mrbgem provides BSD socket interface for mruby.
+API is compatible with CRuby's "socket" library.
+
+
+## Example
+```sh
+% vi kame.rb
+s = TCPSocket.open("www.kame.net", 80)
+s.write("GET / HTTP/1.0\r\n\r\n")
+puts s.read
+s.close
+
+% mruby kame.rb
+HTTP/1.1 200 OK
+Date: Tue, 21 May 2013 04:31:30 GMT
+...
+```
+
+## Requirement
+- [iij/mruby-io](https://github.com/iij/mruby-io) mrbgem
+- [iij/mruby-mtest](https://github.com/iij/mruby-mtest) mrgbem to run tests
+- system must have RFC3493 basic socket interface
+- and some POSIX API...
+
+## TODO
+- add missing methods
+- write more tests
+- fix possible descriptor leakage (see XXX comments)
+- `UNIXSocket#recv_io` `UNIXSocket#send_io`
+
+
+## License
+
+Copyright (c) 2013 Internet Initiative Japan Inc.
+
+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 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.
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/mrbgem.rake	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/mrbgem.rake	(revision 279)
@@ -0,0 +1,16 @@
+MRuby::Gem::Specification.new('mruby-socket') do |spec|
+  spec.license = 'MIT'
+  spec.authors = 'Internet Initiative Japan'
+
+  spec.cc.include_paths << "#{build.root}/src"
+  
+  # If Windows, use winsock
+  if ( /mswin|mingw|win32/ =~ RUBY_PLATFORM ) then
+    spec.linker.libraries << "wsock32"
+    spec.linker.libraries << "ws2_32"
+  end
+
+  spec.add_dependency('mruby-io')
+  spec.add_dependency('mruby-pack')
+  # spec.add_dependency('mruby-mtest')
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/mrblib/socket.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/mrblib/socket.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/mrblib/socket.rb	(revision 279)
@@ -0,0 +1,621 @@
+class Addrinfo
+  def initialize(sockaddr, family=Socket::PF_UNSPEC, socktype=0, protocol=0)
+    @hostname = nil
+    if sockaddr.is_a? Array
+      sary = sockaddr
+      if sary[0] == 'AF_INET' || sary[0] == 'AF_INET6'
+        @sockaddr = Socket.sockaddr_in(sary[1], sary[3])
+        @hostname = sary[2]
+      elsif sary[0] == 'AF_UNIX'
+        @sockaddr = Socket.sockaddr_un(sary[1])
+      end
+    else
+      @sockaddr = sockaddr.dup
+    end
+    if family == Socket::PF_UNSPEC or family == nil
+      @family = Socket._sockaddr_family(@sockaddr)
+    else
+      @family = family
+    end
+    @socktype = socktype
+    @protocol = protocol
+    @canonname = nil
+  end
+
+  def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=0, &block)
+    a = self.getaddrinfo(nodename, service, family, socktype, protocol, flags)
+    a.each { |ai| block.call(ai) }
+    a
+  end
+
+  def self.ip(host)
+    Addrinfo.new(Socket.sockaddr_in(0, host))
+  end
+
+  def self.tcp(host, port)
+    Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_STREAM, Socket::IPPROTO_TCP)[0]
+  end
+
+  def self.udp(host, port)
+    Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_DGRAM, Socket::IPPROTO_UDP)[0]
+  end
+
+  def self.unix(path, socktype=Socket::SOCK_STREAM)
+    Addrinfo.new(Socket.sockaddr_un(path), Socket::AF_UNIX, socktype)
+  end
+
+  def afamily
+    @family
+  end
+
+  #def bind
+
+  attr_reader :canonname
+
+  #def connect
+  #def connect_from
+  #def connect_to
+
+  #def family_addrinfo(host, port=nil)
+  #def getnameinfo(flags=0)
+  #  Socket.getnameinfo
+  #end
+
+  def inspect
+    if ipv4? or ipv6?
+      if @protocol == Socket::IPPROTO_TCP or (@socktype == Socket::SOCK_STREAM and @protocol == 0)
+        proto = 'TCP'
+      elsif @protocol == Socket::IPPROTO_UDP or (@socktype == Socket::SOCK_DGRAM and @protocol == 0)
+        proto = 'UDP'
+      else
+        proto = '???'
+      end
+      "#<Addrinfo: #{inspect_sockaddr} #{proto}>"
+    else
+      "#<Addrinfo: #{self.unix_path} SOCK_STREAM>"
+    end
+  end
+
+  def inspect_sockaddr
+    if ipv4?
+      a, p = ip_unpack
+      "#{a}:#{p}"
+    elsif ipv6?
+      a, p = ip_unpack
+      "[#{a}]:#{p}"
+    elsif unix?
+      unix_path
+    else
+      '???'
+    end
+  end
+
+  def ip?
+    ipv4? or ipv6?
+  end
+
+  def ip_address
+    ip_unpack[0]
+  end
+
+  def ip_port
+    ip_unpack[1]
+  end
+
+  def ip_unpack
+    h, p = getnameinfo(Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV)
+    [ h, p.to_i ]
+  end
+
+  def ipv4?
+    @family == Socket::AF_INET
+  end
+
+  #def ipv4_loopback?
+  #def ipv4_multicast?
+  #def ipv4_private?
+
+  def ipv6?
+    @family == Socket::AF_INET6
+  end
+
+  #def ipv6_loopback?
+  #def ipv6_mc_global?
+  #def ipv6_mc_linklocal?
+  #def ipv6_mc_nodelocal?
+  #def ipv6_mc_orilocal?
+  #def ipv6_mc_sitelocal?
+  #def ipv6_multicast?
+  #def ipv6_to_ipv4
+  #def ipv6_unspecified
+  #def ipv6_v4compat?
+  #def ipv6_v4mapped?
+  #def listen(backlog=5)
+
+  def pfamily
+    @family
+  end
+
+  attr_reader :protocol
+  attr_reader :socktype
+
+  def _to_array
+    case @family
+    when Socket::AF_INET
+      s = "AF_INET"
+    when Socket::AF_INET6
+      s = "AF_INET6"
+    when Socket::AF_UNIX
+      s = "AF_UNIX"
+    else
+      s = "(unknown AF)"
+    end
+    addr, port = self.getnameinfo(Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV)
+    [ s, port.to_i, addr, addr ]
+  end
+
+  def to_sockaddr 
+    @sockaddr
+  end
+
+  alias to_s to_sockaddr
+
+  def unix?
+    @family == Socket::AF_UNIX
+  end
+end
+
+class BasicSocket
+  @@do_not_reverse_lookup = true
+
+  def self.do_not_reverse_lookup
+    @@do_not_reverse_lookup
+  end
+
+  def self.do_not_reverse_lookup=(val)
+    @@do_not_reverse_lookup = val ? true : false
+  end
+
+  def initialize(*args)
+    super(*args)
+    @do_not_reverse_lookup = @@do_not_reverse_lookup
+  end
+
+  def self.for_fd(fd)
+    super(fd, "r+")
+  end
+
+  #def connect_address
+
+  def local_address
+    Addrinfo.new self.getsockname
+  end
+
+  def recv_nonblock(maxlen, flags=0)
+    begin
+      _setnonblock(true)
+      recv(maxlen, flags)
+    ensure
+      _setnonblock(false)
+    end
+  end
+
+  def remote_address
+    Addrinfo.new self.getpeername
+  end
+
+  attr_accessor :do_not_reverse_lookup
+end
+
+class IPSocket
+  def self.getaddress(host)
+    Addrinfo.ip(host).ip_address
+  end
+
+  def addr
+    Addrinfo.new(self.getsockname)._to_array
+  end
+
+  def peeraddr
+    Addrinfo.new(self.getpeername)._to_array
+  end
+
+  def recvfrom(maxlen, flags=0)
+    msg, sa = _recvfrom(maxlen, flags)
+    [ msg, Addrinfo.new(sa)._to_array ]
+  end
+end
+
+class TCPSocket
+  def initialize(host, service, local_host=nil, local_service=nil)
+    if @init_with_fd
+      super(host, service)
+    else
+      s = nil
+      e = SocketError
+      Addrinfo.foreach(host, service) { |ai|
+        begin
+          s = Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0)
+          if local_host or local_service
+            local_host ||= (ai.afamily == Socket::AF_INET) ? "0.0.0.0" : "::"
+            local_service ||= "0"
+            bi = Addrinfo.getaddrinfo(local_host, local_service, ai.afamily, ai.socktype)[0]
+            Socket._bind(s, bi.to_sockaddr)
+          end
+          Socket._connect(s, ai.to_sockaddr)
+          super(s, "r+")
+          return
+        rescue => e0
+          e = e0
+        end
+      }
+      raise e
+    end
+  end
+
+  def self.new_with_prelude pre, *args
+    o = self._allocate
+    o.instance_eval(&pre)
+    o.initialize(*args)
+    o
+  end
+
+  #def self.gethostbyname(host)
+end
+
+class TCPServer
+  def initialize(host=nil, service)
+    ai = Addrinfo.getaddrinfo(host, service, nil, nil, nil, Socket::AI_PASSIVE)[0]
+    @init_with_fd = true
+    super(Socket._socket(ai.afamily, Socket::SOCK_STREAM, 0), "r+")
+    if Socket.const_defined?(:SO_REUSEADDR)
+      self.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
+    end
+    Socket._bind(self.fileno, ai.to_sockaddr)
+    listen(5)
+    self
+  end
+
+  def accept
+    fd = self.sysaccept
+    begin
+      proc = Proc.new { @init_with_fd = true }
+      TCPSocket.new_with_prelude(proc, fd, "r+")
+    rescue
+      IO._sysclose(fd) rescue nil
+      raise
+    end
+  end
+
+  def accept_nonblock
+    begin
+      self._setnonblock(true)
+      self.accept
+    ensure
+      self._setnonblock(false)
+    end
+  end
+
+  def listen(backlog)
+    Socket._listen(self.fileno, backlog)
+    0
+  end
+
+  def sysaccept
+    Socket._accept(self.fileno)[0]
+  end
+end
+
+class UDPSocket
+  def initialize(af=Socket::AF_INET)
+    super(Socket._socket(af, Socket::SOCK_DGRAM, 0), "r+")
+    @af = af
+    self
+  end
+
+  def bind(host, port)
+    Socket._bind(self.fileno, _sockaddr_in(port, host))
+    0
+  end
+
+  def connect(host, port)
+    Socket._connect(self.fileno, _sockaddr_in(port, host))
+    0
+  end
+
+  def recvfrom_nonblock(*args)
+    s = self
+    begin
+      self._setnonblock(true)
+      self.recvfrom(*args)
+    ensure
+      # XXX: self is a SystemcallException here! (should be bug)
+      s._setnonblock(false)
+    end
+  end
+
+  def send(mesg, flags, host=nil, port=nil)
+    if port
+      super(mesg, flags, _sockaddr_in(port, host))
+    elsif host
+      super(mesg, flags, host)
+    else
+      super(mesg, flags)
+    end
+  end
+
+  def _sockaddr_in(port, host)
+    ai = Addrinfo.getaddrinfo(host, port, @af, Socket::SOCK_DGRAM)[0]
+    ai.to_sockaddr
+  end
+end
+
+class Socket
+  def initialize(domain, type, protocol=0)
+    super(Socket._socket(domain, type, protocol), "r+")
+  end
+
+  #def self.accept_loop
+
+  def self.getaddrinfo(nodename, servname, family=nil, socktype=nil, protocol=nil, flags=0)
+    Addrinfo.getaddrinfo(nodename, servname, family, socktype, protocol, flags).map { |ai|
+      ary = ai._to_array
+      ary[2] = nodename
+      ary[4] = ai.afamily
+      ary[5] = ai.socktype
+      ary[6] = ai.protocol
+      ary
+    }
+  end
+
+  #def self.getnameinfo
+  #def self.ip_address_list
+
+  def self.open(*args)
+    new(args)
+  end
+
+  def self.sockaddr_in(port, host)
+    ai = Addrinfo.getaddrinfo(host, port, nil, Socket::SOCK_DGRAM)[0]
+    ai.to_sockaddr
+  end
+
+  #def self.tcp
+  #def self.tcp_server_loop
+  #def self.tcp_server_sockets
+  #def self.udp_server_loop
+  #def self.udp_server_loop_on
+  #def self.udp_server_recv
+  #def self.udp_server_sockets
+  #def self.unix(path)
+  #def self.unix_server_loop
+  #def self.unix_server_socket
+
+  def self.unpack_sockaddr_in(sa)
+    Addrinfo.new(sa).ip_unpack.reverse
+  end
+
+  def self.unpack_sockaddr_un(sa)
+    Addrinfo.new(sa).unix_path
+  end
+
+  class << self
+    alias pack_sockaddr_in sockaddr_in
+    alias pack_sockaddr_un sockaddr_un
+    alias pair socketpair
+  end
+
+  def accept
+    fd, addr = self.sysaccept
+    [ Socket.for_fd(fd), addr ]
+  end
+
+  def accept_nonblock
+    begin
+      self._setnonblock(true)
+      self.accept
+    ensure
+      self._setnonblock(false)
+    end
+  end
+
+  def bind(sockaddr)
+    sockaddr = sockaddr.to_sockaddr if sockaddr.is_a? Addrinfo
+    Socket._bind(self.fileno, sockaddr)
+    0
+  end
+
+  def connect(sockaddr)
+    sockaddr = sockaddr.to_sockaddr if sockaddr.is_a? Addrinfo
+    Socket._connect(self.fileno, sockaddr)
+    0
+  end
+
+  def connect_nonblock(sockaddr)
+    begin
+      self._setnonblock(true)
+      self.connect(sockaddr)
+    ensure
+      self._setnonblock(false)
+    end
+  end
+
+  #def ipv6only!
+
+  def listen(backlog)
+    Socket._listen(self.fileno, backlog)
+    0
+  end
+
+  def recvfrom(maxlen, flags=0)
+    msg, sa = _recvfrom(maxlen, flags)
+    socktype = self.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE).int
+    [ msg, Addrinfo.new(sa, Socket::PF_UNSPEC, socktype) ]
+  end
+
+  def recvfrom_nonblock(*args)
+    begin
+      self._setnonblock(true)
+      self._recvfrom(*args)
+    ensure
+      self._setnonblock(false)
+    end
+  end
+
+  def sysaccept
+    Socket._accept(self.fileno)[0]
+  end
+end
+
+class UNIXSocket < BasicSocket
+  def initialize(path, &block)
+    if self.is_a? UNIXServer
+      super(path, "r")
+    else
+      super(Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0), "r+")
+      Socket._connect(self.fileno, Socket.sockaddr_un(path))
+
+      if block_given?
+        begin
+          yield self
+        ensure
+          begin
+            self.close unless self.closed?
+          rescue StandardError
+          end
+        end
+      end
+    end
+  end
+
+  def self.socketpair(type=Socket::SOCK_STREAM, protocol=0)
+    a = Socket.socketpair(Socket::AF_UNIX, type, protocol)
+    [ UNIXSocket.for_fd(a[0]), UNIXSocket.for_fd(a[1]) ]
+  end
+
+  class << self
+    alias pair socketpair
+  end
+
+  def addr
+    [ "AF_UNIX", path ]
+  end
+
+  def path
+    Addrinfo.new(self.getsockname).unix_path
+  end
+
+  def peeraddr
+    [ "AF_UNIX", Addrinfo.new(self.getpeername).unix_path ]
+  end
+
+  #def recv_io
+
+  def recvfrom(maxlen, flags=0)
+    msg, sa = _recvfrom(maxlen, flags)
+    path = (sa.size > 0) ? Addrinfo.new(sa).unix_path : ""
+    [ msg, [ "AF_UNIX", path ] ]
+  end
+
+  #def send_io
+end
+
+class UNIXServer < UNIXSocket
+  def initialize(path)
+    fd = Socket._socket(Socket::AF_UNIX, Socket::SOCK_STREAM, 0)
+    begin
+      super(fd)
+      Socket._bind(fd, Socket.pack_sockaddr_un(path))
+      self.listen(5)
+    rescue => e
+      IO._sysclose(fd) rescue nil
+      raise e
+    end
+
+    if block_given?
+      begin
+        yield self
+      ensure
+        self.close rescue nil unless self.closed?
+      end
+    end
+  end
+
+  def accept
+    fd = self.sysaccept
+    begin
+      sock = UNIXSocket.for_fd(fd)
+    rescue
+      IO._sysclose(fd) rescue nil
+    end
+    sock
+  end
+
+  def accept_nonblock
+    begin
+      self._setnonblock(true)
+      self.accept
+    ensure
+      self._setnonblock(false)
+    end
+  end
+
+  def listen(backlog)
+    Socket._listen(self.fileno, backlog)
+    0
+  end
+
+  def sysaccept
+    Socket._accept(self.fileno)[0]
+  end
+end
+
+class Socket
+  include Constants
+end
+
+class Socket
+  class Option
+    def initialize(family, level, optname, data)
+      @family  = family
+      @level   = level
+      @optname = optname
+      @data    = data
+    end
+
+    def self.bool(family, level, optname, bool)
+      self.new(family, level, optname, [(bool ? 1 : 0)].pack('i'))
+    end
+
+    def self.int(family, level, optname, integer)
+      self.new(family, level, optname, [integer].pack('i'))
+    end
+
+    #def self.linger(family, level, optname, integer)
+    #end
+
+    attr_reader :data, :family, :level, :optname
+
+    def bool
+      @data.unpack('i')[0] != 0
+    end
+
+    def inspect
+      "#<Socket::Option: family:#{@family} level:#{@level} optname:#{@optname} #{@data.inspect}>"
+    end
+
+    def int
+      @data.unpack('i')[0]
+    end
+
+    def linger
+      raise NotImplementedError.new
+    end
+
+    def unpack(template)
+      raise NotImplementedError.new
+    end
+  end
+end
+
+class SocketError < StandardError; end
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/run_test.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/run_test.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/run_test.rb	(revision 279)
@@ -0,0 +1,28 @@
+#!/usr/bin/env ruby
+#
+# mrbgems test runner
+#
+
+if __FILE__ == $0
+  repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby'
+  build_args = ARGV
+
+  Dir.mkdir 'tmp'  unless File.exist?('tmp')
+  unless File.exist?(dir)
+    system "git clone #{repository} #{dir}"
+  end
+
+  exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}])
+end
+
+MRuby::Build.new do |conf|
+  toolchain :gcc
+  conf.gembox 'default'
+
+  conf.gem :git => 'https://github.com/iij/mruby-mtest.git'
+  conf.gem :git => 'https://github.com/iij/mruby-io.git'
+  conf.gem :git => 'https://github.com/iij/mruby-pack.git'
+
+  conf.gem File.expand_path(File.dirname(__FILE__))
+  conf.enable_test
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/src/const.cstub
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/src/const.cstub	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/src/const.cstub	(revision 279)
@@ -0,0 +1,453 @@
+#ifdef AF_INET
+  define_const(AF_INET);
+#endif
+#ifdef PF_INET
+  define_const(PF_INET);
+#endif
+#ifdef AF_INET6
+  define_const(AF_INET6);
+#endif
+#ifdef PF_INET6
+  define_const(PF_INET6);
+#endif
+#ifdef AF_LINK
+  define_const(AF_LINK);
+#endif
+#ifdef PF_LINK
+  define_const(PF_LINK);
+#endif
+#ifdef AF_LOCAL
+  define_const(AF_LOCAL);
+#endif
+#ifdef PF_LOCAL
+  define_const(PF_LOCAL);
+#endif
+#ifdef AF_UNIX
+  define_const(AF_UNIX);
+#endif
+#ifdef PF_UNIX
+  define_const(PF_UNIX);
+#endif
+#ifdef AF_MAX
+  define_const(AF_MAX);
+#endif
+#ifdef AF_UNSPEC
+  define_const(AF_UNSPEC);
+#endif
+#ifdef PF_UNSPEC
+  define_const(PF_UNSPEC);
+#endif
+#ifdef AF_ROUTE
+  define_const(AF_ROUTE);
+#endif
+#ifdef PF_ROUTE
+  define_const(PF_ROUTE);
+#endif
+#ifdef AI_CANONNAME
+  define_const(AI_CANONNAME);
+#endif
+#ifdef AI_FQDN
+  define_const(AI_FQDN);
+#endif
+#ifdef AI_NUMERICHOST
+  define_const(AI_NUMERICHOST);
+#endif
+#ifdef AI_NUMERICSERV
+  define_const(AI_NUMERICSERV);
+#endif
+#ifdef AI_PASSIVE
+  define_const(AI_PASSIVE);
+#endif
+#ifdef IP_ADD_MEMBERSHIP
+  define_const(IP_ADD_MEMBERSHIP);
+#endif
+#ifdef IP_ADD_SOURCE_MEMBERSHIP
+  define_const(IP_ADD_SOURCE_MEMBERSHIP);
+#endif
+#ifdef IP_BLOCK_SOURCE
+  define_const(IP_BLOCK_SOURCE);
+#endif
+#ifdef IP_DROP_MEMBERSHIP
+  define_const(IP_DROP_MEMBERSHIP);
+#endif
+#ifdef IP_DROP_SOURCE_MEMBERSHIP
+  define_const(IP_DROP_SOURCE_MEMBERSHIP);
+#endif
+#ifdef IP_FREEBIND
+  define_const(IP_FREEBIND);
+#endif
+#ifdef IP_HDRINCL
+  define_const(IP_HDRINCL);
+#endif
+#ifdef IP_IPSEC_POLICY
+  define_const(IP_IPSEC_POLICY);
+#endif
+#ifdef IP_MINTTL
+  define_const(IP_MINTTL);
+#endif
+#ifdef IP_MSFILTER
+  define_const(IP_MSFILTER);
+#endif
+#ifdef IP_MTU
+  define_const(IP_MTU);
+#endif
+#ifdef IP_MTU_DISCOVER
+  define_const(IP_MTU_DISCOVER);
+#endif
+#ifdef IP_MULTICAST_ALL
+  define_const(IP_MULTICAST_ALL);
+#endif
+#ifdef IP_MULTICAST_IF
+  define_const(IP_MULTICAST_IF);
+#endif
+#ifdef IP_MULTICAST_LOOP
+  define_const(IP_MULTICAST_LOOP);
+#endif
+#ifdef IP_MULTICAST_TTL
+  define_const(IP_MULTICAST_TTL);
+#endif
+#ifdef IP_OPTIONS
+  define_const(IP_OPTIONS);
+#endif
+#ifdef IP_ORIGDSTADDR
+  define_const(IP_ORIGDSTADDR);
+#endif
+#ifdef IP_PASSSEC
+  define_const(IP_PASSSEC);
+#endif
+#ifdef IP_PKTINFO
+  define_const(IP_PKTINFO);
+#endif
+#ifdef IP_PKTOPTIONS
+  define_const(IP_PKTOPTIONS);
+#endif
+#ifdef IP_PMTUDISC_DO
+  define_const(IP_PMTUDISC_DO);
+#endif
+#ifdef IP_PMTUDISC_DONT
+  define_const(IP_PMTUDISC_DONT);
+#endif
+#ifdef IP_PMTUDISC_PROBE
+  define_const(IP_PMTUDISC_PROBE);
+#endif
+#ifdef IP_PMTUDISC_WANT
+  define_const(IP_PMTUDISC_WANT);
+#endif
+#ifdef IP_RECVDSTADDR
+  define_const(IP_RECVDSTADDR);
+#endif
+#ifdef IP_RECVERR
+  define_const(IP_RECVERR);
+#endif
+#ifdef IP_RECVOPTS
+  define_const(IP_RECVOPTS);
+#endif
+#ifdef IP_RECVORIGDSTADDR
+  define_const(IP_RECVORIGDSTADDR);
+#endif
+#ifdef IP_RECVRETOPTS
+  define_const(IP_RECVRETOPTS);
+#endif
+#ifdef IP_RECVTOS
+  define_const(IP_RECVTOS);
+#endif
+#ifdef IP_RECVTTL
+  define_const(IP_RECVTTL);
+#endif
+#ifdef IP_RETOPTS
+  define_const(IP_RETOPTS);
+#endif
+#ifdef IP_ROUTER_ALERT
+  define_const(IP_ROUTER_ALERT);
+#endif
+#ifdef IP_TOS
+  define_const(IP_TOS);
+#endif
+#ifdef IP_TRANSPARENT
+  define_const(IP_TRANSPARENT);
+#endif
+#ifdef IP_TTL
+  define_const(IP_TTL);
+#endif
+#ifdef IP_UNBLOCK_SOURCE
+  define_const(IP_UNBLOCK_SOURCE);
+#endif
+#ifdef IP_XFRM_POLICY
+  define_const(IP_XFRM_POLICY);
+#endif
+#ifdef IPV6_JOIN_GROUP
+  define_const(IPV6_JOIN_GROUP);
+#endif
+#ifdef IPV6_LEAVE_GROUP
+  define_const(IPV6_LEAVE_GROUP);
+#endif
+#ifdef IPV6_MULTICAST_HOPS
+  define_const(IPV6_MULTICAST_HOPS);
+#endif
+#ifdef IPV6_MULTICAST_IF
+  define_const(IPV6_MULTICAST_IF);
+#endif
+#ifdef IPV6_MULTICAST_LOOP
+  define_const(IPV6_MULTICAST_LOOP);
+#endif
+#ifdef IPV6_UNICAST_HOPS
+  define_const(IPV6_UNICAST_HOPS);
+#endif
+#ifdef IPV6_V6ONLY
+  define_const(IPV6_V6ONLY);
+#endif
+#ifdef IPPROTO_AH
+  define_const(IPPROTO_AH);
+#endif
+#ifdef IPPROTO_DSTOPTS
+  define_const(IPPROTO_DSTOPTS);
+#endif
+#ifdef IPPROTO_ESP
+  define_const(IPPROTO_ESP);
+#endif
+#ifdef IPPROTO_FRAGMENT
+  define_const(IPPROTO_FRAGMENT);
+#endif
+#ifdef IPPROTO_ICMP
+  define_const(IPPROTO_ICMP);
+#endif
+#ifdef IPPROTO_ICMPV6
+  define_const(IPPROTO_ICMPV6);
+#endif
+#ifdef IPPROTO_IP
+  define_const(IPPROTO_IP);
+#endif
+#ifdef IPPROTO_IPV6
+  define_const(IPPROTO_IPV6);
+#endif
+#ifdef IPPROTO_NONE
+  define_const(IPPROTO_NONE);
+#endif
+#ifdef IPPROTO_RAW
+  define_const(IPPROTO_RAW);
+#endif
+#ifdef IPPROTO_ROUTING
+  define_const(IPPROTO_ROUTING);
+#endif
+#ifdef IPPROTO_TCP
+  define_const(IPPROTO_TCP);
+#endif
+#ifdef IPPROTO_UDP
+  define_const(IPPROTO_UDP);
+#endif
+#ifdef MCAST_BLOCK_SOURCE
+  define_const(MCAST_BLOCK_SOURCE);
+#endif
+#ifdef MCAST_JOIN_GROUP
+  define_const(MCAST_JOIN_GROUP);
+#endif
+#ifdef MCAST_JOIN_SOURCE_GROUP
+  define_const(MCAST_JOIN_SOURCE_GROUP);
+#endif
+#ifdef MCAST_LEAVE_GROUP
+  define_const(MCAST_LEAVE_GROUP);
+#endif
+#ifdef MCAST_LEAVE_SOURCE_GROUP
+  define_const(MCAST_LEAVE_SOURCE_GROUP);
+#endif
+#ifdef MCAST_MSFILTER
+  define_const(MCAST_MSFILTER);
+#endif
+#ifdef MCAST_UNBLOCK_SOURCE
+  define_const(MCAST_UNBLOCK_SOURCE);
+#endif
+#ifdef MSG_BCAST
+  define_const(MSG_BCAST);
+#endif
+#ifdef MSG_CTRUNC
+  define_const(MSG_CTRUNC);
+#endif
+#ifdef MSG_DONTROUTE
+  define_const(MSG_DONTROUTE);
+#endif
+#ifdef MSG_DONTWAIT
+  define_const(MSG_DONTWAIT);
+#endif
+#ifdef MSG_EOR
+  define_const(MSG_EOR);
+#endif
+#ifdef MSG_MCAST
+  define_const(MSG_MCAST);
+#endif
+#ifdef MSG_NOSIGNAL
+  define_const(MSG_NOSIGNAL);
+#endif
+#ifdef MSG_OOB
+  define_const(MSG_OOB);
+#endif
+#ifdef MSG_PEEK
+  define_const(MSG_PEEK);
+#endif
+#ifdef MSG_TRUNC
+  define_const(MSG_TRUNC);
+#endif
+#ifdef MSG_WAITALL
+  define_const(MSG_WAITALL);
+#endif
+#ifdef NI_DGRAM
+  define_const(NI_DGRAM);
+#endif
+#ifdef NI_MAXHOST
+  define_const(NI_MAXHOST);
+#endif
+#ifdef NI_MAXSERV
+  define_const(NI_MAXSERV);
+#endif
+#ifdef NI_NAMEREQD
+  define_const(NI_NAMEREQD);
+#endif
+#ifdef NI_NOFQDN
+  define_const(NI_NOFQDN);
+#endif
+#ifdef NI_NUMERICHOST
+  define_const(NI_NUMERICHOST);
+#endif
+#ifdef NI_NUMERICSERV
+  define_const(NI_NUMERICSERV);
+#endif
+#ifdef SHUT_RD
+  define_const(SHUT_RD);
+#endif
+#ifdef SHUT_WR
+  define_const(SHUT_WR);
+#endif
+#ifdef SHUT_RDWR
+  define_const(SHUT_RDWR);
+#endif
+#ifdef SO_BINDANY
+  define_const(SO_BINDANY);
+#endif
+#ifdef SO_BROADCAST
+  define_const(SO_BROADCAST);
+#endif
+#ifdef SO_DEBUG
+  define_const(SO_DEBUG);
+#endif
+#ifdef SO_DONTROUTE
+  define_const(SO_DONTROUTE);
+#endif
+#ifdef SO_ERROR
+  define_const(SO_ERROR);
+#endif
+#ifdef SO_KEEPALIVE
+  define_const(SO_KEEPALIVE);
+#endif
+#ifdef SO_LINGER
+  define_const(SO_LINGER);
+#endif
+#ifdef SO_NOSIGPIPE
+  define_const(SO_NOSIGPIPE);
+#endif
+#ifdef SO_OOBINLINE
+  define_const(SO_OOBINLINE);
+#endif
+#ifdef SO_PEERCRED
+  define_const(SO_PEERCRED);
+#endif
+#ifdef SO_RCVBUF
+  define_const(SO_RCVBUF);
+#endif
+#ifdef SO_RCVLOWAT
+  define_const(SO_RCVLOWAT);
+#endif
+#ifdef SO_RCVTIMEO
+  define_const(SO_RCVTIMEO);
+#endif
+#ifdef SO_REUSEADDR
+  define_const(SO_REUSEADDR);
+#endif
+#ifdef SO_REUSEPORT
+  define_const(SO_REUSEPORT);
+#endif
+#ifdef SO_RTABLE
+  define_const(SO_RTABLE);
+#endif
+#ifdef SO_SNDBUF
+  define_const(SO_SNDBUF);
+#endif
+#ifdef SO_SNDLOWAT
+  define_const(SO_SNDLOWAT);
+#endif
+#ifdef SO_SNDTIMEO
+  define_const(SO_SNDTIMEO);
+#endif
+#ifdef SO_SPLICE
+  define_const(SO_SPLICE);
+#endif
+#ifdef SO_TIMESTAMP
+  define_const(SO_TIMESTAMP);
+#endif
+#ifdef SO_TYPE
+  define_const(SO_TYPE);
+#endif
+#ifdef SOCK_DGRAM
+  define_const(SOCK_DGRAM);
+#endif
+#ifdef SOCK_RAW
+  define_const(SOCK_RAW);
+#endif
+#ifdef SOCK_SEQPACKET
+  define_const(SOCK_SEQPACKET);
+#endif
+#ifdef SOCK_STREAM
+  define_const(SOCK_STREAM);
+#endif
+#ifdef SOL_SOCKET
+  define_const(SOL_SOCKET);
+#endif
+#ifdef TCP_CONGCTL
+  define_const(TCP_CONGCTL);
+#endif
+#ifdef TCP_CONGESTION
+  define_const(TCP_CONGESTION);
+#endif
+#ifdef TCP_CORK
+  define_const(TCP_CORK);
+#endif
+#ifdef TCP_DEFER_ACCEPT
+  define_const(TCP_DEFER_ACCEPT);
+#endif
+#ifdef TCP_INFO
+  define_const(TCP_INFO);
+#endif
+#ifdef TCP_KEEPCNT
+  define_const(TCP_KEEPCNT);
+#endif
+#ifdef TCP_KEEPIDLE
+  define_const(TCP_KEEPIDLE);
+#endif
+#ifdef TCP_KEEPINIT
+  define_const(TCP_KEEPINIT);
+#endif
+#ifdef TCP_KEEPINTVL
+  define_const(TCP_KEEPINTVL);
+#endif
+#ifdef TCP_LINGER2
+  define_const(TCP_LINGER2);
+#endif
+#ifdef TCP_MAXSEG
+  define_const(TCP_MAXSEG);
+#endif
+#ifdef TCP_MD5SIG
+  define_const(TCP_MD5SIG);
+#endif
+#ifdef TCP_NODELAY
+  define_const(TCP_NODELAY);
+#endif
+#ifdef TCP_QUICKACK
+  define_const(TCP_QUICKACK);
+#endif
+#ifdef TCP_SACK_ENABLE
+  define_const(TCP_SACK_ENABLE);
+#endif
+#ifdef TCP_SYNCNT
+  define_const(TCP_SYNCNT);
+#endif
+#ifdef TCP_WINDOW_CLAMP
+  define_const(TCP_WINDOW_CLAMP);
+#endif
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/src/const.def
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/src/const.def	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/src/const.def	(revision 279)
@@ -0,0 +1,163 @@
+AF_INET
+PF_INET
+AF_INET6
+PF_INET6
+AF_LINK
+PF_LINK
+AF_LOCAL
+PF_LOCAL
+AF_UNIX
+PF_UNIX
+AF_MAX
+AF_UNSPEC
+PF_UNSPEC
+AF_ROUTE
+PF_ROUTE
+
+AI_CANONNAME
+AI_FQDN
+AI_NUMERICHOST
+AI_NUMERICSERV
+AI_PASSIVE
+
+IP_ADD_MEMBERSHIP
+IP_ADD_SOURCE_MEMBERSHIP
+IP_BLOCK_SOURCE
+IP_DROP_MEMBERSHIP
+IP_DROP_SOURCE_MEMBERSHIP
+IP_FREEBIND
+IP_HDRINCL
+IP_IPSEC_POLICY
+IP_MINTTL
+IP_MSFILTER
+IP_MTU
+IP_MTU_DISCOVER
+IP_MULTICAST_ALL
+IP_MULTICAST_IF
+IP_MULTICAST_LOOP
+IP_MULTICAST_TTL
+IP_OPTIONS
+IP_ORIGDSTADDR
+IP_PASSSEC
+IP_PKTINFO
+IP_PKTOPTIONS
+IP_PMTUDISC_DO
+IP_PMTUDISC_DONT
+IP_PMTUDISC_PROBE
+IP_PMTUDISC_WANT
+IP_RECVDSTADDR
+IP_RECVERR
+IP_RECVOPTS
+IP_RECVORIGDSTADDR
+IP_RECVRETOPTS
+IP_RECVTOS
+IP_RECVTTL
+IP_RETOPTS
+IP_ROUTER_ALERT
+IP_TOS
+IP_TRANSPARENT
+IP_TTL
+IP_UNBLOCK_SOURCE
+IP_XFRM_POLICY
+
+IPV6_JOIN_GROUP
+IPV6_LEAVE_GROUP
+IPV6_MULTICAST_HOPS
+IPV6_MULTICAST_IF
+IPV6_MULTICAST_LOOP
+IPV6_UNICAST_HOPS
+IPV6_V6ONLY
+
+IPPROTO_AH
+IPPROTO_DSTOPTS
+IPPROTO_ESP
+IPPROTO_FRAGMENT
+IPPROTO_ICMP
+IPPROTO_ICMPV6
+IPPROTO_IP
+IPPROTO_IPV6
+IPPROTO_NONE
+IPPROTO_RAW
+IPPROTO_ROUTING
+IPPROTO_TCP
+IPPROTO_UDP
+
+MCAST_BLOCK_SOURCE
+MCAST_JOIN_GROUP
+MCAST_JOIN_SOURCE_GROUP
+MCAST_LEAVE_GROUP
+MCAST_LEAVE_SOURCE_GROUP
+MCAST_MSFILTER
+MCAST_UNBLOCK_SOURCE
+
+MSG_BCAST
+MSG_CTRUNC
+MSG_DONTROUTE
+MSG_DONTWAIT
+MSG_EOR
+MSG_MCAST
+MSG_NOSIGNAL
+MSG_OOB
+MSG_PEEK
+MSG_TRUNC
+MSG_WAITALL
+
+NI_DGRAM
+NI_MAXHOST
+NI_MAXSERV
+NI_NAMEREQD
+NI_NOFQDN
+NI_NUMERICHOST
+NI_NUMERICSERV
+
+SHUT_RD
+SHUT_WR
+SHUT_RDWR
+
+SO_BINDANY
+SO_BROADCAST
+SO_DEBUG
+SO_DONTROUTE
+SO_ERROR
+SO_KEEPALIVE
+SO_LINGER
+SO_NOSIGPIPE
+SO_OOBINLINE
+SO_PEERCRED
+SO_RCVBUF
+SO_RCVLOWAT
+SO_RCVTIMEO
+SO_REUSEADDR
+SO_REUSEPORT
+SO_RTABLE
+SO_SNDBUF
+SO_SNDLOWAT
+SO_SNDTIMEO
+SO_SPLICE
+SO_TIMESTAMP
+SO_TYPE
+
+SOCK_DGRAM
+SOCK_RAW
+SOCK_SEQPACKET
+SOCK_STREAM
+
+SOL_SOCKET
+
+TCP_CONGCTL
+TCP_CONGESTION
+TCP_CORK
+TCP_DEFER_ACCEPT
+TCP_INFO
+TCP_KEEPCNT
+TCP_KEEPIDLE
+TCP_KEEPINIT
+TCP_KEEPINTVL
+TCP_LINGER2
+TCP_MAXSEG
+TCP_MD5SIG
+TCP_NODELAY
+TCP_QUICKACK
+TCP_SACK_ENABLE
+TCP_SYNCNT
+TCP_WINDOW_CLAMP
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/src/gen.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/src/gen.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/src/gen.rb	(revision 279)
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+
+Dir.chdir(File.dirname($0))
+
+f = File.open("const.cstub", "w")
+
+IO.readlines("const.def").each { |name|
+  name.sub(/^#.*/, "")
+  name.strip!
+  next if name.empty?
+
+  f.write <<CODE
+#ifdef #{name}
+  define_const(#{name});
+#endif
+CODE
+}
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/src/socket.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/src/socket.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/src/socket.c	(revision 279)
@@ -0,0 +1,776 @@
+/*
+** socket.c - Socket module
+**
+** See Copyright Notice in mruby.h
+*/
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <string.h>
+
+/*#include <unistd.h>*/
+extern int gethostname(char *name, size_t len);
+
+#include "mruby.h"
+#include "mruby/array.h"
+#include "mruby/class.h"
+#include "mruby/data.h"
+#include "mruby/string.h"
+#include "mruby/variable.h"
+#include "error.h"
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 255
+#endif
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 32
+#endif
+#define E_SOCKET_ERROR             (mrb_class_get(mrb, "SocketError"))
+
+#if !defined(mrb_cptr)
+#define mrb_cptr_value(m,p) mrb_voidp_value((m),(p))
+#define mrb_cptr(o) mrb_voidp(o)
+#define mrb_cptr_p(o) mrb_voidp_p(o)
+#endif
+
+//#ifdef _WIN32
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
+{
+    if (af == AF_INET)
+    {
+	struct sockaddr_in in;
+	memset(&in, 0, sizeof(in));
+	in.sin_family = AF_INET;
+	memcpy(&in.sin_addr, src, sizeof(struct in_addr));
+	getnameinfo((struct sockaddr *)&in, sizeof(struct
+		    sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
+	return dst;
+    }
+    else if (af == AF_INET6)
+    {
+	struct sockaddr_in6 in;
+	memset(&in, 0, sizeof(in));
+	in.sin6_family = AF_INET6;
+	memcpy(&in.sin6_addr, src, sizeof(struct in6_addr));
+	getnameinfo((struct sockaddr *)&in, sizeof(struct
+		    sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
+	return dst;
+    }
+    return NULL;
+}
+
+int inet_pton(int af, const char *src, void *dst)
+{
+    struct addrinfo hints, *res, *ressave;
+
+    memset(&hints, 0, sizeof(struct addrinfo));
+    hints.ai_family = af;
+
+    if (getaddrinfo(src, NULL, &hints, &res) != 0)
+    {
+	printf("Couldn't resolve host %s\n", src);
+	return -1;
+    }
+
+    ressave = res;
+
+    while (res)
+    {
+	memcpy(dst, res->ai_addr, res->ai_addrlen);
+	res = res->ai_next;
+    }
+
+    freeaddrinfo(ressave);
+    return 0;
+}
+
+//#endif
+
+static mrb_value
+mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass)
+{
+  struct addrinfo hints, *res0, *res;
+  mrb_value ai, ary, family, lastai, nodename, protocol, sa, service, socktype;
+  mrb_int flags;
+  int arena_idx, error;
+  const char *hostname = NULL, *servname = NULL;
+
+  ary = mrb_ary_new(mrb);
+  arena_idx = mrb_gc_arena_save(mrb);  /* ary must be on arena! */
+
+  family = socktype = protocol = mrb_nil_value();
+  flags = 0;
+  mrb_get_args(mrb, "oo|oooi", &nodename, &service, &family, &socktype, &protocol, &flags);
+
+  if (mrb_string_p(nodename)) {
+    hostname = mrb_str_to_cstr(mrb, nodename);
+  } else if (mrb_nil_p(nodename)) {
+    hostname = NULL;
+  } else {
+    mrb_raise(mrb, E_TYPE_ERROR, "nodename must be String or nil");
+  }
+
+  if (mrb_string_p(service)) {
+    servname = mrb_str_to_cstr(mrb, service);
+  } else if (mrb_fixnum_p(service)) {
+    servname = mrb_str_to_cstr(mrb, mrb_funcall(mrb, service, "to_s", 0));
+  } else if (mrb_nil_p(service)) {
+    servname = NULL;
+  } else {
+    mrb_raise(mrb, E_TYPE_ERROR, "service must be String, Fixnum, or nil");
+  }
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_flags = flags;
+
+  if (mrb_fixnum_p(family)) {
+    hints.ai_family = mrb_fixnum(family);
+  }
+
+  if (mrb_fixnum_p(socktype)) {
+    hints.ai_socktype = mrb_fixnum(socktype);
+  }
+
+  lastai = mrb_cv_get(mrb, klass, mrb_intern_lit(mrb, "_lastai"));
+  if (mrb_cptr_p(lastai)) {
+    freeaddrinfo(mrb_cptr(lastai));
+    mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value());
+  }
+
+  error = getaddrinfo(hostname, servname, &hints, &res0);
+  if (error) {
+    mrb_raisef(mrb, E_SOCKET_ERROR, "getaddrinfo: %S", mrb_str_new_cstr(mrb, gai_strerror(error)));
+  }
+  mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_cptr_value(mrb, res0));
+
+  for (res = res0; res != NULL; res = res->ai_next) {
+    sa = mrb_str_new(mrb, (void *)res->ai_addr, res->ai_addrlen);
+    ai = mrb_funcall(mrb, klass, "new", 4, sa, mrb_fixnum_value(res->ai_family), mrb_fixnum_value(res->ai_socktype), mrb_fixnum_value(res->ai_protocol));
+    mrb_ary_push(mrb, ary, ai);
+    mrb_gc_arena_restore(mrb, arena_idx);
+  }
+
+  freeaddrinfo(res0);
+  mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value());
+
+  return ary;
+}
+
+static mrb_value
+mrb_addrinfo_getnameinfo(mrb_state *mrb, mrb_value self)
+{
+  mrb_int flags;
+  mrb_value ary, host, sastr, serv;
+  int error;
+
+  flags = 0;
+  mrb_get_args(mrb, "|i", &flags);
+  host = mrb_str_buf_new(mrb, NI_MAXHOST);
+  serv = mrb_str_buf_new(mrb, NI_MAXSERV);
+
+  sastr = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@sockaddr"));
+  if (!mrb_string_p(sastr)) {
+    mrb_raise(mrb, E_SOCKET_ERROR, "invalid sockaddr");
+  }
+  error = getnameinfo((struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr), RSTRING_PTR(host), NI_MAXHOST, RSTRING_PTR(serv), NI_MAXSERV, flags);
+  if (error != 0) {
+    mrb_raisef(mrb, E_SOCKET_ERROR, "getnameinfo: %s", gai_strerror(error));
+  }
+  ary = mrb_ary_new_capa(mrb, 2);
+  mrb_str_resize(mrb, host, strlen(RSTRING_PTR(host)));
+  mrb_ary_push(mrb, ary, host);
+  mrb_str_resize(mrb, serv, strlen(RSTRING_PTR(serv)));
+  mrb_ary_push(mrb, ary, serv);
+  return ary;
+}
+
+static mrb_value
+mrb_addrinfo_unix_path(mrb_state *mrb, mrb_value self)
+{
+  mrb_value sastr;
+
+  sastr = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@sockaddr"));
+  if (((struct sockaddr *)RSTRING_PTR(sastr))->sa_family != AF_UNIX)
+    mrb_raise(mrb, E_SOCKET_ERROR, "need AF_UNIX address");
+  return mrb_str_new_cstr(mrb, ((struct sockaddr_un *)RSTRING_PTR(sastr))->sun_path);
+}
+
+static mrb_value
+sa2addrlist(mrb_state *mrb, const struct sockaddr *sa, socklen_t salen)
+{
+  mrb_value ary, host;
+  unsigned short port;
+  const char *afstr;
+
+  switch (sa->sa_family) {
+  case AF_INET:
+    afstr = "AF_INET";
+    port = ((struct sockaddr_in *)sa)->sin_port;
+    break;
+  case AF_INET6:
+    afstr = "AF_INET6";
+    port = ((struct sockaddr_in6 *)sa)->sin6_port;
+    break;
+  default:
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "bad af");
+    return mrb_nil_value();
+  }
+  port = ntohs(port);
+  host = mrb_str_buf_new(mrb, NI_MAXHOST);
+  if (getnameinfo(sa, salen, RSTRING_PTR(host), NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == -1)
+    mrb_sys_fail(mrb, "getnameinfo");
+  mrb_str_resize(mrb, host, strlen(RSTRING_PTR(host)));
+  ary = mrb_ary_new_capa(mrb, 4);
+  mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, afstr));
+  mrb_ary_push(mrb, ary, mrb_fixnum_value(port));
+  mrb_ary_push(mrb, ary, host);
+  mrb_ary_push(mrb, ary, host);
+  return ary;
+}
+
+static int
+socket_fd(mrb_state *mrb, mrb_value sock)
+{
+  return mrb_fixnum(mrb_funcall(mrb, sock, "fileno", 0));
+}
+
+static int
+socket_family(int s)
+{
+  struct sockaddr_storage ss;
+  socklen_t salen;
+
+  salen = sizeof(ss);
+  if (getsockname(s, (struct sockaddr *)&ss, &salen) == -1)
+    return AF_UNSPEC;
+  return ss.ss_family;
+}
+
+static mrb_value
+mrb_basicsocket_getpeereid(mrb_state *mrb, mrb_value self)
+{ 
+#ifdef HAVE_GETPEEREID
+  mrb_value ary;
+  gid_t egid;
+  uid_t euid;
+  int s;
+  
+  s = socket_fd(mrb, self);
+  if (getpeereid(s, &euid, &egid) != 0)
+    mrb_sys_fail(mrb, "getpeereid");
+
+  ary = mrb_ary_new_capa(mrb, 2);
+  mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)euid));
+  mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)egid));
+  return ary;
+#else
+  mrb_raise(mrb, E_RUNTIME_ERROR, "getpeereid is not avaialble on this system");
+  return mrb_nil_value();
+#endif
+}
+
+static mrb_value
+mrb_basicsocket_getpeername(mrb_state *mrb, mrb_value self)
+{ 
+  struct sockaddr_storage ss;
+  socklen_t salen;
+  
+  salen = sizeof(ss);
+  if (getpeername(socket_fd(mrb, self), (struct sockaddr *)&ss, &salen) != 0)
+    mrb_sys_fail(mrb, "getpeername");
+
+  return mrb_str_new(mrb, (void *)&ss, salen);
+}
+
+static mrb_value
+mrb_basicsocket_getsockname(mrb_state *mrb, mrb_value self)
+{ 
+  struct sockaddr_storage ss;
+  socklen_t salen;
+  
+  salen = sizeof(ss);
+  if (getsockname(socket_fd(mrb, self), (struct sockaddr *)&ss, &salen) != 0)
+    mrb_sys_fail(mrb, "getsockname");
+
+  return mrb_str_new(mrb, (void *)&ss, salen);
+}
+
+static mrb_value
+mrb_basicsocket_getsockopt(mrb_state *mrb, mrb_value self)
+{ 
+  char opt[8];
+  int s;
+  mrb_int family, level, optname;
+  mrb_value c, data;
+  socklen_t optlen;
+
+  mrb_get_args(mrb, "ii", &level, &optname);
+  s = socket_fd(mrb, self);
+  optlen = sizeof(opt);
+  if (getsockopt(s, level, optname, opt, &optlen) == -1)
+    mrb_sys_fail(mrb, "getsockopt");
+  c = mrb_const_get(mrb, mrb_obj_value(mrb_class_get(mrb, "Socket")), mrb_intern_lit(mrb, "Option"));
+  family = socket_family(s);
+  data = mrb_str_new(mrb, opt, optlen);
+  return mrb_funcall(mrb, c, "new", 4, mrb_fixnum_value(family), mrb_fixnum_value(level), mrb_fixnum_value(optname), data);
+}
+
+static mrb_value
+mrb_basicsocket_recv(mrb_state *mrb, mrb_value self)
+{ 
+  int n;
+  mrb_int maxlen, flags = 0;
+  mrb_value buf;
+
+  mrb_get_args(mrb, "i|i", &maxlen, &flags);
+  buf = mrb_str_buf_new(mrb, maxlen);
+  n = recv(socket_fd(mrb, self), RSTRING_PTR(buf), maxlen, flags);
+  if (n == -1)
+    mrb_sys_fail(mrb, "recv");
+  mrb_str_resize(mrb, buf, n);
+  return buf;
+}
+
+static mrb_value
+mrb_basicsocket_recvfrom(mrb_state *mrb, mrb_value self)
+{ 
+  int n;
+  mrb_int maxlen, flags = 0;
+  mrb_value ary, buf, sa;
+  socklen_t socklen;
+
+  mrb_get_args(mrb, "i|i", &maxlen, &flags);
+  buf = mrb_str_buf_new(mrb, maxlen);
+  socklen = sizeof(struct sockaddr_storage);
+  sa = mrb_str_buf_new(mrb, socklen);
+  n = recvfrom(socket_fd(mrb, self), RSTRING_PTR(buf), maxlen, flags, (struct sockaddr *)RSTRING_PTR(sa), &socklen);
+  if (n == -1)
+    mrb_sys_fail(mrb, "recvfrom");
+  mrb_str_resize(mrb, buf, n);
+  mrb_str_resize(mrb, sa, socklen);
+  ary = mrb_ary_new_capa(mrb, 2);
+  mrb_ary_push(mrb, ary, buf);
+  mrb_ary_push(mrb, ary, sa);
+  return ary;
+}
+
+static mrb_value
+mrb_basicsocket_send(mrb_state *mrb, mrb_value self)
+{ 
+  int n;
+  mrb_int flags;
+  mrb_value dest, mesg;
+
+  dest = mrb_nil_value();
+  mrb_get_args(mrb, "Si|S", &mesg, &flags, &dest);
+  if (mrb_nil_p(dest)) {
+    n = send(socket_fd(mrb, self), RSTRING_PTR(mesg), RSTRING_LEN(mesg), flags);
+  } else {
+    n = sendto(socket_fd(mrb, self), RSTRING_PTR(mesg), RSTRING_LEN(mesg), flags, (const void *)RSTRING_PTR(dest), RSTRING_LEN(dest));
+  }
+  if (n == -1)
+    mrb_sys_fail(mrb, "send");
+  return mrb_fixnum_value(n);
+}
+
+static mrb_value
+mrb_basicsocket_setnonblock(mrb_state *mrb, mrb_value self)
+{ 
+  int fd, flags;
+  mrb_value bool;
+
+  mrb_get_args(mrb, "o", &bool);
+  fd = socket_fd(mrb, self);
+  flags = fcntl(fd, F_GETFL, 0);
+  if (flags == 1)
+    mrb_sys_fail(mrb, "fcntl");
+  if (mrb_test(bool))
+    flags |= O_NONBLOCK;
+  else
+    flags &= ~O_NONBLOCK;
+  if (fcntl(fd, F_SETFL, flags) == -1)
+    mrb_sys_fail(mrb, "fcntl");
+  return mrb_nil_value();
+}
+
+static mrb_value
+mrb_basicsocket_setsockopt(mrb_state *mrb, mrb_value self)
+{ 
+  int argc, s;
+  mrb_int level = 0, optname;
+  mrb_value optval, so;
+
+  argc = mrb_get_args(mrb, "o|io", &so, &optname, &optval);
+  if (argc == 3) {
+    if (!mrb_fixnum_p(so)) {
+      mrb_raise(mrb, E_ARGUMENT_ERROR, "level is not an integer");
+    }
+    level = mrb_fixnum(so);
+    if (mrb_string_p(optval)) {
+      /* that's good */
+    } else if (mrb_type(optval) == MRB_TT_TRUE || mrb_type(optval) == MRB_TT_FALSE) {
+      mrb_int i = mrb_test(optval) ? 1 : 0;
+      optval = mrb_str_new(mrb, (char *)&i, sizeof(i));
+    } else if (mrb_fixnum_p(optval)) {
+      mrb_int i = mrb_fixnum(optval);
+      optval = mrb_str_new(mrb, (char *)&i, sizeof(i));
+    } else {
+      mrb_raise(mrb, E_ARGUMENT_ERROR, "optval should be true, false, an integer, or a string");
+    }
+  } else if (argc == 1) {
+    if (strcmp(mrb_obj_classname(mrb, so), "Socket::Option") != 0)
+      mrb_raisef(mrb, E_ARGUMENT_ERROR, "not an instance of Socket::Option");
+    level = mrb_fixnum(mrb_funcall(mrb, so, "level", 0));
+    optname = mrb_fixnum(mrb_funcall(mrb, so, "optname", 0));
+    optval = mrb_funcall(mrb, so, "data", 0);
+  } else {
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 3)", argc);
+  }
+
+  s = socket_fd(mrb, self);
+  if (setsockopt(s, level, optname, RSTRING_PTR(optval), RSTRING_LEN(optval)) == -1)
+    mrb_sys_fail(mrb, "setsockopt");
+  return mrb_fixnum_value(0);
+}
+
+static mrb_value
+mrb_basicsocket_shutdown(mrb_state *mrb, mrb_value self)
+{ 
+  mrb_int how = SHUT_RDWR;
+
+  mrb_get_args(mrb, "|i", &how);
+  if (shutdown(socket_fd(mrb, self), how) != 0)
+    mrb_sys_fail(mrb, "shutdown");
+  return mrb_fixnum_value(0);
+}
+
+static mrb_value
+mrb_ipsocket_ntop(mrb_state *mrb, mrb_value klass)
+{ 
+  mrb_int af, n;
+  char *addr, buf[50];
+
+  mrb_get_args(mrb, "is", &af, &addr, &n);
+  if ((af == AF_INET && n != 4) || (af == AF_INET6 && n != 16))
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
+  if (inet_ntop(af, addr, buf, sizeof(buf)) == NULL)
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
+  return mrb_str_new_cstr(mrb, buf);
+}
+
+static mrb_value
+mrb_ipsocket_pton(mrb_state *mrb, mrb_value klass)
+{ 
+  mrb_int af, n;
+  char *bp, buf[50];
+
+  mrb_get_args(mrb, "is", &af, &bp, &n);
+  if (n > sizeof(buf) - 1)
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
+  memcpy(buf, bp, n);
+  buf[n] = '\0';
+
+  if (af == AF_INET) {
+    struct in_addr in;
+    if (inet_pton(AF_INET, buf, (void *)&in.s_addr) != 1)
+      goto invalid;
+    return mrb_str_new(mrb, (char *)&in.s_addr, 4);
+  } else if (af == AF_INET6) {
+    struct in6_addr in6;
+    if (inet_pton(AF_INET6, buf, (void *)&in6.s6_addr) != 1)
+      goto invalid;
+    return mrb_str_new(mrb, (char *)&in6.s6_addr, 16);
+  } else
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "unsupported address family");
+
+invalid:
+  mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid address");
+  return mrb_nil_value(); /* dummy */
+}
+
+static mrb_value
+mrb_ipsocket_recvfrom(mrb_state *mrb, mrb_value self)
+{ 
+  struct sockaddr_storage ss;
+  socklen_t socklen;
+  mrb_value a, buf, pair;
+  mrb_int flags, maxlen, n;
+  int fd;
+
+  fd = socket_fd(mrb, self);
+  flags = 0;
+  mrb_get_args(mrb, "i|i", &maxlen, &flags);
+  buf = mrb_str_buf_new(mrb, maxlen);
+  socklen = sizeof(ss);
+  n = recvfrom(fd, RSTRING_PTR(buf), maxlen, flags,
+  	       (struct sockaddr *)&ss, &socklen);
+  if (n == -1) {
+    mrb_sys_fail(mrb, "recvfrom");
+  }
+  mrb_str_resize(mrb, buf, n);
+  a = sa2addrlist(mrb, (struct sockaddr *)&ss, socklen);
+  pair = mrb_ary_new_capa(mrb, 2);
+  mrb_ary_push(mrb, pair, buf);
+  mrb_ary_push(mrb, pair, a);
+  return pair;
+}
+
+static mrb_value
+mrb_socket_gethostname(mrb_state *mrb, mrb_value cls)
+{
+  mrb_value buf;
+  size_t bufsize;
+  
+#ifdef HOST_NAME_MAX
+  bufsize = HOST_NAME_MAX + 1;
+#else
+  bufsize = 256;
+#endif
+  buf = mrb_str_buf_new(mrb, bufsize);
+  if (gethostname(RSTRING_PTR(buf), bufsize) != 0)
+    mrb_sys_fail(mrb, "gethostname");
+  mrb_str_resize(mrb, buf, strlen(RSTRING_PTR(buf)));
+  return buf;
+}
+
+static mrb_value
+mrb_socket_accept(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value ary, sastr;
+  int s1;
+  mrb_int s0;
+  socklen_t socklen;
+
+  mrb_get_args(mrb, "i", &s0);
+  socklen = sizeof(struct sockaddr_storage);
+  sastr = mrb_str_buf_new(mrb, socklen);
+  s1 = accept(s0, (struct sockaddr *)RSTRING_PTR(sastr), &socklen);
+  if (s1 == -1) {
+    mrb_sys_fail(mrb, "accept");
+  }
+  // XXX: possible descriptor leakage here!
+  mrb_str_resize(mrb, sastr, socklen);
+  ary = mrb_ary_new_capa(mrb, 2);
+  mrb_ary_push(mrb, ary, mrb_fixnum_value(s1));
+  mrb_ary_push(mrb, ary, sastr);
+  return ary;
+}
+
+static mrb_value
+mrb_socket_bind(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value sastr;
+  int s;
+
+  mrb_get_args(mrb, "iS", &s, &sastr);
+  if (bind(s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) {
+    mrb_sys_fail(mrb, "bind");
+  }
+  return mrb_nil_value();
+}
+
+static mrb_value
+mrb_socket_connect(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value sastr;
+  int s;
+
+  mrb_get_args(mrb, "iS", &s, &sastr);
+  if (connect(s, (struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr)) == -1) {
+    mrb_sys_fail(mrb, "connect");
+  }
+  return mrb_nil_value();
+}
+
+static mrb_value
+mrb_socket_listen(mrb_state *mrb, mrb_value klass)
+{
+  int backlog, s;
+
+  mrb_get_args(mrb, "ii", &s, &backlog);
+  if (listen(s, backlog) == -1) {
+    mrb_sys_fail(mrb, "listen");
+  }
+  return mrb_nil_value();
+}
+
+static mrb_value
+mrb_socket_sockaddr_family(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value sa;
+
+  mrb_get_args(mrb, "S", &sa);
+#ifdef __linux__
+  if (RSTRING_LEN(sa) < offsetof(struct sockaddr, sa_family) + sizeof(sa_family_t)) {
+    mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)");
+  }
+#else
+  if (RSTRING_LEN(sa) < sizeof(struct sockaddr)) {
+    mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)");
+  }
+#endif
+  return mrb_fixnum_value(((struct sockaddr *)RSTRING_PTR(sa))->sa_family);
+}
+
+static mrb_value
+mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass)
+{
+  struct sockaddr_un *sunp;
+  mrb_value path, s;
+  
+  mrb_get_args(mrb, "S", &path);
+  if (RSTRING_LEN(path) > sizeof(sunp->sun_path) - 1) {
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "too long unix socket path (max: %ubytes)", (unsigned int)sizeof(sunp->sun_path) - 1);
+  }
+  s = mrb_str_buf_new(mrb, sizeof(struct sockaddr_un));
+  sunp = (struct sockaddr_un *)RSTRING_PTR(s);
+  sunp->sun_family = AF_UNIX;
+  memcpy(sunp->sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
+  sunp->sun_path[RSTRING_LEN(path)] = '\0';
+  mrb_str_resize(mrb, s, sizeof(struct sockaddr_un));
+  return s;
+}
+
+static mrb_value
+mrb_socket_socketpair(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value ary;
+  mrb_int domain, type, protocol;
+  int sv[2];
+
+  mrb_get_args(mrb, "iii", &domain, &type, &protocol);
+  if (socketpair(domain, type, protocol, sv) == -1) {
+    mrb_sys_fail(mrb, "socketpair");
+  }
+  // XXX: possible descriptor leakage here!
+  ary = mrb_ary_new_capa(mrb, 2);
+  mrb_ary_push(mrb, ary, mrb_fixnum_value(sv[0]));
+  mrb_ary_push(mrb, ary, mrb_fixnum_value(sv[1]));
+  return ary;
+}
+
+static mrb_value
+mrb_socket_socket(mrb_state *mrb, mrb_value klass)
+{
+  mrb_int domain, type, protocol;
+  int s;
+
+  mrb_get_args(mrb, "iii", &domain, &type, &protocol);
+  s = socket(domain, type, protocol);
+  if (s == -1)
+    mrb_sys_fail(mrb, "socket");
+  return mrb_fixnum_value(s);
+}
+
+static mrb_value
+mrb_tcpsocket_allocate(mrb_state *mrb, mrb_value klass)
+{
+  struct RClass *c = mrb_class_ptr(klass);
+  enum mrb_vtype ttype = MRB_INSTANCE_TT(c);
+
+  /* copied from mrb_instance_alloc() */
+  if (ttype == 0) ttype = MRB_TT_OBJECT;
+  return mrb_obj_value((struct RObject*)mrb_obj_alloc(mrb, ttype, c));
+}
+
+/* Windows overrides for IO methods on BasicSocket objects.
+ * This is because sockets on Windows are not the same as file
+ * descriptors, and thus functions which operate on file descriptors
+ * will break on socket descriptors.
+ */
+
+void
+mrb_mruby_socket_gem_init(mrb_state* mrb)
+{
+  struct RClass *io, *ai, *sock, *bsock, *ipsock, *tcpsock;
+  struct RClass *constants;
+
+  struct RClass *usock;
+
+  ai = mrb_define_class(mrb, "Addrinfo", mrb->object_class);
+  mrb_mod_cv_set(mrb, ai, mrb_intern_lit(mrb, "_lastai"), mrb_nil_value());
+  mrb_define_class_method(mrb, ai, "getaddrinfo", mrb_addrinfo_getaddrinfo, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(4));
+  mrb_define_method(mrb, ai, "getnameinfo", mrb_addrinfo_getnameinfo, MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, ai, "unix_path", mrb_addrinfo_unix_path, MRB_ARGS_NONE());
+
+  io = mrb_class_get(mrb, "IO");
+
+  bsock = mrb_define_class(mrb, "BasicSocket", io);
+  mrb_define_method(mrb, bsock, "_recvfrom", mrb_basicsocket_recvfrom, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, bsock, "_setnonblock", mrb_basicsocket_setnonblock, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, bsock, "getpeereid", mrb_basicsocket_getpeereid, MRB_ARGS_NONE());
+  mrb_define_method(mrb, bsock, "getpeername", mrb_basicsocket_getpeername, MRB_ARGS_NONE());
+  mrb_define_method(mrb, bsock, "getsockname", mrb_basicsocket_getsockname, MRB_ARGS_NONE());
+  mrb_define_method(mrb, bsock, "getsockopt", mrb_basicsocket_getsockopt, MRB_ARGS_REQ(2));
+  mrb_define_method(mrb, bsock, "recv", mrb_basicsocket_recv, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  // #recvmsg(maxlen, flags=0)
+  mrb_define_method(mrb, bsock, "send", mrb_basicsocket_send, MRB_ARGS_REQ(2)|MRB_ARGS_OPT(1));
+  // #sendmsg
+  // #sendmsg_nonblock
+  mrb_define_method(mrb, bsock, "setsockopt", mrb_basicsocket_setsockopt, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(2));
+  mrb_define_method(mrb, bsock, "shutdown", mrb_basicsocket_shutdown, MRB_ARGS_OPT(1));
+
+  ipsock = mrb_define_class(mrb, "IPSocket", bsock);
+  mrb_define_class_method(mrb, ipsock, "ntop", mrb_ipsocket_ntop, MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, ipsock, "pton", mrb_ipsocket_pton, MRB_ARGS_REQ(2));
+  mrb_define_method(mrb, ipsock, "recvfrom", mrb_ipsocket_recvfrom, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+
+  tcpsock = mrb_define_class(mrb, "TCPSocket", ipsock);
+  mrb_define_class_method(mrb, tcpsock, "_allocate", mrb_tcpsocket_allocate, MRB_ARGS_NONE());
+  mrb_define_class(mrb, "TCPServer", tcpsock);
+
+  mrb_define_class(mrb, "UDPSocket", ipsock);
+  //#recvfrom_nonblock
+
+  sock = mrb_define_class(mrb, "Socket", bsock);
+  mrb_define_class_method(mrb, sock, "_accept", mrb_socket_accept, MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, sock, "_bind", mrb_socket_bind, MRB_ARGS_REQ(3));
+  mrb_define_class_method(mrb, sock, "_connect", mrb_socket_connect, MRB_ARGS_REQ(3));
+  mrb_define_class_method(mrb, sock, "_listen", mrb_socket_listen, MRB_ARGS_REQ(2));
+  mrb_define_class_method(mrb, sock, "_sockaddr_family", mrb_socket_sockaddr_family, MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, sock, "_socket", mrb_socket_socket, MRB_ARGS_REQ(3));
+  //mrb_define_class_method(mrb, sock, "gethostbyaddr", mrb_socket_gethostbyaddr, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  //mrb_define_class_method(mrb, sock, "gethostbyname", mrb_socket_gethostbyname, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  mrb_define_class_method(mrb, sock, "gethostname", mrb_socket_gethostname, MRB_ARGS_NONE());
+  //mrb_define_class_method(mrb, sock, "getservbyname", mrb_socket_getservbyname, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  //mrb_define_class_method(mrb, sock, "getservbyport", mrb_socket_getservbyport, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  mrb_define_class_method(mrb, sock, "sockaddr_un", mrb_socket_sockaddr_un, MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, sock, "socketpair", mrb_socket_socketpair, MRB_ARGS_REQ(3));
+  //mrb_define_method(mrb, sock, "sysaccept", mrb_socket_accept, MRB_ARGS_NONE());
+
+  usock = mrb_define_class(mrb, "UNIXSocket", bsock);
+  //mrb_define_class_method(mrb, usock, "pair", mrb_unixsocket_open, MRB_ARGS_OPT(2));
+  //mrb_define_class_method(mrb, usock, "socketpair", mrb_unixsocket_open, MRB_ARGS_OPT(2));
+
+  //mrb_define_method(mrb, usock, "recv_io", mrb_unixsocket_peeraddr, MRB_ARGS_NONE());
+  //mrb_define_method(mrb, usock, "recvfrom", mrb_unixsocket_peeraddr, MRB_ARGS_NONE());
+  //mrb_define_method(mrb, usock, "send_io", mrb_unixsocket_peeraddr, MRB_ARGS_NONE());
+
+  /* Windows IO Method Overrides on BasicSocket */
+
+  constants = mrb_define_module_under(mrb, sock, "Constants");
+
+#define define_const(SYM) \
+  do {								\
+    mrb_define_const(mrb, constants, #SYM, mrb_fixnum_value(SYM));	\
+  } while (0)
+
+#include "const.cstub"
+}
+
+void
+mrb_mruby_socket_gem_final(mrb_state* mrb)
+{
+  mrb_value ai;
+  ai = mrb_mod_cv_get(mrb, mrb_class_get(mrb, "Addrinfo"), mrb_intern_lit(mrb, "_lastai"));
+  if (mrb_cptr_p(ai)) {
+    freeaddrinfo(mrb_cptr(ai));
+  }
+}
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/test/addrinfo.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/test/addrinfo.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/test/addrinfo.rb	(revision 279)
@@ -0,0 +1,89 @@
+assert('Addrinfo') do
+  assert_equal(Class, Addrinfo.class)
+end
+
+assert('super class of Addrinfo') do
+  assert_equal(Object, Addrinfo.superclass)
+end
+
+assert('Addrinfo.getaddrinfo') do
+  ary = Addrinfo.getaddrinfo("localhost", "domain", Socket::AF_INET, Socket::SOCK_STREAM)
+  assert_true(ary.size >= 1)
+  ai = ary[0]
+  assert_equal(ai.afamily, Socket::AF_INET)
+  assert_equal(ai.pfamily, Socket::PF_INET)
+  assert_equal(ai.socktype, Socket::SOCK_STREAM)
+  assert_equal(ai.ip_address, '127.0.0.1')
+  assert_equal(ai.ip_port, 53)
+end
+
+assert('Addrinfo.foreach') do
+  # assume Addrinfo.getaddrinfo works well
+  a = Addrinfo.getaddrinfo("localhost", "domain")
+  b = []
+  Addrinfo.foreach("localhost", "domain") { |ai| b << ai }
+  assert_equal(a.size, b.size)
+end
+
+assert('Addrinfo.ip') do
+  ai = Addrinfo.ip('127.0.0.1')
+  assert_equal('127.0.0.1', ai.ip_address)
+  assert_equal(Socket::AF_INET, ai.afamily)
+  assert_equal(0, ai.ip_port)
+  assert_equal(0, ai.socktype)
+  assert_equal(0, ai.protocol)
+end
+
+assert('Addrinfo.tcp') do
+  ai = Addrinfo.tcp('127.0.0.1', 'smtp')
+  assert_equal('127.0.0.1', ai.ip_address)
+  assert_equal(Socket::AF_INET, ai.afamily)
+  assert_equal(25, ai.ip_port)
+  assert_equal(Socket::SOCK_STREAM, ai.socktype)
+  assert_equal(Socket::IPPROTO_TCP, ai.protocol)
+end
+
+assert('Addrinfo.udp') do
+  ai = Addrinfo.udp('127.0.0.1', 'domain')
+  assert_equal('127.0.0.1', ai.ip_address)
+  assert_equal(Socket::AF_INET, ai.afamily)
+  assert_equal(53, ai.ip_port)
+  assert_equal(Socket::SOCK_DGRAM, ai.socktype)
+  assert_equal(Socket::IPPROTO_UDP, ai.protocol)
+end
+
+assert('Addrinfo.unix') do
+  a1 = Addrinfo.unix('/tmp/sock')
+  assert_true(a1.unix?)
+  assert_equal('/tmp/sock', a1.unix_path)
+  assert_equal(Socket::SOCK_STREAM, a1.socktype)
+  a2 = Addrinfo.unix('/tmp/sock', Socket::SOCK_DGRAM)
+  assert_equal(Socket::SOCK_DGRAM, a2.socktype)
+end
+
+assert('Addrinfo#afamily') do
+  ai4 = Addrinfo.new(Socket.sockaddr_in(1, '127.0.0.1'))
+  ai6 = Addrinfo.new(Socket.sockaddr_in(1, '::1'))
+  aiu = Addrinfo.new(Socket.sockaddr_un('/tmp/sock'))
+  assert_equal(Socket::AF_INET, ai4.afamily)
+  assert_equal(Socket::AF_INET6, ai6.afamily)
+  assert_equal(Socket::AF_UNIX, aiu.afamily)
+end
+
+# assert('Addrinfo#canonname') do
+
+# #getnameinfo
+# assert('Addrinfo#inspect') do
+# assert('Addrinfo#inspect_socket') do
+# assert('Addrinfo#ip?') do
+# assert('Addrinfo#ip_address') do
+# assert('Addrinfo#ip_port') do
+# assert('Addrinfo#ip_unpack') do
+# assert('Addrinfo#ipv4?') do
+# assert('Addrinfo#ipv6?') do
+# assert('Addrinfo#pfamily') do
+# assert('Addrinfo#protocol') do
+# assert('Addrinfo#socktype') do
+# assert('Addrinfo#to_sockaddr') do
+# assert('Addrinfo#unix?') do
+# #unix_path
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/test/basicsocket.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/test/basicsocket.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/test/basicsocket.rb	(revision 279)
@@ -0,0 +1,17 @@
+assert('BasicSocket') do
+  assert_equal(Class, BasicSocket.class)
+end
+
+assert('super class of BasicSocket') do
+  assert_equal(IO, BasicSocket.superclass)
+end
+
+assert('BasicSocket.do_not_reverse_lookup') do
+  assert_equal(BasicSocket.do_not_reverse_lookup, true)
+end
+
+assert('BasicSocket.do_not_reverse_lookup=') do
+  BasicSocket.do_not_reverse_lookup = false
+  assert_equal(BasicSocket.do_not_reverse_lookup, false)
+  BasicSocket.do_not_reverse_lookup = true
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/test/ipsocket.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/test/ipsocket.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/test/ipsocket.rb	(revision 279)
@@ -0,0 +1,40 @@
+# Note: most of tests below will fail if UDPSocket is broken.
+
+assert('IPSocket.getaddress') do
+  l = IPSocket.getaddress("localhost")
+  assert_true (l == "127.0.0.1" or l == "::1")
+end
+
+assert('IPSocket.addr') do
+  localhost = "127.0.0.1"
+  s = UDPSocket.new
+  s.bind(localhost, 0)
+  port = Addrinfo.new(s.getsockname).ip_port
+
+  a = s.addr
+  assert_equal "AF_INET", a[0]
+  assert_equal port,      a[1]
+  assert_equal localhost, a[2]
+  assert_equal localhost, a[3]
+  s.close
+  true
+end
+
+assert('IPSocket.peeraddr') do
+  localhost = "127.0.0.1"
+  server = UDPSocket.new
+  server.bind(localhost, 0)
+  port = server.local_address.ip_port
+
+  client = UDPSocket.new
+  client.connect(localhost, port)
+
+  a = client.peeraddr
+  assert_equal "AF_INET", a[0]
+  assert_equal port,      a[1]
+  assert_equal localhost, a[2]
+  assert_equal localhost, a[3]
+  client.close
+  server.close
+  true
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/test/socket.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/test/socket.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/test/socket.rb	(revision 279)
@@ -0,0 +1,34 @@
+assert('Socket.gethostname') do
+  assert_true(Socket.gethostname.is_a? String)
+end
+
+assert('Socket::getaddrinfo') do
+  ret = Socket.getaddrinfo("localhost", "domain", Socket::AF_INET, Socket::SOCK_DGRAM)
+  assert_true ret.size >= 1
+  a = ret[0]
+  assert_equal "AF_INET",           a[0]
+  assert_equal 53,                  a[1]
+  # documents says it's a hostname but CRuby returns an address
+  #assert_equal "127.0.0.1",         a[2]
+  assert_equal "127.0.0.1",         a[3]
+  assert_equal Socket::AF_INET,     a[4]
+  assert_equal Socket::SOCK_DGRAM,  a[5]
+  assert_equal Socket::IPPROTO_UDP, a[6]
+end
+
+assert('Socket#recvfrom') do
+  begin
+    sstr = "abcdefg"
+    s = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
+    c = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
+    s.bind(Socket.sockaddr_in(0, "127.0.0.1"))
+    c.send sstr, 0, s.getsockname
+    rstr, ai = s.recvfrom sstr.size
+
+    assert_equal sstr, rstr
+    assert_true "127.0.0.1", ai.ip_address
+  ensure
+    s.close rescue nil
+    c.close rescue nil
+  end
+end
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/test/sockettest.c
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/test/sockettest.c	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/test/sockettest.c	(revision 279)
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+#include "mruby.h"
+
+mrb_value
+mrb_sockettest_tmppath(mrb_state *mrb, mrb_value klass)
+{
+  return mrb_str_new_cstr(mrb, tempnam(NULL, "mruby-socket"));
+}
+
+void
+mrb_mruby_socket_gem_test(mrb_state* mrb)
+{
+  struct RClass *c = mrb_define_module(mrb, "SocketTest");
+  mrb_define_class_method(mrb, c, "tmppath", mrb_sockettest_tmppath, MRB_ARGS_NONE());
+}
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/test/tcpsocket.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/test/tcpsocket.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/test/tcpsocket.rb	(revision 279)
@@ -0,0 +1,4 @@
+#assert('TCPSocket.gethostbyname') do
+#assert('TCPSocket.new') do
+#assert('TCPSocket#close') do
+#assert('TCPSocket#write') do
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/test/udpsocket.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/test/udpsocket.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/test/udpsocket.rb	(revision 279)
@@ -0,0 +1,16 @@
+assert('UDPSocket.new') do
+  s = UDPSocket.new
+  assert_true(s.is_a? UDPSocket)
+  s.close
+  s = UDPSocket.new(Socket::AF_INET6)
+  assert_true(s.is_a? UDPSocket)
+  s.close
+  true
+end
+
+#assert('UDPSocket#connect') do
+#assert('UDPSocket#send') do
+#assert('UDPSocket#recv') do
+
+#assert('UDPSocket#bind') do
+#assert('UDPSocket#recvfrom_nonblock') do
Index: EcnlProtoTool/trunk/mrbgems/mruby-socket/test/unix.rb
===================================================================
--- EcnlProtoTool/trunk/mrbgems/mruby-socket/test/unix.rb	(revision 279)
+++ EcnlProtoTool/trunk/mrbgems/mruby-socket/test/unix.rb	(revision 279)
@@ -0,0 +1,126 @@
+def unixserver_test_block
+  path = SocketTest.tmppath
+  File.unlink path rescue nil
+  begin
+    result = yield path
+  ensure
+    File.unlink path rescue nil
+  end
+  result
+end
+
+def with_unix_server
+  unixserver_test_block do |path|
+    UNIXServer.open(path) { |server|
+      yield path, server
+    }
+  end
+end
+
+def with_unix_client
+  with_unix_server do |path, server|
+    UNIXSocket.open(path) do |csock|
+      ssock = server.accept
+      begin
+        yield path, server, ssock, csock
+      ensure
+        ssock.close unless ssock.closed? rescue nil
+      end
+    end
+  end
+end
+
+assert('UNIXServer.new') do
+  unixserver_test_block do |path|
+    server = UNIXServer.new(path)
+    assert_true server.is_a? UNIXServer
+    server.close
+    File.unlink path
+
+    s2 = nil
+    result = UNIXServer.open(path) { |s1|
+      assert_true s1.is_a? UNIXServer
+      s2 = s1
+      1234
+    }
+    assert_equal 1234, result
+    assert_true s2.is_a? UNIXServer
+    assert_true s2.closed?
+  end
+end
+
+# assert('UNIXServer#accept_nonblock') - would block if fails
+
+assert('UNIXServer#addr') do
+  with_unix_server do |path, server|
+    assert_equal [ "AF_UNIX", path], server.addr
+  end
+end
+
+assert('UNIXServer#path') do
+  with_unix_server do |path, server|
+    assert_equal path, server.path
+  end
+end
+
+# assert('UNIXServer#peeraddr') - will raise a runtime exception
+
+assert('UNIXServer#listen') do
+  with_unix_server do |path, server|
+    assert_equal 0, server.listen(1)
+  end
+end
+
+assert('UNIXServer#sysaccept') do
+  with_unix_server do |path, server|
+    UNIXSocket.open(path) do |csock|
+      begin
+        fd = server.sysaccept
+        assert_true fd.kind_of? Integer
+      ensure
+        IO._sysclose(fd) rescue nil
+      end
+    end
+  end
+end
+
+assert('UNIXSocket.new') do
+  with_unix_server do |path, server|
+    c = UNIXSocket.new(path)
+    assert_true c.is_a? UNIXSocket
+    c.close
+    true
+  end
+end
+
+assert('UNIXSocket#addr') do
+  with_unix_client do |path, server, ssock, csock|
+    assert_equal [ "AF_UNIX", path ], ssock.addr
+    assert_equal [ "AF_UNIX", "" ],   csock.addr
+  end
+end
+
+assert('UNIXSocket#path') do
+  with_unix_client do |path, server, ssock, csock|
+    assert_equal path, ssock.path
+    assert_equal "",   csock.path
+  end
+end
+
+assert('UNIXSocket#peeraddr') do
+  with_unix_client do |path, server, ssock, csock|
+    assert_equal [ "AF_UNIX", ""   ], ssock.peeraddr
+    assert_equal [ "AF_UNIX", path ], csock.peeraddr
+  end
+end
+
+assert('UNIXSocket#recvfrom') do
+  with_unix_client do |path, server, ssock, csock|
+    str = "0123456789"
+    ssock.send str, 0
+    a = csock.recvfrom(8)
+    assert_equal str[0, 8], a[0]
+    assert_equal "AF_UNIX", a[1][0]
+    # a[1][1] would be "" or something
+  end
+end
