aboutsummaryrefslogtreecommitdiff
path: root/Tools/javascript/js_shell.cxx
blob: 470d6418ada9f31a2f857d4b1502e555374ccf31 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#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]();
}