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