1
4
5# include "luametatex.h"
6
7engine_state_info lmt_engine_state = {
8 .lua_init = 0,
9 .lua_only = 0,
10 .luatex_banner = NULL,
11 .engine_name = NULL,
12 .startup_filename = NULL,
13 .startup_jobname = NULL,
14 .dump_name = NULL,
15 .utc_time = 0,
16 .permit_loadlib = 0,
17};
18
19
23
24typedef struct environment_state_info {
25 char **argv;
26 int argc;
27 int npos;
28 char *flag;
29 char *value;
30 char *name;
31 char *ownpath;
32 char *ownbase;
33 char *ownname;
34 char *owncore;
35 char *ownlink;
36 char *input_name;
37 int luatex_lua_offset;
38 int padding;
39} environment_state_info;
40
41static environment_state_info lmt_environment_state = {
42 .argv = NULL,
43 .argc = 0,
44 .npos = 0,
45 .flag = NULL,
46 .value = NULL,
47 .name = NULL,
48 .ownpath = NULL,
49 .ownbase = NULL,
50 .ownname = NULL,
51 .owncore = NULL,
52 .ownlink = NULL,
53 .input_name = NULL,
54 .luatex_lua_offset = 0,
55 .padding = 0,
56};
57
58
59
60static void enginelib_splitnames(void)
61{
62 char *p = lmt_memory_strdup(lmt_environment_state.ownpath);
63
68
74
75 lmt_environment_state.ownbase = aux_basename(lmt_memory_strdup(p));
76 lmt_environment_state.ownname = aux_basename(lmt_memory_strdup(p));
77 lmt_environment_state.ownpath = aux_dirname(lmt_memory_strdup(p));
78 lmt_environment_state.ownlink = aux_utf8_readlink(lmt_environment_state.ownpath);
79
80 for (size_t i = 0; i < strlen(lmt_environment_state.ownname); i++) {
81 if (lmt_environment_state.ownname[i] == '.') {
82 lmt_environment_state.ownname[i] = '\0';
83 break ;
84 }
85 }
86 lmt_environment_state.owncore = lmt_memory_strdup(lmt_environment_state.ownname);
87 lmt_memory_free(p);
88}
89
90
91
92
93
94
95char *tex_engine_input_filename(void)
96{
97
98 return lmt_environment_state.npos > 0 && lmt_environment_state.npos < lmt_environment_state.argc ? lmt_environment_state.argv[lmt_environment_state.npos] : NULL;
99}
100
101
110
111static char *enginelib_normalize_quotes(const char* name, const char* mesg)
112{
113 char *ret = lmt_memory_malloc(strlen(name) + 3);
114 if (ret) {
115 int must_quote = strchr(name, ' ') != NULL;
116
117 int quoted = 0;
118 char *p = ret;
119 if (must_quote) {
120 *p++ = '"';
121 }
122 for (const char *q = name; *q; q++) {
123 if (*q == '"') {
124 quoted = ! quoted;
125 } else {
126 *p++ = *q;
127 }
128 }
129 if (must_quote) {
130 *p++ = '"';
131 }
132 *p = '\0';
133 if (quoted) {
134 tex_emergency_message("system", "unbalanced quotes in %s %s\n", mesg, name);
135 tex_emergency_exit();
136 }
137 }
138 return ret;
139}
140
141
160
161static void enginelib_show_help(void)
162{
163 puts(
164 "Usage: " luametatex_name_lowercase " --lua=FILE [OPTION]... [TEXNAME[.tex]] [COMMANDS]\n"
165 " or: " luametatex_name_lowercase " --lua=FILE [OPTION]... \\FIRST-LINE\n"
166 " or: " luametatex_name_lowercase " --lua=FILE [OPTION]... &FMT ARGS\n"
167 "\n"
168 "Run " luametatex_name_camelcase " on TEXNAME, usually creating TEXNAME.pdf. Any remaining COMMANDS"
169 "are processed as luatex input, after TEXNAME is read.\n"
170 "\n"
171 "Alternatively, if the first non-option argument begins with a backslash,\n"
172 luametatex_name_camelcase " interprets all non-option arguments as an input line.\n"
173 "\n"
174 "Alternatively, if the first non-option argument begins with a &, the next word\n"
175 "is taken as the FMT to read, overriding all else. Any remaining arguments are\n"
176 "processed as above.\n"
177 "\n"
178 "If no arguments or options are specified, prompt for input.\n"
179 "\n"
180 "The following regular options are understood:\n"
181 "\n"
182 " --credits display credits and exit\n"
183 " --fmt=FORMAT load the format file FORMAT\n"
184 " --help display help and exit\n"
185 " --ini be ini" luametatex_name_lowercase ", for dumping formats\n"
186 " --jobname=STRING set the job name to STRING\n"
187 " --lua=FILE load and execute a lua initialization script\n"
188 " --version display version and exit\n"
189 "\n"
190 "Alternate behaviour models can be obtained by special switches\n"
191 "\n"
192 " --luaonly run a lua file, then exit\n"
193 "\n"
194 "Loading libraries from Lua is blocked unless one explicitly permits it:\n"
195 "\n"
196 " --permitloadlib permit loading of external libraries (coming)\n"
197 "\n"
198 "See the reference manual for more information about the startup process.\n"
199 "\n"
200 "Email bug reports to " luametatex_bug_address ".\n"
201 );
202 exit(EXIT_SUCCESS);
203}
204
205
209
210static void enginelib_show_version_info(void)
211{
212 tex_print_version_banner();
213 puts(
214 "\n"
215 "\n"
216 "Execute '" luametatex_name_lowercase " --credits' for credits and version details.\n"
217 "\n"
218 "There is NO warranty. Redistribution of this software is covered by the terms\n"
219 "of the GNU General Public License, version 2 or (at your option) any later\n"
220 "version. For more information about these matters, see the file named COPYING\n"
221 "and the LuaMetaTeX source.\n"
222 "\n"
223 "Functionality : level " LMT_TOSTRING(luametatex_development_id) "\n"
224 "Support : " luametatex_support_address "\n"
225 "Copyright : The Lua(Meta)TeX Team(s) (2005-2023+)\n"
226 "\n"
227 "The LuaMetaTeX project is related to ConTeXt development. This macro package\n"
228 "tightly integrates TeX and MetaPost in close cooperation with Lua. Updates will\n"
229 "happen in sync with ConTeXt and when needed. Don't be fooled by unchanged dates:\n"
230 "long term stability is the objective."
231 );
232 exit(EXIT_SUCCESS);
233}
234
235
260
261static void enginelib_show_credits(void)
262{
263 tex_print_version_banner();
264 puts(
265 "\n"
266 "\n"
267 "Here we mention those involved in the bits and pieces that define " luametatex_name_camelcase ". More details of\n"
268 "what comes from where can be found in the manual and other documents (that come with ConTeXt).\n"
269 "\n"
270 " luametatex : Hans Hagen, Alan Braslau, Mojca Miklavec, Wolfgang Schuster, Mikael Sundqvist\n"
271 "\n"
272 "It is a follow up on:\n"
273 "\n"
274 " luatex : Hans Hagen, Hartmut Henkel, Taco Hoekwater, Luigi Scarso\n"
275 "\n"
276 "This program itself builds upon the code from:\n"
277 "\n"
278 " tex : Donald Knuth\n"
279 "\n"
280 "We also took a few features from:\n"
281 "\n"
282 " etex : Peter Breitenlohner, Phil Taylor and friends\n"
283 "\n"
284 "The font expansion and protrusion code is derived from:\n"
285 "\n"
286 " pdftex : Han The Thanh and friends\n"
287 "\n"
288 "Part of the bidirectional text flow model is inspired by:\n"
289 "\n"
290 " omega : John Plaice and Yannis Haralambous\n"
291 " aleph : Giuseppe Bilotta\n"
292 "\n"
293 "Graphic support is originates in:\n"
294 "\n"
295 " metapost : John Hobby, Taco Hoekwater, Luigi Scarso, Hans Hagen and friends\n"
296 "\n"
297 "All this is opened up with:\n"
298 "\n"
299 " lua : Roberto Ierusalimschy, Waldemar Celes and Luiz Henrique de Figueiredo\n"
300 " lpeg : Roberto Ierusalimschy\n"
301 "\n"
302 "A few libraries are embedded, of which we mention:\n"
303 "\n"
304# ifdef MI_MALLOC_VERSION
305 " mimalloc : Daan Leijen (https://github.com/microsoft/mimalloc)\n"
306# endif
307 " miniz : Rich Geldreich etc\n"
308 " pplib : Paweł Jackowski (with partial code from libraries)\n"
309 " md5 : Peter Deutsch (with partial code from pplib libraries)\n"
310 " sha2 : Aaron D. Gifford (with partial code from pplib libraries)\n"
311 " socket : Diego Nehab (partial and adapted)\n"
312 " libcerf : Joachim Wuttke (adapted for MSVC)\n"
313 " decnumber : Mike Cowlishaw from IBM (one of the number models in MP)\n"
314 " avl : Richard (adapted a bit to fit in)\n"
315 " hjn : Raph Levien (derived from TeX's hyphenator, but adapted again)\n"
316 " softposit : S. H. Leong (Cerlane)\n"
317 " potrace : Peter Selinger\n"
318 "\n"
319 "The code base contains more names and references. Some libraries are partially adapted or\n"
320 "have been replaced. The MetaPost library has additional functionality, some of which is\n"
321 "experimental. The LuaMetaTeX project relates to ConTeXt. This LuaMetaTeX 2+ variant is a\n"
322 "lean and mean variant of LuaTeX 1+ but the core typesetting functionality is the same and\n"
323 "and has been extended in many aspects.\n"
324 "\n"
325 "There is a lightweight subsystem for optional libraries but here we also delegate as much\n"
326 "as possible to Lua. A few interfaces are provided by default, others can be added using a\n"
327 "simple foreign interface subsystem. Although this is provided and considered part of the\n"
328 "LuaMetaTeX engine it is not something ConTeXt depends (and will) depend on.\n"
329 "\n"
330 "version : " luametatex_version_string " | " LMT_TOSTRING(luametatex_development_id) "\n"
331 "format id : " LMT_TOSTRING(luametatex_format_fingerprint) "\n"
332# ifdef __DATE__
333 "date : " __TIME__ " | " __DATE__ "\n"
334# endif
335# ifdef LMT_COMPILER_USED
336 "compiler : " LMT_COMPILER_USED "\n"
337# endif
338 );
339 printf("own path : %s\n", lmt_environment_state.ownpath);
340 printf("own base : %s\n", lmt_environment_state.ownbase);
341 printf("own name : %s\n", lmt_environment_state.ownname);
342 printf("own core : %s\n", lmt_environment_state.owncore);
343 printf("own link : %s\n", lmt_environment_state.ownlink ? lmt_environment_state.ownlink : "<no link>");
344 exit(EXIT_SUCCESS);
345}
346
347
353
354static void enginelib_prepare_cmdline(int zero_offset)
355{
356 lua_State *L = lmt_lua_state.lua_instance;
357
358 lua_createtable(L, lmt_environment_state.argc, 0);
359 for (lua_Integer i = 0; i < lmt_environment_state.argc; i++) {
360 lua_set_string_by_index(L, (int) (i - zero_offset), lmt_environment_state.argv[i]);
361 }
362 lua_setglobal(L, "arg");
363
364 lua_getglobal(L, "os");
365 lua_set_string_by_key(L, "selfbin", lmt_environment_state.argv[0]);
366 lua_set_string_by_key(L, "selfpath", lmt_environment_state.ownpath);
367 lua_set_string_by_key(L, "selfdir", lmt_environment_state.ownpath);
368 lua_set_string_by_key(L, "selflink", lmt_environment_state.ownlink);
369 lua_set_string_by_key(L, "selfname", lmt_environment_state.ownname);
370 lua_set_string_by_key(L, "selfcore", lmt_environment_state.owncore);
371 lua_createtable(L, lmt_environment_state.argc, 0);
372 for (lua_Integer i = 0; i < lmt_environment_state.argc; i++) {
373 lua_set_string_by_index(L, (int) i, lmt_environment_state.argv[i]);
374 }
375 lua_setfield(L, -2, "selfarg");
376}
377
378
389
390static void enginelib_check_option(char **options, int i)
391{
392 char *option = options[i];
393 char *n = option;
394 lmt_environment_state.flag = NULL;
395 lmt_environment_state.value = NULL;
396 if (*n == '-') {
397 n++;
398 } else {
399 goto NOTHING;
400 }
401 if (*n == '-') {
402 n++;
403 } else {
404 goto NOTHING;
405 }
406 if (*n == '\0') {
407 return;
408 } else {
409 char *v = strchr(n, '=');
410 size_t l = (int) (v ? (v - n) : strlen(n));
411 lmt_environment_state.flag = lmt_memory_malloc(l + 1);
412 if (lmt_environment_state.flag) {
413 memcpy(lmt_environment_state.flag, n, l);
414 lmt_environment_state.flag[l] = '\0';
415 if (v) {
416 v++;
417 l = (int) strlen(v);
418 lmt_environment_state.value = lmt_memory_malloc(l + 1);
419 if (lmt_environment_state.value) {
420 memcpy(lmt_environment_state.value, v, l);
421 lmt_environment_state.value[l] = '\0';
422 }
423 }
424 }
425 return;
426 }
427 NOTHING:
428 if (lmt_environment_state.name == NULL && i > 0) {
429 lmt_environment_state.name = option;
430 lmt_environment_state.npos = i;
431 }
432}
433
434
442
443static const char *suffixes[] = { "lmt", "lua", NULL };
444
445static void enginelib_parse_options(void)
446{
447
448 char *firstfile = (char*) lmt_memory_malloc(strlen(lmt_environment_state.ownpath) + strlen(lmt_environment_state.owncore) + 6);
449 for (int i = 0; suffixes[i]; i++) {
450 sprintf(firstfile, "%s/%s.%s", lmt_environment_state.ownpath, lmt_environment_state.owncore, suffixes[i]);
451
452 if (aux_is_readable(firstfile)) {
453 lmt_memory_free(lmt_engine_state.startup_filename);
454 lmt_engine_state.startup_filename = firstfile;
455 lmt_environment_state.luatex_lua_offset = 0;
456 lmt_engine_state.lua_only = 1;
457 lmt_engine_state.lua_init = 1;
458 return;
459 }
460 }
461 lmt_memory_free(firstfile);
462 firstfile = NULL;
463
464 for (int i = 1;;) {
465 if (i == lmt_environment_state.argc || *lmt_environment_state.argv[i] == '\0') {
466 break;
467 }
468 enginelib_check_option(lmt_environment_state.argv, i);
469 i++;
470 if (! lmt_environment_state.flag) {
471 continue;
472 } else if (strcmp(lmt_environment_state.flag, "luaonly") == 0) {
473 lmt_engine_state.lua_only = 1;
474 lmt_environment_state.luatex_lua_offset = i;
475 lmt_engine_state.lua_init = 1;
476 } else if (strcmp(lmt_environment_state.flag, "lua") == 0) {
477 if (lmt_environment_state.value) {
478 lmt_memory_free(lmt_engine_state.startup_filename);
479 lmt_engine_state.startup_filename = lmt_memory_strdup(lmt_environment_state.value);
480 lmt_environment_state.luatex_lua_offset = i - 1;
481 lmt_engine_state.lua_init = 1;
482 }
483 } else if (strcmp(lmt_environment_state.flag, "jobname") == 0) {
484 if (lmt_environment_state.value) {
485 lmt_memory_free(lmt_engine_state.startup_jobname);
486 lmt_engine_state.startup_jobname = lmt_memory_strdup(lmt_environment_state.value);
487 }
488 } else if (strcmp(lmt_environment_state.flag, "fmt") == 0) {
489 if (lmt_environment_state.value) {
490 lmt_memory_free(lmt_engine_state.dump_name);
491 lmt_engine_state.dump_name = lmt_memory_strdup(lmt_environment_state.value);
492 }
493 } else if (! lmt_engine_state.permit_loadlib && strcmp(lmt_environment_state.flag, "permitloadlib") == 0) {
494 lmt_engine_state.permit_loadlib = 1;
495 } else if (strcmp(lmt_environment_state.flag, "ini") == 0) {
496 lmt_main_state.run_state = initializing_state;
497 } else if (strcmp(lmt_environment_state.flag, "help") == 0) {
498 enginelib_show_help();
499 } else if (strcmp(lmt_environment_state.flag, "version") == 0) {
500 enginelib_show_version_info();
501 } else if (strcmp(lmt_environment_state.flag, "credits") == 0) {
502 enginelib_show_credits();
503 }
504 lmt_memory_free(lmt_environment_state.flag);
505 lmt_environment_state.flag = NULL;
506 if (lmt_environment_state.value) {
507 lmt_memory_free(lmt_environment_state.value);
508 lmt_environment_state.value = NULL;
509 }
510 }
511
512 if (lmt_environment_state.argv[lmt_environment_state.npos]) {
513 if (lmt_engine_state.lua_only) {
514 if (! lmt_engine_state.startup_filename) {
515 lmt_engine_state.startup_filename = lmt_memory_strdup(lmt_environment_state.argv[lmt_environment_state.npos]);
516 lmt_environment_state.luatex_lua_offset = lmt_environment_state.npos;
517 }
518 } else if (lmt_environment_state.argv[lmt_environment_state.npos][0] == '&') {
519
520 if (! lmt_engine_state.dump_name) {
521 lmt_engine_state.dump_name = lmt_memory_strdup(lmt_environment_state.argv[lmt_environment_state.npos] + 1);
522 }
523 } else if (lmt_environment_state.argv[lmt_environment_state.npos][0] == '*') {
524
525 if (! lmt_environment_state.input_name) {
526 lmt_environment_state.input_name = lmt_memory_strdup(lmt_environment_state.argv[lmt_environment_state.npos] + 1);
527 }
528 } else if (lmt_environment_state.argv[lmt_environment_state.npos][0] == '\\') {
529
530 } else {
531
532 firstfile = lmt_memory_strdup(lmt_environment_state.argv[lmt_environment_state.npos]);
533 for (int i = 0; suffixes[i]; i++) {
534 if (strstr(firstfile, suffixes[i]) == firstfile + strlen(firstfile) - 4){
535 if (lmt_engine_state.startup_filename) {
536 lmt_memory_free(firstfile);
537 } else {
538 lmt_engine_state.startup_filename = firstfile;
539 lmt_environment_state.luatex_lua_offset = lmt_environment_state.npos;
540 lmt_engine_state.lua_only = 1;
541 lmt_engine_state.lua_init = 1;
542 }
543 goto DONE;
544 }
545 }
546 if (lmt_environment_state.input_name) {
547 lmt_memory_free(firstfile);
548 } else {
549 lmt_environment_state.input_name = firstfile;
550 }
551 }
552 }
553 DONE:
554
555 if (lmt_environment_state.input_name) {
556
557 lmt_environment_state.argv[lmt_environment_state.npos] = enginelib_normalize_quotes(lmt_environment_state.input_name, "argument");
558 }
559}
560
561
568
569static void enginelib_set_locale(void)
570{
571 setlocale(LC_ALL, "C");
572}
573
574static void enginelib_update_options(void)
575{
576 int starttime = -1;
577 int utc = -1;
578 int permitloadlib = -1;
579 if (! lmt_environment_state.input_name) {
580 tex_engine_get_config_string("jobname", &lmt_environment_state.input_name);
581 }
582 if (! lmt_engine_state.dump_name) {
583 tex_engine_get_config_string("formatname", &lmt_engine_state.dump_name);
584 }
585 tex_engine_get_config_number("starttime", &starttime);
586 if (starttime >= 0) {
587 aux_set_start_time(starttime);
588 }
589 tex_engine_get_config_boolean("useutctime", &utc);
590 if (utc >= 0 && utc <= 1) {
591 lmt_engine_state.utc_time = utc;
592 }
593 tex_engine_get_config_boolean("permitloadlib", &permitloadlib);
594 if (permitloadlib >= 0) {
595 lmt_engine_state.permit_loadlib = permitloadlib;
596 }
597}
598
599
606
607void tex_engine_initialize(int ac, char **av)
608{
609
610 lmt_print_state.selector = terminal_selector_code;
611 lmt_environment_state.argc = aux_utf8_setargv(&lmt_environment_state.argv, av, ac);
612
613 lmt_engine_state.lua_only = 0;
614 lmt_engine_state.lua_init = 0;
615 lmt_engine_state.startup_filename = NULL;
616 lmt_engine_state.startup_jobname = NULL;
617 lmt_engine_state.engine_name = luametatex_name_lowercase;
618 lmt_engine_state.dump_name = NULL;
619 lmt_engine_state.luatex_banner = lmt_memory_strdup(lmt_version_state.banner);
620
621 lmt_environment_state.ownpath = aux_utf8_getownpath(lmt_environment_state.argv[0]);
622 lmt_environment_state.ownlink = aux_utf8_readlink(lmt_environment_state.ownpath);
623 enginelib_splitnames();
624 aux_set_run_time();
625
629
630 enginelib_parse_options();
631
632 enginelib_set_locale();
633
634 lmt_initialize();
635
636 lmt_initialize_functions(0);
637 lmt_initialize_properties(0);
638
639 lmt_initialize_languages();
640
641 lmt_initialize_interface();
642 lmt_nodelib_initialize();
643 lmt_tokenlib_initialize();
644 lmt_fontlib_initialize();
645
646 enginelib_prepare_cmdline(lmt_environment_state.luatex_lua_offset);
647 if (lmt_engine_state.startup_filename && ! aux_is_readable(lmt_engine_state.startup_filename)) {
648 lmt_memory_free(lmt_engine_state.startup_filename);
649 lmt_engine_state.startup_filename = NULL;
650 }
651
656 if (lmt_engine_state.startup_filename) {
657 lua_State *L = lmt_lua_state.lua_instance;
658 if (lmt_engine_state.lua_only) {
659 if (luaL_loadfile(L, lmt_engine_state.startup_filename)) {
660 tex_emergency_message("lua error", "startup file: %s", lmt_error_string(L, -1));
661 tex_emergency_exit();
662 } else if (lua_pcall(L, 0, 0, 0)) {
663 tex_emergency_message("lua error", "function call: %s", lmt_error_string(L, -1));
664 lmt_traceback(L);
665 tex_emergency_exit();
666 } else {
667
668 exit(lmt_error_state.default_exit_code);
669 }
670 } else {
671
672 if (luaL_loadfile(L, lmt_engine_state.startup_filename)) {
673 tex_emergency_message("lua error", "startup file: %s", lmt_error_string(L, -1));
674 tex_emergency_exit();
675 } else if (lua_pcall(L, 0, 0, 0)) {
676 tex_emergency_message("lua error", "function call: %s", lmt_error_string(L, -1));
677 lmt_traceback(L);
678 tex_emergency_exit();
679 }
680 enginelib_update_options();
681 tex_check_fmt_name();
682 }
683 } else if (lmt_engine_state.lua_init) {
684 tex_emergency_message("startup error", "no valid startup file given, quitting");
685 tex_emergency_exit();
686 } else {
687 tex_check_fmt_name();
688 }
689}
690
691
702
703static void tex_engine_get_config_numbers(const char *name, int *minimum, int *maximum, int *size, int *step)
704{
705 lua_State *L = lmt_lua_state.lua_instance;
706 if (L && size) {
707 int stacktop = lua_gettop(L);
708 if (lua_getglobal(L, "texconfig") == LUA_TTABLE) {
709 switch (lua_getfield(L, -1, name)) {
710 case LUA_TNUMBER:
711 if (size) {
712 *size = (int) lmt_roundnumber(L, -1);
713 }
714 break;
715 case LUA_TTABLE:
716 if (size && lua_getfield(L, -1, "size")) {
717 *size = (int) lmt_roundnumber(L, -1);
718 }
719 lua_pop(L, 1);
720 if (size && lua_getfield(L, -1, "plus")) {
721 *size += (int) lmt_roundnumber(L, -1);
722 }
723 lua_pop(L, 1);
724 if (step && lua_getfield(L, -1, "step")) {
725 int stp = (int) lmt_roundnumber(L, -1);
726 if (stp > *step) {
727 *step = stp;
728 }
729 }
730 break;
731 }
732 if (minimum && *size < *minimum) {
733 *size = *minimum;
734 } else if (maximum && *size > *maximum) {
735 *size = *maximum;
736 }
737 }
738 lua_settop(L, stacktop);
739 }
740}
741
742void tex_engine_set_memory_data(const char *name, memory_data *data)
743{
744 tex_engine_get_config_numbers(name, &data->minimum, &data->maximum, &data->size, &data->step);
745}
746
747void tex_engine_set_limits_data(const char *name, limits_data *data)
748{
749 tex_engine_get_config_numbers(name, &data->minimum, &data->maximum, &data->size, NULL);
750}
751
752void tex_engine_get_config_boolean(const char *name, int *target)
753{
754 lua_State *L = lmt_lua_state.lua_instance;
755 if (L) {
756 int stacktop = lua_gettop(L);
757 if (lua_getglobal(L, "texconfig") == LUA_TTABLE) {
758 switch (lua_getfield(L, -1, name)) {
759 case LUA_TBOOLEAN:
760 *target = lua_toboolean(L, -1);
761 break;
762 case LUA_TNUMBER:
763 *target = (lua_tointeger(L, -1) == 0 ? 0 : 1);
764 break;
765 }
766 }
767 lua_settop(L, stacktop);
768 }
769}
770
771void tex_engine_get_config_number(const char *name, int *target)
772{
773 tex_engine_get_config_numbers(name, NULL, NULL, target, NULL);
774}
775
776void tex_engine_get_config_string(const char *name, char **target)
777{
778 lua_State *L = lmt_lua_state.lua_instance;
779 if (L) {
780 int stacktop = lua_gettop(L);
781 if (lua_getglobal(L, "texconfig") == LUA_TTABLE) {
782 if (lua_getfield(L, -1, name) == LUA_TSTRING) {
783 *target = lmt_memory_strdup(lua_tostring(L, -1));
784 }
785 }
786 lua_settop(L, stacktop);
787 }
788}
789
790int tex_engine_run_config_function(const char *name)
791{
792 lua_State *L = lmt_lua_state.lua_instance;
793 if (L) {
794 if (lua_getglobal(L, "texconfig") == LUA_TTABLE) {
795 if (lua_getfield(L, -1, name) == LUA_TFUNCTION) {
796 if (! lua_pcall(L, 0, 0, 0)) {
797 return 1;
798 } else {
799
803 tex_emergency_message("lua", "this went wrong: %s\n", lmt_error_string(L, -1));
804 tex_emergency_exit();
805 }
806 }
807 }
808 }
809 return 0;
810}
811
812void tex_engine_check_configuration(void)
813{
814 tex_engine_run_config_function("init");
815}
816
817void lmt_make_table(
818 lua_State *L,
819 const char *tab,
820 const char *mttab,
821 lua_CFunction getfunc,
822 lua_CFunction setfunc
823)
824{
825 lua_pushstring(L, tab);
826 lua_newtable(L);
827 lua_settable(L, -3);
828 lua_pushstring(L, tab);
829 lua_gettable(L, -2);
830 luaL_newmetatable(L, mttab);
831 lua_pushstring(L, "__index");
832 lua_pushcfunction(L, getfunc);
833 lua_settable(L, -3);
834 lua_pushstring(L, "__newindex");
835 lua_pushcfunction(L, setfunc);
836 lua_settable(L, -3);
837 lua_setmetatable(L, -2);
838 lua_pop(L, 1);
839}
840
841static void *enginelib_aux_luaalloc(
842 void *ud,
843 void *ptr,
844 size_t osize,
845 size_t nsize
846)
847{
848 (void) ud;
849 lmt_lua_state.used_bytes += (int) (nsize - osize);
850 if (lmt_lua_state.used_bytes > lmt_lua_state.used_bytes_max) {
851 lmt_lua_state.used_bytes_max = lmt_lua_state.used_bytes;
852 }
853
854 if (nsize == 0) {
855
856 lmt_memory_free(ptr);
857 return NULL;
858 } else if (osize == 0) {
859
860 return lmt_memory_malloc(nsize);
861 } else {
862
863 return lmt_memory_realloc(ptr, nsize);
864 }
865}
866
867static int enginelib_aux_luapanic(lua_State *L)
868{
869 (void) L;
870 tex_emergency_message("lua", "panic: unprotected error in call to Lua API (%s)\n", lmt_error_string(L, -1));
871 return tex_emergency_exit();
872}
873
874static const luaL_Reg lmt_libs_lua_function_list[] = {
875 { "_G", luaopen_base },
876 { "package", luaopen_package },
877 { "table", luaopen_table },
878 { "io", luaopen_io },
879 { "os", luaopen_os },
880 { "string", luaopen_string },
881 { "math", luaopen_math },
882 { "debug", luaopen_debug },
883 { "lpeg", luaopen_lpeg },
884 { "utf8", luaopen_utf8 },
885 { "coroutine", luaopen_coroutine },
886 { NULL, NULL },
887};
888
889static const luaL_Reg lmt_libs_extra_function_list[] = {
890 { "md5", luaopen_md5 },
891 { "sha2", luaopen_sha2 },
892 { "aes", luaopen_aes },
893 { "basexx", luaopen_basexx },
894 { "lfs", luaopen_filelib },
895 { "fio", luaopen_fio },
896 { "sio", luaopen_sio },
897 { "sparse", luaopen_sparse },
898 { "xzip", luaopen_xzip },
899 { "xmath", luaopen_xmath },
900 { "xcomplex", luaopen_xcomplex },
901 { "xdecimal", luaopen_xdecimal },
902 { "posit", luaopen_posit },
903 { "potrace", luaopen_potrace },
904 { NULL, NULL },
905};
906
907static const luaL_Reg lmt_libs_socket_function_list[] = {
908 { "socket", luaopen_socket_core },
909 { "mime", luaopen_mime_core },
910 { NULL, NULL },
911};
912
913static const luaL_Reg lmt_libs_more_function_list[] = {
914 { "lua", luaopen_lua },
915 { "luac", luaopen_luac },
916 { "status", luaopen_status },
917 { "texio", luaopen_texio },
918 { NULL, NULL },
919};
920
921static const luaL_Reg lmt_libs_tex_function_list[] = {
922 { "tex", luaopen_tex },
923 { "token", luaopen_token },
924 { "node", luaopen_node },
925 { "callback", luaopen_callback },
926 { "font", luaopen_font },
927 { "language", luaopen_language },
928 { NULL, NULL },
929};
930
931static const luaL_Reg lmt_libs_mp_function_list[] = {
932 { "mplib", luaopen_mplib },
933 { NULL, NULL },
934};
935
936static const luaL_Reg lmt_libs_pdf_function_list[] = {
937 { "pdfe", luaopen_pdfe },
938 { "pdfdecode", luaopen_pdfdecode },
939 { "pngdecode", luaopen_pngdecode },
940 { NULL, NULL },
941};
942
943
949
950static void enginelib_luaopen_liblist(lua_State *L, const luaL_Reg *lib)
951{
952 for (; lib->func; lib++) {
953 luaL_requiref(L, lib->name, lib->func, 1);
954 lua_setglobal(L, lib->name);
955 }
956}
957
958
974
975static int loadlib_warning(lua_State *L)
976{
977 (void) L;
978 tex_normal_error("lua loadlib", "you can only load external libraries when --permitloadlib is given");
979 return 0;
980}
981
982static void enginelib_disable_loadlib(lua_State *L)
983{
984 int top = lua_gettop(L);
985 lua_getglobal(L, "package");
986 lua_pushliteral(L, "loadlib");
987 lua_pushcfunction(L, &loadlib_warning);
988 lua_rawset(L, -3);
989 lua_pushliteral(L, "searchers");
990 lua_rawget(L, -2);
991 lua_pushnil(L);
992 lua_rawseti(L, -2, 4);
993 lua_pushnil(L);
994 lua_rawseti(L, -2, 3);
995 lua_settop(L, top);
996}
997
998void lmt_initialize(void)
999{
1000 lua_State *L = lua_newstate(enginelib_aux_luaalloc, NULL);
1001 if (L) {
1002
1003 lua_gc(L, LUA_GCGEN, 0, 0);
1004
1005 lmt_lua_state.bytecode_max = -1;
1006 lmt_lua_state.bytecode_bytes = 0;
1007 lmt_lua_state.lua_instance = L;
1008
1009 lua_atpanic(L, &enginelib_aux_luapanic);
1010
1011 lmt_initialize_shared_keys(L);
1012 lmt_initialize_metapost_keys(L);
1013
1014 enginelib_luaopen_liblist(L, lmt_libs_lua_function_list);
1015
1016 enginelib_luaopen_liblist(L, lmt_libs_extra_function_list);
1017
1018 luaextend_os(L);
1019 luaextend_io(L);
1020 luaextend_string(L);
1021
1022 enginelib_luaopen_liblist(L, lmt_libs_socket_function_list);
1023
1024 enginelib_luaopen_liblist(L, lmt_libs_more_function_list);
1025
1026 if (! lmt_engine_state.lua_only) {
1027 enginelib_luaopen_liblist(L, lmt_libs_tex_function_list);
1028 }
1029 if (! lmt_engine_state.permit_loadlib) {
1030 enginelib_disable_loadlib(L);
1031 }
1032
1033 luaopen_optional(L);
1034
1035 enginelib_luaopen_liblist(L, lmt_libs_mp_function_list);
1036
1037 enginelib_luaopen_liblist(L, lmt_libs_pdf_function_list);
1038
1039 luaextend_xcomplex(L);
1040
1041 lua_createtable(L, 0, 0);
1042 lua_setglobal(L, "texconfig");
1043
1044
1045 } else {
1046 tex_emergency_message("system", "the Lua state can't be created");
1047 tex_emergency_exit();
1048 }
1049}
1050
1051int lmt_traceback(lua_State *L)
1052{
1053 const char *msg = lua_tostring(L, 1);
1054 luaL_traceback(L, L, msg ? msg : "<no message>", 1);
1055 return 1;
1056}
1057
1058void lmt_error(
1059 lua_State *L,
1060 const char *where,
1061 int detail,
1062 int is_fatal
1063)
1064{
1065 char* err = NULL;
1066 if (lua_type(L, -1) == LUA_TSTRING) {
1067 const char *luaerr = lua_tostring(L, -1);
1068 size_t len = strlen(luaerr) + strlen(where) + 32;
1069 err = (char *) lmt_memory_malloc((unsigned) len);
1070 if (err) {
1071 if (detail >= 0) {
1072 snprintf(err, len, "%s [%i]: %s", where, detail, luaerr);
1073 } else {
1074 snprintf(err, len, "%s: %s", where, luaerr);
1075 }
1076 if (lmt_error_state.last_lua_error) {
1077 lmt_memory_free(lmt_error_state.last_lua_error);
1078 }
1079 }
1080 lmt_error_state.last_lua_error = err;
1081 }
1082 if (is_fatal > 0) {
1083
1088 tex_normal_error("lua", err ? err : where);
1089
1093
1094 }
1095 else {
1096 tex_normal_warning("lua", err ? err : where);
1097 }
1098}
1099
1100
1107
1108void lmt_dump_engine_info(dumpstream f)
1109{
1110
1111 int x = (int) strlen(lmt_engine_state.engine_name);
1112 if (x > 0) {
1113 char *format_engine = lmt_memory_malloc((size_t) x + 5);
1114 if (format_engine) {
1115 memcpy(format_engine, lmt_engine_state.engine_name, (size_t) x + 1);
1116 for (int k = x; k <= x + 3; k++) {
1117 format_engine[k] = 0;
1118 }
1119 x = x + 4 - (x % 4);
1120 dump_int(f, x);
1121 dump_things(f, format_engine[0], x);
1122 lmt_memory_free(format_engine);
1123 return;
1124 }
1125 }
1126 tex_normal_error("system","dumping engine info failed");
1127}
1128
1129void lmt_undump_engine_info(dumpstream f)
1130{
1131 int x;
1132 undump_int(f, x);
1133 if ((x > 1) && (x < 256)) {
1134 char *format_engine = lmt_memory_malloc((size_t) x);
1135 if (format_engine) {
1136 undump_things(f, format_engine[0], x);
1137 format_engine[x - 1] = 0;
1138 if (strcmp(lmt_engine_state.engine_name, format_engine)) {
1139 lmt_memory_free(format_engine);
1140 goto BAD;
1141 } else {
1142 lmt_memory_free(format_engine);
1143 return;
1144 }
1145 }
1146 }
1147 BAD:
1148 tex_fatal_undump_error("engine");
1149}
1150
1151const char *lmt_error_string(lua_State* L, int index)
1152{
1153 const char *s = lua_tostring(L, index);
1154 return s ? s : "unknown error";
1155}
1156 |