Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/default.gembox
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/default.gembox	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/default.gembox	(revision 439)
@@ -1,3 +1,12 @@
 MRuby::GemBox.new do |conf|
+  # Meta-programming features
+  conf.gem :core => "mruby-metaprog"
+
+  # Use standard IO/File class
+  conf.gem :core => "mruby-io"
+
+  # Use standard Array#pack, String#unpack methods
+  conf.gem :core => "mruby-pack"
+
   # Use standard Kernel#sprintf method
   conf.gem :core => "mruby-sprintf"
@@ -14,4 +23,7 @@
   # Use standard Struct class
   conf.gem :core => "mruby-struct"
+
+  # Use Comparable module extension
+  conf.gem :core => "mruby-compar-ext"
 
   # Use Enumerable module extension
@@ -75,4 +87,7 @@
   conf.gem :core => "mruby-class-ext"
 
+  # Use Method/UnboundMethod class
+  conf.gem :core => "mruby-method"
+
   # Use mruby-compiler to build other mrbgems
   conf.gem :core => "mruby-compiler"
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/full-core.gembox
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/full-core.gembox	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/full-core.gembox	(revision 439)
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-array-ext/mrblib/array.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-array-ext/mrblib/array.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-array-ext/mrblib/array.rb	(revision 439)
@@ -1,28 +1,3 @@
 class Array
-  ##
-  # call-seq:
-  #    Array.try_convert(obj) -> array or nil
-  #
-  # Tries to convert +obj+ into an array, using +to_ary+ method.
-  # converted array or +nil+ if +obj+ cannot be converted for any reason.
-  # This method can be used to check if an argument is an array.
-  #
-  #    Array.try_convert([1])   #=> [1]
-  #    Array.try_convert("1")   #=> nil
-  #
-  #    if tmp = Array.try_convert(arg)
-  #      # the argument is an array
-  #    elsif tmp = String.try_convert(arg)
-  #      # the argument is a string
-  #    end
-  #
-  def self.try_convert(obj)
-    if obj.respond_to?(:to_ary)
-      obj.to_ary
-    else
-      nil
-    end
-  end
-
   ##
   # call-seq:
@@ -42,21 +17,17 @@
   #
   def uniq!(&block)
-    ary = self.dup
-    result = []
+    hash = {}
     if block
+      self.each do |val|
+        key = block.call(val)
+        hash[key] = val unless hash.key?(key)
+      end
+      result = hash.values
+    else
       hash = {}
-      while ary.size > 0
-        val = ary.shift
-        key = block.call(val)
-        hash[key] = val unless hash.has_key?(key)
-      end
-      hash.each_value do |value|
-        result << value
-      end
-    else
-      while ary.size > 0
-        result << ary.shift
-        ary.delete(result.last)
-      end
+      self.each do |val|
+        hash[val] = val
+      end
+      result = hash.keys
     end
     if result.size == self.size
@@ -82,9 +53,5 @@
   def uniq(&block)
     ary = self.dup
-    if block
-      ary.uniq!(&block)
-    else
-      ary.uniq!
-    end
+    ary.uniq!(&block)
     ary
   end
@@ -106,7 +73,34 @@
     hash = {}
     array = []
-    elem.each { |x| hash[x] = true }
-    self.each { |x| array << x unless hash[x] }
+    idx = 0
+    len = elem.size
+    while idx < len
+      hash[elem[idx]] = true
+      idx += 1
+    end
+    idx = 0
+    len = size
+    while idx < len
+      v = self[idx]
+      array << v unless hash[v]
+      idx += 1
+    end
     array
+  end
+
+  ##
+  # call-seq:
+  #    ary.difference(other_ary1, other_ary2, ...)   -> new_ary
+  #
+  # Returns a new array that is a copy of the original array, removing all
+  # occurrences of any item that also appear in +other_ary+. The order is
+  # preserved from the original array.
+  #
+  def difference(*args)
+    ary = self
+    args.each do |x|
+      ary = ary - x
+    end
+    ary
   end
 
@@ -130,4 +124,23 @@
   ##
   # call-seq:
+  #    ary.union(other_ary,...)  -> new_ary
+  #
+  # Set Union---Returns a new array by joining this array with
+  # <i>other_ary</i>, removing duplicates.
+  #
+  #    ["a", "b", "c"].union(["c", "d", "a"], ["a", "c", "e"])
+  #           #=> ["a", "b", "c", "d", "e"]
+  #
+  def union(*args)
+    ary = self.dup
+    args.each do |x|
+      ary.concat(x)
+      ary.uniq!
+    end
+    ary
+  end
+
+  ##
+  # call-seq:
   #    ary & other_ary      -> new_ary
   #
@@ -142,12 +155,39 @@
     hash = {}
     array = []
-    elem.each{|v| hash[v] = true }
-    self.each do |v|
+    idx = 0
+    len = elem.size
+    while idx < len
+      hash[elem[idx]] = true
+      idx += 1
+    end
+    idx = 0
+    len = size
+    while idx < len
+      v = self[idx]
       if hash[v]
         array << v
         hash.delete v
       end
+      idx += 1
     end
     array
+  end
+
+  ##
+  # call-seq:
+  #    ary.intersection(other_ary,...)  -> new_ary
+  #
+  # Set Intersection---Returns a new array containing elements common to
+  # this array and <i>other_ary</i>s, removing duplicates. The order is
+  # preserved from the original array.
+  #
+  #    [1, 2, 3].intersection([3, 4, 1], [1, 3, 5])  #=> [1, 3]
+  #
+  def intersection(*args)
+    ary = self
+    args.each do |x|
+      ary = ary & x
+    end
+    ary
   end
 
@@ -170,13 +210,7 @@
   #
   def flatten(depth=nil)
-    ar = []
-    self.each do |e|
-      if e.is_a?(Array) && (depth.nil? || depth > 0)
-        ar += e.flatten(depth.nil? ? nil : depth - 1)
-      else
-        ar << e
-      end
-    end
-    ar
+    res = dup
+    res.flatten! depth
+    res
   end
 
@@ -201,5 +235,8 @@
     modified = false
     ar = []
-    self.each do |e|
+    idx = 0
+    len = size
+    while idx < len
+      e = self[idx]
       if e.is_a?(Array) && (depth.nil? || depth > 0)
         ar += e.flatten(depth.nil? ? nil : depth - 1)
@@ -208,4 +245,5 @@
         ar << e
       end
+      idx += 1
     end
     if modified
@@ -253,5 +291,5 @@
   # for efficiency
   def reverse_each(&block)
-    return to_enum :reverse_each unless block_given?
+    return to_enum :reverse_each unless block
 
     i = self.size - 1
@@ -263,5 +301,4 @@
   end
 
-  NONE=Object.new
   ##
   #  call-seq:
@@ -288,5 +325,5 @@
   #
 
-  def fetch(n=nil, ifnone=NONE, &block)
+  def fetch(n, ifnone=NONE, &block)
     warn "block supersedes default value argument" if !n.nil? && ifnone != NONE && block
 
@@ -475,5 +512,5 @@
 
   def delete_if(&block)
-    return to_enum :delete_if unless block_given?
+    return to_enum :delete_if unless block
 
     idx = 0
@@ -504,5 +541,5 @@
 
   def reject!(&block)
-    return to_enum :reject! unless block_given?
+    return to_enum :reject! unless block
 
     len = self.size
@@ -594,23 +631,51 @@
 
   def bsearch(&block)
-    return to_enum :bsearch unless block_given?
+    return to_enum :bsearch unless block
+
+    if idx = bsearch_index(&block)
+      self[idx]
+    else
+      nil
+    end
+  end
+
+  ##
+  #  call-seq:
+  #     ary.bsearch_index {|x| block }  -> int or nil
+  #
+  #  By using binary search, finds an index of a value from this array which
+  #  meets the given condition in O(log n) where n is the size of the array.
+  #
+  #  It supports two modes, depending on the nature of the block and they are
+  #  exactly the same as in the case of #bsearch method with the only difference
+  #  being that this method returns the index of the element instead of the
+  #  element itself. For more details consult the documentation for #bsearch.
+
+  def bsearch_index(&block)
+    return to_enum :bsearch_index unless block
 
     low = 0
-    high = self.size
+    high = size
     satisfied = false
+
     while low < high
-      mid = low + ((high - low) / 2).truncate
-      val = self[mid]
-      v = block.call(val)
-      if v.is_a?(Integer)
-        return val if v == 0
-        smaller = v < 0
-      elsif v == true
+      mid = ((low+high)/2).truncate
+      res = block.call self[mid]
+
+      case res
+      when 0 # find-any mode: Found!
+        return mid
+      when Numeric # find-any mode: Continue...
+        in_lower_half = res < 0
+      when true # find-min mode
+        in_lower_half = true
         satisfied = true
-        smaller = true
-      elsif v == false || v.nil?
-        smaller = false
-      end
-      if smaller
+      when false, nil # find-min mode
+        in_lower_half = false
+      else
+        raise TypeError, 'invalid block result (must be numeric, true, false or nil)'
+      end
+
+      if in_lower_half
         high = mid
       else
@@ -618,38 +683,6 @@
       end
     end
-    return nil if low == self.size
-    return nil unless satisfied
-    self[low]
-  end
-
-  ##
-  #  call-seq:
-  #     ary.delete_if { |item| block }  -> ary
-  #     ary.delete_if                   -> Enumerator
-  #
-  #  Deletes every element of +self+ for which block evaluates to +true+.
-  #
-  #  The array is changed instantly every time the block is called, not after
-  #  the iteration is over.
-  #
-  #  See also Array#reject!
-  #
-  #  If no block is given, an Enumerator is returned instead.
-  #
-  #     scores = [ 97, 42, 75 ]
-  #     scores.delete_if {|score| score < 80 }   #=> [97]
-
-  def delete_if(&block)
-    return to_enum :delete_if unless block_given?
-
-    idx = 0
-    while idx < self.size do
-      if block.call(self[idx])
-        self.delete_at(idx)
-      else
-        idx += 1
-      end
-    end
-    self
+
+    satisfied ? low : nil
   end
 
@@ -670,5 +703,5 @@
 
   def keep_if(&block)
-    return to_enum :keep_if unless block_given?
+    return to_enum :keep_if unless block
 
     idx = 0
@@ -699,11 +732,15 @@
 
   def select!(&block)
-    return to_enum :select! unless block_given?
+    return to_enum :select! unless block
 
     result = []
-    self.each do |x|
-      result << x if block.call(x)
-    end
-    return nil if self.size == result.size
+    idx = 0
+    len = size
+    while idx < len
+      elem = self[idx]
+      result << elem if block.call(elem)
+      idx += 1
+    end
+    return nil if len == result.size
     self.replace(result)
   end
@@ -727,6 +764,7 @@
     if block
       idx = 0
-      self.each do |*e|
-        return idx if block.call(*e)
+      len = size
+      while idx < len
+        return idx if block.call self[idx]
         idx += 1
       end
@@ -735,14 +773,4 @@
     end
     nil
-  end
-
-  ##
-  #  call-seq:
-  #     ary.to_ary -> ary
-  #
-  #  Returns +self+.
-  #
-  def to_ary
-    self
   end
 
@@ -763,3 +791,156 @@
     end
   end
+
+  ##
+  # call-seq:
+  #    ary.permutation { |p| block }          -> ary
+  #    ary.permutation                        -> Enumerator
+  #    ary.permutation(n) { |p| block }       -> ary
+  #    ary.permutation(n)                     -> Enumerator
+  #
+  # When invoked with a block, yield all permutations of length +n+ of the
+  # elements of the array, then return the array itself.
+  #
+  # If +n+ is not specified, yield all permutations of all elements.
+  #
+  # The implementation makes no guarantees about the order in which the
+  # permutations are yielded.
+  #
+  # If no block is given, an Enumerator is returned instead.
+  #
+  # Examples:
+  #
+  #  a = [1, 2, 3]
+  #  a.permutation.to_a    #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
+  #  a.permutation(1).to_a #=> [[1],[2],[3]]
+  #  a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
+  #  a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
+  #  a.permutation(0).to_a #=> [[]] # one permutation of length 0
+  #  a.permutation(4).to_a #=> []   # no permutations of length 4
+  def permutation(n=self.size, &block)
+    return to_enum(:permutation, n) unless block
+    size = self.size
+    if n == 0
+      yield []
+    elsif 0 < n && n <= size
+      i = 0
+      while i<size
+        result = [self[i]]
+        if n-1 > 0
+          ary = self[0...i] + self[i+1..-1]
+          ary.permutation(n-1) do |c|
+            yield result + c
+          end
+        else
+          yield result
+        end
+        i += 1
+      end
+    end
+    self
+  end
+
+  ##
+  # call-seq:
+  #    ary.combination(n) { |c| block }    -> ary
+  #    ary.combination(n)                  -> Enumerator
+  #
+  # When invoked with a block, yields all combinations of length +n+ of elements
+  # from the array and then returns the array itself.
+  #
+  # The implementation makes no guarantees about the order in which the
+  # combinations are yielded.
+  #
+  # If no block is given, an Enumerator is returned instead.
+  #
+  # Examples:
+  #
+  #    a = [1, 2, 3, 4]
+  #    a.combination(1).to_a  #=> [[1],[2],[3],[4]]
+  #    a.combination(2).to_a  #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
+  #    a.combination(3).to_a  #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
+  #    a.combination(4).to_a  #=> [[1,2,3,4]]
+  #    a.combination(0).to_a  #=> [[]] # one combination of length 0
+  #    a.combination(5).to_a  #=> []   # no combinations of length 5
+
+  def combination(n, &block)
+    return to_enum(:combination, n) unless block
+    size = self.size
+    if n == 0
+       yield []
+    elsif n == 1
+      i = 0
+      while i<size
+        yield [self[i]]
+        i += 1
+      end
+    elsif n <= size
+      i = 0
+      while i<size
+        result = [self[i]]
+        self[i+1..-1].combination(n-1) do |c|
+          yield result + c
+        end
+        i += 1
+      end
+    end
+    self
+  end
+
+  ##
+  # call-seq:
+  #    ary.transpose -> new_ary
+  #
+  # Assumes that self is an array of arrays and transposes the rows and columns.
+  #
+  # If the length of the subarrays don't match, an IndexError is raised.
+  #
+  # Examples:
+  #
+  #    a = [[1,2], [3,4], [5,6]]
+  #    a.transpose   #=> [[1, 3, 5], [2, 4, 6]]
+
+  def transpose
+    return [] if empty?
+
+    column_count = nil
+    self.each do |row|
+      raise TypeError unless row.is_a?(Array)
+      column_count ||= row.size
+      raise IndexError, 'element size differs' unless column_count == row.size
+    end
+
+    Array.new(column_count) do |column_index|
+      self.map { |row| row[column_index] }
+    end
+  end
+
+  ##
+  #  call-seq:
+  #    ary.to_h                ->   Hash
+  #    ary.to_h{|item| ... }   ->   Hash
+  #
+  # Returns the result of interpreting <i>aray</i> as an array of
+  # <tt>[key, value]</tt> pairs. If a block is given, it should
+  # return <tt>[key, value]</tt> pairs to construct a hash.
+  #
+  #     [[:foo, :bar], [1, 2]].to_h
+  #       # => {:foo => :bar, 1 => 2}
+  #     [1, 2].to_h{|x| [x, x*2]}
+  #       # => {1 => 2, 2 => 4}
+  #
+  def to_h(&blk)
+    h = {}
+    self.each do |v|
+      v = blk.call(v) if blk
+      raise TypeError, "wrong element type #{v.class}" unless Array === v
+      raise ArgumentError, "wrong array length (expected 2, was #{v.length})" unless v.length == 2
+      h[v[0]] = v[1]
+    end
+    h
+  end
+
+  alias append push
+  alias prepend unshift
+  alias filter! select!
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-array-ext/src/array.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-array-ext/src/array.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-array-ext/src/array.c	(revision 439)
@@ -66,5 +66,5 @@
   for (i = 0; i < RARRAY_LEN(ary); ++i) {
     v = RARRAY_PTR(ary)[i];
-    if (mrb_type(v) == MRB_TT_ARRAY &&
+    if (mrb_array_p(v) &&
         RARRAY_LEN(v) > 1 &&
         mrb_equal(mrb, RARRAY_PTR(v)[1], value))
@@ -107,46 +107,4 @@
 }
 
-/*
- *  call-seq:
- *     ary.to_h   ->   Hash
- *
- *  Returns the result of interpreting <i>aray</i> as an array of
- *  <tt>[key, value]</tt> paris.
- *
- *      [[:foo, :bar], [1, 2]].to_h
- *        # => {:foo => :bar, 1 => 2}
- *
- */
-
-static mrb_value
-mrb_ary_to_h(mrb_state *mrb, mrb_value ary)
-{
-  mrb_int i;
-  mrb_value v, hash;
-
-  hash = mrb_hash_new_capa(mrb, 0);
-
-  for (i = 0; i < RARRAY_LEN(ary); ++i) {
-    v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]);
-
-    if (mrb_nil_p(v)) {
-      mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)",
-        mrb_str_new_cstr(mrb,  mrb_obj_classname(mrb, ary_elt(ary, i))),
-        mrb_fixnum_value(i)
-      );
-    }
-
-    if (RARRAY_LEN(v) != 2) {
-      mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong array length at %S (expected 2, was %S)",
-        mrb_fixnum_value(i),
-        mrb_fixnum_value(RARRAY_LEN(v))
-      );
-    }
-
-    mrb_hash_set(mrb, hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]);
-  }
-
-  return hash;
-}
 
 /*
@@ -175,6 +133,5 @@
 {
   struct RArray *a = mrb_ary_ptr(self);
-  mrb_int i, j, k, len;
-  mrb_value index;
+  mrb_int i, j, k, len, alen;
   mrb_value val;
   mrb_value *ptr;
@@ -183,8 +140,11 @@
   mrb_ary_modify(mrb, a);
 
-  if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
+  if (mrb_get_argc(mrb) == 1) {
+    mrb_value index;
+
+    mrb_get_args(mrb, "o|i", &index, &len);
     switch (mrb_type(index)) {
     case MRB_TT_RANGE:
-      if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) {
+      if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == MRB_RANGE_OK) {
         goto delete_pos_len;
       }
@@ -201,25 +161,26 @@
   }
 
-  i = mrb_fixnum(index);
+  mrb_get_args(mrb, "ii", &i, &len);
  delete_pos_len:
-  if (i < 0) i += a->len;
-  if (i < 0 || a->len < i) return mrb_nil_value();
+  alen = ARY_LEN(a);
+  if (i < 0) i += alen;
+  if (i < 0 || alen < i) return mrb_nil_value();
   if (len < 0) return mrb_nil_value();
-  if (a->len == i) return mrb_ary_new(mrb);
-  if (len > a->len - i) len = a->len - i;
+  if (alen == i) return mrb_ary_new(mrb);
+  if (len > alen - i) len = alen - i;
 
   ary = mrb_ary_new_capa(mrb, len);
-
+  ptr = ARY_PTR(a);
   for (j = i, k = 0; k < len; ++j, ++k) {
-    mrb_ary_push(mrb, ary, a->ptr[j]);
-  }
-
-  ptr = a->ptr + i;
-  for (j = i; j < a->len - len; ++j) {
+    mrb_ary_push(mrb, ary, ptr[j]);
+  }
+
+  ptr += i;
+  for (j = i; j < alen - len; ++j) {
     *ptr = *(ptr+len);
     ++ptr;
   }
 
-  mrb_ary_resize(mrb, self, a->len - len);
+  mrb_ary_resize(mrb, self, alen - len);
   return ary;
 }
@@ -234,6 +195,5 @@
   mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1));
   mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY());
-  mrb_define_method(mrb, a, "to_h",   mrb_ary_to_h, MRB_ARGS_REQ(0));
-  mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang,   MRB_ARGS_ANY());
+  mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang,   MRB_ARGS_ARG(1,1));
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-array-ext/test/array.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-array-ext/test/array.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-array-ext/test/array.rb	(revision 439)
@@ -2,9 +2,19 @@
 # Array(Ext) Test
 
-assert("Array.try_convert") do
-  assert_nil Array.try_convert(0)
-  assert_nil Array.try_convert(nil)
-  assert_equal [], Array.try_convert([])
-  assert_equal [1,2,3], Array.try_convert([1,2,3])
+def assert_permutation_combination(exp, receiver, meth, *args)
+  act = []
+  ret = receiver.__send__(meth, *args) { |v| act << v }
+  assert "assert_#{meth}" do
+    assert_equal(exp, act.sort)
+    assert_same(receiver, ret)
+  end
+end
+
+def assert_permutation(exp, receiver, *args)
+  assert_permutation_combination(exp, receiver, :permutation, *args)
+end
+
+def assert_combination(exp, receiver, *args)
+  assert_permutation_combination(exp, receiver, :combination, *args)
 end
 
@@ -76,4 +86,20 @@
 end
 
+assert("Array#union") do
+  a = [1, 2, 3, 1]
+  b = [1, 4]
+  c = [1, 5]
+
+  assert_equal [1, 2, 3, 4, 5], a.union(b,c)
+end
+
+assert("Array#difference") do
+  a = [1, 2, 3, 1, 6, 7]
+  b = [1, 4, 6]
+  c = [1, 5, 7]
+
+  assert_equal [2, 3], a.difference(b,c)
+end
+
 assert("Array#&") do
   a = [1, 2, 3, 1]
@@ -84,4 +110,12 @@
   assert_equal [1], (a & b)
   assert_equal [1, 2, 3, 1], a
+end
+
+assert("Array#intersection") do
+  a = [1, 2, 3, 1, 8, 6, 7, 8]
+  b = [1, 4, 6, 8]
+  c = [1, 5, 7, 8]
+
+  assert_equal [1, 8], a.intersection(b,c)
 end
 
@@ -162,10 +196,4 @@
   end
   assert_equal [ "d", "c", "b", "a" ], b
-
-  if Object.const_defined?(:Enumerator)
-    assert_equal [ "d", "c", "b", "a" ], a.reverse_each.to_a
-  else
-    true
-  end
 end
 
@@ -229,30 +257,46 @@
 assert("Array#bsearch") do
   # Find minimum mode
-  a = [0, 4, 7, 10, 12]
-  assert_include [4, 7], a.bsearch {|x| x >= 4 }
-  assert_equal 7, a.bsearch {|x| x >= 6 }
-  assert_equal 0, a.bsearch {|x| x >= -1 }
-  assert_nil a.bsearch {|x| x >= 100 }
+  a = [0, 2, 4]
+  assert_equal 0, a.bsearch{ |x| x >= -1 }
+  assert_equal 0, a.bsearch{ |x| x >= 0 }
+  assert_equal 2, a.bsearch{ |x| x >= 1 }
+  assert_equal 2, a.bsearch{ |x| x >= 2 }
+  assert_equal 4, a.bsearch{ |x| x >= 3 }
+  assert_equal 4, a.bsearch{ |x| x >= 4 }
+  assert_nil      a.bsearch{ |x| x >= 5 }
 
   # Find any mode
-  a = [0, 4, 7, 10, 12]
-  assert_include [4, 7], a.bsearch {|x| 1 - (x / 4).truncate }
-  assert_nil a.bsearch {|x| 4 - (x / 2).truncate }
-  assert_equal(nil, a.bsearch {|x| 1 })
-  assert_equal(nil, a.bsearch {|x| -1 })
-end
-
-assert("Array#delete_if") do
-  a = [1, 2, 3, 4, 5]
-  assert_equal [1, 2, 3, 4, 5], a.delete_if { false }
-  assert_equal [1, 2, 3, 4, 5], a
-
-  a = [1, 2, 3, 4, 5]
-  assert_equal [], a.delete_if { true }
-  assert_equal [], a
-
-  a = [ 1, 2, 3, 4, 5 ]
-  assert_equal [1, 2, 3], a.delete_if { |val| val > 3 }
-end
+  a = [0, 4, 8]
+  def between(lo, x, hi)
+    if x < lo
+      1
+    elsif x > hi
+      -1
+    else
+      0
+    end
+  end
+  assert_nil      a.bsearch{ |x| between(-3, x, -1) }
+  assert_equal 0, a.bsearch{ |x| between(-1, x,  1) }
+  assert_nil      a.bsearch{ |x| between( 1, x,  3) }
+  assert_equal 4, a.bsearch{ |x| between( 3, x,  5) }
+  assert_nil      a.bsearch{ |x| between( 5, x,  7) }
+  assert_equal 8, a.bsearch{ |x| between( 7, x,  9) }
+  assert_nil      a.bsearch{ |x| between( 9, x, 11) }
+
+  assert_equal 0, a.bsearch{ |x| between( 0, x,  3) }
+  assert_equal 4, a.bsearch{ |x| between( 0, x,  4) }
+  assert_equal 4, a.bsearch{ |x| between( 4, x,  8) }
+  assert_equal 8, a.bsearch{ |x| between( 5, x,  8) }
+
+  # Invalid block result
+  assert_raise TypeError, 'invalid block result (must be numeric, true, false or nil)' do
+    a.bsearch{ 'I like to watch the world burn' }
+  end
+end
+
+# tested through Array#bsearch
+#assert("Array#bsearch_index") do
+#end
 
 assert("Array#keep_if") do
@@ -302,23 +346,7 @@
 end
 
-assert('Array#to_h (Modified)') do
-  class A
-    def to_ary
-      $a.clear
-      nil
-    end
-  end
-  $a = [A.new]
-  assert_raise(TypeError) { $a.to_h }
-end
-
 assert("Array#index (block)") do
   assert_nil (1..10).to_a.index { |i| i % 5 == 0 and i % 7 == 0 }
   assert_equal 34, (1..100).to_a.index { |i| i % 5 == 0 and i % 7 == 0 }
-end
-
-assert("Array#to_ary") do
-  assert_equal [], [].to_ary
-  assert_equal [1,2,3], [1,2,3].to_ary
 end
 
@@ -353,2 +381,35 @@
   assert_equal(j, nil)
 end
+
+assert("Array#permutation") do
+  a = [1, 2, 3]
+  assert_permutation([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]], a)
+  assert_permutation([[1],[2],[3]], a, 1)
+  assert_permutation([[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]], a, 2)
+  assert_permutation([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]], a, 3)
+  assert_permutation([[]], a, 0)
+  assert_permutation([], a, 4)
+  assert_permutation([], a, -1)
+end
+
+assert("Array#combination") do
+  a = [1, 2, 3, 4]
+  assert_combination([[1],[2],[3],[4]], a, 1)
+  assert_combination([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]], a, 2)
+  assert_combination([[1,2,3],[1,2,4],[1,3,4],[2,3,4]], a, 3)
+  assert_combination([[1,2,3,4]], a, 4)
+  assert_combination([[]], a, 0)
+  assert_combination([], a, 5)
+  assert_combination([], a, -1)
+end
+
+assert('Array#transpose') do
+  assert_equal([].transpose, [])
+  assert_equal([[]].transpose, [])
+  assert_equal([[1]].transpose, [[1]])
+  assert_equal([[1,2,3]].transpose, [[1], [2], [3]])
+  assert_equal([[1], [2], [3]].transpose, [[1,2,3]])
+  assert_equal([[1,2], [3,4], [5,6]].transpose, [[1,3,5], [2,4,6]])
+  assert_raise(TypeError) { [1].transpose }
+  assert_raise(IndexError) { [[1], [2,3,4]].transpose }
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-config/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-config/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-config/mrbgem.rake	(revision 439)
@@ -0,0 +1,26 @@
+unless MRuby::Build.current.kind_of?(MRuby::CrossBuild)
+  MRuby::Gem::Specification.new('mruby-bin-config') do |spec|
+    name = 'mruby-config'
+    spec.license = 'MIT'
+    spec.author  = 'mruby developers'
+    spec.summary = "#{name} command"
+
+    mruby_config_dir = "#{build.build_dir}/bin"
+    mruby_config = name + (ENV['OS'] == 'Windows_NT' ? '.bat' : '')
+    mruby_config_path = "#{mruby_config_dir}/#{mruby_config}"
+    make_cfg = "#{build.build_dir}/lib/libmruby.flags.mak"
+    tmplt_path = "#{__dir__}/#{mruby_config}"
+    build.bins << mruby_config
+
+    directory mruby_config_dir
+
+    file mruby_config_path => [mruby_config_dir, make_cfg, tmplt_path] do |t|
+      config = Hash[File.readlines(make_cfg).map!(&:chomp).map! {|l|
+        l.gsub('\\"', '"').split(' = ', 2).map! {|s| s.sub(/^(?=.)/, 'echo ')}
+      }]
+      tmplt = File.read(tmplt_path)
+      File.write(t.name, tmplt.gsub(/(#{Regexp.union(*config.keys)})\b/, config))
+      chmod(0755, t.name)
+    end
+  end
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-config/mruby-config
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-config/mruby-config	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-config/mruby-config	(revision 439)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+while [ $# -gt 0 ]; do
+  case $1 in
+    --cflags) echo MRUBY_CFLAGS;;
+    --ldflags) echo MRUBY_LDFLAGS;;
+    --ldflags-before-libs) echo MRUBY_LDFLAGS_BEFORE_LIBS;;
+    --libs) echo MRUBY_LIBS;;
+    --libmruby-path) echo MRUBY_LIBMRUBY_PATH;;
+    --help) echo "Usage: mruby-config [switches]"
+            echo "  switches:"
+            echo "  --cflags                    print flags passed to compiler"
+            echo "  --ldflags                   print flags passed to linker"
+            echo "  --ldflags-before-libs       print flags passed to linker before linked libraries"
+            echo "  --libs                      print linked libraries"
+            echo "  --libmruby-path             print libmruby path"
+            exit 0;;
+  esac
+  shift
+done
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-config/mruby-config.bat
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-config/mruby-config.bat	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-config/mruby-config.bat	(revision 439)
@@ -0,0 +1,42 @@
+@echo off
+
+:top
+shift
+if "%0" equ "" goto :eof
+if "%0" equ "--cflags" goto cflags
+if "%0" equ "--ldflags" goto ldflags
+if "%0" equ "--ldflags-before-libs" goto ldflagsbeforelibs
+if "%0" equ "--libs" goto libs
+if "%0" equ "--libmruby-path" goto libmrubypath
+if "%0" equ "--help" goto showhelp
+echo Invalid Option
+goto :eof
+
+:cflags
+echo MRUBY_CFLAGS
+goto top
+
+:libs
+echo MRUBY_LIBS
+goto top
+
+:ldflags
+echo MRUBY_LDFLAGS
+goto top
+
+:ldflagsbeforelibs
+echo MRUBY_LDFLAGS_BEFORE_LIBS
+goto top
+
+:libmrubypath
+echo MRUBY_LIBMRUBY_PATH
+goto top
+
+:showhelp
+echo Usage: mruby-config [switches]
+echo   switches:
+echo   --cflags                   print flags passed to compiler
+echo   --ldflags                  print flags passed to linker
+echo   --ldflags-before-libs      print flags passed to linker before linked libraries
+echo   --libs                     print linked libraries
+echo   --libmruby-path            print libmruby path
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/bintest/print.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/bintest/print.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/bintest/print.rb	(revision 439)
@@ -1,8 +1,9 @@
 require 'open3'
 require 'tempfile'
+require 'strscan'
 
 class BinTest_MrubyBinDebugger
-  @debug1=false
-  @debug2=true
+#  @debug1=false
+#  @debug2=true
   def self.test(rubysource, testcase)
     script, bin = Tempfile.new(['test', '.rb']), Tempfile.new(['test', '.mrb'])
@@ -20,8 +21,18 @@
     stdin_data = testcase.map{|t| t[:cmd]}.join("\n") << "\n"
 
+    prompt = /^\(#{Regexp.escape(script.path)}:\d+\) /
     ["bin/mrdb #{script.path}","bin/mrdb -b #{bin.path}"].each do |cmd|
       o, s = Open3.capture2(cmd, :stdin_data => stdin_data)
-
-      exp_vals = testcase.map{|t| t.fetch(:exp, nil)}
+      scanner = StringScanner.new(o)
+      scanner.skip_until(prompt)
+      testcase.each do |tc|
+        exp = tc[:exp]
+        if exp
+          act = scanner.scan_until(/\n/)
+          break unless assert_operator act, :start_with?, exp
+        end
+        scanner.skip_until(prompt)
+      end
+
 =begin
 if @debug1
@@ -42,12 +53,4 @@
       end
 =end
-      idx = 0
-      exp_vals.each do |exp|
-        next if exp.nil?
-        idx = o.index(exp, idx)
-        assert_false idx.nil?
-        break unless idx
-        idx += 1
-      end
     end
   end
@@ -91,6 +94,6 @@
   # test case
   tc = []
-  tc << {:cmd=>"p (1+2",  :exp=>'$1 = SyntaxError'}
-  tc << {:cmd=>"p bar",   :exp=>'$2 = NoMethodError'}
+  tc << {:cmd=>"p (1+2",  :exp=>'$1 = line 1: syntax error'}
+  tc << {:cmd=>"p bar",   :exp=>'$2 = undefined method'}
 
   BinTest_MrubyBinDebugger.test(src, tc)
@@ -318,5 +321,5 @@
 SRC
 
-  # todo: wait for 'break' to be implimented
+  # todo: wait for 'break' to be implemented
   tc = []
   9.times { tc << {:cmd=>"s"} }
@@ -342,11 +345,11 @@
   tc << {:cmd=>"p 0x100",   :exp=>'$4 = 256'}
   tc << {:cmd=>"p 1_234",   :exp=>'$5 = 1234'}
-  tc << {:cmd=>"p 0b1000_0000", :exp=>"$6 = #{0b1000_0000.to_s}"}
-  tc << {:cmd=>"p 0x1000_0000", :exp=>"$7 = #{0x1000_0000.to_s}"}
+  tc << {:cmd=>"p 0b1000_0000", :exp=>"$6 = #{0b1000_0000}"}
+  tc << {:cmd=>"p 0x1000_0000", :exp=>"$7 = #{0x1000_0000}"}
 
   tc << {:cmd=>"p 3.14",    :exp=>'$8 = 3.14'}
   tc << {:cmd=>"p -12.3",   :exp=>'$9 = -12.3'}
-  tc << {:cmd=>"p +12.000", :exp=>'$10 = 12.0'}
-  tc << {:cmd=>"p 1e4",     :exp=>'$11 = 10000.0'}
+  tc << {:cmd=>"p +12.000", :exp=>'$10 = 12'}
+  tc << {:cmd=>"p 1e4",     :exp=>'$11 = 10000'}
   tc << {:cmd=>"p -0.1e-2", :exp=>'$12 = -0.001'}
 
@@ -369,5 +372,5 @@
   tc << {:cmd=>'p "str"',        :exp=>'$1 = "str"'}
   tc << {:cmd=>'p "s\tt\rr\n"',  :exp=>'$2 = "s\\tt\\rr\\n"'}
-  tc << {:cmd=>'p "\C-a\C-z"',   :exp=>'$3 = "\\001\\032"'}
+  tc << {:cmd=>'p "\C-a\C-z"',   :exp=>'$3 = "\\x01\\x1a"'}
   tc << {:cmd=>'p "#{foo+bar}"', :exp=>'$4 = "foobar"'}
 
@@ -375,14 +378,14 @@
   tc << {:cmd=>'p \'s\\tt\\rr\\n\'', :exp=>'$6 = "s\\\\tt\\\\rr\\\\n"'}
   tc << {:cmd=>'p \'\\C-a\\C-z\'',   :exp=>'$7 = "\\\\C-a\\\\C-z"'}
-  tc << {:cmd=>'p \'#{foo+bar}\'',   :exp=>'$8 = "#{foo+bar}"'}
+  tc << {:cmd=>'p \'#{foo+bar}\'',   :exp=>'$8 = "\\#{foo+bar}"'}
 
   tc << {:cmd=>'p %!str!',        :exp=>'$9 = "str"'}
   tc << {:cmd=>'p %!s\tt\rr\n!',  :exp=>'$10 = "s\\tt\\rr\\n"'}
-  tc << {:cmd=>'p %!\C-a\C-z!',   :exp=>'$11 = "\\001\\032"'}
+  tc << {:cmd=>'p %!\C-a\C-z!',   :exp=>'$11 = "\\x01\\x1a"'}
   tc << {:cmd=>'p %!#{foo+bar}!', :exp=>'$12 = "foobar"'}
 
   tc << {:cmd=>'p %Q!str!',        :exp=>'$13 = "str"'}
   tc << {:cmd=>'p %Q!s\tt\rr\n!',  :exp=>'$14 = "s\\tt\\rr\\n"'}
-  tc << {:cmd=>'p %Q!\C-a\C-z!',   :exp=>'$15 = "\\001\\032"'}
+  tc << {:cmd=>'p %Q!\C-a\C-z!',   :exp=>'$15 = "\\x01\\x1a"'}
   tc << {:cmd=>'p %Q!#{foo+bar}!', :exp=>'$16 = "foobar"'}
 
@@ -390,5 +393,5 @@
   tc << {:cmd=>'p %q!s\\tt\\rr\\n!', :exp=>'$18 = "s\\\\tt\\\\rr\\\\n"'}
   tc << {:cmd=>'p %q!\\C-a\\C-z!',   :exp=>'$19 = "\\\\C-a\\\\C-z"'}
-  tc << {:cmd=>'p %q!#{foo+bar}!',   :exp=>'$20 = "#{foo+bar}"'}
+  tc << {:cmd=>'p %q!#{foo+bar}!',   :exp=>'$20 = "\\#{foo+bar}"'}
 
   BinTest_MrubyBinDebugger.test(src, tc)
@@ -411,5 +414,5 @@
   tc << {:cmd=>'p [ 5,  12,   8,    10, ]', :exp=>'$2 = [5, 12, 8, 10]'}
   tc << {:cmd=>'p [1,2.5,"#{foo+bar}"]',    :exp=>'$3 = [1, 2.5, "foobar"]'}
-  tc << {:cmd=>'p %w[3.14 A\ &\ B #{foo}]', :exp=>'$4 = ["3.14", "A & B", "#{foo}"]'}
+  tc << {:cmd=>'p %w[3.14 A\ &\ B #{foo}]', :exp=>'$4 = ["3.14", "A & B", "\#{foo}"]'}
   tc << {:cmd=>'p %W[3.14 A\ &\ B #{foo}]', :exp=>'$5 = ["3.14", "A & B", "foo"]'}
 
@@ -589,5 +592,5 @@
 
   tc << {:cmd=>'p undefined=-1',      :exp=>'$3 = -1'}
-  tc << {:cmd=>'p "#{undefined}"',    :exp=>'$4 = NoMethodError'}
+  tc << {:cmd=>'p "#{undefined}"',    :exp=>'$4 = undefined method'}
 
   BinTest_MrubyBinDebugger.test(src, tc)
@@ -627,5 +630,5 @@
 
   tc << {:cmd=>'p undefined=-1',    :exp=>'$14 = -1'}
-  tc << {:cmd=>'p "#{undefined}"',  :exp=>'$15 = NoMethodError'}
+  tc << {:cmd=>'p "#{undefined}"',  :exp=>'$15 = undefined method'}
 
   BinTest_MrubyBinDebugger.test(src, tc)
@@ -695,7 +698,6 @@
 
   tc << {:cmd=>'p undefined=-1',    :exp=>'$14 = -1'}
-  tc << {:cmd=>'p "#{undefined}"',  :exp=>'$15 = NoMethodError'}
-
-  BinTest_MrubyBinDebugger.test(src, tc)
-end
-
+  tc << {:cmd=>'p "#{undefined}"',  :exp=>'$15 = undefined method'}
+
+  BinTest_MrubyBinDebugger.test(src, tc)
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c	(revision 439)
@@ -85,5 +85,5 @@
 
 static uint16_t
-check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno)
+check_file_lineno(mrb_state *mrb, struct mrb_irep *irep, const char *file, uint16_t lineno)
 {
   mrb_irep_debug_info_file *info_file;
@@ -94,6 +94,8 @@
 
   for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+    const char *filename;
     info_file = irep->debug_info->files[f_idx];
-    if (!strcmp(info_file->filename, file)) {
+    filename = mrb_sym_name_len(mrb, info_file->filename_sym, NULL);
+    if (!strcmp(filename, file)) {
       result = MRB_DEBUG_BP_FILE_OK;
 
@@ -104,5 +106,5 @@
     }
     for (i=0; i < irep->rlen; ++i) {
-      result  |= check_file_lineno(irep->reps[i], file, lineno);
+      result  |= check_file_lineno(mrb, irep->reps[i], file, lineno);
       if (result == (MRB_DEBUG_BP_FILE_OK | MRB_DEBUG_BP_LINENO_OK)) {
         return result;
@@ -113,15 +115,4 @@
 }
 
-static const char*
-get_class_name(mrb_state *mrb, struct RClass *class_obj)
-{
-  struct RClass *outer;
-  mrb_sym class_sym;
-
-  outer = mrb_class_outer_module(mrb, class_obj);
-  class_sym = mrb_class_sym(mrb, class_obj, outer);
-  return mrb_sym2name(mrb, class_sym);
-}
-
 static int32_t
 compare_break_method(mrb_state *mrb, mrb_debug_breakpoint *bp, struct RClass *class_obj, mrb_sym method_sym, mrb_bool* isCfunc)
@@ -129,5 +120,5 @@
   const char* class_name;
   const char* method_name;
-  struct RProc* m;
+  mrb_method_t m;
   struct RClass* sc;
   const char* sn;
@@ -136,9 +127,9 @@
   mrb_bool is_defined;
 
-  method_name = mrb_sym2name(mrb, method_sym);
+  method_name = mrb_sym_name(mrb, method_sym);
 
   method_p = &bp->point.methodpoint;
   if (strcmp(method_p->method_name, method_name) == 0) {
-    class_name = get_class_name(mrb, class_obj);
+    class_name = mrb_class_name(mrb, class_obj);
     if (class_name == NULL) {
       if (method_p->class_name == NULL) {
@@ -148,8 +139,8 @@
     else if (method_p->class_name != NULL) {
       m = mrb_method_search_vm(mrb, &class_obj, method_sym);
-      if (m == NULL) {
+      if (MRB_METHOD_UNDEF_P(m)) {
         return MRB_DEBUG_OK;
       }
-      if (MRB_PROC_CFUNC_P(m)) {
+      if (MRB_METHOD_CFUNC_P(m)) {
         *isCfunc = TRUE;
       }
@@ -163,10 +154,10 @@
       ssym = mrb_symbol(mrb_check_intern_cstr(mrb, method_p->method_name));
       m = mrb_method_search_vm(mrb, &sc, ssym);
-      if (m == NULL) {
+      if (MRB_METHOD_UNDEF_P(m)) {
         return MRB_DEBUG_OK;
       }
 
-      class_name = get_class_name(mrb, class_obj);
-      sn = get_class_name(mrb, sc);
+      class_name = mrb_class_name(mrb, class_obj);
+      sn = mrb_class_name(mrb, sc);
       if (strcmp(sn, class_name) == 0) {
         return bp->bpno;
@@ -197,5 +188,5 @@
 
   /* file and lineno check (line type mrb_debug_line_ary only.) */
-  result = check_file_lineno(dbg->root_irep, file, lineno);
+  result = check_file_lineno(mrb, dbg->root_irep, file, lineno);
   if (result == 0) {
     return MRB_DEBUG_BREAK_INVALID_FILE;
@@ -205,5 +196,5 @@
   }
 
-  set_file = mrb_malloc(mrb, strlen(file) + 1);
+  set_file = (char*)mrb_malloc(mrb, strlen(file) + 1);
 
   index = dbg->bpnum;
@@ -242,5 +233,5 @@
 
   if (class_name != NULL) {
-    set_class = mrb_malloc(mrb, strlen(class_name) + 1);
+    set_class = (char*)mrb_malloc(mrb, strlen(class_name) + 1);
     strncpy(set_class, class_name, strlen(class_name) + 1);
   }
@@ -249,5 +240,5 @@
   }
 
-  set_method = mrb_malloc(mrb, strlen(method_name) + 1);
+  set_method = (char*)mrb_malloc(mrb, strlen(method_name) + 1);
 
   strncpy(set_method, method_name, strlen(method_name) + 1);
@@ -438,8 +429,8 @@
 
 static mrb_bool
-check_start_pc_for_line(mrb_irep *irep, mrb_code *pc, uint16_t line)
+check_start_pc_for_line(mrb_state *mrb, mrb_irep *irep, const mrb_code *pc, uint16_t line)
 {
   if (pc > irep->iseq) {
-    if (line == mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq - 1))) {
+    if (line == mrb_debug_get_line(mrb, irep, pc - irep->iseq - 1)) {
       return FALSE;
     }
@@ -459,5 +450,5 @@
   }
 
-  if (!check_start_pc_for_line(dbg->irep, dbg->pc, line)) {
+  if (!check_start_pc_for_line(mrb, dbg->irep, dbg->pc, line)) {
     return MRB_DEBUG_OK;
   }
@@ -515,4 +506,2 @@
   return 0;
 }
-
-
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c	(revision 439)
@@ -49,5 +49,5 @@
   }
 
-  path = mrb_malloc(mrb, len);
+  path = (char*)mrb_malloc(mrb, len);
   memset(path, 0, len);
 
@@ -65,5 +65,6 @@
 {
   size_t len;
-  char *p, *dir;
+  const char *p;
+  char *dir;
 
   if (path == NULL) {
@@ -74,5 +75,5 @@
   len = p != NULL ? (size_t)(p - path) : strlen(path);
 
-  dir = mrb_malloc(mrb, len + 1);
+  dir = (char*)mrb_malloc(mrb, len + 1);
   strncpy(dir, path, len);
   dir[len] = '\0';
@@ -84,7 +85,7 @@
 source_file_new(mrb_state *mrb, mrb_debug_context *dbg, char *filename)
 {
-  source_file *file = NULL;
-
-  file = mrb_malloc(mrb, sizeof(source_file));
+  source_file *file;
+
+  file = (source_file*)mrb_malloc(mrb, sizeof(source_file));
 
   memset(file, '\0', sizeof(source_file));
@@ -97,5 +98,5 @@
 
   file->lineno = 1;
-  file->path = mrb_malloc(mrb, strlen(filename) + 1);
+  file->path = (char*)mrb_malloc(mrb, strlen(filename) + 1);
   strcpy(file->path, filename);
   return file;
@@ -175,7 +176,11 @@
   const char *search_path[3];
   char *path = NULL;
+  const char *srcname = strrchr(filename, '/');
+
+  if (srcname) srcname++;
+  else srcname = filename;
 
   search_path[0] = srcpath;
-  search_path[1] = dirname(mrb, mrb_debug_get_filename(mrdb->dbg->root_irep, 0));
+  search_path[1] = dirname(mrb, mrb_debug_get_filename(mrb, mrdb->dbg->irep, 0));
   search_path[2] = ".";
 
@@ -185,5 +190,5 @@
     }
 
-    if ((path = build_path(mrb, search_path[i], filename)) == NULL) {
+    if ((path = build_path(mrb, search_path[i], srcname)) == NULL) {
       continue;
     }
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c	(revision 439)
@@ -22,5 +22,5 @@
   c->no_exec = TRUE;
   c->capture_errors = TRUE;
-  c->filename = (char*)dbg->prvfile;
+  mrbc_filename(mrb, c, (const char*)dbg->prvfile);
   c->lineno = dbg->prvline;
 
@@ -32,7 +32,7 @@
 
 mrb_value
-mrb_debug_eval(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t len, mrb_bool *exc)
+mrb_debug_eval(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t len, mrb_bool *exc, int direct_eval)
 {
-  void (*tmp)(struct mrb_state *, struct mrb_irep *, mrb_code *, mrb_value *);
+  void (*tmp)(struct mrb_state *, struct mrb_irep *, const mrb_code *, mrb_value *);
   mrb_value ruby_code;
   mrb_value s;
@@ -48,4 +48,9 @@
     v = mrb_obj_value(mrb->exc);
     mrb->exc = 0;
+  }
+  else if (direct_eval) {
+    recv = dbg->regs[0];
+
+    v = mrb_funcall(mrb, recv, expr, 0);
   }
   else {
@@ -70,5 +75,5 @@
   }
 
-  s = mrb_funcall(mrb, v, "inspect", 0);
+  s = mrb_inspect(mrb, v);
 
   /* enable code_fetch_hook */
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h	(revision 439)
@@ -9,5 +9,5 @@
 #include "mrdb.h"
 
-mrb_value mrb_debug_eval(mrb_state*, mrb_debug_context*, const char*, size_t, mrb_bool*);
+mrb_value mrb_debug_eval(mrb_state*, mrb_debug_context*, const char*, size_t, mrb_bool*, int);
 
 #endif /* APIPRINT_H_ */
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c	(revision 439)
@@ -243,5 +243,5 @@
 
 mrb_debug_bptype
-parse_breakcommand(mrdb_state *mrdb, const char **file, uint32_t *line, char **cname, char **method)
+parse_breakcommand(mrb_state *mrb, mrdb_state *mrdb, const char **file, uint32_t *line, char **cname, char **method)
 {
   mrb_debug_context *dbg = mrdb->dbg;
@@ -275,5 +275,5 @@
       if (l <= 65535) {
         *line = l;
-        *file = (body == args)? mrb_debug_get_filename(dbg->irep, (uint32_t)(dbg->pc - dbg->irep->iseq)): args;
+        *file = (body == args)? mrb_debug_get_filename(mrb, dbg->irep, dbg->pc - dbg->irep->iseq): args;
       }
       else {
@@ -333,5 +333,5 @@
   int32_t ret;
 
-  type = parse_breakcommand(mrdb, &file, &line, &cname, &method);
+  type = parse_breakcommand(mrb, mrdb, &file, &line, &cname, &method);
   switch (type) {
     case MRB_DEBUG_BPTYPE_LINE:
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c	(revision 439)
@@ -81,4 +81,10 @@
     "Status of specified breakpoints (all user-settable breakpoints if no argument).\n"
     "Arguments are breakpoint numbers with spaces in between.\n"
+  },
+  {
+    "i[nfo]", "l[ocals]", "Print name of local variables",
+    "Usage: info locals\n"
+    "\n"
+    "Print name of local variables.\n"
   },
   {
@@ -134,5 +140,5 @@
 listcmd_parser_state_new(mrb_state *mrb)
 {
-  listcmd_parser_state *st = mrb_malloc(mrb, sizeof(listcmd_parser_state));
+  listcmd_parser_state *st = (listcmd_parser_state*)mrb_malloc(mrb, sizeof(listcmd_parser_state));
   memset(st, 0, sizeof(listcmd_parser_state));
   return st;
@@ -228,5 +234,5 @@
 
   if (len > 0) {
-    st->filename = mrb_malloc(mrb, len + 1);
+    st->filename = (char*)mrb_malloc(mrb, len + 1);
     strncpy(st->filename, *sp, len);
     st->filename[len] = '\0';
@@ -243,5 +249,6 @@
 {
   size_t len;
-  char *p, *s;
+  const char *p;
+  char *s;
 
   if (filename == NULL) {
@@ -256,5 +263,5 @@
   }
 
-  s = mrb_malloc(mrb, len + strlen(ext) + 1);
+  s = (char*)mrb_malloc(mrb, len + strlen(ext) + 1);
   memset(s, '\0', len + strlen(ext) + 1);
   strncpy(s, filename, len);
@@ -326,5 +333,5 @@
 check_cmd_pattern(const char *pattern, const char *cmd)
 {
-  char *lbracket, *rbracket, *p, *q;
+  const char *lbracket, *rbracket, *p, *q;
 
   if (pattern == NULL && cmd == NULL) {
@@ -495,5 +502,5 @@
   if (mrdb->dbg->xm == DBG_QUIT) {
     struct RClass *exc;
-    exc = mrb_define_class(mrb, "DebuggerExit", mrb_class_get(mrb, "Exception"));
+    exc = mrb_define_class(mrb, "DebuggerExit", mrb->eException_class);
     mrb_raise(mrb, exc, "Exit mrdb.");
   }
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c	(revision 439)
@@ -19,5 +19,4 @@
   mrb_value expr;
   mrb_value result;
-  mrb_value s;
   uint8_t wcnt;
   int ai;
@@ -37,9 +36,10 @@
   }
 
-  result = mrb_debug_eval(mrb, mrdb->dbg, RSTRING_PTR(expr), RSTRING_LEN(expr), NULL);
+  result = mrb_debug_eval(mrb, mrdb->dbg, RSTRING_PTR(expr), RSTRING_LEN(expr), NULL, 0);
 
   /* $print_no = result */
-  s = mrb_str_cat_lit(mrb, result, "\0");
-  printf("$%lu = %s\n", (unsigned long)mrdb->print_no++, RSTRING_PTR(s));
+  printf("$%lu = ", (unsigned long)mrdb->print_no++);
+  fwrite(RSTRING_PTR(result), RSTRING_LEN(result), 1, stdout);
+  putc('\n', stdout);
 
   if (mrdb->print_no == 0) {
@@ -57,2 +57,25 @@
   return dbgcmd_print(mrb, mrdb);
 }
+
+dbgcmd_state
+dbgcmd_info_local(mrb_state *mrb, mrdb_state *mrdb)
+{
+  mrb_value result;
+  mrb_value s;
+  int ai;
+
+  ai = mrb_gc_arena_save(mrb);
+
+  result = mrb_debug_eval(mrb, mrdb->dbg, "local_variables", 0, NULL, 1);
+
+  s = mrb_str_cat_lit(mrb, result, "\0");
+  printf("$%lu = %s\n", (unsigned long)mrdb->print_no++, RSTRING_PTR(s));
+
+  if (mrdb->print_no == 0) {
+    mrdb->print_no = 1;
+  }
+
+  mrb_gc_arena_restore(mrb, ai);
+
+  return DBGST_PROMPT;
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c	(revision 439)
@@ -20,5 +20,5 @@
       struct RClass *exc;
       puts("Start it from the beginning.");
-      exc = mrb_define_class(mrb, "DebuggerRestart", mrb_class_get(mrb, "Exception"));
+      exc = mrb_define_class(mrb, "DebuggerRestart", mrb->eException_class);
       mrb_raise(mrb, exc, "Restart mrdb.");
     }
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c	(revision 439)
@@ -6,5 +6,4 @@
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
 #include <ctype.h>
 
@@ -53,4 +52,5 @@
   {"help",      NULL,           1, 0, 1, DBGCMD_HELP,           dbgcmd_help},            /* h[elp] */
   {"info",      "breakpoints",  1, 1, 1, DBGCMD_INFO_BREAK,     dbgcmd_info_break},      /* i[nfo] b[reakpoints] */
+  {"info",      "locals",       1, 1, 0, DBGCMD_INFO_LOCAL,     dbgcmd_info_local},      /* i[nfo] l[ocals] */
   {"list",      NULL,           1, 0, 1, DBGCMD_LIST,           dbgcmd_list},            /* l[ist] */
   {"print",     NULL,           1, 0, 0, DBGCMD_PRINT,          dbgcmd_print},           /* p[rint] */
@@ -185,5 +185,5 @@
 mrb_debug_context_new(mrb_state *mrb)
 {
-  mrb_debug_context *dbg = mrb_malloc(mrb, sizeof(mrb_debug_context));
+  mrb_debug_context *dbg = (mrb_debug_context*)mrb_malloc(mrb, sizeof(mrb_debug_context));
 
   memset(dbg, 0, sizeof(mrb_debug_context));
@@ -224,10 +224,10 @@
 mrdb_state_new(mrb_state *mrb)
 {
-  mrdb_state *mrdb = mrb_malloc(mrb, sizeof(mrdb_state));
+  mrdb_state *mrdb = (mrdb_state*)mrb_malloc(mrb, sizeof(mrdb_state));
 
   memset(mrdb, 0, sizeof(mrdb_state));
 
   mrdb->dbg = mrb_debug_context_get(mrb);
-  mrdb->command = mrb_malloc(mrb, MAX_COMMAND_LINE+1);
+  mrdb->command = (char*)mrb_malloc(mrb, MAX_COMMAND_LINE+1);
   mrdb->print_no = 1;
 
@@ -505,5 +505,5 @@
 
 static int32_t
-check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *regs)
+check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, const mrb_code *pc, mrb_value *regs)
 {
   struct RClass* c;
@@ -511,4 +511,5 @@
   int32_t bpno;
   mrb_bool isCfunc;
+  struct mrb_insn_data insn;
 
   mrb_debug_context *dbg = mrb_debug_context_get(mrb);
@@ -518,9 +519,10 @@
   dbg->method_bpno = 0;
 
-  switch(GET_OPCODE(*pc)) {
+  insn = mrb_decode_insn(pc);
+  switch(insn.insn) {
     case OP_SEND:
     case OP_SENDB:
-      c = mrb_class(mrb, regs[GETARG_A(*pc)]);
-      sym = irep->syms[GETARG_B(*pc)];
+      c = mrb_class(mrb, regs[insn.a]);
+      sym = irep->syms[insn.b];
       break;
     case OP_SUPER:
@@ -544,5 +546,5 @@
 
 static void
-mrb_code_fetch_hook(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *regs)
+mrb_code_fetch_hook(mrb_state *mrb, mrb_irep *irep, const mrb_code *pc, mrb_value *regs)
 {
   const char *file;
@@ -567,6 +569,6 @@
   }
 
-  file = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq));
-  line = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq));
+  file = mrb_debug_get_filename(mrb, irep, pc - irep->iseq);
+  line = mrb_debug_get_line(mrb, irep, pc - irep->iseq);
 
   switch (dbg->xm) {
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h	(revision 439)
@@ -24,4 +24,5 @@
   DBGCMD_BREAK,
   DBGCMD_INFO_BREAK,
+  DBGCMD_INFO_LOCAL,
   DBGCMD_WATCH,
   DBGCMD_INFO_WATCH,
@@ -105,5 +106,5 @@
   struct mrb_irep *root_irep;
   struct mrb_irep *irep;
-  mrb_code *pc;
+  const mrb_code *pc;
   mrb_value *regs;
 
@@ -152,4 +153,5 @@
 dbgcmd_state dbgcmd_break(mrb_state*, mrdb_state*);
 dbgcmd_state dbgcmd_info_break(mrb_state*, mrdb_state*);
+dbgcmd_state dbgcmd_info_local(mrb_state*, mrdb_state*);
 dbgcmd_state dbgcmd_delete(mrb_state*, mrdb_state*);
 dbgcmd_state dbgcmd_enable(mrb_state*, mrdb_state*);
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h	(revision 439)
@@ -6,4 +6,12 @@
 #ifndef MRDBCONF_H
 #define MRDBCONF_H
+
+#ifndef MRB_ENABLE_DEBUG_HOOK
+# error mruby-bin-debugger need 'MRB_ENABLE_DEBUG_HOOK' configuration in your 'build_config.rb'
+#endif
+
+#ifdef MRB_DISABLE_STDIO
+# error mruby-bin-debugger conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
+#endif
 
 /* configuration options: */
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mirb/bintest/mirb.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-mirb/bintest/mirb.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mirb/bintest/mirb.rb	(revision 439)
@@ -11,2 +11,24 @@
   assert_true o.include?('=> 3')
 end
+
+assert('mirb -d option') do
+  o, _ = Open3.capture2('bin/mirb', :stdin_data => "$DEBUG\n")
+  assert_true o.include?('=> false')
+  o, _ = Open3.capture2('bin/mirb -d', :stdin_data => "$DEBUG\n")
+  assert_true o.include?('=> true')
+end
+
+assert('mirb -r option') do
+  lib = Tempfile.new('lib.rb')
+  lib.write <<EOS
+class Hoge
+  def hoge
+    :hoge
+  end
+end
+EOS
+  lib.flush
+
+  o, _ = Open3.capture2("bin/mirb -r #{lib.path}", :stdin_data => "Hoge.new.hoge\n")
+  assert_true o.include?('=> :hoge')
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c	(revision 439)
@@ -7,7 +7,20 @@
 */
 
+#include <mruby.h>
+
+#ifdef MRB_DISABLE_STDIO
+# error mruby-bin-mirb conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
+#endif
+
+#include <mruby/array.h>
+#include <mruby/proc.h>
+#include <mruby/compile.h>
+#include <mruby/dump.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/throw.h>
+
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
 #include <ctype.h>
 
@@ -20,4 +33,10 @@
 #define MIRB_ADD_HISTORY(line) add_history(line)
 #define MIRB_READLINE(ch) readline(ch)
+#if !defined(RL_READLINE_VERSION) || RL_READLINE_VERSION < 0x600
+/* libedit & older readline do not have rl_free() */
+#define MIRB_LINE_FREE(line) free(line)
+#else
+#define MIRB_LINE_FREE(line) rl_free(line)
+#endif
 #define MIRB_WRITE_HISTORY(path) write_history(path)
 #define MIRB_READ_HISTORY(path) read_history(path)
@@ -28,4 +47,5 @@
 #define MIRB_ADD_HISTORY(line) linenoiseHistoryAdd(line)
 #define MIRB_READLINE(ch) linenoise(ch)
+#define MIRB_LINE_FREE(line) linenoiseFree(line)
 #define MIRB_WRITE_HISTORY(path) linenoiseHistorySave(path)
 #define MIRB_READ_HISTORY(path) linenoiseHistoryLoad(history_path)
@@ -42,10 +62,4 @@
 #define SIGJMP_BUF jmp_buf
 #endif
-
-#include <mruby.h>
-#include <mruby/array.h>
-#include <mruby/proc.h>
-#include <mruby/compile.h>
-#include <mruby/string.h>
 
 #ifdef ENABLE_READLINE
@@ -89,4 +103,5 @@
 {
   mrb_value val;
+  char* msg;
 
   val = mrb_funcall(mrb, obj, "inspect", 0);
@@ -102,5 +117,7 @@
     val = mrb_obj_as_string(mrb, obj);
   }
-  fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout);
+  msg = mrb_locale_from_utf8(RSTRING_PTR(val), (int)RSTRING_LEN(val));
+  fwrite(msg, strlen(msg), 1, stdout);
+  mrb_locale_free(msg);
   putc('\n', stdout);
 }
@@ -115,8 +132,4 @@
   /* check for heredoc */
   if (parser->parsing_heredoc != NULL) return TRUE;
-  if (parser->heredoc_end_now) {
-    parser->heredoc_end_now = FALSE;
-    return FALSE;
-  }
 
   /* check for unterminated string */
@@ -210,6 +223,9 @@
   FILE *rfp;
   mrb_bool verbose      : 1;
+  mrb_bool debug        : 1;
   int argc;
   char** argv;
+  int libc;
+  char **libv;
 };
 
@@ -219,4 +235,6 @@
   static const char *const usage_msg[] = {
   "switches:",
+  "-d           set $DEBUG to true (same as `mruby -d`)",
+  "-r library   same as `mruby -r`",
   "-v           print version number, then run in verbose mode",
   "--verbose    run in verbose mode",
@@ -227,12 +245,22 @@
   const char *const *p = usage_msg;
 
-  printf("Usage: %s [switches]\n", name);
+  printf("Usage: %s [switches] [programfile] [arguments]\n", name);
   while (*p)
     printf("  %s\n", *p++);
 }
 
+static char *
+dup_arg_item(mrb_state *mrb, const char *item)
+{
+  size_t buflen = strlen(item) + 1;
+  char *buf = (char*)mrb_malloc(mrb, buflen);
+  memcpy(buf, item, buflen);
+  return buf;
+}
+
 static int
 parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
 {
+  char **origargv = argv;
   static const struct _args args_zero = { 0 };
 
@@ -245,4 +273,24 @@
     item = argv[0] + 1;
     switch (*item++) {
+    case 'd':
+      args->debug = TRUE;
+      break;
+    case 'r':
+      if (!item[0]) {
+        if (argc <= 1) {
+          printf("%s: No library specified for -r\n", *origargv);
+          return EXIT_FAILURE;
+        }
+        argc--; argv++;
+        item = argv[0];
+      }
+      if (args->libc == 0) {
+        args->libv = (char**)mrb_malloc(mrb, sizeof(char*));
+      }
+      else {
+        args->libv = (char**)mrb_realloc(mrb, args->libv, sizeof(char*) * (args->libc + 1));
+      }
+      args->libv[args->libc++] = dup_arg_item(mrb, item);
+      break;
     case 'v':
       if (!args->verbose) mrb_show_version(mrb);
@@ -290,4 +338,10 @@
     fclose(args->rfp);
   mrb_free(mrb, args->argv);
+  if (args->libc) {
+    while (args->libc--) {
+      mrb_free(mrb, args->libv[args->libc]);
+    }
+    mrb_free(mrb, args->libv);
+  }
   mrb_close(mrb);
 }
@@ -324,5 +378,5 @@
 
   /* skip preceding spaces */
-  while (*p && isspace((unsigned char)*p)) {
+  while (*p && ISSPACE(*p)) {
     p++;
   }
@@ -334,5 +388,5 @@
   /* skip trailing spaces */
   while (*p) {
-    if (!isspace((unsigned char)*p)) return 0;
+    if (!ISSPACE(*p)) return 0;
     p++;
   }
@@ -354,4 +408,24 @@
 {
   MIRB_SIGLONGJMP(ctrl_c_buf, 1);
+}
+#endif
+
+#ifndef DISABLE_MIRB_UNDERSCORE
+void decl_lv_underscore(mrb_state *mrb, mrbc_context *cxt)
+{
+  struct RProc *proc;
+  struct mrb_parser_state *parser;
+
+  parser = mrb_parse_string(mrb, "_=nil", cxt);
+  if (parser == NULL) {
+    fputs("create parser state error\n", stderr);
+    mrb_close(mrb);
+    exit(EXIT_FAILURE);
+  }
+
+  proc = mrb_generate_code(mrb, parser);
+  mrb_vm_run(mrb, proc, mrb_top_self(mrb), 0);
+
+  mrb_parser_free(parser);
 }
 #endif
@@ -404,4 +478,5 @@
   }
   mrb_define_global_const(mrb, "ARGV", ARGV);
+  mrb_gv_set(mrb, mrb_intern_lit(mrb, "$DEBUG"), mrb_bool_value(args.debug));
 
 #ifdef ENABLE_READLINE
@@ -420,4 +495,21 @@
 
   cxt = mrbc_context_new(mrb);
+
+#ifndef DISABLE_MIRB_UNDERSCORE
+  decl_lv_underscore(mrb, cxt);
+#endif
+
+  /* Load libraries */
+  for (i = 0; i < args.libc; i++) {
+    FILE *lfp = fopen(args.libv[i], "r");
+    if (lfp == NULL) {
+      printf("Cannot open library file. (%s)\n", args.libv[i]);
+      cleanup(mrb, &args);
+      return EXIT_FAILURE;
+    }
+    mrb_load_file_cxt(mrb, lfp, cxt);
+    fclose(lfp);
+  }
+
   cxt->capture_errors = TRUE;
   cxt->lineno = 1;
@@ -429,5 +521,8 @@
   while (TRUE) {
     char *utf8;
-
+    struct mrb_jmpbuf c_jmp;
+
+    MRB_TRY(&c_jmp);
+    mrb->jmp = &c_jmp;
     if (args.rfp) {
       if (fgets(last_code_line, sizeof(last_code_line)-1, args.rfp) != NULL)
@@ -490,9 +585,8 @@
     strcat(last_code_line, "\n");
     MIRB_ADD_HISTORY(line);
-    free(line);
-#endif
-
-done:
-
+    MIRB_LINE_FREE(line);
+#endif
+
+  done:
     if (code_block_open) {
       if (strlen(ruby_code)+strlen(last_code_line) > sizeof(ruby_code)-1) {
@@ -529,7 +623,15 @@
     }
     else {
+      if (0 < parser->nwarn) {
+        /* warning */
+        char* msg = mrb_locale_from_utf8(parser->warn_buffer[0].message, -1);
+        printf("line %d: %s\n", parser->warn_buffer[0].lineno, msg);
+        mrb_locale_free(msg);
+      }
       if (0 < parser->nerr) {
         /* syntax error */
-        printf("line %d: %s\n", parser->error_buffer[0].lineno, parser->error_buffer[0].message);
+        char* msg = mrb_locale_from_utf8(parser->error_buffer[0].message, -1);
+        printf("line %d: %s\n", parser->error_buffer[0].lineno, msg);
+        mrb_locale_free(msg);
       }
       else {
@@ -544,4 +646,11 @@
         if (args.verbose) {
           mrb_codedump_all(mrb, proc);
+        }
+        /* adjust stack length of toplevel environment */
+        if (mrb->c->cibase->env) {
+          struct REnv *e = mrb->c->cibase->env;
+          if (e && MRB_ENV_STACK_LEN(e) < proc->body.irep->nlocals) {
+            MRB_ENV_SET_STACK_LEN(e, proc->body.irep->nlocals);
+          }
         }
         /* pass a proc for evaluation */
@@ -563,4 +672,7 @@
           }
           p(mrb, result, 1);
+#ifndef DISABLE_MIRB_UNDERSCORE
+          *(mrb->c->stack + 1) = result;
+#endif
         }
       }
@@ -571,4 +683,9 @@
     mrb_parser_free(parser);
     cxt->lineno++;
+    MRB_CATCH(&c_jmp) {
+      p(mrb, mrb_obj_value(mrb->exc), 0);
+      mrb->exc = 0;
+    }
+    MRB_END_EXC(&c_jmp);
   }
 
@@ -578,4 +695,12 @@
 #endif
 
+  if (args.rfp) fclose(args.rfp);
+  mrb_free(mrb, args.argv);
+  if (args.libv) {
+    for (i = 0; i < args.libc; ++i) {
+      mrb_free(mrb, args.libv[i]);
+    }
+    mrb_free(mrb, args.libv);
+  }
   mrbc_context_free(mrb, cxt);
   mrb_close(mrb);
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mrbc/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-mrbc/mrbgem.rake	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mrbc/mrbgem.rake	(revision 439)
@@ -9,5 +9,5 @@
   mrbc_objs = Dir.glob("#{spec.dir}/tools/mrbc/*.c").map { |f| objfile(f.pathmap("#{spec.build_dir}/tools/mrbc/%n")) }.flatten
 
-  file exec => mrbc_objs + [libfile("#{build.build_dir}/lib/libmruby_core")] do |t|
+  file exec => mrbc_objs + [build.libmruby_core_static] do |t|
     build.linker.run t.name, t.prerequisites
   end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c	(revision 439)
@@ -1,6 +1,10 @@
-#include <stdio.h>
+#include <mruby.h>
+
+#ifdef MRB_DISABLE_STDIO
+# error mruby-bin-mrbc conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
+#endif
+
 #include <stdlib.h>
 #include <string.h>
-#include <mruby.h>
 #include <mruby/compile.h>
 #include <mruby/dump.h>
@@ -19,4 +23,5 @@
   mrb_bool check_syntax : 1;
   mrb_bool verbose      : 1;
+  mrb_bool remove_lv    : 1;
   unsigned int flags    : 4;
 };
@@ -34,4 +39,5 @@
   "-e           generate little endian iseq data",
   "-E           generate big endian iseq data",
+  "--remove-lv  remove local variables",
   "--verbose    run at verbose mode",
   "--version    print the version",
@@ -70,5 +76,4 @@
 parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args)
 {
-  char *outfile = NULL;
   static const struct mrbc_args args_zero = { 0 };
   int i;
@@ -85,5 +90,5 @@
         if (args->outfile) {
           fprintf(stderr, "%s: an output file is already specified. (%s)\n",
-                  args->prog, outfile);
+                  args->prog, args->outfile);
           return -1;
         }
@@ -143,4 +148,8 @@
           exit(EXIT_SUCCESS);
         }
+        else if (strcmp(argv[i] + 2, "remove-lv") == 0) {
+          args->remove_lv = TRUE;
+          break;
+        }
         return -1;
       default:
@@ -179,5 +188,5 @@
   }
   fn = args->argv[args->idx++];
-  p->f = fopen(fn, "r");
+  p->f = fopen(fn, "rb");
   if (p->f == NULL) {
     fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, fn);
@@ -206,5 +215,5 @@
   else {
     need_close = TRUE;
-    if ((infile = fopen(input, "r")) == NULL) {
+    if ((infile = fopen(input, "rb")) == NULL) {
       fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, input);
       return mrb_nil_value();
@@ -233,4 +242,7 @@
   mrb_irep *irep = proc->body.irep;
 
+  if (args->remove_lv) {
+    mrb_irep_remove_lv(mrb, irep);
+  }
   if (args->initname) {
     n = mrb_dump_irep_cfunc(mrb, irep, args->flags, wfp, args->initname);
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mruby/bintest/mruby.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-mruby/bintest/mruby.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mruby/bintest/mruby.rb	(revision 439)
@@ -1,9 +1,17 @@
 require 'tempfile'
+require 'open3'
+
+def assert_mruby(exp_out, exp_err, exp_success, args)
+  out, err, stat = Open3.capture3(cmd("mruby"), *args)
+  assert "assert_mruby" do
+    assert_operator(exp_out, :===, out, "standard output")
+    assert_operator(exp_err, :===, err, "standard error")
+    assert_equal(exp_success, stat.success?, "exit success?")
+  end
+end
 
 assert('regression for #1564') do
-  o = `#{cmd('mruby')} -e #{shellquote('<<')} 2>&1`
-  assert_include o, "-e:1:2: syntax error"
-  o = `#{cmd('mruby')} -e #{shellquote('<<-')} 2>&1`
-  assert_include o, "-e:1:3: syntax error"
+  assert_mruby("", /\A-e:1:2: syntax error, .*\n\z/, false, %w[-e <<])
+  assert_mruby("", /\A-e:1:3: syntax error, .*\n\z/, false, %w[-e <<-])
 end
 
@@ -13,5 +21,5 @@
   system "#{cmd('mrbc')} -g -o #{bin.path} #{script.path}"
   o = `#{cmd('mruby')} -b #{bin.path}`.strip
-  assert_equal o, '"ok"'
+  assert_equal '"ok"', o
 end
 
@@ -30,4 +38,16 @@
   # one liner
   assert_equal '"-e"', `#{cmd('mruby')} -e #{shellquote('p $0')}`.chomp
+end
+
+assert 'ARGV value' do
+  assert_mruby(%{["ab", "cde"]\n}, "", true, %w[-e p(ARGV) ab cde])
+  assert_mruby("[]\n", "", true, %w[-e p(ARGV)])
+end
+
+assert('float literal') do
+  script, bin = Tempfile.new('test.rb'), Tempfile.new('test.mrb')
+  File.write script.path, 'p [3.21, 2e308.infinite?, -2e308.infinite?]'
+  system "#{cmd('mrbc')} -g -o #{bin.path} #{script.path}"
+  assert_equal "[3.21, 1, -1]", `#{cmd('mruby')} -b #{bin.path}`.chomp!
 end
 
@@ -59,2 +79,86 @@
   assert_equal 0, $?.exitstatus
 end
+
+assert('mruby -c option') do
+  assert_mruby("Syntax OK\n", "", true, ["-c", "-e", "p 1"])
+  assert_mruby("", /\A-e:1:7: syntax error, .*\n\z/, false, ["-c", "-e", "p 1; 1."])
+end
+
+assert('mruby -d option') do
+  assert_mruby("false\n", "", true, ["-e", "p $DEBUG"])
+  assert_mruby("true\n", "", true, ["-dep $DEBUG"])
+end
+
+assert('mruby -e option (no code specified)') do
+  assert_mruby("", /\A.*: No code specified for -e\n\z/, false, %w[-e])
+end
+
+assert('mruby -h option') do
+  assert_mruby(/\AUsage: #{Regexp.escape cmd("mruby")} .*/m, "", true, %w[-h])
+end
+
+assert('mruby -r option') do
+  lib = Tempfile.new('lib.rb')
+  lib.write <<EOS
+class Hoge
+  def hoge
+    :hoge
+  end
+end
+EOS
+  lib.flush
+
+  script = Tempfile.new('test.rb')
+  script.write <<EOS
+print Hoge.new.hoge
+EOS
+  script.flush
+  assert_equal 'hoge', `#{cmd('mruby')} -r #{lib.path} #{script.path}`
+  assert_equal 0, $?.exitstatus
+
+  assert_equal 'hogeClass', `#{cmd('mruby')} -r #{lib.path} -r #{script.path} -e #{shellquote('print Hoge.class')}`
+  assert_equal 0, $?.exitstatus
+end
+
+assert('mruby -r option (no library specified)') do
+  assert_mruby("", /\A.*: No library specified for -r\n\z/, false, %w[-r])
+end
+
+assert('mruby -r option (file not found)') do
+  assert_mruby("", /\A.*: Cannot open library file: .*\n\z/, false, %w[-r _no_exists_])
+end
+
+assert('mruby -v option') do
+  ver_re = '\Amruby \d+\.\d+\.\d+ \(\d+-\d+-\d+\)\n'
+  assert_mruby(/#{ver_re}\z/, "", true, %w[-v])
+  assert_mruby(/#{ver_re}^[^\n]*NODE.*\n:end\n\z/m, "", true, %w[-v -e p(:end)])
+end
+
+assert('mruby --verbose option') do
+  assert_mruby(/\A[^\n]*NODE.*\n:end\n\z/m, "", true, %w[--verbose -e p(:end)])
+end
+
+assert('mruby --') do
+  assert_mruby(%{["-x", "1"]\n}, "", true, %w[-e p(ARGV) -- -x 1])
+end
+
+assert('mruby invalid short option') do
+  assert_mruby("", /\A.*: invalid option -1 .*\n\z/, false, %w[-1])
+end
+
+assert('mruby invalid long option') do
+  assert_mruby("", /\A.*: invalid option --longopt .*\n\z/, false, %w[--longopt])
+end
+
+assert('unhandled exception') do
+  assert_mruby("", /\bEXCEPTION\b.*\n\z/, false, %w[-e raise("EXCEPTION")])
+end
+
+assert('program file not found') do
+  assert_mruby("", /\A.*: Cannot open program file: .*\n\z/, false, %w[_no_exists_])
+end
+
+assert('codegen error') do
+  code = "def f(#{(1..100).map{|n| "a#{n}"} * ","}); end"
+  assert_mruby("", /\Acodegen error:.*\n\z/, false, ["-e", code])
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mruby/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-mruby/mrbgem.rake	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mruby/mrbgem.rake	(revision 439)
@@ -6,8 +6,8 @@
   spec.add_dependency('mruby-compiler', :core => 'mruby-compiler')
   spec.add_dependency('mruby-error', :core => 'mruby-error')
+  spec.add_test_dependency('mruby-print', :core => 'mruby-print')
 
   if build.cxx_exception_enabled?
-    @objs << build.compile_as_cxx("#{spec.dir}/tools/mruby/mruby.c", "#{spec.build_dir}/tools/mruby/mruby.cxx")
-    @objs.delete_if { |v| v == objfile("#{spec.build_dir}/tools/mruby/mruby") }
+    build.compile_as_cxx("#{spec.dir}/tools/mruby/mruby.c", "#{spec.build_dir}/tools/mruby/mruby.cxx")
   end
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c	(revision 439)
@@ -1,6 +1,10 @@
-#include <stdio.h>
+#include <mruby.h>
+
+#ifdef MRB_DISABLE_STDIO
+# error mruby-bin-mruby conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
+#endif
+
 #include <stdlib.h>
 #include <string.h>
-#include <mruby.h>
 #include <mruby/array.h>
 #include <mruby/compile.h>
@@ -8,26 +12,25 @@
 #include <mruby/variable.h>
 
-#ifdef MRB_DISABLE_STDIO
-static void
-p(mrb_state *mrb, mrb_value obj)
-{
-  mrb_value val = mrb_inspect(mrb, obj);
-
-  fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout);
-  putc('\n', stdout);
-}
-#else
-#define p(mrb,obj) mrb_p(mrb,obj)
-#endif
-
 struct _args {
   FILE *rfp;
-  char* cmdline;
+  char *cmdline;
   mrb_bool fname        : 1;
   mrb_bool mrbfile      : 1;
   mrb_bool check_syntax : 1;
   mrb_bool verbose      : 1;
+  mrb_bool version      : 1;
+  mrb_bool debug        : 1;
   int argc;
-  char** argv;
+  char **argv;
+  int libc;
+  char **libv;
+};
+
+struct options {
+  int argc;
+  char **argv;
+  char *program;
+  char *opt;
+  char short_opt[2];
 };
 
@@ -39,5 +42,7 @@
   "-b           load and execute RiteBinary (mrb) file",
   "-c           check syntax only",
+  "-d           set debugging flags (set $DEBUG to true)",
   "-e 'command' one line of script",
+  "-r library   load the library before executing your script",
   "-v           print version number, then run in verbose mode",
   "--verbose    run in verbose mode",
@@ -48,51 +53,99 @@
   const char *const *p = usage_msg;
 
-  printf("Usage: %s [switches] programfile\n", name);
+  printf("Usage: %s [switches] [programfile] [arguments]\n", name);
   while (*p)
     printf("  %s\n", *p++);
 }
 
+static void
+options_init(struct options *opts, int argc, char **argv)
+{
+  opts->argc = argc;
+  opts->argv = argv;
+  opts->program = *argv;
+  *opts->short_opt = 0;
+}
+
+static const char *
+options_opt(struct options *opts)
+{
+  /* concatenated short options (e.g. `-cv`) */
+  if (*opts->short_opt && *++opts->opt) {
+   short_opt:
+    opts->short_opt[0] = *opts->opt;
+    opts->short_opt[1] = 0;
+    return opts->short_opt;
+  }
+
+  while (++opts->argv, --opts->argc) {
+    opts->opt = *opts->argv;
+
+    /*  empty         || not start with `-`  || `-` */
+    if (!opts->opt[0] || opts->opt[0] != '-' || !opts->opt[1]) return NULL;
+
+    if (opts->opt[1] == '-') {
+      /* `--` */
+      if (!opts->opt[2]) {
+        ++opts->argv, --opts->argc;
+        return NULL;
+      }
+      /* long option */
+      opts->opt += 2;
+      *opts->short_opt = 0;
+      return opts->opt;
+    }
+    else {
+      /* short option */
+      ++opts->opt;
+      goto short_opt;
+    }
+  }
+  return NULL;
+}
+
+static const char *
+options_arg(struct options *opts)
+{
+  if (*opts->short_opt && opts->opt[1]) {
+    /* concatenated short option and option argument (e.g. `-rLIBRARY`) */
+    *opts->short_opt = 0;
+    return opts->opt + 1;
+  }
+  --opts->argc, ++opts->argv;
+  return opts->argc ? *opts->argv : NULL;
+}
+
+static char *
+dup_arg_item(mrb_state *mrb, const char *item)
+{
+  size_t buflen = strlen(item) + 1;
+  char *buf = (char*)mrb_malloc(mrb, buflen);
+  memcpy(buf, item, buflen);
+  return buf;
+}
+
 static int
 parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
 {
-  char **origargv = argv;
   static const struct _args args_zero = { 0 };
+  struct options opts[1];
+  const char *opt, *item;
 
   *args = args_zero;
-
-  for (argc--,argv++; argc > 0; argc--,argv++) {
-    char *item;
-    if (argv[0][0] != '-') break;
-
-    if (strlen(*argv) <= 1) {
-      argc--; argv++;
-      args->rfp = stdin;
-      break;
-    }
-
-    item = argv[0] + 1;
-    switch (*item++) {
-    case 'b':
+  options_init(opts, argc, argv);
+  while ((opt = options_opt(opts))) {
+    if (strcmp(opt, "b") == 0) {
       args->mrbfile = TRUE;
-      break;
-    case 'c':
+    }
+    else if (strcmp(opt, "c") == 0) {
       args->check_syntax = TRUE;
-      break;
-    case 'e':
-      if (item[0]) {
-        goto append_cmdline;
-      }
-      else if (argc > 1) {
-        argc--; argv++;
-        item = argv[0];
-append_cmdline:
+    }
+    else if (strcmp(opt, "d") == 0) {
+      args->debug = TRUE;
+    }
+    else if (strcmp(opt, "e") == 0) {
+      if ((item = options_arg(opts))) {
         if (!args->cmdline) {
-          size_t buflen;
-          char *buf;
-
-          buflen = strlen(item) + 1;
-          buf = (char *)mrb_malloc(mrb, buflen);
-          memcpy(buf, item, buflen);
-          args->cmdline = buf;
+          args->cmdline = dup_arg_item(mrb, item);
         }
         else {
@@ -109,36 +162,63 @@
       }
       else {
-        printf("%s: No code specified for -e\n", *origargv);
-        return EXIT_SUCCESS;
-      }
-      break;
-    case 'v':
-      if (!args->verbose) mrb_show_version(mrb);
+        fprintf(stderr, "%s: No code specified for -e\n", opts->program);
+        return EXIT_FAILURE;
+      }
+    }
+    else if (strcmp(opt, "h") == 0) {
+      usage(opts->program);
+      exit(EXIT_SUCCESS);
+    }
+    else if (strcmp(opt, "r") == 0) {
+      if ((item = options_arg(opts))) {
+        if (args->libc == 0) {
+          args->libv = (char**)mrb_malloc(mrb, sizeof(char*));
+        }
+        else {
+          args->libv = (char**)mrb_realloc(mrb, args->libv, sizeof(char*) * (args->libc + 1));
+        }
+        args->libv[args->libc++] = dup_arg_item(mrb, item);
+      }
+      else {
+        fprintf(stderr, "%s: No library specified for -r\n", opts->program);
+        return EXIT_FAILURE;
+      }
+    }
+    else if (strcmp(opt, "v") == 0) {
+      if (!args->verbose) {
+        mrb_show_version(mrb);
+        args->version = TRUE;
+      }
       args->verbose = TRUE;
-      break;
-    case '-':
-      if (strcmp((*argv) + 2, "version") == 0) {
-        mrb_show_version(mrb);
-        exit(EXIT_SUCCESS);
-      }
-      else if (strcmp((*argv) + 2, "verbose") == 0) {
-        args->verbose = TRUE;
-        break;
-      }
-      else if (strcmp((*argv) + 2, "copyright") == 0) {
-        mrb_show_copyright(mrb);
-        exit(EXIT_SUCCESS);
-      }
-    default:
+    }
+    else if (strcmp(opt, "version") == 0) {
+      mrb_show_version(mrb);
+      exit(EXIT_SUCCESS);
+    }
+    else if (strcmp(opt, "verbose") == 0) {
+      args->verbose = TRUE;
+    }
+    else if (strcmp(opt, "copyright") == 0) {
+      mrb_show_copyright(mrb);
+      exit(EXIT_SUCCESS);
+    }
+    else {
+      fprintf(stderr, "%s: invalid option %s%s (-h will show valid options)\n",
+              opts->program, opt[1] ? "--" : "-", opt);
       return EXIT_FAILURE;
     }
   }
 
-  if (args->rfp == NULL && args->cmdline == NULL) {
-    if (*argv == NULL) args->rfp = stdin;
-    else {
-      args->rfp = fopen(argv[0], args->mrbfile ? "rb" : "r");
+  argc = opts->argc; argv = opts->argv;
+  if (args->cmdline == NULL) {
+    if (*argv == NULL) {
+      if (args->version) exit(EXIT_SUCCESS);
+      args->rfp = stdin;
+    }
+    else {
+      args->rfp = strcmp(argv[0], "-") == 0 ?
+        stdin : fopen(argv[0], args->mrbfile ? "rb" : "r");
       if (args->rfp == NULL) {
-        printf("%s: Cannot open program file. (%s)\n", *origargv, *argv);
+        fprintf(stderr, "%s: Cannot open program file: %s\n", opts->program, argv[0]);
         return EXIT_FAILURE;
       }
@@ -163,4 +243,10 @@
     mrb_free(mrb, args->cmdline);
   mrb_free(mrb, args->argv);
+  if (args->libc) {
+    while (args->libc--) {
+      mrb_free(mrb, args->libv[args->libc]);
+    }
+    mrb_free(mrb, args->libv);
+  }
   mrb_close(mrb);
 }
@@ -179,5 +265,5 @@
 
   if (mrb == NULL) {
-    fputs("Invalid mrb_state, exiting mruby\n", stderr);
+    fprintf(stderr, "%s: Invalid mrb_state, exiting mruby\n", *argv);
     return EXIT_FAILURE;
   }
@@ -186,5 +272,4 @@
   if (n == EXIT_FAILURE || (args.cmdline == NULL && args.rfp == NULL)) {
     cleanup(mrb, &args);
-    usage(argv[0]);
     return n;
   }
@@ -200,4 +285,5 @@
     }
     mrb_define_global_const(mrb, "ARGV", ARGV);
+    mrb_gv_set(mrb, mrb_intern_lit(mrb, "$DEBUG"), mrb_bool_value(args.debug));
 
     c = mrbc_context_new(mrb);
@@ -220,4 +306,22 @@
     }
 
+    /* Load libraries */
+    for (i = 0; i < args.libc; i++) {
+      FILE *lfp = fopen(args.libv[i], args.mrbfile ? "rb" : "r");
+      if (lfp == NULL) {
+        fprintf(stderr, "%s: Cannot open library file: %s\n", *argv, args.libv[i]);
+        mrbc_context_free(mrb, c);
+        cleanup(mrb, &args);
+        return EXIT_FAILURE;
+      }
+      if (args.mrbfile) {
+        v = mrb_load_irep_file_cxt(mrb, lfp, c);
+      }
+      else {
+        v = mrb_load_file_cxt(mrb, lfp, c);
+      }
+      fclose(lfp);
+    }
+
     /* Load program */
     if (args.mrbfile) {
@@ -237,18 +341,15 @@
     mrbc_context_free(mrb, c);
     if (mrb->exc) {
-      if (mrb_undef_p(v)) {
-        mrb_p(mrb, mrb_obj_value(mrb->exc));
-      }
-      else {
+      if (!mrb_undef_p(v)) {
         mrb_print_error(mrb);
       }
-      n = -1;
+      n = EXIT_FAILURE;
     }
     else if (args.check_syntax) {
-      printf("Syntax OK\n");
+      puts("Syntax OK");
     }
   }
   cleanup(mrb, &args);
 
-  return n == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
-}
+  return n;
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb	(revision 439)
@@ -68,6 +68,6 @@
   `#{cmd('mruby-strip')} -l #{without_lv.path}`
   assert_true without_lv.size < with_lv.size
-
-  assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp
-  assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp
+#
+#  assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp
+#  assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c	(revision 439)
@@ -1,6 +1,10 @@
-#include <stdio.h>
+#include <mruby.h>
+
+#ifdef MRB_DISABLE_STDIO
+# error mruby-bin-strip conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
+#endif
+
 #include <stdlib.h>
 #include <string.h>
-#include <mruby.h>
 #include <mruby/irep.h>
 #include <mruby/dump.h>
@@ -12,20 +16,4 @@
   mrb_bool lvar;
 };
-
-
-static void
-irep_remove_lv(mrb_state *mrb, mrb_irep *irep)
-{
-  size_t i;
-
-  if (irep->lv) {
-    mrb_free(mrb, irep->lv);
-    irep->lv = NULL;
-  }
-
-  for (i = 0; i < irep->rlen; ++i) {
-    irep_remove_lv(mrb, irep->reps[i]);
-  }
-}
 
 static void
@@ -100,5 +88,5 @@
     /* clear lv if --lvar is enabled */
     if (args->lvar) {
-      irep_remove_lv(mrb, irep);
+      mrb_irep_remove_lv(mrb, irep);
     }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-class-ext/mrblib/module.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-class-ext/mrblib/module.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-class-ext/mrblib/module.rb	(revision 439)
@@ -0,0 +1,89 @@
+class Module
+
+  ##
+  # call-seq:
+  #   mod < other   ->  true, false, or nil
+  #
+  # Returns true if `mod` is a subclass of `other`. Returns
+  # <code>nil</code> if there's no relationship between the two.
+  # (Think of the relationship in terms of the class definition:
+  # "class A < B" implies "A < B".)
+  #
+  def <(other)
+    if self.equal?(other)
+      false
+    else
+      self <= other
+    end
+  end
+
+  ##
+  # call-seq:
+  #   mod <= other   ->  true, false, or nil
+  #
+  # Returns true if `mod` is a subclass of `other` or
+  # is the same as `other`. Returns
+  # <code>nil</code> if there's no relationship between the two.
+  # (Think of the relationship in terms of the class definition:
+  # "class A < B" implies "A < B".)
+  def <=(other)
+    raise TypeError, 'compared with non class/module' unless other.is_a?(Module)
+    if self.ancestors.include?(other)
+      return true
+    elsif other.ancestors.include?(self)
+      return false
+    end
+  end
+
+  ##
+  # call-seq:
+  #  mod > other   ->  true, false, or nil
+  #
+  # Returns true if `mod` is an ancestor of `other`. Returns
+  # <code>nil</code> if there's no relationship between the two.
+  # (Think of the relationship in terms of the class definition:
+  # "class A < B" implies "B > A".)
+  #
+  def >(other)
+    if self.equal?(other)
+      false
+    else
+      self >= other
+    end
+  end
+
+  ##
+  # call-seq:
+  #   mod >= other   ->  true, false, or nil
+  #
+  # Returns true if `mod` is an ancestor of `other`, or the
+  # two modules are the same. Returns
+  # <code>nil</code> if there's no relationship between the two.
+  # (Think of the relationship in terms of the class definition:
+  # "class A < B" implies "B > A".)
+  #
+  def >=(other)
+    raise TypeError, 'compared with non class/module' unless other.is_a?(Module)
+    return other < self
+  end
+
+  ##
+  # call-seq:
+  #    module <=> other_module   -> -1, 0, +1, or nil
+  #
+  # Comparison---Returns -1, 0, +1 or nil depending on whether `module`
+  # includes `other_module`, they are the same, or if `module` is included by
+  # `other_module`.
+  #
+  # Returns `nil` if `module` has no relationship with `other_module`, if
+  # `other_module` is not a module, or if the two values are incomparable.
+  #
+  def <=>(other)
+    return 0 if self.equal?(other)
+    return nil unless other.is_a?(Module)
+    cmp = self < other
+    return -1 if cmp
+    return 1 unless cmp.nil?
+    return nil
+  end
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-class-ext/src/class.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-class-ext/src/class.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-class-ext/src/class.c	(revision 439)
@@ -6,6 +6,47 @@
 mrb_mod_name(mrb_state *mrb, mrb_value self)
 {
-  mrb_value name = mrb_class_path(mrb, mrb_class_ptr(self));
-  return mrb_nil_p(name)? name : mrb_str_dup(mrb, name);
+  mrb_value name =  mrb_class_path(mrb, mrb_class_ptr(self));
+  if (mrb_string_p(name)) {
+    MRB_SET_FROZEN_FLAG(mrb_basic_ptr(name));
+  }
+  return name;
+}
+
+static mrb_value
+mrb_mod_singleton_class_p(mrb_state *mrb, mrb_value self)
+{
+  return mrb_bool_value(mrb_sclass_p(self));
+}
+
+/*
+ *  call-seq:
+ *     module_exec(arg...) {|var...| block } -> obj
+ *     class_exec(arg...) {|var...| block } -> obj
+ *
+ * Evaluates the given block in the context of the
+ * class/module. The method defined in the block will belong
+ * to the receiver. Any arguments passed to the method will be
+ * passed to the block. This can be used if the block needs to
+ * access instance variables.
+ *
+ *     class Thing
+ *     end
+ *     Thing.class_exec{
+ *       def hello() "Hello there!" end
+ *     }
+ *     puts Thing.new.hello()
+ */
+
+static mrb_value
+mrb_mod_module_exec(mrb_state *mrb, mrb_value self)
+{
+  const mrb_value *argv;
+  mrb_int argc;
+  mrb_value blk;
+
+  mrb_get_args(mrb, "*&!", &argv, &argc, &blk);
+
+  mrb->c->ci->target_class = mrb_class_ptr(self);
+  return mrb_yield_cont(mrb, blk, self, argc, argv);
 }
 
@@ -16,4 +57,7 @@
 
   mrb_define_method(mrb, mod, "name", mrb_mod_name, MRB_ARGS_NONE());
+  mrb_define_method(mrb, mod, "singleton_class?", mrb_mod_singleton_class_p, MRB_ARGS_NONE());
+  mrb_define_method(mrb, mod, "module_exec", mrb_mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK());
+  mrb_define_method(mrb, mod, "class_exec", mrb_mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK());
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-class-ext/test/module.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-class-ext/test/module.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-class-ext/test/module.rb	(revision 439)
@@ -1,10 +1,109 @@
+assert 'Module#<' do
+  a = Class.new
+  b = Class.new(a)
+  c = Class.new(a)
+  d = Module.new
+  e = Class.new { include d }
+  f = Module.new { include d }
+
+  # compare class to class
+  assert_true b < a
+  assert_false b < b
+  assert_false a < b
+  assert_nil c < b
+
+  # compare class to module
+  assert_true e < d
+  assert_false d < e
+  assert_nil a < d
+
+  # compare module to module
+  assert_true f < d
+  assert_false f < f
+  assert_false d < f
+
+  assert_raise(TypeError) { a < Object.new }
+end
+
+assert 'Module#<=' do
+  a = Class.new
+  b = Class.new(a)
+  c = Class.new(a)
+  d = Module.new
+  e = Class.new { include d }
+  f = Module.new { include d }
+
+  # compare class to class
+  assert_true b <= a
+  assert_true b <= b
+  assert_false a <= b
+  assert_nil c <= b
+
+  # compare class to module
+  assert_true e <= d
+  assert_false d <= e
+  assert_nil a <= d
+
+  # compare module to module
+  assert_true f <= d
+  assert_true f <= f
+  assert_false d <= f
+
+  assert_raise(TypeError) { a <= Object.new }
+end
+
 assert 'Module#name' do
-  module A
-    class B
+  module Outer
+    class Inner; end
+    const_set :SetInner, Class.new
+  end
+
+  assert_equal 'Outer', Outer.name
+  assert_equal 'Outer::Inner', Outer::Inner.name
+  assert_equal 'Outer::SetInner', Outer::SetInner.name
+
+  outer = Module.new do
+    const_set :SetInner, Class.new
+  end
+  Object.const_set :SetOuter, outer
+
+  assert_equal 'SetOuter', SetOuter.name
+  assert_equal 'SetOuter::SetInner', SetOuter::SetInner.name
+
+  mod = Module.new
+  cls = Class.new
+
+  assert_nil mod.name
+  assert_nil cls.name
+end
+
+assert 'Module#singleton_class?' do
+  mod = Module.new
+  cls = Class.new
+  scl = (class <<cls; self; end)
+
+  assert_false mod.singleton_class?
+  assert_false cls.singleton_class?
+  assert_true scl.singleton_class?
+end
+
+assert 'Module#module_eval' do
+  mod = Module.new
+  mod.class_exec(1,2,3) do |a,b,c|
+    assert_equal([1,2,3], [a,b,c])
+    def hi
+      "hi"
     end
   end
-
-  assert_nil A::B.singleton_class.name
-  assert_equal 'Fixnum', Fixnum.name
-  assert_equal 'A::B', A::B.name
+  cls = Class.new
+  cls.class_exec(42) do |x|
+    assert_equal(42, x)
+    include mod
+    def hello
+      "hello"
+    end
+  end
+  obj = cls.new
+  assert_equal("hi", obj.hi)
+  assert_equal("hello", obj.hello)
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compar-ext/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compar-ext/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compar-ext/mrbgem.rake	(revision 439)
@@ -0,0 +1,5 @@
+MRuby::Gem::Specification.new('mruby-compar-ext') do |spec|
+  spec.license = 'MIT'
+  spec.author  = 'mruby developers'
+  spec.summary = 'Enumerable module extension'
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compar-ext/mrblib/compar.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compar-ext/mrblib/compar.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compar-ext/mrblib/compar.rb	(revision 439)
@@ -0,0 +1,31 @@
+module Comparable
+  ##
+  # Returns <i>min</i> if <i>obj</i> <code><=></code> <i>min</i> is less
+  # than zero, <i>max</i> if <i>obj</i> <code><=></code> <i>max</i> is
+  # greater than zero and <i>obj</i> otherwise.
+  #
+  #     12.clamp(0, 100)         #=> 12
+  #     523.clamp(0, 100)        #=> 100
+  #     -3.123.clamp(0, 100)     #=> 0
+  #
+  #     'd'.clamp('a', 'f')      #=> 'd'
+  #     'z'.clamp('a', 'f')      #=> 'f'
+  #
+  def clamp(min, max)
+    if (min <=> max) > 0
+      raise ArgumentError, "min argument must be smaller than max argument"
+    end
+    c = self <=> min
+    if c == 0
+      return self
+    elsif c < 0
+      return min
+    end
+    c = self <=> max
+    if c > 0
+      return max
+    else
+      return self
+    end
+  end
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/codegen.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/codegen.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/codegen.c	(revision 439)
@@ -9,4 +9,5 @@
 #include <stdlib.h>
 #include <string.h>
+#include <math.h>
 #include <mruby.h>
 #include <mruby/compile.h>
@@ -24,4 +25,6 @@
 #endif
 
+#define MAXARG_S (1<<16)
+
 typedef mrb_ast_node node;
 typedef struct mrb_parser_state parser_state;
@@ -37,5 +40,5 @@
 struct loopinfo {
   enum looptype type;
-  int pc1, pc2, pc3, acc;
+  int pc0, pc1, pc2, pc3, acc;
   int ensure_level;
   struct loopinfo *prev;
@@ -51,7 +54,8 @@
   node *lv;
 
-  int sp;
-  int pc;
-  int lastlabel;
+  uint16_t sp;
+  uint16_t pc;
+  uint16_t lastpc;
+  uint16_t lastlabel;
   int ainfo:15;
   mrb_bool mscope:1;
@@ -59,15 +63,13 @@
   struct loopinfo *loop;
   int ensure_level;
-  char const *filename;
+  mrb_sym filename_sym;
   uint16_t lineno;
 
   mrb_code *iseq;
   uint16_t *lines;
-  int icapa;
+  uint32_t icapa;
 
   mrb_irep *irep;
-  size_t pcapa;
-  size_t scapa;
-  size_t rcapa;
+  uint32_t pcapa, scapa, rcapa;
 
   uint16_t nlocals;
@@ -101,10 +103,12 @@
     codegen_scope *tmp = s->prev;
     mrb_free(s->mrb, s->iseq);
+    mrb_free(s->mrb, s->lines);
     mrb_pool_close(s->mpool);
     s = tmp;
   }
 #ifndef MRB_DISABLE_STDIO
-  if (s->filename && s->lineno) {
-    fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message);
+  if (s->filename_sym && s->lineno) {
+    const char *filename = mrb_sym_name_len(s->mrb, s->filename_sym, NULL);
+    fprintf(stderr, "codegen error:%s:%d: %s\n", filename, s->lineno, message);
   }
   else {
@@ -125,13 +129,4 @@
 
 static void*
-codegen_malloc(codegen_scope *s, size_t len)
-{
-  void *p = mrb_malloc_simple(s->mrb, len);
-
-  if (!p) codegen_error(s, "mrb_malloc");
-  return p;
-}
-
-static void*
 codegen_realloc(codegen_scope *s, void *p, size_t len)
 {
@@ -145,24 +140,133 @@
 new_label(codegen_scope *s)
 {
-  s->lastlabel = s->pc;
-  return s->pc;
-}
-
-static inline int
-genop(codegen_scope *s, mrb_code i)
-{
-  if (s->pc == s->icapa) {
+  return s->lastlabel = s->pc;
+}
+
+static void
+emit_B(codegen_scope *s, uint32_t pc, uint8_t i)
+{
+  if (pc >= MAXARG_S || s->icapa >= MAXARG_S) {
+    codegen_error(s, "too big code block");
+  }
+  if (pc >= s->icapa) {
     s->icapa *= 2;
+    if (s->icapa > MAXARG_S) {
+      s->icapa = MAXARG_S;
+    }
     s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa);
     if (s->lines) {
-      s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa);
-      s->irep->lines = s->lines;
-    }
-  }
-  s->iseq[s->pc] = i;
+      s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa);
+    }
+  }
   if (s->lines) {
-    s->lines[s->pc] = s->lineno;
-  }
-  return s->pc++;
+    if (s->lineno > 0 || pc == 0)
+      s->lines[pc] = s->lineno;
+    else
+      s->lines[pc] = s->lines[pc-1];
+  }
+  s->iseq[pc] = i;
+}
+
+static void
+emit_S(codegen_scope *s, int pc, uint16_t i)
+{
+  uint8_t hi = i>>8;
+  uint8_t lo = i&0xff;
+
+  emit_B(s, pc,   hi);
+  emit_B(s, pc+1, lo);
+}
+
+static void
+gen_B(codegen_scope *s, uint8_t i)
+{
+  emit_B(s, s->pc, i);
+  s->pc++;
+}
+
+static void
+gen_S(codegen_scope *s, uint16_t i)
+{
+  emit_S(s, s->pc, i);
+  s->pc += 2;
+}
+
+static void
+genop_0(codegen_scope *s, mrb_code i)
+{
+  s->lastpc = s->pc;
+  gen_B(s, i);
+}
+
+static void
+genop_1(codegen_scope *s, mrb_code i, uint16_t a)
+{
+  s->lastpc = s->pc;
+  if (a > 0xff) {
+    gen_B(s, OP_EXT1);
+    gen_B(s, i);
+    gen_S(s, a);
+  }
+  else {
+    gen_B(s, i);
+    gen_B(s, (uint8_t)a);
+  }
+}
+
+static void
+genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
+{
+  s->lastpc = s->pc;
+  if (a > 0xff && b > 0xff) {
+    gen_B(s, OP_EXT3);
+    gen_B(s, i);
+    gen_S(s, a);
+    gen_S(s, b);
+  }
+  else if (b > 0xff) {
+    gen_B(s, OP_EXT2);
+    gen_B(s, i);
+    gen_B(s, (uint8_t)a);
+    gen_S(s, b);
+  }
+  else if (a > 0xff) {
+    gen_B(s, OP_EXT1);
+    gen_B(s, i);
+    gen_S(s, a);
+    gen_B(s, (uint8_t)b);
+  }
+  else {
+    gen_B(s, i);
+    gen_B(s, (uint8_t)a);
+    gen_B(s, (uint8_t)b);
+  }
+}
+
+static void
+genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint8_t c)
+{
+  genop_2(s, i, a, b);
+  gen_B(s, c);
+}
+
+static void
+genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
+{
+  genop_1(s, i, a);
+  gen_S(s, b);
+}
+
+static void
+genop_W(codegen_scope *s, mrb_code i, uint32_t a)
+{
+  uint8_t a1 = (a>>16) & 0xff;
+  uint8_t a2 = (a>>8) & 0xff;
+  uint8_t a3 = a & 0xff;
+
+  s->lastpc = s->pc;
+  gen_B(s, i);
+  gen_B(s, a1);
+  gen_B(s, a2);
+  gen_B(s, a3);
 }
 
@@ -178,240 +282,241 @@
 }
 
-static int
-genop_peep(codegen_scope *s, mrb_code i, int val)
-{
-  /* peephole optimization */
-  if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) {
-    mrb_code i0 = s->iseq[s->pc-1];
-    int c1 = GET_OPCODE(i);
-    int c0 = GET_OPCODE(i0);
-
-    switch (c1) {
+static
+mrb_bool
+on_eval(codegen_scope *s)
+{
+  if (s && s->parser && s->parser->on_eval)
+    return TRUE;
+  return FALSE;
+}
+
+struct mrb_insn_data
+mrb_decode_insn(const mrb_code *pc)
+{
+  struct mrb_insn_data data = { 0 };
+  mrb_code insn = READ_B();
+  uint16_t a = 0;
+  uint16_t b = 0;
+  uint8_t  c = 0;
+
+  switch (insn) {
+#define FETCH_Z() /* empty */
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+  }
+  switch (insn) {
+  case OP_EXT1:
+    insn = READ_B();
+    switch (insn) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+    }
+    break;
+  case OP_EXT2:
+    insn = READ_B();
+    switch (insn) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+    }
+    break;
+  case OP_EXT3:
+    insn = READ_B();
+    switch (insn) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+    }
+    break;
+  default:
+    break;
+  }
+  data.insn = insn;
+  data.a = a;
+  data.b = b;
+  data.c = c;
+  return data;
+}
+
+static struct mrb_insn_data
+mrb_last_insn(codegen_scope *s)
+{
+  if (s->pc == s->lastpc) {
+    struct mrb_insn_data data;
+
+    data.insn = OP_NOP;
+    return data;
+  }
+  return mrb_decode_insn(&s->iseq[s->lastpc]);
+}
+
+static mrb_bool
+no_peephole(codegen_scope *s)
+{
+  return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc;
+}
+
+static uint16_t
+genjmp(codegen_scope *s, mrb_code i, uint16_t pc)
+{
+  uint16_t pos;
+
+  s->lastpc = s->pc;
+  gen_B(s, i);
+  pos = s->pc;
+  gen_S(s, pc);
+  return pos;
+}
+
+static uint16_t
+genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val)
+{
+  uint16_t pos;
+
+  if (!no_peephole(s) && !val) {
+    struct mrb_insn_data data = mrb_last_insn(s);
+
+    if (data.insn == OP_MOVE && data.a == a) {
+      s->pc = s->lastpc;
+      a = data.b;
+    }
+  }
+
+  s->lastpc = s->pc;
+  if (a > 0xff) {
+    gen_B(s, OP_EXT1);
+    gen_B(s, i);
+    gen_S(s, a);
+    pos = s->pc;
+    gen_S(s, pc);
+  }
+  else {
+    gen_B(s, i);
+    gen_B(s, (uint8_t)a);
+    pos = s->pc;
+    gen_S(s, pc);
+  }
+  return pos;
+}
+
+static void
+gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
+{
+  if (no_peephole(s)) {
+  normal:
+    genop_2(s, OP_MOVE, dst, src);
+    if (on_eval(s)) {
+      genop_0(s, OP_NOP);
+    }
+    return;
+  }
+  else {
+    struct mrb_insn_data data = mrb_last_insn(s);
+
+    switch (data.insn) {
     case OP_MOVE:
-      if (GETARG_A(i) == GETARG_B(i)) {
-        /* skip useless OP_MOVE */
-        return 0;
-      }
-      if (val) break;
-      switch (c0) {
-      case OP_MOVE:
-        if (GETARG_A(i) == GETARG_A(i0)) {
-          /* skip overriden OP_MOVE */
-          s->pc--;
-          s->iseq[s->pc] = i;
-        }
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) {
-          /* skip swapping OP_MOVE */
-          return 0;
-        }
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->pc--;
-          return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val);
-        }
-        break;
-      case OP_LOADI:
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0));
-          return 0;
-        }
-        break;
-      case OP_ARRAY:
-      case OP_HASH:
-      case OP_RANGE:
-      case OP_AREF:
-      case OP_GETUPVAR:
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0));
-          return 0;
-        }
-        break;
-      case OP_LOADSYM:
-      case OP_GETGLOBAL:
-      case OP_GETIV:
-      case OP_GETCV:
-      case OP_GETCONST:
-      case OP_GETSPECIAL:
-      case OP_LOADL:
-      case OP_STRING:
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0));
-          return 0;
-        }
-        break;
-      case OP_SCLASS:
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0));
-          return 0;
-        }
-        break;
-      case OP_LOADNIL:
-      case OP_LOADSELF:
-      case OP_LOADT:
-      case OP_LOADF:
-      case OP_OCLASS:
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i));
-          return 0;
-        }
-        break;
-      default:
-        break;
-      }
+      if (dst == src) return;             /* remove useless MOVE */
+      if (data.b == dst && data.a == src) /* skip swapping MOVE */
+        return;
+      goto normal;
+    case OP_LOADNIL: case OP_LOADSELF: case OP_LOADT: case OP_LOADF:
+    case OP_LOADI__1:
+    case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3:
+    case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7:
+      if (nopeep || data.a != src || data.a < s->nlocals) goto normal;
+      s->pc = s->lastpc;
+      genop_1(s, data.insn, dst);
       break;
-    case OP_SETIV:
-    case OP_SETCV:
-    case OP_SETCONST:
-    case OP_SETMCNST:
-    case OP_SETGLOBAL:
-      if (val) break;
-      if (c0 == OP_MOVE) {
-        if (GETARG_A(i) == GETARG_A(i0)) {
-          s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i));
-          return 0;
-        }
-      }
-      break;
-    case OP_SETUPVAR:
-      if (val) break;
-      if (c0 == OP_MOVE) {
-        if (GETARG_A(i) == GETARG_A(i0)) {
-          s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i));
-          return 0;
-        }
-      }
-      break;
-    case OP_EPOP:
-      if (c0 == OP_EPOP) {
-        s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i));
-        return 0;
-      }
-      break;
-    case OP_POPERR:
-      if (c0 == OP_POPERR) {
-        s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i));
-        return 0;
-      }
-      break;
-    case OP_RETURN:
-      switch (c0) {
-      case OP_RETURN:
-        return 0;
-      case OP_MOVE:
-        if (GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL);
-          return 0;
-        }
-        break;
-      case OP_SETIV:
-      case OP_SETCV:
-      case OP_SETCONST:
-      case OP_SETMCNST:
-      case OP_SETUPVAR:
-      case OP_SETGLOBAL:
-        s->pc--;
-        genop_peep(s, i0, NOVAL);
-        i0 = s->iseq[s->pc-1];
-        return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL));
-#if 0
-      case OP_SEND:
-        if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) {
-          s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0));
-          return;
-        }
-        break;
-#endif
-      default:
-        break;
-      }
-      break;
-    case OP_ADD:
-    case OP_SUB:
-      if (c0 == OP_LOADI) {
-        int c = GETARG_sBx(i0);
-
-        if (c1 == OP_SUB) c = -c;
-        if (c > 127 || c < -127) break;
-        if (0 <= c)
-          s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c);
-        else
-          s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c);
-        return 0;
-      }
-    case OP_STRCAT:
-      if (c0 == OP_STRING) {
-        mrb_value v = s->irep->pool[GETARG_Bx(i0)];
-
-        if (mrb_string_p(v) && RSTRING_LEN(v) == 0) {
-          s->pc--;
-          return 0;
-        }
-      }
-      if (c0 == OP_LOADNIL) {
-        if (GETARG_B(i) == GETARG_A(i0)) {
-          s->pc--;
-          return 0;
-        }
-      }
-      break;
-    case OP_JMPIF:
-    case OP_JMPNOT:
-      if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) {
-        s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i));
-        return s->pc-1;
-      }
+    case OP_LOADI: case OP_LOADINEG: case OP_LOADL: case OP_LOADSYM:
+    case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV:
+    case OP_GETCONST: case OP_STRING:
+    case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH:
+      if (nopeep || data.a != src || data.a < s->nlocals) goto normal;
+      s->pc = s->lastpc;
+      genop_2(s, data.insn, dst, data.b);
       break;
     default:
+      goto normal;
+    }
+  }
+}
+
+static void
+gen_return(codegen_scope *s, uint8_t op, uint16_t src)
+{
+  if (no_peephole(s)) {
+    genop_1(s, op, src);
+  }
+  else {
+    struct mrb_insn_data data = mrb_last_insn(s);
+
+    if (data.insn == OP_MOVE && src == data.a) {
+      s->pc = s->lastpc;
+      genop_1(s, op, data.b);
+    }
+    else if (data.insn != OP_RETURN) {
+      genop_1(s, op, src);
+    }
+  }
+}
+
+static void
+gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst)
+{
+  if (no_peephole(s)) {
+  normal:
+    genop_1(s, op, dst);
+    return;
+  }
+  else {
+    struct mrb_insn_data data = mrb_last_insn(s);
+
+    switch (data.insn) {
+    case OP_LOADI__1:
+      if (op == OP_ADD) op = OP_SUB;
+      else op = OP_ADD;
+      data.b = 1;
+      goto replace;
+    case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3:
+    case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7:
+      data.b = data.insn - OP_LOADI_0;
+      /* fall through */
+    case OP_LOADI:
+    replace:
+      if (data.b >= 128) goto normal;
+      s->pc = s->lastpc;
+      if (op == OP_ADD) {
+        genop_2(s, OP_ADDI, dst, (uint8_t)data.b);
+      }
+      else {
+        genop_2(s, OP_SUBI, dst, (uint8_t)data.b);
+      }
       break;
-    }
-  }
-  return genop(s, i);
+    default:
+      goto normal;
+    }
+  }
+}
+
+static int
+dispatch(codegen_scope *s, uint16_t pos0)
+{
+  uint16_t newpos;
+
+  s->lastlabel = s->pc;
+  newpos = PEEK_S(s->iseq+pos0);
+  emit_S(s, pos0, s->pc);
+  return newpos;
 }
 
 static void
-scope_error(codegen_scope *s)
-{
-  exit(EXIT_FAILURE);
-}
-
-static inline void
-dispatch(codegen_scope *s, int pc)
-{
-  int diff = s->pc - pc;
-  mrb_code i = s->iseq[pc];
-  int c = GET_OPCODE(i);
-
-  s->lastlabel = s->pc;
-  switch (c) {
-  case OP_JMP:
-  case OP_JMPIF:
-  case OP_JMPNOT:
-  case OP_ONERR:
-    break;
-  default:
-#ifndef MRB_DISABLE_STDIO
-    fprintf(stderr, "bug: dispatch on non JMP op\n");
-#endif
-    scope_error(s);
-    break;
-  }
-  if (diff > MAXARG_sBx) {
-    codegen_error(s, "too distant jump address");
-  }
-  s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff);
-}
-
-static void
-dispatch_linked(codegen_scope *s, int pc)
-{
-  mrb_code i;
-  int pos;
-
-  if (!pc) return;
+dispatch_linked(codegen_scope *s, uint16_t pos)
+{
+  if (pos==0) return;
   for (;;) {
-    i = s->iseq[pc];
-    pos = GETARG_sBx(i);
-    dispatch(s, pc);
-    if (!pos) break;
-    pc = pos;
+    pos = dispatch(s, pos);
+    if (pos==0) break;
   }
 }
@@ -419,17 +524,7 @@
 #define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0)
 static void
-push_(codegen_scope *s)
-{
-  if (s->sp > 511) {
-    codegen_error(s, "too complex expression");
-  }
-  s->sp++;
-  nregs_update;
-}
-
-static void
-push_n_(codegen_scope *s, size_t n)
-{
-  if (s->sp+n > 511) {
+push_n_(codegen_scope *s, int n)
+{
+  if (s->sp+n >= 0xffff) {
     codegen_error(s, "too complex expression");
   }
@@ -438,9 +533,17 @@
 }
 
-#define push() push_(s)
+static void
+pop_n_(codegen_scope *s, int n)
+{
+  if ((int)s->sp-n < 0) {
+    codegen_error(s, "stack pointer underflow");
+  }
+  s->sp-=n;
+}
+
+#define push() push_n_(s,1)
 #define push_n(n) push_n_(s,n)
-#define pop_(s) ((s)->sp--)
-#define pop() pop_(s)
-#define pop_n(n) (s->sp-=(n))
+#define pop() pop_n_(s,1)
+#define pop_n(n) pop_n_(s,n)
 #define cursp() (s->sp)
 
@@ -448,5 +551,5 @@
 new_lit(codegen_scope *s, mrb_value val)
 {
-  size_t i;
+  int i;
   mrb_value *pv;
 
@@ -457,5 +560,5 @@
       pv = &s->irep->pool[i];
 
-      if (mrb_type(*pv) != MRB_TT_STRING) continue;
+      if (!mrb_string_p(*pv)) continue;
       if ((len = RSTRING_LEN(*pv)) != RSTRING_LEN(val)) continue;
       if (memcmp(RSTRING_PTR(*pv), RSTRING_PTR(val), len) == 0)
@@ -463,11 +566,16 @@
     }
     break;
+#ifndef MRB_WITHOUT_FLOAT
   case MRB_TT_FLOAT:
     for (i=0; i<s->irep->plen; i++) {
+      mrb_float f1, f2;
       pv = &s->irep->pool[i];
-      if (mrb_type(*pv) != MRB_TT_FLOAT) continue;
-      if (mrb_float(*pv) == mrb_float(val)) return i;
-    }
-    break;
+      if (!mrb_float_p(*pv)) continue;
+      f1 = mrb_float(*pv);
+      f2 = mrb_float(val);
+      if (f1 == f2 && !signbit(f1) == !signbit(f2)) return i;
+    }
+    break;
+#endif
   case MRB_TT_FIXNUM:
     for (i=0; i<s->irep->plen; i++) {
@@ -492,7 +600,8 @@
   switch (mrb_type(val)) {
   case MRB_TT_STRING:
-    *pv = mrb_str_pool(s->mrb, val);
-    break;
-
+    *pv = mrb_str_pool(s->mrb, RSTRING_PTR(val), RSTRING_LEN(val), RSTR_NOFREE_P(RSTRING(val)));
+    break;
+
+#ifndef MRB_WITHOUT_FLOAT
   case MRB_TT_FLOAT:
 #ifdef MRB_WORD_BOXING
@@ -500,4 +609,5 @@
     break;
 #endif
+#endif
   case MRB_TT_FIXNUM:
     *pv = val;
@@ -511,50 +621,21 @@
 }
 
-/* method symbols should be fit in 9 bits */
-#define MAXMSYMLEN 512
 /* maximum symbol numbers */
-#define MAXSYMLEN 65536
+#define MAXSYMLEN 0x10000
 
 static int
-new_msym(codegen_scope *s, mrb_sym sym)
-{
-  size_t i, len;
+new_sym(codegen_scope *s, mrb_sym sym)
+{
+  int i, len;
 
   mrb_assert(s->irep);
 
   len = s->irep->slen;
-  if (len > MAXMSYMLEN) len = MAXMSYMLEN;
   for (i=0; i<len; i++) {
     if (s->irep->syms[i] == sym) return i;
-    if (s->irep->syms[i] == 0) break;
-  }
-  if (i == MAXMSYMLEN) {
-    codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXMSYMLEN) ")");
-  }
-  s->irep->syms[i] = sym;
-  if (i == s->irep->slen) s->irep->slen++;
-  return i;
-}
-
-static int
-new_sym(codegen_scope *s, mrb_sym sym)
-{
-  size_t i;
-
-  for (i=0; i<s->irep->slen; i++) {
-    if (s->irep->syms[i] == sym) return i;
-  }
-  if (s->irep->slen == MAXSYMLEN) {
-    codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXSYMLEN) ")");
-  }
-
-  if (s->irep->slen > MAXMSYMLEN/2 && s->scapa == MAXMSYMLEN) {
-    s->scapa = MAXSYMLEN;
-    s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*MAXSYMLEN);
-    for (i = s->irep->slen; i < MAXMSYMLEN; i++) {
-      static const mrb_sym mrb_sym_zero = { 0 };
-      s->irep->syms[i] = mrb_sym_zero;
-    }
-    s->irep->slen = MAXMSYMLEN;
+  }
+  if (s->irep->slen >= s->scapa) {
+    s->scapa *= 2;
+    s->irep->syms = (mrb_sym*)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*s->scapa);
   }
   s->irep->syms[s->irep->slen] = sym;
@@ -574,6 +655,10 @@
 }
 
-#define sym(x) ((mrb_sym)(intptr_t)(x))
-#define lv_name(lv) sym((lv)->car)
+#define nint(x) ((int)(intptr_t)(x))
+#define nchar(x) ((char)(intptr_t)(x))
+#define nsym(x) ((mrb_sym)(intptr_t)(x))
+
+#define lv_name(lv) nsym((lv)->car)
+
 static int
 lv_idx(codegen_scope *s, mrb_sym id)
@@ -597,5 +682,4 @@
   struct loopinfo *lp;
   node *n2;
-  mrb_code c;
 
   /* generate receiver */
@@ -603,7 +687,4 @@
   /* generate loop-block */
   s = scope_new(s->mrb, s, NULL);
-  if (s == NULL) {
-    raise_error(prev, "unexpected scope");
-  }
 
   push();                       /* push for a block parameter */
@@ -611,5 +692,5 @@
   /* generate loop variable */
   n2 = tree->car;
-  genop(s, MKOP_Ax(OP_ENTER, 0x40000));
+  genop_W(s, OP_ENTER, 0x40000);
   if (n2->car && !n2->car->cdr && !n2->cdr) {
     gen_assignment(s, n2->car->car, 1, NOVAL);
@@ -625,16 +706,13 @@
   codegen(s, tree->cdr->cdr->car, VAL);
   pop();
-  if (s->pc > 0) {
-    c = s->iseq[s->pc-1];
-    if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel)
-      genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
-  }
+  gen_return(s, OP_RETURN, cursp());
   loop_pop(s, NOVAL);
   scope_finish(s);
   s = prev;
-  genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK));
+  genop_2(s, OP_BLOCK, cursp(), s->irep->rlen-1);
+  push();pop(); /* space for a block */
   pop();
-  idx = new_msym(s, mrb_intern_lit(s->mrb, "each"));
-  genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0));
+  idx = new_sym(s, mrb_intern_lit(s->mrb, "each"));
+  genop_3(s, OP_SENDB, cursp(), idx, 0);
 }
 
@@ -642,10 +720,6 @@
 lambda_body(codegen_scope *s, node *tree, int blk)
 {
-  mrb_code c;
   codegen_scope *parent = s;
   s = scope_new(s->mrb, s, tree->car);
-  if (s == NULL) {
-    raise_error(parent, "unexpected scope");
-  }
 
   s->mscope = !blk;
@@ -653,45 +727,59 @@
   if (blk) {
     struct loopinfo *lp = loop_push(s, LOOP_BLOCK);
-    lp->pc1 = new_label(s);
+    lp->pc0 = new_label(s);
   }
   tree = tree->cdr;
-  if (tree->car) {
+  if (tree->car == NULL) {
+    genop_W(s, OP_ENTER, 0);
+  }
+  else {
     mrb_aspec a;
     int ma, oa, ra, pa, ka, kd, ba;
     int pos, i;
-    node *n, *opt;
-
+    node *opt;
+    node *margs, *pargs;
+    node *tail;
+
+    /* mandatory arguments */
     ma = node_len(tree->car->car);
-    n = tree->car->car;
-    while (n) {
-      n = n->cdr;
-    }
+    margs = tree->car->car;
+    tail = tree->car->cdr->cdr->cdr->cdr;
+
+    /* optional arguments */
     oa = node_len(tree->car->cdr->car);
+    /* rest argument? */
     ra = tree->car->cdr->cdr->car ? 1 : 0;
+    /* mandatory arugments after rest argument */
     pa = node_len(tree->car->cdr->cdr->cdr->car);
-    ka = kd = 0;
-    ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0;
+    pargs = tree->car->cdr->cdr->cdr->car;
+    /* keyword arguments */
+    ka = tail? node_len(tail->cdr->car) : 0;
+    /* keyword dictionary? */
+    kd = tail && tail->cdr->cdr->car? 1 : 0;
+    /* block argument? */
+    ba = tail && tail->cdr->cdr->cdr->car ? 1 : 0;
 
     if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) {
       codegen_error(s, "too many formal arguments");
     }
-    a = ((mrb_aspec)(ma & 0x1f) << 18)
-      | ((mrb_aspec)(oa & 0x1f) << 13)
-      | ((ra & 1) << 12)
-      | ((pa & 0x1f) << 7)
-      | ((ka & 0x1f) << 2)
-      | ((kd & 1)<< 1)
-      | (ba & 1);
-    s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */
-      | ((ra & 1) << 5)
-      | (pa & 0x1f);
-    genop(s, MKOP_Ax(OP_ENTER, a));
+    a = MRB_ARGS_REQ(ma)
+      | MRB_ARGS_OPT(oa)
+      | (ra? MRB_ARGS_REST() : 0)
+      | MRB_ARGS_POST(pa)
+      | MRB_ARGS_KEY(ka, kd)
+      | (ba? MRB_ARGS_BLOCK() : 0);
+    s->ainfo = (((ma+oa) & 0x3f) << 7) /* (12bits = 5:1:5:1) */
+      | ((ra & 0x1) << 6)
+      | ((pa & 0x1f) << 1)
+      | ((ka | kd) != 0 ? 0x01 : 0x00);
+    genop_W(s, OP_ENTER, a);
+    /* generate jump table for optional arguments initializer */
     pos = new_label(s);
     for (i=0; i<oa; i++) {
       new_label(s);
-      genop(s, MKOP_sBx(OP_JMP, 0));
+      genjmp(s, OP_JMP, 0);
     }
     if (oa > 0) {
-      genop(s, MKOP_sBx(OP_JMP, 0));
+      genjmp(s, OP_JMP, 0);
     }
     opt = tree->car->cdr->car;
@@ -700,29 +788,87 @@
       int idx;
 
-      dispatch(s, pos+i);
+      dispatch(s, pos+i*3+1);
       codegen(s, opt->car->cdr, VAL);
-      idx = lv_idx(s, (mrb_sym)(intptr_t)opt->car->car);
       pop();
-      genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL);
+      idx = lv_idx(s, nsym(opt->car->car));
+      gen_move(s, idx, cursp(), 0);
       i++;
       opt = opt->cdr;
     }
     if (oa > 0) {
-      dispatch(s, pos+i);
-    }
-  }
+      dispatch(s, pos+i*3+1);
+    }
+
+    /* keyword arguments */
+    if (tail) {
+      node *kwds = tail->cdr->car;
+      int kwrest = 0;
+
+      if (tail->cdr->cdr->car) {
+        kwrest = 1;
+      }
+      mrb_assert(nint(tail->car) == NODE_ARGS_TAIL);
+      mrb_assert(node_len(tail) == 4);
+
+      while (kwds) {
+        int jmpif_key_p, jmp_def_set = -1;
+        node *kwd = kwds->car, *def_arg = kwd->cdr->cdr->car;
+        mrb_sym kwd_sym = nsym(kwd->cdr->car);
+
+        mrb_assert(nint(kwd->car) == NODE_KW_ARG);
+
+        if (def_arg) {
+          genop_2(s, OP_KEY_P, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
+          jmpif_key_p = genjmp2(s, OP_JMPIF, lv_idx(s, kwd_sym), 0, 0);
+          codegen(s, def_arg, VAL);
+          pop();
+          gen_move(s, lv_idx(s, kwd_sym), cursp(), 0);
+          jmp_def_set = genjmp(s, OP_JMP, 0);
+          dispatch(s, jmpif_key_p);
+        }
+        genop_2(s, OP_KARG, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
+        if (jmp_def_set != -1) {
+          dispatch(s, jmp_def_set);
+        }
+        i++;
+
+        kwds = kwds->cdr;
+      }
+      if (tail->cdr->car && !kwrest) {
+        genop_0(s, OP_KEYEND);
+      }
+    }
+
+    /* argument destructuring */
+    if (margs) {
+      node *n = margs;
+
+      pos = 1;
+      while (n) {
+        if (nint(n->car->car) == NODE_MASGN) {
+          gen_vmassignment(s, n->car->cdr->car, pos, NOVAL);
+        }
+        pos++;
+        n = n->cdr;
+      }
+    }
+    if (pargs) {
+      node *n = margs;
+
+      pos = ma+oa+ra+1;
+      while (n) {
+        if (nint(n->car->car) == NODE_MASGN) {
+          gen_vmassignment(s, n->car->cdr->car, pos, NOVAL);
+        }
+        pos++;
+        n = n->cdr;
+      }
+    }
+  }
+
   codegen(s, tree->cdr->car, VAL);
   pop();
   if (s->pc > 0) {
-    c = s->iseq[s->pc-1];
-    if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) {
-      if (s->nregs == 0) {
-        genop(s, MKOP_A(OP_LOADNIL, 0));
-        genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
-      }
-      else {
-        genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
-      }
-    }
+    gen_return(s, OP_RETURN, cursp());
   }
   if (blk) {
@@ -737,23 +883,9 @@
 {
   codegen_scope *scope = scope_new(s->mrb, s, tree->car);
-  if (scope == NULL) {
-    raise_error(s, "unexpected scope");
-  }
 
   codegen(scope, tree->cdr, VAL);
+  gen_return(scope, OP_RETURN, scope->sp-1);
   if (!s->iseq) {
-    genop(scope, MKOP_A(OP_STOP, 0));
-  }
-  else if (!val) {
-    genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
-  }
-  else {
-    if (scope->nregs == 0) {
-      genop(scope, MKOP_A(OP_LOADNIL, 0));
-      genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
-    }
-    else {
-      genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL);
-    }
+    genop_0(scope, OP_STOP);
   }
   scope_finish(scope);
@@ -769,5 +901,5 @@
 {
   while (t) {
-    if ((intptr_t)t->car->car == NODE_SPLAT) return FALSE;
+    if (nint(t->car->car) == NODE_SPLAT) return FALSE;
     t = t->cdr;
   }
@@ -782,5 +914,5 @@
   char *name2;
 
-  name = mrb_sym2name_len(s->mrb, a, &len);
+  name = mrb_sym_name_len(s->mrb, a, &len);
   name2 = (char *)codegen_palloc(s,
                                  (size_t)len
@@ -805,10 +937,10 @@
 
   while (t) {
-    is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */
+    is_splat = nint(t->car->car) == NODE_SPLAT; /* splat mode */
     if (
       n+extra >= CALL_MAXARGS - 1 /* need to subtract one because vm.c expects an array if n == CALL_MAXARGS */
       || is_splat) {
       if (val) {
-        if (is_splat && n == 0 && (intptr_t)t->car->cdr->car == NODE_ARRAY) {
+        if (is_splat && n == 0 && nint(t->car->cdr->car) == NODE_ARRAY) {
           codegen(s, t->car->cdr, VAL);
           pop();
@@ -816,13 +948,18 @@
         else {
           pop_n(n);
-          genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
+          if (n == 0 && is_splat) {
+            genop_1(s, OP_LOADNIL, cursp());
+          }
+          else {
+            genop_2(s, OP_ARRAY, cursp(), n);
+          }
           push();
           codegen(s, t->car, VAL);
           pop(); pop();
           if (is_splat) {
-            genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+            genop_1(s, OP_ARYCAT, cursp());
           }
           else {
-            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+            genop_1(s, OP_ARYPUSH, cursp());
           }
         }
@@ -832,9 +969,9 @@
           codegen(s, t->car, VAL);
           pop(); pop();
-          if ((intptr_t)t->car->car == NODE_SPLAT) {
-            genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+          if (nint(t->car->car) == NODE_SPLAT) {
+            genop_1(s, OP_ARYCAT, cursp());
           }
           else {
-            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+            genop_1(s, OP_ARYPUSH, cursp());
           }
           t = t->cdr;
@@ -860,6 +997,6 @@
 gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
 {
-  mrb_sym sym = name ? name : sym(tree->cdr->car);
-  int idx, skip = 0;
+  mrb_sym sym = name ? name : nsym(tree->cdr->car);
+  int skip = 0;
   int n = 0, noop = 0, sendv = 0, blk = 0;
 
@@ -867,14 +1004,7 @@
   if (safe) {
     int recv = cursp()-1;
-    genop(s, MKOP_A(OP_LOADNIL, cursp()));
-    push();
-    genop(s, MKOP_AB(OP_MOVE, cursp(), recv));
-    push(); pop();              /* space for a block */
-    pop();
-    idx = new_msym(s, mrb_intern_lit(s->mrb, "=="));
-    genop(s, MKOP_ABC(OP_EQ, cursp(), idx, 1));
-    skip = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
-  }
-  idx = new_msym(s, sym);
+    gen_move(s, cursp(), recv, 1);
+    skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val);
+  }
   tree = tree->cdr->cdr->car;
   if (tree) {
@@ -885,12 +1015,13 @@
     }
   }
-  if (sp) {
+  if (sp) {                     /* last argument pushed (attr=) */
     if (sendv) {
+      gen_move(s, cursp(), sp, 0);
       pop();
-      genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp));
+      genop_1(s, OP_ARYPUSH, cursp());
       push();
     }
     else {
-      genop(s, MKOP_AB(OP_MOVE, cursp(), sp));
+      gen_move(s, cursp(), sp, 0);
       push();
       n++;
@@ -901,7 +1032,5 @@
     codegen(s, tree->cdr, VAL);
     pop();
-  }
-  else {
-    blk = cursp();
+    blk = 1;
   }
   push();pop();
@@ -909,40 +1038,41 @@
   {
     mrb_int symlen;
-    const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen);
+    const char *symname = mrb_sym_name_len(s->mrb, sym, &symlen);
 
     if (!noop && symlen == 1 && symname[0] == '+' && n == 1)  {
-      genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val);
+      gen_addsub(s, OP_ADD, cursp());
     }
     else if (!noop && symlen == 1 && symname[0] == '-' && n == 1)  {
-      genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val);
+      gen_addsub(s, OP_SUB, cursp());
     }
     else if (!noop && symlen == 1 && symname[0] == '*' && n == 1)  {
-      genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n));
+      genop_1(s, OP_MUL, cursp());
     }
     else if (!noop && symlen == 1 && symname[0] == '/' && n == 1)  {
-      genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n));
+      genop_1(s, OP_DIV, cursp());
     }
     else if (!noop && symlen == 1 && symname[0] == '<' && n == 1)  {
-      genop(s, MKOP_ABC(OP_LT, cursp(), idx, n));
+      genop_1(s, OP_LT, cursp());
     }
     else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1)  {
-      genop(s, MKOP_ABC(OP_LE, cursp(), idx, n));
+      genop_1(s, OP_LE, cursp());
     }
     else if (!noop && symlen == 1 && symname[0] == '>' && n == 1)  {
-      genop(s, MKOP_ABC(OP_GT, cursp(), idx, n));
+      genop_1(s, OP_GT, cursp());
     }
     else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1)  {
-      genop(s, MKOP_ABC(OP_GE, cursp(), idx, n));
+      genop_1(s, OP_GE, cursp());
     }
     else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1)  {
-      genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n));
+      genop_1(s, OP_EQ, cursp());
     }
     else {
-      if (sendv) n = CALL_MAXARGS;
-      if (blk > 0) {                   /* no block */
-        genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n));
+      int idx = new_sym(s, sym);
+
+      if (sendv) {
+        genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx);
       }
       else {
-        genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n));
+        genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), idx, n);
       }
     }
@@ -960,17 +1090,19 @@
 {
   int idx;
-  int type = (intptr_t)tree->car;
+  int type = nint(tree->car);
 
   tree = tree->cdr;
   switch (type) {
   case NODE_GVAR:
-    idx = new_sym(s, sym(tree));
-    genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val);
-    break;
+    idx = new_sym(s, nsym(tree));
+    genop_2(s, OP_SETGV, sp, idx);
+    break;
+  case NODE_ARG:
   case NODE_LVAR:
-    idx = lv_idx(s, sym(tree));
+    idx = lv_idx(s, nsym(tree));
     if (idx > 0) {
       if (idx != sp) {
-        genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val);
+        gen_move(s, idx, sp, val);
+        if (val && on_eval(s)) genop_0(s, OP_NOP);
       }
       break;
@@ -981,7 +1113,7 @@
 
       while (up) {
-        idx = lv_idx(up, sym(tree));
+        idx = lv_idx(up, nsym(tree));
         if (idx > 0) {
-          genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val);
+          genop_3(s, OP_SETUPVAR, sp, idx, lv);
           break;
         }
@@ -991,23 +1123,27 @@
     }
     break;
+  case NODE_NVAR:
+    idx = nint(tree);
+    codegen_error(s, "Can't assign to numbered parameter");
+    break;
   case NODE_IVAR:
-    idx = new_sym(s, sym(tree));
-    genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val);
+    idx = new_sym(s, nsym(tree));
+    genop_2(s, OP_SETIV, sp, idx);
     break;
   case NODE_CVAR:
-    idx = new_sym(s, sym(tree));
-    genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val);
+    idx = new_sym(s, nsym(tree));
+    genop_2(s, OP_SETCV, sp, idx);
     break;
   case NODE_CONST:
-    idx = new_sym(s, sym(tree));
-    genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val);
+    idx = new_sym(s, nsym(tree));
+    genop_2(s, OP_SETCONST, sp, idx);
     break;
   case NODE_COLON2:
-    idx = new_sym(s, sym(tree->cdr));
-    genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL);
+    gen_move(s, cursp(), sp, 0);
     push();
     codegen(s, tree->car, VAL);
     pop_n(2);
-    genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val);
+    idx = new_sym(s, nsym(tree->cdr));
+    genop_2(s, OP_SETMCNST, sp, idx);
     break;
 
@@ -1015,9 +1151,9 @@
   case NODE_SCALL:
     push();
-    gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL,
+    gen_call(s, tree, attrsym(s, nsym(tree->cdr->car)), sp, NOVAL,
              type == NODE_SCALL);
     pop();
     if (val) {
-      genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val);
+      gen_move(s, cursp(), sp, 0);
     }
     break;
@@ -1050,6 +1186,10 @@
     n = 0;
     while (t) {
-      genop(s, MKOP_ABC(OP_AREF, cursp(), rhs, n));
-      gen_assignment(s, t->car, cursp(), NOVAL);
+      int sp = cursp();
+
+      genop_3(s, OP_AREF, sp, rhs, n);
+      push();
+      gen_assignment(s, t->car, sp, NOVAL);
+      pop();
       n++;
       t = t->cdr;
@@ -1065,15 +1205,10 @@
       }
     }
-    if (val) {
-      genop(s, MKOP_AB(OP_MOVE, cursp(), rhs));
-    }
-    else {
-      pop();
-    }
-    push_n(post);
-    pop_n(post);
-    genop(s, MKOP_ABC(OP_APOST, cursp(), n, post));
+    gen_move(s, cursp(), rhs, val);
+    push_n(post+1);
+    pop_n(post+1);
+    genop_3(s, OP_APOST, cursp(), n, post);
     n = 1;
-    if (t->car) {               /* rest */
+    if (t->car && t->car != (node*)-1) { /* rest */
       gen_assignment(s, t->car, cursp(), NOVAL);
     }
@@ -1086,6 +1221,6 @@
       }
     }
-    if (!val) {
-      push();
+    if (val) {
+      gen_move(s, cursp(), rhs, 0);
     }
   }
@@ -1093,10 +1228,11 @@
 
 static void
-gen_send_intern(codegen_scope *s)
+gen_intern(codegen_scope *s)
 {
   pop();
-  genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0));
+  genop_1(s, OP_INTERN, cursp());
   push();
 }
+
 static void
 gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
@@ -1106,7 +1242,7 @@
 
     while (tree) {
-      switch ((intptr_t)tree->car->car) {
+      switch (nint(tree->car->car)) {
       case NODE_STR:
-        if ((tree->cdr == NULL) && ((intptr_t)tree->car->cdr->cdr == 0))
+        if ((tree->cdr == NULL) && (nint(tree->car->cdr->cdr) == 0))
           break;
         /* fall through */
@@ -1121,13 +1257,13 @@
           ++i;
           if (sym)
-            gen_send_intern(s);
+            gen_intern(s);
         }
         break;
       }
-      if (j >= 2) {
+      while (j >= 2) {
         pop(); pop();
-        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+        genop_1(s, OP_STRCAT, cursp());
         push();
-        j = 1;
+        j--;
       }
       tree = tree->cdr;
@@ -1136,13 +1272,13 @@
       ++i;
       if (sym)
-        gen_send_intern(s);
+        gen_intern(s);
     }
     pop_n(i);
-    genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i));
+    genop_2(s, OP_ARRAY, cursp(), i);
     push();
   }
   else {
     while (tree) {
-      switch ((intptr_t)tree->car->car) {
+      switch (nint(tree->car->car)) {
       case NODE_BEGIN: case NODE_BLOCK:
         codegen(s, tree->car, NOVAL);
@@ -1158,7 +1294,8 @@
   int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg));
 
-  genop(s, MKOP_ABx(OP_ERR, 1, idx));
-}
-
+  genop_1(s, OP_ERR, idx);
+}
+
+#ifndef MRB_WITHOUT_FLOAT
 static double
 readint_float(codegen_scope *s, const char *p, int base)
@@ -1186,4 +1323,5 @@
   return f;
 }
+#endif
 
 static mrb_int
@@ -1233,10 +1371,8 @@
 gen_retval(codegen_scope *s, node *tree)
 {
-  if ((intptr_t)tree->car == NODE_SPLAT) {
-    genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), 0));
-    push();
+  if (nint(tree->car) == NODE_SPLAT) {
     codegen(s, tree, VAL);
-    pop(); pop();
-    genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+    pop();
+    genop_1(s, OP_ARYDUP, cursp());
   }
   else {
@@ -1254,5 +1390,5 @@
   if (!tree) {
     if (val) {
-      genop(s, MKOP_A(OP_LOADNIL, cursp()));
+      genop_1(s, OP_LOADNIL, cursp());
       push();
     }
@@ -1265,12 +1401,15 @@
   }
   if (s->irep && s->filename_index != tree->filename_index) {
-    s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
-    mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc);
+    mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
+    const char *filename = mrb_sym_name_len(s->mrb, fname, NULL);
+
+    mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
+                               filename, s->lines, s->debug_start_pos, s->pc);
     s->debug_start_pos = s->pc;
     s->filename_index = tree->filename_index;
-    s->filename = mrb_parser_get_filename(s->parser, tree->filename_index);
-  }
-
-  nt = (intptr_t)tree->car;
+    s->filename_sym = mrb_parser_get_filename(s->parser, tree->filename_index);
+  }
+
+  nt = nint(tree->car);
   s->lineno = tree->lineno;
   tree = tree->cdr;
@@ -1278,5 +1417,5 @@
   case NODE_BEGIN:
     if (val && !tree) {
-      genop(s, MKOP_A(OP_LOADNIL, cursp()));
+      genop_1(s, OP_LOADNIL, cursp());
       push();
     }
@@ -1289,16 +1428,16 @@
   case NODE_RESCUE:
     {
-      int onerr, noexc, exend, pos1, pos2, tmp;
+      int noexc, exend, pos1, pos2, tmp;
       struct loopinfo *lp;
 
       if (tree->car == NULL) goto exit;
-      onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
       lp = loop_push(s, LOOP_BEGIN);
-      lp->pc1 = onerr;
+      lp->pc0 = new_label(s);
+      lp->pc1 = genjmp(s, OP_ONERR, 0);
       codegen(s, tree->car, VAL);
       pop();
       lp->type = LOOP_RESCUE;
-      noexc = genop(s, MKOP_Bx(OP_JMP, 0));
-      dispatch(s, onerr);
+      noexc = genjmp(s, OP_JMP, 0);
+      dispatch(s, lp->pc1);
       tree = tree->cdr;
       exend = 0;
@@ -1308,5 +1447,5 @@
         int exc = cursp();
 
-        genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0));
+        genop_1(s, OP_EXCEPT, exc);
         push();
         while (n2) {
@@ -1317,9 +1456,10 @@
           pos2 = 0;
           do {
-            if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) {
+            if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) {
               codegen(s, n4->car, VAL);
-              genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
+              gen_move(s, cursp(), exc, 0);
+              push_n(2); pop_n(2); /* space for one arg and a block */
               pop();
-              genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
+              genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1);
             }
             else {
@@ -1328,11 +1468,11 @@
               }
               else {
-                genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError"))));
+                genop_2(s, OP_GETCONST, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "StandardError")));
                 push();
               }
               pop();
-              genop(s, MKOP_ABC(OP_RESCUE, exc, cursp(), 1));
+              genop_2(s, OP_RESCUE, exc, cursp());
             }
-            tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+            tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val);
             pos2 = tmp;
             if (n4) {
@@ -1340,5 +1480,5 @@
             }
           } while (n4);
-          pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
+          pos1 = genjmp(s, OP_JMP, 0);
           dispatch_linked(s, pos2);
 
@@ -1351,5 +1491,5 @@
             if (val) pop();
           }
-          tmp = genop(s, MKOP_sBx(OP_JMP, exend));
+          tmp = genjmp(s, OP_JMP, exend);
           exend = tmp;
           n2 = n2->cdr;
@@ -1358,5 +1498,5 @@
         if (pos1) {
           dispatch(s, pos1);
-          genop(s, MKOP_A(OP_RAISE, exc));
+          genop_1(s, OP_RAISE, exc);
         }
       }
@@ -1364,5 +1504,5 @@
       tree = tree->cdr;
       dispatch(s, noexc);
-      genop(s, MKOP_A(OP_POPERR, 1));
+      genop_1(s, OP_POPERR, 1);
       if (tree->car) {
         codegen(s, tree->car, val);
@@ -1378,16 +1518,14 @@
   case NODE_ENSURE:
     if (!tree->cdr || !tree->cdr->cdr ||
-        ((intptr_t)tree->cdr->cdr->car == NODE_BEGIN &&
+        (nint(tree->cdr->cdr->car) == NODE_BEGIN &&
          tree->cdr->cdr->cdr)) {
       int idx;
-      int epush = s->pc;
-
-      genop(s, MKOP_Bx(OP_EPUSH, 0));
+
       s->ensure_level++;
+      idx = scope_body(s, tree->cdr, NOVAL);
+      genop_1(s, OP_EPUSH, idx);
       codegen(s, tree->car, val);
-      idx = scope_body(s, tree->cdr, NOVAL);
-      s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx);
       s->ensure_level--;
-      genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL);
+      genop_1(s, OP_EPOP, 1);
     }
     else {                      /* empty ensure ignored */
@@ -1400,5 +1538,5 @@
       int idx = lambda_body(s, tree, 1);
 
-      genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA));
+      genop_2(s, OP_LAMBDA, cursp(), idx);
       push();
     }
@@ -1409,5 +1547,5 @@
       int idx = lambda_body(s, tree, 1);
 
-      genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK));
+      genop_2(s, OP_BLOCK, cursp(), idx);
       push();
     }
@@ -1416,12 +1554,12 @@
   case NODE_IF:
     {
-      int pos1, pos2;
-      node *e = tree->cdr->cdr->car;
+      int pos1, pos2, nil_p = FALSE;
+      node *elsepart = tree->cdr->cdr->car;
 
       if (!tree->car) {
-        codegen(s, e, val);
+        codegen(s, elsepart, val);
         goto exit;
       }
-      switch ((intptr_t)tree->car->car) {
+      switch (nint(tree->car->car)) {
       case NODE_TRUE:
       case NODE_INT:
@@ -1431,30 +1569,57 @@
       case NODE_FALSE:
       case NODE_NIL:
-        codegen(s, e, val);
+        codegen(s, elsepart, val);
         goto exit;
-      }
-      codegen(s, tree->car, VAL);
+      case NODE_CALL:
+        {
+          node *n = tree->car->cdr;
+          mrb_sym mid = nsym(n->cdr->car);
+          mrb_sym mnil = mrb_intern_lit(s->mrb, "nil?");
+          if (mid == mnil && n->cdr->cdr->car == NULL) {
+            nil_p = TRUE;
+            codegen(s, n->car, VAL);
+          }
+        }
+        break;
+      }
+      if (!nil_p) {
+        codegen(s, tree->car, VAL);
+      }
       pop();
-      pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL);
-
-      codegen(s, tree->cdr->car, val);
-      if (e) {
+      if (val || tree->cdr->car) {
+        if (nil_p) {
+          pos2 = genjmp2(s, OP_JMPNIL, cursp(), 0, val);
+          pos1 = genjmp(s, OP_JMP, 0);
+          dispatch(s, pos2);
+        }
+        else {
+          pos1 = genjmp2(s, OP_JMPNOT, cursp(), 0, val);
+        }
+        codegen(s, tree->cdr->car, val);
         if (val) pop();
-        pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
-        dispatch(s, pos1);
-        codegen(s, e, val);
-        dispatch(s, pos2);
-      }
-      else {
-        if (val) {
-          pop();
-          pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
+        if (elsepart || val) {
+          pos2 = genjmp(s, OP_JMP, 0);
           dispatch(s, pos1);
-          genop(s, MKOP_A(OP_LOADNIL, cursp()));
+          codegen(s, elsepart, val);
           dispatch(s, pos2);
-          push();
         }
         else {
           dispatch(s, pos1);
+        }
+      }
+      else {                    /* empty then-part */
+        if (elsepart) {
+          if (nil_p) {
+            pos1 = genjmp2(s, OP_JMPNIL, cursp(), 0, val);
+          }
+          else {
+            pos1 = genjmp2(s, OP_JMPIF, cursp(), 0, val);
+          }
+          codegen(s, elsepart, val);
+          dispatch(s, pos1);
+        }
+        else if (val && !nil_p) {
+          genop_1(s, OP_LOADNIL, cursp());
+          push();
         }
       }
@@ -1468,5 +1633,5 @@
       codegen(s, tree->car, VAL);
       pop();
-      pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
+      pos = genjmp2(s, OP_JMPNOT, cursp(), 0, val);
       codegen(s, tree->cdr, val);
       dispatch(s, pos);
@@ -1480,5 +1645,5 @@
       codegen(s, tree->car, VAL);
       pop();
-      pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
+      pos = genjmp2(s, OP_JMPIF, cursp(), 0, val);
       codegen(s, tree->cdr, val);
       dispatch(s, pos);
@@ -1490,5 +1655,6 @@
       struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
 
-      lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
+      lp->pc0 = new_label(s);
+      lp->pc1 = genjmp(s, OP_JMP, 0);
       lp->pc2 = new_label(s);
       codegen(s, tree->cdr, NOVAL);
@@ -1496,5 +1662,5 @@
       codegen(s, tree->car, VAL);
       pop();
-      genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc));
+      genjmp2(s, OP_JMPIF, cursp(), lp->pc2, NOVAL);
 
       loop_pop(s, val);
@@ -1506,5 +1672,6 @@
       struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
 
-      lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
+      lp->pc0 = new_label(s);
+      lp->pc1 = genjmp(s, OP_JMP, 0);
       lp->pc2 = new_label(s);
       codegen(s, tree->cdr, NOVAL);
@@ -1512,5 +1679,5 @@
       codegen(s, tree->car, VAL);
       pop();
-      genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc));
+      genjmp2(s, OP_JMPNOT, cursp(), lp->pc2, NOVAL);
 
       loop_pop(s, val);
@@ -1541,11 +1708,11 @@
           codegen(s, n->car, VAL);
           if (head) {
-            genop(s, MKOP_AB(OP_MOVE, cursp(), head));
-            pop();
-            if ((intptr_t)n->car->car == NODE_SPLAT) {
-              genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
+            gen_move(s, cursp(), head, 0);
+            push(); push(); pop(); pop(); pop();
+            if (nint(n->car->car) == NODE_SPLAT) {
+              genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1);
             }
             else {
-              genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
+              genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "===")), 1);
             }
           }
@@ -1553,15 +1720,15 @@
             pop();
           }
-          tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+          tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, NOVAL);
           pos2 = tmp;
           n = n->cdr;
         }
         if (tree->car->car) {
-          pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
+          pos1 = genjmp(s, OP_JMP, 0);
           dispatch_linked(s, pos2);
         }
         codegen(s, tree->car->cdr, val);
         if (val) pop();
-        tmp = genop(s, MKOP_sBx(OP_JMP, pos3));
+        tmp = genjmp(s, OP_JMP, pos3);
         pos3 = tmp;
         if (pos1) dispatch(s, pos1);
@@ -1570,9 +1737,9 @@
       if (val) {
         int pos = cursp();
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         if (pos3) dispatch_linked(s, pos3);
         if (head) pop();
         if (cursp() != pos) {
-          genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
+          gen_move(s, cursp(), pos, 0);
         }
         push();
@@ -1606,5 +1773,5 @@
     if (val) {
       pop(); pop();
-      genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE));
+      genop_1(s, OP_RANGE_INC, cursp());
       push();
     }
@@ -1616,5 +1783,5 @@
     if (val) {
       pop(); pop();
-      genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE));
+      genop_1(s, OP_RANGE_EXC, cursp());
       push();
     }
@@ -1623,9 +1790,9 @@
   case NODE_COLON2:
     {
-      int sym = new_sym(s, sym(tree->cdr));
+      int sym = new_sym(s, nsym(tree->cdr));
 
       codegen(s, tree->car, VAL);
       pop();
-      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      genop_2(s, OP_GETMCNST, cursp(), sym);
       if (val) push();
     }
@@ -1634,8 +1801,8 @@
   case NODE_COLON3:
     {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_A(OP_OCLASS, cursp()));
-      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      int sym = new_sym(s, nsym(tree));
+
+      genop_1(s, OP_OCLASS, cursp());
+      genop_2(s, OP_GETMCNST, cursp(), sym);
       if (val) push();
     }
@@ -1650,5 +1817,5 @@
         if (val) {
           pop_n(n);
-          genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
+          genop_2(s, OP_ARRAY, cursp(), n);
           push();
         }
@@ -1661,4 +1828,5 @@
 
   case NODE_HASH:
+  case NODE_KW_HASH:
     {
       int len = 0;
@@ -1666,14 +1834,39 @@
 
       while (tree) {
-        codegen(s, tree->car->car, val);
-        codegen(s, tree->car->cdr, val);
-        len++;
+        if (nint(tree->car->car->car) == NODE_KW_REST_ARGS) {
+          if (len > 0) {
+            pop_n(len*2);
+            if (!update) {
+              genop_2(s, OP_HASH, cursp(), len);
+            }
+            else {
+              pop();
+              genop_2(s, OP_HASHADD, cursp(), len);
+            }
+            push();
+          }
+          codegen(s, tree->car->cdr, VAL);
+          if (len > 0 || update) {
+            pop(); pop();
+            genop_1(s, OP_HASHCAT, cursp());
+            push();
+          }
+          update = TRUE;
+          len = 0;
+        }
+        else {
+          codegen(s, tree->car->car, val);
+          codegen(s, tree->car->cdr, val);
+          len++;
+        }
         tree = tree->cdr;
-        if (val && len == 126) {
+        if (val && len == 255) {
           pop_n(len*2);
-          genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
-          if (update) {
+          if (!update) {
+            genop_2(s, OP_HASH, cursp(), len);
+          }
+          else {
             pop();
-            genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
+            genop_2(s, OP_HASHADD, cursp(), len);
           }
           push();
@@ -1684,8 +1877,12 @@
       if (val) {
         pop_n(len*2);
-        genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
-        if (update) {
+        if (!update) {
+          genop_2(s, OP_HASH, cursp(), len);
+        }
+        else {
           pop();
-          genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
+          if (len > 0) {
+            genop_2(s, OP_HASHADD, cursp(), len);
+          }
         }
         push();
@@ -1710,5 +1907,5 @@
       int rhs = cursp();
 
-      if ((intptr_t)t->car == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
+      if (nint(t->car) == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
         /* fixed rhs */
         t = t->cdr;
@@ -1728,5 +1925,5 @@
             }
             else {
-              genop(s, MKOP_A(OP_LOADNIL, rhs+n));
+              genop_1(s, OP_LOADNIL, rhs+n);
               gen_assignment(s, t->car, rhs+n, NOVAL);
             }
@@ -1752,5 +1949,5 @@
               rn = len - post - n;
             }
-            genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn));
+            genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn);
             gen_assignment(s, t->car, cursp(), NOVAL);
             n += rn;
@@ -1767,5 +1964,5 @@
         pop_n(len);
         if (val) {
-          genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len));
+          genop_2(s, OP_ARRAY, rhs, len);
           push();
         }
@@ -1784,16 +1981,16 @@
   case NODE_OP_ASGN:
     {
-      mrb_sym sym = sym(tree->cdr->car);
+      mrb_sym sym = nsym(tree->cdr->car);
       mrb_int len;
-      const char *name = mrb_sym2name_len(s->mrb, sym, &len);
+      const char *name = mrb_sym_name_len(s->mrb, sym, &len);
       int idx, callargs = -1, vsp = -1;
 
       if ((len == 2 && name[0] == '|' && name[1] == '|') &&
-          ((intptr_t)tree->car->car == NODE_CONST ||
-           (intptr_t)tree->car->car == NODE_CVAR)) {
+          (nint(tree->car->car) == NODE_CONST ||
+           nint(tree->car->car) == NODE_CVAR)) {
         int onerr, noexc, exc;
         struct loopinfo *lp;
 
-        onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
+        onerr = genjmp(s, OP_ONERR, 0);
         lp = loop_push(s, LOOP_BEGIN);
         lp->pc1 = onerr;
@@ -1801,14 +1998,16 @@
         codegen(s, tree->car, VAL);
         lp->type = LOOP_RESCUE;
-        genop(s, MKOP_A(OP_POPERR, 1));
-        noexc = genop(s, MKOP_Bx(OP_JMP, 0));
+        genop_1(s, OP_POPERR, 1);
+        noexc = genjmp(s, OP_JMP, 0);
         dispatch(s, onerr);
-        genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0));
-        genop(s, MKOP_A(OP_LOADF, exc));
+        genop_1(s, OP_EXCEPT, exc);
+        genop_1(s, OP_LOADF, exc);
         dispatch(s, noexc);
         loop_pop(s, NOVAL);
       }
-      else if ((intptr_t)tree->car->car == NODE_CALL) {
+      else if (nint(tree->car->car) == NODE_CALL) {
         node *n = tree->car->cdr;
+        int base, i, nargs = 0;
+        callargs = 0;
 
         if (val) {
@@ -1817,35 +2016,24 @@
         }
         codegen(s, n->car, VAL);   /* receiver */
-        idx = new_msym(s, sym(n->cdr->car));
+        idx = new_sym(s, nsym(n->cdr->car));
+        base = cursp()-1;
         if (n->cdr->cdr->car) {
-          int base = cursp()-1;
-          int nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1);
-
-          /* copy receiver and arguments */
+          nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1);
           if (nargs >= 0) {
-            int i;
-
-            genop(s, MKOP_AB(OP_MOVE, cursp(), base));
-            for (i=0; i<nargs; i++) {
-              genop(s, MKOP_AB(OP_MOVE, cursp()+i+1, base+i+1));
-            }
-            push_n(nargs+1);
-            pop_n(nargs+1);
             callargs = nargs;
           }
-          else {
-            /* varargs */
+          else { /* varargs */
             push();
-            genop(s, MKOP_AB(OP_MOVE, cursp(), base));
-            genop(s, MKOP_AB(OP_MOVE, cursp()+1, base+1));
+            nargs = 1;
             callargs = CALL_MAXARGS;
           }
-          genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
-        }
-        else {
-          genop(s, MKOP_AB(OP_MOVE, cursp(), cursp()-1));
-          genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 0));
-          callargs = 0;
-        }
+        }
+        /* copy receiver and arguments */
+        gen_move(s, cursp(), base, 1);
+        for (i=0; i<nargs; i++) {
+          gen_move(s, cursp()+i+1, base+i+1, 1);
+        }
+        push_n(nargs+2);pop_n(nargs+2); /* space for receiver, arguments and a block */
+        genop_3(s, OP_SEND, cursp(), idx, callargs);
         push();
       }
@@ -1861,31 +2049,28 @@
         if (val) {
           if (vsp >= 0) {
-            genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
-          }
-          pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0));
+            gen_move(s, vsp, cursp(), 1);
+          }
+          pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val);
         }
         else {
-          pos = genop_peep(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0), NOVAL);
+          pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val);
         }
         codegen(s, tree->cdr->cdr->car, VAL);
         pop();
         if (val && vsp >= 0) {
-          genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
-        }
-        if ((intptr_t)tree->car->car == NODE_CALL) {
-          mrb_sym m = sym(tree->car->cdr->cdr->car);
-          mrb_sym m2 = attrsym(s, m);
-
-          idx = new_msym(s, m2);
-          pop();
+          gen_move(s, vsp, cursp(), 1);
+        }
+        if (nint(tree->car->car) == NODE_CALL) {
           if (callargs == CALL_MAXARGS) {
-            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
             pop();
-            genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+            genop_1(s, OP_ARYPUSH, cursp());
           }
           else {
             pop_n(callargs);
-            genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs+1));
-          }
+            callargs++;
+          }
+          pop();
+          idx = new_sym(s, attrsym(s, nsym(tree->car->cdr->cdr->car)));
+          genop_3(s, OP_SEND, cursp(), idx, callargs);
         }
         else {
@@ -1899,31 +2084,31 @@
       pop(); pop();
 
-      idx = new_msym(s, sym);
       if (len == 1 && name[0] == '+')  {
-        genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val);
+        gen_addsub(s, OP_ADD, cursp());
       }
       else if (len == 1 && name[0] == '-')  {
-        genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val);
+        gen_addsub(s, OP_SUB, cursp());
       }
       else if (len == 1 && name[0] == '*')  {
-        genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1));
+        genop_1(s, OP_MUL, cursp());
       }
       else if (len == 1 && name[0] == '/')  {
-        genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1));
+        genop_1(s, OP_DIV, cursp());
       }
       else if (len == 1 && name[0] == '<')  {
-        genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1));
+        genop_1(s, OP_LT, cursp());
       }
       else if (len == 2 && name[0] == '<' && name[1] == '=')  {
-        genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1));
+        genop_1(s, OP_LE, cursp());
       }
       else if (len == 1 && name[0] == '>')  {
-        genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1));
+        genop_1(s, OP_GT, cursp());
       }
       else if (len == 2 && name[0] == '>' && name[1] == '=')  {
-        genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1));
+        genop_1(s, OP_GE, cursp());
       }
       else {
-        genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1));
+        idx = new_sym(s, sym);
+        genop_3(s, OP_SEND, cursp(), idx, 1);
       }
       if (callargs < 0) {
@@ -1932,9 +2117,9 @@
       else {
         if (val && vsp >= 0) {
-          genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
+          gen_move(s, vsp, cursp(), 0);
         }
         if (callargs == CALL_MAXARGS) {
           pop();
-          genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+          genop_1(s, OP_ARYPUSH, cursp());
         }
         else {
@@ -1943,6 +2128,6 @@
         }
         pop();
-        idx = new_msym(s, attrsym(s,sym(tree->car->cdr->cdr->car)));
-        genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+        idx = new_sym(s, attrsym(s,nsym(tree->car->cdr->cdr->car)));
+        genop_3(s, OP_SEND, cursp(), idx, callargs);
       }
     }
@@ -1961,5 +2146,5 @@
         if (!s2) break;
       }
-      genop(s, MKOP_ABx(OP_ARGARY, cursp(), (lv & 0xf)));
+      genop_2S(s, OP_ARGARY, cursp(), (lv & 0xf));
       push(); push();         /* ARGARY pushes two values */
       pop(); pop();
@@ -1979,10 +2164,10 @@
       }
       else {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         push(); pop();
       }
       pop_n(n+1);
       if (sendv) n = CALL_MAXARGS;
-      genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n));
+      genop_2(s, OP_SUPER, cursp(), n);
       if (val) push();
     }
@@ -2001,5 +2186,5 @@
       }
       if (s2) ainfo = s2->ainfo;
-      genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)));
+      genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf));
       push(); push(); pop();    /* ARGARY pushes two values */
       if (tree && tree->cdr) {
@@ -2008,5 +2193,5 @@
       }
       pop(); pop();
-      genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS));
+      genop_2(s, OP_SUPER, cursp(), CALL_MAXARGS);
       if (val) push();
     }
@@ -2018,11 +2203,11 @@
     }
     else {
-      genop(s, MKOP_A(OP_LOADNIL, cursp()));
+      genop_1(s, OP_LOADNIL, cursp());
     }
     if (s->loop) {
-      genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN));
+      gen_return(s, OP_RETURN_BLK, cursp());
     }
     else {
-      genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
+      gen_return(s, OP_RETURN, cursp());
     }
     if (val) push();
@@ -2049,8 +2234,9 @@
         }
       }
+      push();pop(); /* space for a block */
       pop_n(n+1);
-      genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)));
+      genop_2S(s, OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf));
       if (sendv) n = CALL_MAXARGS;
-      genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n));
+      genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "call")), n);
       if (val) push();
     }
@@ -2068,8 +2254,8 @@
     else if (s->loop->type == LOOP_NORMAL) {
       if (s->ensure_level > s->loop->ensure_level) {
-        genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
+        genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
       }
       codegen(s, tree, NOVAL);
-      genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc));
+      genjmp(s, OP_JMP, s->loop->pc0);
     }
     else {
@@ -2079,7 +2265,7 @@
       }
       else {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
-      }
-      genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
+        genop_1(s, OP_LOADNIL, cursp());
+      }
+      gen_return(s, OP_RETURN, cursp());
     }
     if (val) push();
@@ -2092,7 +2278,7 @@
     else {
       if (s->ensure_level > s->loop->ensure_level) {
-        genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
-      }
-      genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc));
+        genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
+      }
+      genjmp(s, OP_JMP, s->loop->pc2);
     }
     if (val) push();
@@ -2121,12 +2307,10 @@
         else {
           if (n > 0) {
-            while (n--) {
-              genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL);
-            }
+            genop_1(s, OP_POPERR, n);
           }
           if (s->ensure_level > lp->ensure_level) {
-            genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL);
-          }
-          genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc));
+            genop_1(s, OP_EPOP, s->ensure_level - lp->ensure_level);
+          }
+          genjmp(s, OP_JMP, lp->pc0);
         }
       }
@@ -2137,8 +2321,9 @@
   case NODE_LVAR:
     if (val) {
-      int idx = lv_idx(s, sym(tree));
+      int idx = lv_idx(s, nsym(tree));
 
       if (idx > 0) {
-        genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL);
+        gen_move(s, cursp(), idx, val);
+        if (val && on_eval(s)) genop_0(s, OP_NOP);
       }
       else {
@@ -2147,7 +2332,7 @@
 
         while (up) {
-          idx = lv_idx(up, sym(tree));
+          idx = lv_idx(up, nsym(tree));
           if (idx > 0) {
-            genop(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv));
+            genop_3(s, OP_GETUPVAR, cursp(), idx, lv);
             break;
           }
@@ -2160,28 +2345,39 @@
     break;
 
+  case NODE_NVAR:
+    if (val) {
+      int idx = nint(tree);
+
+      gen_move(s, cursp(), idx, val);
+      if (val && on_eval(s)) genop_0(s, OP_NOP);
+
+      push();
+    }
+    break;
+
   case NODE_GVAR:
-    if (val) {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
-      push();
+    {
+      int sym = new_sym(s, nsym(tree));
+
+      genop_2(s, OP_GETGV, cursp(), sym);
+      if (val) push();
     }
     break;
 
   case NODE_IVAR:
-    if (val) {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_ABx(OP_GETIV, cursp(), sym));
-      push();
+    {
+      int sym = new_sym(s, nsym(tree));
+
+      genop_2(s, OP_GETIV, cursp(), sym);
+      if (val) push();
     }
     break;
 
   case NODE_CVAR:
-    if (val) {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_ABx(OP_GETCV, cursp(), sym));
-      push();
+    {
+      int sym = new_sym(s, nsym(tree));
+
+      genop_2(s, OP_GETCV, cursp(), sym);
+      if (val) push();
     }
     break;
@@ -2189,27 +2385,17 @@
   case NODE_CONST:
     {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym));
-      if (val) {
-        push();
-      }
-    }
-    break;
-
-  case NODE_DEFINED:
-    codegen(s, tree, VAL);
+      int sym = new_sym(s, nsym(tree));
+
+      genop_2(s, OP_GETCONST, cursp(), sym);
+      if (val) push();
+    }
     break;
 
   case NODE_BACK_REF:
     if (val) {
-      char buf[3];
-      int sym;
-
-      buf[0] = '$';
-      buf[1] = (char)(intptr_t)tree;
-      buf[2] = 0;
-      sym = new_sym(s, mrb_intern_cstr(s->mrb, buf));
-      genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
+      char buf[] = {'$', nchar(tree)};
+      int sym = new_sym(s, mrb_intern(s->mrb, buf, sizeof(buf)));
+
+      genop_2(s, OP_GETGV, cursp(), sym);
       push();
     }
@@ -2222,7 +2408,7 @@
       int sym;
 
-      str = mrb_format(mrb, "$%S", mrb_fixnum_value((mrb_int)(intptr_t)tree));
+      str = mrb_format(mrb, "$%d", nint(tree));
       sym = new_sym(s, mrb_intern_str(mrb, str));
-      genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
+      genop_2(s, OP_GETGV, cursp(), sym);
       push();
     }
@@ -2234,5 +2420,5 @@
 
   case NODE_BLOCK_ARG:
-    codegen(s, tree, VAL);
+    codegen(s, tree, val);
     break;
 
@@ -2240,25 +2426,27 @@
     if (val) {
       char *p = (char*)tree->car;
-      int base = (intptr_t)tree->cdr->car;
+      int base = nint(tree->cdr->car);
       mrb_int i;
-      mrb_code co;
       mrb_bool overflow;
 
       i = readint_mrb_int(s, p, base, FALSE, &overflow);
+#ifndef MRB_WITHOUT_FLOAT
       if (overflow) {
         double f = readint_float(s, p, base);
         int off = new_lit(s, mrb_float_value(s->mrb, f));
 
-        genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
-      }
-      else {
-        if (i < MAXARG_sBx && i > -MAXARG_sBx) {
-          co = MKOP_AsBx(OP_LOADI, cursp(), i);
-        }
+        genop_2(s, OP_LOADL, cursp(), off);
+      }
+      else
+#endif
+      {
+        if (i == -1) genop_1(s, OP_LOADI__1, cursp());
+        else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i);
+        else if (i < 8) genop_1(s, OP_LOADI_0 + (uint8_t)i, cursp());
+        else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), (uint16_t)i);
         else {
           int off = new_lit(s, mrb_fixnum_value(i));
-          co = MKOP_ABx(OP_LOADL, cursp(), off);
-        }
-        genop(s, co);
+          genop_2(s, OP_LOADL, cursp(), off);
+        }
       }
       push();
@@ -2266,4 +2454,5 @@
     break;
 
+#ifndef MRB_WITHOUT_FLOAT
   case NODE_FLOAT:
     if (val) {
@@ -2272,50 +2461,55 @@
       int off = new_lit(s, mrb_float_value(s->mrb, f));
 
-      genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
+      genop_2(s, OP_LOADL, cursp(), off);
       push();
     }
     break;
+#endif
 
   case NODE_NEGATE:
     {
-      nt = (intptr_t)tree->car;
-      tree = tree->cdr;
+      nt = nint(tree->car);
       switch (nt) {
+#ifndef MRB_WITHOUT_FLOAT
       case NODE_FLOAT:
         if (val) {
-          char *p = (char*)tree;
+          char *p = (char*)tree->cdr;
           mrb_float f = mrb_float_read(p, NULL);
           int off = new_lit(s, mrb_float_value(s->mrb, -f));
 
-          genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
+          genop_2(s, OP_LOADL, cursp(), off);
           push();
         }
         break;
+#endif
 
       case NODE_INT:
         if (val) {
-          char *p = (char*)tree->car;
-          int base = (intptr_t)tree->cdr->car;
+          char *p = (char*)tree->cdr->car;
+          int base = nint(tree->cdr->cdr->car);
           mrb_int i;
-          mrb_code co;
           mrb_bool overflow;
 
           i = readint_mrb_int(s, p, base, TRUE, &overflow);
+#ifndef MRB_WITHOUT_FLOAT
           if (overflow) {
             double f = readint_float(s, p, base);
             int off = new_lit(s, mrb_float_value(s->mrb, -f));
 
-            genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
+            genop_2(s, OP_LOADL, cursp(), off);
           }
           else {
-            if (i < MAXARG_sBx && i > -MAXARG_sBx) {
-              co = MKOP_AsBx(OP_LOADI, cursp(), i);
+#endif
+            if (i == -1) genop_1(s, OP_LOADI__1, cursp());
+            else if (i >= -0xffff) {
+              genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i);
             }
             else {
               int off = new_lit(s, mrb_fixnum_value(i));
-              co = MKOP_ABx(OP_LOADL, cursp(), off);
+              genop_2(s, OP_LOADL, cursp(), off);
             }
-            genop(s, co);
-          }
+#ifndef MRB_WITHOUT_FLOAT
+          }
+#endif
           push();
         }
@@ -2324,11 +2518,9 @@
       default:
         if (val) {
-          int sym = new_msym(s, mrb_intern_lit(s->mrb, "-"));
-
-          genop(s, MKOP_ABx(OP_LOADI, cursp(), 0));
+          int sym = new_sym(s, mrb_intern_lit(s->mrb, "-@"));
+          codegen(s, tree, VAL);
+          pop();
+          genop_3(s, OP_SEND, cursp(), sym, 0);
           push();
-          codegen(s, tree, VAL);
-          pop(); pop();
-          genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2));
         }
         else {
@@ -2348,5 +2540,5 @@
 
       mrb_gc_arena_restore(s->mrb, ai);
-      genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+      genop_2(s, OP_STRING, cursp(), off);
       push();
     }
@@ -2361,5 +2553,5 @@
 
       if (!n) {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         push();
         break;
@@ -2370,5 +2562,5 @@
         codegen(s, n->car, VAL);
         pop(); pop();
-        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+        genop_1(s, OP_STRCAT, cursp());
         push();
         n = n->cdr;
@@ -2379,5 +2571,5 @@
 
       while (n) {
-        if ((intptr_t)n->car->car != NODE_STR) {
+        if (nint(n->car->car) != NODE_STR) {
           codegen(s, n->car, NOVAL);
         }
@@ -2401,10 +2593,10 @@
       int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
 
-      genop(s, MKOP_A(OP_LOADSELF, cursp()));
+      genop_1(s, OP_LOADSELF, cursp());
       push();
       codegen(s, tree->car, VAL);
       n = tree->cdr;
       while (n) {
-        if ((intptr_t)n->car->car == NODE_XSTR) {
+        if (nint(n->car->car) == NODE_XSTR) {
           n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR;
           mrb_assert(!n->cdr); /* must be the end */
@@ -2412,5 +2604,5 @@
         codegen(s, n->car, VAL);
         pop(); pop();
-        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+        genop_1(s, OP_STRCAT, cursp());
         push();
         n = n->cdr;
@@ -2419,5 +2611,5 @@
       pop_n(3);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
-      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+      genop_3(s, OP_SEND, cursp(), sym, 1);
       if (val) push();
       mrb_gc_arena_restore(s->mrb, ai);
@@ -2433,11 +2625,11 @@
       int sym;
 
-      genop(s, MKOP_A(OP_LOADSELF, cursp()));
+      genop_1(s, OP_LOADSELF, cursp());
       push();
-      genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+      genop_2(s, OP_STRING, cursp(), off);
       push(); push();
       pop_n(3);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
-      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+      genop_3(s, OP_SEND, cursp(), sym, 1);
       if (val) push();
       mrb_gc_arena_restore(s->mrb, ai);
@@ -2455,30 +2647,30 @@
       int argc = 1;
 
-      genop(s, MKOP_A(OP_OCLASS, cursp()));
-      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      genop_1(s, OP_OCLASS, cursp());
+      genop_2(s, OP_GETMCNST, cursp(), sym);
       push();
-      genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+      genop_2(s, OP_STRING, cursp(), off);
+      push();
       if (p2 || p3) {
+        if (p2) { /* opt */
+          off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
+          genop_2(s, OP_STRING, cursp(), off);
+        }
+        else {
+          genop_1(s, OP_LOADNIL, cursp());
+        }
         push();
-        if (p2) {
-          off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
-          genop(s, MKOP_ABx(OP_STRING, cursp(), off));
-        }
-        else {
-          genop(s, MKOP_A(OP_LOADNIL, cursp()));
-        }
         argc++;
-        if (p3) {
+        if (p3) { /* enc */
+          off = new_lit(s, mrb_str_new(s->mrb, p3, 1));
+          genop_2(s, OP_STRING, cursp(), off);
           push();
-          off = new_lit(s, mrb_str_new(s->mrb, p3, 1));
-          genop(s, MKOP_ABx(OP_STRING, cursp(), off));
           argc++;
-          pop();
-        }
-        pop();
-      }
-      pop();
+        }
+      }
+      push(); /* space for a block */
+      pop_n(argc+2);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
-      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
+      genop_3(s, OP_SEND, cursp(), sym, argc);
       mrb_gc_arena_restore(s->mrb, ai);
       push();
@@ -2495,6 +2687,6 @@
       char *p;
 
-      genop(s, MKOP_A(OP_OCLASS, cursp()));
-      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      genop_1(s, OP_OCLASS, cursp());
+      genop_2(s, OP_GETMCNST, cursp(), sym);
       push();
       codegen(s, n->car, VAL);
@@ -2503,36 +2695,36 @@
         codegen(s, n->car, VAL);
         pop(); pop();
-        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+        genop_1(s, OP_STRCAT, cursp());
         push();
         n = n->cdr;
       }
       n = tree->cdr->cdr;
-      if (n->car) {
+      if (n->car) { /* tail */
         p = (char*)n->car;
         off = new_lit(s, mrb_str_new_cstr(s->mrb, p));
         codegen(s, tree->car, VAL);
-        genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+        genop_2(s, OP_STRING, cursp(), off);
         pop();
-        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
-      }
-      if (n->cdr->car) {
+        genop_1(s, OP_STRCAT, cursp());
+        push();
+      }
+      if (n->cdr->car) { /* opt */
         char *p2 = (char*)n->cdr->car;
-
+        off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
+        genop_2(s, OP_STRING, cursp(), off);
         push();
+        argc++;
+      }
+      if (n->cdr->cdr) { /* enc */
+        char *p2 = (char*)n->cdr->cdr;
         off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
-        genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+        genop_2(s, OP_STRING, cursp(), off);
+        push();
         argc++;
       }
-      if (n->cdr->cdr) {
-        char *p2 = (char*)n->cdr->cdr;
-
-        push();
-        off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
-        genop(s, MKOP_ABx(OP_STRING, cursp(), off));
-        argc++;
-      }
-      pop_n(argc);
+      push(); /* space for a block */
+      pop_n(argc+2);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
-      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
+      genop_3(s, OP_SEND, cursp(), sym, argc);
       mrb_gc_arena_restore(s->mrb, ai);
       push();
@@ -2542,5 +2734,5 @@
 
       while (n) {
-        if ((intptr_t)n->car->car != NODE_STR) {
+        if (nint(n->car->car) != NODE_STR) {
           codegen(s, n->car, NOVAL);
         }
@@ -2552,7 +2744,7 @@
   case NODE_SYM:
     if (val) {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
+      int sym = new_sym(s, nsym(tree));
+
+      genop_2(s, OP_LOADSYM, cursp(), sym);
       push();
     }
@@ -2562,5 +2754,5 @@
     codegen(s, tree, val);
     if (val) {
-      gen_send_intern(s);
+      gen_intern(s);
     }
     break;
@@ -2568,5 +2760,5 @@
   case NODE_SELF:
     if (val) {
-      genop(s, MKOP_A(OP_LOADSELF, cursp()));
+      genop_1(s, OP_LOADSELF, cursp());
       push();
     }
@@ -2575,5 +2767,5 @@
   case NODE_NIL:
     if (val) {
-      genop(s, MKOP_A(OP_LOADNIL, cursp()));
+      genop_1(s, OP_LOADNIL, cursp());
       push();
     }
@@ -2582,5 +2774,5 @@
   case NODE_TRUE:
     if (val) {
-      genop(s, MKOP_A(OP_LOADT, cursp()));
+      genop_1(s, OP_LOADT, cursp());
       push();
     }
@@ -2589,5 +2781,5 @@
   case NODE_FALSE:
     if (val) {
-      genop(s, MKOP_A(OP_LOADF, cursp()));
+      genop_1(s, OP_LOADF, cursp());
       push();
     }
@@ -2596,19 +2788,10 @@
   case NODE_ALIAS:
     {
-      int a = new_msym(s, sym(tree->car));
-      int b = new_msym(s, sym(tree->cdr));
-      int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method"));
-
-      genop(s, MKOP_A(OP_TCLASS, cursp()));
-      push();
-      genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a));
-      push();
-      genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b));
-      push();
-      genop(s, MKOP_A(OP_LOADNIL, cursp()));
-      push();
-      pop_n(4);
-      genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2));
+      int a = new_sym(s, nsym(tree->car));
+      int b = new_sym(s, nsym(tree->cdr));
+
+      genop_2(s, OP_ALIAS, a, b);
       if (val) {
+        genop_1(s, OP_LOADNIL, cursp());
         push();
       }
@@ -2618,38 +2801,13 @@
   case NODE_UNDEF:
     {
-      int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method"));
-      int num = 0;
       node *t = tree;
 
-      genop(s, MKOP_A(OP_TCLASS, cursp()));
-      push();
       while (t) {
-        int symbol;
-        if (num >= CALL_MAXARGS - 1) {
-          pop_n(num);
-          genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), num));
-          while (t) {
-            symbol = new_msym(s, sym(t->car));
-            push();
-            genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
-            pop();
-            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
-            t = t->cdr;
-          }
-          num = CALL_MAXARGS;
-          break;
-        }
-        symbol = new_msym(s, sym(t->car));
-        genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
-        push();
+        int symbol = new_sym(s, nsym(t->car));
+        genop_1(s, OP_UNDEF, symbol);
         t = t->cdr;
-        num++;
-      }
-      pop();
-      if (num < CALL_MAXARGS) {
-        pop_n(num);
-      }
-      genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num));
+      }
       if (val) {
+        genop_1(s, OP_LOADNIL, cursp());
         push();
       }
@@ -2660,11 +2818,12 @@
     {
       int idx;
+      node *body;
 
       if (tree->car->car == (node*)0) {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         push();
       }
       else if (tree->car->car == (node*)1) {
-        genop(s, MKOP_A(OP_OCLASS, cursp()));
+        genop_1(s, OP_OCLASS, cursp());
         push();
       }
@@ -2676,12 +2835,18 @@
       }
       else {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         push();
       }
       pop(); pop();
-      idx = new_msym(s, sym(tree->car->cdr));
-      genop(s, MKOP_AB(OP_CLASS, cursp(), idx));
-      idx = scope_body(s, tree->cdr->cdr->car, val);
-      genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
+      idx = new_sym(s, nsym(tree->car->cdr));
+      genop_2(s, OP_CLASS, cursp(), idx);
+      body = tree->cdr->cdr->car;
+      if (nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL) {
+        genop_1(s, OP_LOADNIL, cursp());
+      }
+      else {
+        idx = scope_body(s, body, val);
+        genop_2(s, OP_EXEC, cursp(), idx);
+      }
       if (val) {
         push();
@@ -2695,9 +2860,9 @@
 
       if (tree->car->car == (node*)0) {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         push();
       }
       else if (tree->car->car == (node*)1) {
-        genop(s, MKOP_A(OP_OCLASS, cursp()));
+        genop_1(s, OP_OCLASS, cursp());
         push();
       }
@@ -2706,8 +2871,14 @@
       }
       pop();
-      idx = new_msym(s, sym(tree->car->cdr));
-      genop(s, MKOP_AB(OP_MODULE, cursp(), idx));
-      idx = scope_body(s, tree->cdr->car, val);
-      genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
+      idx = new_sym(s, nsym(tree->car->cdr));
+      genop_2(s, OP_MODULE, cursp(), idx);
+      if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
+          tree->cdr->car->cdr->cdr == NULL) {
+        genop_1(s, OP_LOADNIL, cursp());
+      }
+      else {
+        idx = scope_body(s, tree->cdr->car, val);
+        genop_2(s, OP_EXEC, cursp(), idx);
+      }
       if (val) {
         push();
@@ -2722,7 +2893,13 @@
       codegen(s, tree->car, VAL);
       pop();
-      genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp()));
-      idx = scope_body(s, tree->cdr->car, val);
-      genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
+      genop_1(s, OP_SCLASS, cursp());
+      if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
+          tree->cdr->car->cdr->cdr == NULL) {
+        genop_1(s, OP_LOADNIL, cursp());
+      }
+      else {
+        idx = scope_body(s, tree->cdr->car, val);
+        genop_2(s, OP_EXEC, cursp(), idx);
+      }
       if (val) {
         push();
@@ -2733,15 +2910,15 @@
   case NODE_DEF:
     {
-      int sym = new_msym(s, sym(tree->car));
+      int sym = new_sym(s, nsym(tree->car));
       int idx = lambda_body(s, tree->cdr, 0);
 
-      genop(s, MKOP_A(OP_TCLASS, cursp()));
+      genop_1(s, OP_TCLASS, cursp());
       push();
-      genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD));
+      genop_2(s, OP_METHOD, cursp(), idx);
       push(); pop();
       pop();
-      genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
+      genop_2(s, OP_DEF, cursp(), sym);
       if (val) {
-        genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
+        genop_2(s, OP_LOADSYM, cursp(), sym);
         push();
       }
@@ -2752,16 +2929,16 @@
     {
       node *recv = tree->car;
-      int sym = new_msym(s, sym(tree->cdr->car));
+      int sym = new_sym(s, nsym(tree->cdr->car));
       int idx = lambda_body(s, tree->cdr->cdr, 0);
 
       codegen(s, recv, VAL);
       pop();
-      genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp()));
+      genop_1(s, OP_SCLASS, cursp());
       push();
-      genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD));
+      genop_2(s, OP_METHOD, cursp(), idx);
       pop();
-      genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
+      genop_2(s, OP_DEF, cursp(), sym);
       if (val) {
-        genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
+        genop_2(s, OP_LOADSYM, cursp(), sym);
         push();
       }
@@ -2802,5 +2979,9 @@
   codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope));
 
-  if (!p) return NULL;
+  if (!p) {
+    if (prev)
+      codegen_error(prev, "unexpected scope");
+    return NULL;
+  }
   *p = codegen_scope_zero;
   p->mrb = mrb;
@@ -2825,5 +3006,5 @@
   p->irep->plen = 0;
 
-  p->scapa = MAXMSYMLEN;
+  p->scapa = 256;
   p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa);
   p->irep->slen = 0;
@@ -2850,6 +3031,6 @@
   p->ai = mrb_gc_arena_save(mrb);
 
-  p->filename = prev->filename;
-  if (p->filename) {
+  p->filename_sym = prev->filename_sym;
+  if (p->filename_sym) {
     p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa);
   }
@@ -2858,8 +3039,6 @@
   /* debug setting */
   p->debug_start_pos = 0;
-  if (p->filename) {
+  if (p->filename_sym) {
     mrb_debug_info_alloc(mrb, p->irep);
-    p->irep->filename = p->filename;
-    p->irep->lines = p->lines;
   }
   else {
@@ -2879,32 +3058,24 @@
   mrb_state *mrb = s->mrb;
   mrb_irep *irep = s->irep;
-  size_t fname_len;
-  char *fname;
-
+
+  if (s->nlocals >= 0x3ff) {
+    codegen_error(s, "too many local variables");
+  }
   irep->flags = 0;
   if (s->iseq) {
     irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc);
     irep->ilen = s->pc;
-    if (s->lines) {
-      irep->lines = (uint16_t *)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->pc);
-    }
-    else {
-      irep->lines = 0;
-    }
   }
   irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen);
   irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen);
   irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen);
-  if (s->filename) {
-    irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
-    mrb_debug_info_append_file(mrb, irep, s->debug_start_pos, s->pc);
-
-    fname_len = strlen(s->filename);
-    fname = (char*)codegen_malloc(s, fname_len + 1);
-    memcpy(fname, s->filename, fname_len);
-    fname[fname_len] = '\0';
-    irep->filename = fname;
-    irep->own_filename = TRUE;
-  }
+  if (s->filename_sym) {
+    mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
+    const char *filename = mrb_sym_name_len(s->mrb, fname, NULL);
+
+    mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
+                               filename, s->lines, s->debug_start_pos, s->pc);
+  }
+  mrb_free(s->mrb, s->lines);
 
   irep->nlocals = s->nlocals;
@@ -2921,5 +3092,5 @@
 
   p->type = t;
-  p->pc1 = p->pc2 = p->pc3 = 0;
+  p->pc0 = p->pc1 = p->pc2 = p->pc3 = 0;
   p->prev = s->loop;
   p->ensure_level = s->ensure_level;
@@ -2939,4 +3110,5 @@
   else {
     struct loopinfo *loop;
+    int n = 0;
 
     if (tree) {
@@ -2945,10 +3117,15 @@
 
     loop = s->loop;
-    while (loop && loop->type == LOOP_BEGIN) {
-      genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL);
-      loop = loop->prev;
-    }
-    while (loop && loop->type == LOOP_RESCUE) {
-      loop = loop->prev;
+    while (loop) {
+      if (loop->type == LOOP_BEGIN) {
+        n++;
+        loop = loop->prev;
+      }
+      else if (loop->type == LOOP_RESCUE) {
+        loop = loop->prev;
+      }
+      else{
+        break;
+      }
     }
     if (!loop) {
@@ -2956,4 +3133,7 @@
       return;
     }
+    if (n > 0) {
+      genop_1(s, OP_POPERR, n);
+    }
 
     if (loop->type == LOOP_NORMAL) {
@@ -2961,17 +3141,17 @@
 
       if (s->ensure_level > s->loop->ensure_level) {
-        genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
+        genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
       }
       if (tree) {
-        genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL);
-      }
-      tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3));
+        gen_move(s, loop->acc, cursp(), 0);
+      }
+      tmp = genjmp(s, OP_JMP, loop->pc3);
       loop->pc3 = tmp;
     }
     else {
       if (!tree) {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
-      }
-      genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK));
+        genop_1(s, OP_LOADNIL, cursp());
+      }
+      gen_return(s, OP_BREAK, cursp());
     }
   }
@@ -2981,14 +3161,14 @@
 loop_pop(codegen_scope *s, int val)
 {
+  if (val) {
+    genop_1(s, OP_LOADNIL, cursp());
+  }
   dispatch_linked(s, s->loop->pc3);
-  if (val) {
-    genop(s, MKOP_A(OP_LOADNIL, cursp()));
-  }
   s->loop = s->loop->prev;
   if (val) push();
 }
 
-MRB_API struct RProc*
-mrb_generate_code(mrb_state *mrb, parser_state *p)
+static struct RProc*
+generate_code(mrb_state *mrb, parser_state *p, int val)
 {
   codegen_scope *scope = scope_new(mrb, 0, 0);
@@ -2996,20 +3176,20 @@
   struct mrb_jmpbuf *prev_jmp = mrb->jmp;
 
-  if (!scope) {
-    return NULL;
-  }
   scope->mrb = mrb;
   scope->parser = p;
-  scope->filename = p->filename;
+  scope->filename_sym = p->filename_sym;
   scope->filename_index = p->current_filename_index;
 
   MRB_TRY(&scope->jmp) {
-    mrb->jmp = &scope->jmp; 
+    mrb->jmp = &scope->jmp;
     /* prepare irep */
-    codegen(scope, p->tree, NOVAL);
+    codegen(scope, p->tree, val);
     proc = mrb_proc_new(mrb, scope->irep);
     mrb_irep_decref(mrb, scope->irep);
     mrb_pool_close(scope->mpool);
     proc->c = NULL;
+    if (mrb->c->cibase && mrb->c->cibase->proc == proc->upper) {
+      proc->upper = NULL;
+    }
     mrb->jmp = prev_jmp;
     return proc;
@@ -3023,2 +3203,76 @@
   MRB_END_EXC(&scope->jmp);
 }
+
+MRB_API struct RProc*
+mrb_generate_code(mrb_state *mrb, parser_state *p)
+{
+  return generate_code(mrb, p, VAL);
+}
+
+void
+mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep)
+{
+  int i;
+
+  if (irep->lv) {
+    mrb_free(mrb, irep->lv);
+    irep->lv = NULL;
+  }
+
+  for (i = 0; i < irep->rlen; ++i) {
+    mrb_irep_remove_lv(mrb, irep->reps[i]);
+  }
+}
+
+#undef OPCODE
+#define Z 1
+#define S 3
+#define W 4
+/* instruction sizes */
+uint8_t mrb_insn_size[] = {
+#define B 2
+#define BB 3
+#define BBB 4
+#define BS 4
+#define SB 4
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+#undef OPCODE
+#undef B
+#undef BB
+#undef BS
+#undef SB
+#undef BBB
+};
+/* EXT1 instruction sizes */
+uint8_t mrb_insn_size1[] = {
+#define B 3
+#define BB 4
+#define BBB 5
+#define BS 5
+#define SB 5
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+#undef OPCODE
+#undef B
+};
+/* EXT2 instruction sizes */
+uint8_t mrb_insn_size2[] = {
+#define B 2
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+#undef OPCODE
+#undef BB
+#undef BBB
+#undef BS
+#undef SB
+};
+/* EXT3 instruction sizes */
+#define BB 5
+#define BBB 6
+#define BS 4
+#define SB 5
+uint8_t mrb_insn_size3[] = {
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+};
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/keywords
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/keywords	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/keywords	(revision 439)
@@ -1,7 +1,4 @@
 %{
 struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;};
-const struct kwtable *mrb_reserved_word(const char *, unsigned int);
-static const struct kwtable *reserved_word(const char *, unsigned int);
-#define mrb_reserved_word(str, len) reserved_word(str, len)
 %}
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/lex.def
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/lex.def	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/lex.def	(revision 439)
@@ -1,3 +1,3 @@
-/* ANSI-C code produced by gperf version 3.0.4 */
+/* ANSI-C code produced by gperf version 3.1 */
 /* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' /home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords  */
 
@@ -26,5 +26,5 @@
       && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
 /* The character set is not based on ISO-646.  */
-#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
 #endif
 
@@ -32,8 +32,5 @@
 
 struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;};
-const struct kwtable *mrb_reserved_word(const char *, unsigned int);
-static const struct kwtable *reserved_word(const char *, unsigned int);
-#define mrb_reserved_word(str, len) reserved_word(str, len)
-#line 8 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+#line 5 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
 struct kwtable;
 
@@ -53,5 +50,5 @@
 #endif
 static unsigned int
-hash (register const char *str, register unsigned int len)
+hash (register const char *str, register size_t len)
 {
   static const unsigned char asso_values[] =
@@ -84,5 +81,5 @@
       51, 51, 51, 51, 51, 51
     };
-  register int hval = len;
+  register unsigned int hval = len;
 
   switch (hval)
@@ -99,97 +96,91 @@
 }
 
-#ifdef __GNUC__
-__inline
-#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
-__attribute__ ((__gnu_inline__))
-#endif
-#endif
 const struct kwtable *
-mrb_reserved_word (register const char *str, register unsigned int len)
+mrb_reserved_word (register const char *str, register size_t len)
 {
   static const struct kwtable wordlist[] =
     {
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 15 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"break",        {keyword_break,       keyword_break},       EXPR_MID},
+#line 20 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"else",         {keyword_else,        keyword_else},        EXPR_BEG},
+#line 30 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"nil",          {keyword_nil,         keyword_nil},         EXPR_END},
+#line 23 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"ensure",       {keyword_ensure,      keyword_ensure},      EXPR_BEG},
+#line 22 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"end",          {keyword_end,         keyword_end},         EXPR_END},
+#line 39 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"then",         {keyword_then,        keyword_then},        EXPR_BEG},
+#line 31 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"not",          {keyword_not,         keyword_not},         EXPR_ARG},
+#line 24 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"false",        {keyword_false,       keyword_false},       EXPR_END},
+#line 37 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"self",         {keyword_self,        keyword_self},        EXPR_END},
+#line 21 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"elsif",        {keyword_elsif,       keyword_elsif},       EXPR_VALUE},
+#line 34 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"rescue",       {keyword_rescue,      modifier_rescue},     EXPR_MID},
+#line 40 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"true",         {keyword_true,        keyword_true},        EXPR_END},
+#line 43 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"until",        {keyword_until,       modifier_until},      EXPR_VALUE},
+#line 42 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"unless",       {keyword_unless,      modifier_unless},     EXPR_VALUE},
+#line 36 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"return",       {keyword_return,      keyword_return},      EXPR_MID},
 #line 18 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"break",        {keyword_break,       keyword_break},       EXPR_MID},
-#line 23 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"else",         {keyword_else,        keyword_else},        EXPR_BEG},
+      {"def",          {keyword_def,         keyword_def},         EXPR_FNAME},
+#line 13 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"and",          {keyword_and,         keyword_and},         EXPR_VALUE},
+#line 19 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"do",           {keyword_do,          keyword_do},          EXPR_BEG},
+#line 46 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"yield",        {keyword_yield,       keyword_yield},       EXPR_ARG},
+#line 25 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"for",          {keyword_for,         keyword_for},         EXPR_VALUE},
+#line 41 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"undef",        {keyword_undef,       keyword_undef},       EXPR_FNAME},
+#line 32 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"or",           {keyword_or,          keyword_or},          EXPR_VALUE},
+#line 27 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"in",           {keyword_in,          keyword_in},          EXPR_VALUE},
+#line 44 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"when",         {keyword_when,        keyword_when},        EXPR_VALUE},
+#line 35 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"retry",        {keyword_retry,       keyword_retry},       EXPR_END},
+#line 26 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"if",           {keyword_if,          modifier_if},         EXPR_VALUE},
+#line 16 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"case",         {keyword_case,        keyword_case},        EXPR_VALUE},
 #line 33 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"nil",          {keyword_nil,         keyword_nil},         EXPR_END},
-#line 26 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"ensure",       {keyword_ensure,      keyword_ensure},      EXPR_BEG},
-#line 25 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"end",          {keyword_end,         keyword_end},         EXPR_END},
-#line 42 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"then",         {keyword_then,        keyword_then},        EXPR_BEG},
-#line 34 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"not",          {keyword_not,         keyword_not},         EXPR_ARG},
-#line 27 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"false",        {keyword_false,       keyword_false},       EXPR_END},
-#line 40 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"self",         {keyword_self,        keyword_self},        EXPR_END},
-#line 24 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"elsif",        {keyword_elsif,       keyword_elsif},       EXPR_VALUE},
-#line 37 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"rescue",       {keyword_rescue,      modifier_rescue},     EXPR_MID},
-#line 43 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"true",         {keyword_true,        keyword_true},        EXPR_END},
-#line 46 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"until",        {keyword_until,       modifier_until},      EXPR_VALUE},
-#line 45 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"unless",       {keyword_unless,      modifier_unless},     EXPR_VALUE},
-#line 39 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"return",       {keyword_return,      keyword_return},      EXPR_MID},
-#line 21 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"def",          {keyword_def,         keyword_def},         EXPR_FNAME},
-#line 16 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"and",          {keyword_and,         keyword_and},         EXPR_VALUE},
-#line 22 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"do",           {keyword_do,          keyword_do},          EXPR_BEG},
-#line 49 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"yield",        {keyword_yield,       keyword_yield},       EXPR_ARG},
+      {"redo",         {keyword_redo,        keyword_redo},        EXPR_END},
+#line 29 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"next",         {keyword_next,        keyword_next},        EXPR_MID},
+#line 38 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"super",        {keyword_super,       keyword_super},       EXPR_ARG},
 #line 28 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"for",          {keyword_for,         keyword_for},         EXPR_VALUE},
-#line 44 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"undef",        {keyword_undef,       keyword_undef},       EXPR_FNAME},
-#line 35 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"or",           {keyword_or,          keyword_or},          EXPR_VALUE},
-#line 30 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"in",           {keyword_in,          keyword_in},          EXPR_VALUE},
-#line 47 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"when",         {keyword_when,        keyword_when},        EXPR_VALUE},
-#line 38 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"retry",        {keyword_retry,       keyword_retry},       EXPR_END},
-#line 29 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"if",           {keyword_if,          modifier_if},         EXPR_VALUE},
-#line 19 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"case",         {keyword_case,        keyword_case},        EXPR_VALUE},
-#line 36 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"redo",         {keyword_redo,        keyword_redo},        EXPR_END},
-#line 32 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"next",         {keyword_next,        keyword_next},        EXPR_MID},
-#line 41 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"super",        {keyword_super,       keyword_super},       EXPR_ARG},
-#line 31 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
       {"module",       {keyword_module,      keyword_module},      EXPR_VALUE},
-#line 17 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+#line 14 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
       {"begin",        {keyword_begin,       keyword_begin},       EXPR_BEG},
+#line 9 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"__LINE__",     {keyword__LINE__,     keyword__LINE__},     EXPR_END},
+#line 8 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"__FILE__",     {keyword__FILE__,     keyword__FILE__},     EXPR_END},
+#line 7 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END},
+#line 11 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"END",          {keyword_END,         keyword_END},         EXPR_END},
 #line 12 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"__LINE__",     {keyword__LINE__,     keyword__LINE__},     EXPR_END},
-#line 11 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"__FILE__",     {keyword__FILE__,     keyword__FILE__},     EXPR_END},
+      {"alias",        {keyword_alias,       keyword_alias},       EXPR_FNAME},
 #line 10 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END},
-#line 14 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"END",          {keyword_END,         keyword_END},         EXPR_END},
-#line 15 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"alias",        {keyword_alias,       keyword_alias},       EXPR_FNAME},
-#line 13 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
       {"BEGIN",        {keyword_BEGIN,       keyword_BEGIN},       EXPR_END},
       {""},
-#line 20 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+#line 17 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
       {"class",        {keyword_class,       keyword_class},       EXPR_CLASS},
       {""}, {""},
-#line 48 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+#line 45 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
       {"while",        {keyword_while,       modifier_while},      EXPR_VALUE}
     };
@@ -197,7 +188,7 @@
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
     {
-      register int key = hash (str, len);
-
-      if (key <= MAX_HASH_VALUE && key >= 0)
+      register unsigned int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE)
         {
           register const char *s = wordlist[key].name;
@@ -209,4 +200,4 @@
   return 0;
 }
-#line 50 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-
+#line 47 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/node.h
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/node.h	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/node.h	(revision 439)
@@ -10,6 +10,4 @@
 enum node_type {
   NODE_METHOD,
-  NODE_FBODY,
-  NODE_CFUNC,
   NODE_SCOPE,
   NODE_BLOCK,
@@ -17,5 +15,4 @@
   NODE_CASE,
   NODE_WHEN,
-  NODE_OPT_N,
   NODE_WHILE,
   NODE_UNTIL,
@@ -41,5 +38,4 @@
   NODE_SCALL,
   NODE_FCALL,
-  NODE_VCALL,
   NODE_SUPER,
   NODE_ZSUPER,
@@ -47,4 +43,5 @@
   NODE_ZARRAY,
   NODE_HASH,
+  NODE_KW_HASH,
   NODE_RETURN,
   NODE_YIELD,
@@ -55,9 +52,8 @@
   NODE_CONST,
   NODE_CVAR,
+  NODE_NVAR,
   NODE_NTH_REF,
   NODE_BACK_REF,
   NODE_MATCH,
-  NODE_MATCH2,
-  NODE_MATCH3,
   NODE_INT,
   NODE_FLOAT,
@@ -72,8 +68,8 @@
   NODE_DREGX,
   NODE_DREGX_ONCE,
-  NODE_LIST,
   NODE_ARG,
-  NODE_ARGSCAT,
-  NODE_ARGSPUSH,
+  NODE_ARGS_TAIL,
+  NODE_KW_ARG,
+  NODE_KW_REST_ARGS,
   NODE_SPLAT,
   NODE_TO_ARY,
@@ -89,10 +85,6 @@
   NODE_COLON2,
   NODE_COLON3,
-  NODE_CREF,
   NODE_DOT2,
   NODE_DOT3,
-  NODE_FLIP2,
-  NODE_FLIP3,
-  NODE_ATTRSET,
   NODE_SELF,
   NODE_NIL,
@@ -100,13 +92,6 @@
   NODE_FALSE,
   NODE_DEFINED,
-  NODE_NEWLINE,
   NODE_POSTEXE,
-  NODE_ALLOCA,
-  NODE_DMETHOD,
-  NODE_BMETHOD,
-  NODE_MEMO,
-  NODE_IFUNC,
   NODE_DSYM,
-  NODE_ATTRASGN,
   NODE_HEREDOC,
   NODE_LITERAL_DELIM,
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/parse.y
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/parse.y	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/parse.y	(revision 439)
@@ -11,11 +11,5 @@
 #endif
 #define YYERROR_VERBOSE 1
-/*
- * Force yacc to use our memory management.  This is a little evil because
- * the macros assume that "parser_state *p" is in scope
- */
-#define YYMALLOC(n)    mrb_malloc(p->mrb, (n))
-#define YYFREE(o)      mrb_free(p->mrb, (o))
-#define YYSTACK_USE_ALLOCA 0
+#define YYSTACK_USE_ALLOCA 1
 
 #include <ctype.h>
@@ -28,4 +22,5 @@
 #include <mruby/error.h>
 #include <mruby/throw.h>
+#include <mruby/string.h>
 #include "node.h"
 
@@ -77,4 +72,7 @@
 #define intn(x) ((int)(intptr_t)(x))
 
+#define NUM_SUFFIX_R   (1<<0)
+#define NUM_SUFFIX_I   (1<<1)
+
 static inline mrb_sym
 intern_cstr_gen(parser_state *p, const char *s)
@@ -91,10 +89,5 @@
 #define intern(s,len) intern_gen(p,(s),(len))
 
-static inline mrb_sym
-intern_gen_c(parser_state *p, const char c)
-{
-  return mrb_intern(p->mrb, &c, 1);
-}
-#define intern_c(c) intern_gen_c(p,(c))
+#define intern_lit(s) mrb_intern_lit(p->mrb, s)
 
 static void
@@ -134,4 +127,8 @@
   c->lineno = p->lineno;
   c->filename_index = p->current_filename_index;
+  /* beginning of next partial file; need to point the previous file */
+  if (p->lineno == 0 && p->current_filename_index > 0) {
+    c->filename_index-- ;
+  }
   return c;
 }
@@ -186,10 +183,9 @@
 
   if (!a) return b;
+  if (!b) return a;
   while (c->cdr) {
     c = c->cdr;
   }
-  if (b) {
-    c->cdr = b;
-  }
+  c->cdr = b;
   return a;
 }
@@ -216,4 +212,24 @@
 #undef strdup
 #define strdup(s) parser_strdup(p, s)
+
+static void
+dump_int(uint16_t i, char *s)
+{
+  char *p = s;
+  char *t = s;
+
+  while (i > 0) {
+    *p++ = (i % 10)+'0';
+    i /= 10;
+  }
+  if (p == s) *p++ = '0';
+  *p = 0;
+  p--;  /* point the last char */
+  while (t < p) {
+    char c = *t;
+    *t++ = *p;
+    *p-- = c;
+  }
+}
 
 /* xxx ----------------------------- */
@@ -280,8 +296,40 @@
 }
 
+static void
+local_add_blk(parser_state *p, mrb_sym blk)
+{
+  /* allocate register for block */
+  local_add_f(p, blk ? blk : mrb_intern_lit(p->mrb, "&"));
+}
+
+static void
+local_add_kw(parser_state *p, mrb_sym kwd)
+{
+  /* allocate register for keywords hash */
+  local_add_f(p, kwd ? kwd : mrb_intern_lit(p->mrb, "**"));
+}
+
 static node*
 locals_node(parser_state *p)
 {
   return p->locals ? p->locals->car : NULL;
+}
+
+static void
+nvars_nest(parser_state *p)
+{
+  p->nvars = cons(nint(0), p->nvars);
+}
+
+static void
+nvars_block(parser_state *p)
+{
+  p->nvars = cons(nint(-2), p->nvars);
+}
+
+static void
+nvars_unnest(parser_state *p)
+{
+  p->nvars = p->nvars->cdr;
 }
 
@@ -569,4 +617,11 @@
 }
 
+/* (:kw_hash (k . v) (k . v)...) */
+static node*
+new_kw_hash(parser_state *p, node *a)
+{
+  return cons((node*)NODE_KW_HASH, a);
+}
+
 /* (:sym . a) */
 static node*
@@ -613,4 +668,14 @@
 }
 
+/* (:nvar . a) */
+static node*
+new_nvar(parser_state *p, int num)
+{
+  int nvars = intn(p->nvars->car);
+
+  p->nvars->car = nint(nvars > num ? nvars : num);
+  return cons((node*)NODE_NVAR, nint(num));
+}
+
 /* (:const . a) */
 static node*
@@ -672,5 +737,33 @@
 }
 
-/* (m o r m2 b) */
+static void
+local_add_margs(parser_state *p, node *n)
+{
+  while (n) {
+    if (n->car->car == (node*)NODE_MASGN) {
+      node *t = n->car->cdr->cdr;
+
+      n->car->cdr->cdr = NULL;
+      while (t) {
+        local_add_f(p, sym(t->car));
+        t = t->cdr;
+      }
+      local_add_margs(p, n->car->cdr->car->car);
+      local_add_margs(p, n->car->cdr->car->cdr->cdr->car);
+    }
+    n = n->cdr;
+  }
+}
+
+static void
+local_add_lv(parser_state *p, node *lv)
+{
+  while (lv) {
+    local_add_f(p, sym(lv->car));
+    lv = lv->cdr;
+  }
+}
+
+/* (m o r m2 tail) */
 /* m: (a b c) */
 /* o: ((a . e1) (b . e2)) */
@@ -679,14 +772,60 @@
 /* b: a */
 static node*
-new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk)
+new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail)
 {
   node *n;
 
-  n = cons(m2, nsym(blk));
+  local_add_margs(p, m);
+  local_add_margs(p, m2);
+  n = cons(m2, tail);
   n = cons(nsym(rest), n);
   n = cons(opt, n);
+  while (opt) {
+    /* opt: (sym . (opt . lv)) -> (sym . opt) */
+    local_add_lv(p, opt->car->cdr->cdr);
+    opt->car->cdr = opt->car->cdr->car;
+    opt = opt->cdr;
+  }
   return cons(m, n);
 }
 
+/* (:args_tail keywords rest_keywords_sym block_sym) */
+static node*
+new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk)
+{
+  node *k;
+
+  if (kws || kwrest) {
+    local_add_kw(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : 0);
+  }
+
+  local_add_blk(p, blk);
+
+  /* allocate register for keywords arguments */
+  /* order is for Proc#parameters */
+  for (k = kws; k; k = k->cdr) {
+    if (!k->car->cdr->cdr->car) { /* allocate required keywords */
+      local_add_f(p, sym(k->car->cdr->car));
+    }
+  }
+  for (k = kws; k; k = k->cdr) {
+    if (k->car->cdr->cdr->car) { /* allocate keywords with default */
+      local_add_lv(p, k->car->cdr->cdr->car->cdr);
+      k->car->cdr->cdr->car = k->car->cdr->cdr->car->car;
+      local_add_f(p, sym(k->car->cdr->car));
+    }
+  }
+
+  return list4((node*)NODE_ARGS_TAIL, kws, kwrest, nsym(blk));
+}
+
+/* (:kw_arg kw_sym def_arg) */
+static node*
+new_kw_arg(parser_state *p, mrb_sym kw, node *def_arg)
+{
+  mrb_assert(kw);
+  return list3((node*)NODE_KW_ARG, nsym(kw), def_arg);
+}
+
 /* (:block_arg . a) */
 static node*
@@ -696,8 +835,39 @@
 }
 
+static node*
+setup_numparams(parser_state *p, node *a)
+{
+  int nvars = intn(p->nvars->car);
+  if (nvars > 0) {
+    int i;
+    mrb_sym sym;
+    // m || opt || rest || tail
+    if (a && (a->car || (a->cdr && a->cdr->car) || (a->cdr->cdr && a->cdr->cdr->car) || (a->cdr->cdr->cdr->cdr && a->cdr->cdr->cdr->cdr->car))) {
+      yyerror(p, "ordinary parameter is defined");
+    }
+    else if (p->locals) {
+      /* p->locals should not be NULL unless error happens before the point */
+      node* args = 0;
+      for (i = nvars; i > 0; i--) {
+        char buf[3];
+
+        buf[0] = '_';
+        buf[1] = i+'0';
+        buf[2] = '\0';
+        sym = intern_cstr(buf);
+        args = cons(new_arg(p, sym), args);
+        p->locals->car = cons(nsym(sym), p->locals->car);
+      }
+      a = new_args(p, args, 0, 0, 0, 0);
+    }
+  }
+  return a;
+}
+
 /* (:block arg body) */
 static node*
 new_block(parser_state *p, node *a, node *b)
 {
+  a = setup_numparams(p, a);
   return list4((node*)NODE_BLOCK, locals_node(p), a, b);
 }
@@ -726,4 +896,11 @@
 }
 
+/* (:masgn mlhs mrhs) no check */
+static node*
+new_masgn_param(parser_state *p, node *a, node *b)
+{
+  return cons((node*)NODE_MASGN, cons(a, b));
+}
+
 /* (:asgn lhs rhs) */
 static node*
@@ -734,21 +911,49 @@
 }
 
+static node*
+new_imaginary(parser_state *p, node *imaginary)
+{
+  return new_call(p, new_const(p, intern_lit("Kernel")), intern_lit("Complex"), list1(list2(list3((node*)NODE_INT, (node*)strdup("0"), nint(10)), imaginary)), 1);
+}
+
+static node*
+new_rational(parser_state *p, node *rational)
+{
+  return new_call(p, new_const(p, intern_lit("Kernel")), intern_lit("Rational"), list1(list1(rational)), 1);
+}
+
 /* (:int . i) */
 static node*
-new_int(parser_state *p, const char *s, int base)
-{
-  return list3((node*)NODE_INT, (node*)strdup(s), nint(base));
-}
-
+new_int(parser_state *p, const char *s, int base, int suffix)
+{
+  node* result = list3((node*)NODE_INT, (node*)strdup(s), nint(base));
+  if (suffix & NUM_SUFFIX_R) {
+    result = new_rational(p, result);
+  }
+  if (suffix & NUM_SUFFIX_I) {
+    result = new_imaginary(p, result);
+  }
+  return result;
+}
+
+#ifndef MRB_WITHOUT_FLOAT
 /* (:float . i) */
 static node*
-new_float(parser_state *p, const char *s)
-{
-  return cons((node*)NODE_FLOAT, (node*)strdup(s));
-}
+new_float(parser_state *p, const char *s, int suffix)
+{
+  node* result = cons((node*)NODE_FLOAT, (node*)strdup(s));
+  if (suffix & NUM_SUFFIX_R) {
+    result = new_rational(p, result);
+  }
+  if (suffix & NUM_SUFFIX_I) {
+    result = new_imaginary(p, result);
+  }
+  return result;
+}
+#endif
 
 /* (:str . (s . len)) */
 static node*
-new_str(parser_state *p, const char *s, int len)
+new_str(parser_state *p, const char *s, size_t len)
 {
   return cons((node*)NODE_STR, cons((node*)strndup(s, len), nint(len)));
@@ -762,4 +967,84 @@
 }
 
+static int
+string_node_p(node *n)
+{
+  return (int)((enum node_type)(intptr_t)n->car == NODE_STR);
+}
+
+static node*
+composite_string_node(parser_state *p, node *a, node *b)
+{
+  size_t newlen = (size_t)a->cdr + (size_t)b->cdr;
+  char *str = (char*)mrb_pool_realloc(p->pool, a->car, (size_t)a->cdr + 1, newlen + 1);
+  memcpy(str + (size_t)a->cdr, b->car, (size_t)b->cdr);
+  str[newlen] = '\0';
+  a->car = (node*)str;
+  a->cdr = (node*)newlen;
+  cons_free(b);
+  return a;
+}
+
+static node*
+concat_string(parser_state *p, node *a, node *b)
+{
+  if (string_node_p(a)) {
+    if (string_node_p(b)) {
+      /* a == NODE_STR && b == NODE_STR */
+      composite_string_node(p, a->cdr, b->cdr);
+      cons_free(b);
+      return a;
+    }
+    else {
+      /* a == NODE_STR && b == NODE_DSTR */
+
+      if (string_node_p(b->cdr->car)) {
+        /* a == NODE_STR && b->[NODE_STR, ...] */
+        composite_string_node(p, a->cdr, b->cdr->car->cdr);
+        cons_free(b->cdr->car);
+        b->cdr->car = a;
+        return b;
+      }
+    }
+  }
+  else {
+    node *c; /* last node of a */
+    for (c = a; c->cdr != NULL; c = c->cdr) ;
+
+    if (string_node_p(b)) {
+      /* a == NODE_DSTR && b == NODE_STR */
+      if (string_node_p(c->car)) {
+        /* a->[..., NODE_STR] && b == NODE_STR */
+        composite_string_node(p, c->car->cdr, b->cdr);
+        cons_free(b);
+        return a;
+      }
+
+      push(a, b);
+      return a;
+    }
+    else {
+      /* a == NODE_DSTR && b == NODE_DSTR */
+      if (string_node_p(c->car) && string_node_p(b->cdr->car)) {
+        /* a->[..., NODE_STR] && b->[NODE_STR, ...] */
+        node *d = b->cdr;
+        cons_free(b);
+        composite_string_node(p, c->car->cdr, d->car->cdr);
+        cons_free(d->car);
+        c->cdr = d->cdr;
+        cons_free(d);
+        return a;
+      }
+      else {
+        c->cdr = b->cdr;
+        cons_free(b);
+        return a;
+      }
+    }
+  }
+
+  return new_dstr(p, list2(a, b));
+}
+
 /* (:str . (s . len)) */
 static node*
@@ -780,5 +1065,5 @@
 new_dsym(parser_state *p, node *a)
 {
-  return cons((node*)NODE_DSYM, new_dstr(p, a));
+  return cons((node*)NODE_DSYM, a);
 }
 
@@ -1024,9 +1309,7 @@
   if (p->parsing_heredoc == NULL) {
     p->lstate = EXPR_BEG;
-    p->cmd_start = TRUE;
     end_strterm(p);
     p->lex_strterm = p->lex_strterm_before_heredoc;
     p->lex_strterm_before_heredoc = NULL;
-    p->heredoc_end_now = TRUE;
   }
   else {
@@ -1105,11 +1388,12 @@
         keyword__ENCODING__
 
-%token <id>  tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
+%token <id>  tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL_TAG
 %token <nd>  tINTEGER tFLOAT tCHAR tXSTRING tREGEXP
-%token <nd>  tSTRING tSTRING_PART tSTRING_MID tLABEL_END
+%token <nd>  tSTRING tSTRING_PART tSTRING_MID
 %token <nd>  tNTH_REF tBACK_REF
 %token <num> tREGEXP_END
-
-%type <nd> singleton string string_rep string_interp xstring regexp
+%token <num> tNUMPARAM
+
+%type <nd> singleton string string_fragment string_rep string_interp xstring regexp
 %type <nd> literal numeric cpath symbol
 %type <nd> top_compstmt top_stmts top_stmt
@@ -1122,5 +1406,5 @@
 %type <nd> command_asgn command_rhs mrhs superclass block_call block_command
 %type <nd> f_block_optarg f_block_opt
-%type <nd> f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs
+%type <nd> f_arglist f_args f_arg f_arg_item f_optarg f_margs
 %type <nd> assoc_list assocs assoc undef_list backref for_var
 %type <nd> block_param opt_block_param block_param_def f_opt
@@ -1132,4 +1416,8 @@
 %type <nd> heredoc words symbols
 %type <num> call_op call_op2     /* 0:'&.', 1:'.', 2:'::' */
+
+%type <nd> args_tail opt_args_tail f_kwarg f_kw f_kwrest
+%type <nd> f_block_kwarg f_block_kw block_args_tail opt_block_args_tail
+%type <id> f_label
 
 %token tUPLUS             /* unary+ */
@@ -1158,4 +1446,5 @@
 %token tLBRACE_ARG        /* { */
 %token tSTAR              /* * */
+%token tDSTAR             /* ** */
 %token tAMPER             /* & */
 %token tLAMBDA            /* -> */
@@ -1179,5 +1468,5 @@
 %right '=' tOP_ASGN
 %left modifier_rescue
-%right '?' ':'
+%right '?' ':' tLABEL_TAG
 %nonassoc tDOT2 tDOT3
 %left  tOROP
@@ -1237,4 +1526,5 @@
                     {
                       $<nd>$ = local_switch(p);
+                      nvars_block(p);
                     }
                   '{' top_compstmt '}'
@@ -1242,4 +1532,5 @@
                       yyerror(p, "BEGIN not supported");
                       local_resume(p, $<nd>2);
+                      nvars_unnest(p);
                       $$ = 0;
                     }
@@ -1359,7 +1650,7 @@
                       $$ = new_op_asgn(p, $1, $2, $3);
                     }
-                | primary_value '[' opt_call_args rbracket tOP_ASGN command_rhs
-                    {
-                      $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3, '.'), $5, $6);
+                | primary_value '[' opt_call_args ']' tOP_ASGN command_rhs
+                    {
+                      $$ = new_op_asgn(p, new_call(p, $1, intern_lit("[]"), $3, '.'), $5, $6);
                     }
                 | primary_value call_op tIDENTIFIER tOP_ASGN command_rhs
@@ -1385,5 +1676,5 @@
                       $$ = new_begin(p, 0);
                     }
-		;
+                ;
 
 command_rhs     : command_call   %prec tOP_ASGN
@@ -1439,4 +1730,5 @@
                     {
                       local_nest(p);
+                      nvars_nest(p);
                     }
                   opt_block_param
@@ -1446,4 +1738,5 @@
                       $$ = new_block(p, $3, $4);
                       local_unnest(p);
+                      nvars_unnest(p);
                     }
                 ;
@@ -1588,7 +1881,7 @@
                       assignable(p, $1);
                     }
-                | primary_value '[' opt_call_args rbracket
-                    {
-                      $$ = new_call(p, $1, intern("[]",2), $3, '.');
+                | primary_value '[' opt_call_args ']'
+                    {
+                      $$ = new_call(p, $1, intern_lit("[]"), $3, '.');
                     }
                 | primary_value call_op tIDENTIFIER
@@ -1627,7 +1920,7 @@
                       assignable(p, $1);
                     }
-                | primary_value '[' opt_call_args rbracket
-                    {
-                      $$ = new_call(p, $1, intern("[]",2), $3, '.');
+                | primary_value '[' opt_call_args ']'
+                    {
+                      $$ = new_call(p, $1, intern_lit("[]"), $3, '.');
                     }
                 | primary_value call_op tIDENTIFIER
@@ -1659,4 +1952,8 @@
                       backref_error(p, $1);
                       $$ = 0;
+                    }
+                | tNUMPARAM
+                    {
+                      yyerror(p, "can't assign to numbered parameter");
                     }
                 ;
@@ -1713,33 +2010,34 @@
                 ;
 
-op              : '|'           { $$ = intern_c('|');   }
-                | '^'           { $$ = intern_c('^');   }
-                | '&'           { $$ = intern_c('&');   }
-                | tCMP          { $$ = intern("<=>",3); }
-                | tEQ           { $$ = intern("==",2);  }
-                | tEQQ          { $$ = intern("===",3); }
-                | tMATCH        { $$ = intern("=~",2);  }
-                | tNMATCH       { $$ = intern("!~",2);  }
-                | '>'           { $$ = intern_c('>');   }
-                | tGEQ          { $$ = intern(">=",2);  }
-                | '<'           { $$ = intern_c('<');   }
-                | tLEQ          { $$ = intern("<=",2);  }
-                | tNEQ          { $$ = intern("!=",2);  }
-                | tLSHFT        { $$ = intern("<<",2);  }
-                | tRSHFT        { $$ = intern(">>",2);  }
-                | '+'           { $$ = intern_c('+');   }
-                | '-'           { $$ = intern_c('-');   }
-                | '*'           { $$ = intern_c('*');   }
-                | tSTAR         { $$ = intern_c('*');   }
-                | '/'           { $$ = intern_c('/');   }
-                | '%'           { $$ = intern_c('%');   }
-                | tPOW          { $$ = intern("**",2);  }
-                | '!'           { $$ = intern_c('!');   }
-                | '~'           { $$ = intern_c('~');   }
-                | tUPLUS        { $$ = intern("+@",2);  }
-                | tUMINUS       { $$ = intern("-@",2);  }
-                | tAREF         { $$ = intern("[]",2);  }
-                | tASET         { $$ = intern("[]=",3); }
-                | '`'           { $$ = intern_c('`');   }
+op              : '|'           { $$ = intern_lit("|");   }
+                | '^'           { $$ = intern_lit("^");   }
+                | '&'           { $$ = intern_lit("&");   }
+                | tCMP          { $$ = intern_lit("<=>"); }
+                | tEQ           { $$ = intern_lit("==");  }
+                | tEQQ          { $$ = intern_lit("==="); }
+                | tMATCH        { $$ = intern_lit("=~");  }
+                | tNMATCH       { $$ = intern_lit("!~");  }
+                | '>'           { $$ = intern_lit(">");   }
+                | tGEQ          { $$ = intern_lit(">=");  }
+                | '<'           { $$ = intern_lit("<");   }
+                | tLEQ          { $$ = intern_lit("<=");  }
+                | tNEQ          { $$ = intern_lit("!=");  }
+                | tLSHFT        { $$ = intern_lit("<<");  }
+                | tRSHFT        { $$ = intern_lit(">>");  }
+                | '+'           { $$ = intern_lit("+");   }
+                | '-'           { $$ = intern_lit("-");   }
+                | '*'           { $$ = intern_lit("*");   }
+                | tSTAR         { $$ = intern_lit("*");   }
+                | '/'           { $$ = intern_lit("/");   }
+                | '%'           { $$ = intern_lit("%");   }
+                | tPOW          { $$ = intern_lit("**");  }
+                | tDSTAR        { $$ = intern_lit("**");  }
+                | '!'           { $$ = intern_lit("!");   }
+                | '~'           { $$ = intern_lit("~");   }
+                | tUPLUS        { $$ = intern_lit("+@");  }
+                | tUMINUS       { $$ = intern_lit("-@");  }
+                | tAREF         { $$ = intern_lit("[]");  }
+                | tASET         { $$ = intern_lit("[]="); }
+                | '`'           { $$ = intern_lit("`");   }
                 ;
 
@@ -1766,7 +2064,7 @@
                       $$ = new_op_asgn(p, $1, $2, $3);
                     }
-                | primary_value '[' opt_call_args rbracket tOP_ASGN arg_rhs
-                    {
-                      $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3, '.'), $5, $6);
+                | primary_value '[' opt_call_args ']' tOP_ASGN arg_rhs
+                    {
+                      $$ = new_op_asgn(p, new_call(p, $1, intern_lit("[]"), $3, '.'), $5, $6);
                     }
                 | primary_value call_op tIDENTIFIER tOP_ASGN arg_rhs
@@ -1925,4 +2223,8 @@
                       $$ = new_if(p, cond($1), $3, $6);
                     }
+                | arg '?' arg opt_nl tLABEL_TAG arg
+                    {
+                      $$ = new_if(p, cond($1), $3, $6);
+                    }
                 | primary
                     {
@@ -1939,9 +2241,9 @@
                 | args comma assocs trailer
                     {
-                      $$ = push($1, new_hash(p, $3));
+                      $$ = push($1, new_kw_hash(p, $3));
                     }
                 | assocs trailer
                     {
-                      $$ = cons(new_hash(p, $1), 0);
+                      $$ = cons(new_kw_hash(p, $1), 0);
                       NODE_LINENO($$, $1);
                     }
@@ -1960,5 +2262,5 @@
                 ;
 
-paren_args      : '(' opt_call_args rparen
+paren_args      : '(' opt_call_args ')'
                     {
                       $$ = $2;
@@ -1971,18 +2273,18 @@
 
 opt_call_args   : none
-                | call_args
-                | args ','
+                | call_args opt_terms
+                | args comma
                     {
                       $$ = cons($1,0);
                       NODE_LINENO($$, $1);
                     }
-                | args comma assocs ','
-                    {
-                      $$ = cons(push($1, new_hash(p, $3)), 0);
+                | args comma assocs comma
+                    {
+                      $$ = cons(push($1, new_kw_hash(p, $3)), 0);
                       NODE_LINENO($$, $1);
                     }
-                | assocs ','
-                    {
-                      $$ = cons(list1(new_hash(p, $1)), 0);
+                | assocs comma
+                    {
+                      $$ = cons(list1(new_kw_hash(p, $1)), 0);
                       NODE_LINENO($$, $1);
                     }
@@ -2002,10 +2304,10 @@
                 | assocs opt_block_arg
                     {
-                      $$ = cons(list1(new_hash(p, $1)), $2);
+                      $$ = cons(list1(new_kw_hash(p, $1)), $2);
                       NODE_LINENO($$, $1);
                     }
                 | args comma assocs opt_block_arg
                     {
-                      $$ = cons(push($1, new_hash(p, $3)), $4);
+                      $$ = cons(push($1, new_kw_hash(p, $3)), $4);
                       NODE_LINENO($$, $1);
                     }
@@ -2045,5 +2347,5 @@
 
 comma           : ','
-                | ','  heredoc_bodies
+                | ','  opt_nl heredoc_bodies
                 ;
 
@@ -2096,4 +2398,8 @@
                 | var_ref
                 | backref
+                | tNUMPARAM
+                    {
+                      $$ = new_nvar(p, $1);
+                    }
                 | tFID
                     {
@@ -2248,4 +2554,5 @@
                         yyerror(p, "class definition in method body");
                       $<nd>$ = local_switch(p);
+                      nvars_block(p);
                     }
                   bodystmt
@@ -2255,4 +2562,5 @@
                       SET_LINENO($$, $1);
                       local_resume(p, $<nd>4);
+                      nvars_unnest(p);
                     }
                 | keyword_class
@@ -2265,4 +2573,5 @@
                     {
                       $<nd>$ = cons(local_switch(p), nint(p->in_single));
+                      nvars_block(p);
                       p->in_single = 0;
                     }
@@ -2273,4 +2582,5 @@
                       SET_LINENO($$, $1);
                       local_resume(p, $<nd>6->car);
+                      nvars_unnest(p);
                       p->in_def = $<num>4;
                       p->in_single = intn($<nd>6->cdr);
@@ -2282,4 +2592,5 @@
                         yyerror(p, "module definition in method body");
                       $<nd>$ = local_switch(p);
+                      nvars_block(p);
                     }
                   bodystmt
@@ -2289,4 +2600,5 @@
                       SET_LINENO($$, $1);
                       local_resume(p, $<nd>3);
+                      nvars_unnest(p);
                     }
                 | keyword_def fname
@@ -2298,4 +2610,5 @@
                       p->in_def++;
                       $<nd>$ = local_switch(p);
+                      nvars_block(p);
                     }
                   f_arglist
@@ -2306,4 +2619,5 @@
                       SET_LINENO($$, $1);
                       local_resume(p, $<nd>4);
+                      nvars_unnest(p);
                       p->in_def--;
                       p->cmdarg_stack = $<stack>3;
@@ -2320,4 +2634,5 @@
                       p->lstate = EXPR_ENDFN; /* force for args */
                       $<nd>$ = local_switch(p);
+                      nvars_block(p);
                     }
                   f_arglist
@@ -2328,4 +2643,5 @@
                       SET_LINENO($$, $1);
                       local_resume(p, $<nd>6);
+                      nvars_unnest(p);
                       p->in_single--;
                       p->cmdarg_stack = $<stack>4;
@@ -2388,41 +2704,22 @@
                 ;
 
-f_marg          : f_norm_arg
-                    {
-                      $$ = new_arg(p, $1);
-                    }
-                | tLPAREN f_margs rparen
-                    {
-                      $$ = new_masgn(p, $2, 0);
-                    }
-                ;
-
-f_marg_list     : f_marg
-                    {
-                      $$ = list1($1);
-                    }
-                | f_marg_list ',' f_marg
-                    {
-                      $$ = push($1, $3);
-                    }
-                ;
-
-f_margs         : f_marg_list
+f_margs         : f_arg
                     {
                       $$ = list3($1,0,0);
                     }
-                | f_marg_list ',' tSTAR f_norm_arg
+                | f_arg ',' tSTAR f_norm_arg
                     {
                       $$ = list3($1, new_arg(p, $4), 0);
                     }
-                | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list
+                | f_arg ',' tSTAR f_norm_arg ',' f_arg
                     {
                       $$ = list3($1, new_arg(p, $4), $6);
                     }
-                | f_marg_list ',' tSTAR
-                    {
+                | f_arg ',' tSTAR
+                    {
+                      local_add_f(p, 0);
                       $$ = list3($1, (node*)-1, 0);
                     }
-                | f_marg_list ',' tSTAR ',' f_marg_list
+                | f_arg ',' tSTAR ',' f_arg
                     {
                       $$ = list3($1, (node*)-1, $5);
@@ -2432,5 +2729,5 @@
                       $$ = list3(0, new_arg(p, $2), 0);
                     }
-                | tSTAR f_norm_arg ',' f_marg_list
+                | tSTAR f_norm_arg ',' f_arg
                     {
                       $$ = list3(0, new_arg(p, $2), $4);
@@ -2438,69 +2735,102 @@
                 | tSTAR
                     {
+                      local_add_f(p, 0);
                       $$ = list3(0, (node*)-1, 0);
                     }
-                | tSTAR ',' f_marg_list
-                    {
-                      $$ = list3(0, (node*)-1, $3);
-                    }
-                ;
-
-block_param     : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
+                | tSTAR ','
+                    {
+                      local_add_f(p, 0);
+                    }
+                  f_arg
+                    {
+                      $$ = list3(0, (node*)-1, $4);
+                    }
+                ;
+
+block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, $1, $3, $4);
+                    }
+                | f_block_kwarg opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, $1, 0, $2);
+                    }
+                | f_kwrest opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, 0, $1, $2);
+                    }
+                | f_block_arg
+                    {
+                      $$ = new_args_tail(p, 0, 0, $1);
+                    }
+                ;
+
+opt_block_args_tail : ',' block_args_tail
+                    {
+                      $$ = $2;
+                    }
+                | /* none */
+                    {
+                      $$ = new_args_tail(p, 0, 0, 0);
+                    }
+                ;
+
+block_param     : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, $3, $5, 0, $6);
                     }
-                | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, $3, $5, $7, $8);
                     }
-                | f_arg ',' f_block_optarg opt_f_block_arg
+                | f_arg ',' f_block_optarg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, $3, 0, 0, $4);
                     }
-                | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg
+                | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, $3, 0, $5, $6);
                     }
-                | f_arg ',' f_rest_arg opt_f_block_arg
+                | f_arg ',' f_rest_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, 0, $3, 0, $4);
                     }
-                | f_arg ','
-                    {
-                      $$ = new_args(p, $1, 0, 0, 0, 0);
-                    }
-                | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_arg ',' opt_block_args_tail
+                    {
+                      $$ = new_args(p, $1, 0, 0, 0, $3);
+                    }
+                | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, 0, $3, $5, $6);
                     }
-                | f_arg opt_f_block_arg
+                | f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, 0, 0, 0, $2);
                     }
-                | f_block_optarg ',' f_rest_arg opt_f_block_arg
+                | f_block_optarg ',' f_rest_arg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, $1, $3, 0, $4);
                     }
-                | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, $1, $3, $5, $6);
                     }
-                | f_block_optarg opt_f_block_arg
+                | f_block_optarg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, $1, 0, 0, $2);
                     }
-                | f_block_optarg ',' f_arg opt_f_block_arg
+                | f_block_optarg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, $1, 0, $3, $4);
                     }
-                | f_rest_arg opt_f_block_arg
+                | f_rest_arg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, 0, $1, 0, $2);
                     }
-                | f_rest_arg ',' f_arg opt_f_block_arg
+                | f_rest_arg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, 0, $1, $3, $4);
                     }
-                | f_block_arg
+                | block_args_tail
                     {
                       $$ = new_args(p, 0, 0, 0, 0, $1);
@@ -2509,6 +2839,10 @@
 
 opt_block_param : none
+                    {
+                      local_add_blk(p, 0);
+                      $$ = 0;
+                    }
                 | block_param_def
-                    {
+                   {
                       p->cmd_start = TRUE;
                       $$ = $1;
@@ -2516,5 +2850,5 @@
                 ;
 
-block_param_def : '|' opt_bv_decl '|'
+block_param_def : '|' {local_add_blk(p, 0);} opt_bv_decl '|'
                     {
                       $$ = 0;
@@ -2522,4 +2856,5 @@
                 | tOROP
                     {
+                      local_add_blk(p, 0);
                       $$ = 0;
                     }
@@ -2567,5 +2902,5 @@
                       $$ = $2;
                     }
-                | keyword_do_LAMBDA compstmt keyword_end
+                | keyword_do_LAMBDA bodystmt keyword_end
                     {
                       $$ = $2;
@@ -2576,11 +2911,13 @@
                     {
                       local_nest(p);
+                      nvars_nest(p);
                     }
                   opt_block_param
-                  compstmt
+                  bodystmt
                   keyword_end
                     {
                       $$ = new_block(p,$3,$4);
                       local_unnest(p);
+                      nvars_unnest(p);
                     }
                 ;
@@ -2630,9 +2967,9 @@
                 | primary_value call_op paren_args
                     {
-                      $$ = new_call(p, $1, intern("call",4), $3, $2);
+                      $$ = new_call(p, $1, intern_lit("call"), $3, $2);
                     }
                 | primary_value tCOLON2 paren_args
                     {
-                      $$ = new_call(p, $1, intern("call",4), $3, tCOLON2);
+                      $$ = new_call(p, $1, intern_lit("call"), $3, tCOLON2);
                     }
                 | keyword_super paren_args
@@ -2644,7 +2981,7 @@
                       $$ = new_zsuper(p);
                     }
-                | primary_value '[' opt_call_args rbracket
-                    {
-                      $$ = new_call(p, $1, intern("[]",2), $3, '.');
+                | primary_value '[' opt_call_args ']'
+                    {
+                      $$ = new_call(p, $1, intern_lit("[]"), $3, '.');
                     }
                 ;
@@ -2653,4 +2990,5 @@
                     {
                       local_nest(p);
+                      nvars_nest(p);
                       $<num>$ = p->lineno;
                     }
@@ -2661,16 +2999,19 @@
                       SET_LINENO($$, $<num>2);
                       local_unnest(p);
+                      nvars_unnest(p);
                     }
                 | keyword_do
                     {
                       local_nest(p);
+                      nvars_nest(p);
                       $<num>$ = p->lineno;
                     }
                   opt_block_param
-                  compstmt keyword_end
+                  bodystmt keyword_end
                     {
                       $$ = new_block(p,$3,$4);
                       SET_LINENO($$, $<num>2);
                       local_unnest(p);
+                      nvars_unnest(p);
                     }
                 ;
@@ -2734,5 +3075,12 @@
                 ;
 
-string          : tCHAR
+string          : string_fragment
+                | string string_fragment
+                    {
+                      $$ = concat_string(p, $1, $2);
+                    }
+                ;
+
+string_fragment : tCHAR
                 | tSTRING
                 | tSTRING_BEG tSTRING
@@ -2854,10 +3202,11 @@
 symbol          : basic_symbol
                     {
+                      p->lstate = EXPR_ENDARG;
                       $$ = new_sym(p, $1);
                     }
                 | tSYMBEG tSTRING_BEG string_rep tSTRING
                     {
-                      p->lstate = EXPR_END;
-                      $$ = new_dsym(p, push($3, $4));
+                      p->lstate = EXPR_ENDARG;
+                      $$ = new_dsym(p, new_dstr(p, push($3, $4)));
                     }
                 ;
@@ -2865,5 +3214,4 @@
 basic_symbol    : tSYMBEG sym
                     {
-                      p->lstate = EXPR_END;
                       $$ = $2;
                     }
@@ -2932,4 +3280,8 @@
                       assignable(p, $1);
                     }
+                | tNUMPARAM
+                    {
+                      yyerror(p, "can't assign to numbered parameter");
+                    }
                 ;
 
@@ -2956,5 +3308,5 @@
                 | keyword__FILE__
                     {
-                      const char *fn = p->filename;
+                      const char *fn = mrb_sym_name_len(p->mrb, p->filename_sym, NULL);
                       if (!fn) {
                         fn = "(null)";
@@ -2966,6 +3318,15 @@
                       char buf[16];
 
-                      snprintf(buf, sizeof(buf), "%d", p->lineno);
-                      $$ = new_int(p, buf, 10);
+                      dump_int(p->lineno, buf);
+                      $$ = new_int(p, buf, 10, 0);
+                    }
+                | keyword__ENCODING__
+                    {
+#ifdef MRB_UTF8_STRING
+                      const char *enc = "UTF-8";
+#else
+                      const char *enc = "ASCII-8BIT";
+#endif
+                      $$ = new_str(p, enc, strlen(enc));
                     }
                 ;
@@ -3007,57 +3368,150 @@
                 ;
 
-f_args          : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg
+f_label         : tIDENTIFIER tLABEL_TAG
+                    {
+                      local_nest(p);
+                    }
+                ;
+
+f_kw            : f_label arg
+                    {
+                      void_expr_error(p, $2);
+                      $$ = new_kw_arg(p, $1, cons($2, locals_node(p)));
+                      local_unnest(p);
+                    }
+                | f_label
+                    {
+                      $$ = new_kw_arg(p, $1, 0);
+                      local_unnest(p);
+                    }
+                ;
+
+f_block_kw      : f_label primary_value
+                    {
+                      $$ = new_kw_arg(p, $1, cons($2, locals_node(p)));
+                      local_unnest(p);
+                    }
+                | f_label
+                    {
+                      $$ = new_kw_arg(p, $1, 0);
+                      local_unnest(p);
+                    }
+                ;
+
+f_block_kwarg   : f_block_kw
+                    {
+                      $$ = list1($1);
+                    }
+                | f_block_kwarg ',' f_block_kw
+                    {
+                      $$ = push($1, $3);
+                    }
+                ;
+
+f_kwarg         : f_kw
+                    {
+                      $$ = list1($1);
+                    }
+                | f_kwarg ',' f_kw
+                    {
+                      $$ = push($1, $3);
+                    }
+                ;
+
+kwrest_mark     : tPOW
+                | tDSTAR
+                ;
+
+f_kwrest        : kwrest_mark tIDENTIFIER
+                    {
+                      $$ = cons((node*)NODE_KW_REST_ARGS, nsym($2));
+                    }
+                | kwrest_mark
+                    {
+                      $$ = cons((node*)NODE_KW_REST_ARGS, 0);
+                    }
+                ;
+
+args_tail       : f_kwarg ',' f_kwrest opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, $1, $3, $4);
+                    }
+                | f_kwarg opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, $1, 0, $2);
+                    }
+                | f_kwrest opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, 0, $1, $2);
+                    }
+                | f_block_arg
+                    {
+                      $$ = new_args_tail(p, 0, 0, $1);
+                    }
+                ;
+
+opt_args_tail   : ',' args_tail
+                    {
+                      $$ = $2;
+                    }
+                | /* none */
+                    {
+                      $$ = new_args_tail(p, 0, 0, 0);
+                    }
+                ;
+
+f_args          : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, $3, $5, 0, $6);
                     }
-                | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, $3, $5, $7, $8);
                     }
-                | f_arg ',' f_optarg opt_f_block_arg
+                | f_arg ',' f_optarg opt_args_tail
                     {
                       $$ = new_args(p, $1, $3, 0, 0, $4);
                     }
-                | f_arg ',' f_optarg ',' f_arg opt_f_block_arg
+                | f_arg ',' f_optarg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, $3, 0, $5, $6);
                     }
-                | f_arg ',' f_rest_arg opt_f_block_arg
+                | f_arg ',' f_rest_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, 0, $3, 0, $4);
                     }
-                | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_arg ',' f_rest_arg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, 0, $3, $5, $6);
                     }
-                | f_arg opt_f_block_arg
+                | f_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, 0, 0, 0, $2);
                     }
-                | f_optarg ',' f_rest_arg opt_f_block_arg
+                | f_optarg ',' f_rest_arg opt_args_tail
                     {
                       $$ = new_args(p, 0, $1, $3, 0, $4);
                     }
-                | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, 0, $1, $3, $5, $6);
                     }
-                | f_optarg opt_f_block_arg
+                | f_optarg opt_args_tail
                     {
                       $$ = new_args(p, 0, $1, 0, 0, $2);
                     }
-                | f_optarg ',' f_arg opt_f_block_arg
+                | f_optarg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, 0, $1, 0, $3, $4);
                     }
-                | f_rest_arg opt_f_block_arg
+                | f_rest_arg opt_args_tail
                     {
                       $$ = new_args(p, 0, 0, $1, 0, $2);
                     }
-                | f_rest_arg ',' f_arg opt_f_block_arg
+                | f_rest_arg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, 0, 0, $1, $3, $4);
                     }
-                | f_block_arg
+                | args_tail
                     {
                       $$ = new_args(p, 0, 0, 0, 0, $1);
@@ -3065,5 +3519,5 @@
                 | /* none */
                     {
-                      local_add_f(p, 0);
+                      local_add_f(p, mrb_intern_lit(p->mrb, "&"));
                       $$ = new_args(p, 0, 0, 0, 0, 0);
                     }
@@ -3090,4 +3544,9 @@
                       $$ = 0;
                     }
+                | tNUMPARAM
+                    {
+                      yyerror(p, "formal argument cannot be a numbered parameter");
+                      $$ = 0;
+                    }
                 ;
 
@@ -3107,7 +3566,13 @@
                       $$ = new_arg(p, $1);
                     }
-                | tLPAREN f_margs rparen
-                    {
-                      $$ = new_masgn(p, $2, 0);
+                | tLPAREN
+                    {
+                      $<nd>$ = local_switch(p);
+                    }
+                  f_margs rparen
+                    {
+                      $$ = new_masgn_param(p, $3, p->locals->car);
+                      local_resume(p, $<nd>2);
+                      local_add_f(p, 0);
                     }
                 ;
@@ -3126,4 +3591,5 @@
                     {
                       local_add_f(p, $1);
+                      local_nest(p);
                       $$ = $1;
                     }
@@ -3133,5 +3599,6 @@
                     {
                       void_expr_error(p, $2);
-                      $$ = cons(nsym($1), $2);
+                      $$ = cons(nsym($1), cons($2, locals_node(p)));
+                      local_unnest(p);
                     }
                 ;
@@ -3140,5 +3607,6 @@
                     {
                       void_expr_error(p, $2);
-                      $$ = cons(nsym($1), $2);
+                      $$ = cons(nsym($1), cons($2, locals_node(p)));
+                      local_unnest(p);
                     }
                 ;
@@ -3175,5 +3643,5 @@
                 | restarg_mark
                     {
-                      local_add_f(p, 0);
+                      local_add_f(p, mrb_intern_lit(p->mrb, "*"));
                       $$ = -1;
                     }
@@ -3186,5 +3654,4 @@
 f_block_arg     : blkarg_mark tIDENTIFIER
                     {
-                      local_add_f(p, $2);
                       $$ = $2;
                     }
@@ -3197,5 +3664,4 @@
                 | none
                     {
-                      local_add_f(p, 0);
                       $$ = 0;
                     }
@@ -3244,8 +3710,12 @@
                       NODE_LINENO($$, $1);
                     }
-                | assocs ',' assoc
+                | assocs comma assoc
                     {
                       $$ = push($1, $3);
                     }
+                ;
+
+label_tag       : tLABEL_TAG
+                | tLABEL_TAG heredoc_bodies
                 ;
 
@@ -3256,23 +3726,23 @@
                       $$ = cons($1, $3);
                     }
-                | tLABEL arg
+                | tIDENTIFIER label_tag arg
+                    {
+                      void_expr_error(p, $3);
+                      $$ = cons(new_sym(p, $1), $3);
+                    }
+                | string_fragment label_tag arg
+                    {
+                      void_expr_error(p, $3);
+                      if ($1->car == (node*)NODE_DSTR) {
+                        $$ = cons(new_dsym(p, $1), $3);
+                      }
+                      else {
+                        $$ = cons(new_sym(p, new_strsym(p, $1)), $3);
+                      }
+                    }
+                | tDSTAR arg
                     {
                       void_expr_error(p, $2);
-                      $$ = cons(new_sym(p, $1), $2);
-                    }
-                | tLABEL_END arg
-                    {
-                      void_expr_error(p, $2);
-                      $$ = cons(new_sym(p, new_strsym(p, $1)), $2);
-                    }
-                | tSTRING_BEG tLABEL_END arg
-                    {
-                      void_expr_error(p, $3);
-                      $$ = cons(new_sym(p, new_strsym(p, $2)), $3);
-                    }
-                | tSTRING_BEG string_rep tLABEL_END arg
-                    {
-                      void_expr_error(p, $4);
-                      $$ = cons(new_dsym(p, push($2, $3)), $4);
+                      $$ = cons(cons((node*)NODE_KW_REST_ARGS, 0), $2);
                     }
                 ;
@@ -3323,12 +3793,9 @@
                 ;
 
-rparen          : opt_nl ')'
-                ;
-
-rbracket        : opt_nl ']'
+rparen          : opt_terms ')'
                 ;
 
 trailer         : /* none */
-                | nl
+                | terms
                 | comma
                 ;
@@ -3362,10 +3829,11 @@
 {
   char* c;
-  int n;
+  size_t n;
 
   if (! p->capture_errors) {
 #ifndef MRB_DISABLE_STDIO
-    if (p->filename) {
-      fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s);
+    if (p->filename_sym) {
+      const char *filename = mrb_sym_name_len(p->mrb, p->filename_sym, NULL);
+      fprintf(stderr, "%s:%d:%d: %s\n", filename, p->lineno, p->column, s);
     }
     else {
@@ -3386,9 +3854,11 @@
 
 static void
-yyerror_i(parser_state *p, const char *fmt, int i)
+yyerror_c(parser_state *p, const char *msg, char c)
 {
   char buf[256];
 
-  snprintf(buf, sizeof(buf), fmt, i);
+  strncpy(buf, msg, sizeof(buf) - 2);
+  buf[sizeof(buf) - 2] = '\0';
+  strncat(buf, &c, 1);
   yyerror(p, buf);
 }
@@ -3398,13 +3868,14 @@
 {
   char* c;
-  int n;
+  size_t n;
 
   if (! p->capture_errors) {
 #ifndef MRB_DISABLE_STDIO
-    if (p->filename) {
-      fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s);
+    if (p->filename_sym) {
+      const char *filename = mrb_sym_name_len(p->mrb, p->filename_sym, NULL);
+      fprintf(stderr, "%s:%d:%d: warning: %s\n", filename, p->lineno, p->column, s);
     }
     else {
-      fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s);
+      fprintf(stderr, "line %d:%d: warning: %s\n", p->lineno, p->column, s);
     }
 #endif
@@ -3428,9 +3899,12 @@
 
 static void
-yywarning_s(parser_state *p, const char *fmt, const char *s)
+yywarning_s(parser_state *p, const char *msg, const char *s)
 {
   char buf[256];
 
-  snprintf(buf, sizeof(buf), fmt, s);
+  strncpy(buf, msg, sizeof(buf) - 1);
+  buf[sizeof(buf) - 1] = '\0';
+  strncat(buf, ": ", sizeof(buf) - strlen(buf) - 1);
+  strncat(buf, s, sizeof(buf) - strlen(buf) - 1);
   yywarning(p, buf);
 }
@@ -3441,14 +3915,14 @@
   int c;
 
-  c = (int)(intptr_t)n->car;
+  c = intn(n->car);
 
   if (c == NODE_NTH_REF) {
-    yyerror_i(p, "can't set variable $%" MRB_PRId, (mrb_int)(intptr_t)n->cdr);
+    yyerror_c(p, "can't set variable $", (char)intn(n->cdr)+'0');
   }
   else if (c == NODE_BACK_REF) {
-    yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr);
+    yyerror_c(p, "can't set variable $", (char)intn(n->cdr));
   }
   else {
-    mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c));
+    mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %d", c);
   }
 }
@@ -3460,5 +3934,5 @@
 
   if (n == NULL) return;
-  c = (int)(intptr_t)n->car;
+  c = intn(n->car);
   switch (c) {
   case NODE_BREAK:
@@ -3471,6 +3945,8 @@
   case NODE_AND:
   case NODE_OR:
-    void_expr_error(p, n->cdr->car);
-    void_expr_error(p, n->cdr->cdr);
+    if (n->cdr) {
+      void_expr_error(p, n->cdr->car);
+      void_expr_error(p, n->cdr->cdr);
+    }
     break;
   case NODE_BEGIN:
@@ -3492,4 +3968,25 @@
 
 static inline int
+nextc0(parser_state *p)
+{
+  int c;
+#ifndef MRB_DISABLE_STDIO
+  if (p->f) {
+    if (feof(p->f)) return -1;
+    c = fgetc(p->f);
+    if (c == EOF) return -1;
+  }
+  else
+#endif
+    if (!p->s || p->s >= p->send) {
+      return -1;
+    }
+    else {
+      c = (unsigned char)*p->s++;
+    }
+  return c;
+}
+
+static inline int
 nextc(parser_state *p)
 {
@@ -3499,5 +3996,5 @@
     node *tmp;
 
-    c = (int)(intptr_t)p->pb->car;
+    c = intn(p->pb->car);
     tmp = p->pb;
     p->pb = p->pb->cdr;
@@ -3505,18 +4002,6 @@
   }
   else {
-#ifndef MRB_DISABLE_STDIO
-    if (p->f) {
-      if (feof(p->f)) goto eof;
-      c = fgetc(p->f);
-      if (c == EOF) goto eof;
-    }
-    else
-#endif
-      if (!p->s || p->s >= p->send) {
-        goto eof;
-      }
-      else {
-        c = (unsigned char)*p->s++;
-      }
+    c = nextc0(p);
+    if (c < 0) goto eof;
   }
   if (c >= 0) {
@@ -3524,10 +4009,9 @@
   }
   if (c == '\r') {
-    c = nextc(p);
-    if (c != '\n') {
-      pushback(p, c);
-      return '\r';
-    }
-    return c;
+    const int lf = nextc0(p);
+    if (lf == '\n') {
+      return '\n';
+    }
+    if (lf > 0) pushback(p, lf);
   }
   return c;
@@ -3548,5 +4032,5 @@
     p->column--;
   }
-  p->pb = cons((node*)(intptr_t)c, p->pb);
+  p->pb = cons(nint(c), p->pb);
 }
 
@@ -3573,5 +4057,5 @@
     if (c0 == -1) return c0;    /* do not skip partial EOF */
     if (c0 >= 0) --p->column;
-    list = push(list, (node*)(intptr_t)c0);
+    list = push(list, nint(c0));
   } while(n--);
   if (p->pb) {
@@ -3594,5 +4078,5 @@
 peeks(parser_state *p, const char *s)
 {
-  int len = strlen(s);
+  size_t len = strlen(s);
 
 #ifndef MRB_DISABLE_STDIO
@@ -3630,5 +4114,5 @@
     s++;
     if (peeks(p, s)) {
-      int len = strlen(s);
+      size_t len = strlen(s);
 
       while (len--) {
@@ -3752,9 +4236,9 @@
 #define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1))
 
-static int
+static int32_t
 scan_oct(const int *start, int len, int *retlen)
 {
   const int *s = start;
-  int retval = 0;
+  int32_t retval = 0;
 
   /* mrb_assert(len <= 3) */
@@ -3763,5 +4247,5 @@
     retval |= *s++ - '0';
   }
-  *retlen = s - start;
+  *retlen = (int)(s - start);
 
   return retval;
@@ -3769,9 +4253,9 @@
 
 static int32_t
-scan_hex(const int *start, int len, int *retlen)
+scan_hex(parser_state *p, const int *start, int len, int *retlen)
 {
   static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
   const int *s = start;
-  int32_t retval = 0;
+  uint32_t retval = 0;
   char *tmp;
 
@@ -3782,7 +4266,7 @@
     s++;
   }
-  *retlen = s - start;
-
-  return retval;
+  *retlen = (int)(s - start);
+
+  return (int32_t)retval;
 }
 
@@ -3790,12 +4274,16 @@
 read_escape_unicode(parser_state *p, int limit)
 {
-  int32_t c;
   int buf[9];
   int i;
+  int32_t hex;
 
   /* Look for opening brace */
   i = 0;
   buf[0] = nextc(p);
-  if (buf[0] < 0) goto eof;
+  if (buf[0] < 0) {
+  eof:
+    yyerror(p, "invalid escape character syntax");
+    return -1;
+  }
   if (ISXDIGIT(buf[0])) {
     /* \uxxxx form */
@@ -3812,15 +4300,10 @@
     pushback(p, buf[0]);
   }
-  c = scan_hex(buf, i, &i);
-  if (i == 0) {
-  eof:
-    yyerror(p, "Invalid escape character syntax");
+  hex = scan_hex(p, buf, i, &i);
+  if (i == 0 || hex > 0x10FFFF || (hex & 0xFFFFF800) == 0xD800) {
+    yyerror(p, "invalid Unicode code point");
     return -1;
   }
-  if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) {
-    yyerror(p, "Invalid Unicode code point");
-    return -1;
-  }
-  return c;
+  return hex;
 }
 
@@ -3888,11 +4371,10 @@
       }
     }
-    c = scan_hex(buf, i, &i);
     if (i == 0) {
-      yyerror(p, "Invalid escape character syntax");
-      return 0;
-    }
-  }
-  return c;
+      yyerror(p, "invalid hex escape");
+      return -1;
+    }
+    return scan_hex(p, buf, i, &i);
+  }
 
   case 'u':     /* Unicode */
@@ -3961,9 +4443,8 @@
   int c;
   string_type type = (string_type)(intptr_t)p->lex_strterm->car;
-  int nest_level = (intptr_t)p->lex_strterm->cdr->car;
-  int beg = (intptr_t)p->lex_strterm->cdr->cdr->car;
-  int end = (intptr_t)p->lex_strterm->cdr->cdr->cdr;
+  int nest_level = intn(p->lex_strterm->cdr->car);
+  int beg = intn(p->lex_strterm->cdr->cdr->car);
+  int end = intn(p->lex_strterm->cdr->cdr->cdr);
   parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL;
-  int cmd_state = p->cmd_start;
 
   if (beg == 0) beg = -3;       /* should never happen */
@@ -3990,16 +4471,20 @@
         }
         if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) {
-          if (c < 0) {
-            p->parsing_heredoc = NULL;
-          }
-          else {
-            return tHEREDOC_END;
-          }
+          return tHEREDOC_END;
         }
       }
       if (c < 0) {
         char buf[256];
-        snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term);
-        yyerror(p, buf);
+        const char s1[] = "can't find heredoc delimiter \"";
+        const char s2[] = "\" anywhere before EOF";
+
+        if (sizeof(s1)+sizeof(s2)+strlen(hinf->term)+1 >= sizeof(buf)) {
+          yyerror(p, "can't find heredoc delimiter anywhere before EOF");
+        } else {
+          strcpy(buf, s1);
+          strcat(buf, hinf->term);
+          strcat(buf, s2);
+          yyerror(p, buf);
+        }
         return 0;
       }
@@ -4013,9 +4498,9 @@
     else if (c == beg) {
       nest_level++;
-      p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level;
+      p->lex_strterm->cdr->car = nint(nest_level);
     }
     else if (c == end) {
       nest_level--;
-      p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level;
+      p->lex_strterm->cdr->car = nint(nest_level);
     }
     else if (c == '\\') {
@@ -4119,5 +4604,5 @@
 
   tokfix(p);
-  p->lstate = EXPR_END;
+  p->lstate = EXPR_ENDARG;
   end_strterm(p);
 
@@ -4145,4 +4630,5 @@
       case 'u': f |= 16; break;
       case 'n': f |= 32; break;
+      case 'o': break;
       default: tokadd(p, re_opt); break;
       }
@@ -4151,7 +4637,12 @@
     if (toklen(p)) {
       char msg[128];
+
+      strcpy(msg, "unknown regexp option");
       tokfix(p);
-      snprintf(msg, sizeof(msg), "unknown regexp option%s - %s",
-          toklen(p) > 1 ? "s" : "", tok(p));
+      if (toklen(p) > 1) {
+        strcat(msg, "s");
+      }
+      strcat(msg, " - ");
+      strncat(msg, tok(p), sizeof(msg) - strlen(msg) - 1);
       yyerror(p, msg);
     }
@@ -4180,15 +4671,46 @@
   }
   pylval.nd = new_str(p, tok(p), toklen(p));
-  if (IS_LABEL_POSSIBLE()) {
-    if (IS_LABEL_SUFFIX(0)) {
-      p->lstate = EXPR_BEG;
-      nextc(p);
-      return tLABEL_END;
-    }
-  }
 
   return tSTRING;
 }
 
+static int
+number_literal_suffix(parser_state *p)
+{
+  int c, result = 0;
+  node *list = 0;
+  int column = p->column;
+  int mask = NUM_SUFFIX_R|NUM_SUFFIX_I;
+
+  while ((c = nextc(p)) != -1) {
+    list = push(list, (node*)(intptr_t)c);
+
+    if ((mask & NUM_SUFFIX_I) && c == 'i') {
+      result |= (mask & NUM_SUFFIX_I);
+      mask &= ~NUM_SUFFIX_I;
+      /* r after i, rational of complex is disallowed */
+      mask &= ~NUM_SUFFIX_R;
+      continue;
+    }
+    if ((mask & NUM_SUFFIX_R) && c == 'r') {
+      result |= (mask & NUM_SUFFIX_R);
+      mask &= ~NUM_SUFFIX_R;
+      continue;
+    }
+    if (!ISASCII(c) || ISALPHA(c) || c == '_') {
+      p->column = column;
+      if (p->pb) {
+        p->pb = append((node*)list, p->pb);
+      }
+      else {
+        p->pb = list;
+      }
+      return 0;
+    }
+    pushback(p, c);
+    break;
+  }
+  return result;
+}
 
 static int
@@ -4311,64 +4833,87 @@
   case -2:      /* end of a file */
   case '\n':
-    maybe_heredoc:
+  maybe_heredoc:
     heredoc_treat_nextline(p);
-  switch (p->lstate) {
-  case EXPR_BEG:
-  case EXPR_FNAME:
-  case EXPR_DOT:
-  case EXPR_CLASS:
-  case EXPR_VALUE:
-    p->lineno++;
     p->column = 0;
+    switch (p->lstate) {
+    case EXPR_BEG:
+    case EXPR_FNAME:
+    case EXPR_DOT:
+    case EXPR_CLASS:
+    case EXPR_VALUE:
+      p->lineno++;
+      if (p->parsing_heredoc != NULL) {
+        if (p->lex_strterm) {
+          return parse_string(p);
+        }
+      }
+      goto retry;
+    default:
+      break;
+    }
     if (p->parsing_heredoc != NULL) {
-      if (p->lex_strterm) {
-        return parse_string(p);
-      }
-    }
-    goto retry;
-  default:
-    break;
-  }
-  if (p->parsing_heredoc != NULL) {
+      return '\n';
+    }
+    while ((c = nextc(p))) {
+      switch (c) {
+      case ' ': case '\t': case '\f': case '\r':
+      case '\13': /* '\v' */
+        space_seen = 1;
+        break;
+      case '#': /* comment as a whitespace */
+        pushback(p, '#');
+        p->lineno++;
+        goto retry;
+      case '.':
+        if (!peek(p, '.')) {
+          pushback(p, '.');
+          p->lineno++;
+          goto retry;
+        }
+        pushback(p, c);
+        goto normal_newline;
+      case '&':
+        if (peek(p, '.')) {
+          pushback(p, '&');
+          p->lineno++;
+          goto retry;
+        }
+        pushback(p, c);
+        goto normal_newline;
+      case -1:                  /* EOF */
+      case -2:                  /* end of a file */
+        goto normal_newline;
+      default:
+        pushback(p, c);
+        goto normal_newline;
+      }
+    }
+  normal_newline:
+    p->cmd_start = TRUE;
+    p->lstate = EXPR_BEG;
     return '\n';
-  }
-  while ((c = nextc(p))) {
-    switch (c) {
-    case ' ': case '\t': case '\f': case '\r':
-    case '\13': /* '\v' */
-      space_seen = 1;
-      break;
-    case '.':
-      if ((c = nextc(p)) != '.') {
-        pushback(p, c);
-        pushback(p, '.');
-        goto retry;
-      }
-    case -1:                  /* EOF */
-    case -2:                  /* end of a file */
-      goto normal_newline;
-    default:
-      pushback(p, c);
-      goto normal_newline;
-    }
-  }
-  normal_newline:
-  p->cmd_start = TRUE;
-  p->lstate = EXPR_BEG;
-  return '\n';
 
   case '*':
     if ((c = nextc(p)) == '*') {
       if ((c = nextc(p)) == '=') {
-        pylval.id = intern("**",2);
+        pylval.id = intern_lit("**");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
       }
       pushback(p, c);
-      c = tPOW;
+      if (IS_SPCARG(c)) {
+        yywarning(p, "'**' interpreted as argument prefix");
+        c = tDSTAR;
+      }
+      else if (IS_BEG()) {
+        c = tDSTAR;
+      }
+      else {
+        c = tPOW; /* "**", "argument prefix" */
+      }
     }
     else {
       if (c == '=') {
-        pylval.id = intern_c('*');
+        pylval.id = intern_lit("*");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
@@ -4486,5 +5031,5 @@
     if (c == '<') {
       if ((c = nextc(p)) == '=') {
-        pylval.id = intern("<<",2);
+        pylval.id = intern_lit("<<");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
@@ -4508,5 +5053,5 @@
     if (c == '>') {
       if ((c = nextc(p)) == '=') {
-        pylval.id = intern(">>",2);
+        pylval.id = intern_lit(">>");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
@@ -4579,5 +5124,8 @@
         if (c2) {
           char buf[256];
-          snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2);
+          char cc[] = { (char)c2, '\0' };
+
+          strcpy(buf, "invalid character syntax; use ?\\");
+          strncat(buf, cc, 2);
           yyerror(p, buf);
         }
@@ -4590,8 +5138,8 @@
     newtok(p);
     /* need support UTF-8 if configured */
-    if ((isalnum(c) || c == '_')) {
+    if ((ISALNUM(c) || c == '_')) {
       int c2 = nextc(p);
       pushback(p, c2);
-      if ((isalnum(c2) || c2 == '_')) {
+      if ((ISALNUM(c2) || c2 == '_')) {
         goto ternary;
       }
@@ -4606,5 +5154,5 @@
     tokfix(p);
     pylval.nd = new_str(p, tok(p), toklen(p));
-    p->lstate = EXPR_END;
+    p->lstate = EXPR_ENDARG;
     return tCHAR;
 
@@ -4613,5 +5161,5 @@
       p->lstate = EXPR_BEG;
       if ((c = nextc(p)) == '=') {
-        pylval.id = intern("&&",2);
+        pylval.id = intern_lit("&&");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
@@ -4625,5 +5173,5 @@
     }
     else if (c == '=') {
-      pylval.id = intern_c('&');
+      pylval.id = intern_lit("&");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -4652,5 +5200,5 @@
       p->lstate = EXPR_BEG;
       if ((c = nextc(p)) == '=') {
-        pylval.id = intern("||",2);
+        pylval.id = intern_lit("||");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
@@ -4660,5 +5208,5 @@
     }
     if (c == '=') {
-      pylval.id = intern_c('|');
+      pylval.id = intern_lit("|");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -4684,5 +5232,5 @@
     }
     if (c == '=') {
-      pylval.id = intern_c('+');
+      pylval.id = intern_lit("+");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -4712,5 +5260,5 @@
     }
     if (c == '=') {
-      pylval.id = intern_c('-');
+      pylval.id = intern_lit("-");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -4753,7 +5301,8 @@
   {
     int is_float, seen_point, seen_e, nondigit;
+    int suffix = 0;
 
     is_float = seen_point = seen_e = nondigit = 0;
-    p->lstate = EXPR_END;
+    p->lstate = EXPR_ENDARG;
     newtok(p);
     if (c == '-' || c == '+') {
@@ -4786,5 +5335,6 @@
         }
         else if (nondigit) goto trailing_uc;
-        pylval.nd = new_int(p, tok(p), 16);
+        suffix = number_literal_suffix(p);
+        pylval.nd = new_int(p, tok(p), 16, suffix);
         return tINTEGER;
       }
@@ -4810,5 +5360,6 @@
         }
         else if (nondigit) goto trailing_uc;
-        pylval.nd = new_int(p, tok(p), 2);
+        suffix = number_literal_suffix(p);
+        pylval.nd = new_int(p, tok(p), 2, suffix);
         return tINTEGER;
       }
@@ -4834,5 +5385,6 @@
         }
         else if (nondigit) goto trailing_uc;
-        pylval.nd = new_int(p, tok(p), 10);
+        suffix = number_literal_suffix(p);
+        pylval.nd = new_int(p, tok(p), 10, suffix);
         return tINTEGER;
       }
@@ -4867,5 +5419,6 @@
           tokfix(p);
           if (nondigit) goto trailing_uc;
-          pylval.nd = new_int(p, tok(p), 8);
+          suffix = number_literal_suffix(p);
+          pylval.nd = new_int(p, tok(p), 8, suffix);
           return tINTEGER;
         }
@@ -4884,5 +5437,6 @@
       else {
         pushback(p, c);
-        pylval.nd = new_int(p, "0", 10);
+        suffix = number_literal_suffix(p);
+        pylval.nd = new_int(p, "0", 10, suffix);
         return tINTEGER;
       }
@@ -4952,8 +5506,13 @@
     if (nondigit) {
       trailing_uc:
-      yyerror_i(p, "trailing '%c' in number", nondigit);
+      yyerror_c(p, "trailing non digit in number: ", (char)nondigit);
     }
     tokfix(p);
     if (is_float) {
+#ifdef MRB_WITHOUT_FLOAT
+      yywarning_s(p, "floating point numbers are not supported", tok(p));
+      pylval.nd = new_int(p, "0", 10, 0);
+      return tINTEGER;
+#else
       double d;
       char *endp;
@@ -4962,14 +5521,17 @@
       d = mrb_float_read(tok(p), &endp);
       if (d == 0 && endp == tok(p)) {
-        yywarning_s(p, "corrupted float value %s", tok(p));
+        yywarning_s(p, "corrupted float value", tok(p));
       }
       else if (errno == ERANGE) {
-        yywarning_s(p, "float %s out of range", tok(p));
+        yywarning_s(p, "float out of range", tok(p));
         errno = 0;
       }
-      pylval.nd = new_float(p, tok(p));
+      suffix = number_literal_suffix(p);
+      pylval.nd = new_float(p, tok(p), suffix);
       return tFLOAT;
-    }
-    pylval.nd = new_int(p, tok(p), 10);
+#endif
+    }
+    suffix = number_literal_suffix(p);
+    pylval.nd = new_int(p, tok(p), 10, suffix);
     return tINTEGER;
   }
@@ -4985,5 +5547,5 @@
       p->lstate = EXPR_ENDFN;
     else
-      p->lstate = EXPR_ENDARG;
+      p->lstate = EXPR_END;
     return c;
 
@@ -4998,12 +5560,17 @@
       return tCOLON2;
     }
-    if (IS_END() || ISSPACE(c)) {
+    if (!space_seen && IS_END()) {
       pushback(p, c);
       p->lstate = EXPR_BEG;
-      return ':';
+      return tLABEL_TAG;
+    }
+    if (!ISSPACE(c) || IS_BEG()) {
+      pushback(p, c);
+      p->lstate = EXPR_FNAME;
+      return tSYMBEG;
     }
     pushback(p, c);
-    p->lstate = EXPR_FNAME;
-    return tSYMBEG;
+    p->lstate = EXPR_BEG;
+    return ':';
 
   case '/':
@@ -5013,5 +5580,5 @@
     }
     if ((c = nextc(p)) == '=') {
-      pylval.id = intern_c('/');
+      pylval.id = intern_lit("/");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -5032,5 +5599,5 @@
   case '^':
     if ((c = nextc(p)) == '=') {
-      pylval.id = intern_c('^');
+      pylval.id = intern_lit("^");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -5070,4 +5637,7 @@
     }
     else if (IS_SPCARG(-1)) {
+      c = tLPAREN_ARG;
+    }
+    else if (p->lstate == EXPR_END && space_seen) {
       c = tLPAREN_ARG;
     }
@@ -5147,5 +5717,5 @@
       else {
         term = nextc(p);
-        if (isalnum(term)) {
+        if (ISALNUM(term)) {
           yyerror(p, "unknown type of %string");
           return 0;
@@ -5206,5 +5776,5 @@
     }
     if ((c = nextc(p)) == '=') {
-      pylval.id = intern_c('%');
+      pylval.id = intern_lit("%");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -5260,5 +5830,5 @@
       tokadd(p, c);
       tokfix(p);
-      pylval.id = intern_cstr(tok(p));
+      pylval.id = intern(tok(p), toklen(p));
       return tGVAR;
 
@@ -5270,5 +5840,5 @@
       gvar:
       tokfix(p);
-      pylval.id = intern_cstr(tok(p));
+      pylval.id = intern(tok(p), toklen(p));
       return tGVAR;
 
@@ -5291,5 +5861,5 @@
         tokadd(p, c);
         c = nextc(p);
-      } while (c >= 0 && isdigit(c));
+      } while (c >= 0 && ISDIGIT(c));
       pushback(p, c);
       if (last_state == EXPR_FNAME) goto gvar;
@@ -5298,5 +5868,5 @@
         unsigned long n = strtoul(tok(p), NULL, 10);
         if (n > INT_MAX) {
-          yyerror_i(p, "capture group index must be <= %d", INT_MAX);
+          yyerror(p, "capture group index must be <= " MRB_STRINGIZE(INT_MAX));
           return 0;
         }
@@ -5333,10 +5903,10 @@
         return 0;
       }
-      else if (isdigit(c)) {
+      else if (ISDIGIT(c)) {
         if (p->tidx == 1) {
-          yyerror_i(p, "'@%c' is not allowed as an instance variable name", c);
+          yyerror_c(p, "wrong instance variable name: @", c);
         }
         else {
-          yyerror_i(p, "'@@%c' is not allowed as a class variable name", c);
+          yyerror_c(p, "wrong class variable name: @@", c);
         }
         return 0;
@@ -5354,5 +5924,13 @@
     default:
       if (!identchar(c)) {
-        yyerror_i(p,  "Invalid char '\\x%02X' in expression", c);
+        char buf[36];
+        const char s[] = "Invalid char in expression: 0x";
+        const char hexdigits[] = "0123456789ABCDEF";
+
+        strcpy(buf, s);
+        buf[sizeof(s)-1] = hexdigits[(c & 0xf0) >> 4];
+        buf[sizeof(s)]   = hexdigits[(c & 0x0f)];
+        buf[sizeof(s)+1] = 0;
+        yyerror(p, buf);
         goto retry;
       }
@@ -5400,4 +5978,37 @@
       break;
 
+    case '_':
+      if (toklen(p) == 2 && ISDIGIT(tok(p)[1]) && p->nvars) {
+        int n = tok(p)[1] - '0';
+        int nvar;
+
+        if (n > 0) {
+          node *nvars = p->nvars->cdr;
+
+          while (nvars) {
+            nvar = intn(nvars->car);
+            if (nvar == -2) break; /* top of the scope */
+            if (nvar > 0) {
+              yywarning(p, "numbered parameter used in outer block");
+              break;
+            }
+            nvars->car = nint(-1);
+            nvars = nvars->cdr;
+          }
+          nvar = intn(p->nvars->car);
+          if (nvar == -1) {
+            yywarning(p, "numbered parameter used in inner block");
+          }
+          if (nvar >= -1) {
+            pylval.num = n;
+            p->lstate = EXPR_END;
+            return tNUMPARAM;
+          }
+          else {
+            yywarning(p, "identifier for numbered parameter; consider another name");
+          }
+        }
+      }
+      /* fall through */
     default:
       if (toklast(p) == '!' || toklast(p) == '?') {
@@ -5406,4 +6017,13 @@
       else {
         if (p->lstate == EXPR_FNAME) {
+          if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') &&
+              (!peek(p, '=') || (peek_n(p, '>', 1)))) {
+            result = tIDENTIFIER;
+            tokadd(p, c);
+            tokfix(p);
+          }
+          else {
+            pushback(p, c);
+          }
           if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') &&
               (!peek(p, '=') || (peek_n(p, '>', 1)))) {
@@ -5426,9 +6046,8 @@
       if (IS_LABEL_POSSIBLE()) {
         if (IS_LABEL_SUFFIX(0)) {
-          p->lstate = EXPR_BEG;
-          nextc(p);
+          p->lstate = EXPR_END;
           tokfix(p);
-          pylval.id = intern_cstr(tok(p));
-          return tLABEL;
+          pylval.id = intern(tok(p), toklen(p));
+          return tIDENTIFIER;
         }
       }
@@ -5488,12 +6107,10 @@
     }
     {
-      mrb_sym ident = intern_cstr(tok(p));
+      mrb_sym ident = intern(tok(p), toklen(p));
 
       pylval.id = ident;
-#if 0
-      if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) {
+      if (last_state != EXPR_DOT && ISLOWER(tok(p)[0]) && local_var_p(p, ident)) {
         p->lstate = EXPR_END;
       }
-#endif
     }
     return result;
@@ -5524,4 +6141,5 @@
   p->capture_errors = cxt->capture_errors;
   p->no_optimize = cxt->no_optimize;
+  p->on_eval = cxt->on_eval;
   if (cxt->partial_hook) {
     p->cxt = cxt;
@@ -5536,5 +6154,5 @@
 
   if (!cxt) return;
-  if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return;
+  if (intn(p->tree->car) != NODE_SCOPE) return;
   n0 = n = p->tree->cdr->car;
   while (n) {
@@ -5559,5 +6177,5 @@
 
   MRB_TRY(p->jmp) {
-    int n;
+    int n = 1;
 
     p->cmd_start = TRUE;
@@ -5675,5 +6293,5 @@
 {
   if (s) {
-    int len = strlen(s);
+    size_t len = strlen(s);
     char *p = (char *)mrb_malloc(mrb, len + 1);
 
@@ -5702,19 +6320,23 @@
 
   sym = mrb_intern_cstr(p->mrb, f);
-  p->filename = mrb_sym2name_len(p->mrb, sym, NULL);
+  p->filename_sym = sym;
   p->lineno = (p->filename_table_length > 0)? 0 : 1;
 
   for (i = 0; i < p->filename_table_length; ++i) {
     if (p->filename_table[i] == sym) {
-      p->current_filename_index = i;
+      p->current_filename_index = (int)i;
       return;
     }
   }
 
+  if (p->filename_table_length == UINT16_MAX) {
+    yyerror(p, "too many files to compile");
+    return;
+  }
   p->current_filename_index = p->filename_table_length++;
 
   new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length);
   if (p->filename_table) {
-    memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length);
+    memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->current_filename_index);
   }
   p->filename_table = new_table;
@@ -5722,9 +6344,9 @@
 }
 
-MRB_API char const*
+MRB_API mrb_sym
 mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) {
-  if (idx >= p->filename_table_length) { return NULL; }
+  if (idx >= p->filename_table_length) return 0;
   else {
-    return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL);
+    return p->filename_table[idx];
   }
 }
@@ -5747,5 +6369,5 @@
 
 MRB_API parser_state*
-mrb_parse_nstring(mrb_state *mrb, const char *s, int len, mrbc_context *c)
+mrb_parse_nstring(mrb_state *mrb, const char *s, size_t len, mrbc_context *c)
 {
   parser_state *p;
@@ -5778,11 +6400,13 @@
   }
   if (!p->tree || p->nerr) {
+    if (c) c->parser_nerr = p->nerr;
     if (p->capture_errors) {
       char buf[256];
-      int n;
-
-      n = snprintf(buf, sizeof(buf), "line %d: %s\n",
-          p->error_buffer[0].lineno, p->error_buffer[0].message);
-      mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
+
+      strcpy(buf, "line ");
+      dump_int(p->error_buffer[0].lineno, buf+5);
+      strcat(buf, ": ");
+      strncat(buf, p->error_buffer[0].message, sizeof(buf) - strlen(buf) - 1);
+      mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf)));
       mrb_parser_free(p);
       return mrb_undef_value();
@@ -5817,5 +6441,5 @@
     }
   }
-  proc->target_class = target;
+  MRB_PROC_SET_TARGET_CLASS(proc, target);
   if (mrb->c->ci) {
     mrb->c->ci->target_class = target;
@@ -5841,5 +6465,5 @@
 
 MRB_API mrb_value
-mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *c)
+mrb_load_nstring_cxt(mrb_state *mrb, const char *s, size_t len, mrbc_context *c)
 {
   return mrb_load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c);
@@ -5847,5 +6471,5 @@
 
 MRB_API mrb_value
-mrb_load_nstring(mrb_state *mrb, const char *s, int len)
+mrb_load_nstring(mrb_state *mrb, const char *s, size_t len)
 {
   return mrb_load_nstring_cxt(mrb, s, len, NULL);
@@ -5885,4 +6509,68 @@
 }
 
+static void
+dump_args(mrb_state *mrb, node *n, int offset)
+{
+  if (n->car) {
+    dump_prefix(n, offset+1);
+    printf("mandatory args:\n");
+    dump_recur(mrb, n->car, offset+2);
+  }
+  n = n->cdr;
+  if (n->car) {
+    dump_prefix(n, offset+1);
+    printf("optional args:\n");
+    {
+      node *n2 = n->car;
+
+      while (n2) {
+        dump_prefix(n2, offset+2);
+        printf("%s=\n", mrb_sym_name(mrb, sym(n2->car->car)));
+        mrb_parser_dump(mrb, n2->car->cdr, offset+3);
+        n2 = n2->cdr;
+      }
+    }
+  }
+  n = n->cdr;
+  if (n->car) {
+    dump_prefix(n, offset+1);
+    printf("rest=*%s\n", mrb_sym_name(mrb, sym(n->car)));
+  }
+  n = n->cdr;
+  if (n->car) {
+    dump_prefix(n, offset+1);
+    printf("post mandatory args:\n");
+    dump_recur(mrb, n->car, offset+2);
+  }
+
+  n = n->cdr;
+  if (n) {
+    mrb_assert(intn(n->car) == NODE_ARGS_TAIL);
+    mrb_parser_dump(mrb, n, offset);
+  }
+}
+
+/*
+ * This function restores the GC arena on return.
+ * For this reason, if a process that further generates an object is
+ * performed at the caller, the string pointer returned as the return
+ * value may become invalid.
+ */
+static const char*
+str_dump(mrb_state *mrb, const char *str, int len)
+{
+  mrb_int ai = mrb_gc_arena_save(mrb);
+  mrb_value s;
+# if INT_MAX > MRB_INT_MAX / 4
+  /* check maximum length with "\xNN" charactor */
+  if (len > MRB_INT_MAX / 4) {
+    len = MRB_INT_MAX / 4;
+  }
+# endif
+  s = mrb_str_new(mrb, str, (mrb_int)len);
+  s = mrb_str_dump(mrb, s);
+  mrb_gc_arena_restore(mrb, ai);
+  return RSTRING_PTR(s);
+}
 #endif
 
@@ -5896,5 +6584,5 @@
   again:
   dump_prefix(tree, offset);
-  nodetype = (int)(intptr_t)tree->car;
+  nodetype = intn(tree->car);
   tree = tree->cdr;
   switch (nodetype) {
@@ -5956,5 +6644,6 @@
 
   case NODE_LAMBDA:
-    printf("NODE_BLOCK:\n");
+    printf("NODE_LAMBDA:\n");
+    dump_prefix(tree, offset);
     goto block;
 
@@ -5964,41 +6653,5 @@
     tree = tree->cdr;
     if (tree->car) {
-      node *n = tree->car;
-
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("optional args:\n");
-        {
-          node *n2 = n->car;
-
-          while (n2) {
-            dump_prefix(n2, offset+2);
-            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
-            mrb_parser_dump(mrb, n2->car->cdr, 0);
-            n2 = n2->cdr;
-          }
-        }
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("post mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      if (n->cdr) {
-        dump_prefix(n, offset+1);
-        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr)));
-      }
+      dump_args(mrb, tree->car, offset+1);
     }
     dump_prefix(tree, offset+1);
@@ -6123,5 +6776,5 @@
           if (n2->car) {
             if (!first_lval) printf(", ");
-            printf("%s", mrb_sym2name(mrb, sym(n2->car)));
+            printf("%s", mrb_sym_name(mrb, sym(n2->car)));
             first_lval = FALSE;
           }
@@ -6151,6 +6804,6 @@
     dump_prefix(tree, offset+1);
     printf("method='%s' (%d)\n",
-        mrb_sym2name(mrb, sym(tree->cdr->car)),
-        (int)(intptr_t)tree->cdr->car);
+        mrb_sym_dump(mrb, sym(tree->cdr->car)),
+        intn(tree->cdr->car));
     tree = tree->cdr->cdr->car;
     if (tree) {
@@ -6182,9 +6835,9 @@
     mrb_parser_dump(mrb, tree->car, offset+1);
     dump_prefix(tree, offset+1);
-    printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr)));
+    printf("::%s\n", mrb_sym_name(mrb, sym(tree->cdr)));
     break;
 
   case NODE_COLON3:
-    printf("NODE_COLON3: ::%s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_COLON3: ::%s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
@@ -6196,4 +6849,17 @@
   case NODE_HASH:
     printf("NODE_HASH:\n");
+    while (tree) {
+      dump_prefix(tree, offset+1);
+      printf("key:\n");
+      mrb_parser_dump(mrb, tree->car->car, offset+2);
+      dump_prefix(tree, offset+1);
+      printf("value:\n");
+      mrb_parser_dump(mrb, tree->car->cdr, offset+2);
+      tree = tree->cdr;
+    }
+    break;
+
+  case NODE_KW_HASH:
+    printf("NODE_KW_HASH:\n");
     while (tree) {
       dump_prefix(tree, offset+1);
@@ -6269,5 +6935,5 @@
     tree = tree->cdr;
     dump_prefix(tree, offset+1);
-    printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car);
+    printf("op='%s' (%d)\n", mrb_sym_name(mrb, sym(tree->car)), intn(tree->car));
     tree = tree->cdr;
     mrb_parser_dump(mrb, tree->car, offset+1);
@@ -6321,21 +6987,25 @@
 
   case NODE_LVAR:
-    printf("NODE_LVAR %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_LVAR %s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
   case NODE_GVAR:
-    printf("NODE_GVAR %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_GVAR %s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
   case NODE_IVAR:
-    printf("NODE_IVAR %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_IVAR %s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
   case NODE_CVAR:
-    printf("NODE_CVAR %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_CVAR %s\n", mrb_sym_name(mrb, sym(tree)));
+    break;
+
+  case NODE_NVAR:
+    printf("NODE_NVAR %d\n", intn(tree));
     break;
 
   case NODE_CONST:
-    printf("NODE_CONST %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_CONST %s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
@@ -6351,13 +7021,13 @@
 
   case NODE_BACK_REF:
-    printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree);
+    printf("NODE_BACK_REF: $%c\n", intn(tree));
     break;
 
   case NODE_NTH_REF:
-    printf("NODE_NTH_REF: $%" MRB_PRId "\n", (mrb_int)(intptr_t)tree);
+    printf("NODE_NTH_REF: $%d\n", intn(tree));
     break;
 
   case NODE_ARG:
-    printf("NODE_ARG %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_ARG %s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
@@ -6368,5 +7038,5 @@
 
   case NODE_INT:
-    printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car);
+    printf("NODE_INT %s base %d\n", (char*)tree->car, intn(tree->cdr->car));
     break;
 
@@ -6376,23 +7046,23 @@
 
   case NODE_NEGATE:
-    printf("NODE_NEGATE\n");
+    printf("NODE_NEGATE:\n");
     mrb_parser_dump(mrb, tree, offset+1);
     break;
 
   case NODE_STR:
-    printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr);
+    printf("NODE_STR %s len %d\n", str_dump(mrb, (char*)tree->car, intn(tree->cdr)), intn(tree->cdr));
     break;
 
   case NODE_DSTR:
-    printf("NODE_DSTR\n");
+    printf("NODE_DSTR:\n");
     dump_recur(mrb, tree, offset+1);
     break;
 
   case NODE_XSTR:
-    printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr);
+    printf("NODE_XSTR %s len %d\n", str_dump(mrb, (char*)tree->car, intn(tree->cdr)), intn(tree->cdr));
     break;
 
   case NODE_DXSTR:
-    printf("NODE_DXSTR\n");
+    printf("NODE_DXSTR:\n");
     dump_recur(mrb, tree, offset+1);
     break;
@@ -6403,5 +7073,5 @@
 
   case NODE_DREGX:
-    printf("NODE_DREGX\n");
+    printf("NODE_DREGX:\n");
     dump_recur(mrb, tree->car, offset+1);
     dump_prefix(tree, offset);
@@ -6418,6 +7088,25 @@
 
   case NODE_SYM:
-    printf("NODE_SYM :%s (%d)\n", mrb_sym2name(mrb, sym(tree)),
-           (int)(intptr_t)tree);
+    printf("NODE_SYM :%s (%d)\n", mrb_sym_dump(mrb, sym(tree)),
+           intn(tree));
+    break;
+
+  case NODE_DSYM:
+    printf("NODE_DSYM:\n");
+    mrb_parser_dump(mrb, tree, offset+1);
+    break;
+
+  case NODE_WORDS:
+    printf("NODE_WORDS:\n");
+    dump_recur(mrb, tree, offset+1);
+    break;
+
+  case NODE_SYMBOLS:
+    printf("NODE_SYMBOLS:\n");
+    dump_recur(mrb, tree, offset+1);
+    break;
+
+  case NODE_LITERAL_DELIM:
+    printf("NODE_LITERAL_DELIM\n");
     break;
 
@@ -6440,6 +7129,6 @@
   case NODE_ALIAS:
     printf("NODE_ALIAS %s %s:\n",
-        mrb_sym2name(mrb, sym(tree->car)),
-        mrb_sym2name(mrb, sym(tree->cdr)));
+        mrb_sym_dump(mrb, sym(tree->car)),
+        mrb_sym_dump(mrb, sym(tree->cdr)));
     break;
 
@@ -6449,5 +7138,5 @@
       node *t = tree;
       while (t) {
-        printf(" %s", mrb_sym2name(mrb, sym(t->car)));
+        printf(" %s", mrb_sym_dump(mrb, sym(t->car)));
         t = t->cdr;
       }
@@ -6460,14 +7149,14 @@
     if (tree->car->car == (node*)0) {
       dump_prefix(tree, offset+1);
-      printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf(":%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     else if (tree->car->car == (node*)1) {
       dump_prefix(tree, offset+1);
-      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     else {
       mrb_parser_dump(mrb, tree->car->car, offset+1);
       dump_prefix(tree, offset+1);
-      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     if (tree->cdr->car) {
@@ -6485,14 +7174,14 @@
     if (tree->car->car == (node*)0) {
       dump_prefix(tree, offset+1);
-      printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf(":%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     else if (tree->car->car == (node*)1) {
       dump_prefix(tree, offset+1);
-      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     else {
       mrb_parser_dump(mrb, tree->car->car, offset+1);
       dump_prefix(tree, offset+1);
-      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     dump_prefix(tree, offset+1);
@@ -6512,5 +7201,5 @@
     printf("NODE_DEF:\n");
     dump_prefix(tree, offset+1);
-    printf("%s\n", mrb_sym2name(mrb, sym(tree->car)));
+    printf("%s\n", mrb_sym_dump(mrb, sym(tree->car)));
     tree = tree->cdr;
     {
@@ -6525,5 +7214,5 @@
           if (n2->car) {
             if (!first_lval) printf(", ");
-            printf("%s", mrb_sym2name(mrb, sym(n2->car)));
+            printf("%s", mrb_sym_name(mrb, sym(n2->car)));
             first_lval = FALSE;
           }
@@ -6535,41 +7224,5 @@
     tree = tree->cdr;
     if (tree->car) {
-      node *n = tree->car;
-
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("optional args:\n");
-        {
-          node *n2 = n->car;
-
-          while (n2) {
-            dump_prefix(n2, offset+2);
-            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
-            mrb_parser_dump(mrb, n2->car->cdr, 0);
-            n2 = n2->cdr;
-          }
-        }
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("post mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      if (n->cdr) {
-        dump_prefix(n, offset+1);
-        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr)));
-      }
+      dump_args(mrb, tree->car, offset);
     }
     mrb_parser_dump(mrb, tree->cdr->car, offset+1);
@@ -6581,45 +7234,8 @@
     tree = tree->cdr;
     dump_prefix(tree, offset+1);
-    printf(":%s\n", mrb_sym2name(mrb, sym(tree->car)));
+    printf(":%s\n", mrb_sym_dump(mrb, sym(tree->car)));
     tree = tree->cdr->cdr;
     if (tree->car) {
-      node *n = tree->car;
-
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("optional args:\n");
-        {
-          node *n2 = n->car;
-
-          while (n2) {
-            dump_prefix(n2, offset+2);
-            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
-            mrb_parser_dump(mrb, n2->car->cdr, 0);
-            n2 = n2->cdr;
-          }
-        }
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("post mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      n = n->cdr;
-      if (n) {
-        dump_prefix(n, offset+1);
-        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
-      }
+      dump_args(mrb, tree->car, offset+1);
     }
     tree = tree->cdr;
@@ -6637,4 +7253,35 @@
     break;
 
+  case NODE_ARGS_TAIL:
+    printf("NODE_ARGS_TAIL:\n");
+    {
+      node *kws = tree->car;
+
+      while (kws) {
+        mrb_parser_dump(mrb, kws->car, offset+1);
+        kws = kws->cdr;
+      }
+    }
+    tree = tree->cdr;
+    if (tree->car) {
+      mrb_assert(intn(tree->car->car) == NODE_KW_REST_ARGS);
+      mrb_parser_dump(mrb, tree->car, offset+1);
+    }
+    tree = tree->cdr;
+    if (tree->car) {
+      dump_prefix(tree, offset+1);
+      printf("block='%s'\n", mrb_sym_name(mrb, sym(tree->car)));
+    }
+    break;
+
+  case NODE_KW_ARG:
+    printf("NODE_KW_ARG %s:\n", mrb_sym_name(mrb, sym(tree->car)));
+    mrb_parser_dump(mrb, tree->cdr->car, offset + 1);
+    break;
+
+  case NODE_KW_REST_ARGS:
+    printf("NODE_KW_REST_ARGS %s\n", mrb_sym_name(mrb, sym(tree)));
+    break;
+
   default:
     printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype);
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/mrbgem.rake	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/mrbgem.rake	(revision 439)
@@ -24,8 +24,8 @@
     end
   end
-  file objfile("#{current_build_dir}/core/y.tab") => lex_def
 
   # Parser
-  file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y"] do |t|
+  file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y", lex_def] do |t|
+    mkdir_p File.dirname t.name
     yacc.run t.name, t.prerequisites.first
   end
@@ -36,5 +36,5 @@
   end
 
-  file libfile("#{build.build_dir}/lib/libmruby_core") => core_objs
+  file build.libmruby_core_static => core_objs
   build.libmruby << core_objs
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/mrbgem.rake	(revision 439)
@@ -0,0 +1,7 @@
+MRuby::Gem::Specification.new('mruby-complex') do |spec|
+  spec.license = 'MIT'
+  spec.author  = 'mruby developers'
+  spec.summary = 'Complex class'
+
+  spec.add_dependency 'mruby-math', core: 'mruby-math'
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/mrblib/complex.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/mrblib/complex.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/mrblib/complex.rb	(revision 439)
@@ -0,0 +1,122 @@
+class Complex < Numeric
+  def self.polar(abs, arg = 0)
+    Complex(abs * Math.cos(arg), abs * Math.sin(arg))
+  end
+
+  def inspect
+    "(#{to_s})"
+  end
+
+  def to_s
+    "#{real}#{'+' unless imaginary < 0}#{imaginary}i"
+  end
+
+  def +@
+    Complex(real, imaginary)
+  end
+
+  def -@
+    Complex(-real, -imaginary)
+  end
+
+  def +(rhs)
+    if rhs.is_a? Complex
+      Complex(real + rhs.real, imaginary + rhs.imaginary)
+    elsif rhs.is_a? Numeric
+      Complex(real + rhs, imaginary)
+    end
+  end
+
+  def -(rhs)
+    if rhs.is_a? Complex
+      Complex(real - rhs.real, imaginary - rhs.imaginary)
+    elsif rhs.is_a? Numeric
+      Complex(real - rhs, imaginary)
+    end
+  end
+
+  def *(rhs)
+    if rhs.is_a? Complex
+      Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary)
+    elsif rhs.is_a? Numeric
+      Complex(real * rhs, imaginary * rhs)
+    end
+  end
+
+  def /(rhs)
+    if rhs.is_a? Complex
+      __div__(rhs)
+    elsif rhs.is_a? Numeric
+      Complex(real / rhs, imaginary / rhs)
+    end
+  end
+  alias_method :quo, :/
+
+  def ==(rhs)
+    if rhs.is_a? Complex
+      real == rhs.real && imaginary == rhs.imaginary
+    elsif rhs.is_a? Numeric
+      imaginary == 0 && real == rhs
+    end
+  end
+
+  def abs
+    Math.hypot imaginary, real
+  end
+  alias_method :magnitude, :abs
+
+  def abs2
+    real * real + imaginary * imaginary
+  end
+
+  def arg
+    Math.atan2 imaginary, real
+  end
+  alias_method :angle, :arg
+  alias_method :phase, :arg
+
+  def conjugate
+    Complex(real, -imaginary)
+  end
+  alias_method :conj, :conjugate
+
+  def fdiv(numeric)
+    Complex(real.to_f / numeric, imaginary.to_f / numeric)
+  end
+
+  def polar
+    [abs, arg]
+  end
+
+  def real?
+    false
+  end
+
+  def rectangular
+    [real, imaginary]
+  end
+  alias_method :rect, :rectangular
+
+  def to_r
+    raise RangeError.new "can't convert #{to_s} into Rational" unless imaginary.zero?
+    Rational(real, 1)
+  end
+
+  alias_method :imag, :imaginary
+
+  [Fixnum, Float].each do |cls|
+    [:+, :-, :*, :/, :==].each do |op|
+      cls.instance_eval do
+        original_operator_name = "__original_operator_#{op}_complex"
+        alias_method original_operator_name, op
+        define_method op do |rhs|
+          if rhs.is_a? Complex
+            Complex(self).__send__(op, rhs)
+          else
+            __send__(original_operator_name, rhs)
+          end
+        end
+      end
+    end
+  end
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/src/complex.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/src/complex.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/src/complex.c	(revision 439)
@@ -0,0 +1,249 @@
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/numeric.h>
+#include <math.h>
+
+#ifdef MRB_WITHOUT_FLOAT
+# error Complex conflicts 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb'
+#endif
+
+struct mrb_complex {
+  mrb_float real;
+  mrb_float imaginary;
+};
+
+#ifdef MRB_USE_FLOAT
+#define F(x) x##f
+#else
+#define F(x) x
+#endif
+
+#if defined(MRB_64BIT) || defined(MRB_USE_FLOAT)
+
+#define COMPLEX_USE_ISTRUCT
+/* use TT_ISTRUCT */
+#include <mruby/istruct.h>
+
+#define complex_ptr(mrb, v) (struct mrb_complex*)mrb_istruct_ptr(v)
+
+static struct RBasic*
+complex_alloc(mrb_state *mrb, struct RClass *c, struct mrb_complex **p)
+{
+  struct RIStruct *s;
+
+  s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c);
+  *p = (struct mrb_complex*)s->inline_data;
+
+  return (struct RBasic*)s;
+}
+
+#else
+/* use TT_DATA */
+#include <mruby/data.h>
+
+static const struct mrb_data_type mrb_complex_type = {"Complex", mrb_free};
+
+static struct RBasic*
+complex_alloc(mrb_state *mrb, struct RClass *c, struct mrb_complex **p)
+{
+  struct RData *d;
+
+  Data_Make_Struct(mrb, c, struct mrb_complex, &mrb_complex_type, *p, d);
+
+  return (struct RBasic*)d;
+}
+
+static struct mrb_complex*
+complex_ptr(mrb_state *mrb, mrb_value v)
+{
+  struct mrb_complex *p;
+
+  p = DATA_GET_PTR(mrb, v, &mrb_complex_type, struct mrb_complex);
+  if (!p) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized complex");
+  }
+  return p;
+}
+#endif
+
+static mrb_value
+complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary)
+{
+  struct RClass *c = mrb_class_get(mrb, "Complex");
+  struct mrb_complex *p;
+  struct RBasic *comp = complex_alloc(mrb, c, &p);
+  p->real = real;
+  p->imaginary = imaginary;
+  MRB_SET_FROZEN_FLAG(comp);
+
+  return mrb_obj_value(comp);
+}
+
+static mrb_value
+complex_real(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_complex *p = complex_ptr(mrb, self);
+  return mrb_float_value(mrb, p->real);
+}
+
+static mrb_value
+complex_imaginary(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_complex *p = complex_ptr(mrb, self);
+  return mrb_float_value(mrb, p->imaginary);
+}
+
+static mrb_value
+complex_s_rect(mrb_state *mrb, mrb_value self)
+{
+  mrb_float real, imaginary = 0.0;
+
+  mrb_get_args(mrb, "f|f", &real, &imaginary);
+  return complex_new(mrb, real, imaginary);
+}
+
+static mrb_value
+complex_to_f(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_complex *p = complex_ptr(mrb, self);
+
+  if (p->imaginary != 0) {
+    mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %v into Float", self);
+  }
+
+  return mrb_float_value(mrb, p->real);
+}
+
+static mrb_value
+complex_to_i(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_complex *p = complex_ptr(mrb, self);
+
+  if (p->imaginary != 0) {
+    mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %v into Float", self);
+  }
+  return mrb_int_value(mrb, p->real);
+}
+
+static mrb_value
+complex_to_c(mrb_state *mrb, mrb_value self)
+{
+  return self;
+}
+
+/* Arithmetic on (significand, exponent) pairs avoids premature overflow in
+   complex division */
+struct float_pair {
+  mrb_float s;
+  int x;
+};
+
+static void
+add_pair(struct float_pair *s, struct float_pair const *a,
+         struct float_pair const *b)
+{
+  if (b->s == 0.0F) {
+    *s = *a;
+  } else if (a->s == 0.0F) {
+    *s = *b;
+  } else if (a->x >= b->x) {
+    s->s = a->s + F(ldexp)(b->s, b->x - a->x);
+    s->x = a->x;
+  } else {
+    s->s = F(ldexp)(a->s, a->x - b->x) + b->s;
+    s->x = b->x;
+  }
+}
+
+static void
+mul_pair(struct float_pair *p, struct float_pair const *a,
+         struct float_pair const *b)
+{
+  p->s = a->s * b->s;
+  p->x = a->x + b->x;
+}
+
+static void
+div_pair(struct float_pair *q, struct float_pair const *a,
+         struct float_pair const *b)
+{
+  q->s = a->s / b->s;
+  q->x = a->x - b->x;
+}
+
+static mrb_value
+complex_div(mrb_state *mrb, mrb_value self)
+{
+  mrb_value rhs;
+  struct mrb_complex *a, *b;
+  struct float_pair ar, ai, br, bi;
+  struct float_pair br2, bi2;
+  struct float_pair div;
+  struct float_pair ar_br, ai_bi;
+  struct float_pair ai_br, ar_bi;
+  struct float_pair zr, zi;
+
+  mrb_get_args(mrb, "o", &rhs);
+  a = complex_ptr(mrb, self);
+  b = complex_ptr(mrb, rhs);
+
+  /* Split floating point components into significand and exponent */
+  ar.s = F(frexp)(a->real, &ar.x);
+  ai.s = F(frexp)(a->imaginary, &ai.x);
+  br.s = F(frexp)(b->real, &br.x);
+  bi.s = F(frexp)(b->imaginary, &bi.x);
+
+  /* Perform arithmetic on (significand, exponent) pairs to produce
+     the result: */
+
+  /* the divisor */
+  mul_pair(&br2, &br, &br);
+  mul_pair(&bi2, &bi, &bi);
+  add_pair(&div, &br2, &bi2);
+
+  /* real component */
+  mul_pair(&ar_br, &ar, &br);
+  mul_pair(&ai_bi, &ai, &bi);
+  add_pair(&zr, &ar_br, &ai_bi);
+  div_pair(&zr, &zr, &div);
+
+  /* imaginary component */
+  mul_pair(&ai_br, &ai, &br);
+  mul_pair(&ar_bi, &ar, &bi);
+  ar_bi.s = -ar_bi.s;
+  add_pair(&zi, &ai_br, &ar_bi);
+  div_pair(&zi, &zi, &div);
+
+  /* assemble the result */
+  return complex_new(mrb, F(ldexp)(zr.s, zr.x), F(ldexp)(zi.s, zi.x));
+}
+
+void mrb_mruby_complex_gem_init(mrb_state *mrb)
+{
+  struct RClass *comp;
+
+#ifdef COMPLEX_USE_ISTRUCT
+  mrb_assert(sizeof(struct mrb_complex) < ISTRUCT_DATA_SIZE);
+#endif
+  comp = mrb_define_class(mrb, "Complex", mrb_class_get(mrb, "Numeric"));
+#ifdef COMPLEX_USE_ISTRUCT
+  MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT);
+#else
+  MRB_SET_INSTANCE_TT(comp, MRB_TT_DATA);
+#endif
+  mrb_undef_class_method(mrb, comp, "new");
+  mrb_define_class_method(mrb, comp, "rectangular", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  mrb_define_class_method(mrb, comp, "rect", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, mrb->kernel_module, "Complex", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, comp, "real", complex_real, MRB_ARGS_NONE());
+  mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE());
+  mrb_define_method(mrb, comp, "to_f", complex_to_f, MRB_ARGS_NONE());
+  mrb_define_method(mrb, comp, "to_i", complex_to_i, MRB_ARGS_NONE());
+  mrb_define_method(mrb, comp, "to_c", complex_to_c, MRB_ARGS_NONE());
+  mrb_define_method(mrb, comp, "__div__", complex_div, MRB_ARGS_REQ(1));
+}
+
+void
+mrb_mruby_complex_gem_final(mrb_state* mrb)
+{
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/test/complex.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/test/complex.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-complex/test/complex.rb	(revision 439)
@@ -0,0 +1,153 @@
+def assert_complex(real, exp)
+  assert "assert_complex" do
+    assert_float real.real,      exp.real
+    assert_float real.imaginary, exp.imaginary
+  end
+end
+
+assert 'Complex' do
+  c = 123i
+  assert_equal Complex, c.class
+  assert_equal [c.real, c.imaginary], [0, 123]
+  c = 123 + -1.23i
+  assert_equal Complex, c.class
+  assert_equal [c.real, c.imaginary], [123, -1.23]
+end
+
+assert 'Complex::polar' do
+  assert_complex Complex.polar(3, 0),           (3  +  0i)
+  assert_complex Complex.polar(3, Math::PI/2),  (0  +  3i)
+  assert_complex Complex.polar(3, Math::PI),    (-3 +  0i)
+  assert_complex Complex.polar(3, -Math::PI/2), (0  + -3i)
+end
+
+assert 'Complex::rectangular' do
+  assert_complex Complex.rectangular(1, 2), (1 + 2i)
+end
+
+assert 'Complex#*' do
+  assert_complex Complex(2, 3)  * Complex(2, 3),  (-5    + 12i)
+  assert_complex Complex(900)   * Complex(1),     (900   + 0i)
+  assert_complex Complex(-2, 9) * Complex(-9, 2), (0     - 85i)
+  assert_complex Complex(9, 8)  * 4,              (36    + 32i)
+  assert_complex Complex(20, 9) * 9.8,            (196.0 + 88.2i)
+end
+
+assert 'Complex#+' do
+  assert_complex Complex(2, 3)  + Complex(2, 3) , (4    + 6i)
+  assert_complex Complex(900)   + Complex(1)    , (901  + 0i)
+  assert_complex Complex(-2, 9) + Complex(-9, 2), (-11  + 11i)
+  assert_complex Complex(9, 8)  + 4             , (13   + 8i)
+  assert_complex Complex(20, 9) + 9.8           , (29.8 + 9i)
+end
+
+assert 'Complex#-' do
+  assert_complex Complex(2, 3)  - Complex(2, 3) , (0    + 0i)
+  assert_complex Complex(900)   - Complex(1)    , (899  + 0i)
+  assert_complex Complex(-2, 9) - Complex(-9, 2), (7    + 7i)
+  assert_complex Complex(9, 8)  - 4             , (5    + 8i)
+  assert_complex Complex(20, 9) - 9.8           , (10.2 + 9i)
+end
+
+assert 'Complex#-@' do
+  assert_complex(-Complex(1, 2), (-1 - 2i))
+end
+
+assert 'Complex#/' do
+  assert_complex Complex(2, 3)  / Complex(2, 3) , (1                  + 0i)
+  assert_complex Complex(900)   / Complex(1)    , (900                + 0i)
+  assert_complex Complex(-2, 9) / Complex(-9, 2), ((36 / 85)          - (77i / 85))
+  assert_complex Complex(9, 8)  / 4             , ((9 / 4)            + 2i)
+  assert_complex Complex(20, 9) / 9.8           , (2.0408163265306123 + 0.9183673469387754i)
+  if 1e39.infinite? then
+    # MRB_USE_FLOAT in effect
+    ten = 1e21
+    one = 1e20
+  else
+    ten = 1e201
+    one = 1e200
+  end
+  assert_complex Complex(ten, ten) / Complex(one, one), Complex(10.0, 0.0)
+end
+
+assert 'Complex#==' do
+  assert_true  Complex(2, 3)  == Complex(2, 3)
+  assert_true  Complex(5)     == 5
+  assert_true  Complex(0)     == 0.0
+end
+
+assert 'Complex#abs' do
+  assert_float Complex(-1).abs,        1
+  assert_float Complex(3.0, -4.0).abs, 5.0
+  if 1e39.infinite? then
+    # MRB_USE_FLOAT in effect
+    exp = 125
+  else
+    exp = 1021
+  end
+  assert_true Complex(3.0*2.0**exp, 4.0*2.0**exp).abs.finite?
+  assert_float Complex(3.0*2.0**exp, 4.0*2.0**exp).abs, 5.0*2.0**exp
+end
+
+assert 'Complex#abs2' do
+  assert_float Complex(-1).abs2,        1
+  assert_float Complex(3.0, -4.0).abs2, 25.0
+end
+
+assert 'Complex#arg' do
+  assert_float Complex.polar(3, Math::PI/2).arg, 1.5707963267948966
+end
+
+assert 'Complex#conjugate' do
+  assert_complex Complex(1, 2).conjugate, (1 - 2i)
+end
+
+assert 'Complex#fdiv' do
+  assert_complex Complex(11, 22).fdiv(3), (3.6666666666666665 + 7.333333333333333i)
+end
+
+assert 'Complex#imaginary' do
+  assert_float Complex(7).imaginary    , 0
+  assert_float Complex(9, -4).imaginary, -4
+end
+
+assert 'Complex#polar' do
+  assert_equal Complex(1, 2).polar, [2.23606797749979, 1.1071487177940904]
+end
+
+assert 'Complex#real' do
+  assert_float Complex(7).real,     7
+  assert_float Complex(9, -4).real, 9
+end
+
+assert 'Complex#real?' do
+  assert_false Complex(1).real?
+end
+
+assert 'Complex::rectangular' do
+  assert_equal Complex(1, 2).rectangular, [1, 2]
+end
+
+assert 'Complex::to_c' do
+  assert_equal Complex(1, 2).to_c, Complex(1, 2)
+end
+
+assert 'Complex::to_f' do
+  assert_float Complex(1, 0).to_f, 1.0
+  assert_raise(RangeError) do
+    Complex(1, 2).to_f
+  end
+end
+
+assert 'Complex::to_i' do
+  assert_equal Complex(1, 0).to_i, 1
+  assert_raise(RangeError) do
+    Complex(1, 2).to_i
+  end
+end
+
+assert 'Complex#frozen?' do
+  assert_predicate(1i, :frozen?)
+  assert_predicate(Complex(2,3), :frozen?)
+  assert_predicate(4+5i, :frozen?)
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-chain/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-chain/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-chain/mrbgem.rake	(revision 439)
@@ -0,0 +1,6 @@
+MRuby::Gem::Specification.new('mruby-enum-chain') do |spec|
+  spec.license = 'MIT'
+  spec.author  = 'mruby developers'
+  spec.summary = 'Enumerator::Chain class'
+  spec.add_dependency('mruby-enumerator', :core => 'mruby-enumerator')
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-chain/mrblib/chain.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-chain/mrblib/chain.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-chain/mrblib/chain.rb	(revision 439)
@@ -0,0 +1,62 @@
+##
+# chain.rb Enumerator::Chain class
+# See Copyright Notice in mruby.h
+
+module Enumerable
+  def chain(*args)
+    Enumerator::Chain.new(self, *args)
+  end
+end
+
+class Enumerator
+  def +(other)
+    Chain.new(self, other)
+  end
+
+  class Chain
+    include Enumerable
+
+    def initialize(*args)
+      @enums = args.freeze
+      @pos = -1
+    end
+
+    def each(&block)
+      return to_enum unless block
+
+      i = 0
+      while i < @enums.size
+        @pos = i
+        @enums[i].each(&block)
+        i += 1
+      end
+
+      self
+    end
+
+    def size
+      @enums.reduce(0) do |a, e|
+        return nil unless e.respond_to?(:size)
+        a + e.size
+      end
+    end
+
+    def rewind
+      while 0 <= @pos && @pos < @enums.size
+        e = @enums[@pos]
+        e.rewind if e.respond_to?(:rewind)
+        @pos -= 1
+      end
+
+      self
+    end
+
+    def +(other)
+      self.class.new(self, other)
+    end
+
+    def inspect
+      "#<#{self.class}: #{@enums.inspect}>"
+    end
+  end
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-chain/test/enum_chain.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-chain/test/enum_chain.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-chain/test/enum_chain.rb	(revision 439)
@@ -0,0 +1,108 @@
+##
+# Enumerator::Chain test
+
+assert("Enumerable#chain") do
+  a = []
+  b = {}
+  c = Object.new # not has #each method
+
+  assert_kind_of Enumerator::Chain, a.chain
+  assert_kind_of Enumerator::Chain, a.chain(b)
+  assert_kind_of Enumerator::Chain, a.chain(b, c)
+  assert_raise(NoMethodError) { c.chain }
+end
+
+assert("Enumerator#+") do
+  a = [].each
+  b = {}.each
+  c = Object.new # not has #each method
+
+  assert_kind_of Enumerator::Chain, a + b
+  assert_kind_of Enumerator::Chain, a + c
+  assert_kind_of Enumerator::Chain, b + a
+  assert_kind_of Enumerator::Chain, b + c
+  assert_raise(NoMethodError) { c + a }
+end
+
+assert("Enumerator::Chain.new") do
+  a = []
+  b = {}
+  c = Object.new # not has #each method
+
+  assert_kind_of Enumerator::Chain, Enumerator::Chain.new
+  assert_kind_of Enumerator::Chain, Enumerator::Chain.new(a, a)
+  assert_kind_of Enumerator::Chain, Enumerator::Chain.new(a, b)
+  assert_kind_of Enumerator::Chain, Enumerator::Chain.new(a, c)
+  assert_kind_of Enumerator::Chain, Enumerator::Chain.new(b, a)
+  assert_kind_of Enumerator::Chain, Enumerator::Chain.new(b, b)
+  assert_kind_of Enumerator::Chain, Enumerator::Chain.new(b, c)
+  assert_kind_of Enumerator::Chain, Enumerator::Chain.new(c, a)
+end
+
+assert("Enumerator::Chain#each") do
+  a = [1, 2, 3]
+
+  aa = a.chain(a)
+  assert_kind_of Enumerator, aa.each
+  assert_equal [1, 2, 3, 1, 2, 3], aa.each.to_a
+
+  aa = a.chain(6..9)
+  assert_kind_of Enumerator, aa.each
+  assert_equal [1, 2, 3, 6, 7, 8, 9], aa.each.to_a
+
+  aa = a.chain((-3..-2).each_with_index, a)
+  assert_kind_of Enumerator, aa.each
+  assert_equal [1, 2, 3, [-3, 0], [-2, 1], 1, 2, 3], aa.each.to_a
+
+  aa = a.chain(Object.new)
+  assert_kind_of Enumerator, aa.each
+  assert_raise(NoMethodError) {  aa.each.to_a }
+end
+
+assert("Enumerator::Chain#size") do
+  a = [1, 2, 3]
+
+  aa = a.chain(a)
+  assert_equal 6, aa.size
+
+  aa = a.chain(3..4)
+  assert_nil aa.size
+
+  aa = a.chain(3..4, a)
+  assert_nil aa.size
+
+  aa = a.chain(Object.new)
+  assert_nil aa.size
+end
+
+assert("Enumerator::Chain#rewind") do
+  rewound = nil
+  e1 = [1, 2]
+  e2 = (4..6)
+  (class << e1; self end).define_method(:rewind) { rewound << self }
+  (class << e2; self end).define_method(:rewind) { rewound << self }
+  c = e1.chain(e2)
+
+  rewound = []
+  c.rewind
+  assert_equal [], rewound
+
+  rewound = []
+  c.each{break c}.rewind
+  assert_equal [e1], rewound
+
+  rewound = []
+  c.each{}.rewind
+  assert_equal [e2, e1], rewound
+end
+
+assert("Enumerator::Chain#+") do
+  a = [].chain
+  b = {}.chain
+  c = Object.new # not has #each method
+
+  assert_kind_of Enumerator::Chain, a + b
+  assert_kind_of Enumerator::Chain, a + c
+  assert_kind_of Enumerator::Chain, b + a
+  assert_kind_of Enumerator::Chain, b + c
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-ext/mrblib/enum.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-enum-ext/mrblib/enum.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-ext/mrblib/enum.rb	(revision 439)
@@ -14,8 +14,7 @@
 
   def drop(n)
-    raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
+    n = n.__to_int
     raise ArgumentError, "attempt to drop negative size" if n < 0
 
-    n = n.to_int
     ary = []
     self.each {|*val| n == 0 ? ary << val.__svalue : n -= 1 }
@@ -58,6 +57,6 @@
 
   def take(n)
-    raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
-    i = n.to_int
+    n = n.__to_int
+    i = n.to_i
     raise ArgumentError, "attempt to take negative size" if i < 0
     ary = []
@@ -114,10 +113,10 @@
 
   def each_cons(n, &block)
-    raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
+    n = n.__to_int
     raise ArgumentError, "invalid size" if n <= 0
 
     return to_enum(:each_cons,n) unless block
     ary = []
-    n = n.to_int
+    n = n.to_i
     self.each do |*val|
       ary.shift if ary.size == n
@@ -142,10 +141,10 @@
 
   def each_slice(n, &block)
-    raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
+    n = n.__to_int
     raise ArgumentError, "invalid slice size" if n <= 0
 
     return to_enum(:each_slice,n) unless block
     ary = []
-    n = n.to_int
+    n = n.to_i
     self.each do |*val|
       ary << val.__svalue
@@ -202,12 +201,9 @@
     }
     if ary.size > 1
-      __sort_sub__(ary, ::Array.new(ary.size), 0, 0, ary.size - 1) do |a,b|
-        a <=> b
-      end
+      ary.sort!
     end
     ary.collect{|e,i| orig[i]}
   end
 
-  NONE = Object.new
   ##
   # call-seq:
@@ -226,7 +222,5 @@
       return nil
     when 1
-      n = args[0]
-      raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int)
-      i = n.to_int
+      i = args[0].__to_int
       raise ArgumentError, "attempt to take negative size" if i < 0
       ary = []
@@ -452,4 +446,5 @@
   #  call-seq:
   #     enum.none? [{ |obj| block }]   -> true or false
+  #     enum.none?(pattern)            -> true or false
   #
   #  Passes each element of the collection to the given block. The method
@@ -458,12 +453,21 @@
   #  <code>true</code> only if none of the collection members is true.
   #
+  #  If a pattern is supplied instead, the method returns whether
+  #  <code>pattern === element</code> for none of the collection members.
+  #
   #     %w(ant bear cat).none? { |word| word.length == 5 } #=> true
   #     %w(ant bear cat).none? { |word| word.length >= 4 } #=> false
+  #     %w{ant bear cat}.none?(/d/)                        #=> true
+  #     [1, 3.14, 42].none?(Float)                         #=> false
   #     [].none?                                           #=> true
   #     [nil, false].none?                                 #=> true
   #     [nil, true].none?                                  #=> false
 
-  def none?(&block)
-    if block
+  def none?(pat=NONE, &block)
+    if pat != NONE
+      self.each do |*val|
+        return false if pat === val.__svalue
+      end
+    elsif block
       self.each do |*val|
         return false if block.call(*val)
@@ -480,4 +484,5 @@
   #  call-seq:
   #    enum.one? [{ |obj| block }]   -> true or false
+  #    enum.one?(pattern)            -> true or false
   #
   # Passes each element of the collection to the given block. The method
@@ -487,14 +492,24 @@
   # true.
   #
+  # If a pattern is supplied instead, the method returns whether
+  # <code>pattern === element</code> for exactly one collection member.
+  #
   #    %w(ant bear cat).one? { |word| word.length == 4 }  #=> true
   #    %w(ant bear cat).one? { |word| word.length > 4 }   #=> false
   #    %w(ant bear cat).one? { |word| word.length < 4 }   #=> false
+  #    %w{ant bear cat}.one?(/t/)                         #=> false
   #    [nil, true, 99].one?                               #=> false
   #    [nil, true, false].one?                            #=> true
-  #
-
-  def one?(&block)
+  #    [ nil, true, 99 ].one?(Integer)                    #=> true
+  #    [].one?                                            #=> false
+
+  def one?(pat=NONE, &block)
     count = 0
-    if block
+    if pat!=NONE
+      self.each do |*val|
+        count += 1 if pat === val.__svalue
+        return false if count > 1
+      end
+    elsif block
       self.each do |*val|
         count += 1 if block.call(*val)
@@ -511,4 +526,69 @@
   end
 
+  # ISO 15.3.2.2.1
+  #  call-seq:
+  #     enum.all? [{ |obj| block } ]   -> true or false
+  #     enum.all?(pattern)             -> true or false
+  #
+  #  Passes each element of the collection to the given block. The method
+  #  returns <code>true</code> if the block never returns
+  #  <code>false</code> or <code>nil</code>. If the block is not given,
+  #  Ruby adds an implicit block of <code>{ |obj| obj }</code> which will
+  #  cause #all? to return +true+ when none of the collection members are
+  #  +false+ or +nil+.
+  #
+  #  If a pattern is supplied instead, the method returns whether
+  #  <code>pattern === element</code> for every collection member.
+  #
+  #     %w[ant bear cat].all? { |word| word.length >= 3 } #=> true
+  #     %w[ant bear cat].all? { |word| word.length >= 4 } #=> false
+  #     %w[ant bear cat].all?(/t/)                        #=> false
+  #     [1, 2i, 3.14].all?(Numeric)                       #=> true
+  #     [nil, true, 99].all?                              #=> false
+  #
+  def all?(pat=NONE, &block)
+    if pat != NONE
+      self.each{|*val| return false unless pat === val.__svalue}
+    elsif block
+      self.each{|*val| return false unless block.call(*val)}
+    else
+      self.each{|*val| return false unless val.__svalue}
+    end
+    true
+  end
+
+  # ISO 15.3.2.2.2
+  #  call-seq:
+  #     enum.any? [{ |obj| block }]   -> true or false
+  #     enum.any?(pattern)            -> true or false
+  #
+  #  Passes each element of the collection to the given block. The method
+  #  returns <code>true</code> if the block ever returns a value other
+  #  than <code>false</code> or <code>nil</code>. If the block is not
+  #  given, Ruby adds an implicit block of <code>{ |obj| obj }</code> that
+  #  will cause #any? to return +true+ if at least one of the collection
+  #  members is not +false+ or +nil+.
+  #
+  #  If a pattern is supplied instead, the method returns whether
+  #  <code>pattern === element</code> for any collection member.
+  #
+  #     %w[ant bear cat].any? { |word| word.length >= 3 } #=> true
+  #     %w[ant bear cat].any? { |word| word.length >= 4 } #=> true
+  #     %w[ant bear cat].any?(/d/)                        #=> false
+  #     [nil, true, 99].any?(Integer)                     #=> true
+  #     [nil, true, 99].any?                              #=> true
+  #     [].any?                                           #=> false
+  #
+  def any?(pat=NONE, &block)
+    if pat != NONE
+      self.each{|*val| return true if pat === val.__svalue}
+    elsif block
+      self.each{|*val| return true if block.call(*val)}
+    else
+      self.each{|*val| return true if val.__svalue}
+    end
+    false
+  end
+
   ##
   #  call-seq:
@@ -525,7 +605,5 @@
   #
 
-  def each_with_object(obj=nil, &block)
-    raise ArgumentError, "wrong number of arguments (0 for 1)" if obj.nil?
-
+  def each_with_object(obj, &block)
     return to_enum(:each_with_object, obj) unless block
 
@@ -592,11 +670,5 @@
       n = -1
     else
-      unless nv.respond_to?(:to_int)
-        raise TypeError, "no implicit conversion of #{nv.class} into Integer"
-      end
-      n = nv.to_int
-      unless n.kind_of?(Integer)
-        raise TypeError, "no implicit conversion of #{nv.class} into Integer"
-      end
+      n = nv.__to_int
       return nil if n <= 0
     end
@@ -657,4 +729,5 @@
   #  call-seq:
   #     enum.zip(arg, ...)                  -> an_array_of_array
+  #     enum.zip(arg, ...) { |arr| block }  -> nil
   #
   #  Takes one element from <i>enum</i> and merges corresponding
@@ -663,10 +736,30 @@
   #  count of arguments.  The length of the resulting sequence will be
   #  <code>enum#size</code>.  If the size of any argument is less than
-  #  <code>enum#size</code>, <code>nil</code> values are supplied.
-  #
-
-  def zip(*arg)
-    ary = []
-    arg = arg.map{|a|a.to_a}
+  #  <code>enum#size</code>, <code>nil</code> values are supplied. If
+  #  a block is given, it is invoked for each output array, otherwise
+  #  an array of arrays is returned.
+  #
+  #     a = [ 4, 5, 6 ]
+  #     b = [ 7, 8, 9 ]
+  #
+  #     a.zip(b)                 #=> [[4, 7], [5, 8], [6, 9]]
+  #     [1, 2, 3].zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
+  #     [1, 2].zip(a, b)         #=> [[1, 4, 7], [2, 5, 8]]
+  #     a.zip([1, 2], [8])       #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
+  #
+  #     c = []
+  #     a.zip(b) { |x, y| c << x + y }  #=> nil
+  #     c                               #=> [11, 13, 15]
+  #
+
+  def zip(*arg, &block)
+    result = block ? nil : []
+    arg = arg.map do |a|
+      unless a.respond_to?(:to_a)
+        raise TypeError, "wrong argument type #{a.class} (must respond to :to_a)"
+      end
+      a.to_a
+    end
+
     i = 0
     self.each do |*val|
@@ -678,8 +771,12 @@
         idx += 1
       end
-      ary.push(a)
       i += 1
-    end
-    ary
+      if result.nil?
+        block.call(a)
+      else
+        result.push(a)
+      end
+    end
+    result
   end
 
@@ -695,17 +792,68 @@
   #
 
-  def to_h
+  def to_h(&blk)
     h = {}
-    self.each do |*v|
-      v = v.__svalue
-      raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array
-      raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2
-      h[v[0]] = v[1]
+    if blk
+      self.each do |v|
+        v = blk.call(v)
+        raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array
+        raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2
+        h[v[0]] = v[1]
+      end
+    else
+      self.each do |*v|
+        v = v.__svalue
+        raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array
+        raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2
+        h[v[0]] = v[1]
+      end
     end
     h
   end
 
-  def nil.to_h
-    {}
+  def uniq(&block)
+    hash = {}
+    if block
+      self.each do|*v|
+        v = v.__svalue
+        hash[block.call(v)] ||= v
+      end
+    else
+      self.each do|*v|
+        v = v.__svalue
+        hash[v] ||= v
+      end
+    end
+    hash.values
+  end
+
+  def filter_map(&blk)
+    return to_enum(:filter_map) unless blk
+
+    ary = []
+    self.each do |x|
+      x = blk.call(x)
+      ary.push x if x
+    end
+    ary
+  end
+
+  alias filter select
+
+  ##
+  # call-seq:
+  #   enum.tally -> a_hash
+  #
+  # Tallys the collection.  Returns a hash where the keys are the
+  # elements and the values are numbers of elements in the collection
+  # that correspond to the key.
+  #
+  #    ["a", "b", "c", "b"].tally #=> {"a"=>1, "b"=>2, "c"=>1}
+  def tally
+    hash = {}
+    self.each do |x|
+      hash[x] = (hash[x]||0)+1
+    end
+    hash
   end
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-ext/test/enum.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-enum-ext/test/enum.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-ext/test/enum.rb	(revision 439)
@@ -101,4 +101,5 @@
   assert_true %w(ant bear cat).none? { |word| word.length == 5 }
   assert_false %w(ant bear cat).none? { |word| word.length >= 4 }
+  assert_false [1, 3.14, 42].none?(Float)
   assert_true [].none?
   assert_true [nil, false].none?
@@ -110,10 +111,23 @@
   assert_false %w(ant bear cat).one? { |word| word.length > 4 }
   assert_false %w(ant bear cat).one? { |word| word.length < 4 }
+  assert_true [1, 3.14, 42].one?(Float)
   assert_false [nil, true, 99].one?
   assert_true [nil, true, false].one?
+  assert_true [ nil, true, 99 ].one?(Integer)
+  assert_false [].one?
+end
+
+assert("Enumerable#all? (enhancement)") do
+  assert_false [1, 2, 3.14].all?(Integer)
+  assert_true [1, 2, 3.14].all?(Numeric)
+end
+
+assert("Enumerable#any? (enhancement)") do
+  assert_false [1, 2, 3].all?(Float)
+  assert_true [nil, true, 99].any?(Integer)
 end
 
 assert("Enumerable#each_with_object") do
-  assert_true [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], (1..10).each_with_object([]) { |i, a| a << i*2 }
+  assert_equal [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], (1..10).each_with_object([]) { |i, a| a << i*2 }
   assert_raise(ArgumentError) { (1..10).each_with_object() { |i, a| a << i*2 } }
 end
@@ -122,5 +136,5 @@
   r = (1..3)
   a = []
-  assert_equal (1..3), r.reverse_each { |v| a << v }
+  assert_same r, r.reverse_each { |v| a << v }
   assert_equal [3, 2, 1], a
 end
@@ -153,4 +167,10 @@
   assert_equal [[1, 4, 7], [2, 5, 8]], [1, 2].zip(a, b)
   assert_equal [[4, 1, 8], [5, 2, nil], [6, nil, nil]], a.zip([1, 2], [8])
+
+  ret = []
+  assert_equal nil, a.zip([1, 2], [8]) { |i| ret << i }
+  assert_equal [[4, 1, 8], [5, 2, nil], [6, nil, nil]], ret
+
+  assert_raise(TypeError) { [1].zip(1) }
 end
 
@@ -167,5 +187,12 @@
   assert_equal Hash, h.class
   assert_equal h0, h
-  # mruby-enum-ext also provides nil.to_h
-  assert_equal Hash.new, nil.to_h
+  assert_equal({1=>4,3=>8}, c.new.to_h{|k,v|[k,v*2]})
 end
+
+assert("Enumerable#filter_map") do
+  assert_equal [4, 8, 12, 16, 20], (1..10).filter_map{|i| i * 2 if i%2==0}
+end
+
+assert("Enumerable#tally") do
+  assert_equal({"a"=>1, "b"=>2, "c"=>1}, ["a", "b", "c", "b"].tally)
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-lazy/mrblib/lazy.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-enum-lazy/mrblib/lazy.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-lazy/mrblib/lazy.rb	(revision 439)
@@ -44,4 +44,7 @@
 
     def to_enum(meth=:each, *args, &block)
+      unless self.respond_to?(meth)
+        raise ArgumentError, "undefined method #{meth}"
+      end
       lz = Lazy.new(self, &block)
       lz.obj = self
@@ -70,5 +73,5 @@
     def reject(&block)
       Lazy.new(self){|yielder, val|
-        if not block.call(val)
+        unless block.call(val)
           yielder << val
         end
@@ -156,4 +159,19 @@
     end
 
+    def uniq(&block)
+      hash = {}
+      Lazy.new(self){|yielder, val|
+        if block
+          v = block.call(val)
+        else
+          v = val
+        end
+        unless hash.include?(v)
+          yielder << val
+          hash[v] = val
+        end
+      }
+    end
+
     alias force to_a
   end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-lazy/test/lazy.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-enum-lazy/test/lazy.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enum-lazy/test/lazy.rb	(revision 439)
@@ -41,5 +41,5 @@
 end
 
-assert("Enumrator::Lazy#to_enum") do
+assert("Enumerator::Lazy#to_enum") do
   lazy_enum = (0..Float::INFINITY).lazy.to_enum(:each_slice, 2)
   assert_kind_of Enumerator::Lazy, lazy_enum
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enumerator/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-enumerator/mrbgem.rake	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enumerator/mrbgem.rake	(revision 439)
@@ -3,5 +3,4 @@
   spec.author  = 'mruby developers'
   spec.add_dependency('mruby-fiber', :core => 'mruby-fiber')
-  spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext'
   spec.summary = 'Enumerator class'
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enumerator/mrblib/enumerator.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-enumerator/mrblib/enumerator.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enumerator/mrblib/enumerator.rb	(revision 439)
@@ -90,5 +90,4 @@
 
   ##
-  # @overload initialize(size = nil, &block)
   # @overload initialize(obj, method = :each, *args)
   #
@@ -110,14 +109,20 @@
   #     p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
   #
-  def initialize(obj=nil, meth=:each, *args, &block)
-    if block_given?
+  # In the second, deprecated, form, a generated Enumerator iterates over the
+  # given object using the given method with the given arguments passed. This
+  # form is left only for internal use.
+  #
+  # Use of this form is discouraged.  Use Kernel#enum_for or Kernel#to_enum
+  # instead.
+  def initialize(obj=NONE, meth=:each, *args, &block)
+    if block
       obj = Generator.new(&block)
-    else
-      raise ArgumentError unless obj
+    elsif obj == NONE
+      raise ArgumentError, "wrong number of arguments (given 0, expected 1+)"
     end
 
     @obj = obj
     @meth = meth
-    @args = args.dup
+    @args = args
     @fib = nil
     @dst = nil
@@ -126,6 +131,6 @@
     @stop_exc = false
   end
-  attr_accessor :obj, :meth, :args, :fib
-  private :obj, :meth, :args, :fib
+  attr_accessor :obj, :meth, :args
+  attr_reader :fib
 
   def initialize_copy(obj)
@@ -152,12 +157,11 @@
   # +offset+:: the starting index to use
   #
-  def with_index(offset=0)
-    return to_enum :with_index, offset unless block_given?
-    offset = if offset.nil?
-      0
-    elsif offset.respond_to?(:to_int)
-      offset.to_int
+  def with_index(offset=0, &block)
+    return to_enum :with_index, offset unless block
+
+    if offset.nil?
+      offset = 0
     else
-      raise TypeError, "no implicit conversion of #{offset.class} into Integer"
+      offset = offset.__to_int
     end
 
@@ -165,5 +169,5 @@
     enumerator_block_call do |*i|
       n += 1
-      yield i.__svalue, n
+      block.call i.__svalue, n
     end
   end
@@ -210,9 +214,9 @@
   #   # => foo:2
   #
-  def with_object(object)
-    return to_enum(:with_object, object) unless block_given?
+  def with_object(object, &block)
+    return to_enum(:with_object, object) unless block
 
     enumerator_block_call do |i|
-      yield [i,object]
+      block.call [i,object]
     end
     object
@@ -220,11 +224,9 @@
 
   def inspect
-    return "#<#{self.class}: uninitialized>" unless @obj
-
     if @args && @args.size > 0
       args = @args.join(", ")
-      "#<#{self.class}: #{@obj}:#{@meth}(#{args})>"
+      "#<#{self.class}: #{@obj.inspect}:#{@meth}(#{args})>"
     else
-      "#<#{self.class}: #{@obj}:#{@meth}>"
+      "#<#{self.class}: #{@obj.inspect}:#{@meth}>"
     end
   end
@@ -242,7 +244,8 @@
   # === Examples
   #
-  #   "Hello, world!".scan(/\w+/)                     #=> ["Hello", "world"]
-  #   "Hello, world!".to_enum(:scan, /\w+/).to_a      #=> ["Hello", "world"]
-  #   "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
+  #   Array.new(3)                     #=> [nil, nil, nil]
+  #   Array.new(3) { |i| i }           #=> [0, 1, 2]
+  #   Array.to_enum(:new, 3).to_a      #=> [0, 1, 2]
+  #   Array.to_enum(:new).each(3).to_a #=> [0, 1, 2]
   #
   #   obj = Object.new
@@ -278,5 +281,5 @@
       obj.args = args
     end
-    return obj unless block_given?
+    return obj unless block
     enumerator_block_call(&block)
   end
@@ -539,5 +542,5 @@
   class Yielder
     def initialize(&block)
-      raise LocalJumpError, "no block given" unless block_given?
+      raise LocalJumpError, "no block given" unless block
 
       @proc = block
@@ -553,4 +556,44 @@
     end
   end
+
+  ##
+  # call-seq:
+  #    Enumerator.produce(initial = nil) { |val| } -> enumerator
+  #
+  # Creates an infinite enumerator from any block, just called over and
+  # over.  Result of the previous iteration is passed to the next one.
+  # If +initial+ is provided, it is passed to the first iteration, and
+  # becomes the first element of the enumerator; if it is not provided,
+  # first iteration receives +nil+, and its result becomes first
+  # element of the iterator.
+  #
+  # Raising StopIteration from the block stops an iteration.
+  #
+  # Examples of usage:
+  #
+  #   Enumerator.produce(1, &:succ)   # => enumerator of 1, 2, 3, 4, ....
+  #
+  #   Enumerator.produce { rand(10) } # => infinite random number sequence
+  #
+  #   ancestors = Enumerator.produce(node) { |prev| node = prev.parent or raise StopIteration }
+  #   enclosing_section = ancestors.find { |n| n.type == :section }
+  def Enumerator.produce(init=NONE, &block)
+    raise ArgumentError, "no block given" if block.nil?
+    Enumerator.new do |y|
+      if init == NONE
+        val = nil
+      else
+        val = init
+        y.yield(val)
+      end
+      begin
+        while true
+          y.yield(val = block.call(val))
+        end
+      rescue StopIteration
+        # do nothing
+      end
+    end
+  end
 end
 
@@ -560,12 +603,7 @@
   #   obj.to_enum(method = :each, *args)                 -> enum
   #   obj.enum_for(method = :each, *args)                -> enum
-  #   obj.to_enum(method = :each, *args) {|*args| block} -> enum
-  #   obj.enum_for(method = :each, *args){|*args| block} -> enum
   #
   # Creates a new Enumerator which will enumerate by calling +method+ on
   # +obj+, passing +args+ if any.
-  #
-  # If a block is given, it will be used to calculate the size of
-  # the enumerator without the need to iterate it (see Enumerator#size).
   #
   # === Examples
@@ -586,5 +624,5 @@
   # a generic Enumerable, in case no block is passed.
   #
-  # Here is such an example, with parameter passing and a sizing block:
+  # Here is such an example with parameter passing:
   #
   #     module Enumerable
@@ -593,8 +631,5 @@
   #         raise ArgumentError, "#{n} is negative!" if n < 0
   #         unless block_given?
-  #           return to_enum(__method__, n) do # __method__ is :repeat here
-  #             sz = size     # Call size and multiply by n...
-  #             sz * n if sz  # but return nil if size itself is nil
-  #           end
+  #           return to_enum(__method__, n) # __method__ is :repeat here
   #         end
   #         each do |*val|
@@ -613,29 +648,42 @@
     Enumerator.new self, meth, *args
   end
-  alias :enum_for :to_enum
+  alias enum_for to_enum
 end
 
 module Enumerable
   # use Enumerator to use infinite sequence
-  def zip(*arg)
-    ary = []
-    arg = arg.map{|a|a.each}
-    i = 0
-    self.each do |*val|
-      a = []
-      a.push(val.__svalue)
-      idx = 0
-      while idx < arg.size
-        begin
-          a.push(arg[idx].next)
-        rescue StopIteration
-          a.push(nil)
+  def zip(*args, &block)
+    args = args.map do |a|
+      if a.respond_to?(:each)
+        a.to_enum(:each)
+      else
+        raise TypeError, "wrong argument type #{a.class} (must respond to :each)"
+      end
+    end
+
+    result = block ? nil : []
+
+    each do |*val|
+      tmp = [val.__svalue]
+      args.each do |arg|
+        v = if arg.nil?
+          nil
+        else
+          begin
+            arg.next
+          rescue StopIteration
+            nil
+          end
         end
-        idx += 1
+        tmp.push(v)
       end
-      ary.push(a)
-      i += 1
-    end
-    ary
+      if result.nil?
+        block.call(tmp)
+      else
+        result.push(tmp)
+      end
+    end
+
+    result
   end
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enumerator/test/enumerator.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-enumerator/test/enumerator.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-enumerator/test/enumerator.rb	(revision 439)
@@ -7,9 +7,20 @@
 end
 
-assert 'Enumerator' do
+def assert_take(exp, enumerator)
+  result = []
+  n = exp.size
+  enumerator.each do |v|
+    result << v
+    n -= 1
+    break if n == 0
+  end if n > 0
+  assert_equal exp, result
+end
+
+assert 'Enumerator.class' do
   assert_equal Class, Enumerator.class
 end
 
-assert 'Enumerator' do
+assert 'Enumerator.superclass' do
   assert_equal Object, Enumerator.superclass
 end
@@ -20,9 +31,6 @@
   assert_equal [[:x,1],[:y,2]], {x:1, y:2}.each.map{|i| i}.sort
   assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a
-  assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a
-  assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3)
+  assert_take [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }
   assert_raise(ArgumentError) { Enumerator.new }
-  enum = @obj.to_enum
-  assert_raise(NoMethodError) { enum.each {} }
 
   # examples
@@ -34,5 +42,5 @@
     end
   end
-  assert_equal fib.take(10), [1,1,2,3,5,8,13,21,34,55]
+  assert_take [1,1,2,3,5,8,13,21,34,55], fib
 end
 
@@ -54,10 +62,4 @@
   @obj.to_enum(:foo, 1, 2, 3).with_index(10).with_index(20) { |*i| a << i }
   assert_equal [[[1, 10], 20], [[2, 11], 21], [[3, 12], 22]], a
-end
-
-assert 'Enumerator#with_index nonnum offset' do
-  s = Object.new
-  def s.to_int; 1 end
-  assert_equal([[1,1],[2,2],[3,3]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a)
 end
 
@@ -100,9 +102,11 @@
 assert 'Enumerator#inspect' do
   e = (0..10).each
-  assert_equal("#<Enumerator: 0..10:each>", e.inspect)
-  e = Enumerator.new("FooObject", :foo, 1)
-  assert_equal("#<Enumerator: FooObject:foo(1)>", e.inspect)
-  e = Enumerator.new("FooObject", :foo, 1, 2, 3)
-  assert_equal("#<Enumerator: FooObject:foo(1, 2, 3)>", e.inspect)
+  assert_equal('#<Enumerator: 0..10:each>', e.inspect)
+  e = 'FooObject'.enum_for(:foo, 1)
+  assert_equal('#<Enumerator: "FooObject":foo(1)>', e.inspect)
+  e = 'FooObject'.enum_for(:foo, 1, 2, 3)
+  assert_equal('#<Enumerator: "FooObject":foo(1, 2, 3)>', e.inspect)
+  e = nil.enum_for(:to_s)
+  assert_equal('#<Enumerator: nil:to_s>', e.inspect)
 end
 
@@ -426,6 +430,8 @@
 
 assert 'Kernel#to_enum' do
+  e = nil
   assert_equal Enumerator, [].to_enum.class
-  assert_raise(ArgumentError){ nil.to_enum }
+  assert_nothing_raised { e = [].to_enum(:_not_implemented_) }
+  assert_raise(NoMethodError) { e.first }
 end
 
@@ -510,5 +516,5 @@
 assert 'Hash#select' do
   h = {1=>2,3=>4,5=>6}
-  hret = h.select.with_index {|a,b| a[1] == 4}
+  hret = h.select.with_index {|a,_b| a[1] == 4}
   assert_equal({3=>4}, hret)
   assert_equal({1=>2,3=>4,5=>6}, h)
@@ -517,5 +523,5 @@
 assert 'Hash#select!' do
   h = {1=>2,3=>4,5=>6}
-  hret = h.select!.with_index {|a,b| a[1] == 4}
+  hret = h.select!.with_index {|a,_b| a[1] == 4}
   assert_equal h, hret
   assert_equal({3=>4}, h)
@@ -524,5 +530,5 @@
 assert 'Hash#reject' do
   h = {1=>2,3=>4,5=>6}
-  hret = h.reject.with_index {|a,b| a[1] == 4}
+  hret = h.reject.with_index {|a,_b| a[1] == 4}
   assert_equal({1=>2,5=>6}, hret)
   assert_equal({1=>2,3=>4,5=>6}, h)
@@ -531,5 +537,5 @@
 assert 'Hash#reject!' do
   h = {1=>2,3=>4,5=>6}
-  hret = h.reject!.with_index {|a,b| a[1] == 4}
+  hret = h.reject!.with_index {|a,_b| a[1] == 4}
   assert_equal h, hret
   assert_equal({1=>2,5=>6}, h)
@@ -545,2 +551,50 @@
   assert_equal [1,2,3,4,5], c
 end
+
+assert 'Enumerable#zip' do
+  assert_equal [[1, 10], [2, 11], [3, 12]], [1,2,3].zip(10..Float::INFINITY)
+
+  ret = []
+  assert_equal nil, [1,2,3].zip(10..Float::INFINITY) { |i| ret << i }
+  assert_equal [[1, 10], [2, 11], [3, 12]], ret
+
+  assert_raise(TypeError) { [1].zip(1) }
+end
+
+assert 'Enumerator.produce' do
+  assert_raise(ArgumentError) { Enumerator.produce }
+
+  # Without initial object
+  passed_args = []
+  enum = Enumerator.produce {|obj| passed_args << obj; (obj || 0).succ }
+  assert_equal Enumerator, enum.class 
+  assert_take [1, 2, 3], enum
+  assert_equal [nil, 1, 2], passed_args
+
+  # With initial object
+  passed_args = []
+  enum = Enumerator.produce(1) {|obj| passed_args << obj; obj.succ }
+  assert_take [1, 2, 3], enum
+  assert_equal [1, 2], passed_args
+
+  # Raising StopIteration
+  words = %w[The quick brown fox jumps over the lazy dog]
+  enum = Enumerator.produce { words.shift or raise StopIteration }
+  assert_equal %w[The quick brown fox jumps over the lazy dog], enum.to_a
+
+  # Raising StopIteration
+  object = [[[["abc", "def"], "ghi", "jkl"], "mno", "pqr"], "stuv", "wxyz"]
+  enum = Enumerator.produce(object) {|obj|
+    obj.respond_to?(:first) or raise StopIteration
+    obj.first
+  }
+  assert_nothing_raised {
+    assert_equal [
+      [[[["abc", "def"], "ghi", "jkl"], "mno", "pqr"], "stuv", "wxyz"],
+      [[["abc", "def"], "ghi", "jkl"], "mno", "pqr"],
+      [["abc", "def"], "ghi", "jkl"],
+      ["abc", "def"],
+      "abc",
+    ], enum.to_a
+  }
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-error/src/exception.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-error/src/exception.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-error/src/exception.c	(revision 439)
@@ -9,4 +9,5 @@
   struct mrb_jmpbuf c_jmp;
   mrb_value result = mrb_nil_value();
+  int ai = mrb_gc_arena_save(mrb);
 
   if (state) { *state = FALSE; }
@@ -23,4 +24,5 @@
   } MRB_END_EXC(&c_jmp);
 
+  mrb_gc_arena_restore(mrb, ai);
   mrb_gc_protect(mrb, result);
   return result;
@@ -33,4 +35,5 @@
   struct mrb_jmpbuf c_jmp;
   mrb_value result;
+  int ai = mrb_gc_arena_save(mrb);
 
   MRB_TRY(&c_jmp) {
@@ -40,9 +43,13 @@
   } MRB_CATCH(&c_jmp) {
     mrb->jmp = prev_jmp;
+    mrb_gc_arena_restore(mrb, ai);
     ensure(mrb, e_data);
     MRB_THROW(mrb->jmp); /* rethrow catched exceptions */
   } MRB_END_EXC(&c_jmp);
 
+  mrb_gc_arena_restore(mrb, ai);
+  mrb_gc_protect(mrb, result);
   ensure(mrb, e_data);
+  mrb_gc_arena_restore(mrb, ai);
   mrb_gc_protect(mrb, result);
   return result;
@@ -65,4 +72,5 @@
   mrb_bool error_matched = FALSE;
   mrb_int i;
+  int ai = mrb_gc_arena_save(mrb);
 
   MRB_TRY(&c_jmp) {
@@ -83,7 +91,9 @@
 
     mrb->exc = NULL;
+    mrb_gc_arena_restore(mrb, ai);
     result = rescue(mrb, r_data);
   } MRB_END_EXC(&c_jmp);
 
+  mrb_gc_arena_restore(mrb, ai);
   mrb_gc_protect(mrb, result);
   return result;
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-eval/src/eval.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-eval/src/eval.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-eval/src/eval.c	(revision 439)
@@ -13,27 +13,12 @@
 get_closure_irep(mrb_state *mrb, int level)
 {
-  struct mrb_context *c = mrb->c;
-  struct REnv *e = c->ci[-1].proc->env;
-  struct RProc *proc;
-
-  if (level == 0) {
-    proc = c->ci[-1].proc;
-    if (MRB_PROC_CFUNC_P(proc)) {
-      return NULL;
-    }
-    return proc->body.irep;
-  }
-
-  while (--level) {
-    e = (struct REnv*)e->c;
-    if (!e) return NULL;
-  }
-
-  if (!e) return NULL;
-  if (!MRB_ENV_STACK_SHARED_P(e)) return NULL;
-  c = e->cxt.c;
-  proc = c->cibase[e->cioff].proc;
-
-  if (!proc || MRB_PROC_CFUNC_P(proc)) {
+  struct RProc *proc = mrb->c->ci[-1].proc;
+
+  while (level--) {
+    if (!proc) return NULL;
+    proc = proc->upper;
+  }
+  if (!proc) return NULL;
+  if (MRB_PROC_CFUNC_P(proc)) {
     return NULL;
   }
@@ -41,5 +26,24 @@
 }
 
-static inline mrb_code
+/* search for irep lev above the bottom */
+static mrb_irep*
+search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom)
+{
+  int i;
+
+  for (i=0; i<top->rlen; i++) {
+    mrb_irep* tmp = top->reps[i];
+
+    if (tmp == bottom) return top;
+    tmp = search_irep(tmp, bnest-1, lev, bottom);
+    if (tmp) {
+      if (bnest == lev) return top;
+      return tmp;
+    }
+  }
+  return NULL;
+}
+
+static uint16_t
 search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
 {
@@ -49,14 +53,28 @@
 
   for (level = 0; (virep = get_closure_irep(mrb, level)); level++) {
-    if (!virep || virep->lv == NULL) {
+    if (virep->lv == NULL) {
       continue;
     }
     for (pos = 0; pos < virep->nlocals - 1; pos++) {
       if (vsym == virep->lv[pos].name) {
-        return (MKARG_B(pos + 1) | MKARG_C(level + bnest));
-      }
-    }
-  }
-
+        return (pos+1)<<8 | (level+bnest);
+      }
+    }
+  }
+
+  return 0;
+}
+
+static int
+irep_argc(mrb_irep *irep)
+{
+  mrb_code c;
+
+  c = irep->iseq[0];
+  if (c == OP_ENTER) {
+    mrb_aspec ax = PEEK_W(irep->iseq+1);
+    /* extra 1 means a slot for block */
+    return MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1;
+  }
   return 0;
 }
@@ -71,44 +89,50 @@
 }
 
+extern uint8_t mrb_insn_size[];
+extern uint8_t mrb_insn_size1[];
+extern uint8_t mrb_insn_size2[];
+extern uint8_t mrb_insn_size3[];
+
 static void
-patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest)
-{
-  size_t i;
-  mrb_code c;
-  int argc = 0;
-
-  for (i = 0; i < irep->ilen; i++) {
-    c = irep->iseq[i];
-    switch(GET_OPCODE(c)){
-    case OP_ENTER:
-      {
-        mrb_aspec ax = GETARG_Ax(c);
-        /* extra 1 means a slot for block */
-        argc = MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1;
-      }
-      break;
-
+patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top)
+{
+  int i;
+  uint32_t a;
+  uint16_t b;
+  uint8_t c;
+  mrb_code insn;
+  int argc = irep_argc(irep);
+  mrb_code *iseq = (mrb_code *)irep->iseq;
+
+  mrb_assert((irep->flags & MRB_ISEQ_NO_FREE) == 0);
+
+  for (i = 0; i < irep->ilen; ) {
+    insn = iseq[i];
+    switch(insn){
     case OP_EPUSH:
-      patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1);
+      a = PEEK_B(iseq+i+1);
+      patch_irep(mrb, irep->reps[a], bnest + 1, top);
       break;
 
     case OP_LAMBDA:
-      {
-        int arg_c = GETARG_c(c);
-        if (arg_c & OP_L_CAPTURE) {
-          patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1);
-        }
-      }
+    case OP_BLOCK:
+      a = PEEK_B(iseq+i+1);
+      b = PEEK_B(iseq+i+2);
+      patch_irep(mrb, irep->reps[b], bnest + 1, top);
       break;
 
     case OP_SEND:
-      if (GETARG_C(c) != 0) {
+      b = PEEK_B(iseq+i+2);
+      c = PEEK_B(iseq+i+3);
+      if (c != 0) {
         break;
       }
-      {
-        mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest);
+      else {
+        uint16_t arg = search_variable(mrb, irep->syms[b], bnest);
         if (arg != 0) {
           /* must replace */
-          irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
+          iseq[i] = OP_GETUPVAR;
+          iseq[i+2] = arg >> 8;
+          iseq[i+3] = arg & 0xff;
         }
       }
@@ -116,28 +140,82 @@
 
     case OP_MOVE:
+      a = PEEK_B(iseq+i+1);
+      b = PEEK_B(iseq+i+2);
       /* src part */
-      if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) {
-        mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest);
+      if (potential_upvar_p(irep->lv, b, argc, irep->nlocals)) {
+        uint16_t arg = search_variable(mrb, irep->lv[b - 1].name, bnest);
         if (arg != 0) {
           /* must replace */
-          irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
+          iseq[i] = insn = OP_GETUPVAR;
+          iseq[i+2] = arg >> 8;
+          iseq[i+3] = arg & 0xff;
         }
       }
       /* dst part */
-      if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) {
-        mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest);
+      if (potential_upvar_p(irep->lv, a, argc, irep->nlocals)) {
+        uint16_t arg = search_variable(mrb, irep->lv[a - 1].name, bnest);
         if (arg != 0) {
           /* must replace */
-          irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg;
-        }
-      }
-      break;
-
-    case OP_STOP:
-      if (mrb->c->ci->acc >= 0) {
-        irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL);
-      }
-      break;
-    }
+          iseq[i] = insn = OP_SETUPVAR;
+          iseq[i+1] = (mrb_code)b;
+          iseq[i+2] = arg >> 8;
+          iseq[i+3] = arg & 0xff;
+        }
+      }
+      break;
+
+    case OP_GETUPVAR:
+      a = PEEK_B(iseq+i+1);
+      b = PEEK_B(iseq+i+2);
+      c = PEEK_B(iseq+i+3);
+      {
+        int lev = c+1;
+        mrb_irep *tmp = search_irep(top, bnest, lev, irep);
+        if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) {
+          uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest);
+          if (arg != 0) {
+            /* must replace */
+            iseq[i] = OP_GETUPVAR;
+            iseq[i+2] = arg >> 8;
+            iseq[i+3] = arg & 0xff;
+          }
+        }
+      }
+      break;
+
+    case OP_SETUPVAR:
+      a = PEEK_B(iseq+i+1);
+      b = PEEK_B(iseq+i+2);
+      c = PEEK_B(iseq+i+3);
+      {
+        int lev = c+1;
+        mrb_irep *tmp = search_irep(top, bnest, lev, irep);
+        if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) {
+          uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest);
+          if (arg != 0) {
+            /* must replace */
+            iseq[i] = OP_SETUPVAR;
+            iseq[i+1] = a;
+            iseq[i+2] = arg >> 8;
+            iseq[i+3] = arg & 0xff;
+          }
+        }
+      }
+      break;
+
+    case OP_EXT1:
+      insn = PEEK_B(iseq+i+1);
+      i += mrb_insn_size1[insn]+1;
+      continue;
+    case OP_EXT2:
+      insn = PEEK_B(iseq+i+1);
+      i += mrb_insn_size2[insn]+1;
+      continue;
+    case OP_EXT3:
+      insn = PEEK_B(iseq+i+1);
+      i += mrb_insn_size3[insn]+1;
+      continue;
+    }
+    i+=mrb_insn_size[insn];
   }
 }
@@ -146,5 +224,5 @@
 
 static struct RProc*
-create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, const char *file, mrb_int line)
+create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, const char *file, mrb_int line)
 {
   mrbc_context *cxt;
@@ -152,5 +230,7 @@
   struct RProc *proc;
   struct REnv *e;
-  struct mrb_context *c = mrb->c;
+  mrb_callinfo *ci; /* callinfo of eval caller */
+  struct RClass *target_class = NULL;
+  int bidx;
 
   if (!mrb_nil_p(binding)) {
@@ -159,9 +239,10 @@
 
   cxt = mrbc_context_new(mrb);
-  cxt->lineno = line;
+  cxt->lineno = (uint16_t)line;
 
   mrbc_filename(mrb, cxt, file ? file : "(eval)");
   cxt->capture_errors = TRUE;
   cxt->no_optimize = TRUE;
+  cxt->on_eval = TRUE;
 
   p = mrb_parse_nstring(mrb, s, len, cxt);
@@ -177,13 +258,13 @@
 
     if (file) {
-      str = mrb_format(mrb, " file %S line %S: %S",
-                       mrb_str_new_cstr(mrb, file),
-                       mrb_fixnum_value(p->error_buffer[0].lineno),
-                       mrb_str_new_cstr(mrb, p->error_buffer[0].message));
+      str = mrb_format(mrb, "file %s line %d: %s",
+                       file,
+                       p->error_buffer[0].lineno,
+                       p->error_buffer[0].message);
     }
     else {
-      str = mrb_format(mrb, " line %S: %S",
-                       mrb_fixnum_value(p->error_buffer[0].lineno),
-                       mrb_str_new_cstr(mrb, p->error_buffer[0].message));
+      str = mrb_format(mrb, "line %d: %s",
+                       p->error_buffer[0].lineno,
+                       p->error_buffer[0].message);
     }
     mrb_parser_free(p);
@@ -199,18 +280,38 @@
     mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error");
   }
-  if (c->ci[-1].proc->target_class) {
-    proc->target_class = c->ci[-1].proc->target_class;
-  }
-  e = c->ci[-1].proc->env;
-  if (!e) e = c->ci[-1].env;
-  e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)e);
-  e->cxt.c = c;
-  e->cioff = c->ci - c->cibase;
-  e->stack = c->ci->stackent;
-  MRB_SET_ENV_STACK_LEN(e, c->ci->proc->body.irep->nlocals);
-  c->ci->target_class = proc->target_class;
-  c->ci->env = 0;
-  proc->env = e;
-  patch_irep(mrb, proc->body.irep, 0);
+  if (mrb->c->ci > mrb->c->cibase) {
+    ci = &mrb->c->ci[-1];
+  }
+  else {
+    ci = mrb->c->cibase;
+  }
+  if (ci->proc) {
+    target_class = MRB_PROC_TARGET_CLASS(ci->proc);
+  }
+  if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
+    if (ci->env) {
+      e = ci->env;
+    }
+    else {
+      e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV,
+                                      (struct RClass*)target_class);
+      e->mid = ci->mid;
+      e->stack = ci[1].stackent;
+      e->cxt = mrb->c;
+      MRB_ENV_SET_STACK_LEN(e, ci->proc->body.irep->nlocals);
+      bidx = ci->argc;
+      if (ci->argc < 0) bidx = 2;
+      else bidx += 1;
+      MRB_ENV_SET_BIDX(e, bidx);
+      ci->env = e;
+    }
+    proc->e.env = e;
+    proc->flags |= MRB_PROC_ENVSET;
+    mrb_field_write_barrier(mrb, (struct RBasic*)proc, (struct RBasic*)e);
+  }
+  proc->upper = ci->proc;
+  mrb->c->ci->target_class = target_class;
+  patch_irep(mrb, proc->body.irep, 0, proc->body.irep);
+  /* mrb_codedump_all(mrb, proc); */
 
   mrb_parser_free(p);
@@ -223,11 +324,17 @@
 exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc)
 {
+  /* no argument passed from eval() */
+  mrb->c->ci->argc = 0;
   if (mrb->c->ci->acc < 0) {
-    mrb_value ret = mrb_top_run(mrb, proc, mrb->c->stack[0], 0);
+    ptrdiff_t cioff = mrb->c->ci - mrb->c->cibase;
+    mrb_value ret = mrb_top_run(mrb, proc, self, 0);
     if (mrb->exc) {
       mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
     }
+    mrb->c->ci = mrb->c->cibase + cioff;
     return ret;
   }
+  /* clear block */
+  mrb->c->stack[1] = mrb_nil_value();
   return mrb_exec_irep(mrb, self, proc);
 }
@@ -256,5 +363,5 @@
   mrb_int argc; mrb_value *argv;
 
-  mrb_get_args(mrb, "*&", &argv, &argc, &b);
+  mrb_get_args(mrb, "*!&", &argv, &argc, &b);
 
   if (mrb_nil_p(b)) {
@@ -269,7 +376,7 @@
     cv = mrb_singleton_class(mrb, self);
     proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line);
-    proc->target_class = mrb_class_ptr(cv);
-    mrb->c->ci->env = NULL;
+    MRB_PROC_SET_TARGET_CLASS(proc, mrb_class_ptr(cv));
     mrb_assert(!MRB_PROC_CFUNC_P(proc));
+    mrb->c->ci->target_class = mrb_class_ptr(cv);
     return exec_irep(mrb, self, proc);
   }
@@ -284,5 +391,5 @@
 {
   mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_ARG(1, 3));
-  mrb_define_method(mrb, mrb->kernel_module, "instance_eval", f_instance_eval, MRB_ARGS_ARG(1, 2));
+  mrb_define_method(mrb, mrb_class_get(mrb, "BasicObject"), "instance_eval", f_instance_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK());
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-eval/test/eval.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-eval/test/eval.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-eval/test/eval.rb	(revision 439)
@@ -35,5 +35,5 @@
   assert_equal(2) {
     a = 10
-    Kernel.eval 'def f(a); b=a.send(:+, 1); end'
+    Kernel.eval 'def f(a); b=a+1; end'
     f(1)
   }
@@ -59,5 +59,5 @@
 assert('String instance_eval') do
   obj = Object.new
-  obj.instance_variable_set :@test, 'test'
+  obj.instance_eval{ @test = 'test' }
   assert_raise(ArgumentError) { obj.instance_eval(0) { } }
   assert_raise(ArgumentError) { obj.instance_eval('0', 'test', 0, 'test') }
@@ -81,5 +81,5 @@
 end
 
-assert('Object#instance_eval with begin-rescue-ensure execution order') do
+assert('BasicObject#instance_eval with begin-rescue-ensure execution order') do
   class HellRaiser
     def raise_hell
@@ -100,2 +100,33 @@
   assert_equal([:enter_raise_hell, :begin, :rescue, :ensure], hell_raiser.raise_hell)
 end
+
+assert('BasicObject#instance_eval to define singleton methods Issue #3141') do
+  foo_class = Class.new do
+    def bar(x)
+      instance_eval "def baz; #{x}; end"
+    end
+  end
+
+  f1 = foo_class.new
+  f2 = foo_class.new
+  f1.bar 1
+  f2.bar 2
+  assert_equal(1){f1.baz}
+  assert_equal(2){f2.baz}
+end
+
+assert('Kernel.#eval(string) Issue #4021') do
+  assert_equal('FOO') { (eval <<'EOS').call }
+foo = "FOO"
+Proc.new { foo }
+EOS
+  assert_equal('FOO') {
+    def do_eval(code)
+      eval(code)
+    end
+    do_eval(<<'EOS').call
+foo = "FOO"
+Proc.new { foo }
+EOS
+  }
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-exit/src/mruby-exit.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-exit/src/mruby-exit.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-exit/src/mruby-exit.c	(revision 439)
@@ -5,10 +5,15 @@
 f_exit(mrb_state *mrb, mrb_value self)
 {
-  mrb_int i = EXIT_SUCCESS;
+  mrb_value status = mrb_true_value();
+  int istatus;
 
-  mrb_get_args(mrb, "|i", &i);
-  exit(i);
+  mrb_get_args(mrb, "|o", &status);
+  istatus = mrb_true_p(status) ? EXIT_SUCCESS :
+            mrb_false_p(status) ? EXIT_FAILURE :
+            (int)mrb_int(mrb, status);
+  exit(istatus);
+
   /* not reached */
-  return mrb_nil_value();
+  return status;
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-fiber/src/fiber.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-fiber/src/fiber.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-fiber/src/fiber.c	(revision 439)
@@ -73,11 +73,8 @@
   size_t slen;
 
-  mrb_get_args(mrb, "&", &blk);
+  mrb_get_args(mrb, "&!", &blk);
 
   if (f->cxt) {
     mrb_raise(mrb, E_RUNTIME_ERROR, "cannot initialize twice");
-  }
-  if (mrb_nil_p(blk)) {
-    mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Fiber object without a block");
   }
   p = mrb_proc_ptr(blk);
@@ -124,8 +121,8 @@
   /* adjust return callinfo */
   ci = c->ci;
-  ci->target_class = p->target_class;
+  ci->target_class = MRB_PROC_TARGET_CLASS(p);
   ci->proc = p;
+  mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p);
   ci->pc = p->body.irep->iseq;
-  ci->nregs = p->body.irep->nregs;
   ci[1] = ci[0];
   c->ci++;                      /* push dummy callinfo */
@@ -187,24 +184,35 @@
   struct mrb_context *c = fiber_check(mrb, self);
   struct mrb_context *old_c = mrb->c;
+  enum mrb_fiber_state status;
   mrb_value value;
 
   fiber_check_cfunc(mrb, c);
-  if (resume && c->status == MRB_FIBER_TRANSFERRED) {
-    mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber");
-  }
-  if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMED) {
-    mrb_raise(mrb, E_FIBER_ERROR, "double resume (fib)");
-  }
-  if (c->status == MRB_FIBER_TERMINATED) {
+  status = c->status;
+  switch (status) {
+  case MRB_FIBER_TRANSFERRED:
+    if (resume) {
+      mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber");
+    }
+    break;
+  case MRB_FIBER_RUNNING:
+  case MRB_FIBER_RESUMED:
+    mrb_raise(mrb, E_FIBER_ERROR, "double resume");
+    break;
+  case MRB_FIBER_TERMINATED:
     mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber");
-  }
-  mrb->c->status = resume ? MRB_FIBER_RESUMED : MRB_FIBER_TRANSFERRED;
+    break;
+  default:
+    break;
+  }
+  old_c->status = resume ? MRB_FIBER_RESUMED : MRB_FIBER_TRANSFERRED;
   c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c);
-  if (c->status == MRB_FIBER_CREATED) {
+  fiber_switch_context(mrb, c);
+  if (status == MRB_FIBER_CREATED) {
     mrb_value *b, *e;
 
-    if (len >= c->stend - c->stack) {
-      mrb_raise(mrb, E_FIBER_ERROR, "too many arguments to fiber");
+    if (!c->ci->proc) {
+      mrb_raise(mrb, E_FIBER_ERROR, "double resume (current)");
     }
+    mrb_stack_extend(mrb, len+2); /* for receiver and (optional) block */
     b = c->stack+1;
     e = b + len;
@@ -212,11 +220,10 @@
       *b++ = *a++;
     }
-    c->cibase->argc = len;
-    value = c->stack[0] = c->ci->proc->env->stack[0];
+    c->cibase->argc = (int)len;
+    value = c->stack[0] = MRB_PROC_ENV(c->ci->proc)->stack[0];
   }
   else {
     value = fiber_result(mrb, a, len);
   }
-  fiber_switch_context(mrb, c);
 
   if (vmexec) {
@@ -253,5 +260,5 @@
   mrb_bool vmexec = FALSE;
 
-  mrb_get_args(mrb, "*", &a, &len);
+  mrb_get_args(mrb, "*!", &a, &len);
   if (mrb->c->ci->acc < 0) {
     vmexec = TRUE;
@@ -274,10 +281,11 @@
  *  execution of the fiber block this method will always return false.
  */
-static mrb_value
-fiber_alive_p(mrb_state *mrb, mrb_value self)
+MRB_API mrb_value
+mrb_fiber_alive_p(mrb_state *mrb, mrb_value self)
 {
   struct mrb_context *c = fiber_check(mrb, self);
   return mrb_bool_value(c->status != MRB_FIBER_TERMINATED);
 }
+#define fiber_alive_p mrb_fiber_alive_p
 
 static mrb_value
@@ -287,5 +295,5 @@
   mrb_get_args(mrb, "o", &other);
 
-  if (mrb_type(other) != MRB_TT_FIBER) {
+  if (!mrb_fiber_p(other)) {
     return mrb_false_value();
   }
@@ -313,5 +321,5 @@
 
   fiber_check_cfunc(mrb, mrb->c);
-  mrb_get_args(mrb, "*", &a, &len);
+  mrb_get_args(mrb, "*!", &a, &len);
 
   if (c == mrb->root_c) {
@@ -371,5 +379,5 @@
   mrb_int len;
 
-  mrb_get_args(mrb, "*", &a, &len);
+  mrb_get_args(mrb, "*!", &a, &len);
   return mrb_fiber_yield(mrb, len, a);
 }
@@ -402,5 +410,5 @@
   MRB_SET_INSTANCE_TT(c, MRB_TT_FIBER);
 
-  mrb_define_method(mrb, c, "initialize", fiber_init,    MRB_ARGS_NONE());
+  mrb_define_method(mrb, c, "initialize", fiber_init,    MRB_ARGS_NONE()|MRB_ARGS_BLOCK());
   mrb_define_method(mrb, c, "resume",     fiber_resume,  MRB_ARGS_ANY());
   mrb_define_method(mrb, c, "transfer",   fiber_transfer, MRB_ARGS_ANY());
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-fiber/test/fiber.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-fiber/test/fiber.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-fiber/test/fiber.rb	(revision 439)
@@ -77,5 +77,5 @@
 
 assert('Fiber with splat in the block argument list') {
-  Fiber.new{|*x|x}.resume(1) == [1]
+  assert_equal([1], Fiber.new{|*x|x}.resume(1))
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-hash-ext/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-hash-ext/mrbgem.rake	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-hash-ext/mrbgem.rake	(revision 439)
@@ -3,5 +3,4 @@
   spec.author  = 'mruby developers'
   spec.summary = 'Hash class extension'
-  spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext'
-  spec.add_dependency 'mruby-array-ext', :core => 'mruby-array-ext'
+  spec.add_dependency 'mruby-array-ext', core: 'mruby-array-ext'
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-hash-ext/mrblib/hash.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-hash-ext/mrblib/hash.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-hash-ext/mrblib/hash.rb	(revision 439)
@@ -28,7 +28,7 @@
     if length == 1
       o = object[0]
-      if o.respond_to?(:to_hash)
+      if Hash === o
         h = self.new
-        object[0].to_hash.each { |k, v| h[k] = v }
+        o.each { |k, v| h[k] = v }
         return h
       elsif o.respond_to?(:to_a)
@@ -63,23 +63,4 @@
   ##
   # call-seq:
-  #     Hash.try_convert(obj) -> hash or nil
-  #
-  # Try to convert <i>obj</i> into a hash, using to_hash method.
-  # Returns converted hash or nil if <i>obj</i> cannot be converted
-  # for any reason.
-  #
-  #     Hash.try_convert({1=>2})   # => {1=>2}
-  #     Hash.try_convert("1=>2")   # => nil
-  #
-  def self.try_convert(obj)
-    if obj.respond_to?(:to_hash)
-      obj.to_hash
-    else
-      nil
-    end
-  end
-
-  ##
-  # call-seq:
   #     hsh.merge!(other_hash)                                 -> hsh
   #     hsh.merge!(other_hash){|key, oldval, newval| block}    -> hsh
@@ -102,5 +83,5 @@
 
   def merge!(other, &block)
-    raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash)
+    raise TypeError, "Hash required (#{other.class} given)" unless Hash === other
     if block
       other.each_key{|k|
@@ -114,4 +95,49 @@
 
   alias update merge!
+
+  ##
+  # call-seq:
+  #   hsh.compact!    -> hsh
+  #
+  # Removes all nil values from the hash. Returns the hash.
+  # Returns nil if the hash does not contain nil values.
+  #
+  #   h = { a: 1, b: false, c: nil }
+  #   h.compact!     #=> { a: 1, b: false }
+  #
+
+  def compact!
+    keys = self.keys
+    nk = keys.select{|k|
+      self[k] != nil
+    }
+    return nil if (keys.size == nk.size)
+    h = {}
+    nk.each {|k|
+      h[k] = self[k]
+    }
+    h
+    self.replace(h)
+  end
+
+  ##
+  # call-seq:
+  #    hsh.compact     -> new_hsh
+  #
+  # Returns a new hash with the nil values/key pairs removed
+  #
+  #    h = { a: 1, b: false, c: nil }
+  #    h.compact     #=> { a: 1, b: false }
+  #    h             #=> { a: 1, b: false, c: nil }
+  #
+  def compact
+    h = {}
+    self.keys.select{|k|
+      self[k] != nil
+    }.each {|k|
+      h[k] = self[k]
+    }
+    h
+  end
 
   ##
@@ -150,5 +176,5 @@
         none
       else
-        raise KeyError, "Key not found: #{key}"
+        raise KeyError, "Key not found: #{key.inspect}"
       end
     else
@@ -172,5 +198,5 @@
 
   def delete_if(&block)
-    return to_enum :delete_if unless block_given?
+    return to_enum :delete_if unless block
 
     self.each do |k, v|
@@ -229,5 +255,5 @@
 
   def keep_if(&block)
-    return to_enum :keep_if unless block_given?
+    return to_enum :keep_if unless block
 
     keys = []
@@ -285,9 +311,5 @@
   #
   def <(hash)
-    begin
-      hash = hash.to_hash
-    rescue NoMethodError
-      raise TypeError, "can't convert #{hash.class} to Hash"
-    end
+    raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
     size < hash.size and all? {|key, val|
       hash.key?(key) and hash[key] == val
@@ -309,9 +331,5 @@
   #
   def <=(hash)
-    begin
-      hash = hash.to_hash
-    rescue NoMethodError
-      raise TypeError, "can't convert #{hash.class} to Hash"
-    end
+    raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
     size <= hash.size and all? {|key, val|
       hash.key?(key) and hash[key] == val
@@ -333,9 +351,5 @@
   #
   def >(hash)
-    begin
-      hash = hash.to_hash
-    rescue NoMethodError
-      raise TypeError, "can't convert #{hash.class} to Hash"
-    end
+    raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
     size > hash.size and hash.all? {|key, val|
       key?(key) and self[key] == val
@@ -357,9 +371,5 @@
   #
   def >=(hash)
-    begin
-      hash = hash.to_hash
-    rescue NoMethodError
-      raise TypeError, "can't convert #{hash.class} to Hash"
-    end
+    raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash
     size >= hash.size and hash.all? {|key, val|
       key?(key) and self[key] == val
@@ -383,3 +393,108 @@
     end
   end
+
+  ##
+  # call-seq:
+  #    hsh.transform_keys {|key| block } -> new_hash
+  #    hsh.transform_keys                -> an_enumerator
+  #
+  # Returns a new hash, with the keys computed from running the block
+  # once for each key in the hash, and the values unchanged.
+  #
+  # If no block is given, an enumerator is returned instead.
+  #
+  def transform_keys(&block)
+    return to_enum :transform_keys unless block
+    hash = {}
+    self.keys.each do |k|
+      new_key = block.call(k)
+      hash[new_key] = self[k]
+    end
+    hash
+  end
+  ##
+  # call-seq:
+  #    hsh.transform_keys! {|key| block } -> hsh
+  #    hsh.transform_keys!                -> an_enumerator
+  #
+  # Invokes the given block once for each key in <i>hsh</i>, replacing it
+  # with the new key returned by the block, and then returns <i>hsh</i>.
+  #
+  # If no block is given, an enumerator is returned instead.
+  #
+  def transform_keys!(&block)
+    return to_enum :transform_keys! unless block
+    self.keys.each do |k|
+      value = self[k]
+      self.__delete(k)
+      k = block.call(k) if block
+      self[k] = value
+    end
+    self
+  end
+  ##
+  # call-seq:
+  #    hsh.transform_values {|value| block } -> new_hash
+  #    hsh.transform_values                  -> an_enumerator
+  #
+  # Returns a new hash with the results of running the block once for
+  # every value.
+  # This method does not change the keys.
+  #
+  # If no block is given, an enumerator is returned instead.
+  #
+  def transform_values(&b)
+    return to_enum :transform_values unless block_given?
+    hash = {}
+    self.keys.each do |k|
+      hash[k] = yield(self[k])
+    end
+    hash
+  end
+
+  ##
+  # call-seq:
+  #    hsh.transform_values! {|key| block } -> hsh
+  #    hsh.transform_values!                -> an_enumerator
+  #
+  # Invokes the given block once for each value in the hash, replacing
+  # with the new value returned by the block, and then returns <i>hsh</i>.
+  #
+  # If no block is given, an enumerator is returned instead.
+  #
+  def transform_values!(&b)
+    return to_enum :transform_values! unless block_given?
+    self.keys.each do |k|
+      self[k] = yield(self[k])
+    end
+    self
+  end
+
+  def to_proc
+    ->x{self[x]}
+  end
+
+  ##
+  # call-seq:
+  #   hsh.fetch_values(key, ...)                 -> array
+  #   hsh.fetch_values(key, ...) { |key| block } -> array
+  #
+  # Returns an array containing the values associated with the given keys
+  # but also raises <code>KeyError</code> when one of keys can't be found.
+  # Also see <code>Hash#values_at</code> and <code>Hash#fetch</code>.
+  #
+  #   h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" }
+  #
+  #   h.fetch_values("cow", "cat")                   #=> ["bovine", "feline"]
+  #   h.fetch_values("cow", "bird")                  # raises KeyError
+  #   h.fetch_values("cow", "bird") { |k| k.upcase } #=> ["bovine", "BIRD"]
+  #
+  def fetch_values(*keys, &block)
+    keys.map do |k|
+      self.fetch(k, &block)
+    end
+  end
+
+  alias filter select
+  alias filter! select!
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-hash-ext/src/hash-ext.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-hash-ext/src/hash-ext.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-hash-ext/src/hash-ext.c	(revision 439)
@@ -37,4 +37,35 @@
 }
 
+/*
+ *  call-seq:
+ *     hsh.slice(*keys) -> a_hash
+ *
+ *  Returns a hash containing only the given keys and their values.
+ *
+ *     h = { a: 100, b: 200, c: 300 }
+ *     h.slice(:a)           #=> {:a=>100}
+ *     h.slice(:b, :c, :d)   #=> {:b=>200, :c=>300}
+ */
+static mrb_value
+hash_slice(mrb_state *mrb, mrb_value hash)
+{
+  mrb_value *argv, result;
+  mrb_int argc, i;
+
+  mrb_get_args(mrb, "*", &argv, &argc);
+  result = mrb_hash_new_capa(mrb, argc);
+  if (argc == 0) return result; /* empty hash */
+  for (i = 0; i < argc; i++) {
+    mrb_value key = argv[i];
+    mrb_value val;
+
+    val = mrb_hash_fetch(mrb, hash, key, mrb_undef_value());
+    if (!mrb_undef_p(val)) {
+      mrb_hash_set(mrb, result, key, val);
+    }
+  }
+  return result;
+}
+
 void
 mrb_mruby_hash_ext_gem_init(mrb_state *mrb)
@@ -44,4 +75,5 @@
   h = mrb->hash_class;
   mrb_define_method(mrb, h, "values_at", hash_values_at, MRB_ARGS_ANY());
+  mrb_define_method(mrb, h, "slice",     hash_slice, MRB_ARGS_ANY());
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-hash-ext/test/hash.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-hash-ext/test/hash.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-hash-ext/test/hash.rb	(revision 439)
@@ -46,10 +46,4 @@
 end
 
-assert('Hash.try_convert') do
-  assert_nil Hash.try_convert(nil)
-  assert_nil Hash.try_convert("{1=>2}")
-  assert_equal({1=>2}, Hash.try_convert({1=>2}))
-end
-
 assert('Hash#merge!') do
   a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' }
@@ -81,4 +75,18 @@
   h = Hash.new { |hash,k| hash[k] = k }
   assert_equal keys, h.values_at(*keys)
+end
+
+assert('Hash#compact') do
+  h = { "cat" => "feline", "dog" => nil, "cow" => false }
+
+  assert_equal({ "cat" => "feline", "cow" => false }, h.compact)
+  assert_equal({ "cat" => "feline", "dog" => nil, "cow" => false }, h)
+end
+
+assert('Hash#compact!') do
+  h = { "cat" => "feline", "dog" => nil, "cow" => false }
+
+  h.compact!
+  assert_equal({ "cat" => "feline", "cow" => false }, h)
 end
 
@@ -255,2 +263,28 @@
   assert_nil(h.dig(:d))
 end
+
+assert("Hash#transform_keys") do
+  h = {"1" => 100, "2" => 200}
+  assert_equal({"1!" => 100, "2!" => 200},
+               h.transform_keys{|k| k+"!"})
+  assert_equal({1 => 100, 2 => 200},
+               h.transform_keys{|k|k.to_i})
+  assert_same(h, h.transform_keys!{|k|k.to_i})
+  assert_equal({1 => 100, 2 => 200}, h)
+end
+
+assert("Hash#transform_values") do
+  h = {a: 1, b: 2, c: 3}
+  assert_equal({a: 2, b: 5, c: 10},
+               h.transform_values{|v| v * v + 1})
+  assert_equal({a: "1", b: "2", c: "3"},
+               h.transform_values{|v|v.to_s})
+  assert_same(h, h.transform_values!{|v|v.to_s})
+  assert_equal({a: "1", b: "2", c: "3"}, h)
+end
+
+assert("Hash#slice") do
+  h = { a: 100, b: 200, c: 300 }
+  assert_equal({:a=>100}, h.slice(:a))
+  assert_equal({:b=>200, :c=>300}, h.slice(:b, :c, :d))
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-inline-struct/test/inline.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-inline-struct/test/inline.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-inline-struct/test/inline.c	(revision 439)
@@ -12,15 +12,17 @@
   mrb_get_args(mrb, "o", &object);
 
-  if (mrb_float_p(object))
-  {
-    snprintf(string, size, "float(%.3f)", mrb_float(object));
+  if (mrb_fixnum_p(object)) {
+    strncpy(string, "fixnum", size-1);
   }
-  else if (mrb_fixnum_p(object))
-  {
-    snprintf(string, size, "fixnum(%" MRB_PRId ")", mrb_fixnum(object));
+#ifndef MRB_WITHOUT_FLOAT
+  else if (mrb_float_p(object)) {
+    strncpy(string, "float", size-1);
   }
-  else if (mrb_string_p(object))
-  {
-    snprintf(string, size, "string(%s)", mrb_string_value_cstr(mrb, &object));
+#endif
+  else if (mrb_string_p(object)) {
+    strncpy(string, "string", size-1);
+  }
+  else {
+    strncpy(string, "anything", size-1);
   }
 
@@ -48,5 +50,5 @@
   if (mrb_obj_class(mrb, object) != mrb_class_get(mrb, "InlineStructTest"))
   {
-    mrb_raisef(mrb, E_TYPE_ERROR, "Expected InlineStructTest");
+    mrb_raise(mrb, E_TYPE_ERROR, "Expected InlineStructTest");
   }
   return mrb_bool_value(((char*)mrb_istruct_ptr(object))[0] == 's');
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-inline-struct/test/inline.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-inline-struct/test/inline.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-inline-struct/test/inline.rb	(revision 439)
@@ -18,12 +18,12 @@
 assert('InlineStructTest#dup') do
   obj = InlineStructTest.new(1)
-  assert_equal obj.to_s, 'fixnum(1)'
-  assert_equal obj.dup.to_s, 'fixnum(1)'
+  assert_equal obj.to_s, 'fixnum'
+  assert_equal obj.dup.to_s, 'fixnum'
 end
 
 assert('InlineStructTest#clone') do
   obj = InlineStructTest.new(1)
-  assert_equal obj.to_s, 'fixnum(1)'
-  assert_equal obj.clone.to_s, 'fixnum(1)'
+  assert_equal obj.to_s, 'fixnum'
+  assert_equal obj.clone.to_s, 'fixnum'
 end
 
@@ -39,20 +39,20 @@
 assert('InlineStructTest#mutate (dup)') do
   obj1 = InlineStructTest.new("foo")
-  assert_equal obj1.to_s, "string(foo)"
+  assert_equal obj1.to_s, "string"
   obj2 = obj1.dup
-  assert_equal obj2.to_s, "string(foo)"
+  assert_equal obj2.to_s, "string"
   obj1.mutate
-  assert_equal obj1.to_s, "mutate(foo)"
-  assert_equal obj2.to_s, "string(foo)"
+  assert_equal obj1.to_s, "mutate"
+  assert_equal obj2.to_s, "string"
 end
 
 assert('InlineStructTest#mutate (clone)') do
   obj1 = InlineStructTest.new("foo")
-  assert_equal obj1.to_s, "string(foo)"
+  assert_equal obj1.to_s, "string"
   obj2 = obj1.clone
-  assert_equal obj2.to_s, "string(foo)"
+  assert_equal obj2.to_s, "string"
   obj1.mutate
-  assert_equal obj1.to_s, "mutate(foo)"
-  assert_equal obj2.to_s, "string(foo)"
+  assert_equal obj1.to_s, "mutate"
+  assert_equal obj2.to_s, "string"
 end
 
@@ -102,24 +102,4 @@
     assert_equal InlineStructTest.length, 3 * 8
   end
-
-  assert('InlineStructTest w/float [64 bit]') do
-    obj = InlineStructTest.new(1.25)
-    assert_equal obj.to_s, "float(1.250)"
-  end
-
-  assert('InlineStructTest w/fixnum [64 bit]') do
-    obj = InlineStructTest.new(42)
-    assert_equal obj.to_s, "fixnum(42)"
-  end
-
-  assert('InlineStructTest w/string [64 bit]') do
-    obj = InlineStructTest.new("hello")
-    assert_equal obj.to_s, "string(hello)"
-  end
-
-  assert('InlineStructTest w/long string [64 bit]') do
-    obj = InlineStructTest.new("this won't fit in 3 * 8 bytes available for the structure")
-    assert_equal obj.to_s, "string(this won't fit i"
-  end
 end
 
@@ -129,23 +109,10 @@
     assert_equal InlineStructTest.length, 3 * 4
   end
+end
 
-  assert('InlineStructTest w/float [32 bit]') do
-    obj = InlineStructTest.new(1.25)
-    assert_equal obj.to_s, "float(1.250"
-  end
-
-  assert('InlineStructTest w/fixnum [32 bit]') do
-    obj = InlineStructTest.new(42)
-    assert_equal obj.to_s, "fixnum(42)"
-  end
-
-  assert('InlineStructTest w/string [32 bit]') do
-    obj = InlineStructTest.new("hello")
-    assert_equal obj.to_s, "string(hell"
-  end
-
-  assert('InlineStructTest w/long string [32 bit]') do
-    obj = InlineStructTest.new("this won't fit in 3 * 4 bytes available for the structure")
-    assert_equal obj.to_s, "string(this"
+# 16-bit mode
+if InlineStructTest.length == 6
+  assert('InlineStructTest length [16 bit]') do
+    assert_equal InlineStructTest.length, 3 * 2
   end
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/README.md
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/README.md	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/README.md	(revision 439)
@@ -0,0 +1,192 @@
+mruby-io
+========
+
+`IO` and `File` classes for mruby
+
+## Installation
+Add the line below to your `build_config.rb`:
+
+```
+  conf.gem core: '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           |    o     |      |
+| 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?         |    o     |      |
+| 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                  |   o      |      |
+| 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               |   o      |      |
+| 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.
+Copyright (c) 2017 mruby developers
+
+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/mruby-2.1.1/mrbgems/mruby-io/include/mruby/ext/io.h
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/include/mruby/ext/io.h	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/include/mruby/ext/io.h	(revision 439)
@@ -0,0 +1,70 @@
+/*
+** io.h - IO class
+*/
+
+#ifndef MRUBY_IO_H
+#define MRUBY_IO_H
+
+#include <mruby.h>
+
+#ifdef MRB_DISABLE_STDIO
+# error IO and File conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(MRB_WITHOUT_IO_PREAD_PWRITE)
+# undef MRB_WITH_IO_PREAD_PWRITE
+#elif !defined(MRB_WITH_IO_PREAD_PWRITE)
+# if defined(__unix__)
+#  define MRB_WITH_IO_PREAD_PWRITE
+# endif
+#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,
+               is_socket:1;
+};
+
+#define MRB_O_RDONLY            0x0000
+#define MRB_O_WRONLY            0x0001
+#define MRB_O_RDWR              0x0002
+#define MRB_O_ACCMODE           (MRB_O_RDONLY | MRB_O_WRONLY | MRB_O_RDWR)
+#define MRB_O_NONBLOCK          0x0004
+#define MRB_O_APPEND            0x0008
+#define MRB_O_SYNC              0x0010
+#define MRB_O_NOFOLLOW          0x0020
+#define MRB_O_CREAT             0x0040
+#define MRB_O_TRUNC             0x0080
+#define MRB_O_EXCL              0x0100
+#define MRB_O_NOCTTY            0x0200
+#define MRB_O_DIRECT            0x0400
+#define MRB_O_BINARY            0x0800
+#define MRB_O_SHARE_DELETE      0x1000
+#define MRB_O_TMPFILE           0x2000
+#define MRB_O_NOATIME           0x4000
+#define MRB_O_DSYNC             0x00008000 /* Ignored with MRB_INT16 and MRB_WITHOUT_FLOAT */
+#define MRB_O_RSYNC             0x00010000 /* Ignored with MRB_INT16 and MRB_WITHOUT_FLOAT */
+
+#define MRB_O_RDONLY_P(f)       ((mrb_bool)(((f) & MRB_O_ACCMODE) == MRB_O_RDONLY))
+#define MRB_O_WRONLY_P(f)       ((mrb_bool)(((f) & MRB_O_ACCMODE) == MRB_O_WRONLY))
+#define MRB_O_RDWR_P(f)         ((mrb_bool)(((f) & MRB_O_ACCMODE) == MRB_O_RDWR))
+#define MRB_O_READABLE_P(f)     ((mrb_bool)((((f) & MRB_O_ACCMODE) | 2) == 2))
+#define MRB_O_WRITABLE_P(f)     ((mrb_bool)(((((f) & MRB_O_ACCMODE) + 1) & 2) == 2))
+
+#define E_IO_ERROR                 (mrb_class_get(mrb, "IOError"))
+#define E_EOF_ERROR                (mrb_class_get(mrb, "EOFError"))
+
+int mrb_io_fileno(mrb_state *mrb, mrb_value io);
+
+#if defined(__cplusplus)
+} /* extern "C" { */
+#endif
+#endif /* MRUBY_IO_H */
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrbgem.rake	(revision 439)
@@ -0,0 +1,12 @@
+MRuby::Gem::Specification.new('mruby-io') do |spec|
+  spec.license = 'MIT'
+  spec.authors = ['Internet Initiative Japan Inc.', 'mruby developers']
+  spec.summary = 'IO and File class'
+
+  spec.cc.include_paths << "#{build.root}/src"
+
+  if for_windows?
+    spec.linker.libraries << "ws2_32"
+  end
+  spec.add_test_dependency 'mruby-time', core: 'mruby-time'
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrblib/file.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrblib/file.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrblib/file.rb	(revision 439)
@@ -0,0 +1,203 @@
+class File < IO
+  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._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
+
+  def self.expand_path(path, default_dir = '.')
+    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/mruby-2.1.1/mrbgems/mruby-io/mrblib/file_constants.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrblib/file_constants.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrblib/file_constants.rb	(revision 439)
@@ -0,0 +1,13 @@
+class File
+  module Constants
+    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/mruby-2.1.1/mrbgems/mruby-io/mrblib/io.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrblib/io.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrblib/io.rb	(revision 439)
@@ -0,0 +1,369 @@
+##
+# 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
+        mode = opt[:mode] || "r"
+        fd = IO.sysopen(path, mode)
+        io = IO.open(fd, mode)
+      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 0 if str.empty?
+    unless @buf.empty?
+      # reset real pos ignore buf
+      seek(pos, SEEK_SET)
+    end
+    len = syswrite(str)
+    len
+  end
+
+  def <<(str)
+    write(str)
+    self
+  end
+
+  def eof?
+    _check_readable
+    begin
+      _read_buf
+      return @buf.empty?
+    rescue EOFError
+      return true
+    end
+  end
+  alias_method :eof, :eof?
+
+  def pos
+    raise IOError if closed?
+    sysseek(0, SEEK_CUR) - @buf.bytesize
+  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?
+    sysseek(i, whence)
+    @buf = ''
+    0
+  end
+
+  def _read_buf
+    return @buf if @buf && @buf.bytesize > 0
+    sysread(BUF_SIZE, @buf)
+  end
+
+  def ungetc(substr)
+    raise TypeError.new "expect String, got #{substr.class}" unless substr.is_a?(String)
+    if @buf.empty?
+      @buf.replace(substr)
+    else
+      @buf[0,0] = substr
+    end
+    nil
+  end
+
+  def read(length = nil, outbuf = "")
+    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 = []
+    while 1
+      begin
+        _read_buf
+      rescue EOFError
+        array = nil if array.empty? and (not length.nil?) and length != 0
+        break
+      end
+
+      if length
+        consume = (length <= @buf.bytesize) ? length : @buf.bytesize
+        array.push IO._bufread(@buf, consume)
+        length -= consume
+        break if length == 0
+      else
+        array.push @buf
+        @buf = ''
+      end
+    end
+
+    if array.nil?
+      outbuf.replace("")
+      nil
+    else
+      outbuf.replace(array.join)
+    end
+  end
+
+  def readline(arg = "\n", limit = nil)
+    case arg
+    when String
+      rs = arg
+    when Fixnum
+      rs = "\n"
+      limit = arg
+    else
+      raise ArgumentError
+    end
+
+    if rs.nil?
+      return read
+    end
+
+    if rs == ""
+      rs = "\n\n"
+    end
+
+    array = []
+    while 1
+      begin
+        _read_buf
+      rescue EOFError
+        array = nil if array.empty?
+        break
+      end
+
+      if limit && limit <= @buf.size
+        array.push @buf[0, limit]
+        @buf[0, limit] = ""
+        break
+      elsif idx = @buf.index(rs)
+        len = idx + rs.size
+        array.push @buf[0, len]
+        @buf[0, len] = ""
+        break
+      else
+        array.push @buf
+        @buf = ''
+      end
+    end
+
+    raise EOFError.new "end of file reached" if array.nil?
+
+    array.join
+  end
+
+  def gets(*args)
+    begin
+      readline(*args)
+    rescue EOFError
+      nil
+    end
+  end
+
+  def readchar
+    _read_buf
+    _readchar(@buf)
+  end
+
+  def getc
+    begin
+      readchar
+    rescue EOFError
+      c = @buf[0]
+      @buf[0,1]="" if c
+      nil
+    end
+  end
+
+  # 15.2.20.5.3
+  def each(&block)
+    return to_enum unless block
+
+    while line = self.gets
+      block.call(line)
+    end
+    self
+  end
+
+  # 15.2.20.5.4
+  def each_byte(&block)
+    return to_enum(:each_byte) unless 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
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrblib/kernel.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrblib/kernel.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/mrblib/kernel.rb	(revision 439)
@@ -0,0 +1,31 @@
+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
+
+  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
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/file.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/file.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/file.c	(revision 439)
@@ -0,0 +1,703 @@
+/*
+** file.c - File class
+*/
+
+#include "mruby.h"
+#include "mruby/class.h"
+#include "mruby/data.h"
+#include "mruby/string.h"
+#include "mruby/ext/io.h"
+#include "mruby/error.h"
+
+#include <sys/types.h>
+#if !defined(AZURE_SPHERE)
+#include <sys/stat.h>
+#else
+mode_t umask(mode_t);
+int chmod(const char *, mode_t);
+#endif
+
+#include <fcntl.h>
+#include <limits.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_WIN32) || defined(_WIN64)
+  #include <windows.h>
+  #include <io.h>
+  #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)
+#if !defined(AZURE_SPHERE)
+  #include <sys/file.h>
+  #include <libgen.h>
+#else
+char *basename(char *);
+#endif
+  #include <sys/param.h>
+#if !defined(AZURE_SPHERE)
+  #include <pwd.h>
+#endif
+#endif
+
+#if defined(AZURE_SPHERE)
+  #include <time.h>
+int unlink(const char *);
+ssize_t readlink(const char *__restrict, char *__restrict, size_t);
+int symlink(const char *, const char *);
+int rename(const char *, const char *);
+int ftruncate(int, off_t);
+char *realpath (const char *__restrict, char *__restrict);
+char *getcwd(char *, size_t);
+struct passwd {
+  char *pw_dir;
+};
+struct passwd *getpwnam (const char *);
+struct stat {
+  mode_t st_mode;
+  struct timespec st_mtim;
+  off_t st_size;
+};
+#define st_mtime st_mtim.tv_sec
+int fstat(int, struct stat *);
+int flock(int, int);
+char *dirname(char *);
+#endif
+
+#define FILE_SEPARATOR "/"
+
+#if defined(_WIN32) || defined(_WIN64)
+  #define PATH_SEPARATOR ";"
+  #define FILE_ALT_SEPARATOR "\\"
+  #define VOLUME_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
+
+#ifndef _WIN32
+typedef struct stat         mrb_stat;
+# define mrb_stat(path, sb) stat(path, sb)
+# define mrb_fstat(fd, sb)  fstat(fd, sb)
+#else
+typedef struct __stat64     mrb_stat;
+# define mrb_stat(path, sb) _stat64(path, sb)
+# define mrb_fstat(fd, sb)  _fstat64(fd, sb)
+#endif
+
+#ifdef _WIN32
+static int
+flock(int fd, int operation) {
+  OVERLAPPED ov;
+  HANDLE h = (HANDLE)_get_osfhandle(fd);
+  DWORD flags;
+  flags = ((operation & LOCK_NB) ? LOCKFILE_FAIL_IMMEDIATELY : 0)
+          | ((operation & LOCK_SH) ? LOCKFILE_EXCLUSIVE_LOCK : 0);
+  memset(&ov, 0, sizeof(ov));
+  return LockFileEx(h, flags, 0, 0xffffffff, 0xffffffff, &ov) ? 0 : -1;
+}
+#endif
+
+mrb_value
+mrb_file_s_umask(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+  /* 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;
+  char *path;
+
+  mrb_get_args(mrb, "*", &argv, &argc);
+  for (i = 0; i < argc; i++) {
+    const char *utf8_path;
+    pathv = mrb_ensure_string_type(mrb, argv[i]);
+    utf8_path = RSTRING_CSTR(mrb, pathv);
+    path = mrb_locale_from_utf8(utf8_path, -1);
+    if (UNLINK(path) < 0) {
+      mrb_locale_free(path);
+      mrb_sys_fail(mrb, utf8_path);
+    }
+    mrb_locale_free(path);
+  }
+  return mrb_fixnum_value(argc);
+}
+
+static mrb_value
+mrb_file_s_rename(mrb_state *mrb, mrb_value obj)
+{
+  mrb_value from, to;
+  char *src, *dst;
+
+  mrb_get_args(mrb, "SS", &from, &to);
+  src = mrb_locale_from_utf8(RSTRING_CSTR(mrb, from), -1);
+  dst = mrb_locale_from_utf8(RSTRING_CSTR(mrb, to), -1);
+  if (rename(src, dst) < 0) {
+#if defined(_WIN32) || defined(_WIN64)
+    if (CHMOD(dst, 0666) == 0 && UNLINK(dst) == 0 && rename(src, dst) == 0) {
+      mrb_locale_free(src);
+      mrb_locale_free(dst);
+      return mrb_fixnum_value(0);
+    }
+#endif
+    mrb_locale_free(src);
+    mrb_locale_free(dst);
+    mrb_sys_fail(mrb, RSTRING_CSTR(mrb, mrb_format(mrb, "(%v, %v)", from, to)));
+    return mrb_fixnum_value(-1); /* not reached */
+  }
+  mrb_locale_free(src);
+  mrb_locale_free(dst);
+  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];
+  const char *utf8_path;
+  char *path;
+  size_t ridx;
+  mrb_get_args(mrb, "z", &utf8_path);
+  path = mrb_locale_from_utf8(utf8_path, -1);
+  _splitpath(path, vname, dname, NULL, NULL);
+  snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname);
+  mrb_locale_free(path);
+  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_locale_from_utf8(mrb_str_to_cstr(mrb, s), -1);
+
+  if ((dname = dirname(path)) == NULL) {
+    mrb_locale_free(path);
+    mrb_sys_fail(mrb, "dirname");
+  }
+  mrb_locale_free(path);
+  return mrb_str_new_cstr(mrb, dname);
+#endif
+}
+
+static mrb_value
+mrb_file_basename(mrb_state *mrb, mrb_value klass)
+{
+  // NOTE: Do not use mrb_locale_from_utf8 here
+#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");
+  }
+  if (strncmp(bname, "//", 3) == 0) bname[1] = '\0';  /* patch for Cygwin */
+  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;
+  mrb_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_locale_from_utf8(RSTRING_CSTR(mrb, pathname), -1);
+  result = mrb_str_buf_new(mrb, PATH_MAX);
+  if (realpath(cpath, RSTRING_PTR(result)) == NULL) {
+    mrb_locale_free(cpath);
+    mrb_sys_fail(mrb, cpath);
+    return result;              /* not reached */
+  }
+  mrb_locale_free(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;
+  char buf[MAXPATHLEN], *utf8;
+
+  if (GETCWD(buf, MAXPATHLEN) == NULL) {
+    mrb_sys_fail(mrb, "getcwd(2)");
+  }
+  utf8 = mrb_utf8_from_locale(buf, -1);
+  path = mrb_str_new_cstr(mrb, utf8);
+  mrb_utf8_free(utf8);
+  return path;
+}
+
+#ifdef _WIN32
+#define IS_FILESEP(x) (x == (*(char*)(FILE_SEPARATOR)) || x == (*(char*)(FILE_ALT_SEPARATOR)))
+#define IS_VOLSEP(x) (x == (*(char*)(VOLUME_SEPARATOR)))
+#define IS_DEVICEID(x) (x == '.' || x == '?')
+#define CHECK_UNCDEV_PATH (IS_FILESEP(path[0]) && IS_FILESEP(path[1]))
+
+static int 
+is_absolute_traditional_path(const char *path, size_t len)
+{
+  if (len < 3) return 0;
+  return (ISALPHA(path[0]) && IS_VOLSEP(path[1]) && IS_FILESEP(path[2]));
+}
+
+static int 
+is_aboslute_unc_path(const char *path, size_t len) {
+  if (len < 2) return 0;
+  return (CHECK_UNCDEV_PATH && !IS_DEVICEID(path[2]));
+}
+
+static int 
+is_absolute_device_path(const char *path, size_t len) {
+  if (len < 4) return 0;
+  return (CHECK_UNCDEV_PATH && IS_DEVICEID(path[2]) && IS_FILESEP(path[3]));
+}
+
+static int
+mrb_file_is_absolute_path(const char *path)
+{
+  size_t len = strlen(path);
+  if (IS_FILESEP(path[0])) return 1;
+  if (len > 0)
+    return (
+      is_absolute_traditional_path(path, len) || 
+      is_aboslute_unc_path(path, len) || 
+      is_absolute_device_path(path, len)
+      );
+  else
+    return 0;
+}
+
+#undef IS_FILESEP
+#undef IS_VOLSEP
+#undef IS_DEVICEID
+#undef CHECK_UNCDEV_PATH
+
+#else
+static int
+mrb_file_is_absolute_path(const char *path)
+{
+  return (path[0] == *(char*)(FILE_SEPARATOR));
+}
+#endif
+
+static mrb_value
+mrb_file__gethome(mrb_state *mrb, mrb_value klass)
+{
+  mrb_int argc;
+  char *home;
+  mrb_value path;
+
+#ifndef _WIN32
+  mrb_value username;
+
+  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 = RSTRING_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 ~%v", username);
+    }
+  }
+  home = mrb_locale_from_utf8(home, -1);
+  path = mrb_str_new_cstr(mrb, home);
+  mrb_locale_free(home);
+  return path;
+#else  /* _WIN32 */
+  argc = mrb_get_argc(mrb);
+  if (argc == 0) {
+    home = getenv("USERPROFILE");
+    if (home == NULL) {
+      return mrb_nil_value();
+    }
+    if (!mrb_file_is_absolute_path(home)) {
+      mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home");
+    }
+  } else {
+    return mrb_nil_value();
+  }
+  home = mrb_locale_from_utf8(home, -1);
+  path = mrb_str_new_cstr(mrb, home);
+  mrb_locale_free(home);
+  return path;
+#endif
+}
+
+static mrb_value
+mrb_file_mtime(mrb_state *mrb, mrb_value self)
+{
+  mrb_value obj;
+  struct stat st;
+  int fd;
+
+  obj = mrb_obj_value(mrb_class_get(mrb, "Time"));
+  fd = mrb_io_fileno(mrb, self);
+  if (fstat(fd, &st) == -1)
+    return mrb_false_value();
+  return mrb_funcall(mrb, obj, "at", 1, mrb_fixnum_value(st.st_mtime));
+}
+
+mrb_value
+mrb_file_flock(mrb_state *mrb, mrb_value self)
+{
+#if defined(sun)
+  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_io_fileno(mrb, self);
+
+  while (flock(fd, (int)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_size(mrb_state *mrb, mrb_value self)
+{
+  mrb_stat st;
+  int fd;
+
+  fd = mrb_io_fileno(mrb, self);
+  if (mrb_fstat(fd, &st) == -1) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "fstat failed");
+  }
+
+  if (st.st_size > MRB_INT_MAX) {
+#ifdef MRB_WITHOUT_FLOAT
+    mrb_raise(mrb, E_RUNTIME_ERROR, "File#size too large for MRB_WITHOUT_FLOAT");
+#else
+    return mrb_float_value(mrb, (mrb_float)st.st_size);
+#endif
+  }
+
+  return mrb_fixnum_value((mrb_int)st.st_size);
+}
+
+static int
+mrb_ftruncate(int fd, int64_t length)
+{
+#ifndef _WIN32
+  return ftruncate(fd, (off_t)length);
+#else
+  HANDLE file;
+  __int64 cur;
+
+  file = (HANDLE)_get_osfhandle(fd);
+  if (file == INVALID_HANDLE_VALUE) {
+    return -1;
+  }
+
+  cur = _lseeki64(fd, 0, SEEK_CUR);
+  if (cur == -1) return -1;
+
+  if (_lseeki64(fd, (__int64)length, SEEK_SET) == -1) return -1;
+
+  if (!SetEndOfFile(file)) {
+    errno = EINVAL; /* TODO: GetLastError to errno */
+    return -1;
+  }
+
+  if (_lseeki64(fd, cur, SEEK_SET) == -1) return -1;
+
+  return 0;
+#endif /* _WIN32 */
+}
+
+static mrb_value
+mrb_file_truncate(mrb_state *mrb, mrb_value self)
+{
+  int fd;
+  int64_t length;
+  mrb_value lenv;
+
+  fd = mrb_io_fileno(mrb, self);
+  mrb_get_args(mrb, "o", &lenv);
+  switch (mrb_type(lenv)) {
+#ifndef MRB_WITHOUT_FLOAT
+    case MRB_TT_FLOAT:
+      {
+        mrb_float lenf = mrb_float(lenv);
+        if (lenf > INT64_MAX) {
+          mrb_raise(mrb, E_ARGUMENT_ERROR, "length too large");
+        }
+        length = (int64_t)lenf;
+      }
+      break;
+#endif
+    case MRB_TT_FIXNUM:
+    default:
+      {
+        mrb_int leni = mrb_int(mrb, lenv);
+        length = (int64_t)leni;
+      }
+      break;
+  }
+
+  if (mrb_ftruncate(fd, length) != 0) {
+    mrb_raise(mrb, E_IO_ERROR, "ftruncate failed");
+  }
+
+  return mrb_fixnum_value(0);
+}
+
+static mrb_value
+mrb_file_s_symlink(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
+  mrb_value from, to;
+  const char *src, *dst;
+  int ai = mrb_gc_arena_save(mrb);
+
+  mrb_get_args(mrb, "SS", &from, &to);
+  src = mrb_locale_from_utf8(RSTRING_CSTR(mrb, from), -1);
+  dst = mrb_locale_from_utf8(RSTRING_CSTR(mrb, to), -1);
+  if (symlink(src, dst) == -1) {
+    mrb_locale_free(src);
+    mrb_locale_free(dst);
+    mrb_sys_fail(mrb, RSTRING_CSTR(mrb, mrb_format(mrb, "(%v, %v)", from, to)));
+  }
+  mrb_locale_free(src);
+  mrb_locale_free(dst);
+  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++) {
+    const char *utf8_path = RSTRING_CSTR(mrb, filenames[i]);
+    char *path = mrb_locale_from_utf8(utf8_path, -1);
+    if (CHMOD(path, mode) == -1) {
+      mrb_locale_free(path);
+      mrb_sys_fail(mrb, utf8_path);
+    }
+    mrb_locale_free(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)
+  mrb_raise(mrb, E_NOTIMP_ERROR, "readlink is not supported on this platform");
+  return mrb_nil_value(); // unreachable
+#else
+  char *path, *buf, *tmp;
+  size_t bufsize = 100;
+  ssize_t rc;
+  mrb_value ret;
+  int ai = mrb_gc_arena_save(mrb);
+
+  mrb_get_args(mrb, "z", &path);
+  tmp = mrb_locale_from_utf8(path, -1);
+
+  buf = (char *)mrb_malloc(mrb, bufsize);
+  while ((rc = readlink(tmp, buf, bufsize)) == (ssize_t)bufsize && rc != -1) {
+    bufsize *= 2;
+    buf = (char *)mrb_realloc(mrb, buf, bufsize);
+  }
+  mrb_locale_free(tmp);
+  if (rc == -1) {
+    mrb_free(mrb, buf);
+    mrb_sys_fail(mrb, path);
+  }
+  tmp = mrb_utf8_from_locale(buf, -1);
+  ret = mrb_str_new(mrb, tmp, rc);
+  mrb_locale_free(tmp);
+  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_OPT(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));
+  mrb_define_method(mrb, file, "mtime", mrb_file_mtime, MRB_ARGS_NONE());
+  mrb_define_method(mrb, file, "size", mrb_file_size, MRB_ARGS_NONE());
+  mrb_define_method(mrb, file, "truncate", mrb_file_truncate, 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));
+
+  mrb_define_const(mrb, cnst, "RDONLY", mrb_fixnum_value(MRB_O_RDONLY));
+  mrb_define_const(mrb, cnst, "WRONLY", mrb_fixnum_value(MRB_O_WRONLY));
+  mrb_define_const(mrb, cnst, "RDWR", mrb_fixnum_value(MRB_O_RDWR));
+  mrb_define_const(mrb, cnst, "APPEND", mrb_fixnum_value(MRB_O_APPEND));
+  mrb_define_const(mrb, cnst, "CREAT", mrb_fixnum_value(MRB_O_CREAT));
+  mrb_define_const(mrb, cnst, "EXCL", mrb_fixnum_value(MRB_O_EXCL));
+  mrb_define_const(mrb, cnst, "TRUNC", mrb_fixnum_value(MRB_O_TRUNC));
+  mrb_define_const(mrb, cnst, "NONBLOCK", mrb_fixnum_value(MRB_O_NONBLOCK));
+  mrb_define_const(mrb, cnst, "NOCTTY", mrb_fixnum_value(MRB_O_NOCTTY));
+  mrb_define_const(mrb, cnst, "BINARY", mrb_fixnum_value(MRB_O_BINARY));
+  mrb_define_const(mrb, cnst, "SHARE_DELETE", mrb_fixnum_value(MRB_O_SHARE_DELETE));
+  mrb_define_const(mrb, cnst, "SYNC", mrb_fixnum_value(MRB_O_SYNC));
+  mrb_define_const(mrb, cnst, "DSYNC", mrb_fixnum_value(MRB_O_DSYNC));
+  mrb_define_const(mrb, cnst, "RSYNC", mrb_fixnum_value(MRB_O_RSYNC));
+  mrb_define_const(mrb, cnst, "NOFOLLOW", mrb_fixnum_value(MRB_O_NOFOLLOW));
+  mrb_define_const(mrb, cnst, "NOATIME", mrb_fixnum_value(MRB_O_NOATIME));
+  mrb_define_const(mrb, cnst, "DIRECT", mrb_fixnum_value(MRB_O_DIRECT));
+  mrb_define_const(mrb, cnst, "TMPFILE", mrb_fixnum_value(MRB_O_TMPFILE));
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/file_test.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/file_test.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/file_test.c	(revision 439)
@@ -0,0 +1,383 @@
+/*
+** file_test.c - FileTest class
+*/
+
+#include "mruby.h"
+#include "mruby/class.h"
+#include "mruby/data.h"
+#include "mruby/string.h"
+#include "mruby/ext/io.h"
+#include "mruby/error.h"
+
+#include <sys/types.h>
+#if !defined(AZURE_SPHERE)
+#include <sys/stat.h>
+#endif
+
+#if defined(_WIN32) || defined(_WIN64)
+  #define LSTAT stat
+  #include <winsock.h>
+#elif defined(AZURE_SPHERE)
+  #define LSTAT lstat
+  #include <sys/param.h>
+  #include <unistd.h>
+  #include <time.h>
+
+struct stat {
+  mode_t st_mode;
+  struct timespec st_mtim;
+  off_t st_size;
+};
+#define S_IFMT  0170000
+#define S_IFDIR 0040000
+#define S_IFREG 0100000
+int stat(const char *__restrict, struct stat *__restrict);
+int fstat(int, struct stat *);
+int lstat(const char *__restrict, struct stat *__restrict);
+#else
+  #define LSTAT lstat
+  #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 <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)
+{
+  if (mrb_obj_is_kind_of(mrb, obj, mrb_class_get(mrb, "IO"))) {
+    struct mrb_io *fptr;
+    fptr = (struct mrb_io *)mrb_data_get_ptr(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;
+  }
+  else {
+    char *path = mrb_locale_from_utf8(RSTRING_CSTR(mrb, obj), -1);
+    int ret;
+    if (do_lstat) {
+      ret = LSTAT(path, st);
+    } else {
+      ret = stat(path, st);
+    }
+    mrb_locale_free(path);
+    return ret;
+  }
+}
+
+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/mruby-2.1.1/mrbgems/mruby-io/src/io.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/io.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/io.c	(revision 439)
@@ -0,0 +1,1550 @@
+/*
+** 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"
+#include "mruby/error.h"
+
+#if defined(AZURE_SPHERE)
+#define _GNU_SOURCE
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#if !defined(AZURE_SPHERE)
+#include <sys/stat.h>
+#endif
+
+#if defined(_WIN32) || defined(_WIN64)
+  #include <winsock.h>
+  #include <io.h>
+  #define open  _open
+  #define close _close
+  #define dup _dup
+  #define dup2 _dup2
+  #define read  _read
+  #define write _write
+  #define lseek _lseek
+  #define isatty _isatty
+  #define WEXITSTATUS(x) (x)
+  typedef int fsize_t;
+#ifdef _WIN64
+  typedef signed __int64    ssize_t;
+#else  /* _WIN64 */
+  typedef signed int        ssize_t;
+#endif  /* _WIN64 */
+  typedef long ftime_t;
+  typedef long fsuseconds_t;
+  typedef int fmode_t;
+  typedef int mrb_io_read_write_size;
+
+  #ifndef O_TMPFILE
+    #define O_TMPFILE O_TEMPORARY
+  #endif
+
+#else
+#if !defined(AZURE_SPHERE)
+  #include <sys/wait.h>
+#endif
+  #include <unistd.h>
+  typedef size_t fsize_t;
+  typedef time_t ftime_t;
+  typedef suseconds_t fsuseconds_t;
+  typedef mode_t fmode_t;
+  typedef ssize_t mrb_io_read_write_size;
+#endif
+
+#ifdef _MSC_VER
+typedef mrb_int pid_t;
+#endif
+
+#include <fcntl.h>
+
+#include <errno.h>
+#include <string.h>
+
+#if defined(AZURE_SPHERE)
+pid_t fork(void);
+int execl(const char *, const char *, ...);
+_Noreturn void _exit(int);
+int isatty(int);
+int open(const char *, int, ...);
+#define O_RDONLY  00
+#define O_WRONLY  01
+#define O_RDWR    02
+#define O_CREAT        0100
+#define O_EXCL         0200
+#define O_TRUNC       01000
+#define O_APPEND      02000
+
+pid_t waitpid(pid_t pid, int *status, int options);
+#endif
+
+#define OPEN_ACCESS_MODE_FLAGS (O_RDONLY | O_WRONLY | O_RDWR)
+#define OPEN_RDONLY_P(f)       ((mrb_bool)(((f) & OPEN_ACCESS_MODE_FLAGS) == O_RDONLY))
+#define OPEN_WRONLY_P(f)       ((mrb_bool)(((f) & OPEN_ACCESS_MODE_FLAGS) == O_WRONLY))
+#define OPEN_RDWR_P(f)         ((mrb_bool)(((f) & OPEN_ACCESS_MODE_FLAGS) == O_RDWR))
+#define OPEN_READABLE_P(f)     ((mrb_bool)(OPEN_RDONLY_P(f) || OPEN_RDWR_P(f)))
+#define OPEN_WRITABLE_P(f)     ((mrb_bool)(OPEN_WRONLY_P(f) || OPEN_RDWR_P(f)))
+
+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_mode_to_flags(mrb_state *mrb, mrb_value mode);
+static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet);
+
+static struct mrb_io *
+io_get_open_fptr(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_io *fptr;
+
+  fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, self, &mrb_io_type);
+  if (fptr == NULL) {
+    mrb_raise(mrb, E_IO_ERROR, "uninitialized stream.");
+  }
+  if (fptr->fd < 0) {
+    mrb_raise(mrb, E_IO_ERROR, "closed stream.");
+  }
+  return fptr;
+}
+
+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);
+}
+
+static int
+mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode)
+{
+  int flags;
+  const char *m = mode;
+
+  switch (*m++) {
+    case 'r':
+      flags = O_RDONLY;
+      break;
+    case 'w':
+      flags = O_WRONLY | O_CREAT | O_TRUNC;
+      break;
+    case 'a':
+      flags = O_WRONLY | O_CREAT | O_APPEND;
+      break;
+    default:
+      mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %s", mode);
+      flags = 0; /* not reached */
+  }
+
+  while (*m) {
+    switch (*m++) {
+      case 'b':
+#ifdef O_BINARY
+        flags |= O_BINARY;
+#endif
+        break;
+      case '+':
+        flags = (flags & ~OPEN_ACCESS_MODE_FLAGS) | O_RDWR;
+        break;
+      case ':':
+        /* XXX: PASSTHROUGH*/
+      default:
+        mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %s", mode);
+    }
+  }
+
+  return flags;
+}
+
+static int
+mrb_io_mode_to_flags(mrb_state *mrb, mrb_value mode)
+{
+  if (mrb_nil_p(mode)) {
+    return mrb_io_modestr_to_flags(mrb, "r");
+  }
+  else if (mrb_string_p(mode)) {
+    return mrb_io_modestr_to_flags(mrb, RSTRING_CSTR(mrb, mode));
+  }
+  else {
+    int flags = 0;
+    mrb_int flags0 = mrb_int(mrb, mode);
+
+    switch (flags0 & MRB_O_ACCMODE) {
+      case MRB_O_RDONLY:
+        flags |= O_RDONLY;
+        break;
+      case MRB_O_WRONLY:
+        flags |= O_WRONLY;
+        break;
+      case MRB_O_RDWR:
+        flags |= O_RDWR;
+        break;
+      default:
+        mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %v", mode);
+    }
+
+    if (flags0 & MRB_O_APPEND)        flags |= O_APPEND;
+    if (flags0 & MRB_O_CREAT)         flags |= O_CREAT;
+    if (flags0 & MRB_O_EXCL)          flags |= O_EXCL;
+    if (flags0 & MRB_O_TRUNC)         flags |= O_TRUNC;
+#ifdef O_NONBLOCK
+    if (flags0 & MRB_O_NONBLOCK)      flags |= O_NONBLOCK;
+#endif
+#ifdef O_NOCTTY
+    if (flags0 & MRB_O_NOCTTY)        flags |= O_NOCTTY;
+#endif
+#ifdef O_BINARY
+    if (flags0 & MRB_O_BINARY)        flags |= O_BINARY;
+#endif
+#ifdef O_SHARE_DELETE
+    if (flags0 & MRB_O_SHARE_DELETE)  flags |= O_SHARE_DELETE;
+#endif
+#ifdef O_SYNC
+    if (flags0 & MRB_O_SYNC)          flags |= O_SYNC;
+#endif
+#ifdef O_DSYNC
+    if (flags0 & MRB_O_DSYNC)         flags |= O_DSYNC;
+#endif
+#ifdef O_RSYNC
+    if (flags0 & MRB_O_RSYNC)         flags |= O_RSYNC;
+#endif
+#ifdef O_NOFOLLOW
+    if (flags0 & MRB_O_NOFOLLOW)      flags |= O_NOFOLLOW;
+#endif
+#ifdef O_NOATIME
+    if (flags0 & MRB_O_NOATIME)       flags |= O_NOATIME;
+#endif
+#ifdef O_DIRECT
+    if (flags0 & MRB_O_DIRECT)        flags |= O_DIRECT;
+#endif
+#ifdef O_TMPFILE
+    if (flags0 & MRB_O_TMPFILE)       flags |= O_TMPFILE;
+#endif
+
+    return flags;
+  }
+}
+
+static 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_bug(mrb, "mrb_fd_cloexec: fcntl(%d, F_GETFD) failed: %d", fd, errno);
+  }
+  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_bug(mrb, "mrb_fd_cloexec: fcntl(%d, F_SETFD, %d) failed: %d", fd, flags2, errno);
+    }
+  }
+#endif
+}
+
+#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
+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;
+  fptr->is_socket = 0;
+  return fptr;
+}
+
+#ifndef NOFILE
+#define NOFILE 64
+#endif
+
+static int
+option_to_fd(mrb_state *mrb, mrb_value hash, const char *key)
+{
+  mrb_value opt;
+
+  if (!mrb_hash_p(hash)) return -1;
+  opt = mrb_hash_fetch(mrb, hash, mrb_symbol_value(mrb_intern_static(mrb, key, strlen(key))), mrb_nil_value());
+  if (mrb_nil_p(opt)) return -1;
+
+  switch (mrb_type(opt)) {
+    case MRB_TT_DATA: /* IO */
+      return mrb_io_fileno(mrb, opt);
+    case MRB_TT_FIXNUM:
+      return (int)mrb_fixnum(opt);
+    default:
+      mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong exec redirect action");
+      break;
+  }
+  return -1; /* never reached */
+}
+
+#ifdef _WIN32
+mrb_value
+mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value cmd, io;
+  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 = 0, flags;
+  STARTUPINFO si;
+  PROCESS_INFORMATION pi;
+  SECURITY_ATTRIBUTES saAttr;
+
+  HANDLE ifd[2];
+  HANDLE ofd[2];
+
+  int doexec;
+  int opt_in, opt_out, opt_err;
+
+  ifd[0] = INVALID_HANDLE_VALUE;
+  ifd[1] = INVALID_HANDLE_VALUE;
+  ofd[0] = INVALID_HANDLE_VALUE;
+  ofd[1] = INVALID_HANDLE_VALUE;
+
+  mrb_get_args(mrb, "S|oH", &cmd, &mode, &opt);
+  io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
+
+  pname = RSTRING_CSTR(mrb, cmd);
+  flags = mrb_io_mode_to_flags(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");
+
+  saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+  saAttr.bInheritHandle = TRUE;
+  saAttr.lpSecurityDescriptor = NULL;
+
+  if (OPEN_READABLE_P(flags)) {
+    if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
+        || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) {
+      mrb_sys_fail(mrb, "pipe");
+    }
+  }
+
+  if (OPEN_WRITABLE_P(flags)) {
+    if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
+        || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) {
+      mrb_sys_fail(mrb, "pipe");
+    }
+  }
+
+  if (doexec) {
+    ZeroMemory(&pi, sizeof(pi));
+    ZeroMemory(&si, sizeof(si));
+    si.cb = sizeof(si);
+    si.dwFlags |= STARTF_USESHOWWINDOW;
+    si.wShowWindow = SW_HIDE;
+    si.dwFlags |= STARTF_USESTDHANDLES;
+    if (OPEN_READABLE_P(flags)) {
+      si.hStdOutput = ofd[1];
+      si.hStdError = ofd[1];
+    }
+    if (OPEN_WRITABLE_P(flags)) {
+      si.hStdInput = ifd[0];
+    }
+    if (!CreateProcess(
+        NULL, (char*)pname, NULL, NULL,
+        TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) {
+      CloseHandle(ifd[0]);
+      CloseHandle(ifd[1]);
+      CloseHandle(ofd[0]);
+      CloseHandle(ofd[1]);
+      mrb_raisef(mrb, E_IO_ERROR, "command not found: %v", cmd);
+    }
+    CloseHandle(pi.hThread);
+    CloseHandle(ifd[0]);
+    CloseHandle(ofd[1]);
+    pid = pi.dwProcessId;
+  }
+
+  mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
+
+  fptr = mrb_io_alloc(mrb);
+  fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0);
+  fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0);
+  fptr->pid = pid;
+  fptr->readable = OPEN_READABLE_P(flags);
+  fptr->writable = OPEN_WRITABLE_P(flags);
+  fptr->sync = 0;
+
+  DATA_TYPE(io) = &mrb_io_type;
+  DATA_PTR(io)  = fptr;
+  return io;
+}
+#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+mrb_value
+mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
+{
+  mrb_raise(mrb, E_NOTIMP_ERROR, "IO#popen is not supported on the platform");
+  return mrb_false_value();
+}
+#else
+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|oH", &cmd, &mode, &opt);
+  io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
+
+  pname = RSTRING_CSTR(mrb, cmd);
+  flags = mrb_io_mode_to_flags(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 (OPEN_READABLE_P(flags)) {
+    if (pipe(pr) == -1) {
+      mrb_sys_fail(mrb, "pipe");
+    }
+    mrb_fd_cloexec(mrb, pr[0]);
+    mrb_fd_cloexec(mrb, pr[1]);
+  }
+
+  if (OPEN_WRITABLE_P(flags)) {
+    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 (OPEN_READABLE_P(flags)) {
+        close(pr[0]);
+        if (pr[1] != 1) {
+          dup2(pr[1], 1);
+          close(pr[1]);
+        }
+      }
+      if (OPEN_WRITABLE_P(flags)) {
+        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: %v", cmd);
+        _exit(127);
+      }
+      result = mrb_nil_value();
+      break;
+
+    default: /* parent */
+      if (OPEN_RDWR_P(flags)) {
+        close(pr[1]);
+        fd = pr[0];
+        close(pw[0]);
+        write_fd = pw[1];
+      } else if (OPEN_RDONLY_P(flags)) {
+        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, ""));
+
+      fptr = mrb_io_alloc(mrb);
+      fptr->fd = fd;
+      fptr->fd2 = write_fd;
+      fptr->pid = pid;
+      fptr->readable = OPEN_READABLE_P(flags);
+      fptr->writable = OPEN_WRITABLE_P(flags);
+      fptr->sync = 0;
+
+      DATA_TYPE(io) = &mrb_io_type;
+      DATA_PTR(io)  = fptr;
+      result = io;
+      break;
+
+    case -1: /* error */
+      saved_errno = errno;
+      if (OPEN_READABLE_P(flags)) {
+        close(pr[0]);
+        close(pr[1]);
+      }
+      if (OPEN_WRITABLE_P(flags)) {
+        close(pw[0]);
+        close(pw[1]);
+      }
+      errno = saved_errno;
+      mrb_sys_fail(mrb, "pipe_open failed.");
+      break;
+  }
+  return result;
+}
+#endif
+
+static int
+mrb_dup(mrb_state *mrb, int fd, mrb_bool *failed)
+{
+  int new_fd;
+
+  *failed = TRUE;
+  if (fd < 0)
+    return fd;
+
+  new_fd = dup(fd);
+  if (new_fd > 0) *failed = FALSE;
+  return new_fd;
+}
+
+mrb_value
+mrb_io_initialize_copy(mrb_state *mrb, mrb_value copy)
+{
+  mrb_value orig;
+  mrb_value buf;
+  struct mrb_io *fptr_copy;
+  struct mrb_io *fptr_orig;
+  mrb_bool failed = TRUE;
+
+  mrb_get_args(mrb, "o", &orig);
+  fptr_orig = io_get_open_fptr(mrb, orig);
+  fptr_copy = (struct mrb_io *)DATA_PTR(copy);
+  if (fptr_orig == fptr_copy) return copy;
+  if (fptr_copy != NULL) {
+    fptr_finalize(mrb, fptr_copy, FALSE);
+    mrb_free(mrb, fptr_copy);
+  }
+  fptr_copy = (struct mrb_io *)mrb_io_alloc(mrb);
+
+  DATA_TYPE(copy) = &mrb_io_type;
+  DATA_PTR(copy) = fptr_copy;
+
+  buf = mrb_iv_get(mrb, orig, mrb_intern_cstr(mrb, "@buf"));
+  mrb_iv_set(mrb, copy, mrb_intern_cstr(mrb, "@buf"), buf);
+
+  fptr_copy->fd = mrb_dup(mrb, fptr_orig->fd, &failed);
+  if (failed) {
+    mrb_sys_fail(mrb, 0);
+  }
+  mrb_fd_cloexec(mrb, fptr_copy->fd);
+
+  if (fptr_orig->fd2 != -1) {
+    fptr_copy->fd2 = mrb_dup(mrb, fptr_orig->fd2, &failed);
+    if (failed) {
+      close(fptr_copy->fd);
+      mrb_sys_fail(mrb, 0);
+    }
+    mrb_fd_cloexec(mrb, fptr_copy->fd2);
+  }
+
+  fptr_copy->pid = fptr_orig->pid;
+  fptr_copy->readable = fptr_orig->readable;
+  fptr_copy->writable = fptr_orig->writable;
+  fptr_copy->sync = fptr_orig->sync;
+  fptr_copy->is_socket = fptr_orig->is_socket;
+
+  return copy;
+}
+
+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|oo", &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_mode_to_flags(mrb, mode);
+
+  mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
+
+  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 = (int)fd;
+  fptr->readable = OPEN_READABLE_P(flags);
+  fptr->writable = OPEN_WRITABLE_P(flags);
+  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) {
+#ifdef _WIN32
+    if (fptr->is_socket) {
+      if (closesocket(fptr->fd) != 0) {
+        saved_errno = WSAGetLastError();
+      }
+      fptr->fd = -1;
+    }
+#endif
+    if (fptr->fd != -1) {
+      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 (fptr->pid != 0) {
+#if !defined(_WIN32) && !defined(_WIN64)
+    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);
+    }
+#else
+    HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid);
+    DWORD status;
+    if (WaitForSingleObject(h, INFINITE) && GetExitCodeProcess(h, &status))
+      if (!quiet)
+        io_set_process_status(mrb, fptr->pid, (int)status);
+    CloseHandle(h);
+#endif
+    fptr->pid = 0;
+    /* Note: we don't raise an exception when waitpid(3) fails */
+  }
+
+  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((int)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;
+  char* fname = mrb_locale_from_utf8(pathname, -1);
+
+#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(fname, (int)flags, (fmode_t)mode);
+  if (fd == -1) {
+    if (!retry) {
+      switch (errno) {
+        case ENFILE:
+        case EMFILE:
+        mrb_garbage_collect(mrb);
+        retry = TRUE;
+        goto reopen;
+      }
+    }
+
+    mrb_sys_fail(mrb, RSTRING_CSTR(mrb, mrb_format(mrb, "open %s", pathname)));
+  }
+  mrb_locale_free(fname);
+
+  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, perm = -1;
+  const char *pat;
+  int flags;
+
+  mrb_get_args(mrb, "S|oi", &path, &mode, &perm);
+  if (perm < 0) {
+    perm = 0666;
+  }
+
+  pat = RSTRING_CSTR(mrb, path);
+  flags = mrb_io_mode_to_flags(mrb, mode);
+  fd = mrb_cloexec_open(mrb, pat, flags, perm);
+  return mrb_fixnum_value(fd);
+}
+
+static mrb_value mrb_io_sysread_common(mrb_state *mrb,
+    mrb_io_read_write_size (*readfunc)(int, void *, fsize_t, off_t),
+    mrb_value io, mrb_value buf, mrb_int maxlen, off_t offset);
+
+static mrb_io_read_write_size
+mrb_sysread_dummy(int fd, void *buf, fsize_t nbytes, off_t offset)
+{
+  return (mrb_io_read_write_size)read(fd, buf, nbytes);
+}
+
+mrb_value
+mrb_io_sysread(mrb_state *mrb, mrb_value io)
+{
+  mrb_value buf = mrb_nil_value();
+  mrb_int maxlen;
+
+  mrb_get_args(mrb, "i|S", &maxlen, &buf);
+
+  return mrb_io_sysread_common(mrb, mrb_sysread_dummy, io, buf, maxlen, 0);
+}
+
+static mrb_value
+mrb_io_sysread_common(mrb_state *mrb,
+    mrb_io_read_write_size (*readfunc)(int, void *, fsize_t, off_t),
+    mrb_value io, mrb_value buf, mrb_int maxlen, off_t offset)
+{
+  struct mrb_io *fptr;
+  int ret;
+
+  if (maxlen < 0) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "negative expanding string size");
+  }
+  else if (maxlen == 0) {
+    return mrb_str_new(mrb, NULL, maxlen);
+  }
+
+  if (mrb_nil_p(buf)) {
+    buf = mrb_str_new(mrb, NULL, maxlen);
+  }
+
+  if (RSTRING_LEN(buf) != maxlen) {
+    buf = mrb_str_resize(mrb, buf, maxlen);
+  }
+  else {
+    mrb_str_modify(mrb, RSTRING(buf));
+  }
+
+  fptr = (struct mrb_io *)io_get_open_fptr(mrb, io);
+  if (!fptr->readable) {
+    mrb_raise(mrb, E_IO_ERROR, "not opened for reading");
+  }
+  ret = readfunc(fptr->fd, RSTRING_PTR(buf), (fsize_t)maxlen, offset);
+  if (ret < 0) {
+    mrb_sys_fail(mrb, "sysread failed");
+  }
+  if (RSTRING_LEN(buf) != ret) {
+    buf = mrb_str_resize(mrb, buf, ret);
+  }
+  if (ret == 0 && maxlen > 0) {
+    mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File");
+  }
+  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 = io_get_open_fptr(mrb, io);
+  pos = lseek(fptr->fd, (off_t)offset, (int)whence);
+  if (pos == -1) {
+    mrb_sys_fail(mrb, "sysseek");
+  }
+  if (pos > MRB_INT_MAX) {
+#ifndef MRB_WITHOUT_FLOAT
+    return mrb_float_value(mrb, (mrb_float)pos);
+#else
+    mrb_raise(mrb, E_IO_ERROR, "sysseek reached too far for MRB_WITHOUT_FLOAT");
+#endif
+  } else {
+    return mrb_fixnum_value(pos);
+  }
+}
+
+static mrb_value
+mrb_io_syswrite_common(mrb_state *mrb,
+    mrb_io_read_write_size (*writefunc)(int, const void *, fsize_t, off_t),
+    mrb_value io, mrb_value buf, off_t offset)
+{
+  struct mrb_io *fptr;
+  int fd, length;
+
+  fptr = io_get_open_fptr(mrb, io);
+  if (! fptr->writable) {
+    mrb_raise(mrb, E_IO_ERROR, "not opened for writing");
+  }
+
+  if (fptr->fd2 == -1) {
+    fd = fptr->fd;
+  } else {
+    fd = fptr->fd2;
+  }
+  length = writefunc(fd, RSTRING_PTR(buf), (fsize_t)RSTRING_LEN(buf), offset);
+  if (length == -1) {
+    mrb_sys_fail(mrb, 0);
+  }
+
+  return mrb_fixnum_value(length);
+}
+
+static mrb_io_read_write_size
+mrb_syswrite_dummy(int fd, const void *buf, fsize_t nbytes, off_t offset)
+{
+  return (mrb_io_read_write_size)write(fd, buf, nbytes);
+}
+
+mrb_value
+mrb_io_syswrite(mrb_state *mrb, mrb_value io)
+{
+  mrb_value buf;
+
+  mrb_get_args(mrb, "S", &buf);
+
+  return mrb_io_syswrite_common(mrb, mrb_syswrite_dummy, io, buf, 0);
+}
+
+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_close_write(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_io *fptr;
+  fptr = io_get_open_fptr(mrb, self);
+  if (close((int)fptr->fd2) == -1) {
+    mrb_sys_fail(mrb, "close");
+  }
+  return mrb_nil_value();
+}
+
+mrb_value
+mrb_io_closed(mrb_state *mrb, mrb_value io)
+{
+  struct mrb_io *fptr;
+  fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, io, &mrb_io_type);
+  if (fptr == NULL || 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 = io_get_open_fptr(mrb, io);
+
+  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 = (ftime_t)mrb_fixnum(time);
+      t.tv_usec = 0;
+      break;
+
+#ifndef MRB_WITHOUT_FLOAT
+    case MRB_TT_FLOAT:
+      t.tv_sec = (ftime_t)mrb_float(time);
+      t.tv_usec = (fsuseconds_t)((mrb_float(time) - t.tv_sec) * 1000000.0);
+      break;
+#endif
+
+    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_string_p(buf) && RSTRING_LEN(buf) > 0) {
+    return 1;
+  }
+  return 0;
+}
+
+#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
+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, ""));
+  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, ""));
+  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_argnum_error(mrb, argc, 1, 4);
+  }
+
+  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 = io_get_open_fptr(mrb, read_io);
+      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 = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]);
+      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 = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]);
+      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 = io_get_open_fptr(mrb, RARRAY_PTR(read)[i]);
+        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 = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]);
+        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 = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]);
+        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;
+}
+
+int
+mrb_io_fileno(mrb_state *mrb, mrb_value io)
+{
+  struct mrb_io *fptr;
+  fptr = io_get_open_fptr(mrb, io);
+  return fptr->fd;
+}
+
+static mrb_value
+mrb_io_fileno_m(mrb_state *mrb, mrb_value io)
+{
+  int fd = mrb_io_fileno(mrb, io);
+  return mrb_fixnum_value(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);
+}
+
+#ifndef MRB_WITH_IO_PREAD_PWRITE
+# define mrb_io_pread   mrb_notimplement_m
+# define mrb_io_pwrite  mrb_notimplement_m
+#else
+static off_t
+value2off(mrb_state *mrb, mrb_value offv)
+{
+  switch (mrb_type(offv)) {
+#ifndef MRB_WITHOUT_FLOAT
+    case MRB_TT_FLOAT:
+      {
+        mrb_float tmp = mrb_float(offv);
+        if (tmp < INT64_MIN || tmp > INT64_MAX) {
+          /* fall through to use convert by `mrb_int()` (and raise error if out of range) */
+        } else {
+          return (off_t)tmp;
+        }
+      }
+      /* fall through */
+#endif /* MRB_WITHOUT_FLOAT */
+    default:
+      return (off_t)mrb_int(mrb, offv);
+  }
+}
+
+/*
+ * call-seq:
+ *  pread(maxlen, offset, outbuf = "") -> outbuf
+ */
+static mrb_value
+mrb_io_pread(mrb_state *mrb, mrb_value io)
+{
+  mrb_value buf = mrb_nil_value();
+  mrb_value off;
+  mrb_int maxlen;
+
+  mrb_get_args(mrb, "io|S!", &maxlen, &off, &buf);
+
+  return mrb_io_sysread_common(mrb, pread, io, buf, maxlen, value2off(mrb, off));
+}
+
+/*
+ * call-seq:
+ *  pwrite(buffer, offset) -> wrote_bytes
+ */
+static mrb_value
+mrb_io_pwrite(mrb_state *mrb, mrb_value io)
+{
+  mrb_value buf, off;
+
+  mrb_get_args(mrb, "So", &buf, &off);
+
+  return mrb_io_syswrite_common(mrb, pwrite, io, buf, value2off(mrb, off));
+}
+#endif /* MRB_WITH_IO_PREAD_PWRITE */
+
+static mrb_value
+io_bufread(mrb_state *mrb, mrb_value str, mrb_int len)
+{
+  mrb_value str2;
+  mrb_int newlen;
+  struct RString *s;
+  char *p;
+
+  s = RSTRING(str);
+  mrb_str_modify(mrb, s);
+  p = RSTR_PTR(s);
+  str2 = mrb_str_new(mrb, p, len);
+  newlen = RSTR_LEN(s)-len;
+  memmove(p, p+len, newlen);
+  p[newlen] = '\0';
+  RSTR_SET_LEN(s, newlen);
+
+  return str2;
+}
+
+static mrb_value
+mrb_io_bufread(mrb_state *mrb, mrb_value self)
+{
+  mrb_value str;
+  mrb_int len;
+
+  mrb_get_args(mrb, "Si", &str, &len);
+  return io_bufread(mrb, str, len);
+}
+
+static mrb_value
+mrb_io_readchar(mrb_state *mrb, mrb_value self)
+{
+  mrb_value buf;
+  mrb_int len = 1;
+#ifdef MRB_UTF8_STRING
+  unsigned char c;
+#endif
+
+  mrb_get_args(mrb, "S", &buf);
+  mrb_assert(RSTRING_PTR(buf) > 0);
+  mrb_str_modify(mrb, RSTRING(buf));
+#ifdef MRB_UTF8_STRING
+  c = RSTRING_PTR(buf)[0];
+  if (c & 0x80) {
+    len = mrb_utf8len(RSTRING_PTR(buf), RSTRING_END(buf));
+    if (len == 1 && RSTRING_LEN(buf) < 4) { /* partial UTF-8 */
+      mrb_int blen = RSTRING_LEN(buf);
+      ssize_t n;
+
+      struct mrb_io *fptr = (struct mrb_io*)io_get_open_fptr(mrb, self);
+
+      if (!fptr->readable) {
+        mrb_raise(mrb, E_IO_ERROR, "not opened for reading");
+      }
+      /* refill the buffer */
+      mrb_str_resize(mrb, buf, 4096);
+      n = read(fptr->fd, RSTRING_PTR(buf)+blen, 4096-blen);
+      if (n < 0) mrb_sys_fail(mrb, "sysread failed");
+      mrb_str_resize(mrb, buf, blen+n);
+    }
+    len = mrb_utf8len(RSTRING_PTR(buf), RSTRING_END(buf));
+  }
+#endif
+  return io_bufread(mrb, buf, len);
+}
+
+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 */
+  mrb_define_class_method(mrb, io, "_popen",  mrb_io_s_popen,   MRB_ARGS_ARG(1,2));
+  mrb_define_class_method(mrb, io, "_sysclose",  mrb_io_s_sysclose, MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, io, "for_fd",  mrb_io_s_for_fd,   MRB_ARGS_ARG(1,2));
+  mrb_define_class_method(mrb, io, "select",  mrb_io_s_select,  MRB_ARGS_ARG(1,3));
+  mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ARG(1,2));
+#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
+  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_ARG(1,2));    /* 15.2.20.5.21 (x)*/
+  mrb_define_method(mrb, io, "initialize_copy", mrb_io_initialize_copy, MRB_ARGS_REQ(1));
+  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_ARG(1,1));
+  mrb_define_method(mrb, io, "sysseek",    mrb_io_sysseek,    MRB_ARGS_ARG(1,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_write",    mrb_io_close_write,       MRB_ARGS_NONE());
+  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_m,   MRB_ARGS_NONE());
+  mrb_define_method(mrb, io, "pread",      mrb_io_pread,      MRB_ARGS_ANY());    /* ruby 2.5 feature */
+  mrb_define_method(mrb, io, "pwrite",     mrb_io_pwrite,     MRB_ARGS_ANY());    /* ruby 2.5 feature */
+
+  mrb_define_method(mrb, io, "_readchar",  mrb_io_readchar,   MRB_ARGS_REQ(1));
+  mrb_define_class_method(mrb, io, "_bufread",   mrb_io_bufread,    MRB_ARGS_REQ(2));
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/mruby_io_gem.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/mruby_io_gem.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/src/mruby_io_gem.c	(revision 439)
@@ -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/mruby-2.1.1/mrbgems/mruby-io/test/file.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/file.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/file.rb	(revision 439)
@@ -0,0 +1,229 @@
+##
+# File Test
+
+MRubyIOTestUtil.io_test_setup
+
+assert('File.class', '15.2.21') do
+  assert_equal Class, File.class
+end
+
+assert('File.superclass', '15.2.21.2') do
+  assert_equal IO, File.superclass
+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
+  assert_true 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')
+  assert_raise(ArgumentError) { File.basename("/a/b\0") }
+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('File#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#mtime') do
+  begin
+    File.open("#{$mrbtest_io_wfname}.mtime", 'w') do |f|
+      assert_equal Time, f.mtime.class
+      File.open("#{$mrbtest_io_wfname}.mtime", 'r') do |f2|
+        assert_equal true, f.mtime == f2.mtime
+      end
+    end
+  ensure
+    File.delete("#{$mrbtest_io_wfname}.mtime")
+  end
+end
+
+assert('File#size and File#truncate') do
+  fname = "#{$mrbtest_io_wfname}.resize"
+  begin
+    File.open(fname, 'w') do |f|
+      assert_equal 0, f.size
+      assert_equal 0, f.truncate(100)
+      assert_equal 100, f.size
+      assert_equal 0, f.pos
+      assert_equal 0, f.truncate(5)
+      assert_equal 5, f.size
+    end
+  ensure
+    File.delete(fname)
+  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
+
+  assert_raise(ArgumentError) { File.realpath("TO\0DO") }
+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
+  skip "readlink is not supported on this platform" if MRubyIOTestUtil.win?
+  begin
+    e2 = nil
+    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
+      rescue NotImplementedError => e
+        e2 = e
+      end
+    }
+    raise e2 if e2
+  rescue NotImplementedError => e
+    skip e.message
+  end
+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"
+  if !File.exist?(target_name)
+    skip("target directory of File.symlink is not found")
+  end
+
+  begin
+    tmpdir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX")
+  rescue => e
+    skip e.message
+  end
+
+  symlink_name = "#{tmpdir}/test-bin-dummy"
+  begin
+    assert_equal 0, File.symlink(target_name, symlink_name)
+    assert_equal true, File.symlink?(symlink_name)
+  rescue NotImplementedError => e
+    skip e.message
+  ensure
+    File.delete symlink_name rescue nil
+    MRubyIOTestUtil.rmdir tmpdir rescue nil
+  end
+end
+
+assert('File.chmod') do
+  File.open("#{$mrbtest_io_wfname}.chmod-test", 'w') {}
+  begin
+    assert_equal 1, File.chmod(0400, "#{$mrbtest_io_wfname}.chmod-test")
+  ensure
+    File.delete("#{$mrbtest_io_wfname}.chmod-test")
+  end
+end
+
+MRubyIOTestUtil.io_test_cleanup
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/file_test.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/file_test.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/file_test.rb	(revision 439)
@@ -0,0 +1,112 @@
+##
+# FileTest
+
+MRubyIOTestUtil.io_test_setup
+
+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) { FileTest.exist?(io) }
+  assert_raise(TypeError) { File.exist?($mrbtest_io_rfname.to_sym) }
+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_true fp1.closed?
+  assert_raise IOError do
+    FileTest.size?(fp2)
+  end
+  assert_true 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_true fp1.closed?
+  assert_raise IOError do
+    FileTest.zero?(fp2)
+  end
+  assert_true fp2.closed?
+end
+
+MRubyIOTestUtil.io_test_cleanup
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/io.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/io.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/io.rb	(revision 439)
@@ -0,0 +1,643 @@
+##
+# IO Test
+
+MRubyIOTestUtil.io_test_setup
+$cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""]
+
+def assert_io_open(meth)
+  assert "assert_io_open" do
+    fd = IO.sysopen($mrbtest_io_rfname)
+    assert_equal Fixnum, fd.class
+    io1 = IO.__send__(meth, fd)
+    begin
+      assert_equal IO, io1.class
+      assert_equal $mrbtest_io_msg, io1.read
+    ensure
+      io1.close
+    end
+
+    io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io|
+      if meth == :open
+        assert_equal $mrbtest_io_msg, io.read
+      else
+        flunk "IO.#{meth} does not take block"
+      end
+    end
+    io2.close unless meth == :open
+  end
+end
+
+assert('IO.class', '15.2.20') do
+  assert_equal(Class, IO.class)
+end
+
+assert('IO.superclass', '15.2.20.2') do
+  assert_equal(Object, IO.superclass)
+end
+
+assert('IO.ancestors', '15.2.20.3') do
+  assert_include(IO.ancestors, Enumerable)
+end
+
+assert('IO.open', '15.2.20.4.1') do
+  assert_io_open(:open)
+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
+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.split("").each { |ch|
+    assert_equal ch, io.getc
+  }
+  assert_equal nil, io.getc
+  io.close
+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#read(n) with n > IO::BUF_SIZE" do
+  skip "pipe is not supported on this platform" if MRubyIOTestUtil.win?
+  IO.pipe do |r,w|
+    n = IO::BUF_SIZE+1
+    w.write 'a'*n
+    assert_equal 'a'*n, r.read(n)
+  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.split("").each { |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
+
+  io = IO.open(IO.sysopen($mrbtest_io_wfname, "r+"), "r+")
+  assert_equal 7, io.write("abcdefg")
+  io.rewind
+  assert_equal "ab", io.read(2)
+  assert_equal 3, io.write("123")
+  io.rewind
+  assert_equal "ab123fg", io.read
+  io.close
+end
+
+assert('IO#<<') do
+  io = IO.open(IO.sysopen($mrbtest_io_wfname))
+  io << "" << ""
+  assert_equal 0, io.pos
+  io.close
+end
+
+assert('IO#dup for readable') do
+  io = IO.new(IO.sysopen($mrbtest_io_rfname))
+  dup = io.dup
+  assert_true io != dup
+  assert_true io.fileno != dup.fileno
+  begin
+    assert_true dup.close_on_exec?
+  rescue NotImplementedError
+  end
+  assert_equal 'm', dup.sysread(1)
+  assert_equal 'r', io.sysread(1)
+  assert_equal 'u', dup.sysread(1)
+  assert_equal 'b', io.sysread(1)
+  assert_equal 'y', dup.sysread(1)
+  dup.close
+  assert_false io.closed?
+  io.close
+end
+
+assert('IO#dup for writable') do
+  io = IO.open(IO.sysopen($mrbtest_io_wfname, 'w+'), 'w+')
+  dup = io.dup
+  io.syswrite "mruby"
+  assert_equal 5, dup.sysseek(0, IO::SEEK_CUR)
+  io.sysseek 0, IO::SEEK_SET
+  assert_equal 0, dup.sysseek(0, IO::SEEK_CUR)
+  assert_equal "mruby", dup.sysread(5)
+  dup.close
+  io.close
+end
+
+assert('IO.for_fd') do
+  assert_io_open(:for_fd)
+end
+
+assert('IO.new') do
+  assert_io_open(:new)
+end
+
+assert('IO gc check') do
+  assert_nothing_raised { 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
+
+  assert_raise RuntimeError do
+    io.sysread(5, "abcde".freeze)
+  end
+
+  io.close
+  assert_equal "", io.sysread(0)
+  assert_raise(IOError) { io.sysread(1) }
+  assert_raise(ArgumentError) { io.sysread(-1) }
+  io.closed?
+
+  fd = IO.sysopen $mrbtest_io_wfname, "w"
+  io = IO.new fd, "w"
+  assert_raise(IOError) { io.sysread(1) }
+  io.close
+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
+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
+end
+
+assert('IO#isatty') do
+  skip "isatty is not supported on this platform" if MRubyIOTestUtil.win?
+  begin
+    f = File.open("/dev/tty")
+  rescue RuntimeError => e
+    skip e.message
+  else
+    assert_true f.isatty
+  ensure
+    f&.close
+  end
+  begin
+    f = File.open($mrbtest_io_rfname)
+    assert_false f.isatty
+  ensure
+    f&.close
+  end
+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
+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
+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 + $cr, 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 + $cr, 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
+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 + $cr * 4, io.pos
+  io.close
+
+  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
+end
+
+assert('IO.popen') do
+  begin
+    $? = nil
+    io = IO.popen("#{$cmd}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
+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
+    io.close
+    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
+
+  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#pread') do
+  skip "IO#pread is not implemented on this configuration" unless MRubyIOTestUtil::MRB_WITH_IO_PREAD_PWRITE
+
+  IO.open(IO.sysopen($mrbtest_io_rfname, 'r'), 'r') do |io|
+    assert_equal $mrbtest_io_msg.byteslice(5, 8), io.pread(8, 5)
+    assert_equal 0, io.pos
+    assert_equal $mrbtest_io_msg.byteslice(1, 5), io.pread(5, 1)
+    assert_equal 0, io.pos
+    assert_raise(RuntimeError) { io.pread(20, -9) }
+  end
+end
+
+assert('IO#pwrite') do
+  skip "IO#pwrite is not implemented on this configuration" unless MRubyIOTestUtil::MRB_WITH_IO_PREAD_PWRITE
+
+  IO.open(IO.sysopen($mrbtest_io_wfname, 'w+'), 'w+') do |io|
+    assert_equal 6, io.pwrite("Warld!", 7)
+    assert_equal 0, io.pos
+    assert_equal 7, io.pwrite("Hello, ", 0)
+    assert_equal 0, io.pos
+    assert_equal "Hello, Warld!", io.read
+    assert_equal 6, io.pwrite("world!", 7)
+    assert_equal 13, io.pos
+    io.pos = 0
+    assert_equal "Hello, world!", io.read
+  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 `#{$cmd}echo foo`, "foo#{$crlf}"
+  rescue NotImplementedError => e
+    skip e.message
+  end
+end
+
+MRubyIOTestUtil.io_test_cleanup
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/mruby_io_test.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/mruby_io_test.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-io/test/mruby_io_test.c	(revision 439)
@@ -0,0 +1,286 @@
+#include <mruby/common.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+
+#if defined(_WIN32) || defined(_WIN64)
+
+#include <winsock.h>
+#include <io.h>
+#include <fcntl.h>
+#include <direct.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#if (!defined __MINGW64__) && (!defined __MINGW32__)
+typedef int mode_t;
+#endif
+
+#define open _open
+#define close _close
+
+#if defined(_MSC_VER) || \
+    (defined(MRB_MINGW32_VERSION) && MRB_MINGW32_VERSION < 3021) || \
+    (defined(MRB_MINGW64_VERSION) && MRB_MINGW64_VERSION < 4000)
+#include <sys/stat.h>
+
+static int
+mkstemp(char *p)
+{
+  int fd;
+  char* fname = _mktemp(p);
+  if (fname == NULL)
+    return -1;
+  fd = open(fname, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
+  if (fd >= 0)
+    return fd;
+  return -1;
+}
+#endif
+
+static char*
+mkdtemp(char *temp)
+{
+  char *path = _mktemp(temp);
+  if (path[0] == 0) return NULL;
+  if (_mkdir(path) < 0) return NULL;
+  return path;
+}
+
+#define umask(mode) _umask(mode)
+#define rmdir(path) _rmdir(path)
+#else
+  #include <sys/socket.h>
+  #include <unistd.h>
+  #include <sys/un.h>
+  #include <fcntl.h>
+#endif
+
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include "mruby.h"
+#include "mruby/array.h"
+#include "mruby/error.h"
+#include "mruby/string.h"
+#include "mruby/variable.h"
+#include <mruby/ext/io.h>
+
+int wd_save;
+int socket_available_p;
+
+#if !defined(_WIN32) && !defined(_WIN64)
+static int mrb_io_socket_available()
+{
+  int fd, retval = 0;
+  struct sockaddr_un sun0;
+  char socketname[] = "tmp.mruby-io-socket-ok.XXXXXXXX";
+  if (!(fd = mkstemp(socketname))) {
+    goto sock_test_out;
+  }
+  unlink(socketname);
+  close(fd);
+  fd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (fd == -1) {
+    goto sock_test_out;
+  }
+  sun0.sun_family = AF_UNIX;
+  strncpy(sun0.sun_path, socketname, sizeof(sun0.sun_path));
+  if (bind(fd, (struct sockaddr *)&sun0, sizeof(sun0)) == 0) {
+    retval = 1;
+  }
+sock_test_out:
+  unlink(socketname);
+  close(fd);
+  return retval;
+}
+#endif
+
+static mrb_value
+mrb_io_test_io_setup(mrb_state *mrb, mrb_value self)
+{
+  char rfname[]      = "tmp.mruby-io-test-r.XXXXXXXX";
+  char wfname[]      = "tmp.mruby-io-test-w.XXXXXXXX";
+  char symlinkname[] = "tmp.mruby-io-test-l.XXXXXXXX";
+  char socketname[]  = "tmp.mruby-io-test-s.XXXXXXXX";
+  char msg[] = "mruby io test\n";
+  mode_t mask;
+  int fd0, fd1;
+  FILE *fp;
+
+#if !defined(_WIN32) && !defined(_WIN64)
+  int fd2, fd3;
+  struct sockaddr_un sun0;
+
+  if(!(socket_available_p = mrb_io_socket_available())) {
+    char *tmpdir;
+    wd_save = open(".", O_DIRECTORY);
+    tmpdir = getenv("TMPDIR");
+    if (tmpdir) chdir(tmpdir);
+    else chdir("/tmp");
+  }
+#endif
+
+  mask = umask(077);
+  fd0 = mkstemp(rfname);
+  fd1 = mkstemp(wfname);
+  if (fd0 == -1 || fd1 == -1) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file");
+    return mrb_nil_value();
+  }
+  close(fd0);
+  close(fd1);
+
+#if !defined(_WIN32) && !defined(_WIN64)
+  fd2 = mkstemp(symlinkname);
+  fd3 = mkstemp(socketname);
+  if (fd2 == -1 || fd3 == -1) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file");
+    return mrb_nil_value();
+  }
+#endif
+  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);
+
+#if !defined(_WIN32) && !defined(_WIN64)
+  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;
+  strncpy(sun0.sun_path, socketname, sizeof(sun0.sun_path));
+  if (bind(fd3, (struct sockaddr *)&sun0, sizeof(sun0)) == -1) {
+    mrb_raisef(mrb, E_RUNTIME_ERROR, "can't bind AF_UNIX socket to %s: %d",
+               sun0.sun_path,
+               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_string_p(rfname)) {
+    remove(RSTRING_PTR(rfname));
+  }
+  if (mrb_string_p(wfname)) {
+    remove(RSTRING_PTR(wfname));
+  }
+  if (mrb_string_p(symlinkname)) {
+    remove(RSTRING_PTR(symlinkname));
+  }
+  if (mrb_string_p(socketname)) {
+    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());
+
+#if !defined(_WIN32) && !defined(_WIN64)
+  if(!socket_available_p) {
+    fchdir(wd_save);
+    close(wd_save);
+  }
+#endif
+
+  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)
+{
+  const char *cp;
+
+  mrb_get_args(mrb, "z", &cp);
+  if (rmdir(cp) == -1) {
+    mrb_sys_fail(mrb, "rmdir");
+  }
+  return mrb_true_value();
+}
+
+mrb_value
+mrb_io_win_p(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+# if defined(__CYGWIN__) || defined(__CYGWIN32__)
+  return mrb_false_value();
+# else
+  return mrb_true_value();
+# endif
+#else
+  return mrb_false_value();
+#endif
+}
+
+#ifdef MRB_WITH_IO_PREAD_PWRITE
+# define MRB_WITH_IO_PREAD_PWRITE_ENABLED TRUE
+#else
+# define MRB_WITH_IO_PREAD_PWRITE_ENABLED FALSE
+#endif
+
+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, "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));
+  mrb_define_class_method(mrb, io_test, "win?", mrb_io_win_p, MRB_ARGS_NONE());
+
+  mrb_define_const(mrb, io_test, "MRB_WITH_IO_PREAD_PWRITE", mrb_bool_value(MRB_WITH_IO_PREAD_PWRITE_ENABLED));
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-kernel-ext/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-kernel-ext/mrbgem.rake	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-kernel-ext/mrbgem.rake	(revision 439)
@@ -2,4 +2,4 @@
   spec.license = 'MIT'
   spec.author  = 'mruby developers'
-  spec.summary = 'Kernel module extension'
+  spec.summary = 'extensional function-like methods'
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-kernel-ext/src/kernel.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-kernel-ext/src/kernel.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-kernel-ext/src/kernel.c	(revision 439)
@@ -21,7 +21,7 @@
       break;
     case 1:
-      if (mrb_type(v) == MRB_TT_RANGE) {
+      if (mrb_range_p(v)) {
         mrb_int beg, len;
-        if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == 1) {
+        if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == MRB_RANGE_OK) {
           lev = beg;
           n = len;
@@ -32,8 +32,7 @@
       }
       else {
-        v = mrb_to_int(mrb, v);
-        lev = mrb_fixnum(v);
+        lev = mrb_int(mrb, v);
         if (lev < 0) {
-          mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%S)", v);
+          mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%v)", v);
         }
         n = bt_len - lev;
@@ -41,11 +40,11 @@
       break;
     case 2:
-      lev = mrb_fixnum(mrb_to_int(mrb, v));
-      n = mrb_fixnum(mrb_to_int(mrb, length));
+      lev = mrb_int(mrb, v);
+      n = mrb_int(mrb, length);
       if (lev < 0) {
-        mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%S)", v);
+        mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%v)", v);
       }
       if (n < 0) {
-        mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative size (%S)", length);
+        mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative size (%v)", length);
       }
       break;
@@ -94,7 +93,6 @@
  *  In any case, strings should be strictly conformed to numeric
  *  representation. This behavior is different from that of
- *  <code>String#to_i</code>.  Non string values will be converted using
- *  <code>to_int</code>, and <code>to_i</code>. Passing <code>nil</code>
- *  raises a TypeError.
+ *  <code>String#to_i</code>.  Non string values will be treated as integers.
+ *  Passing <code>nil</code> raises a TypeError.
  *
  *     Integer(123.999)    #=> 123
@@ -115,4 +113,5 @@
 }
 
+#ifndef MRB_WITHOUT_FLOAT
 /*
  *  call-seq:
@@ -135,4 +134,5 @@
   return mrb_Float(mrb, arg);
 }
+#endif
 
 /*
@@ -141,6 +141,5 @@
  *
  *  Returns <i>arg</i> as an <code>String</code>.
- *
- *  First tries to call its <code>to_str</code> method, then its to_s method.
+ *  converted using <code>to_s</code> method.
  *
  *     String(self)        #=> "main"
@@ -154,8 +153,5 @@
 
   mrb_get_args(mrb, "o", &arg);
-  tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_str");
-  if (mrb_nil_p(tmp)) {
-    tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s");
-  }
+  tmp = mrb_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s");
   return tmp;
 }
@@ -165,7 +161,5 @@
  *     Array(arg)    -> array
  *
- *  Returns +arg+ as an Array.
- *
- *  First tries to call Array#to_ary on +arg+, then Array#to_a.
+ *  Returns +arg+ as an Array using to_a method.
  *
  *     Array(1..5)   #=> [1, 2, 3, 4, 5]
@@ -178,8 +172,5 @@
 
   mrb_get_args(mrb, "o", &arg);
-  tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_ary");
-  if (mrb_nil_p(tmp)) {
-    tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a");
-  }
+  tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a");
   if (mrb_nil_p(tmp)) {
     return mrb_ary_new_from_values(mrb, 1, &arg);
@@ -193,7 +184,7 @@
  *     Hash(arg)    -> hash
  *
- *  Converts <i>arg</i> to a <code>Hash</code> by calling
- *  <i>arg</i><code>.to_hash</code>. Returns an empty <code>Hash</code> when
- *  <i>arg</i> is <tt>nil</tt> or <tt>[]</tt>.
+ *  Returns a <code>Hash</code> if <i>arg</i> is a <code>Hash</code>.
+ *  Returns an empty <code>Hash</code> when <i>arg</i> is <tt>nil</tt>
+ *  or <tt>[]</tt>.
  *
  *      Hash([])          #=> {}
@@ -206,19 +197,11 @@
 mrb_f_hash(mrb_state *mrb, mrb_value self)
 {
-  mrb_value arg, tmp;
-
-  mrb_get_args(mrb, "o", &arg);
-  if (mrb_nil_p(arg)) {
+  mrb_value arg;
+
+  mrb_get_args(mrb, "o", &arg);
+  if (mrb_nil_p(arg) || (mrb_array_p(arg) && RARRAY_LEN(arg) == 0)) {
     return mrb_hash_new(mrb);
   }
-  tmp = mrb_check_convert_type(mrb, arg, MRB_TT_HASH, "Hash", "to_hash");
-  if (mrb_nil_p(tmp)) {
-    if (mrb_array_p(arg) && RARRAY_LEN(arg) == 0) {
-      return mrb_hash_new(mrb);
-    }
-    mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into Hash",
-      mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, arg)));
-  }
-  return tmp;
+  return mrb_ensure_hash_type(mrb, arg);
 }
 
@@ -231,6 +214,8 @@
   mrb_define_module_function(mrb, krn, "caller", mrb_f_caller, MRB_ARGS_OPT(2));
   mrb_define_method(mrb, krn, "__method__", mrb_f_method, MRB_ARGS_NONE());
-  mrb_define_module_function(mrb, krn, "Integer", mrb_f_integer, MRB_ARGS_ANY());
+  mrb_define_module_function(mrb, krn, "Integer", mrb_f_integer, MRB_ARGS_ARG(1,1));
+#ifndef MRB_WITHOUT_FLOAT
   mrb_define_module_function(mrb, krn, "Float", mrb_f_float, MRB_ARGS_REQ(1));
+#endif
   mrb_define_module_function(mrb, krn, "String", mrb_f_string, MRB_ARGS_REQ(1));
   mrb_define_module_function(mrb, krn, "Array", mrb_f_array, MRB_ARGS_REQ(1));
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-kernel-ext/test/kernel.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-kernel-ext/test/kernel.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-kernel-ext/test/kernel.rb	(revision 439)
@@ -50,18 +50,50 @@
 
 assert('Kernel#Integer') do
-  assert_equal(123, Integer(123.999))
-  assert_equal(26, Integer("0x1a"))
-  assert_equal(930, Integer("0930", 10))
-  assert_equal(7, Integer("111", 2))
-  assert_equal(0, Integer("0"))
-  assert_equal(0, Integer("00000"))
+  assert_operator(26, :eql?, Integer("0x1a"))
+  assert_operator(930, :eql?, Integer("0930", 10))
+  assert_operator(7, :eql?, Integer("111", 2))
+  assert_operator(0, :eql?, Integer("0"))
+  assert_operator(0, :eql?, Integer("00000"))
+  assert_operator(123, :eql?, Integer('1_2_3'))
+  assert_operator(123, :eql?, Integer("\t\r\n\f\v 123 \t\r\n\f\v"))
   assert_raise(TypeError) { Integer(nil) }
+  assert_raise(ArgumentError) { Integer('a') }
+  assert_raise(ArgumentError) { Integer('4a5') }
+  assert_raise(ArgumentError) { Integer('1_2__3') }
+  assert_raise(ArgumentError) { Integer('68_') }
+  assert_raise(ArgumentError) { Integer('68_ ') }
+  assert_raise(ArgumentError) { Integer('_68') }
+  assert_raise(ArgumentError) { Integer(' _68') }
+  assert_raise(ArgumentError) { Integer('6 8') }
+  assert_raise(ArgumentError) { Integer("15\0") }
+  assert_raise(ArgumentError) { Integer("15.0") }
+  skip unless Object.const_defined?(:Float)
+  assert_operator(123, :eql?, Integer(123.999))
 end
 
 assert('Kernel#Float') do
-  assert_equal(1.0, Float(1))
-  assert_equal(123.456, Float(123.456))
-  assert_equal(123.456, Float("123.456"))
+  skip unless Object.const_defined?(:Float)
+  assert_operator(1.0, :eql?, Float(1))
+  assert_operator(123.456, :eql?, Float(123.456))
+  assert_operator(123.456, :eql?, Float("123.456"))
+  assert_operator(123.0, :eql?, Float('1_2_3'))
+  assert_operator(12.34, :eql?, Float('1_2.3_4'))
+  assert_operator(0.9, :eql?, Float('.9'))
+  assert_operator(0.9, :eql?, Float(" \t\r\n\f\v.9 \t\r\n\f\v"))
+  assert_operator(16.0, :eql?, Float("0x10"))
   assert_raise(TypeError) { Float(nil) }
+  assert_raise(ArgumentError) { Float("1. 5") }
+  assert_raise(ArgumentError) { Float("1.5a") }
+  assert_raise(ArgumentError) { Float("1.5\0") }
+  assert_raise(ArgumentError) { Float('a') }
+  assert_raise(ArgumentError) { Float('4a5') }
+  assert_raise(ArgumentError) { Float('1_2__3') }
+  assert_raise(ArgumentError) { Float('68_') }
+  assert_raise(ArgumentError) { Float('68._7') }
+  assert_raise(ArgumentError) { Float('68.7_') }
+  assert_raise(ArgumentError) { Float('68.7_ ') }
+  assert_raise(ArgumentError) { Float('_68') }
+  assert_raise(ArgumentError) { Float(' _68') }
+  assert_raise(ArgumentError) { Float('1_2.3__4') }
 end
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-math/src/math.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-math/src/math.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-math/src/math.c	(revision 439)
@@ -5,4 +5,8 @@
 */
 
+#ifdef MRB_WITHOUT_FLOAT
+# error Math conflicts 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb'
+#endif
+
 #include <mruby.h>
 #include <mruby/array.h>
@@ -15,6 +19,5 @@
   struct RClass *math = mrb_module_get(mrb, "Math");
   struct RClass *domainerror = mrb_class_get_under(mrb, math, "DomainError");
-  mrb_value str = mrb_str_new_cstr(mrb, func);
-  mrb_raisef(mrb, domainerror, "Numerical argument is out of domain - %S", str);
+  mrb_raisef(mrb, domainerror, "Numerical argument is out of domain - %s", func);
 }
 
@@ -23,6 +26,4 @@
 
 #include <float.h>
-
-#define MATH_TOLERANCE 1E-12
 
 double
@@ -123,5 +124,6 @@
     sum  += term/(2*j+1);
     ++j;
-  } while (fabs(term/sum) > MATH_TOLERANCE);
+    if (sum == 0) break;
+  } while (fabs(term/sum) > DBL_EPSILON);
   return two_sqrtpi*sum;
 }
@@ -156,8 +158,12 @@
     q1 = q2;
     q2 = b/d;
-  } while (fabs(q1-q2)/q2 > MATH_TOLERANCE);
+  } while (fabs(q1-q2)/q2 > DBL_EPSILON);
   return one_sqrtpi*exp(-x*x)*q2;
 }
 
+#endif
+
+#if defined __FreeBSD__ && !defined __FreeBSD_version
+#include <osreldate.h> /* for __FreeBSD_version */
 #endif
 
@@ -487,5 +493,5 @@
 {
   mrb_float x, base;
-  int argc;
+  mrb_int argc;
 
   argc = mrb_get_args(mrb, "f|f", &x, &base);
@@ -658,5 +664,5 @@
 
   mrb_get_args(mrb, "fi", &x, &i);
-  x = ldexp(x, i);
+  x = ldexp(x, (int)i);
 
   return mrb_float_value(mrb, x);
@@ -737,10 +743,4 @@
 #else
   mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, exp(1.0)));
-#endif
-
-#ifdef MRB_USE_FLOAT
-  mrb_define_const(mrb, mrb_math, "TOLERANCE", mrb_float_value(mrb, 1e-5));
-#else
-  mrb_define_const(mrb, mrb_math, "TOLERANCE", mrb_float_value(mrb, 1e-12));
 #endif
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-math/test/math.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-math/test/math.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-math/test/math.rb	(revision 439)
@@ -2,44 +2,37 @@
 # Math Test
 
-##
-# Performs fuzzy check for equality on methods returning floats
-# on the basis of the Math::TOLERANCE constant.
-def check_float(a, b)
-  tolerance = Math::TOLERANCE
-  a = a.to_f
-  b = b.to_f
-  if a.finite? and b.finite?
-    (a-b).abs < tolerance
-  else
-    true
+def assert_float_and_int(exp_ary, act_ary)
+  assert('assert_float_and_int') do
+    flo_exp, int_exp, flo_act, int_act = *exp_ary, *act_ary
+    assert_float(flo_exp, flo_act)
+    assert_operator(int_exp, :eql?, int_act)
   end
 end
 
 assert('Math.sin 0') do
-  check_float(Math.sin(0), 0)
+  assert_float(0, Math.sin(0))
 end
 
 assert('Math.sin PI/2') do
-  check_float(Math.sin(Math::PI / 2), 1)
+  assert_float(1, Math.sin(Math::PI / 2))
 end
 
 assert('Math.cos 0') do
-  check_float(Math.cos(0), 1)
+  assert_float(1, Math.cos(0))
 end
 
 assert('Math.cos PI/2') do
-  check_float(Math.cos(Math::PI / 2), 0)
+  assert_float(0, Math.cos(Math::PI / 2))
 end
 
 assert('Math.tan 0') do
-  check_float(Math.tan(0), 0)
+  assert_float(0, Math.tan(0))
 end
 
 assert('Math.tan PI/4') do
-  check_float(Math.tan(Math::PI / 4), 1)
+  assert_float(1, Math.tan(Math::PI / 4))
 end
 
 assert('Fundamental trig identities') do
-  result = true
   N = 13
   N.times do |i|
@@ -49,59 +42,58 @@
     c  = Math.cos(a)
     t  = Math.tan(a)
-    result &= check_float(s, Math.cos(ca))
-    result &= check_float(t, 1 / Math.tan(ca))
-    result &= check_float(s ** 2 + c ** 2, 1)
-    result &= check_float(t ** 2 + 1, (1/c) ** 2)
-    result &= check_float((1/t) ** 2 + 1, (1/s) ** 2)
-  end
-  result
+    assert_float(Math.cos(ca), s)
+    assert_float(1 / Math.tan(ca), t)
+    assert_float(1, s ** 2 + c ** 2)
+    assert_float((1/c) ** 2, t ** 2 + 1)
+    assert_float((1/s) ** 2, (1/t) ** 2 + 1)
+  end
 end
 
 assert('Math.erf 0') do
-  check_float(Math.erf(0), 0)
+  assert_float(0, Math.erf(0))
 end
 
 assert('Math.exp 0') do
-  check_float(Math.exp(0), 1.0)
+  assert_float(1.0, Math.exp(0))
 end
 
 assert('Math.exp 1') do
-  check_float(Math.exp(1), 2.718281828459045)
+  assert_float(2.718281828459045, Math.exp(1))
 end
 
 assert('Math.exp 1.5') do
-  check_float(Math.exp(1.5), 4.4816890703380645)
+  assert_float(4.4816890703380645, Math.exp(1.5))
 end
 
 assert('Math.log 1') do
-  check_float(Math.log(1), 0)
+  assert_float(0, Math.log(1))
 end
 
 assert('Math.log E') do
-  check_float(Math.log(Math::E), 1.0)
+  assert_float(1.0, Math.log(Math::E))
 end
 
 assert('Math.log E**3') do
-  check_float(Math.log(Math::E**3), 3.0)
+  assert_float(3.0, Math.log(Math::E**3))
 end
 
 assert('Math.log2 1') do
-  check_float(Math.log2(1), 0.0)
+  assert_float(0.0, Math.log2(1))
 end
 
 assert('Math.log2 2') do
-  check_float(Math.log2(2), 1.0)
+  assert_float(1.0, Math.log2(2))
 end
 
 assert('Math.log10 1') do
-  check_float(Math.log10(1), 0.0)
+  assert_float(0.0, Math.log10(1))
 end
 
 assert('Math.log10 10') do
-  check_float(Math.log10(10), 1.0)
+  assert_float(1.0, Math.log10(10))
 end
 
 assert('Math.log10 10**100') do
-  check_float(Math.log10(10**100), 100.0)
+  assert_float(100.0, Math.log10(10**100))
 end
 
@@ -109,9 +101,7 @@
   num = [0.0, 1.0, 2.0, 3.0, 4.0]
   sqr = [0, 1, 4, 9, 16]
-  result = true
   sqr.each_with_index do |v,i|
-    result &= check_float(Math.sqrt(v), num[i])
-  end
-  result
+    assert_float(num[i], Math.sqrt(v))
+  end
 end
 
@@ -119,34 +109,131 @@
   num = [-2.0, -1.0, 0.0, 1.0, 2.0]
   cub = [-8, -1, 0, 1, 8]
-  result = true
   cub.each_with_index do |v,i|
-    result &= check_float(Math.cbrt(v), num[i])
-  end
-  result
+    assert_float(num[i], Math.cbrt(v))
+  end
 end
 
 assert('Math.hypot') do
-  check_float(Math.hypot(3, 4), 5.0)
-end
-
-assert('Math.frexp 1234') do
-  n = 1234
-  fraction, exponent = Math.frexp(n)
-  check_float(Math.ldexp(fraction, exponent), n)
+  assert_float(5.0, Math.hypot(3, 4))
 end
 
 assert('Math.erf 1') do
-  check_float(Math.erf(1), 0.842700792949715)
+  assert_float(0.842700792949715, Math.erf(1))
 end
 
 assert('Math.erfc 1') do
-  check_float(Math.erfc(1), 0.157299207050285)
+  assert_float(0.157299207050285, Math.erfc(1))
 end
 
 assert('Math.erf -1') do
-  check_float(Math.erf(-1), -0.8427007929497148)
+  assert_float(-0.8427007929497148, Math.erf(-1))
 end
 
 assert('Math.erfc -1') do
-  check_float(Math.erfc(-1), 1.8427007929497148)
-end
+  assert_float(1.8427007929497148, Math.erfc(-1))
+end
+
+assert('Math.acos') do
+  assert_float(0 * Math::PI / 4, Math.acos( 1.0))
+  assert_float(1 * Math::PI / 4, Math.acos( 1.0 / Math.sqrt(2)))
+  assert_float(2 * Math::PI / 4, Math.acos( 0.0))
+  assert_float(4 * Math::PI / 4, Math.acos(-1.0))
+  assert_raise(Math::DomainError) { Math.acos(+1.1) }
+  assert_raise(Math::DomainError) { Math.acos(-1.1) }
+end
+
+assert('Math.asin') do
+  assert_float( 0 * Math::PI / 4, Math.asin( 0.0))
+  assert_float( 1 * Math::PI / 4, Math.asin( 1.0 / Math.sqrt(2)))
+  assert_float( 2 * Math::PI / 4, Math.asin( 1.0))
+  assert_float(-2 * Math::PI / 4, Math.asin(-1.0))
+  assert_raise(Math::DomainError) { Math.asin(+1.1) }
+  assert_raise(Math::DomainError) { Math.asin(-1.1) }
+  assert_raise(Math::DomainError) { Math.asin(2.0) }
+end
+
+assert('Math.atan') do
+  assert_float( 0 * Math::PI / 4, Math.atan( 0.0))
+  assert_float( 1 * Math::PI / 4, Math.atan( 1.0))
+  assert_float( 2 * Math::PI / 4, Math.atan(1.0 / 0.0))
+  assert_float(-1 * Math::PI / 4, Math.atan(-1.0))
+end
+
+assert('Math.cosh') do
+  assert_float(1, Math.cosh(0))
+  assert_float((Math::E ** 1 + Math::E ** -1) / 2, Math.cosh(1))
+  assert_float((Math::E ** 2 + Math::E ** -2) / 2, Math.cosh(2))
+end
+
+assert('Math.sinh') do
+  assert_float(0, Math.sinh(0))
+  assert_float((Math::E ** 1 - Math::E ** -1) / 2, Math.sinh(1))
+  assert_float((Math::E ** 2 - Math::E ** -2) / 2, Math.sinh(2))
+end
+
+assert('Math.tanh') do
+  assert_float(Math.sinh(0) / Math.cosh(0), Math.tanh(0))
+  assert_float(Math.sinh(1) / Math.cosh(1), Math.tanh(1))
+  assert_float(Math.sinh(2) / Math.cosh(2), Math.tanh(2))
+  assert_float(+1.0, Math.tanh(+1000.0))
+  assert_float(-1.0, Math.tanh(-1000.0))
+end
+
+assert('Math.acosh') do
+  assert_float(0, Math.acosh(1))
+  assert_float(1, Math.acosh((Math::E ** 1 + Math::E ** -1) / 2))
+  assert_float(2, Math.acosh((Math::E ** 2 + Math::E ** -2) / 2))
+  assert_raise(Math::DomainError) { Math.acosh(0.9) }
+  assert_raise(Math::DomainError) { Math.acosh(0) }
+end
+
+assert('Math.asinh') do
+  assert_float(0, Math.asinh(0))
+  assert_float(1, Math.asinh((Math::E ** 1 - Math::E ** -1) / 2))
+  assert_float(2, Math.asinh((Math::E ** 2 - Math::E ** -2) / 2))
+end
+
+assert('Math.atanh') do
+  assert_float(0, Math.atanh(Math.sinh(0) / Math.cosh(0)))
+  assert_float(1, Math.atanh(Math.sinh(1) / Math.cosh(1)))
+  assert_float(2, Math.atanh(Math.sinh(2) / Math.cosh(2)))
+  assert_float(Float::INFINITY, Math.atanh(1))
+  assert_float(-Float::INFINITY, Math.atanh(-1))
+  assert_raise(Math::DomainError) { Math.atanh(+1.1) }
+  assert_raise(Math::DomainError) { Math.atanh(-1.1) }
+end
+
+assert('Math.atan2') do
+  assert_float(+0.0, Math.atan2(+0.0, +0.0))
+  assert_float(-0.0, Math.atan2(-0.0, +0.0))
+  assert_float(+Math::PI, Math.atan2(+0.0, -0.0))
+  assert_float(-Math::PI, Math.atan2(-0.0, -0.0))
+
+  inf = Float::INFINITY
+  expected = 3.0 * Math::PI / 4.0
+  assert_float(+expected, Math.atan2(+inf, -inf))
+  assert_float(-expected, Math.atan2(-inf, -inf))
+  expected = Math::PI / 4.0
+  assert_float(+expected, Math.atan2(+inf, +inf))
+  assert_float(-expected, Math.atan2(-inf, +inf))
+
+  assert_float(0, Math.atan2(0, 1))
+  assert_float(Math::PI / 4, Math.atan2(1, 1))
+  assert_float(Math::PI / 2, Math.atan2(1, 0))
+end
+
+assert('Math.ldexp') do
+  assert_float(0.0, Math.ldexp(0.0, 0.0))
+  assert_float(0.5, Math.ldexp(0.5, 0.0))
+  assert_float(1.0, Math.ldexp(0.5, 1.0))
+  assert_float(2.0, Math.ldexp(0.5, 2.0))
+  assert_float(3.0, Math.ldexp(0.75, 2.0))
+end
+
+assert('Math.frexp') do
+  assert_float_and_int([0.0,  0], Math.frexp(0.0))
+  assert_float_and_int([0.5,  0], Math.frexp(0.5))
+  assert_float_and_int([0.5,  1], Math.frexp(1.0))
+  assert_float_and_int([0.5,  2], Math.frexp(2.0))
+  assert_float_and_int([0.75, 2], Math.frexp(3.0))
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-metaprog/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-metaprog/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-metaprog/mrbgem.rake	(revision 439)
@@ -0,0 +1,5 @@
+MRuby::Gem::Specification.new('mruby-metaprog') do |spec|
+  spec.license = 'MIT'
+  spec.author  = 'mruby developers'
+  spec.summary = 'Meta-programming features for mruby'
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-metaprog/src/metaprog.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-metaprog/src/metaprog.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-metaprog/src/metaprog.c	(revision 439)
@@ -0,0 +1,728 @@
+#include "mruby.h"
+#include "mruby/array.h"
+#include "mruby/hash.h"
+#include "mruby/variable.h"
+#include "mruby/proc.h"
+#include "mruby/class.h"
+#include "mruby/string.h"
+
+typedef enum {
+  NOEX_PUBLIC    = 0x00,
+  NOEX_NOSUPER   = 0x01,
+  NOEX_PRIVATE   = 0x02,
+  NOEX_PROTECTED = 0x04,
+  NOEX_MASK      = 0x06,
+  NOEX_BASIC     = 0x08,
+  NOEX_UNDEF     = NOEX_NOSUPER,
+  NOEX_MODFUNC   = 0x12,
+  NOEX_SUPER     = 0x20,
+  NOEX_VCALL     = 0x40,
+  NOEX_RESPONDS  = 0x80
+} mrb_method_flag_t;
+
+static mrb_value
+mrb_f_nil(mrb_state *mrb, mrb_value cv)
+{
+  return mrb_nil_value();
+}
+
+/* 15.3.1.3.20 */
+/*
+ *  call-seq:
+ *     obj.instance_variable_defined?(symbol)    -> true or false
+ *
+ *  Returns <code>true</code> if the given instance variable is
+ *  defined in <i>obj</i>.
+ *
+ *     class Fred
+ *       def initialize(p1, p2)
+ *         @a, @b = p1, p2
+ *       end
+ *     end
+ *     fred = Fred.new('cat', 99)
+ *     fred.instance_variable_defined?(:@a)    #=> true
+ *     fred.instance_variable_defined?("@b")   #=> true
+ *     fred.instance_variable_defined?("@c")   #=> false
+ */
+static mrb_value
+mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self)
+{
+  mrb_sym sym;
+
+  mrb_get_args(mrb, "n", &sym);
+  mrb_iv_name_sym_check(mrb, sym);
+  return mrb_bool_value(mrb_iv_defined(mrb, self, sym));
+}
+
+/* 15.3.1.3.21 */
+/*
+ *  call-seq:
+ *     obj.instance_variable_get(symbol)    -> obj
+ *
+ *  Returns the value of the given instance variable, or nil if the
+ *  instance variable is not set. The <code>@</code> part of the
+ *  variable name should be included for regular instance
+ *  variables. Throws a <code>NameError</code> exception if the
+ *  supplied symbol is not valid as an instance variable name.
+ *
+ *     class Fred
+ *       def initialize(p1, p2)
+ *         @a, @b = p1, p2
+ *       end
+ *     end
+ *     fred = Fred.new('cat', 99)
+ *     fred.instance_variable_get(:@a)    #=> "cat"
+ *     fred.instance_variable_get("@b")   #=> 99
+ */
+static mrb_value
+mrb_obj_ivar_get(mrb_state *mrb, mrb_value self)
+{
+  mrb_sym iv_name;
+
+  mrb_get_args(mrb, "n", &iv_name);
+  mrb_iv_name_sym_check(mrb, iv_name);
+  return mrb_iv_get(mrb, self, iv_name);
+}
+
+/* 15.3.1.3.22 */
+/*
+ *  call-seq:
+ *     obj.instance_variable_set(symbol, obj)    -> obj
+ *
+ *  Sets the instance variable names by <i>symbol</i> to
+ *  <i>object</i>, thereby frustrating the efforts of the class's
+ *  author to attempt to provide proper encapsulation. The variable
+ *  did not have to exist prior to this call.
+ *
+ *     class Fred
+ *       def initialize(p1, p2)
+ *         @a, @b = p1, p2
+ *       end
+ *     end
+ *     fred = Fred.new('cat', 99)
+ *     fred.instance_variable_set(:@a, 'dog')   #=> "dog"
+ *     fred.instance_variable_set(:@c, 'cat')   #=> "cat"
+ *     fred.inspect                             #=> "#<Fred:0x401b3da8 @a=\"dog\", @b=99, @c=\"cat\">"
+ */
+static mrb_value
+mrb_obj_ivar_set(mrb_state *mrb, mrb_value self)
+{
+  mrb_sym iv_name;
+  mrb_value val;
+
+  mrb_get_args(mrb, "no", &iv_name, &val);
+  mrb_iv_name_sym_check(mrb, iv_name);
+  mrb_iv_set(mrb, self, iv_name, val);
+  return val;
+}
+
+/* 15.3.1.2.7 */
+/* 15.3.1.3.28 */
+/*
+ *  call-seq:
+ *     local_variables   -> array
+ *
+ *  Returns the names of local variables in the current scope.
+ *
+ *  [mruby limitation]
+ *  If variable symbol information was stripped out from
+ *  compiled binary files using `mruby-strip -l`, this
+ *  method always returns an empty array.
+ */
+static mrb_value
+mrb_local_variables(mrb_state *mrb, mrb_value self)
+{
+  struct RProc *proc;
+  mrb_irep *irep;
+  mrb_value vars;
+  size_t i;
+
+  proc = mrb->c->ci[-1].proc;
+
+  if (proc == NULL || MRB_PROC_CFUNC_P(proc)) {
+    return mrb_ary_new(mrb);
+  }
+  vars = mrb_hash_new(mrb);
+  while (proc) {
+    if (MRB_PROC_CFUNC_P(proc)) break;
+    irep = proc->body.irep;
+    if (!irep->lv) break;
+    for (i = 0; i + 1 < irep->nlocals; ++i) {
+      if (irep->lv[i].name) {
+        mrb_sym sym = irep->lv[i].name;
+        const char *name = mrb_sym_name(mrb, sym);
+        switch (name[0]) {
+        case '*': case '&':
+          break;
+        default:
+          mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value());
+          break;
+        }
+      }
+    }
+    if (!MRB_PROC_ENV_P(proc)) break;
+    proc = proc->upper;
+    //if (MRB_PROC_SCOPE_P(proc)) break;
+    if (!proc->c) break;
+  }
+
+  return mrb_hash_keys(mrb, vars);
+}
+
+KHASH_DECLARE(st, mrb_sym, char, FALSE)
+
+static void
+method_entry_loop(mrb_state *mrb, struct RClass *klass, khash_t(st) *set, khash_t(st) *undef)
+{
+  khint_t i;
+
+  khash_t(mt) *h = klass->mt;
+  if (!h || kh_size(h) == 0) return;
+  for (i=0;i<kh_end(h);i++) {
+    if (kh_exist(h, i)) {
+      mrb_method_t m = kh_value(h, i);
+      if (MRB_METHOD_UNDEF_P(m)) {
+        if (undef) {
+          kh_put(st, mrb, undef, kh_key(h, i));
+        }
+      }
+      else if (undef == NULL ||
+               kh_get(st, mrb, undef, kh_key(h, i)) == kh_end(undef)) {
+        kh_put(st, mrb, set, kh_key(h, i));
+      }
+    }
+  }
+}
+
+static mrb_value
+mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass *klass, int obj)
+{
+  khint_t i;
+  mrb_value ary;
+  mrb_bool prepended = FALSE;
+  struct RClass *oldklass;
+  khash_t(st) *set = kh_init(st, mrb);
+  khash_t(st) *undef = (recur ? kh_init(st, mrb) : NULL);
+
+  if (!recur && (klass->flags & MRB_FL_CLASS_IS_PREPENDED)) {
+    MRB_CLASS_ORIGIN(klass);
+    prepended = TRUE;
+  }
+
+  oldklass = 0;
+  while (klass && (klass != oldklass)) {
+    method_entry_loop(mrb, klass, set, undef);
+    if ((klass->tt == MRB_TT_ICLASS && !prepended) ||
+        (klass->tt == MRB_TT_SCLASS)) {
+    }
+    else {
+      if (!recur) break;
+    }
+    oldklass = klass;
+    klass = klass->super;
+  }
+
+  ary = mrb_ary_new_capa(mrb, kh_size(set));
+  for (i=0;i<kh_end(set);i++) {
+    if (kh_exist(set, i)) {
+      mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i)));
+    }
+  }
+  kh_destroy(st, mrb, set);
+  if (undef) kh_destroy(st, mrb, undef);
+
+  return ary;
+}
+
+static mrb_value
+mrb_obj_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj, mrb_method_flag_t flag)
+{
+  return mrb_class_instance_method_list(mrb, recur, mrb_class(mrb, obj), 0);
+}
+/* 15.3.1.3.31 */
+/*
+ *  call-seq:
+ *     obj.methods    -> array
+ *
+ *  Returns a list of the names of methods publicly accessible in
+ *  <i>obj</i>. This will include all the methods accessible in
+ *  <i>obj</i>'s ancestors.
+ *
+ *     class Klass
+ *       def kMethod()
+ *       end
+ *     end
+ *     k = Klass.new
+ *     k.methods[0..9]    #=> [:kMethod, :respond_to?, :nil?, :is_a?,
+ *                        #    :class, :instance_variable_set,
+ *                        #    :methods, :extend, :__send__, :instance_eval]
+ *     k.methods.length   #=> 42
+ */
+static mrb_value
+mrb_obj_methods_m(mrb_state *mrb, mrb_value self)
+{
+  mrb_bool recur = TRUE;
+  mrb_get_args(mrb, "|b", &recur);
+  return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */
+}
+
+/* 15.3.1.3.36 */
+/*
+ *  call-seq:
+ *     obj.private_methods(all=true)   -> array
+ *
+ *  Returns the list of private methods accessible to <i>obj</i>. If
+ *  the <i>all</i> parameter is set to <code>false</code>, only those methods
+ *  in the receiver will be listed.
+ */
+static mrb_value
+mrb_obj_private_methods(mrb_state *mrb, mrb_value self)
+{
+  mrb_bool recur = TRUE;
+  mrb_get_args(mrb, "|b", &recur);
+  return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */
+}
+
+/* 15.3.1.3.37 */
+/*
+ *  call-seq:
+ *     obj.protected_methods(all=true)   -> array
+ *
+ *  Returns the list of protected methods accessible to <i>obj</i>. If
+ *  the <i>all</i> parameter is set to <code>false</code>, only those methods
+ *  in the receiver will be listed.
+ */
+static mrb_value
+mrb_obj_protected_methods(mrb_state *mrb, mrb_value self)
+{
+  mrb_bool recur = TRUE;
+  mrb_get_args(mrb, "|b", &recur);
+  return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */
+}
+
+/* 15.3.1.3.38 */
+/*
+ *  call-seq:
+ *     obj.public_methods(all=true)   -> array
+ *
+ *  Returns the list of public methods accessible to <i>obj</i>. If
+ *  the <i>all</i> parameter is set to <code>false</code>, only those methods
+ *  in the receiver will be listed.
+ */
+static mrb_value
+mrb_obj_public_methods(mrb_state *mrb, mrb_value self)
+{
+  mrb_bool recur = TRUE;
+  mrb_get_args(mrb, "|b", &recur);
+  return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */
+}
+
+static mrb_value
+mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj)
+{
+  khint_t i;
+  mrb_value ary;
+  struct RClass *klass;
+  khash_t(st) *set = kh_init(st, mrb);
+  khash_t(st) *undef = (recur ? kh_init(st, mrb) : NULL);
+
+  klass = mrb_class(mrb, obj);
+
+  if (klass && (klass->tt == MRB_TT_SCLASS)) {
+      method_entry_loop(mrb, klass, set, undef);
+      klass = klass->super;
+  }
+  if (recur) {
+      while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) {
+        method_entry_loop(mrb, klass, set, undef);
+        klass = klass->super;
+      }
+  }
+
+  ary = mrb_ary_new(mrb);
+  for (i=0;i<kh_end(set);i++) {
+    if (kh_exist(set, i)) {
+      mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set, i)));
+    }
+  }
+  kh_destroy(st, mrb, set);
+  if (undef) kh_destroy(st, mrb, undef);
+
+  return ary;
+}
+
+/* 15.3.1.3.45 */
+/*
+ *  call-seq:
+ *     obj.singleton_methods(all=true)    -> array
+ *
+ *  Returns an array of the names of singleton methods for <i>obj</i>.
+ *  If the optional <i>all</i> parameter is true, the list will include
+ *  methods in modules included in <i>obj</i>.
+ *  Only public and protected singleton methods are returned.
+ *
+ *     module Other
+ *       def three() end
+ *     end
+ *
+ *     class Single
+ *       def Single.four() end
+ *     end
+ *
+ *     a = Single.new
+ *
+ *     def a.one()
+ *     end
+ *
+ *     class << a
+ *       include Other
+ *       def two()
+ *       end
+ *     end
+ *
+ *     Single.singleton_methods    #=> [:four]
+ *     a.singleton_methods(false)  #=> [:two, :one]
+ *     a.singleton_methods         #=> [:two, :one, :three]
+ */
+static mrb_value
+mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self)
+{
+  mrb_bool recur = TRUE;
+  mrb_get_args(mrb, "|b", &recur);
+  return mrb_obj_singleton_methods(mrb, recur, self);
+}
+
+static mrb_value
+mod_define_singleton_method(mrb_state *mrb, mrb_value self)
+{
+  struct RProc *p;
+  mrb_method_t m;
+  mrb_sym mid;
+  mrb_value blk = mrb_nil_value();
+
+  mrb_get_args(mrb, "n&!", &mid, &blk);
+  p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class);
+  mrb_proc_copy(p, mrb_proc_ptr(blk));
+  p->flags |= MRB_PROC_STRICT;
+  MRB_METHOD_FROM_PROC(m, p);
+  mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, m);
+  return mrb_symbol_value(mid);
+}
+
+static mrb_bool
+cv_name_p(mrb_state *mrb, const char *name, mrb_int len)
+{
+  return len > 2 && name[0] == '@' && name[1] == '@' &&
+         !ISDIGIT(name[2]) && mrb_ident_p(name+2, len-2);
+}
+
+static void
+check_cv_name_sym(mrb_state *mrb, mrb_sym id)
+{
+  mrb_int len;
+  const char *name = mrb_sym_name_len(mrb, id, &len);
+  if (!cv_name_p(mrb, name, len)) {
+    mrb_name_error(mrb, id, "'%n' is not allowed as a class variable name", id);
+  }
+}
+
+/* 15.2.2.4.39 */
+/*
+ *  call-seq:
+ *     remove_class_variable(sym)    -> obj
+ *
+ *  Removes the definition of the <i>sym</i>, returning that
+ *  constant's value.
+ *
+ *     class Dummy
+ *       @@var = 99
+ *       puts @@var
+ *       p class_variables
+ *       remove_class_variable(:@@var)
+ *       p class_variables
+ *     end
+ *
+ *  <em>produces:</em>
+ *
+ *     99
+ *     [:@@var]
+ *     []
+ */
+
+static mrb_value
+mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod)
+{
+  mrb_value val;
+  mrb_sym id;
+
+  mrb_get_args(mrb, "n", &id);
+  check_cv_name_sym(mrb, id);
+
+  val = mrb_iv_remove(mrb, mod, id);
+  if (!mrb_undef_p(val)) return val;
+
+  if (mrb_cv_defined(mrb, mod, id)) {
+    mrb_name_error(mrb, id, "cannot remove %n for %v", id, mod);
+  }
+
+  mrb_name_error(mrb, id, "class variable %n not defined for %v", id, mod);
+
+ /* not reached */
+ return mrb_nil_value();
+}
+
+/* 15.2.2.4.16 */
+/*
+ *  call-seq:
+ *     obj.class_variable_defined?(symbol)    -> true or false
+ *
+ *  Returns <code>true</code> if the given class variable is defined
+ *  in <i>obj</i>.
+ *
+ *     class Fred
+ *       @@foo = 99
+ *     end
+ *     Fred.class_variable_defined?(:@@foo)    #=> true
+ *     Fred.class_variable_defined?(:@@bar)    #=> false
+ */
+
+static mrb_value
+mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod)
+{
+  mrb_sym id;
+
+  mrb_get_args(mrb, "n", &id);
+  check_cv_name_sym(mrb, id);
+  return mrb_bool_value(mrb_cv_defined(mrb, mod, id));
+}
+
+/* 15.2.2.4.17 */
+/*
+ *  call-seq:
+ *     mod.class_variable_get(symbol)    -> obj
+ *
+ *  Returns the value of the given class variable (or throws a
+ *  <code>NameError</code> exception). The <code>@@</code> part of the
+ *  variable name should be included for regular class variables
+ *
+ *     class Fred
+ *       @@foo = 99
+ *     end
+ *     Fred.class_variable_get(:@@foo)     #=> 99
+ */
+
+static mrb_value
+mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod)
+{
+  mrb_sym id;
+
+  mrb_get_args(mrb, "n", &id);
+  check_cv_name_sym(mrb, id);
+  return mrb_cv_get(mrb, mod, id);
+}
+
+/* 15.2.2.4.18 */
+/*
+ *  call-seq:
+ *     obj.class_variable_set(symbol, obj)    -> obj
+ *
+ *  Sets the class variable names by <i>symbol</i> to
+ *  <i>object</i>.
+ *
+ *     class Fred
+ *       @@foo = 99
+ *       def foo
+ *         @@foo
+ *       end
+ *     end
+ *     Fred.class_variable_set(:@@foo, 101)     #=> 101
+ *     Fred.new.foo                             #=> 101
+ */
+
+static mrb_value
+mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod)
+{
+  mrb_value value;
+  mrb_sym id;
+
+  mrb_get_args(mrb, "no", &id, &value);
+  check_cv_name_sym(mrb, id);
+  mrb_cv_set(mrb, mod, id, value);
+  return value;
+}
+
+static mrb_value
+mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
+{
+  mrb_value result;
+  struct RClass *c = mrb_class_ptr(self);
+  struct RClass *origin = c;
+
+  MRB_CLASS_ORIGIN(origin);
+  result = mrb_ary_new(mrb);
+  while (c) {
+    if (c != origin && c->tt == MRB_TT_ICLASS) {
+      if (c->c->tt == MRB_TT_MODULE) {
+        mrb_ary_push(mrb, result, mrb_obj_value(c->c));
+      }
+    }
+    c = c->super;
+  }
+
+  return result;
+}
+
+/* 15.2.2.4.33 */
+/*
+ *  call-seq:
+ *     mod.instance_methods(include_super=true)   -> array
+ *
+ *  Returns an array containing the names of the public and protected instance
+ *  methods in the receiver. For a module, these are the public and protected methods;
+ *  for a class, they are the instance (not singleton) methods. With no
+ *  argument, or with an argument that is <code>false</code>, the
+ *  instance methods in <i>mod</i> are returned, otherwise the methods
+ *  in <i>mod</i> and <i>mod</i>'s superclasses are returned.
+ *
+ *     module A
+ *       def method1()  end
+ *     end
+ *     class B
+ *       def method2()  end
+ *     end
+ *     class C < B
+ *       def method3()  end
+ *     end
+ *
+ *     A.instance_methods                #=> [:method1]
+ *     B.instance_methods(false)         #=> [:method2]
+ *     C.instance_methods(false)         #=> [:method3]
+ *     C.instance_methods(true).length   #=> 43
+ */
+
+static mrb_value
+mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod)
+{
+  struct RClass *c = mrb_class_ptr(mod);
+  mrb_bool recur = TRUE;
+  mrb_get_args(mrb, "|b", &recur);
+  return mrb_class_instance_method_list(mrb, recur, c, 0);
+}
+
+static void
+remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid)
+{
+  struct RClass *c = mrb_class_ptr(mod);
+  khash_t(mt) *h;
+  khiter_t k;
+
+  MRB_CLASS_ORIGIN(c);
+  h = c->mt;
+
+  if (h) {
+    k = kh_get(mt, mrb, h, mid);
+    if (k != kh_end(h)) {
+      kh_del(mt, mrb, h, k);
+      mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid));
+      return;
+    }
+  }
+
+  mrb_name_error(mrb, mid, "method '%n' not defined in %v", mid, mod);
+}
+
+/* 15.2.2.4.41 */
+/*
+ *  call-seq:
+ *     remove_method(symbol)   -> self
+ *
+ *  Removes the method identified by _symbol_ from the current
+ *  class. For an example, see <code>Module.undef_method</code>.
+ */
+
+static mrb_value
+mrb_mod_remove_method(mrb_state *mrb, mrb_value mod)
+{
+  mrb_int argc;
+  mrb_value *argv;
+
+  mrb_get_args(mrb, "*", &argv, &argc);
+  mrb_check_frozen(mrb, mrb_obj_ptr(mod));
+  while (argc--) {
+    remove_method(mrb, mod, mrb_obj_to_sym(mrb, *argv));
+    argv++;
+  }
+  return mod;
+}
+
+static mrb_value
+mrb_mod_s_constants(mrb_state *mrb, mrb_value mod)
+{
+  mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented");
+  return mrb_nil_value();       /* not reached */
+}
+
+static mrb_value
+mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod)
+{
+  struct RProc *proc;
+  mrb_value ary;
+  struct RClass *c = NULL;
+
+  ary = mrb_ary_new(mrb);
+  proc = mrb->c->ci[-1].proc;   /* callee proc */
+  mrb_assert(!MRB_PROC_CFUNC_P(proc));
+  while (proc) {
+    if (MRB_PROC_SCOPE_P(proc)) {
+      struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc);
+
+      if (c2 != c) {
+        c = c2;
+        mrb_ary_push(mrb, ary, mrb_obj_value(c));
+      }
+    }
+    proc = proc->upper;
+  }
+  return ary;
+}
+
+void
+mrb_mruby_metaprog_gem_init(mrb_state* mrb)
+{
+  struct RClass *krn = mrb->kernel_module;
+  struct RClass *mod = mrb->module_class;
+
+  mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 (15.3.1.2.4) */
+  mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 (15.3.1.2.7) */
+
+  mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE());
+  mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */
+  mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */
+  mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */
+  mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */
+  mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */
+  mrb_define_method(mrb, krn, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */
+  mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */
+  mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */
+  mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */
+  mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_REQ(1)|MRB_ARGS_BLOCK());
+  mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_REQ(1)|MRB_ARGS_REST()|MRB_ARGS_BLOCK()); /* 15.3.1.3.44 */
+
+  mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_OPT(1)); /* 15.2.2.4.19 */
+  mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */
+  mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */
+  mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */
+  mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */
+  mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */
+  mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */
+  mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */
+  mrb_define_method(mrb, mod, "method_removed", mrb_f_nil, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */
+  mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */
+  mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_NONE()); /* 15.2.2.3.2 */
+}
+
+void
+mrb_mruby_metaprog_gem_final(mrb_state* mrb)
+{
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-metaprog/test/metaprog.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-metaprog/test/metaprog.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-metaprog/test/metaprog.rb	(revision 439)
@@ -0,0 +1,400 @@
+assert('Kernel#send', '15.3.1.3.44') do
+  # test with block
+  l = send(:lambda) do
+    true
+  end
+
+  assert_true l.call
+  assert_equal l.class, Proc
+  # test with argument
+  assert_true send(:respond_to?, :nil?)
+  # test without argument and without block
+  assert_equal send(:to_s).class, String
+end
+
+assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do
+  o = Object.new
+  o.instance_variable_set(:@a, 1)
+
+  assert_true o.instance_variable_defined?("@a")
+  assert_false o.instance_variable_defined?("@b")
+  assert_true o.instance_variable_defined?("@a"[0,2])
+  assert_true o.instance_variable_defined?("@abc"[0,2])
+  assert_raise(NameError) { o.instance_variable_defined?("@0") }
+end
+
+assert('Kernel#instance_variable_get', '15.3.1.3.21') do
+  o = Class.new { attr_accessor :foo, :bar }.new
+  o.foo = "one"
+  o.bar = 2
+  assert_equal("one", o.instance_variable_get(:@foo))
+  assert_equal(2, o.instance_variable_get("@bar"))
+  assert_equal(nil, o.instance_variable_get(:@baz))
+  %w[foo @1].each do |n|
+    assert_raise(NameError) { o.instance_variable_get(n) }
+  end
+end
+
+assert('Kernel#instance_variable_set', '15.3.1.3.22') do
+  o = Class.new { attr_reader :foo, :_bar }.new
+  assert_equal("one", o.instance_variable_set(:@foo, "one"))
+  assert_equal("one", o.foo)
+  assert_equal(2, o.instance_variable_set("@_bar", 2))
+  assert_equal(2, o._bar)
+  %w[@6 @% @@a @ a].each do |n|
+    assert_raise(NameError) { o.instance_variable_set(n, 1) }
+  end
+  assert_raise(FrozenError) { o.freeze.instance_variable_set(:@a, 2) }
+  assert_raise(FrozenError, ArgumentError) { nil.instance_variable_set(:@a, 2) }
+end
+
+assert('Kernel#instance_variables', '15.3.1.3.23') do
+  o = Object.new
+  o.instance_eval do
+    @a = 11
+    @b = 12
+  end
+  ivars = o.instance_variables
+
+  assert_equal Array, ivars.class,
+  assert_equal(2, ivars.size)
+  assert_true ivars.include?(:@a)
+  assert_true ivars.include?(:@b)
+end
+
+assert('Kernel#methods', '15.3.1.3.31') do
+  assert_equal Array, methods.class
+end
+
+assert('Kernel#private_methods', '15.3.1.3.36') do
+  assert_equal Array, private_methods.class
+end
+
+assert('Kernel#protected_methods', '15.3.1.3.37') do
+  assert_equal Array, protected_methods.class
+end
+
+assert('Kernel#public_methods', '15.3.1.3.38') do
+  assert_equal Array, public_methods.class
+  class Foo
+    def foo
+    end
+  end
+  assert_equal [:foo], Foo.new.public_methods(false)
+end
+
+assert('Kernel#singleton_methods', '15.3.1.3.45') do
+  assert_equal singleton_methods.class, Array
+end
+
+assert('Kernel.global_variables', '15.3.1.2.4') do
+  assert_equal Array, Kernel.global_variables.class
+end
+
+assert('Kernel#global_variables', '15.3.1.3.14') do
+  variables1 = global_variables
+  assert_equal Array, variables1.class
+  assert_not_include(variables1, :$kernel_global_variables_test)
+
+  $kernel_global_variables_test = nil
+  variables2 = global_variables
+  assert_include(variables2, :$kernel_global_variables_test)
+  assert_equal(1, variables2.size - variables1.size)
+end
+
+assert('Kernel.local_variables', '15.3.1.2.7') do
+  a, b = 0, 1
+  a += b
+
+  vars = Kernel.local_variables.sort
+  assert_equal [:a, :b, :vars], vars
+
+  assert_equal [:a, :b, :c, :vars], Proc.new { |a, b|
+    c = 2
+    # Kernel#local_variables: 15.3.1.3.28
+    local_variables.sort
+  }.call(-1, -2)
+end
+
+assert('Kernel#define_singleton_method') do
+  o = Object.new
+  ret = o.define_singleton_method(:test_method) do
+    :singleton_method_ok
+  end
+  assert_equal :test_method, ret
+  assert_equal :singleton_method_ok, o.test_method
+  assert_raise(TypeError) { 2.define_singleton_method(:f){} }
+  assert_raise(FrozenError) { [].freeze.define_singleton_method(:f){} }
+end
+
+assert('Kernel#singleton_class') do
+  o1 = Object.new
+  assert_same(o1.singleton_class, class << o1; self end)
+
+  o2 = Object.new
+  sc2 = class << o2; self end
+  assert_same(o2.singleton_class, sc2)
+
+  o3 = Object.new
+  sc3 = o3.singleton_class
+  o3.freeze
+  assert_predicate(sc3, :frozen?)
+
+  assert_predicate(Object.new.freeze.singleton_class, :frozen?)
+end
+
+def labeled_module(name, &block)
+  Module.new do
+    (class <<self; self end).class_eval do
+      define_method(:to_s) { name }
+      alias_method :inspect, :to_s
+    end
+    class_eval(&block) if block
+  end
+end
+
+def labeled_class(name, supklass = Object, &block)
+  Class.new(supklass) do
+    (class <<self; self end).class_eval do
+      define_method(:to_s) { name }
+      alias_method :inspect, :to_s
+    end
+    class_eval(&block) if block
+  end
+end
+
+assert('Module#class_variable_defined?', '15.2.2.4.16') do
+  class Test4ClassVariableDefined
+    @@cv = 99
+  end
+
+  assert_true Test4ClassVariableDefined.class_variable_defined?(:@@cv)
+  assert_false Test4ClassVariableDefined.class_variable_defined?(:@@noexisting)
+  assert_raise(NameError) { Test4ClassVariableDefined.class_variable_defined?("@@2") }
+end
+
+assert('Module#class_variable_get', '15.2.2.4.17') do
+  class Test4ClassVariableGet
+    @@cv = 99
+  end
+
+  assert_equal 99, Test4ClassVariableGet.class_variable_get(:@@cv)
+  assert_raise(NameError) { Test4ClassVariableGet.class_variable_get(:@@a) }
+  %w[@@a? @@! @a a].each do |n|
+    assert_raise(NameError) { Test4ClassVariableGet.class_variable_get(n) }
+  end
+end
+
+assert('Module#class_variable_set', '15.2.2.4.18') do
+  class Test4ClassVariableSet
+    @@foo = 100
+    def foo
+      @@foo
+    end
+  end
+  assert_equal 99, Test4ClassVariableSet.class_variable_set(:@@cv, 99)
+  assert_equal 101, Test4ClassVariableSet.class_variable_set(:@@foo, 101)
+  assert_true Test4ClassVariableSet.class_variables.include? :@@cv
+  assert_equal 99, Test4ClassVariableSet.class_variable_get(:@@cv)
+  assert_equal 101, Test4ClassVariableSet.new.foo
+  %w[@@ @@1 @@x= @x @ x 1].each do |n|
+    assert_raise(NameError) { Test4ClassVariableSet.class_variable_set(n, 1) }
+  end
+
+  m = Module.new.freeze
+  assert_raise(FrozenError) { m.class_variable_set(:@@cv, 1) }
+
+  parent = Class.new{ class_variable_set(:@@a, nil) }.freeze
+  child = Class.new(parent)
+  assert_raise(FrozenError) { child.class_variable_set(:@@a, 1) }
+end
+
+assert('Module#class_variables', '15.2.2.4.19') do
+  class Test4ClassVariables1
+    @@var1 = 1
+  end
+  class Test4ClassVariables2 < Test4ClassVariables1
+    @@var2 = 2
+  end
+
+  assert_equal [:@@var1], Test4ClassVariables1.class_variables
+  assert_equal [:@@var2, :@@var1], Test4ClassVariables2.class_variables
+end
+
+assert('Module#constants', '15.2.2.4.24') do
+  $n = []
+  module TestA
+    C = 1
+  end
+  class TestB
+    include TestA
+    C2 = 1
+    $n = constants.sort
+  end
+
+  assert_equal [ :C ], TestA.constants
+  assert_equal [ :C, :C2 ], $n
+end
+
+assert('Module#included_modules', '15.2.2.4.30') do
+  module Test4includedModules
+  end
+  module Test4includedModules2
+    include Test4includedModules
+  end
+  r = Test4includedModules2.included_modules
+
+  assert_equal Array, r.class
+  assert_true r.include?(Test4includedModules)
+end
+
+assert('Module#instance_methods', '15.2.2.4.33') do
+  module Test4InstanceMethodsA
+    def method1()  end
+  end
+  class Test4InstanceMethodsB
+    def method2()  end
+  end
+  class Test4InstanceMethodsC < Test4InstanceMethodsB
+    def method3()  end
+  end
+
+  r = Test4InstanceMethodsC.instance_methods(true)
+
+  assert_equal [:method1], Test4InstanceMethodsA.instance_methods
+  assert_equal [:method2], Test4InstanceMethodsB.instance_methods(false)
+  assert_equal [:method3], Test4InstanceMethodsC.instance_methods(false)
+  assert_equal Array, r.class
+  assert_true r.include?(:method3)
+  assert_true r.include?(:method2)
+end
+
+assert 'Module#prepend #instance_methods(false)' do
+  bug6660 = '[ruby-dev:45863]'
+  assert_equal([:m1], Class.new{ prepend Module.new; def m1; end }.instance_methods(false), bug6660)
+  assert_equal([:m1], Class.new(Class.new{def m2;end}){ prepend Module.new; def m1; end }.instance_methods(false), bug6660)
+end
+
+assert('Module#remove_class_variable', '15.2.2.4.39') do
+  class Test4RemoveClassVariable
+    @@cv = 99
+  end
+
+  assert_equal 99, Test4RemoveClassVariable.remove_class_variable(:@@cv)
+  assert_false Test4RemoveClassVariable.class_variables.include? :@@cv
+  assert_raise(NameError) do
+    Test4RemoveClassVariable.remove_class_variable(:@@cv)
+  end
+  assert_raise(NameError) do
+    Test4RemoveClassVariable.remove_class_variable(:@v)
+  end
+  assert_raise(FrozenError) do
+    Test4RemoveClassVariable.freeze.remove_class_variable(:@@cv)
+  end
+end
+
+assert('Module#remove_method', '15.2.2.4.41') do
+  module Test4RemoveMethod
+    class Parent
+      def hello
+      end
+    end
+
+    class Child < Parent
+      def hello
+      end
+    end
+  end
+
+  klass = Test4RemoveMethod::Child
+  assert_same klass, klass.class_eval{ remove_method :hello }
+  assert_true klass.instance_methods.include? :hello
+  assert_false klass.instance_methods(false).include? :hello
+  assert_raise(FrozenError) { klass.freeze.remove_method :m }
+end
+
+assert('Module.nesting', '15.2.2.2.2') do
+  module Test4ModuleNesting
+    module Test4ModuleNesting2
+      assert_equal [Test4ModuleNesting2, Test4ModuleNesting],
+                   Module.nesting
+    end
+  end
+  module Test4ModuleNesting::Test4ModuleNesting2
+    assert_equal [Test4ModuleNesting::Test4ModuleNesting2], Module.nesting
+  end
+end
+
+assert('Moduler#prepend + #instance_methods') do
+  bug6655 = '[ruby-core:45915]'
+  assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655)
+end
+
+assert 'Module#prepend + #singleton_methods' do
+  o = Object.new
+  o.singleton_class.class_eval {prepend Module.new}
+  assert_equal([], o.singleton_methods)
+end
+
+assert 'Module#prepend + #remove_method' do
+  c = Class.new do
+    prepend Module.new { def foo; end }
+  end
+  assert_raise(NameError) do
+    c.class_eval do
+      remove_method(:foo)
+    end
+  end
+  c.class_eval do
+    def foo; end
+  end
+  removed = nil
+  c.singleton_class.class_eval do
+    define_method(:method_removed) {|id| removed = id}
+  end
+  assert_nothing_raised('[Bug #7843]') do
+    c.class_eval do
+      remove_method(:foo)
+    end
+  end
+  assert_equal(:foo, removed)
+end
+
+assert 'Module#prepend + #included_modules' do
+  bug8025 = '[ruby-core:53158] [Bug #8025]'
+  mixin = labeled_module("mixin")
+  c = labeled_module("c") {prepend mixin}
+  im = c.included_modules
+  assert_not_include(im, c, bug8025)
+  assert_include(im, mixin, bug8025)
+  c1 = labeled_class("c1") {prepend mixin}
+  c2 = labeled_class("c2", c1)
+  im = c2.included_modules
+  assert_not_include(im, c1, bug8025)
+  assert_not_include(im, c2, bug8025)
+  assert_include(im, mixin, bug8025)
+end
+
+assert("remove_method doesn't segfault if the passed in argument isn't a symbol") do
+  klass = Class.new
+  assert_raise(TypeError) { klass.remove_method nil }
+  assert_raise(TypeError) { klass.remove_method 123 }
+  assert_raise(TypeError) { klass.remove_method 1.23 }
+  assert_raise(NameError) { klass.remove_method "hello" }
+  assert_raise(TypeError) { klass.remove_method Class.new }
+end
+
+assert('alias_method and remove_method') do
+  begin
+    Fixnum.alias_method :to_s_, :to_s
+    Fixnum.remove_method :to_s
+
+    assert_nothing_raised do
+      # segfaults if mrb_cptr is used
+      1.to_s
+    end
+  ensure
+    Fixnum.alias_method :to_s, :to_s_
+    Fixnum.remove_method :to_s_
+  end
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/README.md
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/README.md	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/README.md	(revision 439)
@@ -0,0 +1,59 @@
+mruby-method
+===
+
+A implementetion of class **Method** and **UnboundMethod** for mruby
+
+```ruby
+p Enumerable.instance_method(:find_all).source_location
+#=> ["mruby/mruby/mrblib/enum.rb", 148]
+```
+
+# Note
+
+`source_location` method need this configuration in build_config.rb
+
+```ruby
+MRuby::Build.new do |conf|
+  enable_debug
+end
+```
+
+# Supported Methods
+
+## Kernel
+
+- `Kernel#method`
+- `Kernel#singleton_method`
+
+## Module
+
+- `Module#instance_method`
+
+## Method class
+
+- `Method#name`
+- `Method#call`
+- `Method#super_method`
+- `Method#arity`
+- `Method#unbind`
+- `Method#[]`
+- `Method#owner`
+- `Method#receiver`
+- `Method#parameters`
+- `Method#source_location`
+- `Method#to_proc`
+
+## UnboundMethod class
+
+- `UnboundMethod#name`
+- `UnboundMethod#bind`
+- `UnboundMethod#super_method`
+- `UnboundMethod#arity`
+- `UnboundMethod#owner`
+- `UnboundMethod#parameters`
+- `UnboundMethod#source_location`
+
+# See also
+
+- https://ruby-doc.org/core-2.3.3/Method.html
+- https://ruby-doc.org/core-2.3.3/UnboundMethod.html
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/mrbgem.rake	(revision 439)
@@ -0,0 +1,7 @@
+MRuby::Gem::Specification.new('mruby-method') do |spec|
+  spec.license = 'MIT'
+  spec.author  = 'mruby developers'
+  spec.summary = 'Method and UnboundMethod class'
+
+  spec.add_dependency('mruby-proc-ext', :core => 'mruby-proc-ext')
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/mrblib/kernel.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/mrblib/kernel.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/mrblib/kernel.rb	(revision 439)
@@ -0,0 +1,10 @@
+module Kernel
+  def singleton_method(name)
+    m = method(name)
+    sc = (class <<self; self; end)
+    if m.owner != sc
+      raise NameError, "undefined method '#{name}' for class '#{sc}'"
+    end
+    m
+  end
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/mrblib/method.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/mrblib/method.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/mrblib/method.rb	(revision 439)
@@ -0,0 +1,16 @@
+class Method
+  def to_proc
+    m = self
+    lambda { |*args, &b|
+      m.call(*args, &b)
+    }
+  end
+
+  def <<(other)
+    ->(*args, &block) { call(other.call(*args, &block)) }
+  end
+
+  def >>(other)
+    ->(*args, &block) { other.call(call(*args, &block)) }
+  end
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/src/method.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/src/method.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/src/method.c	(revision 439)
@@ -0,0 +1,451 @@
+#include "mruby.h"
+#include "mruby/array.h"
+#include "mruby/class.h"
+#include "mruby/variable.h"
+#include "mruby/proc.h"
+#include "mruby/string.h"
+
+static struct RObject *
+method_object_alloc(mrb_state *mrb, struct RClass *mclass)
+{
+  return (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mclass);
+}
+
+static void
+bind_check(mrb_state *mrb, mrb_value recv, mrb_value owner)
+{
+  if (!mrb_module_p(owner) &&
+      mrb_class_ptr(owner) != mrb_obj_class(mrb, recv) &&
+      !mrb_obj_is_kind_of(mrb, recv, mrb_class_ptr(owner))) {
+    if (mrb_sclass_p(owner)) {
+      mrb_raise(mrb, E_TYPE_ERROR, "singleton method called for a different object");
+    } else {
+      mrb_raisef(mrb, E_TYPE_ERROR, "bind argument must be an instance of %v", owner);
+    }
+  }
+}
+
+static mrb_value
+unbound_method_bind(mrb_state *mrb, mrb_value self)
+{
+  struct RObject *me;
+  mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
+  mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
+  mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
+  mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass"));
+  mrb_value recv;
+
+  mrb_get_args(mrb, "o", &recv);
+  bind_check(mrb, recv, owner);
+  me = method_object_alloc(mrb, mrb_class_get(mrb, "Method"));
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_owner"), owner);
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_recv"), recv);
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_name"), name);
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_proc"), proc);
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_klass"), klass);
+
+  return mrb_obj_value(me);
+}
+
+#define IV_GET(value, name) mrb_iv_get(mrb, value, mrb_intern_lit(mrb, name))
+static mrb_value
+method_eql(mrb_state *mrb, mrb_value self)
+{
+  mrb_value other, receiver, orig_proc, other_proc;
+  struct RClass *owner, *klass;
+  struct RProc *orig_rproc, *other_rproc;
+
+  mrb_get_args(mrb, "o", &other);
+  if (!mrb_obj_is_instance_of(mrb, other, mrb_class(mrb, self)))
+    return mrb_false_value();
+
+  if (mrb_class(mrb, self) != mrb_class(mrb, other))
+    return mrb_false_value();
+
+  klass = mrb_class_ptr(IV_GET(self, "_klass"));
+  if (klass != mrb_class_ptr(IV_GET(other, "_klass")))
+    return mrb_false_value();
+
+  owner = mrb_class_ptr(IV_GET(self, "_owner"));
+  if (owner != mrb_class_ptr(IV_GET(other, "_owner")))
+    return mrb_false_value();
+
+  receiver = IV_GET(self, "_recv");
+  if (!mrb_obj_equal(mrb, receiver, IV_GET(other, "_recv")))
+    return mrb_false_value();
+
+  orig_proc = IV_GET(self, "_proc");
+  other_proc = IV_GET(other, "_proc");
+  if (mrb_nil_p(orig_proc) && mrb_nil_p(other_proc)) {
+    if (mrb_symbol(IV_GET(self, "_name")) == mrb_symbol(IV_GET(other, "_name")))
+      return mrb_true_value();
+    else
+      return mrb_false_value();
+  }
+
+  if (mrb_nil_p(orig_proc))
+    return mrb_false_value();
+  if (mrb_nil_p(other_proc))
+    return mrb_false_value();
+
+  orig_rproc = mrb_proc_ptr(orig_proc);
+  other_rproc = mrb_proc_ptr(other_proc);
+  if (MRB_PROC_CFUNC_P(orig_rproc)) {
+    if (!MRB_PROC_CFUNC_P(other_rproc))
+      return mrb_false_value();
+    if (orig_rproc->body.func != other_rproc->body.func)
+      return mrb_false_value();
+  }
+  else {
+    if (MRB_PROC_CFUNC_P(other_rproc))
+      return mrb_false_value();
+    if (orig_rproc->body.irep != other_rproc->body.irep)
+      return mrb_false_value();
+  }
+
+  return mrb_true_value();
+}
+
+#undef IV_GET
+
+static mrb_value
+mcall(mrb_state *mrb, mrb_value recv, mrb_value proc, mrb_value name, struct RClass *owner,
+      int argc, mrb_value *argv, mrb_value block)
+{
+  mrb_value ret;
+  mrb_sym orig_mid = mrb->c->ci->mid;
+
+  mrb->c->ci->mid = mrb_symbol(name);
+  if (mrb_nil_p(proc)) {
+    mrb_value missing_argv = mrb_ary_new_from_values(mrb, argc, argv);
+    mrb_ary_unshift(mrb, missing_argv, name);
+    ret = mrb_funcall_argv(mrb, recv, mrb_intern_lit(mrb, "method_missing"), argc + 1, RARRAY_PTR(missing_argv));
+  }
+  else if (!mrb_nil_p(block)) {
+    /*
+      workaround since `mrb_yield_with_class` does not support passing block as parameter
+      need new API that initializes `mrb->c->stack[argc+1]` with block passed by argument
+    */
+    ret = mrb_funcall_with_block(mrb, recv, mrb_symbol(name), argc, argv, block);
+  }
+  else {
+    ret = mrb_yield_with_class(mrb, proc, argc, argv, recv, owner);
+  }
+  mrb->c->ci->mid = orig_mid;
+  return ret;
+}
+
+static mrb_value
+method_call(mrb_state *mrb, mrb_value self)
+{
+  mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
+  mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
+  mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv"));
+  struct RClass *owner = mrb_class_ptr(mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner")));
+  mrb_int argc;
+  mrb_value *argv, block;
+
+  mrb_get_args(mrb, "*&", &argv, &argc, &block);
+  return mcall(mrb, recv, proc, name, owner, argc, argv, block);
+}
+
+static mrb_value
+method_bcall(mrb_state *mrb, mrb_value self)
+{
+  mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
+  mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
+  mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv"));
+  mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
+  mrb_int argc;
+  mrb_value *argv, block;
+
+  mrb_get_args(mrb, "o*&", &recv, &argv, &argc, &block);
+  bind_check(mrb, recv, owner);
+  return mcall(mrb, recv, proc, name, mrb_class_ptr(owner), argc, argv, block);
+}
+
+static mrb_value
+method_unbind(mrb_state *mrb, mrb_value self)
+{
+  struct RObject *ume;
+  mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
+  mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
+  mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
+  mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass"));
+
+  ume = method_object_alloc(mrb, mrb_class_get(mrb, "UnboundMethod"));
+  mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_owner"), owner);
+  mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_recv"), mrb_nil_value());
+  mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_name"), name);
+  mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_proc"), proc);
+  mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_klass"), klass);
+
+  return mrb_obj_value(ume);
+}
+
+static struct RProc *
+method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
+{
+  mrb_method_t m = mrb_method_search_vm(mrb, cp, mid);
+  if (MRB_METHOD_UNDEF_P(m))
+    return NULL;
+  if (MRB_METHOD_PROC_P(m))
+    return MRB_METHOD_PROC(m);
+  return mrb_proc_new_cfunc(mrb, MRB_METHOD_FUNC(m));
+}
+
+static mrb_value
+method_super_method(mrb_state *mrb, mrb_value self)
+{
+  mrb_value recv = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv"));
+  mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass"));
+  mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
+  mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
+  struct RClass *super, *rklass;
+  struct RProc *proc;
+  struct RObject *me;
+
+  switch (mrb_type(klass)) {
+    case MRB_TT_SCLASS:
+      super = mrb_class_ptr(klass)->super->super;
+      break;
+    case MRB_TT_ICLASS:
+      super = mrb_class_ptr(klass)->super;
+      break;
+    default:
+      super = mrb_class_ptr(owner)->super;
+      break;
+  }
+
+  proc = method_search_vm(mrb, &super, mrb_symbol(name));
+  if (!proc)
+    return mrb_nil_value();
+
+  rklass = super;
+  while (super->tt == MRB_TT_ICLASS)
+    super = super->c;
+
+  me = method_object_alloc(mrb, mrb_obj_class(mrb, self));
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_owner"), mrb_obj_value(super));
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_recv"), recv);
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_name"), name);
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_proc"), mrb_obj_value(proc));
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_klass"), mrb_obj_value(rklass));
+
+  return mrb_obj_value(me);
+}
+
+static mrb_value
+method_arity(mrb_state *mrb, mrb_value self)
+{
+  mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
+  mrb_int arity = mrb_nil_p(proc) ? -1 : mrb_proc_arity(mrb_proc_ptr(proc));
+  return mrb_fixnum_value(arity);
+}
+
+static mrb_value
+method_source_location(mrb_state *mrb, mrb_value self)
+{
+  mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
+  struct RProc *rproc;
+  struct RClass *orig;
+  mrb_value ret;
+
+  if (mrb_nil_p(proc))
+    return mrb_nil_value();
+
+  rproc = mrb_proc_ptr(proc);
+  orig = rproc->c;
+  rproc->c = mrb->proc_class;
+  ret = mrb_funcall(mrb, proc, "source_location", 0);
+  rproc->c = orig;
+  return ret;
+}
+
+static mrb_value
+method_parameters(mrb_state *mrb, mrb_value self)
+{
+  mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_proc"));
+  struct RProc *rproc;
+  struct RClass *orig;
+  mrb_value ret;
+
+  if (mrb_nil_p(proc)) {
+    mrb_value rest = mrb_symbol_value(mrb_intern_lit(mrb, "rest"));
+    mrb_value arest = mrb_ary_new_from_values(mrb, 1, &rest);
+    return mrb_ary_new_from_values(mrb, 1, &arest);
+  }
+
+  rproc = mrb_proc_ptr(proc);
+  orig = rproc->c;
+  rproc->c = mrb->proc_class;
+  ret = mrb_funcall(mrb, proc, "parameters", 0);
+  rproc->c = orig;
+  return ret;
+}
+
+static mrb_value
+method_to_s(mrb_state *mrb, mrb_value self)
+{
+  mrb_value owner = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
+  mrb_value klass = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_klass"));
+  mrb_value name = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
+  mrb_value str = mrb_str_new_lit(mrb, "#<");
+  struct RClass *rklass;
+
+  mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, self));
+  mrb_str_cat_lit(mrb, str, ": ");
+  rklass = mrb_class_ptr(klass);
+  if (mrb_class_ptr(owner) == rklass) {
+    mrb_str_concat(mrb, str, owner);
+    mrb_str_cat_lit(mrb, str, "#");
+    mrb_str_concat(mrb, str, name);
+  }
+  else {
+    mrb_str_cat_cstr(mrb, str, mrb_class_name(mrb, rklass));
+    mrb_str_cat_lit(mrb, str, "(");
+    mrb_str_concat(mrb, str, owner);
+    mrb_str_cat_lit(mrb, str, ")#");
+    mrb_str_concat(mrb, str, name);
+  }
+  mrb_str_cat_lit(mrb, str, ">");
+  return str;
+}
+
+static void
+mrb_search_method_owner(mrb_state *mrb, struct RClass *c, mrb_value obj, mrb_sym name, struct RClass **owner, struct RProc **proc, mrb_bool unbound)
+{
+  mrb_value ret;
+
+  *owner = c;
+  *proc = method_search_vm(mrb, owner, name);
+  if (!*proc) {
+    if (unbound) {
+      goto name_error;
+    }
+    if (!mrb_respond_to(mrb, obj, mrb_intern_lit(mrb, "respond_to_missing?"))) {
+      goto name_error;
+    }
+    ret = mrb_funcall(mrb, obj, "respond_to_missing?", 2, mrb_symbol_value(name), mrb_true_value());
+    if (!mrb_test(ret)) {
+      goto name_error;
+    }
+    *owner = c;
+  }
+
+  while ((*owner)->tt == MRB_TT_ICLASS)
+    *owner = (*owner)->c;
+
+  return;
+
+name_error:
+  mrb_raisef(mrb, E_NAME_ERROR, "undefined method '%n' for class '%C'", name, c);
+}
+
+static mrb_value
+mrb_kernel_method(mrb_state *mrb, mrb_value self)
+{
+  struct RClass *owner;
+  struct RProc *proc;
+  struct RObject *me;
+  mrb_sym name;
+
+  mrb_get_args(mrb, "n", &name);
+
+  mrb_search_method_owner(mrb, mrb_class(mrb, self), self, name, &owner, &proc, FALSE);
+
+  me = method_object_alloc(mrb, mrb_class_get(mrb, "Method"));
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_owner"), mrb_obj_value(owner));
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_recv"), self);
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_name"), mrb_symbol_value(name));
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_proc"), proc ? mrb_obj_value(proc) : mrb_nil_value());
+  mrb_obj_iv_set(mrb, me, mrb_intern_lit(mrb, "_klass"), mrb_obj_value(mrb_class(mrb, self)));
+
+  return mrb_obj_value(me);
+}
+
+static mrb_value
+mrb_module_instance_method(mrb_state *mrb, mrb_value self)
+{
+  struct RClass *owner;
+  struct RProc *proc;
+  struct RObject *ume;
+  mrb_sym name;
+
+  mrb_get_args(mrb, "n", &name);
+
+  mrb_search_method_owner(mrb, mrb_class_ptr(self), self, name, &owner, &proc, TRUE);
+
+  ume = method_object_alloc(mrb, mrb_class_get(mrb, "UnboundMethod"));
+  mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_owner"), mrb_obj_value(owner));
+  mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_recv"), mrb_nil_value());
+  mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_name"), mrb_symbol_value(name));
+  mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_proc"), proc ? mrb_obj_value(proc) : mrb_nil_value());
+  mrb_obj_iv_set(mrb, ume, mrb_intern_lit(mrb, "_klass"), self);
+
+  return mrb_obj_value(ume);
+}
+
+static mrb_value
+method_owner(mrb_state *mrb, mrb_value self)
+{
+  return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_owner"));
+}
+
+static mrb_value
+method_receiver(mrb_state *mrb, mrb_value self)
+{
+  return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_recv"));
+}
+
+static mrb_value
+method_name(mrb_state *mrb, mrb_value self)
+{
+  return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "_name"));
+}
+
+void
+mrb_mruby_method_gem_init(mrb_state* mrb)
+{
+  struct RClass *unbound_method = mrb_define_class(mrb, "UnboundMethod", mrb->object_class);
+  struct RClass *method = mrb_define_class(mrb, "Method", mrb->object_class);
+
+  mrb_undef_class_method(mrb, unbound_method, "new");
+  mrb_define_method(mrb, unbound_method, "bind", unbound_method_bind, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, unbound_method, "super_method", method_super_method, MRB_ARGS_NONE());
+  mrb_define_method(mrb, unbound_method, "==", method_eql, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, unbound_method, "eql?", method_eql, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, unbound_method, "to_s", method_to_s, MRB_ARGS_NONE());
+  mrb_define_method(mrb, unbound_method, "inspect", method_to_s, MRB_ARGS_NONE());
+  mrb_define_method(mrb, unbound_method, "arity", method_arity, MRB_ARGS_NONE());
+  mrb_define_method(mrb, unbound_method, "source_location", method_source_location, MRB_ARGS_NONE());
+  mrb_define_method(mrb, unbound_method, "parameters", method_parameters, MRB_ARGS_NONE());
+  mrb_define_method(mrb, unbound_method, "bind_call", method_bcall, MRB_ARGS_REQ(1)|MRB_ARGS_ANY());
+  mrb_define_method(mrb, unbound_method, "owner", method_owner, MRB_ARGS_NONE());
+  mrb_define_method(mrb, unbound_method, "name", method_name, MRB_ARGS_NONE());
+
+  mrb_undef_class_method(mrb, method, "new");
+  mrb_define_method(mrb, method, "==", method_eql, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, method, "eql?", method_eql, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, method, "to_s", method_to_s, MRB_ARGS_NONE());
+  mrb_define_method(mrb, method, "inspect", method_to_s, MRB_ARGS_NONE());
+  mrb_define_method(mrb, method, "call", method_call, MRB_ARGS_ANY());
+  mrb_define_method(mrb, method, "[]", method_call, MRB_ARGS_ANY());
+  mrb_define_method(mrb, method, "unbind", method_unbind, MRB_ARGS_NONE());
+  mrb_define_method(mrb, method, "super_method", method_super_method, MRB_ARGS_NONE());
+  mrb_define_method(mrb, method, "arity", method_arity, MRB_ARGS_NONE());
+  mrb_define_method(mrb, method, "source_location", method_source_location, MRB_ARGS_NONE());
+  mrb_define_method(mrb, method, "parameters", method_parameters, MRB_ARGS_NONE());
+  mrb_define_method(mrb, method, "owner", method_owner, MRB_ARGS_NONE());
+  mrb_define_method(mrb, method, "receiver", method_receiver, MRB_ARGS_NONE());
+  mrb_define_method(mrb, method, "name", method_name, MRB_ARGS_NONE());
+
+  mrb_define_method(mrb, mrb->kernel_module, "method", mrb_kernel_method, MRB_ARGS_REQ(1));
+
+  mrb_define_method(mrb, mrb->module_class, "instance_method", mrb_module_instance_method, MRB_ARGS_REQ(1));
+}
+
+void
+mrb_mruby_method_gem_final(mrb_state* mrb)
+{
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/test/method.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/test/method.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-method/test/method.rb	(revision 439)
@@ -0,0 +1,451 @@
+class Base
+  def foo() :base end
+end
+
+class Derived < Base
+  def foo() :derived end
+end
+
+class Interpreter
+  attr_accessor :ret
+
+  def do_a() @ret += "there, "; end
+  def do_d() @ret += "Hello ";  end
+  def do_e() @ret += "!\n";     end
+  def do_v() @ret += "Dave";    end
+  Dispatcher = {
+    "a" => instance_method(:do_a),
+    "d" => instance_method(:do_d),
+    "e" => instance_method(:do_e),
+    "v" => instance_method(:do_v)
+  }
+  def interpret(string)
+    @ret = ""
+    string.split("").each {|b| Dispatcher[b].bind(self).call }
+  end
+end
+
+assert 'demo' do
+  interpreter = Interpreter.new
+  interpreter.interpret('dave')
+  assert_equal "Hello there, Dave!\n", interpreter.ret
+end
+
+assert 'Method#arity' do
+  Class.new {
+    attr_accessor :done
+    def initialize; @done = false; end
+    def m0() end
+    def m1(a) end
+    def m2(a, b) end
+    def mo1(a = nil, &b) end
+    def mo2(a, b = nil) end
+    def mo3(*a) end
+    def mo4(a, *b, &c) end
+    def mo5(a, *b, c) end
+    def mo6(a, *b, c, &d) end
+    def mo7(a, b = nil, *c, d, &e) end
+    def ma1((a), &b) nil && a end
+
+    def run
+      assert_equal(0, method(:m0).arity)
+      assert_equal(1, method(:m1).arity)
+      assert_equal(2, method(:m2).arity)
+      assert_equal(-1, method(:mo1).arity)
+      assert_equal(-2, method(:mo2).arity)
+      assert_equal(-1, method(:mo3).arity)
+      assert_equal(-2, method(:mo4).arity)
+      assert_equal(-3, method(:mo5).arity)
+      assert_equal(-3, method(:mo6).arity)
+      assert_equal(-3, method(:mo7).arity)
+      assert_equal(1, method(:ma1).arity)
+
+      assert_equal(-1, method(:__send__).arity)
+      assert_equal(-1, method(:nothing).arity)
+    end
+
+    def respond_to_missing?(m, b)
+      m == :nothing
+    end
+  }.new.run
+end
+
+assert 'Method and UnboundMethod should not be have a `new` method' do
+  assert_raise(NoMethodError){ Method.new }
+  assert_raise(NoMethodError){ UnboundMethod.new }
+end
+
+assert 'instance' do
+  assert_kind_of Method, 1.method(:+)
+  assert_kind_of UnboundMethod, Fixnum.instance_method(:+)
+end
+
+assert 'Method#call' do
+  assert_equal 3, 1.method(:+).call(2)
+  assert_equal "ab", "a".method(:+)["b"]
+  klass = Class.new {
+    def foo; 42; end
+  }
+  klass2 = Class.new(klass) {
+    def foo; super; end
+  }
+  assert_equal 42, klass2.new.method(:foo).call
+
+  i = Class.new {
+   def bar
+     yield 3
+   end
+  }.new
+  assert_raise(LocalJumpError) { i.method(:bar).call }
+  assert_equal 3, i.method(:bar).call { |i| i }
+end
+
+assert 'Method#call for regression' do
+  obj = BasicObject.new
+  assert_equal String, Kernel.instance_method(:inspect).bind(obj).call().class, "https://github.com/ksss/mruby-method/issues/4"
+end
+
+assert 'Method#call with undefined method' do
+  c = Class.new {
+    attr_accessor :m, :argv
+    def respond_to_missing?(m, b)
+      m == :foo
+    end
+
+    def method_missing(m, *argv)
+      @m = m
+      @argv = argv
+      super
+    end
+  }
+  cc = c.new
+  assert_raise(NameError) { cc.method(:nothing) }
+  assert_kind_of Method, cc.method(:foo)
+  assert_raise(NoMethodError) { cc.method(:foo).call(:arg1, :arg2) }
+  assert_equal :foo, cc.m
+  assert_equal [:arg1, :arg2], cc.argv
+
+  cc = c.new
+  m = cc.method(:foo)
+  c.class_eval do
+    def foo
+      :ng
+    end
+  end
+  assert_raise(NoMethodError) { m.call(:arg1, :arg2) }
+end
+
+assert 'Method#source_location' do
+  skip if proc{}.source_location.nil?
+
+  filename = __FILE__
+  klass = Class.new
+
+  lineno = __LINE__ + 1
+  klass.define_method(:find_me_if_you_can) {}
+  assert_equal [filename, lineno], klass.new.method(:find_me_if_you_can).source_location
+
+  lineno = __LINE__ + 1
+  class <<klass; define_method(:s_find_me_if_you_can) {}; end
+  assert_equal [filename, lineno], klass.method(:s_find_me_if_you_can).source_location
+
+  klass = Class.new { def respond_to_missing?(m, b); m == :nothing; end }
+  assert_nil klass.new.method(:nothing).source_location
+end
+
+assert 'UnboundMethod#source_location' do
+  skip if proc{}.source_location.nil?
+
+  filename = __FILE__
+  klass = Class.new {
+    def respond_to_missing?(m, b)
+      m == :nothing
+    end
+  }
+
+  lineno = __LINE__ + 1
+  klass.define_method(:find_me_if_you_can) {}
+  assert_equal [filename, lineno], klass.instance_method(:find_me_if_you_can).source_location
+  assert_nil klass.new.method(:nothing).unbind.source_location
+end
+
+assert 'Method#parameters' do
+  klass = Class.new {
+    def foo(a, b=nil, *c) end
+    def respond_to_missing?(m, b)
+      m == :missing
+    end
+  }
+  assert_equal [[:req, :a], [:opt, :b], [:rest, :c]], klass.new.method(:foo).parameters
+  assert_equal [[:rest]], klass.new.method(:missing).parameters
+end
+
+assert 'UnboundMethod#parameters' do
+  klass = Class.new {
+    def foo(a, b=nil, *c) end
+    def respond_to_missing?(m, b)
+      m == :nothing
+    end
+  }
+  assert_equal [[:req, :a], [:opt, :b], [:rest, :c]], klass.instance_method(:foo).parameters
+  assert_equal [[:rest]], klass.new.method(:nothing).unbind.parameters
+end
+
+assert 'Method#to_proc' do
+  m = 3.method(:+)
+  assert_kind_of Proc, m.to_proc
+  assert_equal 7, m.call(4)
+
+  o = Object.new
+  def o.foo(a, b=nil, *c)
+    [a, b, c]
+  end
+  assert_equal [:bar, nil, []], o.method(:foo).to_proc.call(:bar)
+#  We can fix this issue but leave until the problem
+#  assert_equal o.method(:foo).arity, o.method(:foo).to_proc.arity
+
+  def o.bar
+    yield 39
+  end
+  assert_equal 42, o.bar(&3.method(:+))
+end
+
+assert 'to_s' do
+  o = Object.new
+  def o.foo; end
+  m = o.method(:foo)
+  assert_equal("#<UnboundMethod: #{ class << o; self; end.inspect }#foo>", m.unbind.inspect)
+
+  c = Class.new
+  c.class_eval { def foo; end; }
+  m = c.new.method(:foo)
+  assert_equal("#<Method: #{ c.inspect }#foo>", m.inspect)
+  m = c.instance_method(:foo)
+  assert_equal("#<UnboundMethod: #{ c.inspect }#foo>", m.inspect)
+end
+
+assert 'owner' do
+  c = Class.new do
+    def foo; end
+    def self.bar; end
+  end
+  m = Module.new do
+    def baz; end
+  end
+  c.include(m)
+  c2 = Class.new(c)
+
+  assert_equal(c, c.instance_method(:foo).owner)
+  assert_equal(c, c2.instance_method(:foo).owner)
+
+  assert_equal(c, c.new.method(:foo).owner)
+  assert_equal(c, c2.new.method(:foo).owner)
+  assert_equal((class <<c; self; end), c2.method(:bar).owner)
+end
+
+assert 'owner missing' do
+  c = Class.new do
+    def respond_to_missing?(name, bool)
+      name == :foo
+    end
+  end
+  c2 = Class.new(c)
+  assert_equal(c, c.new.method(:foo).owner)
+  assert_equal(c2, c2.new.method(:foo).owner)
+end
+
+assert 'receiver name owner' do
+  o = Object.new
+  def o.foo; end
+  m = o.method(:foo)
+  assert_equal(o, m.receiver)
+  assert_equal(:foo, m.name)
+  assert_equal(class << o; self; end, m.owner)
+  assert_equal(:foo, m.unbind.name)
+  assert_equal(class << o; self; end, m.unbind.owner)
+end
+
+assert 'Method#unbind' do
+  assert_equal(:derived, Derived.new.foo)
+  um = Derived.new.method(:foo).unbind
+  assert_kind_of(UnboundMethod, um)
+  Derived.class_eval do
+    def foo() :changed end
+  end
+  assert_equal(:changed, Derived.new.foo)
+  assert_equal(:changed, Derived.new.foo{})
+  assert_equal(:derived, um.bind(Derived.new).call)
+  assert_raise(TypeError) do
+    um.bind(Base.new)
+  end
+
+  # TODO:
+  #  Block passed method not handled correctly with workaround.
+  #  See comment near `mrb_funcall_with_block` for detail.
+  # assert_equal(:derived, um.bind(Derived.new).call{})
+end
+
+assert 'Kernel#method' do
+  c1 = Class.new {
+    def foo; :foo; end
+  }
+  o = c1.new
+  assert_kind_of Method, o.method(:foo)
+  assert_kind_of Method, o.method('foo')
+  assert_raise(TypeError) { o.method(nil) }
+  assert_raise(NameError) { o.method('bar') }
+  assert_raise(NameError) { o.method(:bar) }
+end
+
+assert "Module#instance_method" do
+  assert_kind_of UnboundMethod, Object.instance_method(:object_id)
+  assert_raise(NameError) { Object.instance_method(:nothing) }
+  c = Class.new {
+    def respond_to_missing?(m, b)
+      false
+    end
+  }
+  assert_raise(NameError) { c.instance_method(:nothing) }
+end
+
+assert 'Kernel#singleton_method' do
+  c1 = Class.new {
+    def foo; :foo; end
+  }
+  o = c1.new
+  def o.bar; :bar; end
+  assert_kind_of Method, o.method(:foo)
+  assert_raise(NameError) { o.singleton_method(:foo) }
+  assert_kind_of Method, o.singleton_method(:bar)
+  assert_raise(TypeError) { o.singleton_method(nil) }
+  m = assert_nothing_raised(NameError) { break o.singleton_method(:bar) }
+  assert_equal(:bar, m.call)
+end
+
+assert 'Method#super_method' do
+  o = Derived.new
+  m = o.method(:foo).super_method
+  assert_equal(Base, m.owner)
+  assert_true(o.equal? m.receiver)
+  assert_equal(:foo, m.name)
+  assert_nil(m.super_method)
+
+  c = Class.new {
+    def foo; end
+  }
+  o = c.new
+  o.extend Module.new {
+    def foo; end
+  }
+  assert_equal c, o.method(:foo).super_method.owner
+  assert_equal :foo, o.method(:foo).super_method.name
+  assert_equal o, o.method(:foo).super_method.receiver
+end
+
+assert 'Method#==' do
+  o = Object.new
+  class << o
+    def foo; end
+  end
+  assert_not_equal(o.method(:foo), nil)
+  m = o.method(:foo)
+  def m.foo; end
+  # TODO: assert_not_equal(o.method(:foo), m)
+  assert_equal(o.method(:foo), o.method(:foo))
+  # TODO: assert_false(o.method(:foo).eql? m)
+  assert_true(o.method(:foo).eql? o.method(:foo))
+
+  assert_false(0.method(:+) == 1.method(:+))
+  assert_false(0.method(:+) == 0.method(:-))
+  a = 0.method(:+)
+  assert_true(a.method(:==) == a.method(:eql?))
+end
+
+assert "Method#initialize_copy" do
+  c = Class.new {
+    def foo
+    end
+  }.new
+  m1 = c.method(:foo)
+  m2 = m1.clone
+  assert_equal(m1, m2)
+end
+
+assert "Method#<< and Method#>>" do
+  obj = Object.new
+  class << obj
+    def mul2(n); n * 2; end
+    def add3(n); n + 3; end
+  end
+
+  f = obj.method(:mul2)
+  g = obj.method(:add3)
+
+  m1 = f << g
+  assert_kind_of Proc, m1
+  assert_equal 16, m1.call(5)
+
+  m2 = f >> g
+  assert_kind_of Proc, m2
+  assert_equal 13, m2.call(5)
+end
+
+assert 'UnboundMethod#arity' do
+  c = Class.new {
+    def foo(a, b)
+    end
+
+    def respond_to_missing?(m, b)
+      m == :nothing
+    end
+  }
+  assert_equal 2, c.instance_method(:foo).arity
+  assert_equal(-1, c.new.method(:nothing).unbind.arity)
+end
+
+assert 'UnboundMethod#==' do
+  assert_false(Fixnum.instance_method(:+) == Fixnum.instance_method(:-))
+  assert_true(Fixnum.instance_method(:+) == Fixnum.instance_method(:+))
+  assert_false(Fixnum.instance_method(:+) == Float.instance_method(:+))
+  assert_true(UnboundMethod.instance_method(:==) == UnboundMethod.instance_method(:eql?))
+end
+
+assert 'UnboundMethod#super_method' do
+  m = Derived.instance_method(:foo)
+  m = m.super_method
+  assert_equal(Base.instance_method(:foo), m)
+  assert_nil(m.super_method)
+
+  m = Object.instance_method(:object_id)
+  assert_nil(m.super_method)
+end
+
+assert 'UnboundMethod#bind' do
+  m = Module.new{ def meth() :meth end }.instance_method(:meth)
+  assert_raise(ArgumentError) { m.bind }
+  assert_kind_of Method, m.bind(1)
+  assert_kind_of Method, m.bind(:sym)
+  assert_kind_of Method, m.bind(Object.new)
+  assert_equal(:meth, m.bind(1).call)
+  assert_equal(:meth, m.bind(:sym).call)
+  assert_equal(:meth, m.bind(Object.new).call)
+  sc = nil
+  Class.new {
+    sc = class << self
+      def foo
+      end
+      self
+    end
+  }
+  assert_raise(TypeError) { sc.instance_method(:foo).bind([]) }
+  assert_raise(TypeError) { Array.instance_method(:each).bind(1) }
+  assert_kind_of Method, Object.instance_method(:object_id).bind(Object.new)
+end
+
+assert 'UnboundMethod#bind_call' do
+  m = Array.instance_method(:size)
+  assert_equal(:size, m.name)
+  assert_equal(0, m.bind_call([]))
+  assert_equal(1, m.bind_call([1]))
+  assert_equal(2, m.bind_call([1,2]))
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb	(revision 439)
@@ -1,7 +1,3 @@
-module Integral
-  def div(other)
-    self.divmod(other)[0]
-  end
-
+class Numeric
   def zero?
     self == 0
@@ -15,3 +11,11 @@
     end
   end
+
+  def positive?
+    self > 0
+  end
+
+  def negative?
+    self < 0
+  end
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-numeric-ext/src/numeric_ext.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-numeric-ext/src/numeric_ext.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-numeric-ext/src/numeric_ext.c	(revision 439)
@@ -1,18 +1,52 @@
 #include <limits.h>
 #include <mruby.h>
+#include <mruby/numeric.h>
 
+/*
+ *  call-seq:
+ *     int.allbits?(mask)  ->  true or false
+ *
+ *  Returns +true+ if all bits of <code>+int+ & +mask+</code> are 1.
+ */
 static mrb_value
-mrb_int_chr(mrb_state *mrb, mrb_value x)
+mrb_int_allbits(mrb_state *mrb, mrb_value self)
 {
-  mrb_int chr;
-  char c;
+  mrb_int n, m;
 
-  chr = mrb_fixnum(x);
-  if (chr >= (1 << CHAR_BIT)) {
-    mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", x);
-  }
-  c = (char)chr;
+  mrb_get_args(mrb, "i", &m);
+  n = mrb_int(mrb, self);
+  return mrb_bool_value((n & m) == m);
+}
 
-  return mrb_str_new(mrb, &c, 1);
+/*
+ *  call-seq:
+ *     int.anybits?(mask)  ->  true or false
+ *
+ *  Returns +true+ if any bits of <code>+int+ & +mask+</code> are 1.
+ */
+static mrb_value
+mrb_int_anybits(mrb_state *mrb, mrb_value self)
+{
+  mrb_int n, m;
+
+  mrb_get_args(mrb, "i", &m);
+  n = mrb_int(mrb, self);
+  return mrb_bool_value((n & m) != 0);
+}
+
+/*
+ *  call-seq:
+ *     int.nobits?(mask)  ->  true or false
+ *
+ *  Returns +true+ if no bits of <code>+int+ & +mask+</code> are 1.
+ */
+static mrb_value
+mrb_int_nobits(mrb_state *mrb, mrb_value self)
+{
+  mrb_int n, m;
+
+  mrb_get_args(mrb, "i", &m);
+  n = mrb_int(mrb, self);
+  return mrb_bool_value((n & m) == 0);
 }
 
@@ -20,7 +54,22 @@
 mrb_mruby_numeric_ext_gem_init(mrb_state* mrb)
 {
-  struct RClass *i = mrb_class_get(mrb, "Integer");
+  struct RClass *i = mrb_module_get(mrb, "Integral");
 
-  mrb_define_method(mrb, i, "chr", mrb_int_chr, MRB_ARGS_NONE());
+  mrb_define_method(mrb, i, "allbits?", mrb_int_allbits, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, i, "anybits?", mrb_int_anybits, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, i, "nobits?", mrb_int_nobits, MRB_ARGS_REQ(1));
+
+#ifndef MRB_WITHOUT_FLOAT
+  mrb_define_const(mrb, mrb->float_class, "RADIX",        mrb_fixnum_value(MRB_FLT_RADIX));
+  mrb_define_const(mrb, mrb->float_class, "MANT_DIG",     mrb_fixnum_value(MRB_FLT_MANT_DIG));
+  mrb_define_const(mrb, mrb->float_class, "EPSILON",      mrb_float_value(mrb, MRB_FLT_EPSILON));
+  mrb_define_const(mrb, mrb->float_class, "DIG",          mrb_fixnum_value(MRB_FLT_DIG));
+  mrb_define_const(mrb, mrb->float_class, "MIN_EXP",      mrb_fixnum_value(MRB_FLT_MIN_EXP));
+  mrb_define_const(mrb, mrb->float_class, "MIN",          mrb_float_value(mrb, MRB_FLT_MIN));
+  mrb_define_const(mrb, mrb->float_class, "MIN_10_EXP",   mrb_fixnum_value(MRB_FLT_MIN_10_EXP));
+  mrb_define_const(mrb, mrb->float_class, "MAX_EXP",      mrb_fixnum_value(MRB_FLT_MAX_EXP));
+  mrb_define_const(mrb, mrb->float_class, "MAX",          mrb_float_value(mrb, MRB_FLT_MAX));
+  mrb_define_const(mrb, mrb->float_class, "MAX_10_EXP",   mrb_fixnum_value(MRB_FLT_MAX_10_EXP));
+#endif /* MRB_WITHOUT_FLOAT */
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-numeric-ext/test/numeric.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-numeric-ext/test/numeric.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-numeric-ext/test/numeric.rb	(revision 439)
@@ -1,12 +1,4 @@
 ##
 # Numeric(Ext) Test
-
-assert('Integer#chr') do
-  assert_equal("A", 65.chr)
-  assert_equal("B", 0x42.chr)
-
-  # multibyte encoding (not support yet)
-  assert_raise(RangeError) { 256.chr }
-end
 
 assert('Integer#div') do
@@ -15,4 +7,5 @@
 
 assert('Float#div') do
+  skip unless Object.const_defined?(:Float)
   assert_float 52, 365.2425.div(7)
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-object-ext/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-object-ext/mrbgem.rake	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-object-ext/mrbgem.rake	(revision 439)
@@ -2,4 +2,4 @@
   spec.license = 'MIT'
   spec.author  = 'mruby developers'
-  spec.summary = 'Object class extension'
+  spec.summary = 'extensional methods shared by all objects'
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-object-ext/mrblib/object.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-object-ext/mrblib/object.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-object-ext/mrblib/object.rb	(revision 439)
@@ -1,3 +1,17 @@
-class Object
+module Kernel
+  # call-seq:
+  #   obj.yield_self {|_obj|...} -> an_object
+  #   obj.then {|_obj|...}       -> an_object
+  #
+  # Yields <i>obj</i> and returns the result.
+  #
+  #   'my string'.yield_self {|s|s.upcase} #=> "MY STRING"
+  #
+  def yield_self(&block)
+    return to_enum :yield_self unless block
+    block.call(self)
+  end
+  alias then yield_self
+
   ##
   #  call-seq:
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-object-ext/src/object.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-object-ext/src/object.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-object-ext/src/object.c	(revision 439)
@@ -2,4 +2,5 @@
 #include <mruby/array.h>
 #include <mruby/class.h>
+#include <mruby/hash.h>
 #include <mruby/proc.h>
 
@@ -17,4 +18,5 @@
 }
 
+#ifndef MRB_WITHOUT_FLOAT
 /*
  *  call-seq:
@@ -28,4 +30,18 @@
 {
   return mrb_float_value(mrb, 0.0);
+}
+#endif
+
+/*
+ *  call-seq:
+ *     nil.to_h    -> {}
+ *
+ *  Always returns an empty hash.
+ */
+
+static mrb_value
+nil_to_h(mrb_state *mrb, mrb_value obj)
+{
+  return mrb_hash_new(mrb);
 }
 
@@ -41,4 +57,20 @@
 {
   return mrb_fixnum_value(0);
+}
+
+/*
+ *  call-seq:
+ *     obj.itself -> an_object
+ *
+ *  Returns <i>obj</i>.
+ *
+ *      string = 'my string' #=> "my string"
+ *      string.itself.object_id == string.object_id #=> true
+ *
+ */
+static mrb_value
+mrb_f_itself(mrb_state *mrb, mrb_value self)
+{
+  return self;
 }
 
@@ -68,16 +100,13 @@
   mrb_value blk;
   struct RClass *c;
-  mrb_value args;
 
-  mrb_get_args(mrb, "*&", &argv, &argc, &blk);
-
-  if (mrb_nil_p(blk)) {
-    mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
-  }
+  mrb_get_args(mrb, "*&!", &argv, &argc, &blk);
 
   switch (mrb_type(self)) {
   case MRB_TT_SYMBOL:
   case MRB_TT_FIXNUM:
+#ifndef MRB_WITHOUT_FLOAT
   case MRB_TT_FLOAT:
+#endif
     c = NULL;
     break;
@@ -86,6 +115,4 @@
     break;
   }
-  args = mrb_ary_new_from_values(mrb, argc, argv);
-  argv = RARRAY_PTR(args);
   mrb->c->ci->target_class = c;
   return mrb_yield_cont(mrb, blk, self, argc, argv);
@@ -98,8 +125,13 @@
 
   mrb_define_method(mrb, n, "to_a", nil_to_a,       MRB_ARGS_NONE());
+#ifndef MRB_WITHOUT_FLOAT
   mrb_define_method(mrb, n, "to_f", nil_to_f,       MRB_ARGS_NONE());
+#endif
+  mrb_define_method(mrb, n, "to_h", nil_to_h,       MRB_ARGS_NONE());
   mrb_define_method(mrb, n, "to_i", nil_to_i,       MRB_ARGS_NONE());
 
-  mrb_define_method(mrb, mrb->kernel_module, "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK());
+  mrb_define_method(mrb, mrb->kernel_module, "itself", mrb_f_itself, MRB_ARGS_NONE());
+
+  mrb_define_method(mrb, mrb_class_get(mrb, "BasicObject"), "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK());
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-object-ext/test/nil.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-object-ext/test/nil.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-object-ext/test/nil.rb	(revision 439)
@@ -4,5 +4,10 @@
 
 assert('NilClass#to_f') do
+  skip unless Object.const_defined?(:Float)
   assert_equal 0.0, nil.to_f
+end
+
+assert('NilClass#to_h') do
+  assert_equal Hash.new, nil.to_h
 end
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-objectspace/src/mruby_objectspace.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-objectspace/src/mruby_objectspace.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-objectspace/src/mruby_objectspace.c	(revision 439)
@@ -58,5 +58,5 @@
   }
 
-  if (!mrb_test(mrb_hash_empty_p(mrb, hash))) {
+  if (!mrb_hash_empty_p(mrb, hash)) {
     mrb_hash_clear(mrb, hash);
   }
@@ -162,9 +162,5 @@
   mrb_value cls = mrb_nil_value();
   struct os_each_object_data d;
-  mrb_get_args(mrb, "&|C", &d.block, &cls);
-
-  if (mrb_nil_p(d.block)) {
-    mrb_raise(mrb, E_ARGUMENT_ERROR, "Expected block in ObjectSpace.each_object.");
-  }
+  mrb_get_args(mrb, "&!|C", &d.block, &cls);
 
   d.target_module = mrb_nil_p(cls) ? NULL : mrb_class_ptr(cls);
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-objectspace/test/objectspace.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-objectspace/test/objectspace.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-objectspace/test/objectspace.rb	(revision 439)
@@ -1,5 +1,5 @@
 assert('ObjectSpace.count_objects') do
   h = {}
-  f = Fiber.new {} if Object.const_defined? :Fiber
+  f = Fiber.new {} if Object.const_defined?(:Fiber)
   ObjectSpace.count_objects(h)
   assert_kind_of(Hash, h)
@@ -32,6 +32,6 @@
     objs << {}
   end
+  ObjectSpace.count_objects(h)
   objs = nil
-  ObjectSpace.count_objects(h)
   GC.start
   ObjectSpace.count_objects(h_after)
@@ -57,4 +57,4 @@
 
 assert 'Check class pointer of ObjectSpace.each_object.' do
-  ObjectSpace.each_object { |obj| !obj }
+  assert_nothing_raised { ObjectSpace.each_object { |obj| !obj } }
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/README.md
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/README.md	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/README.md	(revision 439)
@@ -0,0 +1,71 @@
+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`)
+ - U : UTF-8 character
+ - V : 32-bit unsigned, VAX (little-endian) byte order
+ - v : 16-bit unsigned, VAX (little-endian) byte order
+ - x : null byte
+ - Z : same as "a", except that null is added with *
+
+
+
+## License
+
+Copyright (c) 2012 Internet Initiative Japan Inc.
+Copyright (c) 2017 mruby developers
+
+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/mruby-2.1.1/mrbgems/mruby-pack/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/mrbgem.rake	(revision 439)
@@ -0,0 +1,7 @@
+MRuby::Gem::Specification.new('mruby-pack') do |spec|
+  spec.license = 'MIT'
+  spec.authors = ['Internet Initiative Japan Inc.', 'mruby developers']
+  spec.summary = 'Array#pack and String#unpack method'
+
+  spec.cc.include_paths << "#{build.root}/src"
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/src/pack.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/src/pack.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/src/pack.c	(revision 439)
@@ -0,0 +1,1340 @@
+/*
+ ** pack.c - Array#pack, String#unpack
+ */
+
+#include <mruby.h>
+
+#ifdef MRB_DISABLE_STDIO
+# error pack/unpack conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
+#endif
+
+#include "mruby/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 <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
+
+const static unsigned char base64chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static unsigned char base64_dec_tab[128];
+
+#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER__)
+# define BYTE_ORDER __BYTE_ORDER__
+#endif
+#if !defined(BIG_ENDIAN) && defined(__ORDER_BIG_ENDIAN__)
+# define BIG_ENDIAN __ORDER_BIG_ENDIAN__
+#endif
+#if !defined(LITTLE_ENDIAN) && defined(__ORDER_LITTLE_ENDIAN__)
+# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
+#endif
+
+#ifdef BYTE_ORDER
+# if BYTE_ORDER == BIG_ENDIAN
+#  define littleendian 0
+#  define check_little_endian() (void)0
+# elif BYTE_ORDER == LITTLE_ENDIAN
+#  define littleendian 1
+#  define check_little_endian() (void)0
+# endif
+#endif
+#ifndef littleendian
+/* can't distinguish endian in compile time */
+static int littleendian = 0;
+static void
+check_little_endian(void)
+{
+  unsigned int n = 1;
+  littleendian = (*(unsigned char *)&n == 1);
+}
+#endif
+
+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['+'+0] = 62;
+  base64_dec_tab['/'+0] = 63;
+  base64_dec_tab['='+0] = PACK_BASE64_PADDING;
+}
+
+static mrb_value
+str_len_ensure(mrb_state *mrb, mrb_value str, mrb_int len)
+{
+  mrb_int n = RSTRING_LEN(str);
+  if (len < 0) {
+    mrb_raise(mrb, E_RANGE_ERROR, "negative (or overflowed) integer");
+  }
+  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] = (char)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)
+{
+  uint16_t n;
+
+  str = str_len_ensure(mrb, str, sidx + 2);
+  n = (uint16_t)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)
+{
+  uint32_t n;
+
+  str = str_len_ensure(mrb, str, sidx + 4);
+  n = (uint32_t)mrb_fixnum(o);
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+    RSTRING_PTR(str)[sidx+0] = (char)(n & 0xff);
+    RSTRING_PTR(str)[sidx+1] = (char)(n >> 8);
+    RSTRING_PTR(str)[sidx+2] = (char)(n >> 16);
+    RSTRING_PTR(str)[sidx+3] = (char)(n >> 24);
+  } else {
+    RSTRING_PTR(str)[sidx+0] = (char)(n >> 24);
+    RSTRING_PTR(str)[sidx+1] = (char)(n >> 16);
+    RSTRING_PTR(str)[sidx+2] = (char)(n >> 8);
+    RSTRING_PTR(str)[sidx+3] = (char)(n & 0xff);
+  }
+  return 4;
+}
+
+static int
+unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags)
+{
+#ifndef MRB_INT64
+  char msg[60];
+#endif
+  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;
+#ifndef MRB_INT64
+    if (!FIXABLE(sl)) {
+      snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %" PRId32, sl);
+      mrb_raise(mrb, E_RANGE_ERROR, msg);
+    }
+#endif
+    n = sl;
+  } else {
+#ifndef MRB_INT64
+    if (!POSFIXABLE(ul)) {
+      snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %" PRIu32, ul);
+      mrb_raise(mrb, E_RANGE_ERROR, msg);
+    }
+#endif
+    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)
+{
+  uint64_t n;
+
+  str = str_len_ensure(mrb, str, sidx + 8);
+  n = (uint64_t)mrb_fixnum(o);
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+    RSTRING_PTR(str)[sidx+0] = (char)(n & 0xff);
+    RSTRING_PTR(str)[sidx+1] = (char)(n >> 8);
+    RSTRING_PTR(str)[sidx+2] = (char)(n >> 16);
+    RSTRING_PTR(str)[sidx+3] = (char)(n >> 24);
+    RSTRING_PTR(str)[sidx+4] = (char)(n >> 32);
+    RSTRING_PTR(str)[sidx+5] = (char)(n >> 40);
+    RSTRING_PTR(str)[sidx+6] = (char)(n >> 48);
+    RSTRING_PTR(str)[sidx+7] = (char)(n >> 56);
+  } else {
+    RSTRING_PTR(str)[sidx+0] = (char)(n >> 56);
+    RSTRING_PTR(str)[sidx+1] = (char)(n >> 48);
+    RSTRING_PTR(str)[sidx+2] = (char)(n >> 40);
+    RSTRING_PTR(str)[sidx+3] = (char)(n >> 32);
+    RSTRING_PTR(str)[sidx+4] = (char)(n >> 24);
+    RSTRING_PTR(str)[sidx+5] = (char)(n >> 16);
+    RSTRING_PTR(str)[sidx+6] = (char)(n >> 8);
+    RSTRING_PTR(str)[sidx+7] = (char)(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: %" PRId64, sll);
+      mrb_raise(mrb, E_RANGE_ERROR, msg);
+    }
+    n = sll;
+  } else {
+    if (!POSFIXABLE(ull)) {
+      snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %" PRIu64, ull);
+      mrb_raise(mrb, E_RANGE_ERROR, msg);
+    }
+    n = ull;
+  }
+  mrb_ary_push(mrb, ary, mrb_fixnum_value(n));
+  return 8;
+}
+
+#ifndef MRB_WITHOUT_FLOAT
+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) {
+    if (littleendian) {
+      memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
+    }
+    else {
+      for (i = 0; i < 8; ++i) {
+        RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1];
+      }
+    }
+  } else {
+    if (littleendian) {
+      for (i = 0; i < 8; ++i) {
+        RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1];
+      }
+    }
+    else {
+      memcpy(RSTRING_PTR(str) + sidx, buffer, 8);
+    }
+  }
+
+  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) {
+    if (littleendian) {
+      memcpy(buffer, src, 8);
+    }
+    else {
+      for (i = 0; i < 8; ++i) {
+        buffer[8 - i - 1] = src[i];
+      }
+    }
+  } else {
+    if (littleendian) {
+      for (i = 0; i < 8; ++i) {
+        buffer[8 - i - 1] = src[i];
+      }
+    }
+    else {
+      memcpy(buffer, src, 8);
+    }
+  }
+  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 = (float)mrb_float(o);
+
+  if (flags & PACK_FLAG_LITTLEENDIAN) {
+    if (littleendian) {
+      memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
+    }
+    else {
+      for (i = 0; i < 4; ++i) {
+        RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1];
+      }
+    }
+  } else {
+    if (littleendian) {
+      for (i = 0; i < 4; ++i) {
+        RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1];
+      }
+    }
+    else {
+      memcpy(RSTRING_PTR(str) + sidx, buffer, 4);
+    }
+  }
+
+  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) {
+    if (littleendian) {
+      memcpy(buffer, src, 4);
+    }
+    else {
+      for (i = 0; i < 4; ++i) {
+        buffer[4 - i - 1] = src[i];
+      }
+    }
+  } else {
+    if (littleendian) {
+      for (i = 0; i < 4; ++i) {
+        buffer[4 - i - 1] = src[i];
+      }
+    }
+    else {
+      memcpy(buffer, src, 4);
+    }
+  }
+  mrb_ary_push(mrb, ary, mrb_float_value(mrb, f));
+
+  return 4;
+}
+#endif
+
+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 = 0;
+  uint32_t c = 0;
+
+  c = (uint32_t)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 if (c < 0x200000) {
+    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;
+  }
+  else {
+    mrb_raise(mrb, E_RANGE_ERROR, "pack(U): value out of range");
+  }
+
+  str = str_len_ensure(mrb, str, sidx + len);
+  memcpy(RSTRING_PTR(str) + sidx, utf8, len);
+
+  return len;
+}
+
+static const unsigned long utf8_limits[] = {
+  0x0,        /* 1 */
+  0x80,       /* 2 */
+  0x800,      /* 3 */
+  0x10000,    /* 4 */
+  0x200000,   /* 5 */
+  0x4000000,  /* 6 */
+  0x80000000, /* 7 */
+};
+
+static unsigned long
+utf8_to_uv(mrb_state *mrb, const char *p, long *lenp)
+{
+  int c = *p++ & 0xff;
+  unsigned long uv = c;
+  long n = 1;
+
+  if (!(uv & 0x80)) {
+    *lenp = 1;
+    return uv;
+  }
+  if (!(uv & 0x40)) {
+    *lenp = 1;
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character");
+  }
+
+  if      (!(uv & 0x20)) { n = 2; uv &= 0x1f; }
+  else if (!(uv & 0x10)) { n = 3; uv &= 0x0f; }
+  else if (!(uv & 0x08)) { n = 4; uv &= 0x07; }
+  else if (!(uv & 0x04)) { n = 5; uv &= 0x03; }
+  else if (!(uv & 0x02)) { n = 6; uv &= 0x01; }
+  else {
+    *lenp = 1;
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character");
+  }
+  if (n > *lenp) {
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character (expected %d bytes, given %d bytes)",
+               n, *lenp);
+  }
+  *lenp = n--;
+  if (n != 0) {
+    while (n--) {
+      c = *p++ & 0xff;
+      if ((c & 0xc0) != 0x80) {
+        *lenp -= n + 1;
+        mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character");
+      }
+      else {
+        c &= 0x3f;
+        uv = uv << 6 | c;
+      }
+    }
+  }
+  n = *lenp - 1;
+  if (uv < utf8_limits[n]) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "redundant UTF-8 sequence");
+  }
+  return uv;
+}
+
+static int
+unpack_utf8(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ary, unsigned int flags)
+{
+  unsigned long uv;
+  long lenp = srclen;
+
+  if (srclen == 0) {
+    return 1;
+  }
+  uv = utf8_to_uv(mrb, (const char *)src, &lenp);
+  mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)uv));
+  return (int)lenp;
+}
+
+static int
+pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags)
+{
+  mrb_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 (int)(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;
+  int copylen;
+
+  sptr = (const char *)src;
+  if (count != -1 && count < slen)  {
+    slen = count;
+  }
+  copylen = slen;
+
+  if (slen >= 0 && flags & PACK_FLAG_Z) {  /* "Z" */
+    if ((cp = (const char *)memchr(sptr, '\0', slen)) != NULL) {
+      copylen = (int)(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--;
+    }
+  }
+
+  if (copylen < 0) copylen = 0;
+  dst = mrb_str_new(mrb, sptr, (mrb_int)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;
+  long slen;
+  char *dptr, *dptr0, *sptr;
+
+  sptr = RSTRING_PTR(src);
+  slen = (long)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 (int)(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 (int)(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;
+  mrb_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+2) / 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 (int)(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 (c >= sizeof(base64_dec_tab) || 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 (int)(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;
+
+  if (count < 0) return 0;
+  dst = str_len_ensure(mrb, dst, didx + count);
+  for (i = 0; i < count; i++) {
+    RSTRING_PTR(dst)[didx + i] = '\0';
+  }
+  return count;
+}
+static int
+unpack_x(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
+{
+  if (count < 0) return slen;
+  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, int *countp, unsigned int *flagsp)
+{
+  mrb_int t, tlen;
+  int ch, dir, type, size = 0;
+  int 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) == %d", (int)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) == %d", (int)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 | PACK_FLAG_COUNT2;
+    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])) {
+        int ch = tptr[tmpl->idx++] - '0';
+        if (count+ch > INT_MAX/10) {
+          mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length");
+        }
+        count = count * 10 + ch;
+      }
+      continue;  /* special case */
+    } else if (ch == '*')  {
+      count = -1;
+    } else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') {
+      if (strchr("sSiIlLqQ", (int)t) == NULL) {
+        mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%c' allowed only after types sSiIlLqQ", ch);
+      }
+      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;
+  int 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);
+      }
+#ifndef MRB_WITHOUT_FLOAT
+      else if (type == PACK_TYPE_FLOAT) {
+        if (!mrb_float_p(o)) {
+          mrb_float f = mrb_to_flo(mrb, o);
+          o = mrb_float_value(mrb, f);
+        }
+      }
+#endif
+      else if (type == PACK_TYPE_STRING) {
+        if (!mrb_string_p(o)) {
+          mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %T into String", 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;
+#ifndef MRB_WITHOUT_FLOAT
+      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;
+#endif
+      case PACK_DIR_UTF8:
+        ridx += pack_utf8(mrb, o, result, ridx, count, flags);
+        break;
+      default:
+        break;
+      }
+      if (dir == PACK_DIR_STR || dir == PACK_DIR_BASE64) { /* always consumes 1 entry */
+        aidx++;
+        break;
+      }
+      if (count > 0) {
+        count--;
+      }
+    }
+    if (ridx < 0) {
+      mrb_raise(mrb, E_RANGE_ERROR, "negative (or overflowed) template size");
+    }
+  }
+
+  mrb_str_resize(mrb, result, ridx);
+  return result;
+}
+
+static mrb_value
+pack_unpack(mrb_state *mrb, mrb_value str, int single)
+{
+  mrb_value result;
+  struct tmpl tmpl;
+  int count;
+  unsigned int flags;
+  int dir, size, type;
+  int srcidx, srclen;
+  const unsigned char *sptr;
+
+  prepare_tmpl(mrb, &tmpl);
+
+  srcidx = 0;
+  srclen = (int)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;
+      case PACK_DIR_BASE64:
+        srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, 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;
+#ifndef MRB_WITHOUT_FLOAT
+      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;
+#endif
+      case PACK_DIR_UTF8:
+        srcidx += unpack_utf8(mrb, sptr, srclen - srcidx, result, flags);
+        break;
+      default:
+        mrb_raise(mrb, E_RUNTIME_ERROR, "mruby-pack's bug");
+      }
+      if (count > 0) {
+        count--;
+      }
+    }
+    if (single) break;
+  }
+
+  if (single) {
+    if (RARRAY_LEN(result) > 0) {
+      return RARRAY_PTR(result)[0];
+    }
+    return mrb_nil_value();
+  }
+  return result;
+}
+
+static mrb_value
+mrb_pack_unpack(mrb_state *mrb, mrb_value str)
+{
+  return pack_unpack(mrb, str, 0);
+}
+
+static mrb_value
+mrb_pack_unpack1(mrb_state *mrb, mrb_value str)
+{
+  return pack_unpack(mrb, str, 1);
+}
+
+void
+mrb_mruby_pack_gem_init(mrb_state *mrb)
+{
+  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));
+  mrb_define_method(mrb, mrb->string_class, "unpack1", mrb_pack_unpack1, MRB_ARGS_REQ(1));
+}
+
+void
+mrb_mruby_pack_gem_final(mrb_state *mrb)
+{
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/test/pack.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/test/pack.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-pack/test/pack.rb	(revision 439)
@@ -0,0 +1,159 @@
+PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01
+
+def assert_pack tmpl, packed, unpacked
+  t = tmpl.inspect
+  assert "assert_pack" do
+    assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})"
+    assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})"
+  end
+end
+
+# pack & unpack 'm' (base64)
+assert('[""].pack("m")') do
+  assert_pack "m", "", [""]
+end
+
+assert('["\0"].pack("m")') do
+  assert_pack "m", "AA==\n", ["\0"]
+end
+
+assert('["\0\0"].pack("m")') do
+  assert_pack "m", "AAA=\n", ["\0\0"]
+end
+
+assert('["\0\0\0"].pack("m")') do
+  assert_pack "m", "AAAA\n", ["\0\0\0"]
+end
+
+assert('["abc..xyzABC..XYZ"].pack("m")') do
+  assert_pack "m", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n", ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]
+end
+
+assert('"YWJ...".unpack("m") should "abc..xyzABC..XYZ"') do
+  ary = ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]
+  assert_equal ary, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n".unpack("m")
+  assert_equal ary, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m")
+end
+
+assert('["A", "B"].pack') do
+  assert_equal "QQ==\n", ["A", "B"].pack("m50")
+  assert_equal ["A"], "QQ==\n".unpack("m50")
+  assert_equal "QQ==Qg==", ["A", "B"].pack("m0 m0")
+  assert_equal ["A", "B"], "QQ==Qg==".unpack("m10 m10")
+end
+
+assert('["abc..xyzABC..XYZ"].pack("m0")') do
+  assert_pack "m0", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==", ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]
+end
+
+# pack & unpack 'H'
+assert('["3031"].pack("H*")') do
+  assert_pack "H*", "01", ["3031"]
+end
+
+assert('["10"].pack("H*")') do
+  assert_pack "H*", "\020", ["10"]
+end
+
+assert('[0,1,127,128,255].pack("C*")') do
+  assert_pack "C*", "\x00\x01\x7F\x80\xFF", [0, 1, 127, 128, 255]
+end
+
+# pack "a"
+assert('["abc"].pack("a")') do
+  assert_equal "a", ["abc"].pack("a")
+  assert_equal "abc", ["abc"].pack("a*")
+  assert_equal "abc\0", ["abc"].pack("a4")
+end
+
+# upack "a"
+assert('["abc"].pack("a")') do
+  assert_equal ["abc\0"], "abc\0".unpack("a4")
+  assert_equal ["abc "], "abc ".unpack("a4")
+end
+
+# pack "A"
+assert('["abc"].pack("A")') do
+  assert_equal "a", ["abc"].pack("A")
+  assert_equal "abc", ["abc"].pack("A*")
+  assert_equal "abc ", ["abc"].pack("A4")
+end
+
+# upack "A"
+assert('["abc"].pack("A")') do
+  assert_equal ["abc"], "abc\0".unpack("A4")
+  assert_equal ["abc"], "abc ".unpack("A4")
+end
+
+# regression tests
+assert('issue #1') do
+  assert_equal "\000\001\000\002", [1, 2].pack("nn")
+end
+
+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) + "\xCF\xC7"
+  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) + "\x30\x39"
+  end
+  assert_pack 'I', str, [12345]
+end
+
+assert 'pack/unpack "U"' do
+  assert_equal [], "".unpack("U")
+  assert_equal [], "".unpack("U*")
+  assert_equal [65, 66], "ABC".unpack("U2")
+  assert_equal [12371, 12435, 12395, 12385, 12399, 19990, 30028], "こんにちは世界".unpack("U*")
+
+  assert_equal "", [].pack("U")
+  assert_equal "", [].pack("U*")
+  assert_equal "AB", [65, 66, 67].pack("U2")
+  assert_equal "こんにちは世界", [12371, 12435, 12395, 12385, 12399, 19990, 30028].pack("U*")
+
+  assert_equal "\000", [0].pack("U")
+
+  assert_raise(RangeError) { [-0x40000000].pack("U") }
+  assert_raise(RangeError) { [-1].pack("U") }
+  assert_raise(RangeError) { [0x40000000].pack("U") }
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-print/mrblib/print.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-print/mrblib/print.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-print/mrblib/print.rb	(revision 439)
@@ -46,19 +46,10 @@
       i += 1
     end
-    args[0]
+    args.__svalue
   end
 
-  unless Kernel.respond_to?(:sprintf)
-    def printf(*args)
-      raise NotImplementedError.new('printf not available')
-    end
-    def sprintf(*args)
-      raise NotImplementedError.new('sprintf not available')
-    end
-  else
-    def printf(*args)
-      __printstr__(sprintf(*args))
-      nil
-    end
+  def printf(*args)
+    __printstr__(sprintf(*args))
+    nil
   end
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-print/src/print.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-print/src/print.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-print/src/print.c	(revision 439)
@@ -1,5 +1,9 @@
 #include <mruby.h>
+
+#ifdef MRB_DISABLE_STDIO
+# error print conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
+#endif
+
 #include <mruby/string.h>
-#include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -20,9 +24,8 @@
     if (isatty(fileno(stdout))) {
       DWORD written;
-      int mlen = RSTRING_LEN(obj);
+      int mlen = (int)RSTRING_LEN(obj);
       char* utf8 = RSTRING_PTR(obj);
       int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, NULL, 0);
       wchar_t* utf16 = (wchar_t*)mrb_malloc(mrb, (wlen+1) * sizeof(wchar_t));
-      if (utf16 == NULL) return;
       if (MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, utf16, wlen) > 0) {
         utf16[wlen] = 0;
@@ -34,4 +37,5 @@
 #endif
       fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stdout);
+    fflush(stdout);
   }
 }
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-proc-ext/mrblib/proc.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-proc-ext/mrblib/proc.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-proc-ext/mrblib/proc.rb	(revision 439)
@@ -28,5 +28,5 @@
     pproc = self
     make_curry = proc do |given_args=[]|
-      send(type) do |*args|
+      __send__(type) do |*args|
         new_args = given_args + args
         if new_args.size >= arity
@@ -40,3 +40,11 @@
   end
 
+  def <<(other)
+    ->(*args, &block) { call(other.call(*args, &block)) }
+  end
+
+  def >>(other)
+    ->(*args, &block) { other.call(call(*args, &block)) }
+  end
+
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-proc-ext/src/proc.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-proc-ext/src/proc.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-proc-ext/src/proc.c	(revision 439)
@@ -26,6 +26,6 @@
     const char *filename;
 
-    filename = mrb_debug_get_filename(irep, 0);
-    line = mrb_debug_get_line(irep, 0);
+    filename = mrb_debug_get_filename(mrb, irep, 0);
+    line = mrb_debug_get_line(mrb, irep, 0);
 
     return (!filename && line == -1)? mrb_nil_value()
@@ -39,5 +39,5 @@
   struct RProc *p = mrb_proc_ptr(self);
   mrb_value str = mrb_str_new_lit(mrb, "#<Proc:");
-  mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(self)));
+  mrb_str_cat_str(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(self)));
 
   if (!MRB_PROC_CFUNC_P(p)) {
@@ -47,11 +47,11 @@
     mrb_str_cat_lit(mrb, str, "@");
 
-    filename = mrb_debug_get_filename(irep, 0);
+    filename = mrb_debug_get_filename(mrb, irep, 0);
     mrb_str_cat_cstr(mrb, str, filename ? filename : "-");
     mrb_str_cat_lit(mrb, str, ":");
 
-    line = mrb_debug_get_line(irep, 0);
+    line = mrb_debug_get_line(mrb, irep, 0);
     if (line != -1) {
-      str = mrb_format(mrb, "%S:%S", str, mrb_fixnum_value(line));
+      mrb_str_concat(mrb, str, mrb_fixnum_value(line));
     }
     else {
@@ -73,8 +73,5 @@
   mrb_value blk;
 
-  mrb_get_args(mrb, "&", &blk);
-  if (mrb_nil_p(blk)) {
-    mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block");
-  }
+  mrb_get_args(mrb, "&!", &blk);
 
   return blk;
@@ -95,19 +92,21 @@
 {
   struct parameters_type {
+    size_t len;
+    const char *name;
     int size;
-    const char *name;
   } *p, parameters_list [] = {
-    {0, "req"},
-    {0, "opt"},
-    {0, "rest"},
-    {0, "req"},
-    {0, "block"},
-    {0, NULL}
+    {sizeof("req")   - 1, "req",   0},
+    {sizeof("opt")   - 1, "opt",   0},
+    {sizeof("rest")  - 1, "rest",  0},
+    {sizeof("req")   - 1, "req",   0},
+    {sizeof("block") - 1, "block", 0},
+    {0, NULL, 0}
   };
   const struct RProc *proc = mrb_proc_ptr(self);
   const struct mrb_irep *irep = proc->body.irep;
   mrb_aspec aspec;
-  mrb_value sname, parameters;
+  mrb_value parameters;
   int i, j;
+  int max = -1;
 
   if (MRB_PROC_CFUNC_P(proc)) {
@@ -121,14 +120,16 @@
     return mrb_ary_new(mrb);
   }
-  if (GET_OPCODE(*irep->iseq) != OP_ENTER) {
+  if (*irep->iseq != OP_ENTER) {
     return mrb_ary_new(mrb);
   }
 
   if (!MRB_PROC_STRICT_P(proc)) {
+    parameters_list[0].len = sizeof("opt") - 1;
     parameters_list[0].name = "opt";
+    parameters_list[3].len = sizeof("opt") - 1;
     parameters_list[3].name = "opt";
   }
 
-  aspec = GETARG_Ax(*irep->iseq);
+  aspec = PEEK_W(irep->iseq+1);
   parameters_list[0].size = MRB_ASPEC_REQ(aspec);
   parameters_list[1].size = MRB_ASPEC_OPT(aspec);
@@ -139,12 +140,23 @@
   parameters = mrb_ary_new_capa(mrb, irep->nlocals-1);
 
+  max = irep->nlocals-1;
   for (i = 0, p = parameters_list; p->name; p++) {
-    if (p->size <= 0) continue;
-    sname = mrb_symbol_value(mrb_intern_cstr(mrb, p->name));
+    mrb_value sname = mrb_symbol_value(mrb_intern_static(mrb, p->name, p->len));
+
     for (j = 0; j < p->size; i++, j++) {
-      mrb_value a = mrb_ary_new(mrb);
+      mrb_value a;
+
+      a = mrb_ary_new(mrb);
       mrb_ary_push(mrb, a, sname);
-      if (irep->lv[i].name) {
-        mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i].name));
+      if (i < max && irep->lv[i].name) {
+        mrb_sym sym = irep->lv[i].name;
+        const char *name = mrb_sym_name(mrb, sym);
+        switch (name[0]) {
+        case '*': case '&':
+          break;
+        default:
+          mrb_ary_push(mrb, a, mrb_symbol_value(sym));
+          break;
+        }
       }
       mrb_ary_push(mrb, parameters, a);
@@ -164,6 +176,6 @@
   mrb_define_method(mrb, p, "parameters",      mrb_proc_parameters,      MRB_ARGS_NONE());
 
-  mrb_define_class_method(mrb, mrb->kernel_module, "proc", mrb_kernel_proc, MRB_ARGS_NONE());
-  mrb_define_method(mrb, mrb->kernel_module,       "proc", mrb_kernel_proc, MRB_ARGS_NONE());
+  mrb_define_class_method(mrb, mrb->kernel_module, "proc", mrb_kernel_proc, MRB_ARGS_NONE()|MRB_ARGS_BLOCK());
+  mrb_define_method(mrb, mrb->kernel_module,       "proc", mrb_kernel_proc, MRB_ARGS_NONE()|MRB_ARGS_BLOCK());
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-proc-ext/test/proc.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-proc-ext/test/proc.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-proc-ext/test/proc.c	(revision 439)
@@ -14,8 +14,11 @@
   mrb_sym n;
   mrb_value n_val;
+  mrb_method_t m;
+  struct RProc *p;
   mrb_get_args(mrb, "n", &n);
   n_val = mrb_symbol_value(n);
-  mrb_define_method_raw(mrb, mrb_class_ptr(self), n,
-                        mrb_proc_new_cfunc_with_env(mrb, return_func_name, 1, &n_val));
+  p = mrb_proc_new_cfunc_with_env(mrb, return_func_name, 1, &n_val);
+  MRB_METHOD_FROM_PROC(m, p);
+  mrb_define_method_raw(mrb, mrb_class_ptr(self), n, m);
   return self;
 }
@@ -34,7 +37,10 @@
   mrb_sym n;
   mrb_value *argv; mrb_int argc;
+  mrb_method_t m;
+  struct RProc *p;
   mrb_get_args(mrb, "na", &n, &argv, &argc);
-  mrb_define_method_raw(mrb, mrb_class_ptr(self), n,
-                        mrb_proc_new_cfunc_with_env(mrb, return_env, argc, argv));
+  p = mrb_proc_new_cfunc_with_env(mrb, return_env, argc, argv);
+  MRB_METHOD_FROM_PROC(m, p);
+  mrb_define_method_raw(mrb, mrb_class_ptr(self), n, m);
   return self;
 }
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-proc-ext/test/proc.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-proc-ext/test/proc.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-proc-ext/test/proc.rb	(revision 439)
@@ -2,14 +2,35 @@
 # Proc(Ext) Test
 
+def enable_debug_info?
+  return @enable_debug_info unless @enable_debug_info == nil
+  begin
+    raise
+  rescue => e
+    @enable_debug_info = !e.backtrace.empty?
+  end
+end
+
 assert('Proc#source_location') do
-  loc = Proc.new {}.source_location
-  next true if loc.nil?
-  assert_equal loc[0][-7, 7], 'proc.rb'
-  assert_equal loc[1], 5
+  skip unless enable_debug_info?
+  file, line = Proc.new{}.source_location
+  assert_equal __FILE__, file
+  assert_equal __LINE__ - 2, line
 end
 
 assert('Proc#inspect') do
   ins = Proc.new{}.inspect
-  assert_kind_of String, ins
+  if enable_debug_info?
+    metas = %w(\\ * ? [ ] { })
+    file = __FILE__.split("").map{|c| metas.include?(c) ? "\\#{c}" : c}.join
+    line = __LINE__ - 4
+  else
+    file = line = "-"
+  end
+  assert_match "#<Proc:0x*@#{file}:#{line}>", ins
+end
+
+assert('Proc#parameters') do
+  parameters = Proc.new{|x,y=42,*other|}.parameters
+  assert_equal [[:opt, :x], [:opt, :y], [:rest, :other]], parameters
 end
 
@@ -67,4 +88,21 @@
 assert('Kernel#proc') do
   assert_true !proc{|a|}.lambda?
+
+  assert_raise LocalJumpError do
+    proc{ break }.call
+  end
+end
+
+assert "Proc#<< and Proc#>>" do
+  add3 = ->(n) { n + 3 }
+  mul2 = ->(n) { n * 2 }
+
+  f1 = mul2 << add3
+  assert_kind_of Proc, f1
+  assert_equal 16, f1.call(5)
+
+  f2 = mul2 >> add3
+  assert_kind_of Proc, f2
+  assert_equal 13, f2.call(5)
 end
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-random/src/mt19937ar.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-random/src/mt19937ar.c	(revision 331)
+++ 	(revision )
@@ -1,226 +1,0 @@
-/*
-** mt19937ar.c - MT Random functions
-**
-** Copyright (C) 1997 - 2016, Makoto Matsumoto and Takuji Nishimura,
-** All rights reserved.
-**
-** 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.
-**
-** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
-**
-** Any feedback is very welcome.
-** http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
-** email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
-**
-** This version is modified by mruby developers. If you see any problem,
-** contact us first at https://github.com/mruby/mruby/issues
-*/
-
-#include <mruby.h>
-#include "mt19937ar.h"
-
-/* Period parameters */
-/* #define N 624 */
-#define M 397
-#define MATRIX_A 0x9908b0dfUL   /* constant vector a */
-#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
-#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
-
-#if 0 /* dead_code */
-static unsigned long mt[N]; /* the array for the state vector  */
-static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
-#endif /* dead_code */
-
-void mrb_random_init_genrand(mt_state *t, unsigned long s)
-{
-    t->mt[0]= s & 0xffffffffUL;
-    for (t->mti=1; t->mti<N; t->mti++) {
-        t->mt[t->mti] =
-	    (1812433253UL * (t->mt[t->mti-1] ^ (t->mt[t->mti-1] >> 30)) + t->mti);
-        t->mt[t->mti] &= 0xffffffffUL;
-    }
-}
-
-unsigned long mrb_random_genrand_int32(mt_state *t)
-{
-    unsigned long y;
-    static const unsigned long mag01[2]={0x0UL, MATRIX_A};
-    /* mag01[x] = x * MATRIX_A  for x=0,1 */
-
-    if (t->mti >= N) { /* generate N words at one time */
-        int kk;
-
-        if (t->mti == N+1)   /* if init_genrand() has not been called, */
-            mrb_random_init_genrand(t, 5489UL); /* a default initial seed is used */
-
-        for (kk=0;kk<N-M;kk++) {
-            y = (t->mt[kk]&UPPER_MASK)|(t->mt[kk+1]&LOWER_MASK);
-            t->mt[kk] = t->mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
-        }
-        for (;kk<N-1;kk++) {
-            y = (t->mt[kk]&UPPER_MASK)|(t->mt[kk+1]&LOWER_MASK);
-            t->mt[kk] = t->mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
-        }
-        y = (t->mt[N-1]&UPPER_MASK)|(t->mt[0]&LOWER_MASK);
-        t->mt[N-1] = t->mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
-
-        t->mti = 0;
-    }
-
-    y = t->mt[t->mti++];
-
-    /* Tempering */
-    y ^= (y >> 11);
-    y ^= (y << 7) & 0x9d2c5680UL;
-    y ^= (y << 15) & 0xefc60000UL;
-    y ^= (y >> 18);
-
-    t->gen.int_ = y;
-
-    return y;
-}
-
-double mrb_random_genrand_real1(mt_state *t)
-{
-    mrb_random_genrand_int32(t);
-    t->gen.double_ =  t->gen.int_*(1.0/4294967295.0);
-    return t->gen.double_;
-    /* divided by 2^32-1 */
-}
-
-#if 0 /* dead_code */
-/* initializes mt[N] with a seed */
-void init_genrand(unsigned long s)
-{
-    mt[0]= s & 0xffffffffUL;
-    for (mti=1; mti<N; mti++) {
-        mt[mti] =
-	    (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
-        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
-        /* In the previous versions, MSBs of the seed affect   */
-        /* only MSBs of the array mt[].                        */
-        /* 2002/01/09 modified by Makoto Matsumoto             */
-        mt[mti] &= 0xffffffffUL;
-        /* for >32 bit machines */
-    }
-}
-
-/* initialize by an array with array-length */
-/* init_key is the array for initializing keys */
-/* key_length is its length */
-/* slight change for C++, 2004/2/26 */
-void init_by_array(unsigned long init_key[], int key_length)
-{
-    int i, j, k;
-    init_genrand(19650218UL);
-    i=1; j=0;
-    k = (N>key_length ? N : key_length);
-    for (; k; k--) {
-        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
-          + init_key[j] + j; /* non linear */
-        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
-        i++; j++;
-        if (i>=N) { mt[0] = mt[N-1]; i=1; }
-        if (j>=key_length) j=0;
-    }
-    for (k=N-1; k; k--) {
-        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
-          - i; /* non linear */
-        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
-        i++;
-        if (i>=N) { mt[0] = mt[N-1]; i=1; }
-    }
-
-    mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
-}
-
-/* generates a random number on [0,0xffffffff]-interval */
-unsigned long genrand_int32(void)
-{
-    unsigned long y;
-    static const unsigned long mag01[2]={0x0UL, MATRIX_A};
-    /* mag01[x] = x * MATRIX_A  for x=0,1 */
-
-    if (mti >= N) { /* generate N words at one time */
-        int kk;
-
-        if (mti == N+1)   /* if init_genrand() has not been called, */
-            init_genrand(5489UL); /* a default initial seed is used */
-
-        for (kk=0;kk<N-M;kk++) {
-            y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
-            mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
-        }
-        for (;kk<N-1;kk++) {
-            y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
-            mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
-        }
-        y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
-        mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
-
-        mti = 0;
-    }
-
-    y = mt[mti++];
-
-    /* Tempering */
-    y ^= (y >> 11);
-    y ^= (y << 7) & 0x9d2c5680UL;
-    y ^= (y << 15) & 0xefc60000UL;
-    y ^= (y >> 18);
-
-    return y;
-}
-
-/* generates a random number on [0,0x7fffffff]-interval */
-long genrand_int31(void)
-{
-    return (long)(genrand_int32()>>1);
-}
-
-/* generates a random number on [0,1]-real-interval */
-double genrand_real1(void)
-{
-    return genrand_int32()*(1.0/4294967295.0);
-    /* divided by 2^32-1 */
-}
-
-/* generates a random number on [0,1)-real-interval */
-double genrand_real2(void)
-{
-    return genrand_int32()*(1.0/4294967296.0);
-    /* divided by 2^32 */
-}
-
-/* generates a random number on (0,1)-real-interval */
-double genrand_real3(void)
-{
-    return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
-    /* divided by 2^32 */
-}
-
-/* generates a random number on [0,1) with 53-bit resolution*/
-double genrand_res53(void)
-{
-    unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
-    return(a*67108864.0+b)*(1.0/9007199254740992.0);
-}
-/* These real versions are due to Isaku Wada, 2002/01/09 added */
-#endif /* dead_code */
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-random/src/mt19937ar.h
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-random/src/mt19937ar.h	(revision 331)
+++ 	(revision )
@@ -1,80 +1,0 @@
-/*
-** mt19937ar.h - MT Random functions
-**
-** Copyright (C) 1997 - 2016, Makoto Matsumoto and Takuji Nishimura,
-** All rights reserved.
-**
-** 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.
-**
-** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
-**
-** Any feedback is very welcome.
-** http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
-** email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
-**
-** This version is modified by mruby developers. If you see any problem,
-** contact us first at https://github.com/mruby/mruby/issues
-*/
-
-#define N 624
-
-typedef struct {
-  unsigned long mt[N];
-  int mti;
-  union {
-    unsigned long int_;
-    double double_;
-  } gen;
-
-  mrb_int seed;
-  mrb_bool has_seed : 1;
-} mt_state;
-
-void mrb_random_init_genrand(mt_state *, unsigned long);
-unsigned long mrb_random_genrand_int32(mt_state *);
-double mrb_random_genrand_real1(mt_state *t);
-
-/* initializes mt[N] with a seed */
-void init_genrand(unsigned long s);
-
-/* initialize by an array with array-length */
-/* init_key is the array for initializing keys */
-/* key_length is its length */
-/* slight change for C++, 2004/2/26 */
-void init_by_array(unsigned long init_key[], int key_length);
-
-/* generates a random number on [0,0xffffffff]-interval */
-unsigned long genrand_int32(void);
-
-/* generates a random number on [0,0x7fffffff]-interval */
-long genrand_int31(void);
-
-/* These real versions are due to Isaku Wada, 2002/01/09 added */
-/* generates a random number on [0,1]-real-interval */
-double genrand_real1(void);
-
-/* generates a random number on [0,1)-real-interval */
-double genrand_real2(void);
-
-/* generates a random number on (0,1)-real-interval */
-double genrand_real3(void);
-
-/* generates a random number on [0,1) with 53-bit resolution*/
-double genrand_res53(void);
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-random/src/random.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-random/src/random.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-random/src/random.c	(revision 439)
@@ -10,60 +10,103 @@
 #include <mruby/data.h>
 #include <mruby/array.h>
-#include "mt19937ar.h"
+#include <mruby/istruct.h>
+#if INT32_MAX <= INTPTR_MAX
+# define XORSHIFT96
+# define NSEEDS 3
+#else
+# define NSEEDS 4
+#endif
+#define LASTSEED (NSEEDS-1)
 
 #include <time.h>
 
-static char const MT_STATE_KEY[] = "$mrb_i_mt_state";
-
-static const struct mrb_data_type mt_state_type = {
-  MT_STATE_KEY, mrb_free,
-};
-
-static mrb_value mrb_random_rand(mrb_state *mrb, mrb_value self);
-static mrb_value mrb_random_srand(mrb_state *mrb, mrb_value self);
+typedef struct rand_state {
+  uint32_t seed[NSEEDS];
+} rand_state;
 
 static void
-mt_srand(mt_state *t, unsigned long seed)
-{
-  mrb_random_init_genrand(t, seed);
-}
-
-static unsigned long
-mt_rand(mt_state *t)
-{
-  return mrb_random_genrand_int32(t);
-}
-
+rand_init(rand_state *t)
+{
+  t->seed[0] = 123456789;
+  t->seed[1] = 362436069;
+  t->seed[2] = 521288629;
+#ifndef XORSHIFT96
+  t->seed[3] = 88675123;
+#endif
+}
+
+static uint32_t
+rand_seed(rand_state *t, uint32_t seed)
+{
+  uint32_t old_seed = t->seed[LASTSEED];
+  rand_init(t);
+  t->seed[LASTSEED] = seed;
+  return old_seed;
+}
+
+#ifdef XORSHIFT96
+static uint32_t
+rand_uint32(rand_state *state)
+{
+  uint32_t *seed = state->seed;
+  uint32_t x = seed[0];
+  uint32_t y = seed[1];
+  uint32_t z = seed[2];
+  uint32_t t;
+
+  t = (x ^ (x << 3)) ^ (y ^ (y >> 19)) ^ (z ^ (z << 6));
+  x = y; y = z; z = t;
+  seed[0] = x;
+  seed[1] = y;
+  seed[2] = z;
+
+  return z;
+}
+#else  /* XORSHIFT96 */
+static uint32_t
+rand_uint32(rand_state *state)
+{
+  uint32_t *seed = state->seed;
+  uint32_t x = seed[0];
+  uint32_t y = seed[1];
+  uint32_t z = seed[2];
+  uint32_t w = seed[3];
+  uint32_t t;
+
+  t = x ^ (x << 11);
+  x = y; y = z; z = w;
+  w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
+  seed[0] = x;
+  seed[1] = y;
+  seed[2] = z;
+  seed[3] = w;
+
+  return w;
+}
+#endif  /* XORSHIFT96 */
+
+#ifndef MRB_WITHOUT_FLOAT
 static double
-mt_rand_real(mt_state *t)
-{
-  return mrb_random_genrand_real1(t);
-}
-
-static mrb_value
-mrb_random_mt_srand(mrb_state *mrb, mt_state *t, mrb_value seed)
-{
-  if (mrb_nil_p(seed)) {
-    seed = mrb_fixnum_value((mrb_int)(time(NULL) + mt_rand(t)));
-    if (mrb_fixnum(seed) < 0) {
-      seed = mrb_fixnum_value(0 - mrb_fixnum(seed));
-    }
-  }
-
-  mt_srand(t, (unsigned) mrb_fixnum(seed));
-
-  return seed;
-}
-
-static mrb_value
-mrb_random_mt_rand(mrb_state *mrb, mt_state *t, mrb_value max)
+rand_real(rand_state *t)
+{
+  uint32_t x = rand_uint32(t);
+  return x*(1.0/4294967295.0);
+}
+#endif
+
+static mrb_value
+random_rand(mrb_state *mrb, rand_state *t, mrb_value max)
 {
   mrb_value value;
 
   if (mrb_fixnum(max) == 0) {
-    value = mrb_float_value(mrb, mt_rand_real(t));
-  }
-  else {
-    value = mrb_fixnum_value(mt_rand(t) % mrb_fixnum(max));
+#ifndef MRB_WITHOUT_FLOAT
+    value = mrb_float_value(mrb, rand_real(t));
+#else
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "Float not supported");
+#endif
+  }
+  else {
+    value = mrb_fixnum_value(rand_uint32(t) % mrb_fixnum(max));
   }
 
@@ -80,10 +123,10 @@
 
   if (!mrb_nil_p(arg)) {
-    arg = mrb_check_convert_type(mrb, arg, MRB_TT_FIXNUM, "Fixnum", "to_int");
-    if (mrb_nil_p(arg)) {
-      mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument type");
-    }
-    if (mrb_fixnum(arg) < 0) {
-      arg = mrb_fixnum_value(0 - mrb_fixnum(arg));
+    mrb_int i;
+
+    arg = mrb_to_int(mrb, arg);
+    i = mrb_fixnum(arg);
+    if (i < 0) {
+      arg = mrb_fixnum_value(0 - i);
     }
   }
@@ -91,104 +134,72 @@
 }
 
-static mrb_value
-get_random(mrb_state *mrb) {
-  return mrb_const_get(mrb,
-             mrb_obj_value(mrb_class_get(mrb, "Random")),
-             mrb_intern_lit(mrb, "DEFAULT"));
-}
-
-static mt_state *
-get_random_state(mrb_state *mrb)
-{
-  mrb_value random_val = get_random(mrb);
-  return DATA_GET_PTR(mrb, random_val, &mt_state_type, mt_state);
-}
-
-static mrb_value
-mrb_random_g_rand(mrb_state *mrb, mrb_value self)
-{
-  mrb_value random = get_random(mrb);
-  return mrb_random_rand(mrb, random);
-}
-
-static mrb_value
-mrb_random_g_srand(mrb_state *mrb, mrb_value self)
-{
-  mrb_value random = get_random(mrb);
-  return mrb_random_srand(mrb, random);
-}
-
-static mrb_value
-mrb_random_init(mrb_state *mrb, mrb_value self)
+static void
+random_check(mrb_state *mrb, mrb_value random) {
+  struct RClass *c = mrb_class_get(mrb, "Random");
+  if (!mrb_obj_is_kind_of(mrb, random, c) || !mrb_istruct_p(random)) {
+    mrb_raise(mrb, E_TYPE_ERROR, "Random instance required");
+  }
+}
+
+static mrb_value
+random_default(mrb_state *mrb) {
+  struct RClass *c = mrb_class_get(mrb, "Random");
+  mrb_value d = mrb_const_get(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, "DEFAULT"));
+  if (!mrb_obj_is_kind_of(mrb, d, c)) {
+    mrb_raise(mrb, E_TYPE_ERROR, "Random::DEFAULT replaced");
+  }
+  return d;
+}
+
+#define random_ptr(v) (rand_state*)mrb_istruct_ptr(v)
+#define random_default_state(mrb) random_ptr(random_default(mrb))
+
+static mrb_value
+random_m_init(mrb_state *mrb, mrb_value self)
 {
   mrb_value seed;
-  mt_state *t;
+  rand_state *t;
 
   seed = get_opt(mrb);
-
   /* avoid memory leaks */
-  t = (mt_state*)DATA_PTR(self);
-  if (t) {
-    mrb_free(mrb, t);
-  }
-  mrb_data_init(self, NULL, &mt_state_type);
-
-  t = (mt_state *)mrb_malloc(mrb, sizeof(mt_state));
-  t->mti = N + 1;
-
-  seed = mrb_random_mt_srand(mrb, t, seed);
+  t = random_ptr(self);
   if (mrb_nil_p(seed)) {
-    t->has_seed = FALSE;
-  }
-  else {
-    mrb_assert(mrb_fixnum_p(seed));
-    t->has_seed = TRUE;
-    t->seed = mrb_fixnum(seed);
-  }
-
-  mrb_data_init(self, t, &mt_state_type);
+    rand_init(t);
+  }
+  else {
+    rand_seed(t, (uint32_t)mrb_fixnum(seed));
+  }
 
   return self;
 }
 
-static void
-mrb_random_rand_seed(mrb_state *mrb, mt_state *t)
-{
-  if (!t->has_seed) {
-    mrb_random_mt_srand(mrb, t, mrb_nil_value());
-  }
-}
-
-static mrb_value
-mrb_random_rand(mrb_state *mrb, mrb_value self)
+static mrb_value
+random_m_rand(mrb_state *mrb, mrb_value self)
 {
   mrb_value max;
-  mt_state *t = DATA_GET_PTR(mrb, self, &mt_state_type, mt_state);
+  rand_state *t = random_ptr(self);
 
   max = get_opt(mrb);
-  mrb_random_rand_seed(mrb, t);
-  return mrb_random_mt_rand(mrb, t, max);
-}
-
-static mrb_value
-mrb_random_srand(mrb_state *mrb, mrb_value self)
-{
-  mrb_value seed;
-  mrb_value old_seed;
-  mt_state *t = DATA_GET_PTR(mrb, self, &mt_state_type, mt_state);
-
-  seed = get_opt(mrb);
-  seed = mrb_random_mt_srand(mrb, t, seed);
-  old_seed = t->has_seed? mrb_fixnum_value(t->seed) : mrb_nil_value();
-  if (mrb_nil_p(seed)) {
-    t->has_seed = FALSE;
-  }
-  else {
-    mrb_assert(mrb_fixnum_p(seed));
-    t->has_seed = TRUE;
-    t->seed = mrb_fixnum(seed);
-  }
-
-  return old_seed;
+  return random_rand(mrb, t, max);
+}
+
+static mrb_value
+random_m_srand(mrb_state *mrb, mrb_value self)
+{
+  uint32_t seed;
+  uint32_t old_seed;
+  mrb_value sv;
+  rand_state *t = random_ptr(self);
+
+  sv = get_opt(mrb);
+  if (mrb_nil_p(sv)) {
+    seed = (uint32_t)time(NULL) + rand_uint32(t);
+  }
+  else {
+    seed = (uint32_t)mrb_fixnum(sv);
+  }
+  old_seed = rand_seed(t, seed);
+
+  return mrb_fixnum_value((mrb_int)old_seed);
 }
 
@@ -204,25 +215,30 @@
 {
   mrb_int i;
-  mt_state *random = NULL;
+  mrb_value max;
+  mrb_value r = mrb_nil_value();
+  rand_state *random;
 
   if (RARRAY_LEN(ary) > 1) {
-    mrb_get_args(mrb, "|d", &random, &mt_state_type);
-
-    if (random == NULL) {
-      random = get_random_state(mrb);
-    }
-    mrb_random_rand_seed(mrb, random);
-
+    mrb_get_args(mrb, "|o", &r);
+
+    if (mrb_nil_p(r)) {
+      random = random_default_state(mrb);
+    }
+    else {
+      random_check(mrb, r);
+      random = random_ptr(r);
+    }
     mrb_ary_modify(mrb, mrb_ary_ptr(ary));
-
+    max = mrb_fixnum_value(RARRAY_LEN(ary));
     for (i = RARRAY_LEN(ary) - 1; i > 0; i--)  {
       mrb_int j;
+      mrb_value *ptr = RARRAY_PTR(ary);
       mrb_value tmp;
 
-      j = mrb_fixnum(mrb_random_mt_rand(mrb, random, mrb_fixnum_value(RARRAY_LEN(ary))));
-
-      tmp = RARRAY_PTR(ary)[i];
-      mrb_ary_ptr(ary)->ptr[i] = RARRAY_PTR(ary)[j];
-      mrb_ary_ptr(ary)->ptr[j] = tmp;
+      j = mrb_fixnum(random_rand(mrb, random, max));
+
+      tmp = ptr[i];
+      ptr[i] = ptr[j];
+      ptr[j] = tmp;
     }
   }
@@ -267,13 +283,16 @@
   mrb_int n = 0;
   mrb_bool given;
-  mt_state *random = NULL;
+  mrb_value r = mrb_nil_value();
+  rand_state *random;
   mrb_int len;
 
-  mrb_get_args(mrb, "|i?d", &n, &given, &random, &mt_state_type);
-  if (random == NULL) {
-    random = get_random_state(mrb);
-  }
-  mrb_random_rand_seed(mrb, random);
-  mt_rand(random);
+  mrb_get_args(mrb, "|i?o", &n, &given, &r);
+  if (mrb_nil_p(r)) {
+    random = random_default_state(mrb);
+  }
+  else {
+    random_check(mrb, r);
+    random = random_ptr(r);
+  }
   len = RARRAY_LEN(ary);
   if (!given) {                 /* pick one element */
@@ -284,5 +303,5 @@
       return RARRAY_PTR(ary)[0];
     default:
-      return RARRAY_PTR(ary)[mt_rand(random) % len];
+      return RARRAY_PTR(ary)[rand_uint32(random) % len];
     }
   }
@@ -299,5 +318,5 @@
       for (;;) {
       retry:
-        r = mt_rand(random) % len;
+        r = (mrb_int)(rand_uint32(random) % len);
 
         for (j=0; j<i; j++) {
@@ -317,4 +336,18 @@
 }
 
+static mrb_value
+random_f_rand(mrb_state *mrb, mrb_value self)
+{
+  rand_state *t = random_default_state(mrb);
+  return random_rand(mrb, t, get_opt(mrb));
+}
+
+static mrb_value
+random_f_srand(mrb_state *mrb, mrb_value self)
+{
+  mrb_value random = random_default(mrb);
+  return random_m_srand(mrb, random);
+}
+
 
 void mrb_mruby_random_gem_init(mrb_state *mrb)
@@ -323,15 +356,17 @@
   struct RClass *array = mrb->array_class;
 
-  mrb_define_method(mrb, mrb->kernel_module, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1));
-  mrb_define_method(mrb, mrb->kernel_module, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1));
+  mrb_assert(sizeof(rand_state) <= ISTRUCT_DATA_SIZE);
+
+  mrb_define_method(mrb, mrb->kernel_module, "rand", random_f_rand, MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, mrb->kernel_module, "srand", random_f_srand, MRB_ARGS_OPT(1));
 
   random = mrb_define_class(mrb, "Random", mrb->object_class);
-  MRB_SET_INSTANCE_TT(random, MRB_TT_DATA);
-  mrb_define_class_method(mrb, random, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1));
-  mrb_define_class_method(mrb, random, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1));
-
-  mrb_define_method(mrb, random, "initialize", mrb_random_init, MRB_ARGS_OPT(1));
-  mrb_define_method(mrb, random, "rand", mrb_random_rand, MRB_ARGS_OPT(1));
-  mrb_define_method(mrb, random, "srand", mrb_random_srand, MRB_ARGS_OPT(1));
+  MRB_SET_INSTANCE_TT(random, MRB_TT_ISTRUCT);
+  mrb_define_class_method(mrb, random, "rand", random_f_rand, MRB_ARGS_OPT(1));
+  mrb_define_class_method(mrb, random, "srand", random_f_srand, MRB_ARGS_OPT(1));
+
+  mrb_define_method(mrb, random, "initialize", random_m_init, MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, random, "rand", random_m_rand, MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, random, "srand", random_m_srand, MRB_ARGS_OPT(1));
 
   mrb_define_method(mrb, array, "shuffle", mrb_ary_shuffle, MRB_ARGS_OPT(1));
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-random/src/random.h
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-random/src/random.h	(revision 331)
+++ 	(revision )
@@ -1,12 +1,0 @@
-/*
-** random.h - Random module
-**
-** See Copyright Notice in mruby.h
-*/
-
-#ifndef MRUBY_RANDOM_H
-#define MRUBY_RANDOM_H
-
-void mrb_mruby_random_gem_init(mrb_state *mrb);
-
-#endif
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-random/test/random.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-random/test/random.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-random/test/random.rb	(revision 439)
@@ -2,46 +2,56 @@
 # Random Test
 
-assert("Random#srand") do
+assert("Random.new") do
   r1 = Random.new(123)
   r2 = Random.new(123)
-  r1.rand == r2.rand
+  r3 = Random.new(124)
+  assert_equal(r1.rand, r2.rand)
+  assert_not_equal(r1.rand, r3.rand)
 end
 
-assert("Kernel::srand") do
+assert("Kernel.srand") do
   srand(234)
   r1 = rand
   srand(234)
   r2 = rand
-  r1 == r2
+  srand(235)
+  r3 = rand
+  assert_equal(r1, r2)
+  assert_not_equal(r1, r3)
 end
 
-assert("Random::srand") do
+assert("Random.srand") do
   Random.srand(345)
   r1 = rand
   srand(345)
   r2 = Random.rand
-  r1 == r2
+  Random.srand(346)
+  r3 = rand
+  assert_equal(r1, r2)
+  assert_not_equal(r1, r3)
 end
 
-assert("fixnum") do
-  rand(3).class == Fixnum
-end
-
-assert("float") do
-  rand.class == Float
+assert("return class of Kernel.rand") do
+  assert_kind_of(Fixnum, rand(3))
+  assert_kind_of(Fixnum, rand(1.5))
+  assert_kind_of(Float, rand)
+  assert_kind_of(Float, rand(0.5))
 end
 
 assert("Array#shuffle") do
-  ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+  orig = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+  ary = orig.dup
   shuffled = ary.shuffle
-
-  ary == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and shuffled != ary and 10.times { |x| ary.include? x }
+  assert_equal(orig, ary)
+  assert_not_equal(ary, shuffled)
+  assert_equal(orig, shuffled.sort)
 end
 
 assert('Array#shuffle!') do
-  ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-  ary.shuffle!
-
-  ary != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary.include? x }
+  orig = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+  ary = orig.dup
+  assert_same(ary, ary.shuffle!)
+  assert_not_equal(orig, ary)
+  assert_equal(orig, ary.sort)
 end
 
@@ -53,10 +63,10 @@
 
   # verify that the same seed causes the same results
-  ary1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-  shuffle1 = ary1.shuffle Random.new 345
-  ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-  shuffle2 = ary2.shuffle Random.new 345
-
-  ary1 != shuffle1 and 10.times { |x| shuffle1.include? x } and shuffle1 == shuffle2
+  ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+  shuffled1 = ary.shuffle Random.new 345
+  shuffled2 = ary.shuffle Random.new 345
+  shuffled3 = ary.shuffle Random.new 346
+  assert_equal(shuffled1, shuffled2)
+  assert_not_equal(shuffled1, shuffled3)
 end
 
@@ -72,17 +82,41 @@
   ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
   ary2.shuffle! Random.new 345
-
-  ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2
+  ary3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+  ary3.shuffle! Random.new 346
+  assert_equal(ary1, ary2)
+  assert_not_equal(ary1, ary3)
 end
 
-assert('Array#sample checks input length after reading arguments') do
-  $ary = [1, 2, 3]
-  class ArrayChange
-    def to_i
-      $ary << 4
-      4
+assert('Array#sample') do
+  100.times do
+    assert_include([0, 1, 2], [2, 1, 0].sample)
+    [2, 1, 0].sample(2).each { |sample| assert_include([0, 1, 2], sample) }
+    h = {}
+    (1..10).to_a.sample(7).each do |sample|
+      assert_not_include(h, sample)
+      h[sample] = true
     end
   end
 
-  assert_equal [1, 2, 3, 4], $ary.sample(ArrayChange.new).sort
+  assert_nil([].sample)
+  assert_equal([], [].sample(1))
+  assert_equal([], [2, 1].sample(0))
+  assert_raise(TypeError) { [2, 1].sample(true) }
+  assert_raise(ArgumentError) { [2, 1].sample(-1) }
 end
+
+assert('Array#sample(random)') do
+  assert_raise(TypeError) do
+    # this will cause an exception due to the wrong argument
+    [1, 2].sample(2, "Not a Random instance")
+  end
+
+  # verify that the same seed causes the same results
+  ary = (1..10).to_a
+  srand(15)
+  samples1 = ary.sample(4)
+  samples2 = ary.sample(4, Random.new(15))
+  samples3 = ary.sample(4, Random.new(16))
+  assert_equal(samples1, samples2)
+  assert_not_equal(samples1, samples3)
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-range-ext/mrblib/range.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-range-ext/mrblib/range.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-range-ext/mrblib/range.rb	(revision 439)
@@ -16,8 +16,5 @@
     raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 1)" unless args.length == 1
     nv = args[0]
-    raise TypeError, "no implicit conversion from nil to integer" if nv.nil?
-    raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless nv.respond_to?(:to_int)
-    n = nv.to_int
-    raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless n.kind_of?(Integer)
+    n = nv.__to_int
     raise ArgumentError, "negative array size (or size too big)" unless 0 <= n
     ary = []
@@ -29,3 +26,41 @@
     ary
   end
+
+  def max(&block)
+    val = self.first
+    last = self.last
+    return super if block
+
+    # fast path for numerics
+    if val.kind_of?(Numeric) && last.kind_of?(Numeric)
+      raise TypeError if exclude_end? && !last.kind_of?(Fixnum)
+      return nil if val > last
+      return nil if val == last && exclude_end?
+
+      max = last
+      max -= 1 if exclude_end?
+      return max
+    end
+
+    # delegate to Enumerable
+    super
+  end
+
+  def min(&block)
+    val = self.first
+    last = self.last
+    return super if block
+
+    # fast path for numerics
+    if val.kind_of?(Numeric) && last.kind_of?(Numeric)
+      return nil if val > last
+      return nil if val == last && exclude_end?
+
+      min = val
+      return min
+    end
+
+    # delegate to Enumerable
+    super
+  end
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-range-ext/src/range.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-range-ext/src/range.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-range-ext/src/range.c	(revision 439)
@@ -2,17 +2,11 @@
 #include <mruby/range.h>
 #include <math.h>
-#include <float.h>
 
 static mrb_bool
 r_le(mrb_state *mrb, mrb_value a, mrb_value b)
 {
-  mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
-  /* output :a < b => -1, a = b =>  0, a > b => +1 */
+  mrb_int n = mrb_cmp(mrb, a, b);
 
-  if (mrb_fixnum_p(r)) {
-    mrb_int c = mrb_fixnum(r);
-    if (c == 0 || c == -1) return TRUE;
-  }
-
+  if (n == 0 || n == -1) return TRUE;
   return FALSE;
 }
@@ -21,8 +15,5 @@
 r_lt(mrb_state *mrb, mrb_value a, mrb_value b)
 {
-  mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b);
-  /* output :a < b => -1, a = b =>  0, a > b => +1 */
-
-  return mrb_fixnum_p(r) && mrb_fixnum(r) == -1;
+  return mrb_cmp(mrb, a, b) == -1;
 }
 
@@ -42,5 +33,5 @@
  */
 static mrb_value
-mrb_range_cover(mrb_state *mrb, mrb_value range)
+range_cover(mrb_state *mrb, mrb_value range)
 {
   mrb_value val;
@@ -50,9 +41,9 @@
   mrb_get_args(mrb, "o", &val);
 
-  beg = r->edges->beg;
-  end = r->edges->end;
+  beg = RANGE_BEG(r);
+  end = RANGE_END(r);
 
   if (r_le(mrb, beg, val)) {
-    if (r->excl) {
+    if (RANGE_EXCL(r)) {
       if (r_lt(mrb, val, end))
         return mrb_true_value();
@@ -84,12 +75,11 @@
  */
 static mrb_value
-mrb_range_last(mrb_state *mrb, mrb_value range)
+range_last(mrb_state *mrb, mrb_value range)
 {
   mrb_value num;
   mrb_value array;
-  struct RRange *r = mrb_range_ptr(mrb, range);
 
   if (mrb_get_args(mrb, "|o", &num) == 0) {
-    return r->edges->end;
+    return mrb_range_end(mrb, range);
   }
 
@@ -109,6 +99,7 @@
  */
 
+#ifndef MRB_WITHOUT_FLOAT
 static mrb_value
-mrb_range_size(mrb_state *mrb, mrb_value range)
+range_size(mrb_state *mrb, mrb_value range)
 {
   struct RRange *r = mrb_range_ptr(mrb, range);
@@ -118,7 +109,7 @@
   mrb_bool excl;
 
-  beg = r->edges->beg;
-  end = r->edges->end;
-  excl = r->excl;
+  beg = RANGE_BEG(r);
+  end = RANGE_END(r);
+  excl = RANGE_EXCL(r);
   if (mrb_fixnum_p(beg)) {
     beg_f = (mrb_float)mrb_fixnum(beg);
@@ -161,4 +152,26 @@
   return mrb_nil_value();
 }
+#else
+static mrb_value
+range_size(mrb_state *mrb, mrb_value range)
+{
+  struct RRange *r = mrb_range_ptr(mrb, range);
+  mrb_value beg, end;
+  mrb_int excl;
+
+  beg = RANGE_BEG(r);
+  end = RANGE_END(r);
+  excl = RANGE_EXCL(r) ? 0 : 1;
+
+  if (mrb_fixnum_p(beg) && mrb_fixnum_p(end)) {
+    mrb_int a = mrb_fixnum(beg);
+    mrb_int b = mrb_fixnum(end);
+    mrb_int c = b - a + excl;
+
+    return mrb_fixnum_value(c);
+  }
+  return mrb_nil_value();
+}
+#endif /* MRB_WITHOUT_FLOAT */
 
 void
@@ -167,7 +180,7 @@
   struct RClass * s = mrb_class_get(mrb, "Range");
 
-  mrb_define_method(mrb, s, "cover?", mrb_range_cover, MRB_ARGS_REQ(1));
-  mrb_define_method(mrb, s, "last",   mrb_range_last,  MRB_ARGS_OPT(1));
-  mrb_define_method(mrb, s, "size",   mrb_range_size,  MRB_ARGS_NONE());
+  mrb_define_method(mrb, s, "cover?", range_cover, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, s, "last",   range_last,  MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, s, "size",   range_size,  MRB_ARGS_NONE());
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-range-ext/test/range.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-range-ext/test/range.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-range-ext/test/range.rb	(revision 439)
@@ -11,4 +11,6 @@
   assert_equal 10, (10..20).first
   assert_equal [10, 11, 12], (10..20).first(3)
+
+  skip unless Object.const_defined?(:Float)
   assert_equal [0, 1, 2], (0..Float::INFINITY).first(3)
 end
@@ -24,4 +26,7 @@
   assert_equal 42, (1..42).size
   assert_equal 41, (1...42).size
+  assert_nil ('a'..'z').size
+
+  skip unless Object.const_defined?(:Float)
   assert_equal 6, (1...6.3).size
   assert_equal 5, (1...6.0).size
@@ -29,4 +34,109 @@
   assert_equal 15, (1.0..15.9).size
   assert_equal Float::INFINITY, (0..Float::INFINITY).size
-  assert_nil ('a'..'z').size
 end
+
+assert('Range#max') do
+  # returns the maximum value in the range when called with no arguments
+  assert_equal 10, (1..10).max
+  assert_equal 9, (1...10).max
+  assert_equal 536870911, (0...2**29).max
+
+  # returns nil when the endpoint is less than the start point
+  assert_equal nil, (100..10).max
+
+  # returns nil when the endpoint equals the start point and the range is exclusive
+  assert_equal nil, (5...5).max
+
+  # returns the endpoint when the endpoint equals the start point and the range is inclusive
+  assert_equal 5, (5..5).max
+
+  skip unless Object.const_defined?(:Float)
+
+  # returns the maximum value in the Float range when called with no arguments
+  assert_equal 908.1111, (303.20..908.1111).max
+
+  # raises TypeError when called on an exclusive range and a non Integer value
+  assert_raise(TypeError) { (303.20...908.1111).max }
+
+  # returns nil when the endpoint is less than the start point in a Float range
+  assert_equal nil, (3003.20..908.1111).max
+end
+
+assert('Range#max given a block') do
+  # passes each pair of values in the range to the block
+  acc = []
+  (1..10).max do |a, b|
+    acc << a
+    acc << b
+    a
+  end
+  (1..10).each do |value|
+    assert_true acc.include?(value)
+  end
+
+  # passes each pair of elements to the block in reversed order
+  acc = []
+  (1..5).max do |a, b|
+    acc << [a, b]
+    a
+  end
+  assert_equal [[2, 1], [3, 2], [4, 3], [5, 4]], acc
+
+  # returns the element the block determines to be the maximum
+  assert_equal 1, ((1..3).max { |_a, _b| -3 })
+
+  # returns nil when the endpoint is less than the start point
+  assert_equal nil, ((100..10).max { |x, y| x <=> y })
+  assert_equal nil, ((5...5).max { |x, y| x <=> y })
+end
+
+assert('Range#min') do
+  # returns the minimum value in the range when called with no arguments
+  assert_equal 1, (1..10).min
+  assert_equal 1, (1...10).min
+
+  # returns nil when the start point is greater than the endpoint
+  assert_equal nil, (100..10).min
+
+  # returns nil when the endpoint equals the start point and the range is exclusive
+  assert_equal nil, (5...5).max
+
+  # returns the endpoint when the endpoint equals the start point and the range is inclusive
+  assert_equal 5, (5..5).max
+
+  skip unless Object.const_defined?(:Float)
+
+  # returns the minimum value in the Float range when called with no arguments
+  assert_equal 303.20, (303.20..908.1111).min
+
+  # returns nil when the start point is greater than the endpoint in a Float range
+  assert_equal nil, (3003.20..908.1111).max
+end
+
+assert('Range#min given a block') do
+  # passes each pair of values in the range to the block
+  acc = []
+  (1..10).min do |a, b|
+    acc << a
+    acc << b
+    a
+  end
+  (1..10).each do |value|
+    assert_true acc.include?(value)
+  end
+
+  # passes each pair of elements to the block in reversed order
+  acc = []
+  (1..5).min do |a, b|
+    acc << [a, b]
+    a
+  end
+  assert_equal [[2, 1], [3, 1], [4, 1], [5, 1]], acc
+
+  # returns the element the block determines to be the minimum
+  assert_equal 3, ((1..3).min { |_a, _b| -3 })
+
+  # returns nil when the start point is greater than the endpoint
+  assert_equal nil, ((100..10).min { |x, y| x <=> y })
+  assert_equal nil, ((5...5).min { |x, y| x <=> y })
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/mrbgem.rake	(revision 439)
@@ -0,0 +1,5 @@
+MRuby::Gem::Specification.new('mruby-rational') do |spec|
+  spec.license = 'MIT'
+  spec.author  = 'mruby developers'
+  spec.summary = 'Rational class'
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/mrblib/rational.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/mrblib/rational.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/mrblib/rational.rb	(revision 439)
@@ -0,0 +1,117 @@
+class Rational < Numeric
+  def inspect
+    "(#{to_s})"
+  end
+
+  def to_s
+    "#{numerator}/#{denominator}"
+  end
+
+  def *(rhs)
+    if rhs.is_a? Rational
+      Rational(numerator * rhs.numerator, denominator * rhs.denominator)
+    elsif rhs.is_a? Integer
+      Rational(numerator * rhs, denominator)
+    elsif rhs.is_a? Numeric
+      numerator * rhs / denominator
+    end
+  end
+
+  def +(rhs)
+    if rhs.is_a? Rational
+      Rational(numerator * rhs.denominator + rhs.numerator * denominator, denominator * rhs.denominator)
+    elsif rhs.is_a? Integer
+      Rational(numerator + rhs * denominator, denominator)
+    elsif rhs.is_a? Numeric
+      (numerator + rhs * denominator) / denominator
+    end
+  end
+
+  def -(rhs)
+    if rhs.is_a? Rational
+      Rational(numerator * rhs.denominator - rhs.numerator * denominator, denominator * rhs.denominator)
+    elsif rhs.is_a? Integer
+      Rational(numerator - rhs * denominator, denominator)
+    elsif rhs.is_a? Numeric
+      (numerator - rhs * denominator) / denominator
+    end
+  end
+
+  def /(rhs)
+    if rhs.is_a? Rational
+      Rational(numerator * rhs.denominator, denominator * rhs.numerator)
+    elsif rhs.is_a? Integer
+      Rational(numerator, denominator * rhs)
+    elsif rhs.is_a? Numeric
+      numerator / rhs / denominator
+    end
+  end
+
+  def <=>(rhs)
+    if rhs.is_a?(Integral)
+      return numerator <=> rhs if denominator == 1
+      rhs = Rational(rhs)
+    end
+
+    case rhs
+    when Rational
+      (numerator * rhs.denominator - denominator * rhs.numerator) <=> 0
+    when Numeric
+      (rhs <=> self)&.-@
+    else
+      nil
+    end
+  end
+
+  def ==(rhs)
+    return true if self.equal?(rhs)
+    if rhs.is_a?(Integral) && denominator == 1
+      return numerator == rhs
+    end
+    if rhs.is_a?(Rational)
+      numerator * rhs.denominator == denominator * rhs.numerator
+    else
+      rhs == self
+    end
+  end
+end
+
+class Numeric
+  def to_r
+    Rational(self, 1)
+  end
+end
+
+module Kernel
+  def Rational(numerator, denominator = 1)
+    a = numerator
+    b = denominator
+    a, b = b, a % b until b == 0
+    Rational._new(numerator.div(a), denominator.div(a))
+  end
+
+  [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op|
+    Fixnum.instance_eval do
+      original_operator_name = "__original_operator_#{op}_rational"
+      alias_method original_operator_name, op
+      define_method op do |rhs|
+        if rhs.is_a? Rational
+          Rational(self).__send__(op, rhs)
+        else
+          __send__(original_operator_name, rhs)
+        end
+      end
+    end
+    Float.instance_eval do
+      original_operator_name = "__original_operator_#{op}_rational"
+      alias_method original_operator_name, op
+      define_method op do |rhs|
+        if rhs.is_a? Rational
+          rhs = rhs.to_f
+        end
+        __send__(original_operator_name, rhs)
+      end
+    end if Object.const_defined?(:Float)
+  end
+end
+
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/src/rational.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/src/rational.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/src/rational.c	(revision 439)
@@ -0,0 +1,209 @@
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/string.h>
+#include <mruby/numeric.h>
+
+struct mrb_rational {
+  mrb_int numerator;
+  mrb_int denominator;
+};
+
+#if MRB_INT_MAX <= INTPTR_MAX
+
+#define RATIONAL_USE_ISTRUCT
+/* use TT_ISTRUCT */
+#include <mruby/istruct.h>
+
+#define rational_ptr(mrb, v) (struct mrb_rational*)mrb_istruct_ptr(v)
+
+static struct RBasic*
+rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p)
+{
+  struct RIStruct *s;
+
+  s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c);
+  *p = (struct mrb_rational*)s->inline_data;
+
+  return (struct RBasic*)s;
+}
+
+#else
+/* use TT_DATA */
+#include <mruby/data.h>
+
+static const struct mrb_data_type mrb_rational_type = {"Rational", mrb_free};
+
+static struct RBasic*
+rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p)
+{
+  struct RData *d;
+
+  Data_Make_Struct(mrb, c, struct mrb_rational, &mrb_rational_type, *p, d);
+
+  return (struct RBasic*)d;
+}
+
+static struct mrb_rational*
+rational_ptr(mrb_state *mrb, mrb_value v)
+{
+  struct mrb_rational *p;
+
+  p = DATA_GET_PTR(mrb, v, &mrb_rational_type, struct mrb_rational);
+  if (!p) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized rational");
+  }
+  return p;
+}
+#endif
+
+static mrb_value
+rational_numerator(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_rational *p = rational_ptr(mrb, self);
+  return mrb_fixnum_value(p->numerator);
+}
+
+static mrb_value
+rational_denominator(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_rational *p = rational_ptr(mrb, self);
+  return mrb_fixnum_value(p->denominator);
+}
+
+static mrb_value
+rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator)
+{
+  struct RClass *c = mrb_class_get(mrb, "Rational");
+  struct mrb_rational *p;
+  struct RBasic *rat = rational_alloc(mrb, c, &p);
+  p->numerator = numerator;
+  p->denominator = denominator;
+  MRB_SET_FROZEN_FLAG(rat);
+  return mrb_obj_value(rat);
+}
+
+static mrb_value
+rational_s_new(mrb_state *mrb, mrb_value self)
+{
+  mrb_int numerator, denominator;
+
+#ifdef MRB_WITHOUT_FLOAT
+  mrb_get_args(mrb, "ii", &numerator, &denominator);
+#else
+
+#define DROP_PRECISION(cond, num, denom) \
+  do { \
+      while (cond) { \
+        num /= 2; \
+        denom /= 2; \
+      } \
+  } while (0)
+
+  mrb_value numv, denomv;
+
+  mrb_get_args(mrb, "oo", &numv, &denomv);
+  if (mrb_fixnum_p(numv)) {
+    numerator = mrb_fixnum(numv);
+
+    if (mrb_fixnum_p(denomv)) {
+      denominator = mrb_fixnum(denomv);
+    }
+    else {
+      mrb_float denomf = mrb_to_flo(mrb, denomv);
+
+      DROP_PRECISION(denomf < MRB_INT_MIN || denomf > MRB_INT_MAX, numerator, denomf);
+      denominator = denomf;
+    }
+  }
+  else {
+    mrb_float numf = mrb_to_flo(mrb, numv);
+
+    if (mrb_fixnum_p(denomv)) {
+      denominator = mrb_fixnum(denomv);
+    }
+    else {
+      mrb_float denomf = mrb_to_flo(mrb, denomv);
+
+      DROP_PRECISION(denomf < MRB_INT_MIN || denomf > MRB_INT_MAX, numf, denomf);
+      denominator = denomf;
+    }
+
+    DROP_PRECISION(numf < MRB_INT_MIN || numf > MRB_INT_MAX, numf, denominator);
+    numerator = numf;
+  }
+#endif
+
+  return rational_new(mrb, numerator, denominator);
+}
+
+#ifndef MRB_WITHOUT_FLOAT
+static mrb_value
+rational_to_f(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_rational *p = rational_ptr(mrb, self);
+  mrb_float f = (mrb_float)p->numerator / (mrb_float)p->denominator;
+
+  return mrb_float_value(mrb, f);
+}
+#endif
+
+static mrb_value
+rational_to_i(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_rational *p = rational_ptr(mrb, self);
+  if (p->denominator == 0) {
+    mrb_raise(mrb, mrb_exc_get(mrb, "StandardError"), "divided by 0");
+  }
+  return mrb_fixnum_value(p->numerator / p->denominator);
+}
+
+static mrb_value
+rational_to_r(mrb_state *mrb, mrb_value self)
+{
+  return self;
+}
+
+static mrb_value
+rational_negative_p(mrb_state *mrb, mrb_value self)
+{
+  struct mrb_rational *p = rational_ptr(mrb, self);
+  if (p->numerator < 0) {
+    return mrb_true_value();
+  }
+  return mrb_false_value();
+}
+
+static mrb_value
+fix_to_r(mrb_state *mrb, mrb_value self)
+{
+  return rational_new(mrb, mrb_fixnum(self), 1);
+}
+
+void mrb_mruby_rational_gem_init(mrb_state *mrb)
+{
+  struct RClass *rat;
+
+  rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric"));
+#ifdef RATIONAL_USE_ISTRUCT
+  MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT);
+  mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE);
+#else
+  MRB_SET_INSTANCE_TT(rat, MRB_TT_DATA);
+#endif
+  mrb_undef_class_method(mrb, rat, "new");
+  mrb_define_class_method(mrb, rat, "_new", rational_s_new, MRB_ARGS_REQ(2));
+  mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE());
+  mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE());
+#ifndef MRB_WITHOUT_FLOAT
+  mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE());
+#endif
+  mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE());
+  mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE());
+  mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE());
+  mrb_define_method(mrb, mrb->fixnum_class, "to_r", fix_to_r, MRB_ARGS_NONE());
+}
+
+void
+mrb_mruby_rational_gem_final(mrb_state* mrb)
+{
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/test/rational.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/test/rational.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-rational/test/rational.rb	(revision 439)
@@ -0,0 +1,308 @@
+class UserDefinedNumeric < Numeric
+  def initialize(n)
+    @n = n
+  end
+
+  def <=>(rhs)
+    return nil unless rhs.respond_to?(:to_i)
+    rhs = rhs.to_i
+    rhs < 0 ? nil : @n <=> rhs
+  end
+
+  def inspect
+    "#{self.class}(#{@n})"
+  end
+end
+
+class ComplexLikeNumeric < UserDefinedNumeric
+  def ==(rhs)
+    @n == 0 && rhs == 0
+  end
+
+  undef <=>
+end
+
+def assert_rational(exp, real)
+  assert "assert_rational" do
+    assert_float exp.numerator,   real.numerator
+    assert_float exp.denominator, real.denominator
+  end
+end
+
+def assert_equal_rational(exp, o1, o2)
+  assert "assert_equal_rational" do
+    if exp
+      assert_operator(o1, :==, o2)
+      assert_not_operator(o1, :!=, o2)
+    else
+      assert_not_operator(o1, :==, o2)
+      assert_operator(o1, :!=, o2)
+    end
+  end
+end
+
+def assert_cmp(exp, o1, o2)
+  if exp == (o1 <=> o2)
+    pass
+  else
+    flunk "", "    Expected #{o1.inspect} <=> #{o2.inspect} to be #{exp}."
+  end
+end
+
+assert 'Rational' do
+  r = 5r
+  assert_equal(Rational, r.class)
+  assert_equal([5, 1], [r.numerator, r.denominator])
+end
+
+assert 'Kernel#Rational' do
+  r = Rational(4,10)
+  assert_equal(2, r.numerator)
+  assert_equal(5, r.denominator)
+
+  r = Rational(3)
+  assert_equal(3, r.numerator)
+  assert_equal(1, r.denominator)
+
+  assert_raise(ArgumentError) { Rational() }
+  assert_raise(ArgumentError) { Rational(1,2,3) }
+end
+
+assert 'Rational#to_f' do
+  assert_float(2.0, Rational(2).to_f)
+  assert_float(2.25, Rational(9, 4).to_f)
+  assert_float(-0.75, Rational(-3, 4).to_f)
+  assert_float(6.666666666666667, Rational(20, 3).to_f)
+end
+
+assert 'Rational#to_i' do
+  assert_equal(0, Rational(2, 3).to_i)
+  assert_equal(3, Rational(3).to_i)
+  assert_equal(300, Rational(300.6).to_i)
+  assert_equal(1, Rational(98, 71).to_i)
+  assert_equal(-15, Rational(-30, 2).to_i)
+end
+
+assert 'Rational#*' do
+  assert_rational(Rational(4, 9),    Rational(2, 3)  * Rational(2, 3))
+  assert_rational(Rational(900, 1),  Rational(900)   * Rational(1))
+  assert_rational(Rational(1, 1),    Rational(-2, 9) * Rational(-9, 2))
+  assert_rational(Rational(9, 2),    Rational(9, 8)  * 4)
+  assert_float(   21.77777777777778, Rational(20, 9) * 9.8)
+end
+
+assert 'Rational#+' do
+  assert_rational(Rational(4, 3),     Rational(2, 3)  + Rational(2, 3))
+  assert_rational(Rational(901, 1),   Rational(900)   + Rational(1))
+  assert_rational(Rational(-85, 18),  Rational(-2, 9) + Rational(-9, 2))
+  assert_rational(Rational(41, 8),    Rational(9, 8)  + 4)
+  assert_float(   12.022222222222222, Rational(20, 9) + 9.8)
+end
+
+assert 'Rational#-' do
+  assert_rational(Rational(0, 1),     Rational(2, 3)  - Rational(2, 3))
+  assert_rational(Rational(899, 1),   Rational(900)   - Rational(1))
+  assert_rational(Rational(77, 18),   Rational(-2, 9) - Rational(-9, 2))
+  assert_rational(Rational(-23, 8),   Rational(9, 8)  - 4)
+  assert_float(   -7.577777777777778, Rational(20, 9) - 9.8)
+end
+
+assert 'Rational#/' do
+  assert_rational(Rational(1, 1),      Rational(2, 3)  / Rational(2, 3))
+  assert_rational(Rational(900, 1),    Rational(900)   / Rational(1))
+  assert_rational(Rational(4, 81),     Rational(-2, 9) / Rational(-9, 2))
+  assert_rational(Rational(9, 32),     Rational(9, 8)  / 4)
+  assert_float(   0.22675736961451246, Rational(20, 9) / 9.8)
+end
+
+assert 'Rational#==, Rational#!=' do
+  assert_equal_rational(true, Rational(1,1), Rational(1))
+  assert_equal_rational(true, Rational(-1,1), -1r)
+  assert_equal_rational(true, Rational(13,4), 3.25)
+  assert_equal_rational(true, Rational(13,3.25), Rational(4,1))
+  assert_equal_rational(true, Rational(-3,-4), Rational(3,4))
+  assert_equal_rational(true, Rational(-4,5), Rational(4,-5))
+  assert_equal_rational(true, Rational(4,2), 2)
+  assert_equal_rational(true, Rational(-4,2), -2)
+  assert_equal_rational(true, Rational(4,-2), -2)
+  assert_equal_rational(true, Rational(4,2), 2.0)
+  assert_equal_rational(true, Rational(-4,2), -2.0)
+  assert_equal_rational(true, Rational(4,-2), -2.0)
+  assert_equal_rational(true, Rational(8,6), Rational(4,3))
+  assert_equal_rational(false, Rational(13,4), 3)
+  assert_equal_rational(false, Rational(13,4), 3.3)
+  assert_equal_rational(false, Rational(2,1), 1r)
+  assert_equal_rational(false, Rational(1), nil)
+  assert_equal_rational(false, Rational(1), '')
+  assert_equal_rational(true, 0r, UserDefinedNumeric.new(0))
+  assert_equal_rational(true, 1r, UserDefinedNumeric.new(1))
+  assert_equal_rational(false, 1r, UserDefinedNumeric.new(2))
+  assert_equal_rational(false, -1r, UserDefinedNumeric.new(-1))
+  assert_equal_rational(true, 0r, ComplexLikeNumeric.new(0))
+  assert_equal_rational(false, 1r, ComplexLikeNumeric.new(1))
+  assert_equal_rational(false, 1r, ComplexLikeNumeric.new(2))
+end
+
+assert 'Fixnum#==(Rational), Fixnum#!=(Rational)' do
+  assert_equal_rational(true, 2, Rational(4,2))
+  assert_equal_rational(true, -2, Rational(-4,2))
+  assert_equal_rational(true, -2, Rational(4,-2))
+  assert_equal_rational(false, 3, Rational(13,4))
+end
+
+assert 'Float#==(Rational), Float#!=(Rational)' do
+  assert_equal_rational(true, 2.0, Rational(4,2))
+  assert_equal_rational(true, -2.0, Rational(-4,2))
+  assert_equal_rational(true, -2.0, Rational(4,-2))
+  assert_equal_rational(false, 3.3, Rational(13,4))
+end
+
+assert 'Rational#<=>' do
+  assert_cmp(-1, Rational(-1), Rational(0))
+  assert_cmp(0, Rational(0), Rational(0))
+  assert_cmp(1, Rational(1), Rational(0))
+  assert_cmp(-1, Rational(-1), 0)
+  assert_cmp(0, Rational(0), 0)
+  assert_cmp(1, Rational(1), 0)
+  assert_cmp(-1, Rational(-1), 0.0)
+  assert_cmp(0, Rational(0), 0.0)
+  assert_cmp(1, Rational(1), 0.0)
+  assert_cmp(-1, Rational(1,2), Rational(2,3))
+  assert_cmp(0, Rational(2,3), Rational(2,3))
+  assert_cmp(1, Rational(2,3), Rational(1,2))
+  assert_cmp(1, Rational(2,3), Rational(1,2))
+  assert_cmp(1, Rational(0), Rational(-1))
+  assert_cmp(-1, Rational(0), Rational(1))
+  assert_cmp(1, Rational(2,3), Rational(1,2))
+  assert_cmp(0, Rational(2,3), Rational(2,3))
+  assert_cmp(-1, Rational(1,2), Rational(2,3))
+  assert_cmp(-1, Rational(1,2), Rational(2,3))
+  assert_cmp(nil, 3r, "3")
+  assert_cmp(1, 3r, UserDefinedNumeric.new(2))
+  assert_cmp(0, 3r, UserDefinedNumeric.new(3))
+  assert_cmp(-1, 3r, UserDefinedNumeric.new(4))
+  assert_cmp(nil, Rational(-3), UserDefinedNumeric.new(5))
+  assert_raise(NoMethodError) { 0r <=> ComplexLikeNumeric.new(0) }
+  assert_raise(NoMethodError) { 1r <=> ComplexLikeNumeric.new(2) }
+end
+
+assert 'Fixnum#<=>(Rational)' do
+  assert_cmp(-1, -2, Rational(-9,5))
+  assert_cmp(0, 5, 5r)
+  assert_cmp(1, 3, Rational(8,3))
+end
+
+assert 'Float#<=>(Rational)' do
+  assert_cmp(-1, -2.1, Rational(-9,5))
+  assert_cmp(0, 5.0, 5r)
+  assert_cmp(1, 2.7, Rational(8,3))
+end
+
+assert 'Rational#<' do
+  assert_operator(Rational(1,2), :<, Rational(2,3))
+  assert_not_operator(Rational(2,3), :<, Rational(2,3))
+  assert_operator(Rational(2,3), :<, 1)
+  assert_not_operator(2r, :<, 2)
+  assert_not_operator(Rational(2,3), :<, -3)
+  assert_operator(Rational(-4,3), :<, -0.3)
+  assert_not_operator(Rational(13,4), :<, 3.25)
+  assert_not_operator(Rational(2,3), :<, 0.6)
+  assert_raise(ArgumentError) { 1r < "2" }
+end
+
+assert 'Fixnum#<(Rational)' do
+  assert_not_operator(1, :<, Rational(2,3))
+  assert_not_operator(2, :<, 2r)
+  assert_operator(-3, :<, Rational(2,3))
+end
+
+assert 'Float#<(Rational)' do
+  assert_not_operator(-0.3, :<, Rational(-4,3))
+  assert_not_operator(3.25, :<, Rational(13,4))
+  assert_operator(0.6, :<, Rational(2,3))
+end
+
+assert 'Rational#<=' do
+  assert_operator(Rational(1,2), :<=, Rational(2,3))
+  assert_operator(Rational(2,3), :<=, Rational(2,3))
+  assert_operator(Rational(2,3), :<=, 1)
+  assert_operator(2r, :<=, 2)
+  assert_not_operator(Rational(2,3), :<=, -3)
+  assert_operator(Rational(-4,3), :<=, -0.3)
+  assert_operator(Rational(13,4), :<=, 3.25)
+  assert_not_operator(Rational(2,3), :<=, 0.6)
+  assert_raise(ArgumentError) { 1r <= "2" }
+end
+
+assert 'Fixnum#<=(Rational)' do
+  assert_not_operator(1, :<=, Rational(2,3))
+  assert_operator(2, :<=, 2r)
+  assert_operator(-3, :<=, Rational(2,3))
+end
+
+assert 'Float#<=(Rational)' do
+  assert_not_operator(-0.3, :<=, Rational(-4,3))
+  assert_operator(3.25, :<=, Rational(13,4))
+  assert_operator(0.6, :<=, Rational(2,3))
+end
+
+assert 'Rational#>' do
+  assert_not_operator(Rational(1,2), :>, Rational(2,3))
+  assert_not_operator(Rational(2,3), :>, Rational(2,3))
+  assert_not_operator(Rational(2,3), :>, 1)
+  assert_not_operator(2r, :>, 2)
+  assert_operator(Rational(2,3), :>, -3)
+  assert_not_operator(Rational(-4,3), :>, -0.3)
+  assert_not_operator(Rational(13,4), :>, 3.25)
+  assert_operator(Rational(2,3), :>, 0.6)
+  assert_raise(ArgumentError) { 1r > "2" }
+end
+
+assert 'Fixnum#>(Rational)' do
+  assert_operator(1, :>, Rational(2,3))
+  assert_not_operator(2, :>, 2r)
+  assert_not_operator(-3, :>, Rational(2,3))
+end
+
+assert 'Float#>(Rational)' do
+  assert_operator(-0.3, :>, Rational(-4,3))
+  assert_not_operator(3.25, :>, Rational(13,4))
+  assert_not_operator(0.6, :>, Rational(2,3))
+end
+
+assert 'Rational#>=' do
+  assert_not_operator(Rational(1,2), :>=, Rational(2,3))
+  assert_operator(Rational(2,3), :>=, Rational(2,3))
+  assert_not_operator(Rational(2,3), :>=, 1)
+  assert_operator(2r, :>=, 2)
+  assert_operator(Rational(2,3), :>=, -3)
+  assert_not_operator(Rational(-4,3), :>=, -0.3)
+  assert_operator(Rational(13,4), :>=, 3.25)
+  assert_operator(Rational(2,3), :>=, 0.6)
+  assert_raise(ArgumentError) { 1r >= "2" }
+end
+
+assert 'Fixnum#>=(Rational)' do
+  assert_operator(1, :>=, Rational(2,3))
+  assert_operator(2, :>=, 2r)
+  assert_not_operator(-3, :>=, Rational(2,3))
+end
+
+assert 'Float#>=(Rational)' do
+  assert_operator(-0.3, :>=, Rational(-4,3))
+  assert_operator(3.25, :>=, Rational(13,4))
+  assert_not_operator(0.6, :>=, Rational(2,3))
+end
+
+assert 'Rational#negative?' do
+  assert_predicate(Rational(-2,3), :negative?)
+  assert_predicate(Rational(2,-3), :negative?)
+  assert_not_predicate(Rational(2,3), :negative?)
+  assert_not_predicate(Rational(0), :negative?)
+end
+
+assert 'Rational#frozen?' do
+  assert_predicate(1r, :frozen?)
+  assert_predicate(Rational(2,3), :frozen?)
+  assert_predicate(4/5r, :frozen?)
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/README.md
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/README.md	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/README.md	(revision 439)
@@ -0,0 +1,27 @@
+# Sleep Module for mruby
+mruby sleep module
+
+## install by mrbgems
+ - add conf.gem line to `build_config.rb`
+```ruby
+MRuby::Build.new do |conf|
+
+    # ... (snip) ...
+
+    conf.gem :core => 'mruby-sleep'
+end
+```
+
+## example
+
+```ruby
+sleep(10)
+usleep(10000)
+```
+
+# License
+under the MIT License:
+
+* http://www.opensource.org/licenses/mit-license.php
+
+
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/example/sleep.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/example/sleep.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/example/sleep.rb	(revision 439)
@@ -0,0 +1,3 @@
+sleep(10)
+usleep(10000)
+
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/mrbgem.rake	(revision 439)
@@ -0,0 +1,5 @@
+MRuby::Gem::Specification.new('mruby-sleep') do |spec|
+  spec.license = 'MIT'
+  spec.authors = ['MATSUMOTO Ryosuke', 'mruby developers']
+  spec.version = '0.0.1'
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/src/mrb_sleep.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/src/mrb_sleep.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/src/mrb_sleep.c	(revision 439)
@@ -0,0 +1,136 @@
+/*
+** mrb_sleep - sleep methods for mruby
+**
+** Copyright (c) mod_mruby developers 2012-
+** Copyright (c) mruby developers 2018
+**
+** 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.
+**
+** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
+*/
+
+#include <time.h>
+#ifdef _WIN32
+    #include <windows.h>
+    #define sleep(x) Sleep(x * 1000)
+    #define usleep(x) Sleep((DWORD)((x)<1000) ? 1 : ((x)/1000))
+#else
+    #include <unistd.h>
+    #include <sys/time.h>
+#endif
+
+#include "mruby.h"
+
+/* not implemented forever sleep (called without an argument)*/
+static mrb_value
+mrb_f_sleep(mrb_state *mrb, mrb_value self)
+{
+    time_t beg = time(0);
+    time_t end;
+#ifndef MRB_WITHOUT_FLOAT
+    mrb_float sec;
+
+    mrb_get_args(mrb, "f", &sec);
+    if (sec >= 0) {
+        usleep(sec * 1000000);
+    }
+    else {
+        mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must not be negative");
+    }
+#else
+    mrb_int sec;
+
+    mrb_get_args(mrb, "i", &sec);
+    if (sec >= 0) {
+        sleep(sec);
+    } else {
+        mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must not be negative");
+    }
+#endif
+    end = time(0) - beg;
+
+    return mrb_fixnum_value(end);
+}
+
+/* mruby special; needed for mruby without float numbers */
+static mrb_value
+mrb_f_usleep(mrb_state *mrb, mrb_value self)
+{
+    mrb_int usec;
+#ifdef _WIN32
+    FILETIME st_ft,ed_ft;
+    unsigned __int64 st_time = 0;
+    unsigned __int64 ed_time = 0;
+#else
+    struct timeval st_tm,ed_tm;
+#endif
+    time_t slp_tm;
+
+#ifdef _WIN32
+    GetSystemTimeAsFileTime(&st_ft);
+#else
+    gettimeofday(&st_tm, NULL);
+#endif
+
+    /* not implemented forever sleep (called without an argument)*/
+    mrb_get_args(mrb, "i", &usec);
+
+    if (usec >= 0) {
+        usleep(usec);
+    } else {
+        mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must not be negative integer");
+    }
+
+#ifdef _WIN32
+    GetSystemTimeAsFileTime(&ed_ft);
+
+    st_time |= st_ft.dwHighDateTime;
+    st_time <<=32;
+    st_time |= st_ft.dwLowDateTime;
+    ed_time |= ed_ft.dwHighDateTime;
+    ed_time <<=32;
+    ed_time |= ed_ft.dwLowDateTime;
+
+    slp_tm = (ed_time - st_time) / 10;
+#else
+    gettimeofday(&ed_tm, NULL);
+
+    if (st_tm.tv_usec > ed_tm.tv_usec) {
+        slp_tm = 1000000 + ed_tm.tv_usec - st_tm.tv_usec;
+    }
+    else {
+        slp_tm = ed_tm.tv_usec - st_tm.tv_usec;
+    }
+#endif
+
+    return mrb_fixnum_value(slp_tm);
+}
+
+void
+mrb_mruby_sleep_gem_init(mrb_state *mrb)
+{
+    mrb_define_method(mrb, mrb->kernel_module, "sleep",   mrb_f_sleep,   MRB_ARGS_REQ(1));
+    mrb_define_method(mrb, mrb->kernel_module, "usleep",  mrb_f_usleep,  MRB_ARGS_REQ(1));
+}
+
+void
+mrb_mruby_sleep_gem_final(mrb_state *mrb)
+{
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/test/sleep_test.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/test/sleep_test.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sleep/test/sleep_test.rb	(revision 439)
@@ -0,0 +1,29 @@
+assert("sleep works") do
+  assert_nothing_raised { sleep(1) }
+  assert_nothing_raised { sleep(0) }
+end
+
+assert("sleep would accept non-negative float value") do
+  skip unless Object.const_defined?(:Float)
+  assert_nothing_raised { sleep(0.01) }
+  assert_nothing_raised { sleep(0.0) }
+  assert_nothing_raised { sleep(-0.0) }
+end
+
+assert("sleep would not accept negative integer value") do
+  assert_raise(ArgumentError) { sleep(-1) }
+end
+
+assert("sleep would not accept negative float value") do
+  skip unless Object.const_defined?(:Float)
+  assert_raise(ArgumentError) { sleep(-0.1) }
+end
+
+assert("usleep works") do
+  assert_nothing_raised { usleep(100) }
+  assert_nothing_raised { usleep(0) }
+end
+
+assert("usleep would not accept negative value") do
+  assert_raise(ArgumentError) { usleep(-100) }
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/README.md
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/README.md	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/README.md	(revision 439)
@@ -0,0 +1,56 @@
+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
+- [mruby-io](https://github.com/mruby/mruby/tree/master/mrbgems/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.
+Copyright (c) 2017 mruby developers
+
+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/mruby-2.1.1/mrbgems/mruby-socket/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/mrbgem.rake	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/mrbgem.rake	(revision 439)
@@ -0,0 +1,18 @@
+MRuby::Gem::Specification.new('mruby-socket') do |spec|
+  spec.license = 'MIT'
+  spec.authors = ['Internet Initiative Japan', 'mruby developers']
+  spec.summary = 'standard socket class'
+
+  spec.cc.include_paths << "#{build.root}/src"
+  #spec.cc.defines << "HAVE_SA_LEN=0"
+
+  # If Windows, use winsock
+  if for_windows?
+    spec.linker.libraries << "wsock32"
+    spec.linker.libraries << "ws2_32"
+  end
+
+  spec.add_dependency('mruby-io', :core => 'mruby-io')
+  spec.add_dependency('mruby-pack', :core => 'mruby-pack')
+  # spec.add_dependency('mruby-mtest')
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/mrblib/socket.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/mrblib/socket.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/mrblib/socket.rb	(revision 439)
@@ -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 < IO
+  @@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)
+    self._is_socket = true
+    @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 < BasicSocket
+  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 < IPSocket
+  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 < TCPSocket
+  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
+      TCPSocket.new_with_prelude(proc { @init_with_fd = true }, 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)
+  end
+end
+
+class UDPSocket < IPSocket
+  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 < BasicSocket
+  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._accept2(self.fileno)
+  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)
+  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/mruby-2.1.1/mrbgems/mruby-socket/src/const.cstub
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/src/const.cstub	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/src/const.cstub	(revision 439)
@@ -0,0 +1,459 @@
+#if defined(AF_INET)
+  define_const(AF_INET);
+#endif
+#if defined(PF_INET)
+  define_const(PF_INET);
+#endif
+#if defined(AF_INET6)
+  define_const(AF_INET6);
+#endif
+#if defined(PF_INET6)
+  define_const(PF_INET6);
+#endif
+#if defined(AF_LINK)
+  define_const(AF_LINK);
+#endif
+#if defined(PF_LINK)
+  define_const(PF_LINK);
+#endif
+#if defined(AF_LOCAL)
+  define_const(AF_LOCAL);
+#endif
+#if defined(PF_LOCAL)
+  define_const(PF_LOCAL);
+#endif
+#if defined(AF_UNIX)
+  define_const(AF_UNIX);
+#endif
+#if defined(PF_UNIX)
+  define_const(PF_UNIX);
+#endif
+#if defined(AF_MAX)
+  define_const(AF_MAX);
+#endif
+#if defined(AF_UNSPEC)
+  define_const(AF_UNSPEC);
+#endif
+#if defined(PF_UNSPEC)
+  define_const(PF_UNSPEC);
+#endif
+#if defined(AF_ROUTE)
+  define_const(AF_ROUTE);
+#endif
+#if defined(PF_ROUTE)
+  define_const(PF_ROUTE);
+#endif
+#if defined(AI_CANONNAME)
+  define_const(AI_CANONNAME);
+#endif
+#if defined(AI_FQDN)
+  define_const(AI_FQDN);
+#endif
+#if defined(AI_NUMERICHOST)
+  define_const(AI_NUMERICHOST);
+#endif
+#if defined(AI_NUMERICSERV)
+  define_const(AI_NUMERICSERV);
+#endif
+#if defined(AI_PASSIVE)
+  define_const(AI_PASSIVE);
+#endif
+#if defined(IP_ADD_MEMBERSHIP)
+  define_const(IP_ADD_MEMBERSHIP);
+#endif
+#if defined(IP_ADD_SOURCE_MEMBERSHIP)
+  define_const(IP_ADD_SOURCE_MEMBERSHIP);
+#endif
+#if defined(IP_BLOCK_SOURCE)
+  define_const(IP_BLOCK_SOURCE);
+#endif
+#if defined(IP_DROP_MEMBERSHIP)
+  define_const(IP_DROP_MEMBERSHIP);
+#endif
+#if defined(IP_DROP_SOURCE_MEMBERSHIP)
+  define_const(IP_DROP_SOURCE_MEMBERSHIP);
+#endif
+#if defined(IP_FREEBIND)
+  define_const(IP_FREEBIND);
+#endif
+#if defined(IP_HDRINCL)
+  define_const(IP_HDRINCL);
+#endif
+#if defined(IP_IPSEC_POLICY)
+  define_const(IP_IPSEC_POLICY);
+#endif
+#if defined(IP_MINTTL)
+  define_const(IP_MINTTL);
+#endif
+#if defined(IP_MSFILTER)
+  define_const(IP_MSFILTER);
+#endif
+#if defined(IP_MTU)
+  define_const(IP_MTU);
+#endif
+#if defined(IP_MTU_DISCOVER)
+  define_const(IP_MTU_DISCOVER);
+#endif
+#if defined(IP_MULTICAST_ALL)
+  define_const(IP_MULTICAST_ALL);
+#endif
+#if defined(IP_MULTICAST_IF)
+  define_const(IP_MULTICAST_IF);
+#endif
+#if defined(IP_MULTICAST_LOOP)
+  define_const(IP_MULTICAST_LOOP);
+#endif
+#if defined(IP_MULTICAST_TTL)
+  define_const(IP_MULTICAST_TTL);
+#endif
+#if defined(IP_OPTIONS)
+  define_const(IP_OPTIONS);
+#endif
+#if defined(IP_ORIGDSTADDR)
+  define_const(IP_ORIGDSTADDR);
+#endif
+#if defined(IP_PASSSEC)
+  define_const(IP_PASSSEC);
+#endif
+#if defined(IP_PKTINFO)
+  define_const(IP_PKTINFO);
+#endif
+#if defined(IP_PKTOPTIONS)
+  define_const(IP_PKTOPTIONS);
+#endif
+#if defined(IP_PMTUDISC_DO)
+  define_const(IP_PMTUDISC_DO);
+#endif
+#if defined(IP_PMTUDISC_DONT)
+  define_const(IP_PMTUDISC_DONT);
+#endif
+#if defined(IP_PMTUDISC_PROBE)
+  define_const(IP_PMTUDISC_PROBE);
+#endif
+#if defined(IP_PMTUDISC_WANT)
+  define_const(IP_PMTUDISC_WANT);
+#endif
+#if defined(IP_RECVDSTADDR)
+  define_const(IP_RECVDSTADDR);
+#endif
+#if defined(IP_RECVERR)
+  define_const(IP_RECVERR);
+#endif
+#if defined(IP_RECVOPTS)
+  define_const(IP_RECVOPTS);
+#endif
+#if defined(IP_RECVORIGDSTADDR)
+  define_const(IP_RECVORIGDSTADDR);
+#endif
+#if defined(IP_RECVRETOPTS)
+  define_const(IP_RECVRETOPTS);
+#endif
+#if defined(IP_RECVTOS)
+  define_const(IP_RECVTOS);
+#endif
+#if defined(IP_RECVTTL)
+  define_const(IP_RECVTTL);
+#endif
+#if defined(IP_RETOPTS)
+  define_const(IP_RETOPTS);
+#endif
+#if defined(IP_ROUTER_ALERT)
+  define_const(IP_ROUTER_ALERT);
+#endif
+#if defined(IP_TOS)
+  define_const(IP_TOS);
+#endif
+#if defined(IP_TRANSPARENT)
+  define_const(IP_TRANSPARENT);
+#endif
+#if defined(IP_TTL)
+  define_const(IP_TTL);
+#endif
+#if defined(IP_UNBLOCK_SOURCE)
+  define_const(IP_UNBLOCK_SOURCE);
+#endif
+#if defined(IP_XFRM_POLICY)
+  define_const(IP_XFRM_POLICY);
+#endif
+#if defined(IPV6_JOIN_GROUP)
+  define_const(IPV6_JOIN_GROUP);
+#endif
+#if defined(IPV6_LEAVE_GROUP)
+  define_const(IPV6_LEAVE_GROUP);
+#endif
+#if defined(IPV6_MULTICAST_HOPS)
+  define_const(IPV6_MULTICAST_HOPS);
+#endif
+#if defined(IPV6_MULTICAST_IF)
+  define_const(IPV6_MULTICAST_IF);
+#endif
+#if defined(IPV6_MULTICAST_LOOP)
+  define_const(IPV6_MULTICAST_LOOP);
+#endif
+#if defined(IPV6_UNICAST_HOPS)
+  define_const(IPV6_UNICAST_HOPS);
+#endif
+#if defined(IPV6_V6ONLY)
+  define_const(IPV6_V6ONLY);
+#endif
+#if defined(IPPROTO_AH) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_AH);
+#endif
+#if defined(IPPROTO_DSTOPTS) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_DSTOPTS);
+#endif
+#if defined(IPPROTO_ESP) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_ESP);
+#endif
+#if defined(IPPROTO_FRAGMENT) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_FRAGMENT);
+#endif
+#if defined(IPPROTO_ICMP) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_ICMP);
+#endif
+#if defined(IPPROTO_ICMPV6) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_ICMPV6);
+#endif
+#if defined(IPPROTO_IP) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_IP);
+#endif
+#if defined(IPPROTO_IPV6) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_IPV6);
+#endif
+#if defined(IPPROTO_NONE) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_NONE);
+#endif
+#if defined(IPPROTO_RAW) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_RAW);
+#endif
+#if defined(IPPROTO_ROUTING) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_ROUTING);
+#endif
+#if defined(IPPROTO_TCP) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_TCP);
+#endif
+#if defined(IPPROTO_UDP) || defined(_WINSOCKAPI_)
+  define_const(IPPROTO_UDP);
+#endif
+#if defined(MCAST_BLOCK_SOURCE)
+  define_const(MCAST_BLOCK_SOURCE);
+#endif
+#if defined(MCAST_JOIN_GROUP)
+  define_const(MCAST_JOIN_GROUP);
+#endif
+#if defined(MCAST_JOIN_SOURCE_GROUP)
+  define_const(MCAST_JOIN_SOURCE_GROUP);
+#endif
+#if defined(MCAST_LEAVE_GROUP)
+  define_const(MCAST_LEAVE_GROUP);
+#endif
+#if defined(MCAST_LEAVE_SOURCE_GROUP)
+  define_const(MCAST_LEAVE_SOURCE_GROUP);
+#endif
+#if defined(MCAST_MSFILTER)
+  define_const(MCAST_MSFILTER);
+#endif
+#if defined(MCAST_UNBLOCK_SOURCE)
+  define_const(MCAST_UNBLOCK_SOURCE);
+#endif
+#if defined(MSG_BCAST)
+  define_const(MSG_BCAST);
+#endif
+#if defined(MSG_CTRUNC)
+  define_const(MSG_CTRUNC);
+#endif
+#if defined(MSG_DONTROUTE)
+  define_const(MSG_DONTROUTE);
+#endif
+#if defined(MSG_DONTWAIT)
+  define_const(MSG_DONTWAIT);
+#endif
+#if defined(MSG_EOR)
+  define_const(MSG_EOR);
+#endif
+#if defined(MSG_MCAST)
+  define_const(MSG_MCAST);
+#endif
+#if defined(MSG_NOSIGNAL)
+  define_const(MSG_NOSIGNAL);
+#endif
+#if defined(MSG_OOB)
+  define_const(MSG_OOB);
+#endif
+#if defined(MSG_PEEK)
+  define_const(MSG_PEEK);
+#endif
+#if defined(MSG_TRUNC)
+  define_const(MSG_TRUNC);
+#endif
+#if defined(MSG_WAITALL)
+  define_const(MSG_WAITALL);
+#endif
+#if defined(NI_DGRAM)
+  define_const(NI_DGRAM);
+#endif
+#if defined(NI_MAXHOST)
+  define_const(NI_MAXHOST);
+#endif
+#if defined(NI_MAXSERV)
+  define_const(NI_MAXSERV);
+#endif
+#if defined(NI_NAMEREQD)
+  define_const(NI_NAMEREQD);
+#endif
+#if defined(NI_NOFQDN)
+  define_const(NI_NOFQDN);
+#endif
+#if defined(NI_NUMERICHOST)
+  define_const(NI_NUMERICHOST);
+#endif
+#if defined(NI_NUMERICSERV)
+  define_const(NI_NUMERICSERV);
+#endif
+#if defined(SHUT_RD)
+  define_const(SHUT_RD);
+#endif
+#if defined(SHUT_WR)
+  define_const(SHUT_WR);
+#endif
+#if defined(SHUT_RDWR)
+  define_const(SHUT_RDWR);
+#endif
+#if defined(SO_BINDANY)
+  define_const(SO_BINDANY);
+#endif
+#if defined(SO_BROADCAST)
+  define_const(SO_BROADCAST);
+#endif
+#if defined(SO_DEBUG)
+  define_const(SO_DEBUG);
+#endif
+#if defined(SO_DONTROUTE)
+  define_const(SO_DONTROUTE);
+#endif
+#if defined(SO_ERROR)
+  define_const(SO_ERROR);
+#endif
+#if defined(SO_KEEPALIVE)
+  define_const(SO_KEEPALIVE);
+#endif
+#if defined(SO_LINGER)
+  define_const(SO_LINGER);
+#endif
+#if defined(SO_NOSIGPIPE)
+  define_const(SO_NOSIGPIPE);
+#endif
+#if defined(SO_OOBINLINE)
+  define_const(SO_OOBINLINE);
+#endif
+#if defined(SO_PEERCRED)
+  define_const(SO_PEERCRED);
+#endif
+#if defined(SO_RCVBUF)
+  define_const(SO_RCVBUF);
+#endif
+#if defined(SO_RCVLOWAT)
+  define_const(SO_RCVLOWAT);
+#endif
+#if defined(SO_RCVTIMEO)
+  define_const(SO_RCVTIMEO);
+#endif
+#if defined(SO_REUSEADDR)
+  define_const(SO_REUSEADDR);
+#endif
+#if defined(SO_REUSEPORT)
+  define_const(SO_REUSEPORT);
+#endif
+#if defined(SO_RTABLE)
+  define_const(SO_RTABLE);
+#endif
+#if defined(SO_SNDBUF)
+  define_const(SO_SNDBUF);
+#endif
+#if defined(SO_SNDLOWAT)
+  define_const(SO_SNDLOWAT);
+#endif
+#if defined(SO_SNDTIMEO)
+  define_const(SO_SNDTIMEO);
+#endif
+#if defined(SO_SPLICE)
+  define_const(SO_SPLICE);
+#endif
+#if defined(SO_TIMESTAMP)
+  define_const(SO_TIMESTAMP);
+#endif
+#if defined(SO_TYPE)
+  define_const(SO_TYPE);
+#endif
+#if defined(SOCK_DGRAM)
+  define_const(SOCK_DGRAM);
+#endif
+#if defined(SOCK_RAW)
+  define_const(SOCK_RAW);
+#endif
+#if defined(SOCK_SEQPACKET)
+  define_const(SOCK_SEQPACKET);
+#endif
+#if defined(SOCK_STREAM)
+  define_const(SOCK_STREAM);
+#endif
+#if defined(SOL_SOCKET)
+  define_const(SOL_SOCKET);
+#endif
+#if defined(SOL_IP)
+  define_const(SOL_IP);
+#endif
+#if defined(SOL_TCP)
+  define_const(SOL_TCP);
+#endif
+#if defined(TCP_CONGCTL)
+  define_const(TCP_CONGCTL);
+#endif
+#if defined(TCP_CONGESTION)
+  define_const(TCP_CONGESTION);
+#endif
+#if defined(TCP_CORK)
+  define_const(TCP_CORK);
+#endif
+#if defined(TCP_DEFER_ACCEPT)
+  define_const(TCP_DEFER_ACCEPT);
+#endif
+#if defined(TCP_INFO)
+  define_const(TCP_INFO);
+#endif
+#if defined(TCP_KEEPCNT)
+  define_const(TCP_KEEPCNT);
+#endif
+#if defined(TCP_KEEPIDLE)
+  define_const(TCP_KEEPIDLE);
+#endif
+#if defined(TCP_KEEPINIT)
+  define_const(TCP_KEEPINIT);
+#endif
+#if defined(TCP_KEEPINTVL)
+  define_const(TCP_KEEPINTVL);
+#endif
+#if defined(TCP_LINGER2)
+  define_const(TCP_LINGER2);
+#endif
+#if defined(TCP_MAXSEG)
+  define_const(TCP_MAXSEG);
+#endif
+#if defined(TCP_MD5SIG)
+  define_const(TCP_MD5SIG);
+#endif
+#if defined(TCP_NODELAY)
+  define_const(TCP_NODELAY);
+#endif
+#if defined(TCP_QUICKACK)
+  define_const(TCP_QUICKACK);
+#endif
+#if defined(TCP_SACK_ENABLE)
+  define_const(TCP_SACK_ENABLE);
+#endif
+#if defined(TCP_SYNCNT)
+  define_const(TCP_SYNCNT);
+#endif
+#if defined(TCP_WINDOW_CLAMP)
+  define_const(TCP_WINDOW_CLAMP);
+#endif
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/src/const.def
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/src/const.def	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/src/const.def	(revision 439)
@@ -0,0 +1,165 @@
+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
+SOL_IP
+SOL_TCP
+
+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/mruby-2.1.1/mrbgems/mruby-socket/src/gen.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/src/gen.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/src/gen.rb	(revision 439)
@@ -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
+#if defined(#{name})#{name.start_with?('IPPROTO_') ? ' || defined(_WINSOCKAPI_)' : ''}
+  define_const(#{name});
+#endif
+CODE
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/src/socket.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/src/socket.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/src/socket.c	(revision 439)
@@ -0,0 +1,966 @@
+/*
+** socket.c - Socket module
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifdef _WIN32
+  #define _WIN32_WINNT 0x0501
+
+  #include <winsock2.h>
+  #include <ws2tcpip.h>
+  #include <windows.h>
+  #include <winerror.h>
+
+  #define SHUT_RDWR SD_BOTH
+  #ifndef _SSIZE_T_DEFINED
+  typedef int ssize_t;
+  #endif
+  typedef int fsize_t;
+#else
+#if defined(AZURE_SPHERE)
+  #define _GNU_SOURCE
+#endif
+  #include <sys/types.h>
+  #include <sys/socket.h>
+  #include <sys/param.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>
+  typedef size_t fsize_t;
+#if defined(AZURE_SPHERE)
+#define F_GETFL  3
+#define F_SETFL  4
+  int gethostname(char *, size_t);
+  int fcntl(int, int, ...);
+#endif
+#endif
+
+#include <stddef.h>
+#include <string.h>
+
+#include "mruby.h"
+#include "mruby/array.h"
+#include "mruby/class.h"
+#include "mruby/data.h"
+#include "mruby/numeric.h"
+#include "mruby/string.h"
+#include "mruby/variable.h"
+#include "mruby/error.h"
+
+#include "mruby/ext/io.h"
+
+#if !defined(HAVE_SA_LEN)
+#if (defined(BSD) && (BSD >= 199006))
+#define HAVE_SA_LEN  1
+#else
+#define HAVE_SA_LEN  0
+#endif
+#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
+static 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 in_addr6));
+	getnameinfo((struct sockaddr *)&in, sizeof(struct
+		    sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
+	return dst;
+    }
+    return NULL;
+}
+
+static 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 = RSTRING_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 = RSTRING_CSTR(mrb, service);
+  } else if (mrb_fixnum_p(service)) {
+    servname = RSTRING_PTR(mrb_fixnum_to_str(mrb, service, 10));
+  } 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 = (int)flags;
+
+  if (mrb_fixnum_p(family)) {
+    hints.ai_family = (int)mrb_fixnum(family);
+  }
+
+  if (mrb_fixnum_p(socktype)) {
+    hints.ai_socktype = (int)mrb_fixnum(socktype);
+  }
+
+  if (mrb_fixnum_p(protocol)) {
+    hints.ai_protocol = (int)mrb_fixnum(protocol);
+  }
+
+  lastai = mrb_cv_get(mrb, klass, mrb_intern_lit(mrb, "_lastai"));
+  if (mrb_cptr_p(lastai)) {
+    freeaddrinfo((struct addrinfo*)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", 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, (char*)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, (int)flags);
+  if (error) {
+    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;
+}
+
+#ifndef _WIN32
+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");
+  if (RSTRING_LEN(sastr) < (mrb_int)offsetof(struct sockaddr_un, sun_path) + 1) {
+    return mrb_str_new(mrb, "", 0);
+  } else {
+    return mrb_str_new_cstr(mrb, ((struct sockaddr_un *)RSTRING_PTR(sastr))->sun_path);
+  }
+}
+#endif
+
+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 (int)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 available 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, (char*)&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, (char*)&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, (int)level, (int)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)
+{
+  ssize_t 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), (fsize_t)maxlen, (int)flags);
+  if (n == -1)
+    mrb_sys_fail(mrb, "recv");
+  mrb_str_resize(mrb, buf, (mrb_int)n);
+  return buf;
+}
+
+static mrb_value
+mrb_basicsocket_recvfrom(mrb_state *mrb, mrb_value self)
+{
+  ssize_t 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), (fsize_t)maxlen, (int)flags, (struct sockaddr *)RSTRING_PTR(sa), &socklen);
+  if (n == -1)
+    mrb_sys_fail(mrb, "recvfrom");
+  mrb_str_resize(mrb, buf, (mrb_int)n);
+  mrb_str_resize(mrb, sa, (mrb_int)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)
+{
+  ssize_t 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), (fsize_t)RSTRING_LEN(mesg), (int)flags);
+  } else {
+    n = sendto(socket_fd(mrb, self), RSTRING_PTR(mesg), (fsize_t)RSTRING_LEN(mesg), (int)flags, (const struct sockaddr*)RSTRING_PTR(dest), (fsize_t)RSTRING_LEN(dest));
+  }
+  if (n == -1)
+    mrb_sys_fail(mrb, "send");
+  return mrb_fixnum_value((mrb_int)n);
+}
+
+static mrb_value
+mrb_basicsocket_setnonblock(mrb_state *mrb, mrb_value self)
+{
+  int fd, flags;
+  mrb_bool nonblocking;
+#ifdef _WIN32
+  u_long mode = 1;
+#endif
+
+  mrb_get_args(mrb, "b", &nonblocking);
+  fd = socket_fd(mrb, self);
+#ifdef _WIN32
+  flags = ioctlsocket(fd, FIONBIO, &mode);
+  if (flags != NO_ERROR)
+    mrb_sys_fail(mrb, "ioctlsocket");
+#else
+  flags = fcntl(fd, F_GETFL, 0);
+  if (flags == 1)
+    mrb_sys_fail(mrb, "fcntl");
+  if (nonblocking)
+    flags |= O_NONBLOCK;
+  else
+    flags &= ~O_NONBLOCK;
+  if (fcntl(fd, F_SETFL, flags) == -1)
+    mrb_sys_fail(mrb, "fcntl");
+#endif
+  return mrb_nil_value();
+}
+
+static mrb_value
+mrb_basicsocket_setsockopt(mrb_state *mrb, mrb_value self)
+{
+  int s;
+  mrb_int argc, 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_true_p(optval) || mrb_false_p(optval)) {
+      mrb_int i = mrb_test(optval) ? 1 : 0;
+      optval = mrb_str_new(mrb, (char*)&i, sizeof(i));
+    } else if (mrb_fixnum_p(optval)) {
+      if (optname == IP_MULTICAST_TTL || optname == IP_MULTICAST_LOOP) {
+        char uc = (char)mrb_fixnum(optval);
+        optval = mrb_str_new(mrb, &uc, sizeof(uc));
+      } else {
+        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_raise(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_argnum_error(mrb, argc, 3, 3);
+  }
+
+  s = socket_fd(mrb, self);
+  if (setsockopt(s, (int)level, (int)optname, RSTRING_PTR(optval), (socklen_t)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), (int)how) != 0)
+    mrb_sys_fail(mrb, "shutdown");
+  return mrb_fixnum_value(0);
+}
+
+static mrb_value
+mrb_basicsocket_set_is_socket(mrb_state *mrb, mrb_value self)
+{
+  mrb_bool b;
+  struct mrb_io *io_p;
+  mrb_get_args(mrb, "b", &b);
+
+  io_p = (struct mrb_io*)DATA_PTR(self);
+  if (io_p) {
+    io_p->is_socket = b;
+  }
+
+  return mrb_bool_value(b);
+}
+
+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((int)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 ((size_t)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;
+  ssize_t 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), (fsize_t)maxlen, (int)flags,
+  	       (struct sockaddr *)&ss, &socklen);
+  if (n == -1) {
+    mrb_sys_fail(mrb, "recvfrom");
+  }
+  mrb_str_resize(mrb, buf, (mrb_int)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, (mrb_int)bufsize);
+  if (gethostname(RSTRING_PTR(buf), (fsize_t)bufsize) != 0)
+    mrb_sys_fail(mrb, "gethostname");
+  mrb_str_resize(mrb, buf, (mrb_int)strlen(RSTRING_PTR(buf)));
+  return buf;
+}
+
+static mrb_value
+mrb_socket_accept(mrb_state *mrb, mrb_value klass)
+{
+  int s1;
+  mrb_int s0;
+
+  mrb_get_args(mrb, "i", &s0);
+  s1 = (int)accept(s0, NULL, NULL);
+  if (s1 == -1) {
+    mrb_sys_fail(mrb, "accept");
+  }
+  return mrb_fixnum_value(s1);
+}
+
+static mrb_value
+mrb_socket_accept2(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 = (int)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;
+  mrb_int s;
+
+  mrb_get_args(mrb, "iS", &s, &sastr);
+  if (bind((int)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;
+  mrb_int s;
+
+  mrb_get_args(mrb, "iS", &s, &sastr);
+  if (connect((int)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)
+{
+  mrb_int backlog, s;
+
+  mrb_get_args(mrb, "ii", &s, &backlog);
+  if (listen((int)s, (int)backlog) == -1) {
+    mrb_sys_fail(mrb, "listen");
+  }
+  return mrb_nil_value();
+}
+
+static mrb_value
+mrb_socket_sockaddr_family(mrb_state *mrb, mrb_value klass)
+{
+  const struct sockaddr *sa;
+  mrb_value str;
+
+  mrb_get_args(mrb, "S", &str);
+  if ((size_t)RSTRING_LEN(str) < offsetof(struct sockaddr, sa_family) + sizeof(sa->sa_family)) {
+    mrb_raise(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)");
+  }
+  sa = (const struct sockaddr *)RSTRING_PTR(str);
+  return mrb_fixnum_value(sa->sa_family);
+}
+
+static mrb_value
+mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass)
+{
+#ifdef _WIN32
+  mrb_raise(mrb, E_NOTIMP_ERROR, "sockaddr_un unsupported on Windows");
+  return mrb_nil_value();
+#else
+  struct sockaddr_un *sunp;
+  mrb_value path, s;
+
+  mrb_get_args(mrb, "S", &path);
+  if ((size_t)RSTRING_LEN(path) > sizeof(sunp->sun_path) - 1) {
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "too long unix socket path (max: %d bytes)", (int)sizeof(sunp->sun_path) - 1);
+  }
+  s = mrb_str_buf_new(mrb, sizeof(struct sockaddr_un));
+  sunp = (struct sockaddr_un *)RSTRING_PTR(s);
+#if HAVE_SA_LEN
+  sunp->sun_len = sizeof(struct sockaddr_un);
+#endif
+  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;
+#endif
+}
+
+static mrb_value
+mrb_socket_socketpair(mrb_state *mrb, mrb_value klass)
+{
+#ifdef _WIN32
+  mrb_raise(mrb, E_NOTIMP_ERROR, "socketpair unsupported on Windows");
+  return mrb_nil_value();
+#else
+  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;
+#endif
+}
+
+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 = (int)socket((int)domain, (int)type, (int)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.
+ */
+#ifdef _WIN32
+static mrb_value
+mrb_win32_basicsocket_close(mrb_state *mrb, mrb_value self)
+{
+  if (closesocket(socket_fd(mrb, self)) != NO_ERROR)
+    mrb_raise(mrb, E_SOCKET_ERROR, "closesocket unsuccessful");
+  return mrb_nil_value();
+}
+
+#define E_EOF_ERROR                (mrb_class_get(mrb, "EOFError"))
+static mrb_value
+mrb_win32_basicsocket_sysread(mrb_state *mrb, mrb_value self)
+{
+  int sd, ret;
+  mrb_value buf = mrb_nil_value();
+  mrb_int maxlen;
+
+  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);
+  }
+
+  sd = socket_fd(mrb, self);
+  ret = recv(sd, RSTRING_PTR(buf), (int)maxlen, 0);
+
+  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 SOCKET_ERROR: /* Error */
+      mrb_sys_fail(mrb, "recv");
+      break;
+    default:
+      if (RSTRING_LEN(buf) != ret) {
+        buf = mrb_str_resize(mrb, buf, ret);
+      }
+      break;
+  }
+
+  return buf;
+}
+
+static mrb_value
+mrb_win32_basicsocket_sysseek(mrb_state *mrb, mrb_value self)
+{
+  mrb_raise(mrb, E_NOTIMP_ERROR, "sysseek not implemented for windows sockets");
+  return mrb_nil_value();
+}
+
+static mrb_value
+mrb_win32_basicsocket_syswrite(mrb_state *mrb, mrb_value self)
+{
+  int n;
+  SOCKET sd;
+  mrb_value str;
+
+  sd = socket_fd(mrb, self);
+  mrb_get_args(mrb, "S", &str);
+  n = send(sd, RSTRING_PTR(str), (int)RSTRING_LEN(str), 0);
+  if (n == SOCKET_ERROR)
+    mrb_sys_fail(mrb, "send");
+  return mrb_fixnum_value(n);
+}
+
+#endif
+
+void
+mrb_mruby_socket_gem_init(mrb_state* mrb)
+{
+  struct RClass *io, *ai, *sock, *bsock, *ipsock, *tcpsock;
+  struct RClass *constants;
+
+#ifdef _WIN32
+  WSADATA wsaData;
+  int result;
+  result = WSAStartup(MAKEWORD(2,2), &wsaData);
+  if (result != NO_ERROR)
+    mrb_raise(mrb, E_RUNTIME_ERROR, "WSAStartup failed");
+#endif
+
+  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));
+#ifndef _WIN32
+  mrb_define_method(mrb, ai, "unix_path", mrb_addrinfo_unix_path, MRB_ARGS_NONE());
+#endif
+
+  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));
+  mrb_define_method(mrb, bsock, "_is_socket=", mrb_basicsocket_set_is_socket, MRB_ARGS_REQ(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, "_accept2", mrb_socket_accept2, 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());
+
+#ifndef _WIN32
+  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());
+#endif
+
+  /* Windows IO Method Overrides on BasicSocket */
+#ifdef _WIN32
+  mrb_define_method(mrb, bsock, "close", mrb_win32_basicsocket_close, MRB_ARGS_NONE());
+  mrb_define_method(mrb, bsock, "sysread", mrb_win32_basicsocket_sysread, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, bsock, "sysseek", mrb_win32_basicsocket_sysseek, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, bsock, "syswrite", mrb_win32_basicsocket_syswrite, MRB_ARGS_REQ(1));
+#endif
+
+  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((struct addrinfo*)mrb_cptr(ai));
+  }
+#ifdef _WIN32
+  WSACleanup();
+#endif
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/addrinfo.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/addrinfo.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/addrinfo.rb	(revision 439)
@@ -0,0 +1,91 @@
+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", 53, 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", 80)
+  b = []
+  Addrinfo.foreach("localhost", 80) { |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', 25)
+  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', 53)
+  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
+  skip "unix is not supported on Windows" if SocketTest.win?
+  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
+  skip "afamily is not supported on Windows" if SocketTest.win?
+  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/mruby-2.1.1/mrbgems/mruby-socket/test/basicsocket.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/basicsocket.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/basicsocket.rb	(revision 439)
@@ -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/mruby-2.1.1/mrbgems/mruby-socket/test/ipsocket.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/ipsocket.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/ipsocket.rb	(revision 439)
@@ -0,0 +1,44 @@
+unless SocketTest.win?
+
+# 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
+
+end # win?
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/socket.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/socket.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/socket.rb	(revision 439)
@@ -0,0 +1,38 @@
+unless SocketTest.win?
+
+assert('Socket.gethostname') do
+  assert_true(Socket.gethostname.is_a? String)
+end
+
+assert('Socket::getaddrinfo') do
+  ret = Socket.getaddrinfo("localhost", 53, 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] unless SocketTest.cygwin?
+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_equal "127.0.0.1", ai.ip_address
+  ensure
+    s.close rescue nil
+    c.close rescue nil
+  end
+end
+
+end   # win?
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/sockettest.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/sockettest.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/sockettest.c	(revision 439)
@@ -0,0 +1,84 @@
+#include <stdlib.h>
+
+#include "mruby.h"
+#include "mruby/error.h"
+
+#if defined(_WIN32) || defined(_WIN64)
+
+#include <io.h>
+
+#if defined(_MSC_VER) || \
+    (defined(MRB_MINGW32_VERSION) && MRB_MINGW32_VERSION < 3021) || \
+    (defined(MRB_MINGW64_VERSION) && MRB_MINGW64_VERSION < 4000)
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#define open  _open
+#define close _close
+#define unlink _unlink
+
+static int
+mkstemp(char *p)
+{
+  int fd;
+  char* fname = _mktemp(p);
+  if (fname == NULL)
+    return -1;
+  fd = open(fname, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
+  if (fd >= 0)
+    return fd;
+  return -1;
+}
+#endif
+
+#else
+
+#include <unistd.h>
+
+#endif
+
+mrb_value
+mrb_sockettest_tmppath(mrb_state *mrb, mrb_value klass)
+{
+  char name[] = "mruby-socket.XXXXXXXX";
+  int fd = mkstemp(name);
+  if (fd == -1) {
+    mrb_sys_fail(mrb, 0);
+  }
+  if (close(fd) == -1) {
+    mrb_sys_fail(mrb, 0);
+  }
+  if (unlink(name) == -1) {
+    mrb_sys_fail(mrb, 0);
+  }
+  return mrb_str_new_cstr(mrb, name);
+}
+
+mrb_value
+mrb_sockettest_win_p(mrb_state *mrb, mrb_value klass)
+{
+#ifdef _WIN32
+  return mrb_true_value();
+#else
+  return mrb_false_value();
+#endif
+}
+
+mrb_value
+mrb_sockettest_cygwin_p(mrb_state *mrb, mrb_value klass)
+{
+#if defined(__CYGWIN__) || defined(__CYGWIN32__)
+  return mrb_true_value();
+#else
+  return mrb_false_value();
+#endif
+}
+
+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());
+  mrb_define_class_method(mrb, c, "win?", mrb_sockettest_win_p, MRB_ARGS_NONE());
+  mrb_define_class_method(mrb, c, "cygwin?", mrb_sockettest_cygwin_p, MRB_ARGS_NONE());
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/tcpsocket.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/tcpsocket.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/tcpsocket.rb	(revision 439)
@@ -0,0 +1,4 @@
+#assert('TCPSocket.gethostbyname') do
+#assert('TCPSocket.new') do
+#assert('TCPSocket#close') do
+#assert('TCPSocket#write') do
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/udpsocket.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/udpsocket.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/udpsocket.rb	(revision 439)
@@ -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/mruby-2.1.1/mrbgems/mruby-socket/test/unix.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/unix.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-socket/test/unix.rb	(revision 439)
@@ -0,0 +1,130 @@
+unless SocketTest.win? || SocketTest.cygwin?
+
+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
+
+end # SocketTest.win?
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sprintf/src/kernel.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-sprintf/src/kernel.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sprintf/src/kernel.c	(revision 439)
@@ -19,6 +19,6 @@
   krn = mrb->kernel_module;
 
-  mrb_define_method(mrb, krn, "sprintf", mrb_f_sprintf, MRB_ARGS_ANY());
-  mrb_define_method(mrb, krn, "format",  mrb_f_sprintf, MRB_ARGS_ANY());
+  mrb_define_method(mrb, krn, "sprintf", mrb_f_sprintf, MRB_ARGS_REQ(1)|MRB_ARGS_REST());
+  mrb_define_method(mrb, krn, "format",  mrb_f_sprintf, MRB_ARGS_REQ(1)|MRB_ARGS_REST());
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sprintf/src/sprintf.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-sprintf/src/sprintf.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sprintf/src/sprintf.c	(revision 439)
@@ -7,11 +7,16 @@
 #include <mruby.h>
 
+#ifdef MRB_DISABLE_STDIO
+# error sprintf conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
+#endif
+
 #include <limits.h>
-#include <stdio.h>
 #include <string.h>
 #include <mruby/string.h>
 #include <mruby/hash.h>
 #include <mruby/numeric.h>
+#ifndef MRB_WITHOUT_FLOAT
 #include <math.h>
+#endif
 #include <ctype.h>
 
@@ -20,6 +25,8 @@
 #define EXTENDSIGN(n, l) (((~0U << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0U << (n)))
 
-mrb_value mrb_str_format(mrb_state *, int, const mrb_value *, mrb_value);
+mrb_value mrb_str_format(mrb_state *, mrb_int, const mrb_value *, mrb_value);
+#ifndef MRB_WITHOUT_FLOAT
 static void fmt_setup(char*,size_t,int,int,mrb_int,mrb_int);
+#endif
 
 static char*
@@ -78,5 +85,5 @@
 
   if (base != 2) {
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base));
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %d", base);
   }
   if (val == 0) {
@@ -116,11 +123,9 @@
 
 #define CHECK(l) do {\
-/*  int cr = ENC_CODERANGE(result);*/\
   while ((l) >= bsiz - blen) {\
+    if (bsiz > MRB_INT_MAX/2) mrb_raise(mrb, E_ARGUMENT_ERROR, "too big specifier"); \
     bsiz*=2;\
-    if (bsiz < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "too big specifier"); \
   }\
   mrb_str_resize(mrb, result, bsiz);\
-/*  ENC_CODERANGE_SET(result, cr);*/\
   buf = RSTRING_PTR(result);\
 } while (0)
@@ -129,5 +134,5 @@
   CHECK(l);\
   memcpy(&buf[blen], s, l);\
-  blen += (l);\
+  blen += (mrb_int)(l);\
 } while (0)
 
@@ -143,8 +148,8 @@
   switch (posarg) {
   case -1:
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with numbered", mrb_fixnum_value(nextarg));
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%d) mixed with numbered", nextarg);
     break;
   case -2:
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with named", mrb_fixnum_value(nextarg));
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%d) mixed with named", nextarg);
     break;
   default:
@@ -154,27 +159,27 @@
 
 static void
-check_pos_arg(mrb_state *mrb, int posarg, int n)
+check_pos_arg(mrb_state *mrb, int posarg, mrb_int n)
 {
   if (posarg > 0) {
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after unnumbered(%S)",
-               mrb_fixnum_value(n), mrb_fixnum_value(posarg));
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%i) after unnumbered(%d)",
+               n, posarg);
   }
   if (posarg == -2) {
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after named", mrb_fixnum_value(n));
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%i) after named", n);
   }
   if (n < 1) {
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid index - %S$", mrb_fixnum_value(n));
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid index - %i$", n);
   }
 }
 
 static void
-check_name_arg(mrb_state *mrb, int posarg, const char *name, int len)
+check_name_arg(mrb_state *mrb, int posarg, const char *name, size_t len)
 {
   if (posarg > 0) {
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after unnumbered(%S)",
-               mrb_str_new(mrb, (name), (len)), mrb_fixnum_value(posarg));
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%l after unnumbered(%d)",
+               name, len, posarg);
   }
   if (posarg == -1) {
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after numbered", mrb_str_new(mrb, (name), (len)));
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%l after numbered", name, len);
   }
 }
@@ -199,9 +204,8 @@
 #define GETNUM(n, val) \
   for (; p < end && ISDIGIT(*p); p++) {\
-    int next_n = 10 * n + (*p - '0'); \
-    if (next_n / 10 != n) {\
+    if (n > (MRB_INT_MAX - (*p - '0'))/10) {\
       mrb_raise(mrb, E_ARGUMENT_ERROR, #val " too big"); \
     } \
-    n = next_n; \
+    n = 10 * n + (*p - '0'); \
   } \
   if (p >= end) { \
@@ -225,5 +229,5 @@
 
 static mrb_value
-get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv)
+get_hash(mrb_state *mrb, mrb_value *hash, mrb_int argc, const mrb_value *argv)
 {
   mrb_value tmp;
@@ -233,5 +237,5 @@
     mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required");
   }
-  tmp = mrb_check_convert_type(mrb, argv[1], MRB_TT_HASH, "Hash", "to_hash");
+  tmp = mrb_check_hash_type(mrb, argv[1]);
   if (mrb_nil_p(tmp)) {
     mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required");
@@ -519,5 +523,5 @@
 
 mrb_value
-mrb_str_format(mrb_state *mrb, int argc, const mrb_value *argv, mrb_value fmt)
+mrb_str_format(mrb_state *mrb, mrb_int argc, const mrb_value *argv, mrb_value fmt)
 {
   const char *p, *end;
@@ -529,5 +533,4 @@
   mrb_int width;
   mrb_int prec;
-  int flags = FNONE;
   int nextarg = 1;
   int posarg = 0;
@@ -553,10 +556,10 @@
   ++argc;
   --argv;
-  fmt = mrb_str_to_str(mrb, fmt);
+  mrb_to_str(mrb, fmt);
   p = RSTRING_PTR(fmt);
   end = p + RSTRING_LEN(fmt);
   blen = 0;
   bsiz = 120;
-  result = mrb_str_buf_new(mrb, bsiz);
+  result = mrb_str_new_capa(mrb, bsiz);
   buf = RSTRING_PTR(result);
   memset(buf, 0, bsiz);
@@ -565,4 +568,5 @@
     const char *t;
     mrb_sym id = 0;
+    int flags = FNONE;
 
     for (t = p; t < end && *t != '%'; t++) ;
@@ -580,5 +584,5 @@
     switch (*p) {
       default:
-        mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - \\%%S", mrb_str_new(mrb, p, 1));
+        mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - %%%c", *p);
         break;
 
@@ -619,5 +623,5 @@
         if (*p == '$') {
           if (!mrb_undef_p(nextvalue)) {
-            mrb_raisef(mrb, E_ARGUMENT_ERROR, "value given twice - %S$", mrb_fixnum_value(n));
+            mrb_raisef(mrb, E_ARGUMENT_ERROR, "value given twice - %i$", n);
           }
           nextvalue = GETPOSARG(n);
@@ -639,12 +643,12 @@
           p++;
         if (id) {
-          mrb_raisef(mrb, E_ARGUMENT_ERROR, "name%S after <%S>",
-                     mrb_str_new(mrb, start, p - start + 1), mrb_sym2str(mrb, id));
+          mrb_raisef(mrb, E_ARGUMENT_ERROR, "name%l after <%n>",
+                     start, p - start + 1, id);
         }
         symname = mrb_str_new(mrb, start + 1, p - start - 1);
         id = mrb_intern_str(mrb, symname);
-        nextvalue = GETNAMEARG(mrb_symbol_value(id), start, (int)(p - start + 1));
+        nextvalue = GETNAMEARG(mrb_symbol_value(id), start, p - start + 1);
         if (mrb_undef_p(nextvalue)) {
-          mrb_raisef(mrb, E_KEY_ERROR, "key%S not found", mrb_str_new(mrb, start, p - start + 1));
+          mrb_raisef(mrb, E_KEY_ERROR, "key%l not found", start, p - start + 1);
         }
         if (term == '}') goto format_s;
@@ -702,15 +706,25 @@
         tmp = mrb_check_string_type(mrb, val);
         if (!mrb_nil_p(tmp)) {
-          if (mrb_fixnum(mrb_funcall(mrb, tmp, "size", 0)) != 1 ) {
+          if (RSTRING_LEN(tmp) != 1) {
             mrb_raise(mrb, E_ARGUMENT_ERROR, "%c requires a character");
           }
         }
         else if (mrb_fixnum_p(val)) {
-          tmp = mrb_funcall(mrb, val, "chr", 0);
+          mrb_int n = mrb_fixnum(val);
+
+          if (n < 0x80) {
+            char buf[1];
+
+            buf[0] = (char)n;
+            tmp = mrb_str_new(mrb, buf, 1);
+          }
+          else {
+            tmp = mrb_funcall(mrb, val, "chr", 0);
+            mrb_check_type(mrb, tmp, MRB_TT_STRING);
+          }
         }
         else {
           mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character");
         }
-        mrb_check_type(mrb, tmp, MRB_TT_STRING);
         c = RSTRING_PTR(tmp);
         n = RSTRING_LEN(tmp);
@@ -756,5 +770,5 @@
             char *p = RSTRING_PTR(str) + prec;
             slen = prec;
-            len = p - RSTRING_PTR(str);
+            len = (mrb_int)(p - RSTRING_PTR(str));
           }
           /* need to adjust multi-byte string pos */
@@ -792,11 +806,4 @@
         mrb_int len;
 
-        switch (*p) {
-          case 'd':
-          case 'i':
-            sign = 1; break;
-          default:
-            break;
-        }
         if (flags & FSHARP) {
           switch (*p) {
@@ -812,8 +819,10 @@
   bin_retry:
         switch (mrb_type(val)) {
+#ifndef MRB_WITHOUT_FLOAT
           case MRB_TT_FLOAT:
             val = mrb_flo_to_fixnum(mrb, val);
             if (mrb_fixnum_p(val)) goto bin_retry;
             break;
+#endif
           case MRB_TT_STRING:
             val = mrb_str_to_inum(mrb, val, 0, TRUE);
@@ -839,19 +848,12 @@
           case 'd':
           case 'i':
+            sign = 1;
+            /* fall through */
           default:
             base = 10; break;
         }
 
-        if (base == 2) {
-          if (v < 0 && !sign) {
-            val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base);
-            dots = 1;
-          }
-          else {
-            val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base);
-          }
-        }
         if (sign) {
-          if (v > 0) {
+          if (v >= 0) {
             if (flags & FPLUS) {
               sc = '+';
@@ -863,34 +865,30 @@
             }
           }
+          else {
+            sc = '-';
+            width--;
+          }
+          mrb_assert(base == 10);
+          snprintf(nbuf, sizeof(nbuf), "%" MRB_PRId, v);
+          s = nbuf;
+          if (v < 0) s++;       /* skip minus sign */
+        }
+        else {
+          s = nbuf;
+          if (v < 0) {
+            dots = 1;
+          }
           switch (base) {
           case 2:
-            strncpy(nbuf, RSTRING_PTR(val), sizeof(nbuf));
-            break;
-          case 8:
-            snprintf(nbuf, sizeof(nbuf), "%" MRB_PRIo, v);
-            break;
-          case 10:
-            snprintf(nbuf, sizeof(nbuf), "%" MRB_PRId, v);
-            break;
-          case 16:
-            snprintf(nbuf, sizeof(nbuf), "%" MRB_PRIx, v);
-            break;
-          }
-          s = nbuf;
-        }
-        else {
-          s = nbuf;
-          if (base != 10 && v < 0) {
-            dots = 1;
-          }
-          switch (base) {
-          case 2:
+            if (v < 0) {
+              val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base);
+            }
+            else {
+              val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base);
+            }
             strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-1);
             break;
           case 8:
             snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIo, v);
-            break;
-          case 10:
-            snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRId, v);
             break;
           case 16:
@@ -921,9 +919,4 @@
         }
 
-        if (dots) {
-          prec -= 2;
-          width -= 2;
-        }
-
         if (*p == 'X') {
           char *pp = s;
@@ -973,4 +966,5 @@
         if (!(flags&FMINUS) && width > 0) {
           FILL(' ', width);
+          width = 0;
         }
 
@@ -981,14 +975,17 @@
           PUSH(prefix, plen);
         }
-        if (dots) PUSH("..", 2);
+        if (dots) {
+          prec -= 2;
+          width -= 2;
+          PUSH("..", 2);
+        }
 
         if (prec > len) {
           CHECK(prec - len);
-          if (v < 0) {
+          if ((flags & (FMINUS|FPREC)) != FMINUS) {
+            char c = '0';
+            FILL(c, prec - len);
+          } else if (v < 0) {
             char c = sign_bits(base, p);
-            FILL(c, prec - len);
-          }
-          else if ((flags & (FMINUS|FPREC)) != FMINUS) {
-            char c = '0';
             FILL(c, prec - len);
           }
@@ -1001,4 +998,5 @@
       break;
 
+#ifndef MRB_WITHOUT_FLOAT
       case 'f':
       case 'g':
@@ -1010,5 +1008,5 @@
         mrb_value val = GETARG();
         double fval;
-        int i, need = 6;
+        mrb_int need = 6;
         char fbuf[32];
 
@@ -1016,5 +1014,5 @@
         if (!isfinite(fval)) {
           const char *expr;
-          const int elen = 3;
+          const mrb_int elen = 3;
           char sign = '\0';
 
@@ -1031,5 +1029,5 @@
             sign = (flags & FPLUS) ? '+' : ' ';
           if (sign)
-	    ++need;
+            ++need;
           if ((flags & FWIDTH) && need < width)
             need = width;
@@ -1055,21 +1053,25 @@
         need = 0;
         if (*p != 'e' && *p != 'E') {
-          i = INT_MIN;
+          int i;
           frexp(fval, &i);
           if (i > 0)
             need = BIT_DIGITS(i);
         }
+        if (need > MRB_INT_MAX - ((flags&FPREC) ? prec : 6)) {
+        too_big_width:
+          mrb_raise(mrb, E_ARGUMENT_ERROR,
+                    (width > prec ? "width too big" : "prec too big"));
+        }
         need += (flags&FPREC) ? prec : 6;
         if ((flags&FWIDTH) && need < width)
           need = width;
+        if (need > MRB_INT_MAX - 20) {
+          goto too_big_width;
+        }
         need += 20;
-        if (need <= 0) {
-          mrb_raise(mrb, E_ARGUMENT_ERROR,
-                    (width > prec ? "width too big" : "prec too big"));
-        }
 
         CHECK(need);
         n = snprintf(&buf[blen], need, fbuf, fval);
-        if (n < 0) {
+        if (n < 0 || n >= need) {
           mrb_raise(mrb, E_RUNTIME_ERROR, "formatting error");
         }
@@ -1077,4 +1079,5 @@
       }
       break;
+#endif
     }
     flags = FNONE;
@@ -1088,5 +1091,5 @@
     const char *mesg = "too many arguments for format string";
     if (mrb_test(ruby_debug)) mrb_raise(mrb, E_ARGUMENT_ERROR, mesg);
-    if (mrb_test(ruby_verbose)) mrb_warn(mrb, "%S", mrb_str_new_cstr(mrb, mesg));
+    if (mrb_test(ruby_verbose)) mrb_warn(mrb, "%s", mesg);
   }
 #endif
@@ -1096,4 +1099,5 @@
 }
 
+#ifndef MRB_WITHOUT_FLOAT
 static void
 fmt_setup(char *buf, size_t size, int c, int flags, mrb_int width, mrb_int prec)
@@ -1122,2 +1126,3 @@
   *buf = '\0';
 }
+#endif
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sprintf/test/sprintf.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-sprintf/test/sprintf.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-sprintf/test/sprintf.rb	(revision 439)
@@ -4,10 +4,13 @@
 assert('String#%') do
   assert_equal "one=1", "one=%d" % 1
-  assert_equal "1 one 1.0", "%d %s %3.1f" % [ 1, "one", 1.01 ]
+  assert_equal "1 one", "%d %s" % [ 1, "one" ]
   assert_equal "123 < 456", "%{num} < %<str>s" % { num: 123, str: "456" }
   assert_equal 15, ("%b" % (1<<14)).size
+  skip unless Object.const_defined?(:Float)
+  assert_equal "1.0", "%3.1f" % 1.01
 end
 
 assert('String#% with inf') do
+  skip unless Object.const_defined?(:Float)
   inf = Float::INFINITY
 
@@ -38,4 +41,5 @@
 
 assert('String#% with nan') do
+  skip unless Object.const_defined?(:Float)
   nan = Float::NAN
 
@@ -76,5 +80,5 @@
 
     assert_raise TypeError do
-      "%c" % 0
+      "%c" % 0x80
     end
   ensure
@@ -92,4 +96,10 @@
 end
 
+assert("String#% %d") do
+  assert_equal("  10",   "%4d" % 10)
+  assert_equal("1000",   "%4d" % 1000)
+  assert_equal("10000",  "%4d" % 10000)
+end
+
 assert("String#% invalid format") do
   assert_raise ArgumentError do
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/mrbgem.rake	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/mrbgem.rake	(revision 439)
@@ -3,4 +3,3 @@
   spec.author  = 'mruby developers'
   spec.summary = 'String class extension'
-  spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator'
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/mrblib/string.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/mrblib/string.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/mrblib/string.rb	(revision 439)
@@ -1,22 +1,3 @@
 class String
-
-  ##
-  #  call-seq:
-  #     String.try_convert(obj) -> string or nil
-  #
-  # Try to convert <i>obj</i> into a String, using to_str method.
-  # Returns converted string or nil if <i>obj</i> cannot be converted
-  # for any reason.
-  #
-  #     String.try_convert("str")     #=> "str"
-  #     String.try_convert(/re/)      #=> nil
-  #
-  def self.try_convert(obj)
-    if obj.respond_to?(:to_str)
-      obj.to_str
-    else
-      nil
-    end
-  end
 
   ##
@@ -96,5 +77,5 @@
   #
   def lstrip!
-    raise RuntimeError, "can't modify frozen String" if frozen?
+    raise FrozenError, "can't modify frozen String" if frozen?
     s = self.lstrip
     (s == self) ? nil : self.replace(s)
@@ -113,5 +94,5 @@
   #
   def rstrip!
-    raise RuntimeError, "can't modify frozen String" if frozen?
+    raise FrozenError, "can't modify frozen String" if frozen?
     s = self.rstrip
     (s == self) ? nil : self.replace(s)
@@ -126,5 +107,5 @@
   #
   def strip!
-    raise RuntimeError, "can't modify frozen String" if frozen?
+    raise FrozenError, "can't modify frozen String" if frozen?
     s = self.strip
     (s == self) ? nil : self.replace(s)
@@ -143,7 +124,20 @@
   #
   def casecmp(str)
-    self.downcase <=> str.to_str.downcase
+    self.downcase <=> str.__to_str.downcase
   rescue NoMethodError
-    raise TypeError, "no implicit conversion of #{str.class} into String"
+    nil
+  end
+
+  ##
+  # call-seq:
+  #   str.casecmp?(other)  -> true, false, or nil
+  #
+  # Returns true if str and other_str are equal after case folding,
+  # false if they are not equal, and nil if other_str is not a string.
+
+  def casecmp?(str)
+    c = self.casecmp(str)
+    return nil if c.nil?
+    return c == 0
   end
 
@@ -187,5 +181,5 @@
   #
   def slice!(arg1, arg2=nil)
-    raise RuntimeError, "can't modify frozen String" if frozen?
+    raise FrozenError, "can't modify frozen String" if frozen?
     raise "wrong number of arguments (for 1..2)" if arg1.nil? && arg2.nil?
 
@@ -317,9 +311,13 @@
   end
 
+  ##
+  # Call the given block for each character of
+  # +self+.
   def each_char(&block)
     return to_enum :each_char unless block
-
-    split('').each do |i|
-      block.call(i)
+    pos = 0
+    while pos < self.size
+      block.call(self[pos])
+      pos += 1
     end
     self
@@ -353,3 +351,97 @@
     self
   end
+
+  ##
+  #  call-seq:
+  #    string.lines                ->  array of string
+  #    string.lines {|s| block}    ->  array of string
+  #
+  #  Returns strings per line;
+  #
+  #    a = "abc\ndef"
+  #    a.lines    #=> ["abc\n", "def"]
+  #
+  #  If a block is given, it works the same as <code>each_line</code>.
+  def lines(&blk)
+    lines = self.__lines
+    if blk
+      lines.each do |line|
+        blk.call(line)
+      end
+    end
+    lines
+  end
+
+  ##
+  #  call-seq:
+  #     str.upto(other_str, exclusive=false) {|s| block }   -> str
+  #     str.upto(other_str, exclusive=false)                -> an_enumerator
+  #
+  #  Iterates through successive values, starting at <i>str</i> and
+  #  ending at <i>other_str</i> inclusive, passing each value in turn to
+  #  the block. The <code>String#succ</code> method is used to generate
+  #  each value.  If optional second argument exclusive is omitted or is false,
+  #  the last value will be included; otherwise it will be excluded.
+  #
+  #  If no block is given, an enumerator is returned instead.
+  #
+  #     "a8".upto("b6") {|s| print s, ' ' }
+  #     for s in "a8".."b6"
+  #       print s, ' '
+  #     end
+  #
+  #  <em>produces:</em>
+  #
+  #     a8 a9 b0 b1 b2 b3 b4 b5 b6
+  #     a8 a9 b0 b1 b2 b3 b4 b5 b6
+  #
+  #  If <i>str</i> and <i>other_str</i> contains only ascii numeric characters,
+  #  both are recognized as decimal numbers. In addition, the width of
+  #  string (e.g. leading zeros) is handled appropriately.
+  #
+  #     "9".upto("11").to_a   #=> ["9", "10", "11"]
+  #     "25".upto("5").to_a   #=> []
+  #     "07".upto("11").to_a  #=> ["07", "08", "09", "10", "11"]
+  def upto(max, exclusive=false, &block)
+    return to_enum(:upto, max, exclusive) unless block
+    raise TypeError, "no implicit conversion of #{max.class} into String" unless max.kind_of? String
+
+    len = self.length
+    maxlen = max.length
+    # single character
+    if len == 1 and maxlen == 1
+      c = self.ord
+      e = max.ord
+      while c <= e
+        break if exclusive and c == e
+        yield c.chr(__ENCODING__)
+        c += 1
+      end
+      return self
+    end
+    # both edges are all digits
+    bi = self.to_i(10)
+    ei = max.to_i(10)
+    len = self.length
+    if (bi > 0 or bi == "0"*len) and (ei > 0 or ei == "0"*maxlen)
+      while bi <= ei
+        break if exclusive and bi == ei
+        s = bi.to_s
+        s = s.rjust(len, "0") if s.length < len
+        yield s
+        bi += 1
+      end
+      return self
+    end
+    bs = self
+    while true
+      n = (bs <=> max)
+      break if n > 0
+      break if exclusive and n == 0
+      yield bs
+      break if n == 0
+      bs = bs.succ
+    end
+    self
+  end
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/src/string.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/src/string.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/src/string.c	(revision 439)
@@ -6,77 +6,88 @@
 #include <mruby/range.h>
 
-static mrb_value
-mrb_str_getbyte(mrb_state *mrb, mrb_value str)
-{
-  mrb_int pos;
-  mrb_get_args(mrb, "i", &pos);
-
-  if (pos < 0)
-    pos += RSTRING_LEN(str);
-  if (pos < 0 ||  RSTRING_LEN(str) <= pos)
-    return mrb_nil_value();
-
-  return mrb_fixnum_value((unsigned char)RSTRING_PTR(str)[pos]);
-}
-
-static mrb_value
-mrb_str_setbyte(mrb_state *mrb, mrb_value str)
-{
-  mrb_int pos, byte;
-  long len;
-
-  mrb_get_args(mrb, "ii", &pos, &byte);
-
-  len = RSTRING_LEN(str);
-  if (pos < -len || len <= pos)
-    mrb_raisef(mrb, E_INDEX_ERROR, "index %S is out of array", mrb_fixnum_value(pos));
-  if (pos < 0)
-    pos += len;
-
-  mrb_str_modify(mrb, mrb_str_ptr(str));
-  byte &= 0xff;
-  RSTRING_PTR(str)[pos] = byte;
-  return mrb_fixnum_value((unsigned char)byte);
-}
-
-static mrb_value
-mrb_str_byteslice(mrb_state *mrb, mrb_value str)
-{
-  mrb_value a1;
+#define ENC_ASCII_8BIT "ASCII-8BIT"
+#define ENC_BINARY     "BINARY"
+#define ENC_UTF8       "UTF-8"
+
+#define ENC_COMP_P(enc, enc_lit) \
+  str_casecmp_p(RSTRING_PTR(enc), RSTRING_LEN(enc), enc_lit, sizeof(enc_lit"")-1)
+
+#ifdef MRB_WITHOUT_FLOAT
+# define mrb_float_p(o) FALSE
+#endif
+
+static mrb_bool
+str_casecmp_p(const char *s1, mrb_int len1, const char *s2, mrb_int len2)
+{
+  const char *e1, *e2;
+
+  if (len1 != len2) return FALSE;
+  e1 = s1 + len1;
+  e2 = s2 + len2;
+  while (s1 < e1 && s2 < e2) {
+    if (*s1 != *s2 && TOUPPER(*s1) != TOUPPER(*s2)) return FALSE;
+    ++s1;
+    ++s2;
+  }
+  return TRUE;
+}
+
+static mrb_value
+int_chr_binary(mrb_state *mrb, mrb_value num)
+{
+  mrb_int cp = mrb_int(mrb, num);
+  char c;
+  mrb_value str;
+
+  if (cp < 0 || 0xff < cp) {
+    mrb_raisef(mrb, E_RANGE_ERROR, "%v out of char range", num);
+  }
+  c = (char)cp;
+  str = mrb_str_new(mrb, &c, 1);
+  RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
+  return str;
+}
+
+#ifdef MRB_UTF8_STRING
+static mrb_value
+int_chr_utf8(mrb_state *mrb, mrb_value num)
+{
+  mrb_int cp = mrb_int(mrb, num);
+  char utf8[4];
   mrb_int len;
-  int argc;
-
-  argc = mrb_get_args(mrb, "o|i", &a1, &len);
-  if (argc == 2) {
-    return mrb_str_substr(mrb, str, mrb_fixnum(a1), len);
-  }
-  switch (mrb_type(a1)) {
-  case MRB_TT_RANGE:
-    {
-      mrb_int beg;
-
-      len = RSTRING_LEN(str);
-      switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) {
-      case 0:                   /* not range */
-        break;
-      case 1:                   /* range */
-        return mrb_str_substr(mrb, str, beg, len);
-      case 2:                   /* out of range */
-        mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1);
-        break;
-      }
-      return mrb_nil_value();
-    }
-  case MRB_TT_FLOAT:
-    a1 = mrb_fixnum_value((mrb_int)mrb_float(a1));
-    /* fall through */
-  case MRB_TT_FIXNUM:
-    return mrb_str_substr(mrb, str, mrb_fixnum(a1), 1);
-  default:
-    mrb_raise(mrb, E_TYPE_ERROR, "wrong type of argument");
-  }
-  /* not reached */
-  return mrb_nil_value();
-}
+  mrb_value str;
+  uint32_t ascii_flag = 0;
+
+  if (cp < 0 || 0x10FFFF < cp) {
+    mrb_raisef(mrb, E_RANGE_ERROR, "%v out of char range", num);
+  }
+  if (cp < 0x80) {
+    utf8[0] = (char)cp;
+    len = 1;
+    ascii_flag = MRB_STR_ASCII;
+  }
+  else if (cp < 0x800) {
+    utf8[0] = (char)(0xC0 | (cp >> 6));
+    utf8[1] = (char)(0x80 | (cp & 0x3F));
+    len = 2;
+  }
+  else if (cp < 0x10000) {
+    utf8[0] = (char)(0xE0 |  (cp >> 12));
+    utf8[1] = (char)(0x80 | ((cp >>  6) & 0x3F));
+    utf8[2] = (char)(0x80 | ( cp        & 0x3F));
+    len = 3;
+  }
+  else {
+    utf8[0] = (char)(0xF0 |  (cp >> 18));
+    utf8[1] = (char)(0x80 | ((cp >> 12) & 0x3F));
+    utf8[2] = (char)(0x80 | ((cp >>  6) & 0x3F));
+    utf8[3] = (char)(0x80 | ( cp        & 0x3F));
+    len = 4;
+  }
+  str = mrb_str_new(mrb, utf8, len);
+  mrb_str_ptr(str)->flags |= ascii_flag;
+  return str;
+}
+#endif
 
 /*
@@ -135,6 +146,4 @@
 }
 
-static mrb_value mrb_fixnum_chr(mrb_state *mrb, mrb_value num);
-
 /*
  *  call-seq:
@@ -146,5 +155,6 @@
  *  Append---Concatenates the given object to <i>str</i>. If the object is a
  *  <code>Integer</code>, it is considered as a codepoint, and is converted
- *  to a character before concatenation.
+ *  to a character before concatenation
+ *  (equivalent to <code>str.concat(integer.chr(__ENCODING__))</code>).
  *
  *     a = "hello "
@@ -153,14 +163,18 @@
  */
 static mrb_value
-mrb_str_concat2(mrb_state *mrb, mrb_value self)
+mrb_str_concat_m(mrb_state *mrb, mrb_value self)
 {
   mrb_value str;
 
   mrb_get_args(mrb, "o", &str);
-  if (mrb_fixnum_p(str))
-    str = mrb_fixnum_chr(mrb, str);
+  if (mrb_fixnum_p(str) || mrb_float_p(str))
+#ifdef MRB_UTF8_STRING
+    str = int_chr_utf8(mrb, str);
+#else
+    str = int_chr_binary(mrb, str);
+#endif
   else
-    str = mrb_string_type(mrb, str);
-  mrb_str_concat(mrb, self, str);
+    mrb_ensure_string_type(mrb, str);
+  mrb_str_cat_str(mrb, self, str);
   return self;
 }
@@ -189,5 +203,5 @@
     size_t len_l, len_r;
     int ai = mrb_gc_arena_save(mrb);
-    sub = mrb_string_type(mrb, argv[i]);
+    sub = mrb_ensure_string_type(mrb, argv[i]);
     mrb_gc_arena_restore(mrb, ai);
     len_l = RSTRING_LEN(self);
@@ -218,5 +232,5 @@
     size_t len_l, len_r;
     int ai = mrb_gc_arena_save(mrb);
-    sub = mrb_string_type(mrb, argv[i]);
+    sub = mrb_ensure_string_type(mrb, argv[i]);
     mrb_gc_arena_restore(mrb, ai);
     len_l = RSTRING_LEN(self);
@@ -233,4 +247,589 @@
 }
 
+enum tr_pattern_type {
+  TR_UNINITIALIZED = 0,
+  TR_IN_ORDER  = 1,
+  TR_RANGE = 2,
+};
+
+/*
+  #tr Pattern syntax
+
+  <syntax> ::= (<pattern>)* | '^' (<pattern>)*
+  <pattern> ::= <in order> | <range>
+  <in order> ::= (<ch>)+
+  <range> ::= <ch> '-' <ch>
+*/
+struct tr_pattern {
+  uint8_t type;		// 1:in-order, 2:range
+  mrb_bool flag_reverse : 1;
+  mrb_bool flag_on_heap : 1;
+  uint16_t n;
+  union {
+    uint16_t start_pos;
+    char ch[2];
+  } val;
+  struct tr_pattern *next;
+};
+
+#define STATIC_TR_PATTERN { 0 }
+
+static inline void
+tr_free_pattern(mrb_state *mrb, struct tr_pattern *pat)
+{
+  while (pat) {
+    struct tr_pattern *p = pat->next;
+    if (pat->flag_on_heap) {
+      mrb_free(mrb, pat);
+    }
+    pat = p;
+  }
+}
+
+static struct tr_pattern*
+tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_pattern, mrb_bool flag_reverse_enable)
+{
+  const char *pattern = RSTRING_PTR(v_pattern);
+  mrb_int pattern_length = RSTRING_LEN(v_pattern);
+  mrb_bool flag_reverse = FALSE;
+  struct tr_pattern *pat1;
+  mrb_int i = 0;
+
+  if(flag_reverse_enable && pattern_length >= 2 && pattern[0] == '^') {
+    flag_reverse = TRUE;
+    i++;
+  }
+
+  while (i < pattern_length) {
+    /* is range pattern ? */
+    mrb_bool const ret_uninit = (ret->type == TR_UNINITIALIZED);
+    pat1 = ret_uninit
+           ? ret
+           : (struct tr_pattern*)mrb_malloc_simple(mrb, sizeof(struct tr_pattern));
+    if ((i+2) < pattern_length && pattern[i] != '\\' && pattern[i+1] == '-') {
+      if (pat1 == NULL && ret) {
+      nomem:
+        tr_free_pattern(mrb, ret);
+        mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
+        return NULL;            /* not reached */
+      }
+      pat1->type = TR_RANGE;
+      pat1->flag_reverse = flag_reverse;
+      pat1->flag_on_heap = !ret_uninit;
+      pat1->n = pattern[i+2] - pattern[i] + 1;
+      pat1->next = NULL;
+      pat1->val.ch[0] = pattern[i];
+      pat1->val.ch[1] = pattern[i+2];
+      i += 3;
+    }
+    else {
+      /* in order pattern. */
+      mrb_int start_pos = i++;
+      mrb_int len;
+
+      while (i < pattern_length) {
+	if ((i+2) < pattern_length && pattern[i] != '\\' && pattern[i+1] == '-')
+          break;
+	i++;
+      }
+
+      len = i - start_pos;
+      if (len > UINT16_MAX) {
+        mrb_raise(mrb, E_ARGUMENT_ERROR, "tr pattern too long (max 65536)");
+      }
+      if (pat1 == NULL && ret) {
+        goto nomem;
+      }
+      pat1->type = TR_IN_ORDER;
+      pat1->flag_reverse = flag_reverse;
+      pat1->flag_on_heap = !ret_uninit;
+      pat1->n = len;
+      pat1->next = NULL;
+      pat1->val.start_pos = start_pos;
+    }
+
+    if (ret == NULL || ret_uninit) {
+      ret = pat1;
+    }
+    else {
+      struct tr_pattern *p = ret;
+      while (p->next != NULL) {
+        p = p->next;
+      }
+      p->next = pat1;
+    }
+  }
+
+  return ret;
+}
+
+static inline mrb_int
+tr_find_character(const struct tr_pattern *pat, const char *pat_str, int ch)
+{
+  mrb_int ret = -1;
+  mrb_int n_sum = 0;
+  mrb_int flag_reverse = pat ? pat->flag_reverse : 0;
+
+  while (pat != NULL) {
+    if (pat->type == TR_IN_ORDER) {
+      int i;
+      for (i = 0; i < pat->n; i++) {
+	if (pat_str[pat->val.start_pos + i] == ch) ret = n_sum + i;
+      }
+    }
+    else if (pat->type == TR_RANGE) {
+      if (pat->val.ch[0] <= ch && ch <= pat->val.ch[1])
+        ret = n_sum + ch - pat->val.ch[0];
+    }
+    else {
+      mrb_assert(pat->type == TR_UNINITIALIZED);
+    }
+    n_sum += pat->n;
+    pat = pat->next;
+  }
+
+  if (flag_reverse) {
+    return (ret < 0) ? MRB_INT_MAX : -1;
+  }
+  return ret;
+}
+
+static inline mrb_int
+tr_get_character(const struct tr_pattern *pat, const char *pat_str, mrb_int n_th)
+{
+  mrb_int n_sum = 0;
+
+  while (pat != NULL) {
+    if (n_th < (n_sum + pat->n)) {
+      mrb_int i = (n_th - n_sum);
+
+      switch (pat->type) {
+      case TR_IN_ORDER:
+        return pat_str[pat->val.start_pos + i];
+      case TR_RANGE:
+        return pat->val.ch[0]+i;
+      case TR_UNINITIALIZED:
+        return -1;
+      }
+    }
+    if (pat->next == NULL) {
+      switch (pat->type) {
+      case TR_IN_ORDER:
+        return pat_str[pat->val.start_pos + pat->n - 1];
+      case TR_RANGE:
+        return pat->val.ch[1];
+      case TR_UNINITIALIZED:
+        return -1;
+      }
+    }
+    n_sum += pat->n;
+    pat = pat->next;
+  }
+
+  return -1;
+}
+
+static inline void
+tr_bitmap_set(uint8_t bitmap[32], uint8_t ch)
+{
+  uint8_t idx1 = ch / 8;
+  uint8_t idx2 = ch % 8;
+  bitmap[idx1] |= (1<<idx2);
+}
+
+static inline mrb_bool
+tr_bitmap_detect(uint8_t bitmap[32], uint8_t ch)
+{
+  uint8_t idx1 = ch / 8;
+  uint8_t idx2 = ch % 8;
+  if (bitmap[idx1] & (1<<idx2))
+    return TRUE;
+  return FALSE;
+}
+
+/* compile patter to bitmap */
+static void
+tr_compile_pattern(const struct tr_pattern *pat, mrb_value pstr, uint8_t bitmap[32])
+{
+  const char *pattern = RSTRING_PTR(pstr);
+  mrb_int flag_reverse = pat ? pat->flag_reverse : 0;
+  int i;
+
+  for (i=0; i<32; i++) {
+    bitmap[i] = 0;
+  }
+  while (pat != NULL) {
+    if (pat->type == TR_IN_ORDER) {
+      for (i = 0; i < pat->n; i++) {
+        tr_bitmap_set(bitmap, pattern[pat->val.start_pos + i]);
+      }
+    }
+    else if (pat->type == TR_RANGE) {
+      for (i = pat->val.ch[0]; i < pat->val.ch[1]; i++) {
+        tr_bitmap_set(bitmap, i);
+      }
+    }
+    else {
+      mrb_assert(pat->type == TR_UNINITIALIZED);
+    }
+    pat = pat->next;
+  }
+
+  if (flag_reverse) {
+    for (i=0; i<32; i++) {
+      bitmap[i] ^= 0xff;
+    }
+  }
+}
+
+static mrb_bool
+str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squeeze)
+{
+  struct tr_pattern pat = STATIC_TR_PATTERN;
+  struct tr_pattern rep_storage = STATIC_TR_PATTERN;
+  char *s;
+  mrb_int len;
+  mrb_int i;
+  mrb_int j;
+  mrb_bool flag_changed = FALSE;
+  mrb_int lastch = -1;
+  struct tr_pattern *rep;
+
+  mrb_str_modify(mrb, mrb_str_ptr(str));
+  tr_parse_pattern(mrb, &pat, p1, TRUE);
+  rep = tr_parse_pattern(mrb, &rep_storage, p2, FALSE);
+  s = RSTRING_PTR(str);
+  len = RSTRING_LEN(str);
+
+  for (i=j=0; i<len; i++,j++) {
+    mrb_int n = tr_find_character(&pat, RSTRING_PTR(p1), s[i]);
+
+    if (i>j) s[j] = s[i];
+    if (n >= 0) {
+      flag_changed = TRUE;
+      if (rep == NULL) {
+	j--;
+      }
+      else {
+        mrb_int c = tr_get_character(rep, RSTRING_PTR(p2), n);
+
+        if (c < 0 || (squeeze && c == lastch)) {
+          j--;
+          continue;
+        }
+        if (c > 0x80) {
+          mrb_raisef(mrb, E_ARGUMENT_ERROR, "character (%i) out of range", c);
+        }
+	lastch = c;
+	s[i] = (char)c;
+      }
+    }
+  }
+
+  tr_free_pattern(mrb, &pat);
+  tr_free_pattern(mrb, rep);
+
+  if (flag_changed) {
+    RSTR_SET_LEN(RSTRING(str), j);
+    RSTRING_PTR(str)[j] = 0;
+  }
+  return flag_changed;
+}
+
+/*
+ * call-seq:
+ *   str.tr(from_str, to_str)   => new_str
+ *
+ * Returns a copy of str with the characters in from_str replaced by the
+ * corresponding characters in to_str.  If to_str is shorter than from_str,
+ * it is padded with its last character in order to maintain the
+ * correspondence.
+ *
+ *  "hello".tr('el', 'ip')      #=> "hippo"
+ *  "hello".tr('aeiou', '*')    #=> "h*ll*"
+ *  "hello".tr('aeiou', 'AA*')  #=> "hAll*"
+ *
+ * Both strings may use the c1-c2 notation to denote ranges of characters,
+ * and from_str may start with a ^, which denotes all characters except
+ * those listed.
+ *
+ *  "hello".tr('a-y', 'b-z')    #=> "ifmmp"
+ *  "hello".tr('^aeiou', '*')   #=> "*e**o"
+ *
+ * The backslash character \ can be used to escape ^ or - and is otherwise
+ * ignored unless it appears at the end of a range or the end of the
+ * from_str or to_str:
+ *
+ *
+ *  "hello^world".tr("\\^aeiou", "*") #=> "h*ll**w*rld"
+ *  "hello-world".tr("a\\-eo", "*")   #=> "h*ll**w*rld"
+ *
+ *  "hello\r\nworld".tr("\r", "")   #=> "hello\nworld"
+ *  "hello\r\nworld".tr("\\r", "")  #=> "hello\r\nwold"
+ *  "hello\r\nworld".tr("\\\r", "") #=> "hello\nworld"
+ *
+ *  "X['\\b']".tr("X\\", "")   #=> "['b']"
+ *  "X['\\b']".tr("X-\\]", "") #=> "'b'"
+ *
+ *  Note: conversion is effective only in ASCII region.
+ */
+static mrb_value
+mrb_str_tr(mrb_state *mrb, mrb_value str)
+{
+  mrb_value dup;
+  mrb_value p1, p2;
+
+  mrb_get_args(mrb, "SS", &p1, &p2);
+  dup = mrb_str_dup(mrb, str);
+  str_tr(mrb, dup, p1, p2, FALSE);
+  return dup;
+}
+
+/*
+ * call-seq:
+ *   str.tr!(from_str, to_str)   -> str or nil
+ *
+ * Translates str in place, using the same rules as String#tr.
+ * Returns str, or nil if no changes were made.
+ */
+static mrb_value
+mrb_str_tr_bang(mrb_state *mrb, mrb_value str)
+{
+  mrb_value p1, p2;
+
+  mrb_get_args(mrb, "SS", &p1, &p2);
+  if (str_tr(mrb, str, p1, p2, FALSE)) {
+    return str;
+  }
+  return mrb_nil_value();
+}
+
+/*
+ * call-seq:
+ *   str.tr_s(from_str, to_str)   -> new_str
+ *
+ * Processes a copy of str as described under String#tr, then removes
+ * duplicate characters in regions that were affected by the translation.
+ *
+ *  "hello".tr_s('l', 'r')     #=> "hero"
+ *  "hello".tr_s('el', '*')    #=> "h*o"
+ *  "hello".tr_s('el', 'hx')   #=> "hhxo"
+ */
+static mrb_value
+mrb_str_tr_s(mrb_state *mrb, mrb_value str)
+{
+  mrb_value dup;
+  mrb_value p1, p2;
+
+  mrb_get_args(mrb, "SS", &p1, &p2);
+  dup = mrb_str_dup(mrb, str);
+  str_tr(mrb, dup, p1, p2, TRUE);
+  return dup;
+}
+
+/*
+ * call-seq:
+ *   str.tr_s!(from_str, to_str)   -> str or nil
+ *
+ * Performs String#tr_s processing on str in place, returning
+ * str, or nil if no changes were made.
+ */
+static mrb_value
+mrb_str_tr_s_bang(mrb_state *mrb, mrb_value str)
+{
+  mrb_value p1, p2;
+
+  mrb_get_args(mrb, "SS", &p1, &p2);
+  if (str_tr(mrb, str, p1, p2, TRUE)) {
+    return str;
+  }
+  return mrb_nil_value();
+}
+
+static mrb_bool
+str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat)
+{
+  struct tr_pattern pat_storage = STATIC_TR_PATTERN;
+  struct tr_pattern *pat = NULL;
+  mrb_int i, j;
+  char *s;
+  mrb_int len;
+  mrb_bool flag_changed = FALSE;
+  mrb_int lastch = -1;
+  uint8_t bitmap[32];
+
+  mrb_str_modify(mrb, mrb_str_ptr(str));
+  if (!mrb_nil_p(v_pat)) {
+    pat = tr_parse_pattern(mrb, &pat_storage, v_pat, TRUE);
+    tr_compile_pattern(pat, v_pat, bitmap);
+    tr_free_pattern(mrb, pat);
+  }
+  s = RSTRING_PTR(str);
+  len = RSTRING_LEN(str);
+
+  if (pat) {
+    for (i=j=0; i<len; i++,j++) {
+      if (i>j) s[j] = s[i];
+      if (tr_bitmap_detect(bitmap, s[i]) && s[i] == lastch) {
+        flag_changed = TRUE;
+        j--;
+      }
+      lastch = s[i];
+    }
+  }
+  else {
+    for (i=j=0; i<len; i++,j++) {
+      if (i>j) s[j] = s[i];
+      if (s[i] >= 0 && s[i] == lastch) {
+        flag_changed = TRUE;
+        j--;
+      }
+      lastch = s[i];
+    }
+  }
+
+  if (flag_changed) {
+    RSTR_SET_LEN(RSTRING(str), j);
+    RSTRING_PTR(str)[j] = 0;
+  }
+  return flag_changed;
+}
+
+/*
+ * call-seq:
+ *   str.squeeze([other_str])    -> new_str
+ *
+ * Builds a set of characters from the other_str
+ * parameter(s) using the procedure described for String#count. Returns a
+ * new string where runs of the same character that occur in this set are
+ * replaced by a single character. If no arguments are given, all runs of
+ * identical characters are replaced by a single character.
+ *
+ *  "yellow moon".squeeze                  #=> "yelow mon"
+ *  "  now   is  the".squeeze(" ")         #=> " now is the"
+ *  "putters shoot balls".squeeze("m-z")   #=> "puters shot balls"
+ */
+static mrb_value
+mrb_str_squeeze(mrb_state *mrb, mrb_value str)
+{
+  mrb_value pat = mrb_nil_value();
+  mrb_value dup;
+
+  mrb_get_args(mrb, "|S", &pat);
+  dup = mrb_str_dup(mrb, str);
+  str_squeeze(mrb, dup, pat);
+  return dup;
+}
+
+/*
+ * call-seq:
+ *   str.squeeze!([other_str])   -> str or nil
+ *
+ * Squeezes str in place, returning either str, or nil if no
+ * changes were made.
+ */
+static mrb_value
+mrb_str_squeeze_bang(mrb_state *mrb, mrb_value str)
+{
+  mrb_value pat = mrb_nil_value();
+
+  mrb_get_args(mrb, "|S", &pat);
+  if (str_squeeze(mrb, str, pat)) {
+    return str;
+  }
+  return mrb_nil_value();
+}
+
+static mrb_bool
+str_delete(mrb_state *mrb, mrb_value str, mrb_value v_pat)
+{
+  struct tr_pattern pat = STATIC_TR_PATTERN;
+  mrb_int i, j;
+  char *s;
+  mrb_int len;
+  mrb_bool flag_changed = FALSE;
+  uint8_t bitmap[32];
+
+  mrb_str_modify(mrb, mrb_str_ptr(str));
+  tr_parse_pattern(mrb, &pat, v_pat, TRUE);
+  tr_compile_pattern(&pat, v_pat, bitmap);
+  tr_free_pattern(mrb, &pat);
+
+  s = RSTRING_PTR(str);
+  len = RSTRING_LEN(str);
+
+  for (i=j=0; i<len; i++,j++) {
+    if (i>j) s[j] = s[i];
+    if (tr_bitmap_detect(bitmap, s[i])) {
+      flag_changed = TRUE;
+      j--;
+    }
+  }
+  if (flag_changed) {
+    RSTR_SET_LEN(RSTRING(str), j);
+    RSTRING_PTR(str)[j] = 0;
+  }
+  return flag_changed;
+}
+
+static mrb_value
+mrb_str_delete(mrb_state *mrb, mrb_value str)
+{
+  mrb_value pat;
+  mrb_value dup;
+
+  mrb_get_args(mrb, "S", &pat);
+  dup = mrb_str_dup(mrb, str);
+  str_delete(mrb, dup, pat);
+  return dup;
+}
+
+static mrb_value
+mrb_str_delete_bang(mrb_state *mrb, mrb_value str)
+{
+  mrb_value pat;
+
+  mrb_get_args(mrb, "S", &pat);
+  if (str_delete(mrb, str, pat)) {
+    return str;
+  }
+  return mrb_nil_value();
+}
+
+/*
+ * call_seq:
+ *   str.count([other_str])   -> integer
+ *
+ * Each other_str parameter defines a set of characters to count.  The
+ * intersection of these sets defines the characters to count in str.  Any
+ * other_str that starts with a caret ^ is negated.  The sequence c1-c2
+ * means all characters between c1 and c2.  The backslash character \ can
+ * be used to escape ^ or - and is otherwise ignored unless it appears at
+ * the end of a sequence or the end of a other_str.
+ */
+static mrb_value
+mrb_str_count(mrb_state *mrb, mrb_value str)
+{
+  mrb_value v_pat = mrb_nil_value();
+  mrb_int i;
+  char *s;
+  mrb_int len;
+  mrb_int count = 0;
+  struct tr_pattern pat = STATIC_TR_PATTERN;
+  uint8_t bitmap[32];
+
+  mrb_get_args(mrb, "S", &v_pat);
+  tr_parse_pattern(mrb, &pat, v_pat, TRUE);
+  tr_compile_pattern(&pat, v_pat, bitmap);
+  tr_free_pattern(mrb, &pat);
+
+  s = RSTRING_PTR(str);
+  len = RSTRING_LEN(str);
+  for (i = 0; i < len; i++) {
+    if (tr_bitmap_detect(bitmap, s[i])) count++;
+  }
+  return mrb_fixnum_value(count);
+}
+
 static mrb_value
 mrb_str_hex(mrb_state *mrb, mrb_value self)
@@ -260,101 +859,40 @@
 }
 
-static mrb_value
-mrb_fixnum_chr(mrb_state *mrb, mrb_value num)
-{
-  mrb_int cp = mrb_fixnum(num);
+/*
+ *  call-seq:
+ *     int.chr([encoding])  ->  string
+ *
+ *  Returns a string containing the character represented by the +int+'s value
+ *  according to +encoding+. +"ASCII-8BIT"+ (+"BINARY"+) and +"UTF-8"+ (only
+ *  with +MRB_UTF8_STRING+) can be specified as +encoding+ (default is
+ *  +"ASCII-8BIT"+).
+ *
+ *     65.chr                  #=> "A"
+ *     230.chr                 #=> "\xE6"
+ *     230.chr("ASCII-8BIT")   #=> "\xE6"
+ *     230.chr("UTF-8")        #=> "\u00E6"
+ */
+static mrb_value
+mrb_int_chr(mrb_state *mrb, mrb_value num)
+{
+  mrb_value enc;
+  mrb_bool enc_given;
+
+  mrb_get_args(mrb, "|S?", &enc, &enc_given);
+  if (!enc_given ||
+      ENC_COMP_P(enc, ENC_ASCII_8BIT) ||
+      ENC_COMP_P(enc, ENC_BINARY)) {
+    return int_chr_binary(mrb, num);
+  }
 #ifdef MRB_UTF8_STRING
-  char utf8[4];
-  mrb_int len;
-
-  if (cp < 0 || 0x10FFFF < cp) {
-    mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num);
-  }
-  if (cp < 0x80) {
-    utf8[0] = (char)cp;
-    len = 1;
-  }
-  else if (cp < 0x800) {
-    utf8[0] = (char)(0xC0 | (cp >> 6));
-    utf8[1] = (char)(0x80 | (cp & 0x3F));
-    len = 2;
-  }
-  else if (cp < 0x10000) {
-    utf8[0] = (char)(0xE0 |  (cp >> 12));
-    utf8[1] = (char)(0x80 | ((cp >>  6) & 0x3F));
-    utf8[2] = (char)(0x80 | ( cp        & 0x3F));
-    len = 3;
-  }
+  else if (ENC_COMP_P(enc, ENC_UTF8)) {
+    return int_chr_utf8(mrb, num);
+  }
+#endif
   else {
-    utf8[0] = (char)(0xF0 |  (cp >> 18));
-    utf8[1] = (char)(0x80 | ((cp >> 12) & 0x3F));
-    utf8[2] = (char)(0x80 | ((cp >>  6) & 0x3F));
-    utf8[3] = (char)(0x80 | ( cp        & 0x3F));
-    len = 4;
-  }
-  return mrb_str_new(mrb, utf8, len);
-#else
-  char c;
-
-  if (cp < 0 || 0xff < cp) {
-    mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num);
-  }
-  c = (char)cp;
-  return mrb_str_new(mrb, &c, 1);
-#endif
-}
-
-/*
- *  call-seq:
- *     string.lines    ->  array of string
- *
- *  Returns strings per line;
- *
- *     a = "abc\ndef"
- *     a.lines    #=> ["abc\n", "def"]
- */
-static mrb_value
-mrb_str_lines(mrb_state *mrb, mrb_value self)
-{
-  mrb_value result;
-  mrb_value blk;
-  int ai;
-  mrb_int len;
-  mrb_value arg;
-  char *b = RSTRING_PTR(self);
-  char *p = b, *t;
-  char *e = b + RSTRING_LEN(self);
-
-  mrb_get_args(mrb, "&", &blk);
-
-  result = mrb_ary_new(mrb);
-  ai = mrb_gc_arena_save(mrb);
-  if (!mrb_nil_p(blk)) {
-    while (p < e) {
-      t = p;
-      while (p < e && *p != '\n') p++;
-      if (*p == '\n') p++;
-      len = (mrb_int) (p - t);
-      arg = mrb_str_new(mrb, t, len);
-      mrb_yield_argv(mrb, blk, 1, &arg);
-      mrb_gc_arena_restore(mrb, ai);
-      if (b != RSTRING_PTR(self)) {
-        ptrdiff_t diff = p - b;
-        b = RSTRING_PTR(self);
-        p = b + diff;
-      }
-      e = b + RSTRING_LEN(self);
-    }
-    return self;
-  }
-  while (p < e) {
-    t = p;
-    while (p < e && *p != '\n') p++;
-    if (*p == '\n') p++;
-    len = (mrb_int) (p - t);
-    mrb_ary_push(mrb, result, mrb_str_new(mrb, t, len));
-    mrb_gc_arena_restore(mrb, ai);
-  }
-  return result;
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown encoding name - %v", enc);
+  }
+  /* not reached */
+  return mrb_nil_value();
 }
 
@@ -522,123 +1060,137 @@
 #endif
 
-static mrb_bool
-all_digits_p(const char *s, mrb_int len)
-{
-  while (len-- > 0) {
-    if (!ISDIGIT(*s)) return FALSE;
-    s++;
-  }
-  return TRUE;
-}
-
 /*
  *  call-seq:
- *     str.upto(other_str, exclusive=false) {|s| block }   -> str
- *     str.upto(other_str, exclusive=false)                -> an_enumerator
- *
- *  Iterates through successive values, starting at <i>str</i> and
- *  ending at <i>other_str</i> inclusive, passing each value in turn to
- *  the block. The <code>String#succ</code> method is used to generate
- *  each value.  If optional second argument exclusive is omitted or is false,
- *  the last value will be included; otherwise it will be excluded.
- *
- *  If no block is given, an enumerator is returned instead.
- *
- *     "a8".upto("b6") {|s| print s, ' ' }
- *     for s in "a8".."b6"
- *       print s, ' '
- *     end
- *
- *  <em>produces:</em>
- *
- *     a8 a9 b0 b1 b2 b3 b4 b5 b6
- *     a8 a9 b0 b1 b2 b3 b4 b5 b6
- *
- *  If <i>str</i> and <i>other_str</i> contains only ascii numeric characters,
- *  both are recognized as decimal numbers. In addition, the width of
- *  string (e.g. leading zeros) is handled appropriately.
- *
- *     "9".upto("11").to_a   #=> ["9", "10", "11"]
- *     "25".upto("5").to_a   #=> []
- *     "07".upto("11").to_a  #=> ["07", "08", "09", "10", "11"]
- */
-static mrb_value
-mrb_str_upto(mrb_state *mrb, mrb_value beg)
-{
-  mrb_value end;
-  mrb_value exclusive = mrb_false_value();
-  mrb_value block = mrb_nil_value();
-  mrb_value current, after_end;
-  mrb_int n;
-  mrb_bool excl;
-
-  mrb_get_args(mrb, "o|o&", &end, &exclusive, &block);
-
-  if (mrb_nil_p(block)) {
-    return mrb_funcall(mrb, beg, "to_enum", 3, mrb_symbol_value(mrb_intern_lit(mrb, "upto")), end, exclusive);
-  }
-  end = mrb_string_type(mrb, end);
-  excl = mrb_test(exclusive);
-
-  /* single character */
-  if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 &&
-  ISASCII(RSTRING_PTR(beg)[0]) && ISASCII(RSTRING_PTR(end)[0])) {
-    char c = RSTRING_PTR(beg)[0];
-    char e = RSTRING_PTR(end)[0];
-    int ai = mrb_gc_arena_save(mrb);
-
-    if (c > e || (excl && c == e)) return beg;
-    for (;;) {
-      mrb_yield(mrb, block, mrb_str_new(mrb, &c, 1));
-      mrb_gc_arena_restore(mrb, ai);
-      if (!excl && c == e) break;
-      c++;
-      if (excl && c == e) break;
-    }
-    return beg;
-  }
-  /* both edges are all digits */
-  if (ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) &&
-      all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
-      all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
-    int ai = mrb_gc_arena_save(mrb);
-    mrb_int min_width = RSTRING_LEN(beg);
-    mrb_int max_width = RSTRING_LEN(end);
-    mrb_int bi = mrb_int(mrb, mrb_str_to_inum(mrb, beg, 10, FALSE));
-    mrb_int ei = mrb_int(mrb, mrb_str_to_inum(mrb, end, 10, FALSE));
-    mrb_value str = mrb_str_new(mrb, NULL, max_width);
-    char *buf = RSTRING_PTR(str);
-
-    while (bi <= ei) {
-      if (excl && bi == ei) break;
-      snprintf(buf, max_width+1, "%.*" MRB_PRId, (int)min_width, bi);
-      mrb_yield(mrb, block, mrb_str_new(mrb, buf, strlen(buf)));
-      mrb_gc_arena_restore(mrb, ai);
-      bi++;
-    }
-
-    return beg;
-  }
-  /* normal case */
-  n = mrb_int(mrb, mrb_funcall(mrb, beg, "<=>", 1, end));
-  if (n > 0 || (excl && n == 0)) return beg;
-
-  after_end = mrb_funcall(mrb, end, "succ", 0);
-  current = mrb_str_dup(mrb, beg);
-  while (!mrb_str_equal(mrb, current, after_end)) {
-    int ai = mrb_gc_arena_save(mrb);
-    mrb_value next = mrb_nil_value();
-    if (excl || !mrb_str_equal(mrb, current, end))
-      next = mrb_funcall(mrb, current, "succ", 0);
-    mrb_yield(mrb, block, current);
-    if (mrb_nil_p(next)) break;
-    current = mrb_str_to_str(mrb, next);
-    if (excl && mrb_str_equal(mrb, current, end)) break;
-    if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
-      break;
+ *     str.delete_prefix!(prefix) -> self or nil
+ *
+ *  Deletes leading <code>prefix</code> from <i>str</i>, returning
+ *  <code>nil</code> if no change was made.
+ *
+ *     "hello".delete_prefix!("hel") #=> "lo"
+ *     "hello".delete_prefix!("llo") #=> nil
+ */
+static mrb_value
+mrb_str_del_prefix_bang(mrb_state *mrb, mrb_value self)
+{
+  mrb_int plen, slen;
+  char *ptr, *s;
+  struct RString *str = RSTRING(self);
+
+  mrb_get_args(mrb, "s", &ptr, &plen);
+  slen = RSTR_LEN(str);
+  if (plen > slen) return mrb_nil_value();
+  s = RSTR_PTR(str);
+  if (memcmp(s, ptr, plen) != 0) return mrb_nil_value();
+  if (!mrb_frozen_p(str) && (RSTR_SHARED_P(str) || RSTR_FSHARED_P(str))) {
+    str->as.heap.ptr += plen;
+  }
+  else {
+    mrb_str_modify(mrb, str);
+    s = RSTR_PTR(str);
+    memmove(s, s+plen, slen-plen);
+  }
+  RSTR_SET_LEN(str, slen-plen);
+  return self;
+}
+
+/*
+ *  call-seq:
+ *     str.delete_prefix(prefix) -> new_str
+ *
+ *  Returns a copy of <i>str</i> with leading <code>prefix</code> deleted.
+ *
+ *     "hello".delete_prefix("hel") #=> "lo"
+ *     "hello".delete_prefix("llo") #=> "hello"
+ */
+static mrb_value
+mrb_str_del_prefix(mrb_state *mrb, mrb_value self)
+{
+  mrb_int plen, slen;
+  char *ptr;
+
+  mrb_get_args(mrb, "s", &ptr, &plen);
+  slen = RSTRING_LEN(self);
+  if (plen > slen) return mrb_str_dup(mrb, self);
+  if (memcmp(RSTRING_PTR(self), ptr, plen) != 0)
+    return mrb_str_dup(mrb, self);
+  return mrb_str_substr(mrb, self, plen, slen-plen);
+}
+
+/*
+ *  call-seq:
+ *     str.delete_suffix!(suffix) -> self or nil
+ *
+ *  Deletes trailing <code>suffix</code> from <i>str</i>, returning
+ *  <code>nil</code> if no change was made.
+ *
+ *     "hello".delete_suffix!("llo") #=> "he"
+ *     "hello".delete_suffix!("hel") #=> nil
+ */
+static mrb_value
+mrb_str_del_suffix_bang(mrb_state *mrb, mrb_value self)
+{
+  mrb_int plen, slen;
+  char *ptr, *s;
+  struct RString *str = RSTRING(self);
+
+  mrb_get_args(mrb, "s", &ptr, &plen);
+  slen = RSTR_LEN(str);
+  if (plen > slen) return mrb_nil_value();
+  s = RSTR_PTR(str);
+  if (memcmp(s+slen-plen, ptr, plen) != 0) return mrb_nil_value();
+  if (!mrb_frozen_p(str) && (RSTR_SHARED_P(str) || RSTR_FSHARED_P(str))) {
+    /* no need to modify string */
+  }
+  else {
+    mrb_str_modify(mrb, str);
+  }
+  RSTR_SET_LEN(str, slen-plen);
+  return self;
+}
+
+/*
+ *  call-seq:
+ *     str.delete_suffix(suffix) -> new_str
+ *
+ *  Returns a copy of <i>str</i> with leading <code>suffix</code> deleted.
+ *
+ *     "hello".delete_suffix("hel") #=> "lo"
+ *     "hello".delete_suffix("llo") #=> "hello"
+ */
+static mrb_value
+mrb_str_del_suffix(mrb_state *mrb, mrb_value self)
+{
+  mrb_int plen, slen;
+  char *ptr;
+
+  mrb_get_args(mrb, "s", &ptr, &plen);
+  slen = RSTRING_LEN(self);
+  if (plen > slen) return mrb_str_dup(mrb, self);
+  if (memcmp(RSTRING_PTR(self)+slen-plen, ptr, plen) != 0)
+    return mrb_str_dup(mrb, self);
+  return mrb_str_substr(mrb, self, 0, slen-plen);
+}
+
+static mrb_value
+mrb_str_lines(mrb_state *mrb, mrb_value self)
+{
+  mrb_value result;
+  int ai;
+  mrb_int len;
+  char *b = RSTRING_PTR(self);
+  char *p = b, *t;
+  char *e = b + RSTRING_LEN(self);
+
+  result = mrb_ary_new(mrb);
+  ai = mrb_gc_arena_save(mrb);
+  while (p < e) {
+    t = p;
+    while (p < e && *p != '\n') p++;
+    if (*p == '\n') p++;
+    len = (mrb_int) (p - t);
+    mrb_ary_push(mrb, result, mrb_str_new(mrb, t, len));
     mrb_gc_arena_restore(mrb, ai);
   }
-
-  return beg;
+  return result;
 }
 
@@ -649,11 +1201,17 @@
 
   mrb_define_method(mrb, s, "dump",            mrb_str_dump,            MRB_ARGS_NONE());
-  mrb_define_method(mrb, s, "getbyte",         mrb_str_getbyte,         MRB_ARGS_REQ(1));
-  mrb_define_method(mrb, s, "setbyte",         mrb_str_setbyte,         MRB_ARGS_REQ(2));
-  mrb_define_method(mrb, s, "byteslice",       mrb_str_byteslice,       MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
   mrb_define_method(mrb, s, "swapcase!",       mrb_str_swapcase_bang,   MRB_ARGS_NONE());
   mrb_define_method(mrb, s, "swapcase",        mrb_str_swapcase,        MRB_ARGS_NONE());
-  mrb_define_method(mrb, s, "concat",          mrb_str_concat2,         MRB_ARGS_REQ(1));
-  mrb_define_method(mrb, s, "<<",              mrb_str_concat2,         MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, s, "concat",          mrb_str_concat_m,        MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, s, "<<",              mrb_str_concat_m,        MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, s, "count",           mrb_str_count,           MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, s, "tr",              mrb_str_tr,              MRB_ARGS_REQ(2));
+  mrb_define_method(mrb, s, "tr!",             mrb_str_tr_bang,         MRB_ARGS_REQ(2));
+  mrb_define_method(mrb, s, "tr_s",            mrb_str_tr_s,            MRB_ARGS_REQ(2));
+  mrb_define_method(mrb, s, "tr_s!",           mrb_str_tr_s_bang,       MRB_ARGS_REQ(2));
+  mrb_define_method(mrb, s, "squeeze",         mrb_str_squeeze,         MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, s, "squeeze!",        mrb_str_squeeze_bang,    MRB_ARGS_OPT(1));
+  mrb_define_method(mrb, s, "delete",          mrb_str_delete,          MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, s, "delete!",         mrb_str_delete_bang,     MRB_ARGS_REQ(1));
   mrb_define_method(mrb, s, "start_with?",     mrb_str_start_with,      MRB_ARGS_REST());
   mrb_define_method(mrb, s, "end_with?",       mrb_str_end_with,        MRB_ARGS_REST());
@@ -661,13 +1219,17 @@
   mrb_define_method(mrb, s, "oct",             mrb_str_oct,             MRB_ARGS_NONE());
   mrb_define_method(mrb, s, "chr",             mrb_str_chr,             MRB_ARGS_NONE());
-  mrb_define_method(mrb, s, "lines",           mrb_str_lines,           MRB_ARGS_NONE());
   mrb_define_method(mrb, s, "succ",            mrb_str_succ,            MRB_ARGS_NONE());
   mrb_define_method(mrb, s, "succ!",           mrb_str_succ_bang,       MRB_ARGS_NONE());
-  mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ"));
-  mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!"));
-  mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE());
-  mrb_define_method(mrb, s, "upto", mrb_str_upto, MRB_ARGS_ANY());
-
-  mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE());
+  mrb_define_method(mrb, s, "next",            mrb_str_succ,            MRB_ARGS_NONE());
+  mrb_define_method(mrb, s, "next!",           mrb_str_succ_bang,       MRB_ARGS_NONE());
+  mrb_define_method(mrb, s, "ord",             mrb_str_ord,             MRB_ARGS_NONE());
+  mrb_define_method(mrb, s, "delete_prefix!",  mrb_str_del_prefix_bang, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, s, "delete_prefix",   mrb_str_del_prefix,      MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, s, "delete_suffix!",  mrb_str_del_suffix_bang, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, s, "delete_suffix",   mrb_str_del_suffix,      MRB_ARGS_REQ(1));
+
+  mrb_define_method(mrb, s, "__lines",         mrb_str_lines,           MRB_ARGS_NONE());
+
+  mrb_define_method(mrb, mrb_module_get(mrb, "Integral"), "chr", mrb_int_chr, MRB_ARGS_OPT(1));
 }
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/test/numeric.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/test/numeric.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/test/numeric.rb	(revision 439)
@@ -0,0 +1,29 @@
+# coding: utf-8
+
+assert('Integer#chr') do
+  assert_equal("A", 65.chr)
+  assert_equal("B", 0x42.chr)
+  assert_equal("\xab", 171.chr)
+  assert_raise(RangeError) { -1.chr }
+  assert_raise(RangeError) { 256.chr }
+
+  assert_equal("A", 65.chr("ASCII-8BIT"))
+  assert_equal("B", 0x42.chr("BINARY"))
+  assert_equal("\xab", 171.chr("ascii-8bit"))
+  assert_raise(RangeError) { -1.chr("binary") }
+  assert_raise(RangeError) { 256.chr("Ascii-8bit") }
+  assert_raise(ArgumentError) { 65.chr("ASCII") }
+  assert_raise(ArgumentError) { 65.chr("ASCII-8BIT", 2) }
+  assert_raise(TypeError) { 65.chr(:BINARY) }
+
+  if __ENCODING__ == "ASCII-8BIT"
+    assert_raise(ArgumentError) { 65.chr("UTF-8") }
+  else
+    assert_equal("A", 65.chr("UTF-8"))
+    assert_equal("B", 0x42.chr("UTF-8"))
+    assert_equal("«", 171.chr("utf-8"))
+    assert_equal("あ", 12354.chr("Utf-8"))
+    assert_raise(RangeError) { -1.chr("utf-8") }
+    assert_raise(RangeError) { 0x110000.chr.chr("UTF-8") }
+  end
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/test/range.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/test/range.rb	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/test/range.rb	(revision 439)
@@ -0,0 +1,26 @@
+assert('Range#max') do
+  # returns the maximum value in the range when called with no arguments
+  assert_equal 'l', ('f'..'l').max
+  assert_equal 'e', ('a'...'f').max
+
+  # returns nil when the endpoint is less than the start point
+  assert_equal nil, ('z'..'l').max
+end
+
+assert('Range#max given a block') do
+  # returns nil when the endpoint is less than the start point
+  assert_equal nil, (('z'..'l').max { |x, y| x <=> y })
+end
+
+assert('Range#min') do
+  # returns the minimum value in the range when called with no arguments
+  assert_equal 'f', ('f'..'l').min
+
+  # returns nil when the start point is greater than the endpoint
+  assert_equal nil, ('z'..'l').min
+end
+
+assert('Range#min given a block') do
+  # returns nil when the start point is greater than the endpoint
+  assert_equal nil, (('z'..'l').min { |x, y| x <=> y })
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/test/string.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-string-ext/test/string.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-string-ext/test/string.rb	(revision 439)
@@ -1,93 +1,55 @@
+# coding: utf-8
 ##
 # String(Ext) Test
 
-UTF8STRING = ("\343\201\202".size == 1)
-
-assert('String.try_convert') do
-  assert_nil String.try_convert(nil)
-  assert_nil String.try_convert(:foo)
-  assert_equal "", String.try_convert("")
-  assert_equal "1,2,3", String.try_convert("1,2,3")
-end
-
-assert('String#getbyte') do
-  str1 = "hello"
-  bytes1 = [104, 101, 108, 108, 111]
-  assert_equal bytes1[0], str1.getbyte(0)
-  assert_equal bytes1[-1], str1.getbyte(-1)
-  assert_equal bytes1[6], str1.getbyte(6)
-
-  str2 = "\xFF"
-  bytes2 = [0xFF]
-  assert_equal bytes2[0], str2.getbyte(0)
-end
-
-assert('String#setbyte') do
-  str1 = "hello"
-  h = "H".getbyte(0)
-  str1.setbyte(0, h)
-  assert_equal(h, str1.getbyte(0))
-  assert_equal("Hello", str1)
-end
-
-assert("String#setbyte raises IndexError if arg conversion resizes String") do
-  $s = "01234\n"
-  class Tmp
-      def to_i
-          $s.chomp! ''
-          95
-      end
-  end
-  tmp = Tmp.new
-  assert_raise(IndexError) { $s.setbyte(5, tmp) }
-end
-
-assert('String#byteslice') do
-  str1 = "hello"
-  assert_equal("e", str1.byteslice(1))
-  assert_equal("o", str1.byteslice(-1))
-  assert_equal("ell", str1.byteslice(1..3))
-  assert_equal("el", str1.byteslice(1...3))
+UTF8STRING = __ENCODING__ == "UTF-8"
+
+def assert_upto(exp, receiver, *args)
+  act = []
+  receiver.upto(*args) { |v| act << v }
+  assert_equal exp, act
 end
 
 assert('String#dump') do
-  ("\1" * 100).dump     # should not raise an exception - regress #1210
-  "\0".inspect == "\"\\000\"" and
-  "foo".dump == "\"foo\""
+  assert_equal("\"\\x00\"", "\0".dump)
+  assert_equal("\"foo\"", "foo".dump)
+  assert_equal('"\xe3\x82\x8b"', "る".dump)
+  assert_nothing_raised { ("\1" * 100).dump }   # regress #1210
 end
 
 assert('String#strip') do
   s = "  abc  "
-  "".strip == "" and " \t\r\n\f\v".strip == "" and
-  "\0a\0".strip == "\0a" and
-  "abc".strip     == "abc" and
-  "  abc".strip   == "abc" and
-  "abc  ".strip   == "abc" and
-  "  abc  ".strip == "abc" and
-  s == "  abc  "
+  assert_equal("abc", s.strip)
+  assert_equal("  abc  ", s)
+  assert_equal("", "".strip)
+  assert_equal("", " \t\r\n\f\v".strip)
+  assert_equal("\0a", "\0a\0".strip)
+  assert_equal("abc", "abc".strip)
+  assert_equal("abc", "  abc".strip)
+  assert_equal("abc", "abc  ".strip)
 end
 
 assert('String#lstrip') do
   s = "  abc  "
-  s.lstrip
-  "".lstrip == "" and " \t\r\n\f\v".lstrip == "" and
-  "\0a\0".lstrip == "\0a\0" and
-  "abc".lstrip     == "abc"   and
-  "  abc".lstrip   == "abc"   and
-  "abc  ".lstrip   == "abc  " and
-  "  abc  ".lstrip == "abc  " and
-  s == "  abc  "
+  assert_equal("abc  ", s.lstrip)
+  assert_equal("  abc  ", s)
+  assert_equal("", "".lstrip)
+  assert_equal("", " \t\r\n\f\v".lstrip)
+  assert_equal("\0a\0", "\0a\0".lstrip)
+  assert_equal("abc", "abc".lstrip)
+  assert_equal("abc", "  abc".lstrip)
+  assert_equal("abc  ", "abc  ".lstrip)
 end
 
 assert('String#rstrip') do
   s = "  abc  "
-  s.rstrip
-  "".rstrip == "" and " \t\r\n\f\v".rstrip == "" and
-  "\0a\0".rstrip == "\0a" and
-  "abc".rstrip     == "abc"   and
-  "  abc".rstrip   == "  abc" and
-  "abc  ".rstrip   == "abc"   and
-  "  abc  ".rstrip == "  abc" and
-  s == "  abc  "
+  assert_equal("  abc", s.rstrip)
+  assert_equal("  abc  ", s)
+  assert_equal("", "".rstrip)
+  assert_equal("", " \t\r\n\f\v".rstrip)
+  assert_equal("\0a", "\0a\0".rstrip)
+  assert_equal("abc", "abc".rstrip)
+  assert_equal("  abc", "  abc".rstrip)
+  assert_equal("abc", "abc  ".rstrip)
 end
 
@@ -95,5 +57,8 @@
   s = "  abc  "
   t = "abc"
-  s.strip! == "abc" and s == "abc" and t.strip! == nil
+  assert_equal("abc", s.strip!)
+  assert_equal("abc", s)
+  assert_nil(t.strip!)
+  assert_equal("abc", t)
 end
 
@@ -101,5 +66,8 @@
   s = "  abc  "
   t = "abc  "
-  s.lstrip! == "abc  " and s == "abc  " and t.lstrip! == nil
+  assert_equal("abc  ", s.lstrip!)
+  assert_equal("abc  ", s)
+  assert_nil(t.lstrip!)
+  assert_equal("abc  ", t)
 end
 
@@ -107,5 +75,8 @@
   s = "  abc  "
   t = "  abc"
-  s.rstrip! == "  abc" and s == "  abc" and t.rstrip! == nil
+  assert_equal("  abc", s.rstrip!)
+  assert_equal("  abc", s)
+  assert_nil(t.rstrip!)
+  assert_equal("  abc", t)
 end
 
@@ -125,12 +96,13 @@
   assert_equal "Hello World!", "Hello " << "World" << 33
   assert_equal "Hello World!", "Hello ".concat("World").concat(33)
-
-  o = Object.new
-  def o.to_str
-    "to_str"
-  end
-  assert_equal "hi to_str", "hi " << o
-
   assert_raise(TypeError) { "".concat(Object.new) }
+
+  if UTF8STRING
+    assert_equal "H«", "H" << 0xab
+    assert_equal "Hは", "H" << 12399
+  else
+    assert_equal "H\xab", "H" << 0xab
+    assert_raise(RangeError) { "H" << 12399 }
+  end
 end
 
@@ -140,9 +112,67 @@
   assert_equal(-1, "abcdef".casecmp("abcdefg"))
   assert_equal 0, "abcdef".casecmp("ABCDEF")
-  o = Object.new
-  def o.to_str
-    "ABCDEF"
-  end
-  assert_equal 0, "abcdef".casecmp(o)
+end
+
+assert('String#count') do
+  s = "abccdeff123"
+  assert_equal 0, s.count("")
+  assert_equal 1, s.count("a")
+  assert_equal 2, s.count("ab")
+  assert_equal 9, s.count("^c")
+  assert_equal 8, s.count("a-z")
+  assert_equal 4, s.count("a0-9")
+end
+
+assert('String#tr') do
+  assert_equal "ABC", "abc".tr('a-z', 'A-Z')
+  assert_equal "hippo", "hello".tr('el', 'ip')
+  assert_equal "Ruby", "Lisp".tr("Lisp", "Ruby")
+  assert_equal "*e**o", "hello".tr('^aeiou', '*')
+  assert_equal "heo", "hello".tr('l', '')
+end
+
+assert('String#tr!') do
+  s = "abcdefghijklmnopqR"
+  assert_equal "ab12222hijklmnopqR", s.tr!("cdefg", "12")
+  assert_equal "ab12222hijklmnopqR", s
+end
+
+assert('String#tr_s') do
+  assert_equal "hero", "hello".tr_s('l', 'r')
+  assert_equal "h*o", "hello".tr_s('el', '*')
+  assert_equal "hhxo", "hello".tr_s('el', 'hx')
+end
+
+assert('String#tr_s!') do
+  s = "hello"
+  assert_equal "hero", s.tr_s!('l', 'r')
+  assert_equal "hero", s
+  assert_nil s.tr_s!('l', 'r')
+end
+
+assert('String#squeeze') do
+  assert_equal "yelow mon", "yellow moon".squeeze
+  assert_equal " now is the", "  now   is  the".squeeze(" ")
+  assert_equal "puters shot balls", "putters shoot balls".squeeze("m-z")
+end
+
+assert('String#squeeze!') do
+  s = "  now   is  the"
+  assert_equal " now is the", s.squeeze!(" ")
+  assert_equal " now is the", s
+end
+
+assert('String#delete') do
+  assert_equal "he", "hello".delete("lo")
+  assert_equal "hll", "hello".delete("aeiou")
+  assert_equal "ll", "hello".delete("^l")
+  assert_equal "ho", "hello".delete("ej-m")
+end
+
+assert('String#delete!') do
+  s = "hello"
+  assert_equal "he", s.delete!("lo")
+  assert_equal "he", s
+  assert_nil s.delete!("lz")
 end
 
@@ -202,10 +232,4 @@
   assert_equal 8, "010".oct
   assert_equal (-8), "-10".oct
-end
-
-assert('String#chr') do
-  assert_equal "a", "abcde".chr
-  # test Fixnum#chr as well
-  assert_equal "a", 97.chr
 end
 
@@ -496,14 +520,13 @@
 
 assert('String#upto') do
-  assert_equal %w(a8 a9 b0 b1 b2 b3 b4 b5 b6), "a8".upto("b6").to_a
-  assert_equal ["9", "10", "11"], "9".upto("11").to_a
-  assert_equal [], "25".upto("5").to_a
-  assert_equal ["07", "08", "09", "10", "11"], "07".upto("11").to_a
-
-if UTF8STRING
-  assert_equal ["あ", "ぃ", "い", "ぅ", "う", "ぇ", "え", "ぉ", "お"], "あ".upto("お").to_a
-end
-
-  assert_equal ["9", ":", ";", "<", "=", ">", "?", "@", "A"], "9".upto("A").to_a
+  assert_upto %w(a8 a9 b0 b1 b2 b3 b4 b5 b6), "a8", "b6"
+  assert_upto ["9", "10", "11"], "9", "11"
+  assert_upto [], "25", "5"
+  assert_upto ["07", "08", "09", "10", "11"], "07", "11"
+  assert_upto ["9", ":", ";", "<", "=", ">", "?", "@", "A"], "9", "A"
+
+  if UTF8STRING
+    assert_upto %w(あ ぃ い ぅ う ぇ え ぉ お), "あ", "お"
+  end
 
   a     = "aa"
@@ -587,6 +610,9 @@
 
 assert('String#chr') do
+  assert_equal "a", "abcde".chr
   assert_equal "h", "hello!".chr
-end
+  assert_equal "", "".chr
+end
+
 assert('String#chr(UTF-8)') do
   assert_equal "こ", "こんにちは世界!".chr
@@ -614,17 +640,17 @@
 
 assert('String#each_char') do
-  s = ""
+  chars = []
   "hello!".each_char do |x|
-    s += x
-  end
-  assert_equal "hello!", s
+    chars << x
+  end
+  assert_equal ["h", "e", "l", "l", "o", "!"], chars
 end
 
 assert('String#each_char(UTF-8)') do
-  s = ""
+  chars = []
   "こんにちは世界!".each_char do |x|
-    s += x
-  end
-  assert_equal "こんにちは世界!", s
+    chars << x
+  end
+  assert_equal ["こ", "ん", "に", "ち", "は", "世", "界", "!"], chars
 end if UTF8STRING
 
@@ -666,2 +692,16 @@
   assert_equal expect, cp
 end if UTF8STRING
+
+assert('String#delete_prefix') do
+  assert_equal "llo", "hello".delete_prefix("he")
+  assert_equal "hello", "hello".delete_prefix("llo")
+  assert_equal "llo", "hello".delete_prefix!("he")
+  assert_nil "hello".delete_prefix!("llo")
+end
+
+assert('String#delete_suffix') do
+  assert_equal "he", "hello".delete_suffix("llo")
+  assert_equal "hello", "hello".delete_suffix("he")
+  assert_equal "he", "hello".delete_suffix!("llo")
+  assert_nil "hello".delete_suffix!("he")
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-struct/mrblib/struct.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-struct/mrblib/struct.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-struct/mrblib/struct.rb	(revision 439)
@@ -47,5 +47,7 @@
     end
 
-    def _inspect
+    def _inspect(recur_list)
+      return "#<struct #{self.class}:...>" if recur_list[self.object_id]
+      recur_list[self.object_id] = true
       name = self.class.to_s
       if name[0] == "#"
@@ -56,5 +58,5 @@
       buf = []
       self.each_pair do |k,v|
-        buf.push [k.to_s + "=" + v._inspect]
+        buf.push k.to_s + "=" + v._inspect(recur_list)
       end
       str + buf.join(", ") + ">"
@@ -71,9 +73,5 @@
     #
     def inspect
-      begin
-        self._inspect
-      rescue SystemStackError
-        "#<struct #{self.class.to_s}:...>"
-      end
+      self._inspect({})
     end
 
@@ -82,22 +80,21 @@
     #
     alias to_s inspect
-  end
 
-  ##
-  # call-seq:
-  #   hsh.dig(key,...)                 -> object
-  #
-  # Extracts the nested value specified by the sequence of <i>key</i>
-  # objects by calling +dig+ at each step, returning +nil+ if any
-  # intermediate step is +nil+.
-  #
-  def dig(idx,*args)
-    n = self[idx]
-    if args.size > 0
-      n&.dig(*args)
-    else
-      n
+    ##
+    # call-seq:
+    #   hsh.dig(key,...)                 -> object
+    #
+    # Extracts the nested value specified by the sequence of <i>key</i>
+    # objects by calling +dig+ at each step, returning +nil+ if any
+    # intermediate step is +nil+.
+    #
+    def dig(idx,*args)
+      n = self[idx]
+      if args.size > 0
+        n&.dig(*args)
+      else
+        n
+      end
     end
   end
 end
-
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-struct/src/struct.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-struct/src/struct.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-struct/src/struct.c	(revision 439)
@@ -13,7 +13,8 @@
 #include <mruby/hash.h>
 #include <mruby/range.h>
-
-#define RSTRUCT_LEN(st) mrb_ary_ptr(st)->len
-#define RSTRUCT_PTR(st) mrb_ary_ptr(st)->ptr
+#include <mruby/proc.h>
+
+#define RSTRUCT_LEN(st) RARRAY_LEN(st)
+#define RSTRUCT_PTR(st) RARRAY_PTR(st)
 
 static struct RClass *
@@ -24,17 +25,16 @@
 
 static inline mrb_value
-struct_ivar_get(mrb_state *mrb, mrb_value c, mrb_sym id)
-{
-  struct RClass* kclass;
+struct_ivar_get(mrb_state *mrb, mrb_value cls, mrb_sym id)
+{
+  struct RClass* c = mrb_class_ptr(cls);
   struct RClass* sclass = struct_class(mrb);
   mrb_value ans;
 
   for (;;) {
-    ans = mrb_iv_get(mrb, c, id);
+    ans = mrb_iv_get(mrb, mrb_obj_value(c), id);
     if (!mrb_nil_p(ans)) return ans;
-    kclass = RCLASS_SUPER(c);
-    if (kclass == 0 || kclass == sclass)
+    c = c->super;
+    if (c == sclass || c == 0)
       return mrb_nil_value();
-    c = mrb_obj_value(kclass);
   }
 }
@@ -67,6 +67,6 @@
     else {
       mrb_raisef(mrb, E_TYPE_ERROR,
-                 "struct size differs (%S required %S given)",
-                 mrb_fixnum_value(RARRAY_LEN(members)), mrb_fixnum_value(RSTRUCT_LEN(s)));
+                 "struct size differs (%i required %i given)",
+                 RARRAY_LEN(members), RSTRUCT_LEN(s));
     }
   }
@@ -88,8 +88,5 @@
 mrb_struct_modify(mrb_state *mrb, mrb_value strct)
 {
-  if (MRB_FROZEN_P(mrb_basic_ptr(strct))) {
-    mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen struct");
-  }
-
+  mrb_check_frozen(mrb, mrb_basic_ptr(strct));
   mrb_write_barrier(mrb, mrb_basic_ptr(strct));
 }
@@ -114,10 +111,12 @@
 }
 
-static mrb_value struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id);
-
 static mrb_value
 mrb_struct_ref(mrb_state *mrb, mrb_value obj)
 {
-  return struct_aref_sym(mrb, obj, mrb->c->ci->mid);
+  mrb_int i = mrb_fixnum(mrb_proc_cfunc_env_get(mrb, 0));
+  mrb_value *ptr = RSTRUCT_PTR(obj);
+
+  if (!ptr) return mrb_nil_value();
+  return ptr[i];
 }
 
@@ -125,52 +124,47 @@
 mrb_id_attrset(mrb_state *mrb, mrb_sym id)
 {
+#define ONSTACK_ALLOC_MAX 32
+#define ONSTACK_STRLEN_MAX (ONSTACK_ALLOC_MAX - 1) /* '=' character */
+
   const char *name;
   char *buf;
   mrb_int len;
   mrb_sym mid;
-
-  name = mrb_sym2name_len(mrb, id, &len);
-  buf = (char *)mrb_malloc(mrb, (size_t)len+2);
+  char onstack[ONSTACK_ALLOC_MAX];
+
+  name = mrb_sym_name_len(mrb, id, &len);
+  if (len > ONSTACK_STRLEN_MAX) {
+    buf = (char *)mrb_malloc(mrb, (size_t)len+1);
+  }
+  else {
+    buf = onstack;
+  }
   memcpy(buf, name, (size_t)len);
   buf[len] = '=';
-  buf[len+1] = '\0';
 
   mid = mrb_intern(mrb, buf, len+1);
-  mrb_free(mrb, buf);
+  if (buf != onstack) {
+    mrb_free(mrb, buf);
+  }
   return mid;
 }
 
-static mrb_value mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val);
-
 static mrb_value
 mrb_struct_set_m(mrb_state *mrb, mrb_value obj)
 {
+  mrb_int i = mrb_fixnum(mrb_proc_cfunc_env_get(mrb, 0));
+  mrb_value *ptr;
   mrb_value val;
 
-  const char *name;
-  mrb_int slen;
-  mrb_sym mid;
-
   mrb_get_args(mrb, "o", &val);
-
-  /* get base id */
-  name = mrb_sym2name_len(mrb, mrb->c->ci->mid, &slen);
-  mid = mrb_intern(mrb, name, slen-1); /* omit last "=" */
-
-  return mrb_struct_aset_sym(mrb, obj, mid, val);
-}
-
-static mrb_bool
-is_local_id(mrb_state *mrb, const char *name)
-{
-  if (!name) return FALSE;
-  return !ISUPPER(name[0]);
-}
-
-static mrb_bool
-is_const_id(mrb_state *mrb, const char *name)
-{
-  if (!name) return FALSE;
-  return ISUPPER(name[0]);
+  mrb_struct_modify(mrb, obj);
+  ptr = RSTRUCT_PTR(obj);
+  if (ptr == NULL || i >= RSTRUCT_LEN(obj)) {
+    mrb_ary_set(mrb, obj, i, val);
+  }
+  else {
+    ptr[i] = val;
+  }
+  return val;
 }
 
@@ -185,16 +179,18 @@
   for (i=0; i<len; i++) {
     mrb_sym id = mrb_symbol(ptr_members[i]);
-    const char *name = mrb_sym2name_len(mrb, id, NULL);
-
-    if (is_local_id(mrb, name) || is_const_id(mrb, name)) {
-      mrb_define_method_id(mrb, c, id, mrb_struct_ref, MRB_ARGS_NONE());
-      mrb_define_method_id(mrb, c, mrb_id_attrset(mrb, id), mrb_struct_set_m, MRB_ARGS_REQ(1));
-      mrb_gc_arena_restore(mrb, ai);
-    }
-  }
-}
-
-static mrb_value
-make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * klass)
+    mrb_method_t m;
+    mrb_value at = mrb_fixnum_value(i);
+    struct RProc *aref = mrb_proc_new_cfunc_with_env(mrb, mrb_struct_ref, 1, &at);
+    struct RProc *aset = mrb_proc_new_cfunc_with_env(mrb, mrb_struct_set_m, 1, &at);
+    MRB_METHOD_FROM_PROC(m, aref);
+    mrb_define_method_raw(mrb, c, id, m);
+    MRB_METHOD_FROM_PROC(m, aset);
+    mrb_define_method_raw(mrb, c, mrb_id_attrset(mrb, id), m);
+    mrb_gc_arena_restore(mrb, ai);
+  }
+}
+
+static mrb_value
+make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass *klass)
 {
   mrb_value nstr;
@@ -207,11 +203,11 @@
   else {
     /* old style: should we warn? */
-    name = mrb_str_to_str(mrb, name);
+    mrb_to_str(mrb, name);
     id = mrb_obj_to_sym(mrb, name);
-    if (!is_const_id(mrb, mrb_sym2name_len(mrb, id, NULL))) {
-      mrb_name_error(mrb, id, "identifier %S needs to be constant", name);
+    if (!mrb_const_name_p(mrb, RSTRING_PTR(name), RSTRING_LEN(name))) {
+      mrb_name_error(mrb, id, "identifier %v needs to be constant", name);
     }
     if (mrb_const_defined_at(mrb, mrb_obj_value(klass), id)) {
-      mrb_warn(mrb, "redefining constant Struct::%S", name);
+      mrb_warn(mrb, "redefining constant Struct::%v", name);
       mrb_const_remove(mrb, mrb_obj_value(klass), id);
     }
@@ -277,31 +273,36 @@
 
   name = mrb_nil_value();
-  rest = mrb_nil_value();
   mrb_get_args(mrb, "*&", &argv, &argc, &b);
   if (argc == 0) { /* special case to avoid crash */
-    rest = mrb_ary_new(mrb);
+    mrb_argnum_error(mrb, argc, 1, -1);
   }
   else {
-    if (argc > 0) name = argv[0];
-    pargv = &argv[1];
-    argcnt = argc-1;
-    if (!mrb_nil_p(name) && mrb_symbol_p(name)) {
-      /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
-      name = mrb_nil_value();
-      pargv = &argv[0];
-      argcnt++;
+    pargv = argv;
+    argcnt = argc;
+    if (argc > 0) {
+      name = argv[0];
+      if (mrb_symbol_p(name)) {
+        /* 1stArgument:symbol -> name=nil rest=argv[0..n] */
+        name = mrb_nil_value();
+      }
+      else {
+        pargv++;
+        argcnt--;
+      }
     }
     rest = mrb_ary_new_from_values(mrb, argcnt, pargv);
-    for (i=0; i<RARRAY_LEN(rest); i++) {
+    for (i=0; i<argcnt; i++) {
       id = mrb_obj_to_sym(mrb, RARRAY_PTR(rest)[i]);
       mrb_ary_set(mrb, rest, i, mrb_symbol_value(id));
     }
-  }
-  st = make_struct(mrb, name, rest, mrb_class_ptr(klass));
-  if (!mrb_nil_p(b)) {
-    mrb_yield_with_class(mrb, b, 1, &st, st, mrb_class_ptr(st));
-  }
-
-  return st;
+    st = make_struct(mrb, name, rest, mrb_class_ptr(klass));
+    if (!mrb_nil_p(b)) {
+      mrb_yield_with_class(mrb, b, 1, &st, st, mrb_class_ptr(st));
+    }
+
+    return st;
+  }
+  /* not reached */
+  return mrb_nil_value();
 }
 
@@ -347,5 +348,5 @@
   mrb_int argc;
 
-  mrb_get_args(mrb, "*", &argv, &argc);
+  mrb_get_args(mrb, "*!", &argv, &argc);
   return mrb_struct_initialize_withArg(mrb, argc, argv, self);
 }
@@ -388,5 +389,5 @@
     }
   }
-  mrb_raisef(mrb, E_INDEX_ERROR, "'%S' is not a struct member", mrb_sym2str(mrb, id));
+  mrb_name_error(mrb, id, "no member '%n' in struct", id);
   return mrb_nil_value();       /* not reached */
 }
@@ -395,14 +396,13 @@
 struct_aref_int(mrb_state *mrb, mrb_value s, mrb_int i)
 {
-  if (i < 0) i = RSTRUCT_LEN(s) + i;
-  if (i < 0)
-      mrb_raisef(mrb, E_INDEX_ERROR,
-                 "offset %S too small for struct(size:%S)",
-                 mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
-  if (RSTRUCT_LEN(s) <= i)
+  mrb_int idx = i < 0 ? RSTRUCT_LEN(s) + i : i;
+
+  if (idx < 0)
     mrb_raisef(mrb, E_INDEX_ERROR,
-               "offset %S too large for struct(size:%S)",
-               mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
-  return RSTRUCT_PTR(s)[i];
+               "offset %i too small for struct(size:%i)", i, RSTRUCT_LEN(s));
+  if (RSTRUCT_LEN(s) <= idx)
+    mrb_raisef(mrb, E_INDEX_ERROR,
+               "offset %i too large for struct(size:%i)", i, RSTRUCT_LEN(s));
+  return RSTRUCT_PTR(s)[idx];
 }
 
@@ -436,5 +436,5 @@
 
     if (mrb_nil_p(sym)) {
-      mrb_name_error(mrb, mrb_intern_str(mrb, idx), "no member '%S' in struct", idx);
+      mrb_name_error(mrb, mrb_intern_str(mrb, idx), "no member '%v' in struct", idx);
     }
     idx = sym;
@@ -464,5 +464,5 @@
     }
   }
-  mrb_name_error(mrb, id, "no member '%S' in struct", mrb_sym2str(mrb, id));
+  mrb_name_error(mrb, id, "no member '%n' in struct", id);
   return val;                   /* not reach */
 }
@@ -503,5 +503,5 @@
 
     if (mrb_nil_p(sym)) {
-      mrb_name_error(mrb, mrb_intern_str(mrb, idx), "no member '%S' in struct", idx);
+      mrb_name_error(mrb, mrb_intern_str(mrb, idx), "no member '%v' in struct", idx);
     }
     idx = sym;
@@ -515,11 +515,9 @@
   if (i < 0) {
     mrb_raisef(mrb, E_INDEX_ERROR,
-               "offset %S too small for struct(size:%S)",
-               mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
+               "offset %i too small for struct(size:%i)", i, RSTRUCT_LEN(s));
   }
   if (RSTRUCT_LEN(s) <= i) {
     mrb_raisef(mrb, E_INDEX_ERROR,
-               "offset %S too large for struct(size:%S)",
-               mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s)));
+               "offset %i too large for struct(size:%i)", i, RSTRUCT_LEN(s));
   }
   mrb_struct_modify(mrb, s);
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-struct/test/struct.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-struct/test/struct.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-struct/test/struct.rb	(revision 439)
@@ -10,11 +10,4 @@
   assert_equal Struct, c.superclass
   assert_equal [:m1, :m2], c.members
-end
-
-# Check crash bug with Struc.new and no params.
-assert('Struct.new', '15.2.18.3.1') do
-  c = Struct.new()
-  assert_equal Struct, c.superclass
-  assert_equal [], c.members
 end
 
@@ -124,7 +117,8 @@
 
 assert('struct inspect') do
-  c = Struct.new(:m1, :m2, :m3, :m4, :m5)
-  cc = c.new(1,2,3,4,5)
-  assert_equal "#<struct m1=1, m2=2, m3=3, m4=4, m5=5>", cc.inspect
+  c = Struct.new(:m1, :m2, :m3, :m4, :m5, :recur)
+  cc = c.new(1,2,3,4,5,nil)
+  cc.recur = cc
+  assert_equal "#<struct m1=1, m2=2, m3=3, m4=4, m5=5, recur=#<struct #{cc.class}:...>>", cc.inspect
 end
 
@@ -160,12 +154,12 @@
 end
 
-assert("Struct.new removes existing constant") do
-  skip "redefining Struct with same name cause warnings"
-  begin
-    assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b)
-  ensure
-    Struct.remove_const :Test
-  end
-end
+# TODO: suppress redefining Struct warning during test
+# assert("Struct.new removes existing constant") do
+#   begin
+#     assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b)
+#   ensure
+#     Struct.remove_const :Test
+#   end
+# end
 
 assert("Struct#initialize_copy requires struct to be the same type") do
@@ -189,9 +183,13 @@
 end
 
+assert("Struct.new does not allow invalid class name") do
+  assert_raise(NameError) { Struct.new("Test-", :a) }
+end
+
 assert("Struct.new generates subclass of Struct") do
   begin
     original_struct = Struct
     Struct = String
-    assert_equal original_struct, original_struct.new.superclass
+    assert_equal original_struct, original_struct.new(:foo).superclass
   ensure
     Struct = original_struct
@@ -207,6 +205,6 @@
 
   o.freeze
-  assert_raise(RuntimeError) { o.m = :modify }
-  assert_raise(RuntimeError) { o[:m] = :modify }
+  assert_raise(FrozenError) { o.m = :modify }
+  assert_raise(FrozenError) { o[:m] = :modify }
   assert_equal :test, o.m
 end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-symbol-ext/mrblib/symbol.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-symbol-ext/mrblib/symbol.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-symbol-ext/mrblib/symbol.rb	(revision 439)
@@ -3,10 +3,4 @@
 
   alias intern to_sym
-
-  def to_proc
-    ->(obj,*args,&block) do
-      obj.__send__(self, *args, &block)
-    end
-  end
 
   ##
@@ -49,6 +43,19 @@
     return nil unless other.kind_of?(Symbol)
     lhs =  self.to_s; lhs.upcase!
-    rhs = other.to_s; rhs.upcase!
+    rhs = other.to_s.upcase
     lhs <=> rhs
+  end
+
+  ##
+  # call-seq:
+  #   sym.casecmp?(other)  -> true, false, or nil
+  #
+  # Returns true if sym and other_sym are equal after case folding,
+  # false if they are not equal, and nil if other_sym is not a string.
+
+  def casecmp?(sym)
+    c = self.casecmp(sym)
+    return nil if c.nil?
+    return c == 0
   end
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-symbol-ext/src/symbol.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-symbol-ext/src/symbol.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-symbol-ext/src/symbol.c	(revision 439)
@@ -2,9 +2,5 @@
 #include <mruby/khash.h>
 #include <mruby/array.h>
-
-typedef struct symbol_name {
-  size_t len;
-  const char *name;
-} symbol_name;
+#include <mruby/string.h>
 
 /*
@@ -23,4 +19,5 @@
  *                                     :wait2, :$>]
  */
+#ifdef MRB_ENABLE_ALL_SYMBOLS
 static mrb_value
 mrb_sym_all_symbols(mrb_state *mrb, mrb_value self)
@@ -30,9 +27,11 @@
 
   for (i=1, lim=mrb->symidx+1; i<lim; i++) {
-    mrb_ary_push(mrb, ary, mrb_symbol_value(i));
+    mrb_sym sym = i<<1;
+    mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
   }
 
   return ary;
 }
+#endif
 
 /*
@@ -46,5 +45,11 @@
 {
   mrb_int len;
-  mrb_sym2name_len(mrb, mrb_symbol(self), &len);
+#ifdef MRB_UTF8_STRING
+  mrb_int byte_len;
+  const char *name = mrb_sym_name_len(mrb, mrb_symbol(self), &byte_len);
+  len = mrb_utf8_strlen(name, byte_len);
+#else
+  mrb_sym_name_len(mrb, mrb_symbol(self), &len);
+#endif
   return mrb_fixnum_value(len);
 }
@@ -54,5 +59,7 @@
 {
   struct RClass *s = mrb->symbol_class;
+#ifdef MRB_ENABLE_ALL_SYMBOLS
   mrb_define_class_method(mrb, s, "all_symbols", mrb_sym_all_symbols, MRB_ARGS_NONE());
+#endif
   mrb_define_method(mrb, s, "length", mrb_sym_length, MRB_ARGS_NONE());
   mrb_define_method(mrb, s, "size", mrb_sym_length, MRB_ARGS_NONE());
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-symbol-ext/test/symbol.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-symbol-ext/test/symbol.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-symbol-ext/test/symbol.rb	(revision 439)
@@ -1,18 +1,26 @@
+# coding: utf-8
 ##
 # Symbol(Ext) Test
 
-assert('Symbol#to_proc') do
-  assert_equal 5, :abs.to_proc[-5]
+if Symbol.respond_to?(:all_symbols)
+  assert('Symbol.all_symbols') do
+    foo = [:__symbol_test_1, :__symbol_test_2, :__symbol_test_3].sort
+    symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort
+    assert_equal foo, symbols
+  end
 end
 
-assert('Symbol.all_symbols') do
-  foo = [:__symbol_test_1, :__symbol_test_2, :__symbol_test_3].sort
-  symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort
-  assert_equal foo, symbols
-end
-
-assert("Symbol#length") do
-  assert_equal 5, :hello.size
-  assert_equal 5, :mruby.length
+%w[size length].each do |n|
+  assert("Symbol##{n}") do
+    assert_equal 5, :hello.__send__(n)
+    assert_equal 4, :"aA\0b".__send__(n)
+    if __ENCODING__ == "UTF-8"
+      assert_equal 8, :"こんにちは世界!".__send__(n)
+      assert_equal 4, :"aあ\0b".__send__(n)
+    else
+      assert_equal 22, :"こんにちは世界!".__send__(n)
+      assert_equal 6, :"aあ\0b".__send__(n)
+    end
+  end
 end
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-test/README.md
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-test/README.md	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-test/README.md	(revision 439)
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-test/driver.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-test/driver.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-test/driver.c	(revision 439)
@@ -19,6 +19,8 @@
 #include <mruby/array.h>
 
-void
-mrb_init_mrbtest(mrb_state *);
+extern const uint8_t mrbtest_assert_irep[];
+
+void mrbgemtest_init(mrb_state* mrb);
+void mrb_init_test_vformat(mrb_state* mrb);
 
 /* Print a short remark for the user */
@@ -30,19 +32,8 @@
 
 static int
-check_error(mrb_state *mrb)
-{
-  /* Error check */
-  /* $ko_test and $kill_test should be 0 */
-  mrb_value ko_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$ko_test"));
-  mrb_value kill_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$kill_test"));
-
-  return mrb_fixnum_p(ko_test) && mrb_fixnum(ko_test) == 0 && mrb_fixnum_p(kill_test) && mrb_fixnum(kill_test) == 0;
-}
-
-static int
 eval_test(mrb_state *mrb)
 {
   /* evaluate the test */
-  mrb_funcall(mrb, mrb_top_self(mrb), "report", 0);
+  mrb_value result = mrb_funcall(mrb, mrb_top_self(mrb), "report", 0);
   /* did an exception occur? */
   if (mrb->exc) {
@@ -51,32 +42,170 @@
     return EXIT_FAILURE;
   }
-  else if (!check_error(mrb)) {
-    return EXIT_FAILURE;
-  }
-  return EXIT_SUCCESS;
-}
-
-static void
-t_printstr(mrb_state *mrb, mrb_value obj)
-{
-  char *s;
-  int len;
-
-  if (mrb_string_p(obj)) {
-    s = RSTRING_PTR(obj);
-    len = RSTRING_LEN(obj);
-    fwrite(s, len, 1, stdout);
-  }
-}
-
-mrb_value
-mrb_t_printstr(mrb_state *mrb, mrb_value self)
-{
-  mrb_value argv;
-
-  mrb_get_args(mrb, "o", &argv);
-  t_printstr(mrb, argv);
-
-  return argv;
+  else {
+    return mrb_bool(result) ? EXIT_SUCCESS : EXIT_FAILURE;
+  }
+}
+
+/* Implementation of print due to the reason that there might be no print */
+static mrb_value
+t_print(mrb_state *mrb, mrb_value self)
+{
+  mrb_value *argv;
+  mrb_int argc;
+  mrb_int i;
+
+  mrb_get_args(mrb, "*!", &argv, &argc);
+  for (i = 0; i < argc; ++i) {
+    mrb_value s = mrb_obj_as_string(mrb, argv[i]);
+    fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stdout);
+  }
+  fflush(stdout);
+
+  return mrb_nil_value();
+}
+
+#define UNESCAPE(p, endp) ((p) != (endp) && *(p) == '\\' ? (p)+1 : (p))
+#define CHAR_CMP(c1, c2) ((unsigned char)(c1) - (unsigned char)(c2))
+
+static const char *
+str_match_bracket(const char *p, const char *pat_end,
+                  const char *s, const char *str_end)
+{
+  mrb_bool ok = FALSE, negated = FALSE;
+
+  if (p == pat_end) return NULL;
+  if (*p == '!' || *p == '^') {
+    negated = TRUE;
+    ++p;
+  }
+
+  while (*p != ']') {
+    const char *t1 = p;
+    if ((t1 = UNESCAPE(t1, pat_end)) == pat_end) return NULL;
+    if ((p = t1 + 1) == pat_end) return NULL;
+    if (p[0] == '-' && p[1] != ']') {
+      const char *t2 = p + 1;
+      if ((t2 = UNESCAPE(t2, pat_end)) == pat_end) return NULL;
+      p = t2 + 1;
+      if (!ok && CHAR_CMP(*t1, *s) <= 0 && CHAR_CMP(*s, *t2) <= 0) ok = TRUE;
+    }
+    else {
+      if (!ok && CHAR_CMP(*t1, *s) == 0) ok = TRUE;
+    }
+  }
+
+  return ok == negated ? NULL : p + 1;
+}
+
+static mrb_bool
+str_match_no_brace_p(const char *pat, mrb_int pat_len,
+                     const char *str, mrb_int str_len)
+{
+  const char *p = pat, *s = str;
+  const char *pat_end = pat + pat_len, *str_end = str + str_len;
+  const char *p_tmp = NULL, *s_tmp = NULL;
+
+  for (;;) {
+    if (p == pat_end) return s == str_end;
+    switch (*p) {
+      case '*':
+        do { ++p; } while (p != pat_end && *p == '*');
+        if (UNESCAPE(p, pat_end) == pat_end) return TRUE;
+        if (s == str_end) return FALSE;
+        p_tmp = p;
+        s_tmp = s;
+        continue;
+      case '?':
+        if (s == str_end) return FALSE;
+        ++p;
+        ++s;
+        continue;
+      case '[': {
+        const char *t;
+        if (s == str_end) return FALSE;
+        if ((t = str_match_bracket(p+1, pat_end, s, str_end))) {
+          p = t;
+          ++s;
+          continue;
+        }
+        goto L_failed;
+      }
+    }
+
+    /* ordinary */
+    p = UNESCAPE(p, pat_end);
+    if (s == str_end) return p == pat_end;
+    if (p == pat_end) goto L_failed;
+    if (*p++ != *s++) goto L_failed;
+    continue;
+
+    L_failed:
+    if (p_tmp && s_tmp) {
+      /* try next '*' position */
+      p = p_tmp;
+      s = ++s_tmp;
+      continue;
+    }
+
+    return FALSE;
+  }
+}
+
+#define COPY_AND_INC(dst, src, len) \
+  do { memcpy(dst, src, len); dst += len; } while (0)
+
+static mrb_bool
+str_match_p(mrb_state *mrb,
+            const char *pat, mrb_int pat_len,
+            const char *str, mrb_int str_len)
+{
+  const char *p = pat, *pat_end = pat + pat_len;
+  const char *lbrace = NULL, *rbrace = NULL;
+  int nest = 0;
+  mrb_bool ret = FALSE;
+
+  for (; p != pat_end; ++p) {
+    if (*p == '{' && nest++ == 0) lbrace = p;
+    else if (*p == '}' && lbrace && --nest == 0) { rbrace = p; break; }
+    else if (*p == '\\' && ++p == pat_end) break;
+  }
+
+  if (lbrace && rbrace) {
+    /* expand brace */
+    char *ex_pat = (char *)mrb_malloc(mrb, pat_len-2);  /* expanded pattern */
+    char *ex_p = ex_pat;
+
+    COPY_AND_INC(ex_p, pat, lbrace-pat);
+    p = lbrace;
+    while (p < rbrace) {
+      char *orig_ex_p = ex_p;
+      const char *t = ++p;
+      for (nest = 0; p < rbrace && !(*p == ',' && nest == 0); ++p) {
+        if (*p == '{') ++nest;
+        else if (*p == '}') --nest;
+        else if (*p == '\\' && ++p == rbrace) break;
+      }
+      COPY_AND_INC(ex_p, t, p-t);
+      COPY_AND_INC(ex_p, rbrace+1, pat_end-rbrace-1);
+      if ((ret = str_match_p(mrb, ex_pat, ex_p-ex_pat, str, str_len))) break;
+      ex_p = orig_ex_p;
+    }
+    mrb_free(mrb, ex_pat);
+  }
+  else if (!lbrace && !rbrace) {
+    ret = str_match_no_brace_p(pat, pat_len, str, str_len);
+  }
+
+  return ret;
+}
+
+static mrb_value
+m_str_match_p(mrb_state *mrb, mrb_value self)
+{
+  const char *pat, *str;
+  mrb_int pat_len, str_len;
+
+  mrb_get_args(mrb, "ss", &pat, &pat_len, &str, &str_len);
+  return mrb_bool_value(str_match_p(mrb, pat, pat_len, str, str_len));
 }
 
@@ -87,5 +216,6 @@
 
   krn = mrb->kernel_module;
-  mrb_define_method(mrb, krn, "__t_printstr__", mrb_t_printstr, MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, krn, "t_print", t_print, MRB_ARGS_ANY());
+  mrb_define_method(mrb, krn, "_str_match?", m_str_match_p, MRB_ARGS_REQ(2));
 
   mrbtest = mrb_define_module(mrb, "Mrbtest");
@@ -95,4 +225,5 @@
   mrb_define_const(mrb, mrbtest, "FIXNUM_BIT", mrb_fixnum_value(MRB_INT_BIT));
 
+#ifndef MRB_WITHOUT_FLOAT
 #ifdef MRB_USE_FLOAT
   mrb_define_const(mrb, mrbtest, "FLOAT_TOLERANCE", mrb_float_value(mrb, 1e-6));
@@ -100,4 +231,7 @@
   mrb_define_const(mrb, mrbtest, "FLOAT_TOLERANCE", mrb_float_value(mrb, 1e-12));
 #endif
+#endif
+
+  mrb_init_test_vformat(mrb);
 
   if (verbose) {
@@ -128,4 +262,6 @@
   TEST_COUNT_PASS(ko_test);
   TEST_COUNT_PASS(kill_test);
+  TEST_COUNT_PASS(warning_test);
+  TEST_COUNT_PASS(skip_test);
 
 #undef TEST_COUNT_PASS
@@ -165,5 +301,6 @@
 
   mrb_init_test_driver(mrb, verbose);
-  mrb_init_mrbtest(mrb);
+  mrb_load_irep(mrb, mrbtest_assert_irep);
+  mrbgemtest_init(mrb);
   ret = eval_test(mrb);
   mrb_close(mrb);
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-test/init_mrbtest.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-test/init_mrbtest.c	(revision 331)
+++ 	(revision )
@@ -1,38 +1,0 @@
-#include <stdlib.h>
-#include <mruby.h>
-#include <mruby/irep.h>
-#include <mruby/variable.h>
-
-extern const uint8_t mrbtest_assert_irep[];
-
-void mrbgemtest_init(mrb_state* mrb);
-void mrb_init_test_driver(mrb_state* mrb, mrb_bool verbose);
-void mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src);
-
-void
-mrb_init_mrbtest(mrb_state *mrb)
-{
-  mrb_state *core_test;
-
-  mrb_load_irep(mrb, mrbtest_assert_irep);
-
-  core_test = mrb_open_core(mrb_default_allocf, NULL);
-  if (core_test == NULL) {
-    fprintf(stderr, "Invalid mrb_state, exiting %s", __FUNCTION__);
-    exit(EXIT_FAILURE);
-  }
-  mrb_init_test_driver(core_test, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"))));
-  mrb_load_irep(core_test, mrbtest_assert_irep);
-  mrb_t_pass_result(mrb, core_test);
-
-#ifndef DISABLE_GEMS
-  mrbgemtest_init(mrb);
-#endif
-
-  if (mrb->exc) {
-    mrb_print_error(mrb);
-    exit(EXIT_FAILURE);
-  }
-  mrb_close(core_test);
-}
-
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-test/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-test/mrbgem.rake	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-test/mrbgem.rake	(revision 439)
@@ -13,12 +13,10 @@
   exec = exefile("#{build.build_dir}/bin/mrbtest")
 
-  libmruby = libfile("#{build.build_dir}/lib/libmruby")
-  libmruby_core = libfile("#{build.build_dir}/lib/libmruby_core")
-
   mrbtest_lib = libfile("#{build_dir}/mrbtest")
   mrbtest_objs = []
 
-  driver_obj = objfile("#{build_dir}/driver")
-  driver = "#{spec.dir}/driver.c"
+  driver_objs = Dir.glob("#{dir}/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f|
+    objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X"))
+  end
 
   assert_c = "#{build_dir}/assert.c"
@@ -28,5 +26,5 @@
 
   file assert_lib => assert_c
-  file assert_c => assert_rb do |t|
+  file assert_c => [assert_rb, build.mrbcfile] do |t|
     open(t.name, 'w') do |f|
       mrbc.run f, assert_rb, 'mrbtest_assert_irep'
@@ -42,6 +40,6 @@
 
     file test_rbobj => g.test_rbireps
-    file g.test_rbireps => [g.test_rbfiles].flatten do |t|
-      FileUtils.mkdir_p File.dirname(t.name)
+    file g.test_rbireps => [g.test_rbfiles, build.mrbcfile].flatten do |t|
+      mkdir_p File.dirname(t.name)
       open(t.name, 'w') do |f|
         g.print_gem_test_header(f)
@@ -98,4 +96,5 @@
             f.puts %Q[  if (mrb2->exc) {]
             f.puts %Q[    mrb_print_error(mrb2);]
+            f.puts %Q[    mrb_close(mrb2);]
             f.puts %Q[    exit(EXIT_FAILURE);]
             f.puts %Q[  }]
@@ -136,5 +135,5 @@
 
   unless build.build_mrbtest_lib_only?
-    file exec => [driver_obj, mlib, mrbtest_lib, libmruby_core, libmruby] do |t|
+    file exec => [*driver_objs, mlib, mrbtest_lib, build.libmruby_static] do |t|
       gem_flags = build.gems.map { |g| g.linker.flags }
       gem_flags_before_libraries = build.gems.map { |g| g.linker.flags_before_libraries }
@@ -142,26 +141,25 @@
       gem_libraries = build.gems.map { |g| g.linker.libraries }
       gem_library_paths = build.gems.map { |g| g.linker.library_paths }
-      build.linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, gem_flags_before_libraries
+      build.linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags,
+                       gem_flags_before_libraries, gem_flags_after_libraries
     end
   end
-
-  init = "#{spec.dir}/init_mrbtest.c"
 
   # store the last gem selection and make the re-build
   # of the test gem depending on a change to the gem
   # selection
-  active_gems = "#{build_dir}/active_gems.lst"
-  FileUtils.mkdir_p File.dirname(active_gems)
-  open(active_gems, 'w+') do |f|
-    build.gems.each do |g|
-      f.puts g.name
-    end
+  active_gems_path = "#{build_dir}/active_gems_path.lst"
+  active_gem_list = File.read active_gems_path if File.exist? active_gems_path
+  current_gem_list = build.gems.map(&:name).join("\n")
+  task active_gems_path do |_t|
+    mkdir_p File.dirname(active_gems_path)
+    File.write active_gems_path, current_gem_list
   end
-  file clib => active_gems
+  file clib => active_gems_path if active_gem_list != current_gem_list
 
   file mlib => clib
-  file clib => init do |t|
+  file clib => [build.mrbcfile, __FILE__] do |_t|
     _pp "GEN", "*.rb", "#{clib.relative_path}"
-    FileUtils.mkdir_p File.dirname(clib)
+    mkdir_p File.dirname(clib)
     open(clib, 'w') do |f|
       f.puts %Q[/*]
@@ -174,5 +172,6 @@
       f.puts %Q[ */]
       f.puts %Q[]
-      f.puts IO.read(init)
+      f.puts %Q[struct mrb_state;]
+      f.puts %Q[typedef struct mrb_state mrb_state;]
       build.gems.each do |g|
         f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);]
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-test/vformat.c
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-test/vformat.c	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-test/vformat.c	(revision 439)
@@ -0,0 +1,179 @@
+#include <string.h>
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/string.h>
+
+/* no argument */
+static mrb_value
+vf_s_format_0(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value fmt_str;
+  const char *fmt;
+
+  mrb_get_args(mrb, "S", &fmt_str);
+  fmt = RSTRING_CSTR(mrb, fmt_str);
+
+  return mrb_format(mrb, fmt);
+}
+
+/* c char */
+static mrb_value
+vf_s_format_c(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value fmt_str, arg_str;
+  const char *fmt;
+  char c;
+  
+  mrb_get_args(mrb, "SS", &fmt_str, &arg_str);
+  fmt = RSTRING_CSTR(mrb, fmt_str);
+  c = RSTRING_CSTR(mrb, arg_str)[0];
+
+  return mrb_format(mrb, fmt, c);
+}
+
+/* d int */
+static mrb_value
+vf_s_format_d(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value fmt_str;
+  const char *fmt;
+  mrb_int i;
+  int d;
+
+  mrb_get_args(mrb, "Si", &fmt_str, &i);
+  fmt = RSTRING_CSTR(mrb, fmt_str);
+  d = (int)i;
+
+  return mrb_format(mrb, fmt, d);
+}
+
+#ifndef MRB_WITHOUT_FLOAT
+/* f float */
+static mrb_value
+vf_s_format_f(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value fmt_str;
+  const char *fmt;
+  mrb_float f;
+
+  mrb_get_args(mrb, "Sf", &fmt_str, &f);
+  fmt = RSTRING_CSTR(mrb, fmt_str);
+
+  return mrb_format(mrb, fmt, f);
+}
+#endif
+
+/* i fixnum */
+static mrb_value
+vf_s_format_i(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value fmt_str;
+  const char *fmt;
+  mrb_int i;
+
+  mrb_get_args(mrb, "Si", &fmt_str, &i);
+  fmt = RSTRING_CSTR(mrb, fmt_str);
+
+  return mrb_format(mrb, fmt, i);
+}
+
+/* l char*, size_t */
+static mrb_value
+vf_s_format_l(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value fmt_str, arg_str;
+  const char *fmt;
+  const char *s;
+  mrb_int i;
+  size_t len;
+
+  mrb_get_args(mrb, "SSi", &fmt_str, &arg_str, &i);
+  fmt = RSTRING_CSTR(mrb, fmt_str);
+  s = RSTRING_PTR(arg_str);
+  len = (size_t)i;
+  if (len > (size_t)RSTRING_LEN(arg_str)) len = (size_t)RSTRING_LEN(arg_str);
+
+  return mrb_format(mrb, fmt, s, len);
+}
+
+/* n symbol */
+static mrb_value
+vf_s_format_n(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value fmt_str;
+  const char *fmt;
+  mrb_sym sym;
+
+  mrb_get_args(mrb, "Sn", &fmt_str, &sym);
+  fmt = RSTRING_CSTR(mrb, fmt_str);
+
+  return mrb_format(mrb, fmt, sym);
+}
+
+/* s char* */
+static mrb_value
+vf_s_format_s(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value fmt_str, arg_str;
+  const char *fmt;
+  const char *s;
+
+  mrb_get_args(mrb, "SS", &fmt_str, &arg_str);
+  fmt = RSTRING_CSTR(mrb, fmt_str);
+  s = RSTRING_CSTR(mrb, arg_str);
+
+  return mrb_format(mrb, fmt, s);
+}
+
+/* C RClass */
+static mrb_value
+vf_s_format_C(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value fmt_str, arg_cls;
+  const char *fmt;
+  struct RClass *c;
+
+  mrb_get_args(mrb, "SC", &fmt_str, &arg_cls);
+  fmt = RSTRING_CSTR(mrb, fmt_str);
+  c = mrb_class_ptr(arg_cls);
+
+  return mrb_format(mrb, fmt, c);
+}
+
+/* v value */
+static mrb_value
+vf_s_format_v(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value fmt_str, arg_v;
+  const char *fmt;
+
+  mrb_get_args(mrb, "So", &fmt_str, &arg_v);
+  fmt = RSTRING_CSTR(mrb, fmt_str);
+
+  return mrb_format(mrb, fmt, arg_v);
+}
+
+void
+mrb_init_test_vformat(mrb_state *mrb)
+{
+  struct RClass *vf;
+
+  vf = mrb_define_module(mrb, "TestVFormat");
+  mrb_define_class_method(mrb, vf, "z", vf_s_format_0, MRB_ARGS_REQ(1));
+
+#define VF_DEFINE_FORMAT_METHOD(t) VF_DEFINE_FORMAT_METHOD_n(t,2)
+#define VF_DEFINE_FORMAT_METHOD_n(t,n) mrb_define_class_method(mrb, vf, #t, vf_s_format_##t, MRB_ARGS_REQ(n));
+  
+  VF_DEFINE_FORMAT_METHOD(c);
+  VF_DEFINE_FORMAT_METHOD(d);
+#ifndef MRB_WITHOUT_FLOAT
+  VF_DEFINE_FORMAT_METHOD(f);
+#endif
+  VF_DEFINE_FORMAT_METHOD(i);
+  VF_DEFINE_FORMAT_METHOD_n(l,3);
+  VF_DEFINE_FORMAT_METHOD(n);
+  VF_DEFINE_FORMAT_METHOD(s);
+  VF_DEFINE_FORMAT_METHOD(C);
+  VF_DEFINE_FORMAT_METHOD(v);
+}
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-time/include/mruby/time.h
===================================================================
--- EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-time/include/mruby/time.h	(revision 439)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-time/include/mruby/time.h	(revision 439)
@@ -0,0 +1,26 @@
+/*
+** mruby/time.h - Time class
+**
+** See Copyright Notice in mruby.h
+*/
+
+#ifndef MRUBY_TIME_H
+#define MRUBY_TIME_H
+
+#include "mruby/common.h"
+#include <time.h>
+
+MRB_BEGIN_DECL
+
+typedef enum mrb_timezone {
+  MRB_TIMEZONE_NONE   = 0,
+  MRB_TIMEZONE_UTC    = 1,
+  MRB_TIMEZONE_LOCAL  = 2,
+  MRB_TIMEZONE_LAST   = 3
+} mrb_timezone;
+
+MRB_API mrb_value mrb_time_at(mrb_state *mrb, time_t sec, time_t usec, mrb_timezone timezone);
+
+MRB_END_DECL
+
+#endif /* MRUBY_TIME_H */
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-time/src/time.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-time/src/time.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-time/src/time.c	(revision 439)
@@ -5,31 +5,33 @@
 */
 
+#ifndef MRB_WITHOUT_FLOAT
 #include <math.h>
-#include <time.h>
+#endif
+
 #include <mruby.h>
 #include <mruby/class.h>
 #include <mruby/data.h>
-
-#ifndef DISABLE_STDIO
-#include <stdio.h>
-#else
+#include <mruby/numeric.h>
+#include <mruby/time.h>
+
+#ifdef MRB_DISABLE_STDIO
 #include <string.h>
 #endif
 
+#include <stdlib.h>
+
 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
-
-#if _MSC_VER < 1800
+#define TO_S_FMT "%Y-%m-%d %H:%M:%S "
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
 double round(double x) {
-  if (x >= 0.0) {
-    return (double)((int)(x + 0.5));
-  }
-  else {
-    return (double)((int)(x - 0.5));
-  }
-}
-#endif
-
-#if !defined(__MINGW64__) && defined(_WIN32)
-# define llround(x) round(x)
+  return floor(x + 0.5);
+}
+#endif
+
+#ifndef MRB_WITHOUT_FLOAT
+# if !defined(__MINGW64__) && defined(_WIN32)
+#  define llround(x) round(x)
+# endif
 #endif
 
@@ -52,5 +54,5 @@
 
 #ifdef _WIN32
-#if _MSC_VER
+#ifdef _MSC_VER
 /* Win32 platform do not provide gmtime_r/localtime_r; emulate them using gmtime_s/localtime_s */
 #define gmtime_r(tp, tm)    ((gmtime_s((tm), (tp)) == 0) ? (tm) : NULL)
@@ -144,6 +146,12 @@
   unsigned int *nday = (unsigned int*) ndays[is_leapyear(tm->tm_year+1900)];
 
-  for (i = 70; i < tm->tm_year; ++i)
-    r += is_leapyear(i+1900) ? 366*24*60*60 : 365*24*60*60;
+  static const int epoch_year = 70;
+  if(tm->tm_year >= epoch_year) {
+    for (i = epoch_year; i < tm->tm_year; ++i)
+      r += is_leapyear(i+1900) ? 366*24*60*60 : 365*24*60*60;
+  } else {
+    for (i = tm->tm_year; i < epoch_year; ++i)
+      r -= is_leapyear(i+1900) ? 366*24*60*60 : 365*24*60*60;
+  }
   for (i = 0; i < tm->tm_mon; ++i)
     r += nday[i] * 24 * 60 * 60;
@@ -161,11 +169,4 @@
 */
 
-enum mrb_timezone {
-  MRB_TIMEZONE_NONE   = 0,
-  MRB_TIMEZONE_UTC    = 1,
-  MRB_TIMEZONE_LOCAL  = 2,
-  MRB_TIMEZONE_LAST   = 3
-};
-
 typedef struct mrb_timezone_name {
   const char name[8];
@@ -179,5 +180,5 @@
 };
 
-#ifndef DISABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
 static const char mon_names[12][4] = {
   "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
@@ -198,19 +199,102 @@
 static const struct mrb_data_type mrb_time_type = { "Time", mrb_free };
 
+#ifndef MRB_WITHOUT_FLOAT
+void mrb_check_num_exact(mrb_state *mrb, mrb_float num);
+typedef mrb_float mrb_sec;
+#define mrb_sec_value(mrb, sec) mrb_float_value(mrb, sec)
+#else
+typedef mrb_int mrb_sec;
+#define mrb_sec_value(mrb, sec) mrb_fixnum_value(sec)
+#endif
+
+#define MRB_TIME_T_UINT (~(time_t)0 > 0)
+#define MRB_TIME_MIN (                                                      \
+  MRB_TIME_T_UINT ? 0 :                                                     \
+                    (sizeof(time_t) <= 4 ? INT32_MIN : INT64_MIN)           \
+)
+#define MRB_TIME_MAX (                                                      \
+  MRB_TIME_T_UINT ? (sizeof(time_t) <= 4 ? UINT32_MAX : UINT64_MAX) :       \
+                    (sizeof(time_t) <= 4 ? INT32_MAX : INT64_MAX)           \
+)
+
+static mrb_bool
+fixable_time_t_p(time_t v)
+{
+  if (MRB_INT_MIN <= MRB_TIME_MIN && MRB_TIME_MAX <= MRB_INT_MAX) return TRUE;
+  return FIXABLE(v);
+}
+
+static time_t
+mrb_to_time_t(mrb_state *mrb, mrb_value obj, time_t *usec)
+{
+  time_t t;
+
+  switch (mrb_type(obj)) {
+#ifndef MRB_WITHOUT_FLOAT
+    case MRB_TT_FLOAT:
+      {
+        mrb_float f = mrb_float(obj);
+
+        mrb_check_num_exact(mrb, f);
+        if (f >= ((mrb_float)MRB_TIME_MAX-1.0) || f < ((mrb_float)MRB_TIME_MIN+1.0)) {
+          goto out_of_range;
+        }
+
+        if (usec) {
+          t = (time_t)f;
+          *usec = (time_t)llround((f - t) * 1.0e+6);
+        }
+        else {
+          t = (time_t)llround(f);
+        }
+      }
+      break;
+#endif /* MRB_WITHOUT_FLOAT */
+    default:
+    case MRB_TT_FIXNUM:
+      {
+        mrb_int i = mrb_int(mrb, obj);
+
+        if ((MRB_INT_MAX > MRB_TIME_MAX && i > 0 && i > (mrb_int)MRB_TIME_MAX) ||
+            (MRB_TIME_MIN > MRB_INT_MIN && MRB_TIME_MIN > i)) {
+          goto out_of_range;
+        }
+
+        t = (time_t)i;
+        if (usec) { *usec = 0; }
+      }
+      break;
+  }
+
+  return t;
+
+out_of_range:
+  mrb_raisef(mrb, E_ARGUMENT_ERROR, "%v out of Time range", obj);
+
+  /* not reached */
+  if (usec) { *usec = 0; }
+  return 0;
+}
+
 /** Updates the datetime of a mrb_time based on it's timezone and
-seconds setting. Returns self on success, NULL of failure. */
+    seconds setting. Returns self on success, NULL of failure.
+    if `dealloc` is set `true`, it frees `self` on error. */
 static struct mrb_time*
-time_update_datetime(mrb_state *mrb, struct mrb_time *self)
+time_update_datetime(mrb_state *mrb, struct mrb_time *self, int dealloc)
 {
   struct tm *aid;
+  time_t t = self->sec;
 
   if (self->timezone == MRB_TIMEZONE_UTC) {
-    aid = gmtime_r(&self->sec, &self->datetime);
+    aid = gmtime_r(&t, &self->datetime);
   }
   else {
-    aid = localtime_r(&self->sec, &self->datetime);
+    aid = localtime_r(&t, &self->datetime);
   }
   if (!aid) {
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, (mrb_float)self->sec));
+    mrb_sec sec = (mrb_sec)t;
+
+    if (dealloc) mrb_free(mrb, self);
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "%v out of Time range", mrb_sec_value(mrb, sec));
     /* not reached */
     return NULL;
@@ -229,48 +313,48 @@
 }
 
-void mrb_check_num_exact(mrb_state *mrb, mrb_float num);
-
 /* Allocates a mrb_time object and initializes it. */
 static struct mrb_time*
-time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone)
-{
-  struct mrb_time *tm;
-  time_t tsec = 0;
-
-  mrb_check_num_exact(mrb, (mrb_float)sec);
-  mrb_check_num_exact(mrb, (mrb_float)usec);
-
-  if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) {
-    goto out_of_range;
-  }
-  if (sizeof(time_t) == 8 && (sec > (double)INT64_MAX || (double)INT64_MIN > sec)) {
-    goto out_of_range;
-  }
-  tsec  = (time_t)sec;
-  if ((sec > 0 && tsec < 0) || (sec < 0 && (double)tsec > sec)) {
-  out_of_range:
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec));
-  }
+time_alloc_time(mrb_state *mrb, time_t sec, time_t usec, enum mrb_timezone timezone)
+{
+  struct mrb_time *tm;
+
   tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time));
-  tm->sec  = tsec;
-  tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec);
+  tm->sec  = sec;
+  tm->usec = usec;
   if (tm->usec < 0) {
-    long sec2 = (long)NDIV(usec,1000000); /* negative div */
+    long sec2 = (long)NDIV(tm->usec,1000000); /* negative div */
     tm->usec -= sec2 * 1000000;
     tm->sec += sec2;
   }
   else if (tm->usec >= 1000000) {
-    long sec2 = (long)(usec / 1000000);
+    long sec2 = (long)(tm->usec / 1000000);
     tm->usec -= sec2 * 1000000;
     tm->sec += sec2;
   }
   tm->timezone = timezone;
-  time_update_datetime(mrb, tm);
+  time_update_datetime(mrb, tm, TRUE);
 
   return tm;
 }
 
-static mrb_value
-mrb_time_make(mrb_state *mrb, struct RClass *c, double sec, double usec, enum mrb_timezone timezone)
+static struct mrb_time*
+time_alloc(mrb_state *mrb, mrb_value sec, mrb_value usec, enum mrb_timezone timezone)
+{
+  time_t tsec, tusec;
+
+  tsec = mrb_to_time_t(mrb, sec, &tusec);
+  tusec += mrb_to_time_t(mrb, usec, NULL);
+
+  return time_alloc_time(mrb, tsec, tusec, timezone);
+}
+
+static mrb_value
+mrb_time_make_time(mrb_state *mrb, struct RClass *c, time_t sec, time_t usec, enum mrb_timezone timezone)
+{
+  return mrb_time_wrap(mrb, c, time_alloc_time(mrb, sec, usec, timezone));
+}
+
+static mrb_value
+mrb_time_make(mrb_state *mrb, struct RClass *c, mrb_value sec, mrb_value usec, enum mrb_timezone timezone)
 {
   return mrb_time_wrap(mrb, c, time_alloc(mrb, sec, usec, timezone));
@@ -280,16 +364,16 @@
 current_mrb_time(mrb_state *mrb)
 {
-  struct mrb_time *tm;
-
-  tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
-#if defined(TIME_UTC)
+  struct mrb_time tmzero = {0};
+  struct mrb_time *tm;
+  time_t sec, usec;
+
+#if defined(TIME_UTC) && !defined(__ANDROID__)
   {
     struct timespec ts;
     if (timespec_get(&ts, TIME_UTC) == 0) {
-      mrb_free(mrb, tm);
       mrb_raise(mrb, E_RUNTIME_ERROR, "timespec_get() failed for unknown reasons");
     }
-    tm->sec = ts.tv_sec;
-    tm->usec = ts.tv_nsec / 1000;
+    sec = ts.tv_sec;
+    usec = ts.tv_nsec / 1000;
   }
 #elif defined(NO_GETTIMEOFDAY)
@@ -297,7 +381,7 @@
     static time_t last_sec = 0, last_usec = 0;
 
-    tm->sec  = time(NULL);
-    if (tm->sec != last_sec) {
-      last_sec = tm->sec;
+    sec = time(NULL);
+    if (sec != last_sec) {
+      last_sec = sec;
       last_usec = 0;
     }
@@ -306,5 +390,5 @@
       last_usec += 1;
     }
-    tm->usec = last_usec;
+    usec = last_usec;
   }
 #else
@@ -313,10 +397,13 @@
 
     gettimeofday(&tv, NULL);
-    tm->sec = tv.tv_sec;
-    tm->usec = tv.tv_usec;
-  }
-#endif
+    sec = tv.tv_sec;
+    usec = tv.tv_usec;
+  }
+#endif
+  tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
+  *tm = tmzero;
+  tm->sec = sec; tm->usec = usec;
   tm->timezone = MRB_TIMEZONE_LOCAL;
-  time_update_datetime(mrb, tm);
+  time_update_datetime(mrb, tm, TRUE);
 
   return tm;
@@ -328,4 +415,10 @@
 {
   return mrb_time_wrap(mrb, mrb_class_ptr(self), current_mrb_time(mrb));
+}
+
+MRB_API mrb_value
+mrb_time_at(mrb_state *mrb, time_t sec, time_t usec, enum mrb_timezone zone)
+{
+  return mrb_time_make_time(mrb, mrb_class_get(mrb, "Time"), sec, usec, zone);
 }
 
@@ -333,10 +426,12 @@
 /* Creates an instance of time at the given time in seconds, etc. */
 static mrb_value
-mrb_time_at(mrb_state *mrb, mrb_value self)
-{
-  mrb_float f, f2 = 0;
-
-  mrb_get_args(mrb, "f|f", &f, &f2);
-  return mrb_time_make(mrb, mrb_class_ptr(self), f, f2, MRB_TIMEZONE_LOCAL);
+mrb_time_at_m(mrb_state *mrb, mrb_value self)
+{
+  mrb_value sec;
+  mrb_value usec = mrb_fixnum_value(0);
+
+  mrb_get_args(mrb, "o|o", &sec, &usec);
+
+  return mrb_time_make(mrb, mrb_class_ptr(self), sec, usec, MRB_TIMEZONE_LOCAL);
 }
 
@@ -375,5 +470,5 @@
   }
 
-  return time_alloc(mrb, (double)nowsecs, ausec, timezone);
+  return time_alloc_time(mrb, nowsecs, ausec, timezone);
 }
 
@@ -461,10 +556,12 @@
 mrb_time_plus(mrb_state *mrb, mrb_value self)
 {
-  mrb_float f;
-  struct mrb_time *tm;
-
-  mrb_get_args(mrb, "f", &f);
-  tm = time_get_ptr(mrb, self);
-  return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec+f, (double)tm->usec, tm->timezone);
+  mrb_value o;
+  struct mrb_time *tm;
+  time_t sec, usec;
+
+  mrb_get_args(mrb, "o", &o);
+  tm = time_get_ptr(mrb, self);
+  sec = mrb_to_time_t(mrb, o, &usec);
+  return mrb_time_make_time(mrb, mrb_obj_class(mrb, self), tm->sec+sec, tm->usec+usec, tm->timezone);
 }
 
@@ -472,5 +569,4 @@
 mrb_time_minus(mrb_state *mrb, mrb_value self)
 {
-  mrb_float f;
   mrb_value other;
   struct mrb_time *tm, *tm2;
@@ -480,11 +576,20 @@
   tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time);
   if (tm2) {
-    f = (mrb_float)(tm->sec - tm2->sec)
-      + (mrb_float)(tm->usec - tm2->usec) / 1.0e6;
+#ifndef MRB_WITHOUT_FLOAT
+    mrb_float f;
+    f = (mrb_sec)(tm->sec - tm2->sec)
+      + (mrb_sec)(tm->usec - tm2->usec) / 1.0e6;
     return mrb_float_value(mrb, f);
+#else
+    mrb_int f;
+    f = tm->sec - tm2->sec;
+    if (tm->usec < tm2->usec) f--;
+    return mrb_fixnum_value(f);
+#endif
   }
   else {
-    mrb_get_args(mrb, "f", &f);
-    return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec-f, (double)tm->usec, tm->timezone);
+    time_t sec, usec;
+    sec = mrb_to_time_t(mrb, other, &usec);
+    return mrb_time_make_time(mrb, mrb_obj_class(mrb, self), tm->sec-sec, tm->usec-usec, tm->timezone);
   }
 }
@@ -547,5 +652,5 @@
   int len;
 
-#if defined(DISABLE_STDIO)
+#if defined(MRB_DISABLE_STDIO)
   char *s;
 # ifdef NO_ASCTIME_R
@@ -559,8 +664,7 @@
   char buf[256];
 
-  len = snprintf(buf, sizeof(buf), "%s %s %02d %02d:%02d:%02d %s%d",
+  len = snprintf(buf, sizeof(buf), "%s %s %2d %02d:%02d:%02d %.4d",
     wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday,
     d->tm_hour, d->tm_min, d->tm_sec,
-    tm->timezone == MRB_TIMEZONE_UTC ? "UTC " : "",
     d->tm_year + 1900);
 #endif
@@ -603,5 +707,5 @@
   *tm2 = *tm;
   tm2->timezone = MRB_TIMEZONE_UTC;
-  time_update_datetime(mrb, tm2);
+  time_update_datetime(mrb, tm2, TRUE);
   return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2);
 }
@@ -618,5 +722,5 @@
   *tm2 = *tm;
   tm2->timezone = MRB_TIMEZONE_LOCAL;
-  time_update_datetime(mrb, tm2);
+  time_update_datetime(mrb, tm2, TRUE);
   return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2);
 }
@@ -640,5 +744,5 @@
   mrb_int ayear = 0, amonth = 1, aday = 1, ahour = 0,
   amin = 0, asec = 0, ausec = 0;
-  int n;
+  mrb_int n;
   struct mrb_time *tm;
 
@@ -696,5 +800,5 @@
   tm = time_get_ptr(mrb, self);
   tm->timezone = MRB_TIMEZONE_LOCAL;
-  time_update_datetime(mrb, tm);
+  time_update_datetime(mrb, tm, FALSE);
   return self;
 }
@@ -744,5 +848,5 @@
 }
 
-
+#ifndef MRB_WITHOUT_FLOAT
 /* 15.2.19.7.24 */
 /* Returns a Float with the time since the epoch in seconds. */
@@ -755,7 +859,8 @@
   return mrb_float_value(mrb, (mrb_float)tm->sec + (mrb_float)tm->usec/1.0e6);
 }
+#endif
 
 /* 15.2.19.7.25 */
-/* Returns a Fixnum with the time since the epoch in seconds. */
+/* Returns an Integer with the time since the epoch in seconds. */
 static mrb_value
 mrb_time_to_i(mrb_state *mrb, mrb_value self)
@@ -764,12 +869,14 @@
 
   tm = time_get_ptr(mrb, self);
-  if (tm->sec > MRB_INT_MAX || tm->sec < MRB_INT_MIN) {
+#ifndef MRB_WITHOUT_FLOAT
+  if (!fixable_time_t_p(tm->sec)) {
     return mrb_float_value(mrb, (mrb_float)tm->sec);
   }
+#endif
   return mrb_fixnum_value((mrb_int)tm->sec);
 }
 
 /* 15.2.19.7.26 */
-/* Returns a Float with the time since the epoch in microseconds. */
+/* Returns an Integer with the time since the epoch in microseconds. */
 static mrb_value
 mrb_time_usec(mrb_state *mrb, mrb_value self)
@@ -778,7 +885,9 @@
 
   tm = time_get_ptr(mrb, self);
-  if (tm->usec > MRB_INT_MAX || tm->usec < MRB_INT_MIN) {
+#ifndef MRB_WITHOUT_FLOAT
+  if (!fixable_time_t_p(tm->usec)) {
     return mrb_float_value(mrb, (mrb_float)tm->usec);
   }
+#endif
   return mrb_fixnum_value((mrb_int)tm->usec);
 }
@@ -793,5 +902,5 @@
   tm = time_get_ptr(mrb, self);
   tm->timezone = MRB_TIMEZONE_UTC;
-  time_update_datetime(mrb, tm);
+  time_update_datetime(mrb, tm, FALSE);
   return self;
 }
@@ -808,4 +917,44 @@
 }
 
+static size_t
+time_to_s_utc(mrb_state *mrb, struct mrb_time *tm, char *buf, size_t buf_len)
+{
+  return strftime(buf, buf_len, TO_S_FMT "UTC", &tm->datetime);
+}
+
+static size_t
+time_to_s_local(mrb_state *mrb, struct mrb_time *tm, char *buf, size_t buf_len)
+{
+#if defined(_MSC_VER) && _MSC_VER < 1900 || defined(__MINGW64__) || defined(__MINGW32__)
+  struct tm datetime = {0};
+  time_t utc_sec = timegm(&tm->datetime);
+  size_t len;
+  int offset;
+
+  if (utc_sec == (time_t)-1) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time.");
+  }
+  offset = abs((int)(utc_sec - tm->sec) / 60);
+  datetime.tm_year = 100;
+  datetime.tm_hour = offset / 60;
+  datetime.tm_min = offset % 60;
+  len = strftime(buf, buf_len, TO_S_FMT, &tm->datetime);
+  buf[len++] = utc_sec < tm->sec ? '-' : '+';
+
+  return len + strftime(buf + len, buf_len - len, "%H%M", &datetime);
+#else
+  return strftime(buf, buf_len, TO_S_FMT "%z", &tm->datetime);
+#endif
+}
+
+static mrb_value
+mrb_time_to_s(mrb_state *mrb, mrb_value self)
+{
+  char buf[64];
+  struct mrb_time *tm = time_get_ptr(mrb, self);
+  mrb_bool utc = tm->timezone == MRB_TIMEZONE_UTC;
+  size_t len = (utc ? time_to_s_utc : time_to_s_local)(mrb, tm, buf, sizeof(buf));
+  return mrb_str_new(mrb, buf, len);
+}
 
 void
@@ -817,5 +966,5 @@
   MRB_SET_INSTANCE_TT(tc, MRB_TT_DATA);
   mrb_include_module(mrb, tc, mrb_module_get(mrb, "Comparable"));
-  mrb_define_class_method(mrb, tc, "at", mrb_time_at, MRB_ARGS_ARG(1, 1));      /* 15.2.19.6.1 */
+  mrb_define_class_method(mrb, tc, "at", mrb_time_at_m, MRB_ARGS_ARG(1, 1));      /* 15.2.19.6.1 */
   mrb_define_class_method(mrb, tc, "gm", mrb_time_gm, MRB_ARGS_ARG(1,6));       /* 15.2.19.6.2 */
   mrb_define_class_method(mrb, tc, "local", mrb_time_local, MRB_ARGS_ARG(1,6)); /* 15.2.19.6.3 */
@@ -828,6 +977,6 @@
   mrb_define_method(mrb, tc, "+"      , mrb_time_plus   , MRB_ARGS_REQ(1)); /* 15.2.19.7.2 */
   mrb_define_method(mrb, tc, "-"      , mrb_time_minus  , MRB_ARGS_REQ(1)); /* 15.2.19.7.3 */
-  mrb_define_method(mrb, tc, "to_s"   , mrb_time_asctime, MRB_ARGS_NONE());
-  mrb_define_method(mrb, tc, "inspect", mrb_time_asctime, MRB_ARGS_NONE());
+  mrb_define_method(mrb, tc, "to_s"   , mrb_time_to_s   , MRB_ARGS_NONE());
+  mrb_define_method(mrb, tc, "inspect", mrb_time_to_s   , MRB_ARGS_NONE());
   mrb_define_method(mrb, tc, "asctime", mrb_time_asctime, MRB_ARGS_NONE()); /* 15.2.19.7.4 */
   mrb_define_method(mrb, tc, "ctime"  , mrb_time_asctime, MRB_ARGS_NONE()); /* 15.2.19.7.5 */
@@ -849,5 +998,7 @@
   mrb_define_method(mrb, tc, "sec" , mrb_time_sec, MRB_ARGS_NONE());        /* 15.2.19.7.23 */
   mrb_define_method(mrb, tc, "to_i", mrb_time_to_i, MRB_ARGS_NONE());       /* 15.2.19.7.25 */
+#ifndef MRB_WITHOUT_FLOAT
   mrb_define_method(mrb, tc, "to_f", mrb_time_to_f, MRB_ARGS_NONE());       /* 15.2.19.7.24 */
+#endif
   mrb_define_method(mrb, tc, "usec", mrb_time_usec, MRB_ARGS_NONE());       /* 15.2.19.7.26 */
   mrb_define_method(mrb, tc, "utc" , mrb_time_utc, MRB_ARGS_NONE());        /* 15.2.19.7.27 */
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-time/test/time.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-time/test/time.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-time/test/time.rb	(revision 439)
@@ -3,9 +3,9 @@
 
 assert('Time.new', '15.2.3.3.3') do
-  Time.new.class == Time
+  assert_equal(Time, Time.new.class)
 end
 
 assert('Time', '15.2.19') do
-  Time.class == Class
+  assert_equal(Class, Time.class)
 end
 
@@ -22,21 +22,49 @@
 
 assert('Time.gm', '15.2.19.6.2') do
-  Time.gm(2012, 12, 23)
+  t = Time.gm(2012, 9, 23)
+  assert_operator(2012, :eql?, t.year)
+  assert_operator(   9, :eql?, t.month)
+  assert_operator(  23, :eql?, t.day)
+  assert_operator(   0, :eql?, t.hour)
+  assert_operator(   0, :eql?, t.min)
+  assert_operator(   0, :eql?, t.sec)
+  assert_operator(   0, :eql?, t.usec)
 end
 
 assert('Time.local', '15.2.19.6.3') do
-  Time.local(2012, 12, 23)
+  t = Time.local(2014, 12, 27, 18)
+  assert_operator(2014, :eql?, t.year)
+  assert_operator(  12, :eql?, t.month)
+  assert_operator(  27, :eql?, t.day)
+  assert_operator(  18, :eql?, t.hour)
+  assert_operator(   0, :eql?, t.min)
+  assert_operator(   0, :eql?, t.sec)
+  assert_operator(   0, :eql?, t.usec)
 end
 
 assert('Time.mktime', '15.2.19.6.4') do
-  Time.mktime(2012, 12, 23)
+  t = Time.mktime(2013, 10, 4, 6, 15, 58, 3485)
+  assert_operator(2013, :eql?, t.year)
+  assert_operator(  10, :eql?, t.month)
+  assert_operator(   4, :eql?, t.day)
+  assert_operator(   6, :eql?, t.hour)
+  assert_operator(  15, :eql?, t.min)
+  assert_operator(  58, :eql?, t.sec)
+  assert_operator(3485, :eql?, t.usec)
 end
 
 assert('Time.now', '15.2.19.6.5') do
-  Time.now.class == Time
+  assert_equal(Time, Time.now.class)
 end
 
 assert('Time.utc', '15.2.19.6.6') do
-  Time.utc(2012, 12, 23)
+  t = Time.utc(2034)
+  assert_operator(2034, :eql?, t.year)
+  assert_operator(   1, :eql?, t.month)
+  assert_operator(   1, :eql?, t.day)
+  assert_operator(   0, :eql?, t.hour)
+  assert_operator(   0, :eql?, t.min)
+  assert_operator(   0, :eql?, t.sec)
+  assert_operator(   0, :eql?, t.usec)
 end
 
@@ -45,5 +73,5 @@
   t2 = t1.+(60)
 
-  assert_equal(t2.utc.asctime, "Sun Mar 13 07:07:40 UTC 2011")
+  assert_equal("Sun Mar 13 07:07:40 2011", t2.utc.asctime)
 
   assert_raise(FloatDomainError) { Time.at(0) + Float::NAN }
@@ -56,5 +84,5 @@
   t2 = t1.-(60)
 
-  assert_equal(t2.utc.asctime, "Sun Mar 13 07:05:40 UTC 2011")
+  assert_equal("Sun Mar 13 07:05:40 2011", t2.utc.asctime)
 
   assert_raise(FloatDomainError) { Time.at(0) - Float::NAN }
@@ -68,28 +96,28 @@
   t3 = Time.at(1500000000.0)
 
-  t2.<=>(t1) == 1 and
-    t2.<=>(t2) == 0 and
-    t2.<=>(t3) == -1 and
-    t2.<=>(nil) == nil
+  assert_equal(1, t2 <=> t1)
+  assert_equal(0, t2 <=> t2)
+  assert_equal(-1, t2 <=> t3)
+  assert_nil(t2 <=> nil)
 end
 
 assert('Time#asctime', '15.2.19.7.4') do
-  Time.at(1300000000.0).utc.asctime == "Sun Mar 13 07:06:40 UTC 2011"
+  assert_equal("Thu Mar  4 05:06:07 1982", Time.gm(1982,3,4,5,6,7).asctime)
 end
 
 assert('Time#ctime', '15.2.19.7.5') do
-  Time.at(1300000000.0).utc.ctime == "Sun Mar 13 07:06:40 UTC 2011"
+  assert_equal("Thu Oct 24 15:26:47 2013", Time.gm(2013,10,24,15,26,47).ctime)
 end
 
 assert('Time#day', '15.2.19.7.6') do
-  Time.gm(2012, 12, 23).day == 23
+  assert_equal(23, Time.gm(2012, 12, 23).day)
 end
 
 assert('Time#dst?', '15.2.19.7.7') do
-  not Time.gm(2012, 12, 23).utc.dst?
+  assert_not_predicate(Time.gm(2012, 12, 23).utc, :dst?)
 end
 
 assert('Time#getgm', '15.2.19.7.8') do
-  Time.at(1300000000.0).getgm.asctime == "Sun Mar 13 07:06:40 UTC 2011"
+  assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).getgm.asctime)
 end
 
@@ -99,13 +127,14 @@
   t3 = t1.getlocal
 
-  t1 == t3 and t3 == t2.getlocal
+  assert_equal(t1, t3)
+  assert_equal(t3, t2.getlocal)
 end
 
 assert('Time#getutc', '15.2.19.7.10') do
-  Time.at(1300000000.0).getutc.asctime == "Sun Mar 13 07:06:40 UTC 2011"
+  assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).getutc.asctime)
 end
 
 assert('Time#gmt?', '15.2.19.7.11') do
-  Time.at(1300000000.0).utc.gmt?
+  assert_predicate(Time.at(1300000000.0).utc, :gmt?)
 end
 
@@ -114,5 +143,7 @@
 
 assert('Time#gmtime', '15.2.19.7.13') do
-  Time.at(1300000000.0).gmtime
+  t = Time.now
+  assert_predicate(t.gmtime, :gmt?)
+  assert_predicate(t, :gmt?)
 end
 
@@ -121,5 +152,5 @@
 
 assert('Time#hour', '15.2.19.7.15') do
-  Time.gm(2012, 12, 23, 7, 6).hour == 7
+  assert_equal(7, Time.gm(2012, 12, 23, 7, 6).hour)
 end
 
@@ -128,54 +159,57 @@
 
 assert('Time#initialize_copy', '15.2.19.7.17') do
-  time_tmp_2 = Time.at(7.0e6)
-  time_tmp_2.clone == time_tmp_2
+  t = Time.at(7.0e6)
+  assert_equal(t, t.clone)
 end
 
 assert('Time#localtime', '15.2.19.7.18') do
-  t1 = Time.at(1300000000.0)
-  t2 = Time.at(1300000000.0)
-
-  t1.localtime
-  t1 == t2.getlocal
+  t1 = Time.utc(2014, 5 ,6)
+  t2 = Time.utc(2014, 5 ,6)
+  t3 = t2.getlocal
+
+  assert_equal(t3, t1.localtime)
+  assert_equal(t3, t1)
 end
 
 assert('Time#mday', '15.2.19.7.19') do
-  Time.gm(2012, 12, 23).mday == 23
+  assert_equal(23, Time.gm(2012, 12, 23).mday)
 end
 
 assert('Time#min', '15.2.19.7.20') do
-  Time.gm(2012, 12, 23, 7, 6).min == 6
+  assert_equal(6, Time.gm(2012, 12, 23, 7, 6).min)
 end
 
 assert('Time#mon', '15.2.19.7.21') do
-  Time.gm(2012, 12, 23).mon == 12
+  assert_equal(12, Time.gm(2012, 12, 23).mon)
 end
 
 assert('Time#month', '15.2.19.7.22') do
-  Time.gm(2012, 12, 23).month == 12
+  assert_equal(12, Time.gm(2012, 12, 23).month)
 end
 
 assert('Times#sec', '15.2.19.7.23') do
-  Time.gm(2012, 12, 23, 7, 6, 40).sec == 40
+  assert_equal(40, Time.gm(2012, 12, 23, 7, 6, 40).sec)
 end
 
 assert('Time#to_f', '15.2.19.7.24') do
-  Time.at(1300000000.0).to_f == 1300000000.0
+  assert_operator(2.0, :eql?, Time.at(2).to_f)
 end
 
 assert('Time#to_i', '15.2.19.7.25') do
-  Time.at(1300000000.0).to_i == 1300000000
+  assert_operator(2, :eql?, Time.at(2.0).to_i)
 end
 
 assert('Time#usec', '15.2.19.7.26') do
-  Time.at(1300000000.0).usec == 0
+  assert_equal(0, Time.at(1300000000.0).usec)
 end
 
 assert('Time#utc', '15.2.19.7.27') do
-  Time.at(1300000000.0).utc
+  t = Time.now
+  assert_predicate(t.utc, :gmt?)
+  assert_predicate(t, :gmt?)
 end
 
 assert('Time#utc?', '15.2.19.7.28') do
-  Time.at(1300000000.0).utc.utc?
+  assert_predicate(Time.at(1300000000.0).utc, :utc?)
 end
 
@@ -184,17 +218,17 @@
 
 assert('Time#wday', '15.2.19.7.30') do
-  Time.gm(2012, 12, 23).wday == 0
+  assert_equal(0, Time.gm(2012, 12, 23).wday)
 end
 
 assert('Time#yday', '15.2.19.7.31') do
-  Time.gm(2012, 12, 23).yday == 358
+  assert_equal(358, Time.gm(2012, 12, 23).yday)
 end
 
 assert('Time#year', '15.2.19.7.32') do
-  Time.gm(2012, 12, 23).year == 2012
+  assert_equal(2012, Time.gm(2012, 12, 23).year)
 end
 
 assert('Time#zone', '15.2.19.7.33') do
-  Time.at(1300000000.0).utc.zone == 'UTC'
+  assert_equal('UTC', Time.at(1300000000.0).utc.zone)
 end
 
@@ -202,9 +236,10 @@
 
 assert('Time#to_s') do
-  Time.at(1300000000.0).utc.to_s == "Sun Mar 13 07:06:40 UTC 2011"
+  assert_equal("2003-04-05 06:07:08 UTC", Time.gm(2003,4,5,6,7,8,9).to_s)
 end
 
 assert('Time#inspect') do
-  Time.at(1300000000.0).utc.inspect == "Sun Mar 13 07:06:40 UTC 2011"
+  assert_match("2013-10-28 16:27:48 [+-][0-9][0-9][0-9][0-9]",
+               Time.local(2013,10,28,16,27,48).inspect)
 end
 
@@ -225,4 +260,8 @@
     t += 0.0005
   end
-  t.usec == 0
-end
+  assert_equal(0, t.usec)
+end
+
+assert('Time.gm with Dec 31 23:59:59 1969 raise ArgumentError') do
+  assert_raise(ArgumentError) {Time.gm(1969, 12, 31, 23, 59, 59)}
+end
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-toplevel-ext/test/toplevel.rb
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-toplevel-ext/test/toplevel.rb	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-toplevel-ext/test/toplevel.rb	(revision 439)
@@ -17,6 +17,6 @@
   self.include ToplevelTestModule2, ToplevelTestModule1
 
-  assert_true self.class.included_modules.include?( ToplevelTestModule1 )
-  assert_true self.class.included_modules.include?( ToplevelTestModule2 )
+  assert_true self.class.ancestors.include?( ToplevelTestModule1 )
+  assert_true self.class.ancestors.include?( ToplevelTestModule2 )
   assert_equal :foo, method_foo
   assert_equal :bar2, CONST_BAR
