| #include "js_shell.h" |
| |
| #include <iostream> |
| #include <fstream> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| |
| #ifdef __GNUC__ |
| #ifdef __APPLE__ |
| #define LIBRARY_EXT ".bundle" |
| #else |
| #define LIBRARY_EXT ".so" |
| #endif |
| #include <dlfcn.h> |
| #define LOAD_LIBRARY(name) dlopen(name, RTLD_LAZY) |
| #define CLOSE_LIBRARY(handle) dlclose(handle) |
| #define LIBRARY_ERROR dlerror |
| #define LIBRARYFILE(name) std::string("lib").append(name).append(LIBRARY_EXT) |
| #else |
| #error "implement dll loading" |
| #endif |
| |
| |
| JSShell::~JSShell() { |
| |
| for(std::vector<HANDLE>::iterator it = loaded_modules.begin(); |
| it != loaded_modules.end(); ++it) { |
| HANDLE handle = *it; |
| CLOSE_LIBRARY(handle); |
| } |
| |
| } |
| |
| // TODO: this could be done more intelligent... |
| // - can we achieve source file relative loading? |
| // - better path resolution |
| std::string JSShell::LoadModule(const std::string& name, HANDLE* library) { |
| |
| // works only for posix like OSs |
| size_t pathIdx = name.find_last_of("/"); |
| |
| std::string lib_name; |
| std::string module_name; |
| |
| if (pathIdx == std::string::npos) { |
| module_name = name; |
| lib_name = std::string(name).append(LIBRARY_EXT); |
| } else { |
| std::string path = name.substr(0, pathIdx+1); |
| module_name = name.substr(pathIdx+1); |
| lib_name = path.append(module_name).append(LIBRARY_EXT); |
| } |
| |
| std::string lib_path; |
| HANDLE handle = 0; |
| |
| for (int i = 0; i < module_path.size(); ++i) { |
| lib_path = module_path[i] + "/" + lib_name; |
| if (access( lib_path.c_str(), F_OK ) != -1) { |
| handle = LOAD_LIBRARY(lib_path.c_str()); |
| } |
| } |
| |
| if(handle == 0) { |
| std::cerr << "Could not find module " << lib_path << ":" |
| << std::endl << LIBRARY_ERROR() << std::endl; |
| return 0; |
| } |
| |
| loaded_modules.push_back(handle); |
| |
| *library = handle; |
| |
| return module_name; |
| } |
| |
| bool JSShell::RunScript(const std::string& scriptPath) { |
| std::string source = ReadFile(scriptPath); |
| if(!InitializeEngine()) return false; |
| |
| // Node.js compatibility: make `print` available as `console.log()` |
| ExecuteScript("var console = {}; console.log = print;", "<console>"); |
| |
| if(!ExecuteScript(source, scriptPath)) { |
| return false; |
| } |
| |
| return DisposeEngine(); |
| } |
| |
| bool JSShell::RunShell() { |
| |
| if(!InitializeEngine()) return false; |
| |
| static const int kBufferSize = 1024; |
| while (true) { |
| char buffer[kBufferSize]; |
| printf("> "); |
| char* str = fgets(buffer, kBufferSize, stdin); |
| if (str == NULL) break; |
| std::string source(str); |
| ExecuteScript(source, "(shell)"); |
| } |
| printf("\n"); |
| return true; |
| } |
| |
| std::string JSShell::ReadFile(const std::string& fileName) |
| { |
| std::string script; |
| |
| std::ifstream file(fileName.c_str()); |
| if (file.is_open()) { |
| while ( file.good() ) { |
| std::string line; |
| getline(file, line); |
| script.append(line); |
| script.append("\n"); |
| } |
| file.close(); |
| } else { |
| std::cout << "Unable to open file " << fileName << "." << std::endl; |
| } |
| |
| return script; |
| } |
| |
| #ifdef ENABLE_JSC |
| extern JSShell* JSCShell_Create(); |
| #endif |
| #ifdef ENABLE_V8 |
| extern JSShell* V8Shell_Create(); |
| #endif |
| |
| typedef JSShell*(*ShellFactory)(); |
| |
| static ShellFactory js_shell_factories[2] = { |
| #ifdef ENABLE_JSC |
| JSCShell_Create, |
| #else |
| 0, |
| #endif |
| #ifdef ENABLE_V8 |
| V8Shell_Create, |
| #else |
| 0, |
| #endif |
| }; |
| |
| JSShell *JSShell::Create(Engine engine) { |
| if(js_shell_factories[engine] == 0) { |
| throw "Engine not available."; |
| } |
| return js_shell_factories[engine](); |
| } |