From fcbf63e62c627deae76c1b8cb8c0876c536ed811 Mon Sep 17 00:00:00 2001
From: Jari Vetoniemi <jari.vetoniemi@indooratlas.com>
Date: Mon, 16 Mar 2020 18:49:26 +0900
Subject: Fresh start

---
 jni/ruby/nacl/GNUmakefile.in | 100 ++++++
 jni/ruby/nacl/README.nacl    |  51 +++
 jni/ruby/nacl/create_nmf.rb  |  70 +++++
 jni/ruby/nacl/dirent.h       |  15 +
 jni/ruby/nacl/example.html   | 150 +++++++++
 jni/ruby/nacl/nacl-config.rb |  61 ++++
 jni/ruby/nacl/package.rb     | 113 +++++++
 jni/ruby/nacl/pepper_main.c  | 732 +++++++++++++++++++++++++++++++++++++++++++
 jni/ruby/nacl/resource.h     |   8 +
 jni/ruby/nacl/select.h       |   7 +
 jni/ruby/nacl/signal.h       |   6 +
 jni/ruby/nacl/stat.h         |  10 +
 jni/ruby/nacl/unistd.h       |   9 +
 jni/ruby/nacl/utime.h        |  11 +
 14 files changed, 1343 insertions(+)
 create mode 100644 jni/ruby/nacl/GNUmakefile.in
 create mode 100644 jni/ruby/nacl/README.nacl
 create mode 100644 jni/ruby/nacl/create_nmf.rb
 create mode 100644 jni/ruby/nacl/dirent.h
 create mode 100644 jni/ruby/nacl/example.html
 create mode 100755 jni/ruby/nacl/nacl-config.rb
 create mode 100644 jni/ruby/nacl/package.rb
 create mode 100644 jni/ruby/nacl/pepper_main.c
 create mode 100644 jni/ruby/nacl/resource.h
 create mode 100644 jni/ruby/nacl/select.h
 create mode 100644 jni/ruby/nacl/signal.h
 create mode 100644 jni/ruby/nacl/stat.h
 create mode 100644 jni/ruby/nacl/unistd.h
 create mode 100644 jni/ruby/nacl/utime.h

(limited to 'jni/ruby/nacl')

