main.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #ifdef _MSC_VER
  5. #include <io.h>
  6. #else
  7. #include <unistd.h>
  8. #endif
  9. #include <errno.h>
  10. #include "mujs.h"
  11. static char *xoptarg; /* Global argument pointer. */
  12. static int xoptind = 0; /* Global argv index. */
  13. static int xgetopt(int argc, char *argv[], char *optstring)
  14. {
  15. static char *scan = NULL; /* Private scan pointer. */
  16. char c;
  17. char *place;
  18. xoptarg = NULL;
  19. if (!scan || *scan == '\0') {
  20. if (xoptind == 0)
  21. xoptind++;
  22. if (xoptind >= argc || argv[xoptind][0] != '-' || argv[xoptind][1] == '\0')
  23. return EOF;
  24. if (argv[xoptind][1] == '-' && argv[xoptind][2] == '\0') {
  25. xoptind++;
  26. return EOF;
  27. }
  28. scan = argv[xoptind]+1;
  29. xoptind++;
  30. }
  31. c = *scan++;
  32. place = strchr(optstring, c);
  33. if (!place || c == ':') {
  34. fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
  35. return '?';
  36. }
  37. place++;
  38. if (*place == ':') {
  39. if (*scan != '\0') {
  40. xoptarg = scan;
  41. scan = NULL;
  42. } else if (xoptind < argc) {
  43. xoptarg = argv[xoptind];
  44. xoptind++;
  45. } else {
  46. fprintf(stderr, "%s: option requires argument -%c\n", argv[0], c);
  47. return ':';
  48. }
  49. }
  50. return c;
  51. }
  52. #ifdef HAVE_READLINE
  53. #include <readline/readline.h>
  54. #include <readline/history.h>
  55. #else
  56. void using_history(void) { }
  57. void add_history(const char *string) { }
  58. void rl_bind_key(int key, void (*fun)(void)) { }
  59. void rl_insert(void) { }
  60. char *readline(const char *prompt)
  61. {
  62. static char line[500], *p;
  63. int n;
  64. fputs(prompt, stdout);
  65. p = fgets(line, sizeof line, stdin);
  66. if (p) {
  67. n = strlen(line);
  68. if (n > 0 && line[n-1] == '\n')
  69. line[--n] = 0;
  70. p = malloc(n+1);
  71. memcpy(p, line, n+1);
  72. return p;
  73. }
  74. return NULL;
  75. }
  76. #endif
  77. #define PS1 "> "
  78. static void jsB_gc(js_State *J)
  79. {
  80. int report = js_toboolean(J, 1);
  81. js_gc(J, report);
  82. js_pushundefined(J);
  83. }
  84. static void jsB_load(js_State *J)
  85. {
  86. int i, n = js_gettop(J);
  87. for (i = 1; i < n; ++i) {
  88. js_loadfile(J, js_tostring(J, i));
  89. js_pushundefined(J);
  90. js_call(J, 0);
  91. js_pop(J, 1);
  92. }
  93. js_pushundefined(J);
  94. }
  95. static void jsB_compile(js_State *J)
  96. {
  97. const char *source = js_tostring(J, 1);
  98. const char *filename = js_isdefined(J, 2) ? js_tostring(J, 2) : "[string]";
  99. js_loadstring(J, filename, source);
  100. }
  101. static void jsB_print(js_State *J)
  102. {
  103. int i, top = js_gettop(J);
  104. for (i = 1; i < top; ++i) {
  105. const char *s = js_tostring(J, i);
  106. if (i > 1) putchar(' ');
  107. fputs(s, stdout);
  108. }
  109. putchar('\n');
  110. js_pushundefined(J);
  111. }
  112. static void jsB_write(js_State *J)
  113. {
  114. int i, top = js_gettop(J);
  115. for (i = 1; i < top; ++i) {
  116. const char *s = js_tostring(J, i);
  117. if (i > 1) putchar(' ');
  118. fputs(s, stdout);
  119. }
  120. js_pushundefined(J);
  121. }
  122. static void jsB_read(js_State *J)
  123. {
  124. const char *filename = js_tostring(J, 1);
  125. FILE *f;
  126. char *s;
  127. int n, t;
  128. f = fopen(filename, "rb");
  129. if (!f) {
  130. js_error(J, "cannot open file '%s': %s", filename, strerror(errno));
  131. }
  132. if (fseek(f, 0, SEEK_END) < 0) {
  133. fclose(f);
  134. js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno));
  135. }
  136. n = ftell(f);
  137. if (n < 0) {
  138. fclose(f);
  139. js_error(J, "cannot tell in file '%s': %s", filename, strerror(errno));
  140. }
  141. if (fseek(f, 0, SEEK_SET) < 0) {
  142. fclose(f);
  143. js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno));
  144. }
  145. s = malloc(n + 1);
  146. if (!s) {
  147. fclose(f);
  148. js_error(J, "out of memory");
  149. }
  150. t = fread(s, 1, n, f);
  151. if (t != n) {
  152. free(s);
  153. fclose(f);
  154. js_error(J, "cannot read data from file '%s': %s", filename, strerror(errno));
  155. }
  156. s[n] = 0;
  157. js_pushstring(J, s);
  158. free(s);
  159. fclose(f);
  160. }
  161. static void jsB_readline(js_State *J)
  162. {
  163. char *line = readline("");
  164. if (!line) {
  165. js_pushnull(J);
  166. return;
  167. }
  168. js_pushstring(J, line);
  169. if (*line)
  170. add_history(line);
  171. free(line);
  172. }
  173. static void jsB_quit(js_State *J)
  174. {
  175. exit(js_tonumber(J, 1));
  176. }
  177. static void jsB_repr(js_State *J)
  178. {
  179. js_repr(J, 1);
  180. }
  181. static const char *require_js =
  182. "function require(name) {\n"
  183. "var cache = require.cache;\n"
  184. "if (name in cache) return cache[name];\n"
  185. "var exports = {};\n"
  186. "cache[name] = exports;\n"
  187. "Function('exports', read(name+'.js'))(exports);\n"
  188. "return exports;\n"
  189. "}\n"
  190. "require.cache = Object.create(null);\n"
  191. ;
  192. static const char *stacktrace_js =
  193. "Error.prototype.toString = function() {\n"
  194. "var s = this.name;\n"
  195. "if ('message' in this) s += ': ' + this.message;\n"
  196. "if ('stackTrace' in this) s += this.stackTrace;\n"
  197. "return s;\n"
  198. "};\n"
  199. ;
  200. static const char *console_js =
  201. "var console = { log: print, debug: print, warn: print, error: print };"
  202. ;
  203. static int eval_print(js_State *J, const char *source)
  204. {
  205. if (js_ploadstring(J, "[stdin]", source)) {
  206. fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
  207. js_pop(J, 1);
  208. return 1;
  209. }
  210. js_pushundefined(J);
  211. if (js_pcall(J, 0)) {
  212. fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
  213. js_pop(J, 1);
  214. return 1;
  215. }
  216. if (js_isdefined(J, -1)) {
  217. printf("%s\n", js_tryrepr(J, -1, "can't convert to string"));
  218. }
  219. js_pop(J, 1);
  220. return 0;
  221. }
  222. static char *read_stdin(void)
  223. {
  224. int n = 0;
  225. int t = 512;
  226. char *s = NULL;
  227. for (;;) {
  228. char *ss = realloc(s, t);
  229. if (!ss) {
  230. free(s);
  231. fprintf(stderr, "cannot allocate storage for stdin contents\n");
  232. return NULL;
  233. }
  234. s = ss;
  235. n += fread(s + n, 1, t - n - 1, stdin);
  236. if (n < t - 1)
  237. break;
  238. t *= 2;
  239. }
  240. if (ferror(stdin)) {
  241. free(s);
  242. fprintf(stderr, "error reading stdin\n");
  243. return NULL;
  244. }
  245. s[n] = 0;
  246. return s;
  247. }
  248. static void usage(void)
  249. {
  250. fprintf(stderr, "Usage: mujs [options] [script [scriptArgs*]]\n");
  251. fprintf(stderr, "\t-i: Enter interactive prompt after running code.\n");
  252. fprintf(stderr, "\t-s: Check strictness.\n");
  253. exit(1);
  254. }
  255. int
  256. main(int argc, char **argv)
  257. {
  258. char *input;
  259. js_State *J;
  260. int status = 0;
  261. int strict = 0;
  262. int interactive = 0;
  263. int i, c;
  264. while ((c = xgetopt(argc, argv, "is")) != -1) {
  265. switch (c) {
  266. default: usage(); break;
  267. case 'i': interactive = 1; break;
  268. case 's': strict = 1; break;
  269. }
  270. }
  271. J = js_newstate(NULL, NULL, strict ? JS_STRICT : 0);
  272. if (!J) {
  273. fprintf(stderr, "Could not initialize MuJS.\n");
  274. exit(1);
  275. }
  276. js_newcfunction(J, jsB_gc, "gc", 0);
  277. js_setglobal(J, "gc");
  278. js_newcfunction(J, jsB_load, "load", 1);
  279. js_setglobal(J, "load");
  280. js_newcfunction(J, jsB_compile, "compile", 2);
  281. js_setglobal(J, "compile");
  282. js_newcfunction(J, jsB_print, "print", 0);
  283. js_setglobal(J, "print");
  284. js_newcfunction(J, jsB_write, "write", 0);
  285. js_setglobal(J, "write");
  286. js_newcfunction(J, jsB_read, "read", 1);
  287. js_setglobal(J, "read");
  288. js_newcfunction(J, jsB_readline, "readline", 0);
  289. js_setglobal(J, "readline");
  290. js_newcfunction(J, jsB_repr, "repr", 0);
  291. js_setglobal(J, "repr");
  292. js_newcfunction(J, jsB_quit, "quit", 1);
  293. js_setglobal(J, "quit");
  294. js_dostring(J, require_js);
  295. js_dostring(J, stacktrace_js);
  296. js_dostring(J, console_js);
  297. if (xoptind == argc) {
  298. interactive = 1;
  299. } else {
  300. c = xoptind++;
  301. js_newarray(J);
  302. i = 0;
  303. while (xoptind < argc) {
  304. js_pushstring(J, argv[xoptind++]);
  305. js_setindex(J, -2, i++);
  306. }
  307. js_setglobal(J, "scriptArgs");
  308. if (js_dofile(J, argv[c]))
  309. status = 1;
  310. }
  311. if (interactive) {
  312. printf("Welcome to MuJS %d.%d.%d.\n",
  313. JS_VERSION_MAJOR, JS_VERSION_MINOR, JS_VERSION_PATCH);
  314. if (isatty(0)) {
  315. using_history();
  316. rl_bind_key('\t', rl_insert);
  317. input = readline(PS1);
  318. while (input) {
  319. eval_print(J, input);
  320. if (*input)
  321. add_history(input);
  322. free(input);
  323. input = readline(PS1);
  324. }
  325. putchar('\n');
  326. } else {
  327. input = read_stdin();
  328. if (!input || !js_dostring(J, input))
  329. status = 1;
  330. free(input);
  331. }
  332. }
  333. js_gc(J, 0);
  334. js_freestate(J);
  335. return status;
  336. }