ref: 2c0c6c94ca2ab0132bee57e369070eed6a73c9a6
dir: /main.c/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mujs.h"
static char *optarg; /* Global argument pointer. */
static int optind = 0; /* Global argv index. */
static int getopt(int argc, char *argv[], char *optstring)
{
static char *scan = NULL; /* Private scan pointer. */
char c;
char *place;
optarg = NULL;
if (!scan || *scan == '\0') {
if (optind == 0)
optind++;
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
return EOF;
if (argv[optind][1] == '-' && argv[optind][2] == '\0') {
optind++;
return EOF;
}
scan = argv[optind]+1;
optind++;
}
c = *scan++;
place = strchr(optstring, c);
if (!place || c == ':') {
fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
return '?';
}
place++;
if (*place == ':') {
if (*scan != '\0') {
optarg = scan;
scan = NULL;
} else if( optind < argc ) {
optarg = argv[optind];
optind++;
} else {
fprintf(stderr, "%s: option requires argument -%c\n", argv[0], c);
return ':';
}
}
return c;
}
#ifdef HAVE_READLINE
#include <readline/readline.h>
#include <readline/history.h>
#else
void using_history(void) { }
void add_history(const char *string) { }
void rl_bind_key(int key, void (*fun)(void)) { }
void rl_insert(void) { }
char *readline(const char *prompt)
{
static char line[500], *p;
int n;
fputs(prompt, stdout);
p = fgets(line, sizeof line, stdin);
if (p) {
n = strlen(line);
if (n > 0 && line[n-1] == '\n')
line[--n] = 0;
p = malloc(n+1);
memcpy(p, line, n+1);
return p;
}
return NULL;
}
#endif
#define PS1 "> "
static void jsB_gc(js_State *J)
{
int report = js_toboolean(J, 1);
js_gc(J, report);
js_pushundefined(J);
}
static void jsB_load(js_State *J)
{
const char *filename = js_tostring(J, 1);
int rv = js_dofile(J, filename);
js_pushboolean(J, !rv);
}
static void jsB_print(js_State *J)
{
int i, top = js_gettop(J);
for (i = 1; i < top; ++i) {
const char *s = js_tostring(J, i);
if (i > 1) putchar(' ');
fputs(s, stdout);
}
putchar('\n');
js_pushundefined(J);
}
static void jsB_write(js_State *J)
{
int i, top = js_gettop(J);
for (i = 1; i < top; ++i) {
const char *s = js_tostring(J, i);
if (i > 1) putchar(' ');
fputs(s, stdout);
}
js_pushundefined(J);
}
static void jsB_read(js_State *J)
{
const char *filename = js_tostring(J, 1);
FILE *f;
char *s;
int n, t;
f = fopen(filename, "rb");
if (!f) {
js_error(J, "cannot open file: '%s'", filename);
}
if (fseek(f, 0, SEEK_END) < 0) {
fclose(f);
js_error(J, "cannot seek in file: '%s'", filename);
}
n = ftell(f);
if (n < 0) {
fclose(f);
js_error(J, "cannot tell in file: '%s'", filename);
}
if (fseek(f, 0, SEEK_SET) < 0) {
fclose(f);
js_error(J, "cannot seek in file: '%s'", filename);
}
s = malloc(n + 1);
if (!s) {
fclose(f);
js_error(J, "cannot allocate storage for file contents: '%s'", filename);
}
t = fread(s, 1, n, f);
if (t != n) {
free(s);
fclose(f);
js_error(J, "cannot read data from file: '%s'", filename);
}
s[n] = 0;
js_pushstring(J, s);
free(s);
fclose(f);
}
static void jsB_readline(js_State *J)
{
char *line = readline("");
if (!line) {
js_pushnull(J);
return;
}
js_pushstring(J, line);
if (*line)
add_history(line);
free(line);
}
static void jsB_quit(js_State *J)
{
exit(js_tonumber(J, 1));
}
static const char *require_js =
"function require(name) {\n"
"var cache = require.cache;\n"
"if (name in cache) return cache[name];\n"
"var exports = {};\n"
"cache[name] = exports;\n"
"Function('exports', read(name+'.js'))(exports);\n"
"return exports;\n"
"}\n"
"require.cache = Object.create(null);\n"
;
static const char *stacktrace_js =
"Error.prototype.toString = function() {\n"
"if (this.stackTrace) return this.name + ': ' + this.message + this.stackTrace;\n"
"return this.name + ': ' + this.message;\n"
"};\n"
;
static int eval_print(js_State *J, const char *source)
{
if (js_ploadstring(J, "[string]", source)) {
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
js_pop(J, 1);
return 1;
}
js_pushundefined(J);
if (js_pcall(J, 0)) {
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
js_pop(J, 1);
return 1;
}
if (js_isdefined(J, -1))
printf("%s\n", js_trystring(J, -1, "can't convert to string"));
js_pop(J, 1);
return 0;
}
static char *read_stdin(void)
{
int n = 0;
int t = 512;
char *s = NULL;
for (;;) {
char *ss = realloc(s, t);
if (!ss) {
free(s);
fprintf(stderr, "cannot allocate storage for stdin contents\n");
return NULL;
}
s = ss;
n += fread(s + n, 1, t - n - 1, stdin);
if (n < t - 1)
break;
t *= 2;
}
if (ferror(stdin)) {
free(s);
fprintf(stderr, "error reading stdin\n");
return NULL;
}
s[n] = 0;
return s;
}
static void usage(void)
{
fprintf(stderr, "Usage: mujs [options] [script [scriptArgs*]]\n");
fprintf(stderr, "\t-i: Enter interactive prompt after running code.\n");
fprintf(stderr, "\t-s: Check strictness.\n");
exit(1);
}
int
main(int argc, char **argv)
{
char *input;
js_State *J;
int status = 0;
int strict = 0;
int interactive = 0;
int i, c;
while ((c = getopt(argc, argv, "is")) != -1) {
switch (c) {
default: usage(); break;
case 'i': interactive = 1; break;
case 's': strict = 1; break;
}
}
J = js_newstate(NULL, NULL, strict ? JS_STRICT : 0);
js_newcfunction(J, jsB_gc, "gc", 0);
js_setglobal(J, "gc");
js_newcfunction(J, jsB_load, "load", 1);
js_setglobal(J, "load");
js_newcfunction(J, jsB_print, "print", 0);
js_setglobal(J, "print");
js_newcfunction(J, jsB_write, "write", 0);
js_setglobal(J, "write");
js_newcfunction(J, jsB_read, "read", 1);
js_setglobal(J, "read");
js_newcfunction(J, jsB_readline, "readline", 0);
js_setglobal(J, "readline");
js_newcfunction(J, jsB_quit, "quit", 1);
js_setglobal(J, "quit");
js_dostring(J, require_js);
js_dostring(J, stacktrace_js);
if (optind == argc) {
interactive = 1;
} else {
c = optind++;
js_newarray(J);
i = 0;
while (optind < argc) {
js_pushstring(J, argv[optind++]);
js_setindex(J, -2, i++);
}
js_setglobal(J, "scriptArgs");
if (js_dofile(J, argv[c]))
status = 1;
}
if (interactive) {
if (isatty(0)) {
using_history();
rl_bind_key('\t', rl_insert);
input = readline(PS1);
while (input) {
eval_print(J, input);
if (*input)
add_history(input);
free(input);
input = readline(PS1);
}
putchar('\n');
} else {
input = read_stdin();
if (!input || !js_dostring(J, input))
status = 1;
free(input);
}
}
js_gc(J, 0);
js_freestate(J);
return status;
}