diff --git a/jni/ruby/nacl/GNUmakefile.in b/jni/ruby/nacl/GNUmakefile.in
new file mode 100644
index 0000000..1fffcee
--- /dev/null
+++ b/jni/ruby/nacl/GNUmakefile.in
@@ -0,0 +1,100 @@
+# Copyright 2012 Google Inc. All Rights Reserved.
+# Author: yugui@google.com (Yugui Sonoda)
+
+include Makefile
+-include uncommon.mk
+
+NACL_SDK_ROOT=@NACL_SDK_ROOT@
+NACL_TOOLCHAIN=@NACL_TOOLCHAIN@
+NACL_TOOLCHAIN_DIR=$(NACL_SDK_ROOT)/toolchain/$(NACL_TOOLCHAIN)
+CXX=@CXX@
+
+# Don't override CC/LD/etc if they are already set to absolute
+# paths (this is the case when building in the naclports tree).
+ifeq ($(dir $(CC)),./)
+CC:=$(NACL_TOOLCHAIN_DIR)/bin/$(CC)
+endif
+ifeq ($(dir $(CXX)),./)
+CXX:=$(NACL_TOOLCHAIN_DIR)/bin/$(CXX)
+endif
+ifeq ($(dir $(LD)),./)
+LD:=$(NACL_TOOLCHAIN_DIR)/bin/$(LD)
+endif
+ifeq ($(dir $(NM)),./)
+NM:=$(NACL_TOOLCHAIN_DIR)/bin/$(NM)
+endif
+ifeq ($(dir $(AR)),./)
+AR:=$(NACL_TOOLCHAIN_DIR)/bin/$(AR)
+endif
+ifeq ($(dir $(AS)),./)
+AS:=$(NACL_TOOLCHAIN_DIR)/bin/$(AS)
+endif
+ifeq ($(dir $(RANLIB)),./)
+RANLIB:=$(NACL_TOOLCHAIN_DIR)/bin/$(RANLIB)
+endif
+ifeq ($(dir $(OBJDUMP)),./)
+OBJDUMP:=$(NACL_TOOLCHAIN_DIR)/bin/$(OBJDUMP)
+endif
+ifeq ($(dir $(OBJCOPY)),./)
+OBJCOPY:=$(NACL_TOOLCHAIN_DIR)/bin/$(OBJCOPY)
+endif
+PYTHON=@PYTHON@
+
+PPROGRAM=pepper-$(PROGRAM)
+PEPPER_LIBS=-lppapi -lnacl_io
+PROGRAM_NMF=$(PROGRAM:$(EXEEXT)=.nmf)
+PPROGRAM_NMF=$(PPROGRAM:$(EXEEXT)=.nmf)
+
+GNUmakefile: $(srcdir)/nacl/GNUmakefile.in
+$(PPROGRAM): $(PROGRAM) pepper_main.$(OBJEXT)
+	$(Q)$(MAKE) $(MFLAGS) PROGRAM=$(PPROGRAM) MAINOBJ="pepper_main.$(OBJEXT)" LIBS="$(LIBS) $(PEPPER_LIBS)" CC="$(CXX)" program
+$(PROGRAM_NMF) $(PPROGRAM_NMF): $(@:.nmf=$(EXEEXT)) nacl/create_nmf.rb
+
+.PHONY: pprogram package show_naclflags
+.SUFFIXES: $(EXEEXT) .nmf
+$(EXEEXT).nmf:
+	$(ECHO) generating manifest $@
+	$(Q)$(MINIRUBY) $(srcdir)/nacl/create_nmf.rb --verbose=$(V) $(@:.nmf=$(EXEEXT)) $@
+
+pepper_main.$(OBJEXT): $(srcdir)/nacl/pepper_main.c
+	@$(ECHO) compiling nacl/pepper_main.c
+	$(Q) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@ -c $(srcdir)/nacl/pepper_main.c
+
+.rbconfig.time:
+	@$(MAKE) .rbconfig.raw.time RBCONFIG=.rbconfig.raw.time
+	@sed \
+	  -e 's!CONFIG\["CC"\] = .*!CONFIG\["CC"\] = "$(CC)"!' \
+	  -e 's!CONFIG\["LD"\] = .*!CONFIG\["LD"\] = "$(LD)"!' \
+	  -e 's!CONFIG\["NM"\] = .*!CONFIG\["NM"\] = "$(NM)"!' \
+	  -e 's!CONFIG\["AR"\] = .*!CONFIG\["AR"\] = "$(AR)"!' \
+	  -e 's!CONFIG\["AS"\] = .*!CONFIG\["AS"\] = "$(AS)"!' \
+	  -e 's!CONFIG\["RANLIB"\] = .*!CONFIG\["RANLIB"\] = "$(RANLIB)"!' \
+	  -e 's!CONFIG\["OBJDUMP"\] = .*!CONFIG\["OBJDUMP"\] = "$(OBJDUMP)"!' \
+	  -e 's!CONFIG\["OBJCOPY"\] = .*!CONFIG\["OBJCOPY"\] = "$(OBJCOPY)"!' \
+	-i.bak rbconfig.rb
+	@touch .rbconfig.time
+
+all: pprogram
+main: $(PROGRAM_NMF)
+pprogram: showflags $(PPROGRAM) $(PPROGRAM_NMF)
+program: $(PROGRAM_NMF)
+prog: pprogram
+
+package: pprogram install-lib install-ext-comm install-ext-arch
+	$(INSTALL_DATA) $(srcdir)/nacl/example.html $(prefix)
+	$(ECHO) generating manifest $@
+	$(Q)$(MINIRUBY) $(srcdir)/nacl/package.rb $(prefix)
+
+showflags: show_naclflags
+
+show_naclflags:
+	@echo "        NACL_SDK_ROOT = $(NACL_SDK_ROOT)"
+	@echo "        NM = $(NM)"
+	@echo "        AR = $(AR)"
+	@echo "        AS = $(AS)"
+	@echo "        RANLIB = $(RANLIB)"
+	@echo "        OBJDUMP = $(OBJDUMP)"
+	@echo "        OBJCOPY = $(OBJCOPY)"
+
+clean-local::
+	-$(RM) $(PPROGRAM) pepper_main.$(OBJEXT) $(PROGRAM_NMF) $(PPRGORAM_NMF)
diff --git a/jni/ruby/nacl/README.nacl b/jni/ruby/nacl/README.nacl
new file mode 100644
index 0000000..77140e0
--- /dev/null
+++ b/jni/ruby/nacl/README.nacl
@@ -0,0 +1,51 @@
+=begin
+= Native Client port of Ruby
+
+= How to build
+== Prerequisites
+You need to install the following things before building NaCl port of Ruby.
+* Ruby 1.9.3 or later
+* Python 2.6 or later
+* NativeClient SDK pepper 37 or later
+* GNU make
+
+== Steps
+(1) Extract all files from the tarball:
+     $ tar xzf ruby-X.Y.Z.tar.gz
+(2) Set NACL_SDK_ROOT environment variable to the path to the Native Client SDK you installed:
+     $ export NACL_SDK_ROOT=/home/yugui/src/nacl_sdk/pepper_37
+(3) Configure
+     $ ./configure --prefix=/tmp/nacl-ruby --host=x86_64-nacl --with-baseruby=/path/to/ruby-1.9.3-or-later
+(4) Make
+     $ make
+     $ make package
+
+Now you have ruby.nexe. You can run it by sel_ldr in NaCl SDK.
+
+"make package" installs "pepper-ruby.nexe", an example Pepper application that
+embeds Ruby", and libraries to $prefix. You can run it by the following steps:
+(5) Publish the $prefix directory on a web server
+(6) Visit the example.html on the web server by a browser that implements Pepper 18 or later.
+   -- e.g., Chrome 18 implements Pepper 18, Chrome 19 implements Pepper 19, ...
+
+=== Example Configurations
+* x86_32 Native Client
+   $ ./configure --prefix=/tmp/nacl-ruby \
+     --host=i686-nacl \
+     --with-baseruby=/path/to/ruby-1.9.3-or-later
+* arm Native Client
+   $ ./configure --prefix=/tmp/nacl-ruby \
+     --host=arm-nacl \
+     --with-newlib \
+     --with-baseruby=/path/to/ruby-1.9.3-or-later
+* Portable Native Client
+   $ ./configure --prefix=/tmp/nacl-ruby \
+     --host=le32-nacl \
+     --with-newlib \
+     --with-static-linked-ext \
+     --with-baseruby=/path/to/ruby-1.9.3-or-later
+
+= Copyright
+* Copyright 2012 Google Inc. All Rights Reserved.
+* Author: yugui@google.com (Yugui Sonoda)
+=end
diff --git a/jni/ruby/nacl/create_nmf.rb b/jni/ruby/nacl/create_nmf.rb
new file mode 100644
index 0000000..cdfe7ad
--- /dev/null
+++ b/jni/ruby/nacl/create_nmf.rb
@@ -0,0 +1,70 @@
+#!/usr/bin/ruby
+# Copyright:: Copyright 2012 Google Inc.
+# License:: All Rights Reserved.
+# Original Author:: Yugui Sonoda (mailto:yugui@google.com)
+#
+# Wrapper for create_nmf.py / generate_nmf.py
+
+require File.join(File.dirname(__FILE__), 'nacl-config')
+
+include NaClConfig
+$verbosity = 0
+
+def usage_and_exit
+  $stderr.puts "Usage: #{$PROGRAM_NAME} [--verbose=N] path/to/input.nexe path/to/output.nmf"
+  exit false
+end
+
+def create_dynamically_linked(nmf, exe)
+  cmd = [
+    PYTHON, CREATE_NMF,
+    '-o', nmf,
+    '-D', OBJDUMP,
+    '-L', HOST_LIB,
+    exe
+  ]
+  puts cmd.join(' ') if $verbosity > 0
+  exec(*cmd)
+end
+
+def create_statically_linked(nmf, exe)
+  File.open(nmf, "w") {|f|
+    f.write <<-EOS.gsub(/^ {6}/, '')
+      {
+        "program": {
+          "#{ARCH}": {
+            "url": "#{exe}"
+          }
+        }
+      }
+    EOS
+  }
+end
+
+def main
+  while m = ARGV.first.match(/--([a-z-]+)(?:=(\S+))?/)
+    case m[1]
+    when 'verbose'
+      usage_and_exit unless m[2][/\A[0-9]+\z/]
+      $verbosity = m[2].to_i
+    when 'help'
+      usage_end_exit
+    end
+    ARGV.shift
+  end
+
+  usage_and_exit if ARGV.size < 2
+
+  exe, nmf = ARGV[0], ARGV[1]
+  if newlib?
+    create_statically_linked(nmf, exe)
+  else
+    create_dynamically_linked(nmf, exe)
+  end
+end
+
+if __FILE__ == $0
+   main()
+end
+
+
diff --git a/jni/ruby/nacl/dirent.h b/jni/ruby/nacl/dirent.h
new file mode 100644
index 0000000..31bdad3
--- /dev/null
+++ b/jni/ruby/nacl/dirent.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ * Author: yugui@google.com (Yugui Sonoda)
+ */
+#ifndef RUBY_NACL_DIRENT_H
+#define RUBY_NACL_DIRENT_H
+
+/* NaCl SDK 0.3 has implementations of dir functions but no declaration in
+ * dirent.h */
+int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+void rewinddir(DIR *dirp);
+long telldir(DIR *dirp);
+void seekdir(DIR *dirp, long offset);
+
+#endif
diff --git a/jni/ruby/nacl/example.html b/jni/ruby/nacl/example.html
new file mode 100644
index 0000000..3cc3329
--- /dev/null
+++ b/jni/ruby/nacl/example.html
@@ -0,0 +1,150 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Ruby Example</title>
+
+  <script type="text/javascript">
+    RubyModule = null;  // Global application object.
+    statusText = 'NO-STATUS';
+    rubyReady = false;
+
+    // Indicate load success.
+    function moduleDidLoad() {
+      RubyModule = document.getElementById('ruby');
+      form = document.getElementById('source-form');
+      form.style.display = "block";
+      updateStatus('SUCCESS');
+    }
+
+    function evalSource() {
+      if (rubyReady) {
+        RubyModule.postMessage('eval:' + document.getElementById("source").value);
+      } else {
+        throw "Not yet ready";
+      }
+      return false;
+    }
+
+    function RubyError(message) {
+      this.message = message;
+      this.toString = function() {
+        return message;
+      }
+    }
+
+    function FatalError(message) {
+      this.message = message;
+    }
+
+    // The 'message' event handler.  This handler is fired when the NaCl module
+    // posts a message to the browser by calling PPB_Messaging.PostMessage()
+    // (in C) or pp::Instance.PostMessage() (in C++).  This implementation
+    // simply displays the content of the message in an alert panel.
+    function handleMessage(message_event) {
+      var raw = message_event.data;
+      var components;
+      if (raw.indexOf("error") == 0) {
+        components = raw.split(":", 2);
+        throw new RubyError(components[1]);
+      } else if (raw.indexOf("return") == 0) {
+        components = raw.split(":", 2);
+        document.getElementById("result").value = components[1];
+      } else if (raw == "rubyReady") {
+        rubyReady = true;
+      } else {
+        throw new FatalError(raw);
+      }
+    }
+
+    // If the page loads before the Native Client module loads, then set the
+    // status message indicating that the module is still loading.  Otherwise,
+    // do not change the status message.
+    function pageDidLoad() {
+      if (RubyModule == null) {
+        updateStatus('LOADING...');
+      } else {
+        // It's possible that the Native Client module onload event fired
+        // before the page's onload event.  In this case, the status message
+        // will reflect 'SUCCESS', but won't be displayed.  This call will
+        // display the current message.
+        updateStatus();
+      }
+    }
+
+    // Set the global status message.  If the element with id 'statusField'
+    // exists, then set its HTML to the status message as well.
+    // opt_message The message test.  If this is null or undefined, then
+    // attempt to set the element with id 'statusField' to the value of
+    // |statusText|.
+    function updateStatus(opt_message) {
+      if (opt_message)
+        statusText = opt_message;
+      var statusField = document.getElementById('status_field');
+      if (statusField) {
+        statusField.innerHTML = statusText;
+      }
+    }
+  </script>
+</head>
+<body onload="pageDidLoad()">
+
+<h1>Native Client Module Ruby</h1>
+<p>
+  <!-- Load the published .nexe.  This includes the 'nacl' attribute which
+  shows how to load multi-architecture modules.  Each entry in the "nexes"
+  object in the .nmf manifest file is a key-value pair: the key is the
+  instruction set architecture ('x86-32', 'x86-64', etc.); the value is a URL
+  for the desired NaCl module.
+  To load the debug versions of your .nexes, set the 'nacl' attribute to the
+  _dbg.nmf version of the manifest file.
+
+  Note: Since this NaCl module does not use any real-estate in the browser,
+  it's width and height are set to 0.
+
+  Note: The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
+  and a 'message' event listener attached.  This wrapping method is used
+  instead of attaching the event listeners directly to the <EMBED> element to
+  ensure that the listeners are active before the NaCl module 'load' event
+  fires.  This also allows you to use PPB_Messaging.PostMessage() (in C) or
+  pp::Instance.PostMessage() (in C++) from within the initialization code in
+  your NaCl module.
+  -->
+  <div id="listener">
+    <script type="text/javascript">
+      var listener = document.getElementById('listener');
+      listener.addEventListener('load', moduleDidLoad, true);
+      listener.addEventListener('message', handleMessage, true);
+    </script>
+
+    <embed name="nacl_module"
+       id="ruby"
+       width="0" height="0"
+       src="ruby.nmf"
+       type="application/x-nacl" />
+    <form id="source-form" action="#" method="post" style="display:none"
+      onsubmit="evalSource(); return false">
+      <table>
+        <tbody>
+          <tr>
+            <th>Source</th>
+            <td>
+              <textarea rows="10" cols="80" id="source"></textarea>
+              <input type="submit" />
+            </td>
+          </tr>
+          <tr>
+            <th>Result</th>
+            <td>
+              <textarea rows="10" cols="80" id="result"></textarea>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </form>
+  </div>
+</p>
+
+<h2>Status</h2>
+<div id="status_field">NO-STATUS</div>
+</body>
+</html>
diff --git a/jni/ruby/nacl/nacl-config.rb b/jni/ruby/nacl/nacl-config.rb
new file mode 100755
index 0000000..6648130
--- /dev/null
+++ b/jni/ruby/nacl/nacl-config.rb
@@ -0,0 +1,61 @@
+#!/usr/bin/ruby
+#
+# Copyright:: Copyright 2012 Google Inc.
+# License:: All Rights Reserved.
+# Original Author:: Yugui Sonoda (mailto:yugui@google.com)
+#
+# Convenient functions/constants for native client specific configurations.
+require 'rbconfig'
+
+module NaClConfig
+  config = RbConfig::CONFIG
+
+  cpu_nick = config['host_alias'].sub(/-gnu$|-newlib$/, '').sub(/-nacl$/, '').sub(/i.86/, 'x86_32')
+  ARCH = cpu_nick.sub('x86_64', 'x86-64').sub('x86_32', 'x86-32')
+  HOST = ARCH.sub(/x86-../, 'x86_64') + '-nacl'
+
+  lib_suffix = config['host_cpu'][/i.86/] ? '32' : ''
+  PYTHON = config['PYTHON']
+  OBJDUMP = config['OBJDUMP']
+  SDK_ROOT = config['NACL_SDK_ROOT']
+  CREATE_NMF = [
+    File.join(SDK_ROOT, 'build_tools', 'nacl_sdk_scons', 'site_tools', 'create_nmf.py'),
+    File.join(SDK_ROOT, 'tools', 'create_nmf.py')
+  ].find{|path| File.exist?(path) } or raise "No create_nmf found"
+  HOST_LIB = File.join(SDK_ROOT, 'toolchain', config['NACL_TOOLCHAIN'], HOST, "lib#{lib_suffix}")
+
+  NACL_LIB = File.join(SDK_ROOT, 'lib', config['NACL_LIB_PATH'], 'Release')
+
+  INSTALL_PROGRAM = config['INSTALL_PROGRAM']
+  INSTALL_LIBRARY = config['INSTALL_DATA']
+
+  if cpu_nick == 'x86_64' or cpu_nick == 'x86_32'
+    SEL_LDR = File.join(SDK_ROOT, 'tools', "sel_ldr_#{cpu_nick}")
+    IRT_CORE = File.join(SDK_ROOT, 'tools', "irt_core_#{cpu_nick}.nexe")
+    raise "No sel_ldr found" if not File.executable?(SEL_LDR)
+    raise "No irt_core found" if not File.exists?(IRT_CORE)
+  end
+  RUNNABLE_LD = File.join(HOST_LIB, 'runnable-ld.so')
+
+  module_function
+
+  def newlib?
+    RbConfig::CONFIG['NACL_SDK_VARIANT'] == 'newlib'
+  end
+
+  def self.config(name)
+    if NaClConfig::const_defined?(name.upcase)
+      NaClConfig::const_get(name.upcase)
+    elsif NaClConfig::respond_to?(name) and NaClConfig::method(name).arity == 0
+      NaClConfig::send(name)
+    else
+      raise ArgumentError, "No such config: #{name}"
+    end
+  end
+end
+
+if $0 == __FILE__
+  ARGV.each do |arg|
+    puts NaClConfig::config(arg)
+  end
+end
diff --git a/jni/ruby/nacl/package.rb b/jni/ruby/nacl/package.rb
new file mode 100644
index 0000000..9ba9588
--- /dev/null
+++ b/jni/ruby/nacl/package.rb
@@ -0,0 +1,113 @@
+#!/usr/bin/ruby
+# Copyright:: Copyright 2012 Google Inc.
+# License:: All Rights Reserved.
+# Original Author:: Yugui Sonoda (mailto:yugui@google.com)
+#
+# Generates a runnable package of the pepper API example.
+
+require File.join(File.dirname(__FILE__), 'nacl-config')
+require 'json'
+require 'find'
+require 'fileutils'
+
+include NaClConfig
+
+class Installation
+  include NaClConfig
+
+  SRC_DIRS = [
+    Dir.pwd,
+    HOST_LIB,
+    NACL_LIB,
+  ]
+
+  def initialize(destdir)
+    @destdir = destdir
+    @manifest = {
+      "files" => {}
+    }
+    ruby_libs.each do |path|
+      raise "Collision of #{path}" if @manifest['files'].key? path
+      @manifest['files'][path] = {
+        ARCH => {
+          "url" => path
+        }
+      }
+      if path[/\.so$/]
+        alternate_path = path.gsub('/', "_")
+        raise "Collision of #{alternate_path}" if @manifest['files'].key? alternate_path
+        @manifest['files'][alternate_path] = {
+          ARCH => {
+            "url" => path
+          }
+        }
+      end
+    end
+  end
+
+  def manifest
+    @manifest.dup
+  end
+
+  def install_program(basename)
+    do_install_binary(basename, File.join(@destdir, "bin", ARCH))
+    @manifest["program"] = {
+      ARCH => {
+        "url" => File.join("bin", ARCH, basename)
+      }
+    }
+  end
+
+  def install_library(name, basename)
+    do_install_binary(basename, File.join(@destdir, "lib", ARCH))
+    @manifest["files"][name] = {
+      ARCH => {
+        "url" => File.join("lib", ARCH, basename)
+      }
+    }
+  end
+
+  private
+  def do_install_binary(basename, dest_dir)
+    full_path = nil
+    catch(:found) {
+      SRC_DIRS.each do |path|
+        full_path = File.join(path, basename)
+        if File.exist? full_path
+          throw :found
+        end
+      end
+      raise Errno::ENOENT, "No such file to install: %s" % basename
+    }
+    FileUtils.mkdir_p dest_dir
+    system("#{INSTALL_PROGRAM} #{full_path} #{dest_dir}")
+  end
+
+  def ruby_libs
+    Find.find(RbConfig::CONFIG['rubylibdir']).select{|path| File.file?(path) }.map{|path| path.sub("#{@destdir}/", "") }
+  end
+end
+
+def install(destdir)
+  inst = Installation.new(destdir)
+  manifest = JSON.parse(File.read("pepper-ruby.nmf"))
+
+  program = File.basename(manifest['program'][ARCH]['url'])
+  inst.install_program(program)
+
+  manifest['files'].each do |name, attr|
+    inst.install_library(name, File.basename(attr[ARCH]["url"]))
+  end
+
+  File.open(File.join(destdir, "ruby.nmf"), "w") {|f|
+    f.puts JSON.pretty_generate(inst.manifest)
+  }
+end
+
+def main
+  install(ARGV[0])
+end
+
+if __FILE__ == $0
+  main()
+end
diff --git a/jni/ruby/nacl/pepper_main.c b/jni/ruby/nacl/pepper_main.c
new file mode 100644
index 0000000..168e8f9
--- /dev/null
+++ b/jni/ruby/nacl/pepper_main.c
@@ -0,0 +1,732 @@
+/******************************************************************************
+ Copyright 2012 Google Inc. All Rights Reserved.
+ Author: yugui@google.com (Yugui Sonoda)
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_module.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/c/ppb.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_file_ref.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppb_messaging.h"
+#include "ppapi/c/ppb_url_loader.h"
+#include "ppapi/c/ppb_url_request_info.h"
+#include "ppapi/c/ppb_url_response_info.h"
+#include "ppapi/c/ppb_var.h"
+#include "ppapi/c/ppp.h"
+#include "ppapi/c/ppp_instance.h"
+#include "ppapi/c/ppp_messaging.h"
+#include "nacl_io/nacl_io.h"
+
+#include "verconf.h"
+#include "ruby/ruby.h"
+#include "version.h"
+#include "gc.h"
+
+#ifdef HAVE_STRUCT_PPB_CORE
+typedef struct PPB_Core PPB_Core;
+#endif
+#ifdef HAVE_STRUCT_PPB_MESSAGING
+typedef struct PPB_Messaging PPB_Messaging;
+#endif
+#ifdef HAVE_STRUCT_PPB_VAR
+typedef struct PPB_Var PPB_Var;
+#endif
+#ifdef HAVE_STRUCT_PPB_URLLOADER
+typedef struct PPB_URLLoader PPB_URLLoader;
+#endif
+#ifdef HAVE_STRUCT_PPB_URLREQUESTINFO
+typedef struct PPB_URLRequestInfo PPB_URLRequestInfo;
+#endif
+#ifdef HAVE_STRUCT_PPB_URLRESPONSEINFO
+typedef struct PPB_URLResponseInfo PPB_URLResponseInfo;
+#endif
+#ifdef HAVE_STRUCT_PPP_INSTANCE
+typedef struct PPP_Instance PPP_Instance;
+#endif
+
+static PP_Module module_id = 0;
+static PPB_GetInterface get_browser_interface = NULL;
+static PPB_Core* core_interface = NULL;
+static PPB_Messaging* messaging_interface = NULL;
+static PPB_Var* var_interface = NULL;
+static PPB_URLLoader* loader_interface = NULL;
+static PPB_URLRequestInfo* request_interface = NULL;
+static PPB_URLResponseInfo* response_interface = NULL;
+static PPB_FileRef* fileref_interface = NULL;
+static struct st_table* instance_data = NULL;
+
+static VALUE instance_table = Qundef;
+
+static PP_Instance current_instance = 0;
+
+/******************************************************************************
+ * State of instance
+ ******************************************************************************/
+
+static void inst_mark(void *const ptr);
+static void inst_free(void *const ptr);
+static size_t inst_memsize(void *const ptr);
+static const rb_data_type_t pepper_instance_data_type = {
+  "PepperInstance",
+  { inst_mark, inst_free, inst_memsize }
+};
+
+struct PepperInstance {
+  PP_Instance instance;
+  PP_Resource url_loader;
+  VALUE self;
+  void* async_call_args;
+  union {
+    int32_t as_int;
+    const char* as_str;
+    VALUE as_value;
+  } async_call_result;
+  char buf[1000];
+
+  pthread_t th;
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+};
+
+struct PepperInstance*
+pruby_get_instance(PP_Instance instance)
+{
+  VALUE self = rb_hash_aref(instance_table, INT2FIX(instance));
+  if (RTEST(self)) {
+    struct PepperInstance *inst;
+    TypedData_Get_Struct(self, struct PepperInstance, &pepper_instance_data_type, inst);
+    return inst;
+  }
+  else {
+    return NULL;
+  }
+}
+
+#define GET_PEPPER_INSTANCE() (pruby_get_instance(current_instance))
+
+struct PepperInstance*
+pruby_register_instance(PP_Instance instance)
+{
+  VALUE obj;
+  struct PepperInstance *data;
+  obj = TypedData_Make_Struct(rb_cData, struct PepperInstance, &pepper_instance_data_type, data);
+  data->self = obj;
+  data->instance = instance;
+  data->url_loader = 0;
+
+  pthread_mutex_init(&data->mutex, NULL);
+  pthread_cond_init(&data->cond, NULL);
+
+  rb_hash_aset(instance_table, INT2FIX(instance), obj);
+  return data;
+}
+
+int
+pruby_unregister_instance(PP_Instance instance)
+{
+  VALUE inst = rb_hash_delete(instance_table, INT2FIX(instance));
+  return RTEST(inst);
+}
+
+static void
+inst_mark(void *const ptr)
+{
+  RUBY_MARK_ENTER("PepperInstance"0);
+  if (ptr) {
+    const struct PepperInstance* inst = (struct PepperInstance*)ptr;
+    RUBY_MARK_UNLESS_NULL(inst->async_call_result.as_value);
+  }
+  RUBY_MARK_LEAVE("PepperInstance"0);
+}
+
+static void
+inst_free(void *const ptr)
+{
+  ruby_xfree(ptr);
+}
+
+static size_t
+inst_memsize(void *const ptr)
+{
+  if (ptr) {
+    const struct PepperInstance* inst = (struct PepperInstance*)ptr;
+    return sizeof(*inst);
+  } else {
+    return 0;
+  }
+}
+
+void
+pruby_async_return_int(void* data, int32_t result)
+{
+  /* PPAPI main thread */
+  struct PepperInstance* const instance = (struct PepperInstance*)data;
+  instance->async_call_result.as_int = result;
+  if (pthread_cond_signal(&instance->cond)) {
+    perror("pepper-ruby:pthread_cond_signal");
+  }
+}
+
+void
+pruby_async_return_str(void* data, const char *result)
+{
+  /* PPAPI main thread */
+  struct PepperInstance* const instance = (struct PepperInstance*)data;
+  instance->async_call_result.as_str = result;
+  if (pthread_cond_signal(&instance->cond)) {
+    perror("pepper-ruby:pthread_cond_signal");
+  }
+}
+
+void
+pruby_async_return_value(void* data, VALUE value)
+{
+  /* PPAPI main thread */
+  struct PepperInstance* const instance = (struct PepperInstance*)data;
+  instance->async_call_result.as_value = value;
+  if (pthread_cond_signal(&instance->cond)) {
+    perror("pepper-ruby:pthread_cond_signal");
+  }
+}
+/******************************************************************************
+ * Conversion between Ruby's VALUE, Pepper's Var and C string
+ ******************************************************************************/
+
+/**
+ * Creates a new string PP_Var from C string. The resulting object will be a
+ * refcounted string object. It will be AddRef()ed for the caller. When the
+ * caller is done with it, it should be Release()d.
+ * @param[in] str C string to be converted to PP_Var
+ * @return PP_Var containing string.
+ */
+static struct PP_Var
+pruby_cstr_to_var(const char* str)
+{
+#ifndef PPB_VAR_INTERFACE_1_1
+  if (var_interface != NULL)
+    return var_interface->VarFromUtf8(module_id, str, strlen(str));
+  return PP_MakeUndefined();
+#else
+  return var_interface->VarFromUtf8(str, strlen(str));
+#endif
+}
+
+/**
+ * Returns a mutable C string contained in the @a var or NULL if @a var is not
+ * string.  This makes a copy of the string in the @a var and adds a NULL
+ * terminator.  Note that VarToUtf8() does not guarantee the NULL terminator on
+ * the returned string.  See the comments for VarToUtf8() in ppapi/c/ppb_var.h
+ * for more info.  The caller is responsible for freeing the returned memory.
+ * @param[in] var PP_Var containing string.
+ * @return a mutable C string representation of @a var.
+ * @note The caller is responsible for freeing the returned string.
+ */
+static char*
+pruby_var_to_cstr(struct PP_Var var)
+{
+  uint32_t len = 0;
+  if (var_interface != NULL) {
+    const char* var_c_str = var_interface->VarToUtf8(var, &len);
+    if (len > 0) {
+      char* c_str = (char*)malloc(len + 1);
+      memcpy(c_str, var_c_str, len);
+      c_str[len] = '\0';
+      return c_str;
+    }
+  }
+  return NULL;
+}
+
+static struct PP_Var
+pruby_str_to_var(volatile VALUE str)
+{
+  if (!RB_TYPE_P(str, T_STRING)) {
+    fprintf(stderr, "[BUG] Unexpected object type: %x\n", TYPE(str));
+    exit(EXIT_FAILURE);
+  }
+#ifndef PPB_VAR_INTERFACE_1_1
+  if (var_interface != NULL) {
+    return var_interface->VarFromUtf8(module_id, RSTRING_PTR(str), RSTRING_LEN(str));
+  }
+#else
+  return var_interface->VarFromUtf8(RSTRING_PTR(str), RSTRING_LEN(str));
+#endif
+  return PP_MakeUndefined();
+}
+
+static struct PP_Var
+pruby_obj_to_var(volatile VALUE obj)
+{
+  static const char* const error =
+      "throw 'Failed to convert the result to a JavaScript object';";
+  int state;
+  obj = rb_protect(&rb_obj_as_string, obj, &state);
+  if (!state) {
+      return pruby_str_to_var(obj);
+  }
+  else {
+      return pruby_cstr_to_var(error);
+  }
+}
+
+int
+pruby_var_equal_to_cstr_p(struct PP_Var lhs, const char* rhs)
+{
+  uint32_t len = 0;
+  if (var_interface == NULL) {
+    return 0;
+  }
+  else {
+    const char* const cstr = var_interface->VarToUtf8(lhs, &len);
+    return strncmp(cstr, rhs, len) == 0;
+  }
+}
+
+int
+pruby_var_prefixed_p(struct PP_Var var, const char* prefix)
+{
+  uint32_t len = 0;
+  if (var_interface == NULL) {
+    return 0;
+  }
+  else {
+    const char* const cstr = var_interface->VarToUtf8(var, &len);
+    const size_t prefix_len = strlen(prefix);
+    return len >= prefix_len && memcmp(cstr, prefix, len) == 0;
+  }
+}
+
+
+/******************************************************************************
+ * Messaging
+ ******************************************************************************/
+
+/* Posts the given C string as a message.
+ * @param data pointer to a NULL-terminated string */
+void
+pruby_post_cstr(void* data)
+{
+  /* PPAPI main thread */
+  struct PepperInstance* const instance = (struct PepperInstance*)data;
+  const char* const msg = (const char*)instance->async_call_args;
+  messaging_interface->PostMessage(instance->instance,
+                                   pruby_cstr_to_var(msg));
+}
+
+/* Posts the given Ruby VALUE as a message.
+ * @param data a VALUE casted to void* */
+void
+pruby_post_value(void* data)
+{
+  /* PPAPI main thread */
+  struct PepperInstance* const instance = (struct PepperInstance*)data;
+  volatile VALUE value = (VALUE)instance->async_call_args;
+  messaging_interface->PostMessage(instance->instance, pruby_obj_to_var(value));
+}
+
+
+
+/******************************************************************************
+ * Ruby initialization
+ ******************************************************************************/
+
+static void
+init_loadpath(void)
+{
+  ruby_incpush("lib/ruby/"RUBY_LIB_VERSION);
+  ruby_incpush("lib/ruby/"RUBY_LIB_VERSION"/"RUBY_PLATFORM);
+  ruby_incpush(".");
+}
+
+static VALUE
+init_libraries_internal(VALUE unused)
+{
+  extern void Init_enc();
+  extern void Init_ext();
+
+  init_loadpath();
+  Init_enc();
+  Init_ext();
+  return Qnil;
+}
+
+static void*
+init_libraries(void* data)
+{
+  int state;
+  struct PepperInstance* const instance = (struct PepperInstance*)data;
+  current_instance = instance->instance;
+
+  if (pthread_mutex_lock(&instance->mutex)) {
+    perror("pepper-ruby:pthread_mutex_lock");
+    return 0;
+  }
+  rb_protect(&init_libraries_internal, Qnil, &state);
+  pthread_mutex_unlock(&instance->mutex);
+
+  if (state) {
+    volatile VALUE err = rb_errinfo();
+    err = rb_obj_as_string(err);
+  } else {
+    instance->async_call_args = (void*)"rubyReady";
+    core_interface->CallOnMainThread(
+        0, PP_MakeCompletionCallback(pruby_post_cstr, instance), 0);
+  }
+  return NULL;
+}
+
+static int
+init_libraries_if_necessary(void)
+{
+  static int initialized = 0;
+  if (!initialized) {
+    struct PepperInstance* const instance = GET_PEPPER_INSTANCE();
+    int err;
+    initialized = 1;
+    err = pthread_create(&instance->th, NULL, &init_libraries, instance);
+    if (err) {
+      fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err));
+      exit(EXIT_FAILURE);
+    }
+    pthread_detach(instance->th);
+  }
+  return 0;
+}
+
+static int
+reopen_fd(int fd, const char* path, int flags) {
+  int fd2 = open(path, flags);
+  if (fd2 < 0) {
+    perror("open fd");
+    return -1;
+  }
+  if (dup2(fd2, fd) < 0) {
+    perror("dup2 fd");
+    return -1;
+  }
+  if (close(fd2)) {
+    perror("close old fd");
+    return -1;
+  }
+  return fd;
+}
+
+static int
+pruby_init(void)
+{
+  RUBY_INIT_STACK;
+  ruby_init();
+
+  instance_table = rb_hash_new();
+  rb_gc_register_mark_object(instance_table);
+
+  return 0;
+}
+
+
+/******************************************************************************
+ * Ruby evaluation
+ ******************************************************************************/
+
+static void*
+pruby_eval(void* data)
+{
+  extern VALUE ruby_eval_string_from_file_protect(const char* src, const char* path, int* state);
+  struct PepperInstance* const instance = (struct PepperInstance*)data;
+  volatile VALUE src = (VALUE)instance->async_call_args;
+  volatile VALUE result = Qnil;
+  volatile int state;
+
+  RUBY_INIT_STACK;
+
+  if (pthread_mutex_lock(&instance->mutex)) {
+    perror("pepper-ruby:pthread_mutex_lock");
+    return 0;
+  }
+  result = ruby_eval_string_from_file_protect(
+      RSTRING_PTR(src), "(pepper-ruby)", &state);
+  pthread_mutex_unlock(&instance->mutex);
+
+  if (!state) {
+      instance->async_call_args =
+          rb_str_concat(rb_usascii_str_new_cstr("return:"),
+                        rb_obj_as_string(result));
+      core_interface->CallOnMainThread(
+          0, PP_MakeCompletionCallback(pruby_post_value, instance), 0);
+      return NULL;
+  }
+  else {
+      rb_set_errinfo(Qnil);
+      instance->async_call_args =
+          rb_str_concat(rb_usascii_str_new_cstr("error:"),
+                        rb_obj_as_string(result));
+      core_interface->CallOnMainThread(
+          0, PP_MakeCompletionCallback(pruby_post_value, instance), 0);
+      return NULL;
+  }
+}
+
+
+/******************************************************************************
+ * Pepper Module callbacks
+ ******************************************************************************/
+
+/**
+ * Called when the NaCl module is instantiated on the web page. The identifier
+ * of the new instance will be passed in as the first argument (this value is
+ * generated by the browser and is an opaque handle).  This is called for each
+ * instantiation of the NaCl module, which is each time the <embed> tag for
+ * this module is encountered.
+ *
+ * If this function reports a failure (by returning @a PP_FALSE), the NaCl
+ * module will be deleted and DidDestroy will be called.
+ * @param[in] instance The identifier of the new instance representing this
+ *     NaCl module.
+ * @param[in] argc The number of arguments contained in @a argn and @a argv.
+ * @param[in] argn An array of argument names.  These argument names are
+ *     supplied in the <embed> tag, for example:
+ *       <embed id="nacl_module" dimensions="2">
+ *     will produce two arguments, one named "id" and one named "dimensions".
+ * @param[in] argv An array of argument values.  These are the values of the
+ *     arguments listed in the <embed> tag.  In the above example, there will
+ *     be two elements in this array, "nacl_module" and "2".  The indices of
+ *     these values match the indices of the corresponding names in @a argn.
+ * @return @a PP_TRUE on success.
+ */
+static PP_Bool
+Instance_DidCreate(PP_Instance instance,
+                   uint32_t argc, const char* argn[], const char* argv[])
+{
+  struct PepperInstance* data = pruby_register_instance(instance);
+  current_instance = instance;
+
+  nacl_io_init_ppapi(instance, get_browser_interface);
+
+  if (mount("", "/dev2", "dev", 0, "")) {
+    perror("mount dev");
+    return PP_FALSE;
+  }
+  if (reopen_fd(0, "/dev2/stdin", O_RDONLY) < 0) {
+    perror("reopen stdin");
+    return PP_FALSE;
+  }
+  if (reopen_fd(1, "/dev2/stdout", O_WRONLY) < 0) {
+    perror("reopen stdout");
+    return PP_FALSE;
+  }
+  if (reopen_fd(2, "/dev2/console1", O_WRONLY) < 0) {
+    perror("reopen stderr");
+    return PP_FALSE;
+  }
+
+  /* TODO(yugui) Unmount original /dev */
+
+  if (mount("/lib", "/lib", "httpfs",
+        0, "allow_cross_origin_requests=false")) {
+    perror("mount httpfs");
+    return PP_FALSE;
+  }
+
+  return init_libraries_if_necessary() ? PP_FALSE : PP_TRUE;
+}
+
+/**
+ * Called when the NaCl module is destroyed. This will always be called,
+ * even if DidCreate returned failure. This routine should deallocate any data
+ * associated with the instance.
+ * @param[in] instance The identifier of the instance representing this NaCl
+ *     module.
+ */
+static void Instance_DidDestroy(PP_Instance instance) {
+  struct PepperInstance* data = pruby_get_instance(instance);
+  core_interface->ReleaseResource(data->url_loader);
+  pruby_unregister_instance(instance);
+}
+
+/**
+ * Called when the position, the size, or the clip rect of the element in the
+ * browser that corresponds to this NaCl module has changed.
+ * @param[in] instance The identifier of the instance representing this NaCl
+ *     module.
+ * @param[in] position The location on the page of this NaCl module. This is
+ *     relative to the top left corner of the viewport, which changes as the
+ *     page is scrolled.
+ * @param[in] clip The visible region of the NaCl module. This is relative to
+ *     the top left of the plugin's coordinate system (not the page).  If the
+ *     plugin is invisible, @a clip will be (0, 0, 0, 0).
+ */
+#ifndef PPP_INSTANCE_INTERFACE_1_1
+static void
+Instance_DidChangeView(PP_Instance instance,
+                       const struct PP_Rect* position,
+                       const struct PP_Rect* clip)
+{
+}
+#else
+static void
+Instance_DidChangeView(PP_Instance instance, PP_Resource view_resource)
+{
+}
+#endif
+
+/**
+ * Notification that the given NaCl module has gained or lost focus.
+ * Having focus means that keyboard events will be sent to the NaCl module
+ * represented by @a instance. A NaCl module's default condition is that it
+ * will not have focus.
+ *
+ * Note: clicks on NaCl modules will give focus only if you handle the
+ * click event. You signal if you handled it by returning @a true from
+ * HandleInputEvent. Otherwise the browser will bubble the event and give
+ * focus to the element on the page that actually did end up consuming it.
+ * If you're not getting focus, check to make sure you're returning true from
+ * the mouse click in HandleInputEvent.
+ * @param[in] instance The identifier of the instance representing this NaCl
+ *     module.
+ * @param[in] has_focus Indicates whether this NaCl module gained or lost
+ *     event focus.
+ */
+static void
+Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus)
+{
+}
+
+/**
+ * Handler that gets called after a full-frame module is instantiated based on
+ * registered MIME types.  This function is not called on NaCl modules.  This
+ * function is essentially a place-holder for the required function pointer in
+ * the PPP_Instance structure.
+ * @param[in] instance The identifier of the instance representing this NaCl
+ *     module.
+ * @param[in] url_loader A PP_Resource an open PPB_URLLoader instance.
+ * @return PP_FALSE.
+ */
+static PP_Bool
+Instance_HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader)
+{
+  /* NaCl modules do not need to handle the document load function. */
+  return PP_FALSE;
+}
+
+
+/**
+ * Handler for messages coming in from the browser via postMessage.  The
+ * @a var_message can contain anything: a JSON string; a string that encodes
+ * method names and arguments; etc.  For example, you could use JSON.stringify
+ * in the browser to create a message that contains a method name and some
+ * parameters, something like this:
+ *   var json_message = JSON.stringify({ "myMethod" : "3.14159" });
+ *   nacl_module.postMessage(json_message);
+ * On receipt of this message in @a var_message, you could parse the JSON to
+ * retrieve the method name, match it to a function call, and then call it with
+ * the parameter.
+ * @param[in] instance The instance ID.
+ * @param[in] message The contents, copied by value, of the message sent from
+ *     browser via postMessage.
+ */
+void
+Messaging_HandleMessage(PP_Instance instance, struct PP_Var var_message)
+{
+  char* const message = pruby_var_to_cstr(var_message);
+  size_t message_len = strlen(message);
+  current_instance = instance;
+
+  if (strstr(message, "eval:") != NULL) {
+    volatile VALUE src;
+    struct PepperInstance* const instance_data = GET_PEPPER_INSTANCE();
+    int err;
+#define EVAL_PREFIX_LEN 5
+    src = rb_str_new(message + EVAL_PREFIX_LEN, message_len - EVAL_PREFIX_LEN);
+    instance_data->async_call_args = (void*)src;
+    err = pthread_create(&instance_data->th, NULL, &pruby_eval, instance_data);
+    if (err) {
+      fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err));
+      exit(EXIT_FAILURE);
+    }
+    pthread_detach(instance_data->th);
+  }
+  free(message);
+}
+
+/**
+ * Entry points for the module.
+ * Initialize instance interface and scriptable object class.
+ * @param[in] a_module_id Module ID
+ * @param[in] get_browser_interface Pointer to PPB_GetInterface
+ * @return PP_OK on success, any other value on failure.
+ */
+PP_EXPORT int32_t
+PPP_InitializeModule(PP_Module a_module_id, PPB_GetInterface a_get_browser_interface)
+{
+  module_id = a_module_id;
+  get_browser_interface = a_get_browser_interface;
+  core_interface = (PPB_Core*)(get_browser_interface(PPB_CORE_INTERFACE));
+  if (core_interface == NULL) return PP_ERROR_NOINTERFACE;
+
+  var_interface = (PPB_Var*)(get_browser_interface(PPB_VAR_INTERFACE));
+  if (var_interface == NULL) return PP_ERROR_NOINTERFACE;
+
+  messaging_interface = (PPB_Messaging*)(get_browser_interface(PPB_MESSAGING_INTERFACE));
+  if (messaging_interface == NULL) return PP_ERROR_NOINTERFACE;
+
+  loader_interface = (PPB_URLLoader*)(get_browser_interface(PPB_URLLOADER_INTERFACE));
+  if (loader_interface == NULL) return PP_ERROR_NOINTERFACE;
+
+  request_interface = (PPB_URLRequestInfo*)(get_browser_interface(PPB_URLREQUESTINFO_INTERFACE));
+  if (request_interface == NULL) return PP_ERROR_NOINTERFACE;
+
+  response_interface = (PPB_URLResponseInfo*)(get_browser_interface(PPB_URLRESPONSEINFO_INTERFACE));
+  if (response_interface == NULL) return PP_ERROR_NOINTERFACE;
+
+  fileref_interface = (PPB_FileRef*)(get_browser_interface(PPB_FILEREF_INTERFACE));
+  if (fileref_interface == NULL) return PP_ERROR_NOINTERFACE;
+
+  return pruby_init() ? PP_ERROR_FAILED : PP_OK;
+}
+
+/**
+ * Returns an interface pointer for the interface of the given name, or NULL
+ * if the interface is not supported.
+ * @param[in] interface_name name of the interface
+ * @return pointer to the interface
+ */
+PP_EXPORT const void*
+PPP_GetInterface(const char* interface_name)
+{
+  if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
+    static PPP_Instance instance_interface = {
+      &Instance_DidCreate,
+      &Instance_DidDestroy,
+      &Instance_DidChangeView,
+      &Instance_DidChangeFocus,
+      &Instance_HandleDocumentLoad
+    };
+    return &instance_interface;
+  } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
+    static PPP_Messaging messaging_interface = {
+      &Messaging_HandleMessage
+    };
+    return &messaging_interface;
+  }
+  return NULL;
+}
+
+/**
+ * Called before the plugin module is unloaded.
+ */
+PP_EXPORT void
+PPP_ShutdownModule(void)
+{
+  ruby_cleanup(0);
+}
diff --git a/jni/ruby/nacl/resource.h b/jni/ruby/nacl/resource.h
new file mode 100644
index 0000000..57ca53b
--- /dev/null
+++ b/jni/ruby/nacl/resource.h
@@ -0,0 +1,8 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ * Author: yugui@google.com (Yugui Sonoda)
+ * */
+#ifndef RUBY_NACL_RESOURCE_H
+#define RUBY_NACL_RESOURCE_H
+int getrusage(int who, struct rusage *usage);
+#endif
diff --git a/jni/ruby/nacl/select.h b/jni/ruby/nacl/select.h
new file mode 100644
index 0000000..921721a
--- /dev/null
+++ b/jni/ruby/nacl/select.h
@@ -0,0 +1,7 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Author: yugui@google.com (Yugui Sonoda)
+#ifndef RUBY_NACL_SELECT_H
+#define RUBY_NACL_SELECT_H
+int select(int num_fds, fd_set *in_fds, fd_set *out_fds,
+           fd_set *ex_fds, struct timeval *timeout);
+#endif
diff --git a/jni/ruby/nacl/signal.h b/jni/ruby/nacl/signal.h
new file mode 100644
index 0000000..54832de
--- /dev/null
+++ b/jni/ruby/nacl/signal.h
@@ -0,0 +1,6 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Author: yugui@google.com (Yugui Sonoda)
+#ifndef RUBY_NACL_SIGNAL_H
+#define RUBY_NACL_SIGNAL_H
+int kill(pid_t pid, int signal);
+#endif
diff --git a/jni/ruby/nacl/stat.h b/jni/ruby/nacl/stat.h
new file mode 100644
index 0000000..7be40ad
--- /dev/null
+++ b/jni/ruby/nacl/stat.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ * Author: yugui@google.com (Yugui Sonoda)
+ * */
+#ifndef RUBY_NACL_STAT_H
+#define RUBY_NACL_STAT_H
+mode_t umask(mode_t mask);
+struct stat;
+int lstat(const char* path, struct stat* result);
+#endif
diff --git a/jni/ruby/nacl/unistd.h b/jni/ruby/nacl/unistd.h
new file mode 100644
index 0000000..1c97390
--- /dev/null
+++ b/jni/ruby/nacl/unistd.h
@@ -0,0 +1,9 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Author: yugui@google.com (Yugui Sonoda)
+#ifndef RUBY_NACL_UNISTD_H
+#define RUBY_NACL_UNISTD_H
+int seteuid(pid_t pid);
+int setegid(pid_t pid);
+int truncate(const char* path, off_t new_size);
+int ftruncate(int fd, off_t new_size);
+#endif
diff --git a/jni/ruby/nacl/utime.h b/jni/ruby/nacl/utime.h
new file mode 100644
index 0000000..9691005
--- /dev/null
+++ b/jni/ruby/nacl/utime.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ * Author: yugui@google.com (Yugui Sonoda)
+ */
+
+#ifndef RUBY_NACL_UTIME_H
+#define RUBY_NACL_UTIME_H
+#include <utime.h>
+int utime(const char *filename, const struct utimbuf *times);
+int utimes(const char *filename, const struct timeval times[2]);
+#endif
-- 
cgit v1.2.3-70-g09d2