diff mupdf-source/thirdparty/mujs/main.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/thirdparty/mujs/main.c	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,394 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _MSC_VER
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include "mujs.h"
+
+static char *xoptarg; /* Global argument pointer. */
+static int xoptind = 0; /* Global argv index. */
+static int xgetopt(int argc, char *argv[], char *optstring)
+{
+	static char *scan = NULL; /* Private scan pointer. */
+
+	char c;
+	char *place;
+
+	xoptarg = NULL;
+
+	if (!scan || *scan == '\0') {
+		if (xoptind == 0)
+			xoptind++;
+
+		if (xoptind >= argc || argv[xoptind][0] != '-' || argv[xoptind][1] == '\0')
+			return EOF;
+		if (argv[xoptind][1] == '-' && argv[xoptind][2] == '\0') {
+			xoptind++;
+			return EOF;
+		}
+
+		scan = argv[xoptind]+1;
+		xoptind++;
+	}
+
+	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') {
+			xoptarg = scan;
+			scan = NULL;
+		} else if (xoptind < argc) {
+			xoptarg = argv[xoptind];
+			xoptind++;
+		} 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)
+{
+	int i, n = js_gettop(J);
+	for (i = 1; i < n; ++i) {
+		js_loadfile(J, js_tostring(J, i));
+		js_pushundefined(J);
+		js_call(J, 0);
+		js_pop(J, 1);
+	}
+	js_pushundefined(J);
+}
+
+static void jsB_compile(js_State *J)
+{
+	const char *source = js_tostring(J, 1);
+	const char *filename = js_isdefined(J, 2) ? js_tostring(J, 2) : "[string]";
+	js_loadstring(J, filename, source);
+}
+
+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': %s", filename, strerror(errno));
+	}
+
+	if (fseek(f, 0, SEEK_END) < 0) {
+		fclose(f);
+		js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno));
+	}
+
+	n = ftell(f);
+	if (n < 0) {
+		fclose(f);
+		js_error(J, "cannot tell in file '%s': %s", filename, strerror(errno));
+	}
+
+	if (fseek(f, 0, SEEK_SET) < 0) {
+		fclose(f);
+		js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno));
+	}
+
+	s = malloc(n + 1);
+	if (!s) {
+		fclose(f);
+		js_error(J, "out of memory");
+	}
+
+	t = fread(s, 1, n, f);
+	if (t != n) {
+		free(s);
+		fclose(f);
+		js_error(J, "cannot read data from file '%s': %s", filename, strerror(errno));
+	}
+	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 void jsB_repr(js_State *J)
+{
+	js_repr(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"
+	"var s = this.name;\n"
+	"if ('message' in this) s += ': ' + this.message;\n"
+	"if ('stackTrace' in this) s += this.stackTrace;\n"
+	"return s;\n"
+	"};\n"
+;
+
+static const char *console_js =
+	"var console = { log: print, debug: print, warn: print, error: print };"
+;
+
+static int eval_print(js_State *J, const char *source)
+{
+	if (js_ploadstring(J, "[stdin]", 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_tryrepr(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 = xgetopt(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);
+	if (!J) {
+		fprintf(stderr, "Could not initialize MuJS.\n");
+		exit(1);
+	}
+
+	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_compile, "compile", 2);
+	js_setglobal(J, "compile");
+
+	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_repr, "repr", 0);
+	js_setglobal(J, "repr");
+
+	js_newcfunction(J, jsB_quit, "quit", 1);
+	js_setglobal(J, "quit");
+
+	js_dostring(J, require_js);
+	js_dostring(J, stacktrace_js);
+	js_dostring(J, console_js);
+
+	if (xoptind == argc) {
+		interactive = 1;
+	} else {
+		c = xoptind++;
+
+		js_newarray(J);
+		i = 0;
+		while (xoptind < argc) {
+			js_pushstring(J, argv[xoptind++]);
+			js_setindex(J, -2, i++);
+		}
+		js_setglobal(J, "scriptArgs");
+
+		if (js_dofile(J, argv[c]))
+			status = 1;
+	}
+
+	if (interactive) {
+		printf("Welcome to MuJS %d.%d.%d.\n",
+			JS_VERSION_MAJOR, JS_VERSION_MINOR, JS_VERSION_PATCH);
+		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;
+}