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
36
37typedef struct environment_state_info {
38 char **argv;
39 int argc;
40 int npos;
41 char *flag;
42 char *value;
43 char *name;
44 char *ownpath;
45 char *ownbase;
46 char *ownname;
47 char *owncore;
48 char *ownlink;
49 char *input_name;
50 int luatex_lua_offset;
51 int padding;
52} environment_state_info;
53
54static environment_state_info lmt_environment_state = {
55 .argv = NULL,
56 .argc = 0,
57 .npos = 0,
58 .flag = NULL,
59 .value = NULL,
60 .name = NULL,
61 .ownpath = NULL,
62 .ownbase = NULL,
63 .ownname = NULL,
64 .owncore = NULL,
65 .ownlink = NULL,
66 .input_name = NULL,
67 .luatex_lua_offset = 0,
68 .padding = 0,
69};
70
71
72
73static void enginelib_splitnames(void)
74{
75 char *p = lmt_memory_strdup(lmt_environment_state.ownpath);
76
81
87
88 lmt_environment_state.ownbase = aux_basename(lmt_memory_strdup(p));
89 lmt_environment_state.ownname = aux_basename(lmt_memory_strdup(p));
90 lmt_environment_state.ownpath = aux_dirname(lmt_memory_strdup(p));
91 lmt_environment_state.ownlink = aux_utf8_readlink(lmt_environment_state.ownpath);
92
93 for (size_t i = 0; i < strlen(lmt_environment_state.ownname); i++) {
94 if (lmt_environment_state.ownname[i] == '.') {
95 lmt_environment_state.ownname[i] = '\0';
96 break ;
97 }
98 }
99 lmt_environment_state.owncore = lmt_memory_strdup(lmt_environment_state.ownname);
100 lmt_memory_free(p);
101}
102
103
104
105
106
107
108char *tex_engine_input_filename(void)
109{
110
111 return lmt_environment_state.npos > 0 && lmt_environment_state.npos < lmt_environment_state.argc ? lmt_environment_state.argv[lmt_environment_state.npos] : NULL;
112}
113
114
121
122static char *enginelib_normalize_quotes(const char* name, const char* mesg)
123{
124 char *ret = lmt_memory_malloc(strlen(name) + 3);
125 if (ret) {
126 int must_quote = strchr(name, ' ') != NULL;
127
128 int quoted = 0;
129 char *p = ret;
130 if (must_quote) {
131 *p++ = '"';
132 }
133 for (const char *q = name; *q; q++) {
134 if (*q == '"') {
135 quoted = ! quoted;
136 } else {
137 *p++ = *q;
138 }
139 }
140 if (must_quote) {
141 *p++ = '"';
142 }
143 *p = '\0';
144 if (quoted) {
145 tex_emergency_message("system", "unbalanced quotes in %s %s\n", mesg, name);
146 tex_emergency_exit();
147 }
148 }
149 return ret;
150}
151
152
176
177static void enginelib_show_help(void)
178{
179 puts(
180 "Usage: " luametatex_name_lowercase " --lua=FILE [OPTION]... [TEXNAME[.tex]] [COMMANDS]\n"
181 " or: " luametatex_name_lowercase " --lua=FILE [OPTION]... \\FIRST-LINE\n"
182 " or: " luametatex_name_lowercase " --lua=FILE [OPTION]... &FMT ARGS\n"
183 "\n"
184 "Run " luametatex_name_camelcase " on TEXNAME, usually creating TEXNAME.pdf. Any remaining COMMANDS"
185 "are processed as luatex input, after TEXNAME is read.\n"
186 "\n"
187 "Alternatively, if the first non-option argument begins with a backslash,\n"
188 luametatex_name_camelcase " interprets all non-option arguments as an input line.\n"
189 "\n"
190 "Alternatively, if the first non-option argument begins with a &, the next word\n"
191 "is taken as the FMT to read, overriding all else. Any remaining arguments are\n"
192 "processed as above.\n"
193 "\n"
194 "If no arguments or options are specified, prompt for input.\n"
195 "\n"
196 "The following regular options are understood:\n"
197 "\n"
198 " --credits display credits and some details and exit\n"
199 " --fmt=FORMAT load the format file FORMAT\n"
200 " --help display help and exit\n"
201 " --ini be ini" luametatex_name_lowercase ", for dumping formats\n"
202 " --jobname=STRING set the job name to STRING\n"
203 " --lua=FILE load and execute a lua initialization script\n"
204 " --version display version and exit\n"
205 "\n"
206 "Alternate behaviour models can be obtained by special switches\n"
207 "\n"
208 " --luaonly run a lua file, then exit\n"
209 "\n"
210 "Loading libraries from Lua is blocked unless one explicitly permits it:\n"
211 "\n"
212 " --permitloadlib permit loading of external libraries\n"
213 "\n"
214 "See the reference manual for more information about the startup process.\n"
215 "\n"
216 "Email bug reports to " luametatex_bug_address ".\n"
217 );
218 exit(EXIT_SUCCESS);
219}
220
221
225
226static void enginelib_show_version_info(void)
227{
228 tex_print_version_banner();
229 puts(
230 "\n"
231 "\n"
232 "Execute '" luametatex_name_lowercase " --credits' for credits and version details.\n"
233 "\n"
234 "There is NO warranty. Redistribution of this software is covered by the terms\n"
235 "of the GNU General Public License, version 2 or (at your option) any later\n"
236 "version. For more information about these matters, see the file named COPYING\n"
237 "and the LuaMetaTeX source.\n"
238 "\n"
239 "Functionality : level " LMT_TOSTRING(luametatex_development_id) "\n"
240 "Support : " luametatex_support_address "\n"
241 "Copyright : The Lua(Meta)TeX Team(s) (2005-2024+)\n"
242 "\n"
243 "The LuaMetaTeX project is related to ConTeXt development. This macro package\n"
244 "tightly integrates TeX and MetaPost in close cooperation with Lua. Updates will\n"
245 "happen in sync with ConTeXt and when needed. Don't be fooled by unchanged dates:\n"
246 "long term stability is the objective."
247 );
248 exit(EXIT_SUCCESS);
249}
250
251
276
277static void enginelib_show_credits(void)
278{
279 tex_print_version_banner();
280 puts(
281 "\n"
282 "\n"
283 "Here we mention those involved in the bits and pieces that define " luametatex_name_camelcase ". More details of\n"
284 "what comes from where can be found in the manual and other documents (that come with ConTeXt).\n"
285 "\n"
286 " luametatex : Hans Hagen, Alan Braslau, Mojca Miklavec, Wolfgang Schuster, Mikael Sundqvist\n"
287 "\n"
288 "It is a follow up on:\n"
289 "\n"
290 " luatex : Hans Hagen, Hartmut Henkel, Taco Hoekwater, Luigi Scarso\n"
291 "\n"
292 "This program itself builds upon the code from:\n"
293 "\n"
294 " tex : Donald Knuth\n"
295 "\n"
296 "We also took a few features from:\n"
297 "\n"
298 " etex : Peter Breitenlohner, Phil Taylor and friends\n"
299 "\n"
300 "The font expansion and protrusion code is derived from:\n"
301 "\n"
302 " pdftex : Han The Thanh and friends\n"
303 "\n"
304 "Part of the bidirectional text flow model is inspired by:\n"
305 "\n"
306 " omega : John Plaice and Yannis Haralambous\n"
307 " aleph : Giuseppe Bilotta\n"
308 "\n"
309 "Graphic support is originates in:\n"
310 "\n"
311 " metapost : John Hobby, Taco Hoekwater, Luigi Scarso, Hans Hagen and friends\n"
312 "\n"
313 "All this is opened up with:\n"
314 "\n"
315 " lua : Roberto Ierusalimschy, Waldemar Celes and Luiz Henrique de Figueiredo\n"
316 " lpeg : Roberto Ierusalimschy\n"
317 "\n"
318 "A few libraries are embedded, of which we mention:\n"
319 "\n"
320# ifdef MI_MALLOC_VERSION
321 " mimalloc : Daan Leijen (https://github.com/microsoft/mimalloc)\n"
322# endif
323 " miniz : Rich Geldreich etc\n"
324 " pplib : Paweł Jackowski (with partial code from libraries)\n"
325 " md5 : Peter Deutsch (with partial code from pplib libraries)\n"
326 " sha2 : Aaron D. Gifford (with partial code from pplib libraries)\n"
327 " socket : Diego Nehab (partial and adapted)\n"
328 " libcerf : Joachim Wuttke (adapted for MSVC)\n"
329 " decnumber : Mike Cowlishaw from IBM (one of the number models in MP)\n"
330 " avl : Richard (adapted a bit to fit in)\n"
331 " hjn : Raph Levien (derived from TeX's hyphenator, but adapted again)\n"
332 " softposit : S. H. Leong (Cerlane)\n"
333 " potrace : Peter Selinger\n"
334 "\n"
335 "The code base contains more names and references. Some libraries are partially adapted or\n"
336 "have been replaced. The MetaPost library has additional functionality, some of which is\n"
337 "experimental. The LuaMetaTeX project relates to ConTeXt. This LuaMetaTeX 2+ variant is a\n"
338 "lean and mean variant of LuaTeX 1+ but the core typesetting functionality is the same and\n"
339 "and has been extended in many aspects.\n"
340 "\n"
341 "There is a lightweight subsystem for optional libraries but here we also delegate as much\n"
342 "as possible to Lua. A few interfaces are provided by default, others can be added using a\n"
343 "simple foreign interface subsystem. Although this is provided and considered part of the\n"
344 "LuaMetaTeX engine it is not something ConTeXt depends (and will) depend on.\n"
345 "\n"
346 "version : " luametatex_version_string " | " LMT_TOSTRING(luametatex_development_id) "\n"
347 "format id : " LMT_TOSTRING(luametatex_format_fingerprint) "\n"
348# ifdef __DATE__
349 "date : " __TIME__ " | " __DATE__ "\n"
350# endif
351# ifdef LMT_COMPILER_USED
352 "compiler : " LMT_COMPILER_USED "\n"
353# endif
354 "lua : " LUA_VERSION "\n"
355 "luacformat : " LMT_TOSTRING(LUAC_FORMAT) "\n"
356# ifdef LMT_PERMIT_LUA_LIBRARIES
357 "libraries : enabled but not officially supported" "\n"
358# endif
359 );
360 printf("own path : %s\n", lmt_environment_state.ownpath);
361 printf("own base : %s\n", lmt_environment_state.ownbase);
362 printf("own name : %s\n", lmt_environment_state.ownname);
363 printf("own core : %s\n", lmt_environment_state.owncore);
364 printf("own link : %s\n", lmt_environment_state.ownlink ? lmt_environment_state.ownlink : "<no link>");
365 exit(EXIT_SUCCESS);
366}
367
368
374
375static void enginelib_prepare_cmdline(int zero_offset)
376{
377 lua_State *L = lmt_lua_state.lua_instance;
378
379 lua_createtable(L, lmt_environment_state.argc, 0);
380 for (lua_Integer i = 0; i < lmt_environment_state.argc; i++) {
381 lua_set_string_by_index(L, (int) (i - zero_offset), lmt_environment_state.argv[i]);
382 }
383 lua_setglobal(L, "arg");
384
385 lua_getglobal(L, "os");
386 lua_set_string_by_key(L, "selfbin", lmt_environment_state.argv[0]);
387 lua_set_string_by_key(L, "selfpath", lmt_environment_state.ownpath);
388 lua_set_string_by_key(L, "selfdir", lmt_environment_state.ownpath);
389 lua_set_string_by_key(L, "selflink", lmt_environment_state.ownlink);
390 lua_set_string_by_key(L, "selfname", lmt_environment_state.ownname);
391 lua_set_string_by_key(L, "selfcore", lmt_environment_state.owncore);
392 lua_createtable(L, lmt_environment_state.argc, 0);
393 for (lua_Integer i = 0; i < lmt_environment_state.argc; i++) {
394 lua_set_string_by_index(L, (int) i, lmt_environment_state.argv[i]);
395 }
396 lua_setfield(L, -2, "selfarg");
397}
398
399
410
411static void enginelib_check_option(char **options, int i)
412{
413 char *option = options[i];
414 char *n = option;
415 lmt_environment_state.flag = NULL;
416 lmt_environment_state.value = NULL;
417 if (*n == '-') {
418 n++;
419 } else {
420 goto NOTHING;
421 }
422 if (*n == '-') {
423 n++;
424 } else {
425 goto NOTHING;
426 }
427 if (*n == '\0') {
428 return;
429 } else {
430 char *v = strchr(n, '=');
431 size_t l = (int) (v ? (v - n) : strlen(n));
432 lmt_environment_state.flag = lmt_memory_malloc(l + 1);
433 if (lmt_environment_state.flag) {
434 memcpy(lmt_environment_state.flag, n, l);
435 lmt_environment_state.flag[l] = '\0';
436 if (v) {
437 v++;
438 l = (int) strlen(v);
439 lmt_environment_state.value = lmt_memory_malloc(l + 1);
440 if (lmt_environment_state.value) {
441 memcpy(lmt_environment_state.value, v, l);
442 lmt_environment_state.value[l] = '\0';
443 }
444 }
445 }
446 return;
447 }
448 NOTHING:
449 if (lmt_environment_state.name == NULL && i > 0) {
450 lmt_environment_state.name = option;
451 lmt_environment_state.npos = i;
452 }
453}
454
455
463
464static const char *suffixes[] = { "lmt", "lua", NULL };
465
466static void enginelib_parse_options(void)
467{
468
469 char *firstfile = (char*) lmt_memory_malloc(strlen(lmt_environment_state.ownpath) + strlen(lmt_environment_state.owncore) + 6);
470 for (int i = 0; suffixes[i]; i++) {
471 sprintf(firstfile, "%s/%s.%s", lmt_environment_state.ownpath, lmt_environment_state.owncore, suffixes[i]);
472
473 if (aux_is_readable(firstfile)) {
474 lmt_memory_free(lmt_engine_state.startup_filename);
475 lmt_engine_state.startup_filename = firstfile;
476 lmt_environment_state.luatex_lua_offset = 0;
477 lmt_engine_state.lua_only = 1;
478 lmt_engine_state.lua_init = 1;
479 return;
480 }
481 }
482 lmt_memory_free(firstfile);
483 firstfile = NULL;
484
485 for (int i = 1;;) {
486 if (i == lmt_environment_state.argc || *lmt_environment_state.argv[i] == '\0') {
487 break;
488 }
489 enginelib_check_option(lmt_environment_state.argv, i);
490 i++;
491 if (! lmt_environment_state.flag) {
492 continue;
493 } else if (strcmp(lmt_environment_state.flag, "luaonly") == 0) {
494 lmt_engine_state.lua_only = 1;
495 lmt_environment_state.luatex_lua_offset = i;
496 lmt_engine_state.lua_init = 1;
497 } else if (strcmp(lmt_environment_state.flag, "lua") == 0) {
498 if (lmt_environment_state.value) {
499 lmt_memory_free(lmt_engine_state.startup_filename);
500 lmt_engine_state.startup_filename = lmt_memory_strdup(lmt_environment_state.value);
501 lmt_environment_state.luatex_lua_offset = i - 1;
502 lmt_engine_state.lua_init = 1;
503 }
504 } else if (strcmp(lmt_environment_state.flag, "jobname") == 0) {
505 if (lmt_environment_state.value) {
506 lmt_memory_free(lmt_engine_state.startup_jobname);
507 lmt_engine_state.startup_jobname = lmt_memory_strdup(lmt_environment_state.value);
508 }
509 } else if (strcmp(lmt_environment_state.flag, "fmt") == 0) {
510 if (lmt_environment_state.value) {
511 lmt_memory_free(lmt_engine_state.dump_name);
512 lmt_engine_state.dump_name = lmt_memory_strdup(lmt_environment_state.value);
513 }
514 } else if (! lmt_engine_state.permit_loadlib && strcmp(lmt_environment_state.flag, "permitloadlib") == 0) {
515 lmt_engine_state.permit_loadlib = 1;
516 } else if (strcmp(lmt_environment_state.flag, "ini") == 0) {
517 lmt_main_state.run_state = initializing_state;
518 } else if (strcmp(lmt_environment_state.flag, "help") == 0) {
519 enginelib_show_help();
520 } else if (strcmp(lmt_environment_state.flag, "version") == 0) {
521 enginelib_show_version_info();
522 } else if (strcmp(lmt_environment_state.flag, "credits") == 0) {
523 enginelib_show_credits();
524 }
525 lmt_memory_free(lmt_environment_state.flag);
526 lmt_environment_state.flag = NULL;
527 if (lmt_environment_state.value) {
528 lmt_memory_free(lmt_environment_state.value);
529 lmt_environment_state.value = NULL;
530 }
531 }
532
533 if (lmt_environment_state.argv[lmt_environment_state.npos]) {
534 if (lmt_engine_state.lua_only) {
535 if (! lmt_engine_state.startup_filename) {
536 lmt_engine_state.startup_filename = lmt_memory_strdup(lmt_environment_state.argv[lmt_environment_state.npos]);
537 lmt_environment_state.luatex_lua_offset = lmt_environment_state.npos;
538 }
539 } else if (lmt_environment_state.argv[lmt_environment_state.npos][0] == '&') {
540
541 if (! lmt_engine_state.dump_name) {
542 lmt_engine_state.dump_name = lmt_memory_strdup(lmt_environment_state.argv[lmt_environment_state.npos] + 1);
543 }
544 } else if (lmt_environment_state.argv[lmt_environment_state.npos][0] == '*') {
545
546 if (! lmt_environment_state.input_name) {
547 lmt_environment_state.input_name = lmt_memory_strdup(lmt_environment_state.argv[lmt_environment_state.npos] + 1);
548 }
549 } else if (lmt_environment_state.argv[lmt_environment_state.npos][0] == '\\') {
550
551 } else {
552
553 firstfile = lmt_memory_strdup(lmt_environment_state.argv[lmt_environment_state.npos]);
554 for (int i = 0; suffixes[i]; i++) {
555 if (strstr(firstfile, suffixes[i]) == firstfile + strlen(firstfile) - 4){
556 if (lmt_engine_state.startup_filename) {
557 lmt_memory_free(firstfile);
558 } else {
559 lmt_engine_state.startup_filename = firstfile;
560 lmt_environment_state.luatex_lua_offset = lmt_environment_state.npos;
561 lmt_engine_state.lua_only = 1;
562 lmt_engine_state.lua_init = 1;
563 }
564 goto DONE;
565 }
566 }
567 if (lmt_environment_state.input_name) {
568 lmt_memory_free(firstfile);
569 } else {
570 lmt_environment_state.input_name = firstfile;
571 }
572 }
573 }
574 DONE:
575
576 if (lmt_environment_state.input_name) {
577
578 lmt_environment_state.argv[lmt_environment_state.npos] = enginelib_normalize_quotes(lmt_environment_state.input_name, "argument");
579 }
580}
581
582
590
591static void enginelib_set_locale(void)
592{
593 setlocale(LC_ALL, "C");
594}
595
596static void enginelib_update_options(void)
597{
598 int starttime = -1;
599 int utc = -1;
600 int permitloadlib = -1;
601 if (! lmt_environment_state.input_name) {
602 tex_engine_get_config_string("jobname", &lmt_environment_state.input_name);
603 }
604 if (! lmt_engine_state.dump_name) {
605 tex_engine_get_config_string("formatname", &lmt_engine_state.dump_name);
606 }
607 tex_engine_get_config_number("starttime", &starttime);
608 if (starttime >= 0) {
609 aux_set_start_time(starttime);
610 }
611 tex_engine_get_config_boolean("useutctime", &utc);
612 if (utc >= 0 && utc <= 1) {
613 lmt_engine_state.utc_time = utc;
614 }
615 tex_engine_get_config_boolean("permitloadlib", &permitloadlib);
616 if (permitloadlib >= 0) {
617 lmt_engine_state.permit_loadlib = permitloadlib;
618 }
619}
620
621
628
629void tex_engine_initialize(int ac, char **av)
630{
631
632 lmt_print_state.selector = terminal_selector_code;
633 lmt_environment_state.argc = aux_utf8_setargv(&lmt_environment_state.argv, av, ac);
634
635 lmt_engine_state.lua_only = 0;
636 lmt_engine_state.lua_init = 0;
637 lmt_engine_state.startup_filename = NULL;
638 lmt_engine_state.startup_jobname = NULL;
639 lmt_engine_state.engine_name = luametatex_name_lowercase;
640 lmt_engine_state.dump_name = NULL;
641 lmt_engine_state.luatex_banner = lmt_memory_strdup(lmt_version_state.banner);
642
643 lmt_environment_state.ownpath = aux_utf8_getownpath(lmt_environment_state.argv[0]);
644 lmt_environment_state.ownlink = aux_utf8_readlink(lmt_environment_state.ownpath);
645 enginelib_splitnames();
646 aux_set_run_time();
647
651
652 enginelib_parse_options();
653
654 enginelib_set_locale();
655
656 lmt_initialize();
657
658 lmt_initialize_functions(0);
659 lmt_initialize_properties(0);
660
661 lmt_initialize_languages();
662
663 lmt_initialize_interface();
664 lmt_nodelib_initialize();
665 lmt_tokenlib_initialize();
666 lmt_fontlib_initialize();
667
668 enginelib_prepare_cmdline(lmt_environment_state.luatex_lua_offset);
669 if (lmt_engine_state.startup_filename && ! aux_is_readable(lmt_engine_state.startup_filename)) {
670 lmt_memory_free(lmt_engine_state.startup_filename);
671 lmt_engine_state.startup_filename = NULL;
672 }
673
678 if (lmt_engine_state.startup_filename) {
679 lua_State *L = lmt_lua_state.lua_instance;
680 if (lmt_engine_state.lua_only) {
681 if (luaL_loadfile(L, lmt_engine_state.startup_filename)) {
682 tex_emergency_message("lua error", "startup file: %s", lmt_error_string(L, -1));
683 tex_emergency_exit();
684 } else if (lua_pcall(L, 0, 0, 0)) {
685 tex_emergency_message("lua error", "function call: %s", lmt_error_string(L, -1));
686 lmt_traceback(L);
687 tex_emergency_exit();
688 } else {
689
690 exit(lmt_error_state.default_exit_code);
691 }
692 } else {
693
694 if (luaL_loadfile(L, lmt_engine_state.startup_filename)) {
695 tex_emergency_message("lua error", "startup file: %s", lmt_error_string(L, -1));
696 tex_emergency_exit();
697 } else if (lua_pcall(L, 0, 0, 0)) {
698 tex_emergency_message("lua error", "function call: %s", lmt_error_string(L, -1));
699 lmt_traceback(L);
700 tex_emergency_exit();
701 }
702 enginelib_update_options();
703 tex_check_fmt_name();
704 }
705 } else if (lmt_engine_state.lua_init) {
706 tex_emergency_message("startup error", "no valid startup file given, quitting");
707 tex_emergency_exit();
708 } else {
709 tex_check_fmt_name();
710 }
711}
712
713
724
725static void tex_engine_get_config_numbers(const char *name, int *minimum, int *maximum, int *size, int *step)
726{
727 lua_State *L = lmt_lua_state.lua_instance;
728 if (L && size) {
729 int stacktop = lua_gettop(L);
730 if (lua_getglobal(L, "texconfig") == LUA_TTABLE) {
731 switch (lua_getfield(L, -1, name)) {
732 case LUA_TNUMBER:
733 if (size) {
734 *size = (int) lmt_roundnumber(L, -1);
735 }
736 break;
737 case LUA_TTABLE:
738 if (size && lua_getfield(L, -1, "size")) {
739 *size = (int) lmt_roundnumber(L, -1);
740 }
741 lua_pop(L, 1);
742 if (size && lua_getfield(L, -1, "plus")) {
743 *size += (int) lmt_roundnumber(L, -1);
744 }
745 lua_pop(L, 1);
746 if (step && lua_getfield(L, -1, "step")) {
747 int stp = (int) lmt_roundnumber(L, -1);
748 if (stp > *step) {
749 *step = stp;
750 }
751 }
752 break;
753 }
754 if (minimum && *size < *minimum) {
755 *size = *minimum;
756 } else if (maximum && *size > *maximum) {
757 *size = *maximum;
758 }
759 }
760 lua_settop(L, stacktop);
761 }
762}
763
764void tex_engine_set_memory_data(const char *name, memory_data *data)
765{
766 tex_engine_get_config_numbers(name, &data->minimum, &data->maximum, &data->size, &data->step);
767}
768
769void tex_engine_set_limits_data(const char *name, limits_data *data)
770{
771 tex_engine_get_config_numbers(name, &data->minimum, &data->maximum, &data->size, NULL);
772}
773
774void tex_engine_get_config_boolean(const char *name, int *target)
775{
776 lua_State *L = lmt_lua_state.lua_instance;
777 if (L) {
778 int stacktop = lua_gettop(L);
779 if (lua_getglobal(L, "texconfig") == LUA_TTABLE) {
780 switch (lua_getfield(L, -1, name)) {
781 case LUA_TBOOLEAN:
782 *target = lua_toboolean(L, -1);
783 break;
784 case LUA_TNUMBER:
785 *target = (lua_tointeger(L, -1) == 0 ? 0 : 1);
786 break;
787 }
788 }
789 lua_settop(L, stacktop);
790 }
791}
792
793void tex_engine_get_config_number(const char *name, int *target)
794{
795 tex_engine_get_config_numbers(name, NULL, NULL, target, NULL);
796}
797
798void tex_engine_get_config_string(const char *name, char **target)
799{
800 lua_State *L = lmt_lua_state.lua_instance;
801 if (L) {
802 int stacktop = lua_gettop(L);
803 if (lua_getglobal(L, "texconfig") == LUA_TTABLE) {
804 if (lua_getfield(L, -1, name) == LUA_TSTRING) {
805 *target = lmt_memory_strdup(lua_tostring(L, -1));
806 }
807 }
808 lua_settop(L, stacktop);
809 }
810}
811
812int tex_engine_run_config_function(const char *name)
813{
814 lua_State *L = lmt_lua_state.lua_instance;
815 if (L) {
816 if (lua_getglobal(L, "texconfig") == LUA_TTABLE) {
817 if (lua_getfield(L, -1, name) == LUA_TFUNCTION) {
818 if (! lua_pcall(L, 0, 0, 0)) {
819 return 1;
820 } else {
821
825 tex_emergency_message("lua", "this went wrong: %s\n", lmt_error_string(L, -1));
826 tex_emergency_exit();
827 }
828 }
829 }
830 }
831 return 0;
832}
833
834void tex_engine_check_configuration(void)
835{
836 tex_engine_run_config_function("init");
837}
838
839void lmt_make_table(
840 lua_State *L,
841 const char *tab,
842 const char *mttab,
843 lua_CFunction getfunc,
844 lua_CFunction setfunc
845)
846{
847 lua_pushstring(L, tab);
848 lua_newtable(L);
849 lua_settable(L, -3);
850 lua_pushstring(L, tab);
851 lua_gettable(L, -2);
852 luaL_newmetatable(L, mttab);
853 lua_pushstring(L, "__index");
854 lua_pushcfunction(L, getfunc);
855 lua_settable(L, -3);
856 lua_pushstring(L, "__newindex");
857 lua_pushcfunction(L, setfunc);
858 lua_settable(L, -3);
859 lua_setmetatable(L, -2);
860 lua_pop(L, 1);
861}
862
863
868
869# if (1)
870
871static void enginelib_initialize_memory_pool(void)
872{
873
874}
875
876static void *enginelib_aux_luaalloc(
877 void *ud,
878 void *ptr,
879 size_t osize,
880 size_t nsize
881)
882{
883 (void) ud;
884 lmt_lua_state.used_bytes += (int) (nsize - osize);
885 if (lmt_lua_state.used_bytes > lmt_lua_state.used_bytes_max) {
886 lmt_lua_state.used_bytes_max = lmt_lua_state.used_bytes;
887 }
888 if (nsize == 0) {
889
890 lmt_memory_free(ptr);
891 return NULL;
892 } else if (osize == 0) {
893
894 return lmt_memory_malloc(nsize);
895 } else {
896
897 return lmt_memory_realloc(ptr, nsize);
898 }
899}
900
901# else
902
903# define max_memory_pool 96
904# define max_memory_slot (8*1024)
905
906typedef struct memory_pool_entry {
907 unsigned size;
908 unsigned max;
909 void ** data;
910} memory_pool_entry;
911
912static memory_pool_entry memory_pool[max_memory_pool+1];
913
914static void enginelib_initialize_memory_pool(void)
915{
916 for (int i = 0; i < max_memory_pool; i++) {
917 switch (i) {
918 case 4: case 8: case 12: case 24: case 48: case 96:
919 memory_pool[i].data = lmt_memory_calloc(max_memory_slot, sizeof(void *));
920 memory_pool[i].size = 0;
921 memory_pool[i].max = max_memory_slot - 1;
922 break;
923 }
924 }
925}
926
927static void *enginelib_aux_luaalloc(
928 void *ud,
929 void *ptr,
930 size_t osize,
931 size_t nsize
932)
933{
934 (void) ud;
935 lmt_lua_state.used_bytes += (int) (nsize - osize);
936 if (lmt_lua_state.used_bytes > lmt_lua_state.used_bytes_max) {
937 lmt_lua_state.used_bytes_max = lmt_lua_state.used_bytes;
938 }
939 if (nsize == 0) {
940 if (ptr) {
941 switch (osize) {
942 case 4: case 8: case 12: case 24: case 48: case 96:
943 {
944 unsigned s = (unsigned) osize;
945 if (memory_pool[s].size < memory_pool[s].max) {
946 memory_pool[s].data[memory_pool[s].size] = ptr;
947
948 memory_pool[s].size++;
949 break;
950 } else {
951
952 }
953 }
954 default:
955
956 lmt_memory_free(ptr);
957 }
958 }
959 return NULL;
960 } else if (osize == 0) {
961 switch (nsize) {
962 case 4: case 8: case 12: case 24: case 48: case 96:
963 {
964 unsigned s = (unsigned) nsize;
965 if (memory_pool[s].size > 0) {
966 memory_pool[s].size--;
967 void * p = memory_pool[s].data[memory_pool[s].size];
968
969 return p;
970 } else {
971
972 }
973 }
974 default:
975
976 return lmt_memory_malloc(nsize);
977 }
978 } else {
979 if (ptr && nsize && nsize > osize) {
980 switch (nsize) {
981 case 4: case 8: case 12: case 24: case 48: case 96:
982 {
983 unsigned s = (unsigned) nsize;
984 if (memory_pool[s].size > 0) {
985 memory_pool[s].size--;
986 void * p = memory_pool[s].data[memory_pool[s].size];
987 if (osize) {
988 memcpy(p, ptr, osize);
989 }
990
991 switch (osize) {
992 case 4: case 8: case 12: case 24: case 48: case 96:
993 {
994 unsigned s = (unsigned) osize;
995 if (memory_pool[s].size < memory_pool[s].max) {
996 memory_pool[s].data[memory_pool[s].size] = ptr;
997 memory_pool[s].size++;
998 return p;
999 } else {
1000 break;
1001 }
1002 }
1003 }
1004 lmt_memory_free(ptr);
1005 return p;
1006 } else {
1007
1008 }
1009 }
1010 }
1011 }
1012
1013 return lmt_memory_realloc(ptr, nsize);
1014 }
1015}
1016
1017# endif
1018
1019static int enginelib_aux_luapanic(lua_State *L)
1020{
1021 (void) L;
1022 tex_emergency_message("lua", "panic: unprotected error in call to Lua API (%s)\n", lmt_error_string(L, -1));
1023 return tex_emergency_exit();
1024}
1025
1026static const luaL_Reg lmt_libs_lua_function_list[] = {
1027 { "_G", luaopen_base },
1028 { "package", luaopen_package },
1029 { "table", luaopen_table },
1030 { "io", luaopen_io },
1031 { "os", luaopen_os },
1032 { "string", luaopen_string },
1033 { "math", luaopen_math },
1034 { "debug", luaopen_debug },
1035 { "lpeg", luaopen_lpeg },
1036 { "utf8", luaopen_utf8 },
1037 { "coroutine", luaopen_coroutine },
1038 { NULL, NULL },
1039};
1040
1041static const luaL_Reg lmt_libs_extra_function_list[] = {
1042 { "md5", luaopen_md5 },
1043 { "sha2", luaopen_sha2 },
1044 { "aes", luaopen_aes },
1045 { "basexx", luaopen_basexx },
1046 { "lfs", luaopen_filelib },
1047 { "fio", luaopen_fio },
1048 { "sio", luaopen_sio },
1049 { "sparse", luaopen_sparse },
1050 { "xzip", luaopen_xzip },
1051 { "xmath", luaopen_xmath },
1052 { "xcomplex", luaopen_xcomplex },
1053 { "xdecimal", luaopen_xdecimal },
1054 { "posit", luaopen_posit },
1055 { "potrace", luaopen_potrace },
1056 { NULL, NULL },
1057};
1058
1059static const luaL_Reg lmt_libs_socket_function_list[] = {
1060 { "socket", luaopen_socket_core },
1061 { "mime", luaopen_mime_core },
1062 { NULL, NULL },
1063};
1064
1065static const luaL_Reg lmt_libs_more_function_list[] = {
1066 { "lua", luaopen_lua },
1067 { "luac", luaopen_luac },
1068 { "status", luaopen_status },
1069 { "texio", luaopen_texio },
1070 { NULL, NULL },
1071};
1072
1073static const luaL_Reg lmt_libs_tex_function_list[] = {
1074 { "tex", luaopen_tex },
1075 { "token", luaopen_token },
1076 { "node", luaopen_node },
1077 { "callback", luaopen_callback },
1078 { "font", luaopen_font },
1079 { "language", luaopen_language },
1080 { NULL, NULL },
1081};
1082
1083static const luaL_Reg lmt_libs_mp_function_list[] = {
1084 { "mplib", luaopen_mplib },
1085 { NULL, NULL },
1086};
1087
1088static const luaL_Reg lmt_libs_pdf_function_list[] = {
1089 { "pdfe", luaopen_pdfe },
1090 { "pdfdecode", luaopen_pdfdecode },
1091 { "pngdecode", luaopen_pngdecode },
1092 { NULL, NULL },
1093};
1094
1095
1101
1102static void enginelib_luaopen_liblist(lua_State *L, const luaL_Reg *lib)
1103{
1104 for (; lib->func; lib++) {
1105 luaL_requiref(L, lib->name, lib->func, 1);
1106 lua_setglobal(L, lib->name);
1107 }
1108}
1109
1110
1126
1127static int loadlib_warning(lua_State *L)
1128{
1129 (void) L;
1130 tex_normal_error("lua loadlib", "you can only load external libraries when --permitloadlib is given");
1131 return 0;
1132}
1133
1134static void enginelib_disable_loadlib(lua_State *L)
1135{
1136 int top = lua_gettop(L);
1137 lua_getglobal(L, "package");
1138 lua_pushliteral(L, "loadlib");
1139 lua_pushcfunction(L, &loadlib_warning);
1140 lua_rawset(L, -3);
1141 lua_pushliteral(L, "searchers");
1142 lua_rawget(L, -2);
1143 lua_pushnil(L);
1144 lua_rawseti(L, -2, 4);
1145 lua_pushnil(L);
1146 lua_rawseti(L, -2, 3);
1147 lua_settop(L, top);
1148}
1149
1150
1159
1160void lmt_initialize(void)
1161{
1162 lua_State *L = NULL;
1163 int seed = luaL_makeseed(L);
1164 L = lua_newstate(enginelib_aux_luaalloc, NULL, seed);
1165enginelib_initialize_memory_pool();
1166 if (L) {
1167
1168 lua_gc(L, LUA_GCGEN, 0, 0);
1169
1170 lmt_lua_state.bytecode_max = -1;
1171 lmt_lua_state.bytecode_bytes = 0;
1172 lmt_lua_state.lua_instance = L;
1173
1174 lua_atpanic(L, &enginelib_aux_luapanic);
1175
1176 lmt_initialize_shared_keys(L);
1177 lmt_initialize_metapost_keys(L);
1178
1179 enginelib_luaopen_liblist(L, lmt_libs_lua_function_list);
1180
1181 enginelib_luaopen_liblist(L, lmt_libs_extra_function_list);
1182
1183 luaextend_os(L);
1184 luaextend_io(L);
1185 luaextend_string(L);
1186
1187
1188 enginelib_luaopen_liblist(L, lmt_libs_socket_function_list);
1189
1190 enginelib_luaopen_liblist(L, lmt_libs_more_function_list);
1191
1192 if (! lmt_engine_state.lua_only) {
1193 enginelib_luaopen_liblist(L, lmt_libs_tex_function_list);
1194 }
1195 if (! lmt_engine_state.permit_loadlib) {
1196 enginelib_disable_loadlib(L);
1197 }
1198
1199 luaopen_optional(L);
1200
1201 enginelib_luaopen_liblist(L, lmt_libs_mp_function_list);
1202
1203 enginelib_luaopen_liblist(L, lmt_libs_pdf_function_list);
1204
1205 luaextend_xcomplex(L);
1206
1207 lua_createtable(L, 0, 0);
1208 lua_setglobal(L, "texconfig");
1209
1210
1211 } else {
1212 tex_emergency_message("system", "the Lua state can't be created");
1213 tex_emergency_exit();
1214 }
1215}
1216
1217int lmt_traceback(lua_State *L)
1218{
1219 const char *msg = lua_tostring(L, 1);
1220 luaL_traceback(L, L, msg ? msg : "<no message>", 1);
1221 return 1;
1222}
1223
1224void lmt_error(
1225 lua_State *L,
1226 const char *where,
1227 int detail,
1228 int is_fatal
1229)
1230{
1231 char* err = NULL;
1232 if (lua_type(L, -1) == LUA_TSTRING) {
1233 const char *luaerr = lua_tostring(L, -1);
1234 size_t len = strlen(luaerr) + strlen(where) + 32;
1235 err = (char *) lmt_memory_malloc((unsigned) len);
1236 if (err) {
1237 if (detail >= 0) {
1238 snprintf(err, len, "%s [%i]: %s", where, detail, luaerr);
1239 } else {
1240 snprintf(err, len, "%s: %s", where, luaerr);
1241 }
1242 if (lmt_error_state.last_lua_error) {
1243 lmt_memory_free(lmt_error_state.last_lua_error);
1244 }
1245 }
1246 lmt_error_state.last_lua_error = err;
1247 }
1248 if (is_fatal > 0) {
1249
1254 tex_normal_error("lua", err ? err : where);
1255
1259
1260 }
1261 else {
1262 tex_normal_warning("lua", err ? err : where);
1263 }
1264}
1265
1266
1273
1274void lmt_dump_engine_info(dumpstream f)
1275{
1276
1277 int x = (int) strlen(lmt_engine_state.engine_name);
1278 if (x > 0) {
1279 char *format_engine = lmt_memory_malloc((size_t) x + 5);
1280 if (format_engine) {
1281 memcpy(format_engine, lmt_engine_state.engine_name, (size_t) x + 1);
1282 for (int k = x; k <= x + 3; k++) {
1283 format_engine[k] = 0;
1284 }
1285 x = x + 4 - (x % 4);
1286 dump_int(f, x);
1287 dump_things(f, format_engine[0], x);
1288 lmt_memory_free(format_engine);
1289 return;
1290 }
1291 }
1292 tex_normal_error("system","dumping engine info failed");
1293}
1294
1295void lmt_undump_engine_info(dumpstream f)
1296{
1297 int x;
1298 undump_int(f, x);
1299 if ((x > 1) && (x < 256)) {
1300 char *format_engine = lmt_memory_malloc((size_t) x);
1301 if (format_engine) {
1302 undump_things(f, format_engine[0], x);
1303 format_engine[x - 1] = 0;
1304 if (strcmp(lmt_engine_state.engine_name, format_engine)) {
1305 lmt_memory_free(format_engine);
1306 goto BAD;
1307 } else {
1308 lmt_memory_free(format_engine);
1309 return;
1310 }
1311 }
1312 }
1313 BAD:
1314 tex_fatal_undump_error("engine");
1315}
1316
1317const char *lmt_error_string(lua_State* L, int index)
1318{
1319 const char *s = lua_tostring(L, index);
1320 return s ? s : "unknown error";
1321}
1322 |