Mercurial > hgrepos > Python2 > PyMuPDF
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 } |
