lmtenginelib.c /size: 51 Kb    last modification: 2025-02-21 11:03
1/*
2    See license.txt in the root of this project.
3*/
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/*tex
20
21    We assume that the strings are proper \UTF\ and in \MSWINDOWS\ we handle wide characters to get
22    that right. The conversions are hidden for the user. 
23
24    The command line has to be interpreted because we have to pick up the initial filename. We do 
25    handle double quotes here (so that we can have spaces) but we don't do any further magic. So, 
26    we don't do wildcard expansion here. If the operating system does that, so be it: we can deal 
27    with it later and also decide to either or not glob files. In the case of \CONTEXT\ one normally
28    passes explicit names, or uses --pattern when applicable. All these things are shell dependent 
29    anyway. On Windows expansion is up to the application anyway, which means interpretation and 
30    possible errors. 
31
32    On the other hand I might support single quotes as well, so that we can say --foo='bar"bar' 
33    just like in Lua but then I need to check if that works out the same on lin and win. 
34
35*/
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/*tex todo: make helpers in loslibext which has similar code */
72
73static void enginelib_splitnames(void)
74{
75    char *p = lmt_memory_strdup(lmt_environment_state.ownpath); /*tex We need to make copies! */
76    /*
77        We loose some here but not enough to worry about. Maybe eventually we will use our own
78        |basename| and |dirname| anyway. I need to check if all are set to something we can 
79        indeed free. 
80    */
81    /*
82    if (lmt_environment_state.ownbase) { lmt_memory_free(lmt_environment_state.ownbase); }
83    if (lmt_environment_state.ownname) { lmt_memory_free(lmt_environment_state.ownbase); }
84    if (lmt_environment_state.ownpath) { lmt_memory_free(lmt_environment_state.ownbase); }
85    if (lmt_environment_state.ownlink) { lmt_memory_free(lmt_environment_state.ownlink); }
86    */
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)); /* We could use p and not free later, but this is cleaner. */
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/*tex A bunch of internalized strings: see |linterface.h |.*/
104
105/* declare_shared_lua_keys; */
106/* declare_metapost_lua_keys; */
107
108char *tex_engine_input_filename(void)
109{
110    /*tex When npos equals zero we have no filename i.e. nothing that doesn't start with |--|. */
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/*tex
115
116    Filenames can have spaces in which case (double) quotes are used to indicate the bounds of the
117    string. At the \TEX\ level curly braces are also an option but these are dealt with in the
118    scanner.
119
120*/
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        /* Leave room for quotes and NUL. */
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/*
153
154    We support a minimum set of options but more can be supported by supplying an (startup)
155    initialization script and/or by setting values in the |texconfig| table. At some point we might
156    provide some default initiazation script but that's for later. In fact, a bug in \LUATEX\ <
157    1.10 made some of the command line options get lost anyway due to setting their values before
158    checking the config table (probably introduced at some time). As no one noticed that anyway,
159    removing these from the commandline is okay.
160
161    Part of the commandline handler is providing (minimal) help information and reporting credits
162    (more credits can be found in the source file). Here comes the basic help.
163
164    At some point I will likely add a |--permitloadlib| flag and block loading of libraries when
165    that flag is not given so that we satisfy operating systems and/or distributions that have some
166    restrictions on loading libraries. It also means that the optional modules will be (un)locked,
167    but we can control that in the runners so it's no big deal because we will never depend on
168    external code for the \CONTEXT\ core features.
169
170    Commandline options that block |os.execute|, |io.popen|, the debugger and socket libraries etc.
171    will not make it into \LUAMETATEX. If security is a concern there are always ways around it
172    (not that I'll be too public about unplugged holes in engines). One can deal with most issues 
173    in \LUA\ anyway. 
174
175*/
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/*tex
222
223    This is the minimal version info display.  The credits option provides a bit more information.
224*/
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/*tex
252
253    We only mention the most relevelant credits here. The first part is there to indicate a bit of
254    history. A very large part of the code, of course, comes from Don Knuths original \TEX, and the
255    same is true for most documentation!
256
257    Most of the \ETEX\ extensions are present too. Much of the expansion and protrusion code
258    originates in \PDFTEX\ but we don't have any of its backend code. From \OMEGA\ (\ALEPH) we took
259    bits and pieces too, for instance the basics of handling directions but at this point we only
260    have two directions left (that don't need much code). One features that sticks are the left-
261    and right boxes.
262
263    The \METAPOST\ library is an important component and also add quite some code. Here we use a
264    stripped down version of the version 2 library with some extra additions.
265
266    We take \LUA\ as it is. In the meantime we went from \LUA\ 5.2 to 5.3 to 5.4 and will follow up
267    on what makes sense. For as far as possible no changes are made but there are some configuration
268    options in use. We use an \UTF8\ aware setup. Of course \LPEG\ is part of the deal.
269
270    The lean and mean \PDF\ library is made for \LUATEX\ and we use that one here too. In
271    \LUAMETATEX\ we use some of its helpers to implement for instance md5 and sha support. In
272    \LUAMETATEX\ there are some more than mentioned here but they are {\em not} part of the default
273    binary. Some libraries mentioned below can become loaded on demand.
274
275*/
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" /* not enabled for arm yet */
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/*tex
369
370    Some properties of the command line (and startup call) are reflected in variables that start
371    with \type {self}.
372
373*/
374
375static void enginelib_prepare_cmdline(int zero_offset)
376{
377    lua_State *L = lmt_lua_state.lua_instance;
378    /*tex We keep this reorganized |arg| table, which can start at -3! */
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); /* for old times sake */
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/*tex
400
401    Argument checking is somewhat tricky because it can interfere with the used console (shell). It
402    makes sense to combine this with the \LUA\ command line parser code but even that is no real way
403    out. For instance, on \MSWINDOWS\ we need to deal with wide characters.
404
405    The code below is as independent from libraries as possible and differs from the the code used
406    in other \TEX\ engine.  We issue no warnings and silently recover, because in the end the macro
407    package (and its \LUA\ code) can deal with that.
408
409*/
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/*tex
456
457    The |lmt| suffix is actually a \CONTEXT\ thing but it permits us to have \LUA\ files for
458    \LUAMETATEX\ and \LUATEX\ alongside. The ones for this engine can use a more recent variant of
459    \LUA\ and thereby be not compatible. Especially syntax extension complicates this like using
460    |<const>| in \LUA 5.4+ or before that bitwise operators in \LUA\ 5.3 (not/never in \LUAJIT).
461
462*/
463
464static const char *suffixes[] = { "lmt", "lua", NULL };
465
466static void enginelib_parse_options(void)
467{
468    /*tex We add 5 chars (separator and suffix) so we reserve 6. */
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        /* stat */
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    /*tex This is an attempt to find |input_name| or |dump_name|. */
533    if (lmt_environment_state.argv[lmt_environment_state.npos]) { /* aka name */
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            /*tex This is historic but and might go away. */
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            /*tex This is historic but and might go away. */
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            /*tex We have a command but this and might go away. */
551        } else {
552            /*tex We check for some suffixes first. */
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    /*tex Finalize the input filename. */
576    if (lmt_environment_state.input_name) {
577        /* probably not ok */
578        lmt_environment_state.argv[lmt_environment_state.npos] = enginelib_normalize_quotes(lmt_environment_state.input_name, "argument");
579    }
580}
581
582/*tex
583
584    Being a general purpose typesetting system, a \TEX\ system normally has its own way of dealing
585    with language, script, country etc.\ specific properties. It is for that reason that we disable
586    locales. In \CONTEXT\ we even disable the setter completely and this might at some point also 
587    be hardcoded in the \LUA\ library. 
588
589*/
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/*tex
622
623    We have now arrived at the main initializer. What happens after this is determined by what
624    callbacks are set. The engine can behave as just a \LUA\ interpreter, startup the \TEX\
625    machinery in so called virgin mode, or load a format and carry on from that.
626
627*/
628
629void tex_engine_initialize(int ac, char **av)
630{
631    /*tex Save to pass along to topenin. */
632    lmt_print_state.selector = terminal_selector_code;
633    lmt_environment_state.argc = aux_utf8_setargv(&lmt_environment_state.argv, av, ac);
634    /* initializations */
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    /* preparations */
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    /*tex
648        Some options must be initialized before options are parsed. We don't need that many as we
649        can delegate to \LUA.
650    */
651    /*tex Parse the commandline. */
652    enginelib_parse_options();
653    /*tex Forget about locales. */
654    enginelib_set_locale();
655    /*tex Initialize the \LUA\ instance and keys. */
656    lmt_initialize();
657    /*tex This can be redone later. */
658    lmt_initialize_functions(0);
659    lmt_initialize_properties(0);
660    /*tex For word handlers. */
661    lmt_initialize_languages();
662    /*tex Here start the key definitions (will become functions). */
663    lmt_initialize_interface();
664    lmt_nodelib_initialize();
665    lmt_tokenlib_initialize();
666    lmt_fontlib_initialize();
667    /*tex Collect arguments. */
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    /*tex
674        Now run the file (in \LUATEX\ there is a special \TEX\ table pushed with limited
675        functionality (initialize, run, finish) but the normal tex helpers are not unhidden so
676        basically one has no \TEX. We no longer have that.
677    */
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                /*tex We're okay. */
690                exit(lmt_error_state.default_exit_code);
691            }
692        } else {
693            /*tex a normal tex run */
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/*tex
714
715    For practical and historical reasons some of the initalization and checking is split. The
716    mainbody routine call out to these functions. The timing is sort of tricky: we can use a start
717    up script, that sets some configuration parameters, and for sure some callbacks, and these, in
718    turn, are then responsible for follow up actions like telling where to find the format file
719    (when a dump is loaded) or startup file (when we're in virgin mode). When we are in neither of
720    these modes the engine is just a \LUA\ interpreter which means that only a subset of libraries
721    is initialized.
722
723*/
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                    /*tex
822                        We can't be more precise here as it's called before \TEX\ initialization
823                        happens.
824                    */
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);          /*tex |[{<tex>},"dimen"]| */
848    lua_newtable(L);                 /*tex |[{<tex>},"dimen",{}]| */
849    lua_settable(L, -3);             /*tex |[{<tex>}]| */
850    lua_pushstring(L, tab);          /*tex |[{<tex>},"dimen"]| */
851    lua_gettable(L, -2);             /*tex |[{<tex>},{<dimen>}]| */
852    luaL_newmetatable(L, mttab);     /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
853    lua_pushstring(L, "__index");    /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__index"]| */
854    lua_pushcfunction(L, getfunc);   /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__index","getdimen"]| */
855    lua_settable(L, -3);             /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
856    lua_pushstring(L, "__newindex"); /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__newindex"]| */
857    lua_pushcfunction(L, setfunc);   /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__newindex","setdimen"]| */
858    lua_settable(L, -3);             /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
859    lua_setmetatable(L, -2);         /*tex |[{<tex>},{<dimen>}]| : assign the metatable */
860    lua_pop(L, 1);                   /*tex |[{<tex>}]| : clean the stack */
861}
862
863/*tex 
864    Quite some reallocs happen in \LUA. We often see size 4 bumped to some larger size (strings) 
865    but we also see realloc that go from 8 to 7 (kind of weird). We also see 0 coming by. We see 
866    doubling from 24 to 48 (very popular) to 96. 
867*/
868
869# if (1) 
870
871static void enginelib_initialize_memory_pool(void) 
872{
873    /* dummy */
874}
875
876static void *enginelib_aux_luaalloc(
877    void   *ud,    /*tex Not used, but passed by \LUA. */
878    void   *ptr,   /*tex The old pointer. */
879    size_t  osize, /*tex The old size. */
880    size_t  nsize  /*tex The new size. */
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        /* printf("free %i\n",(int) osize); */
890        lmt_memory_free(ptr);
891        return NULL;
892    } else if (osize == 0) {
893        /* printf("malloc %i\n",(int) nsize); */
894        return lmt_memory_malloc(nsize);
895    } else {
896        /* printf("realloc %i -> %i\n",(int)osize,(int)nsize); */
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,    /*tex Not used, but passed by \LUA. */
929    void   *ptr,   /*tex The old pointer. */
930    size_t  osize, /*tex The old size. */
931    size_t  nsize  /*tex The new size. */
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                          // printf("add to pool: size %d slot %d\n",s,memory_pool[s].size);
948                             memory_pool[s].size++;
949                             break;
950                         } else { 
951                          // printf("full pool: size %d\n",s);
952                         }
953                    }
954                 default: 
955                 // printf("free %i\n", (int) osize); 
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                     // printf("take from pool: size %d slot %d\n",s,memory_pool[s].size);
969                        return p;
970                    } else { 
971                     // printf("empty pool: size %d\n",s);
972                    }
973                }
974            default: 
975             // printf("malloc %i\n",(int) nsize); 
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                         // printf("take from pool: size %d slot %d\n",s,memory_pool[s].size);
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                         // printf("empty pool: size %d\n",s);
1008                        }
1009                    }
1010            }
1011        }
1012     // printf("realloc %i -> %i\n", (int) osize, (int) nsize); 
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  }, /* for practical reasons we keep this namespace */
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/*tex
1096
1097    So, we have different library initialization lists for the the two \TEX\ modes (ini and normal)
1098    and \LUA\ mode (interpeter). It's not pretty yet but it might become better over time.
1099
1100 */
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/*tex
1111
1112    In order to overcome (expected) debates about security we disable loading libraries unless
1113    explicitly enabled (as in \LUATEX). An exception are the optional libraries, but as these
1114    interfaces are rather bound to the cannonical \LUAMETATEX\ source code we can control these
1115    from \CONTEXT\ of needed because before users can run code, we can block support of these
1116    libraries. On the other hand, we have no reason to distrust the few that can (optionally) be
1117    used (they also cannot clash with different \LUA\ versions).
1118
1119    \starttyping
1120    package.loadlib = nil|
1121    package.searchers[4] = nil
1122    package.searchers[3] = nil
1123    \stoptyping
1124
1125*/
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/*tex
1151    The seed is new but makeseed needs a state before we have a state. Maybe it relates to multiple
1152    states with the same hash. Anyway, we can decide on zero at some point which brings us back to 
1153    predictable 'ordering', not that it matters much because we adapted when coming from 5.2 already,
1154    even if 5.5 makes it possible to undo that. 
1155
1156    Remark: we might use a common random approach for \LUA\ and \METAPOST\ which gives less code 
1157    in the latter. 
1158*/
1159
1160void lmt_initialize(void)
1161{
1162    lua_State *L = NULL;
1163    int seed = luaL_makeseed(L); /* maybe we will default to the luametatex version number */
1164    L = lua_newstate(enginelib_aux_luaalloc, NULL, seed);
1165enginelib_initialize_memory_pool();
1166    if (L) {
1167        /*tex By default we use the generational garbage collector. */
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        /*tex Initialize the internalized strings. */
1176        lmt_initialize_shared_keys(L);
1177        lmt_initialize_metapost_keys(L);
1178        /*tex This initializes all the 'simple' libraries: */
1179        enginelib_luaopen_liblist(L, lmt_libs_lua_function_list);
1180        /*tex This initializes all the 'extra' libraries: */
1181        enginelib_luaopen_liblist(L, lmt_libs_extra_function_list);
1182        /*tex These are special: we extend them. */
1183        luaextend_os(L);
1184        luaextend_io(L);
1185        luaextend_string(L);
1186     // luaextend_table(L);
1187        /*tex Loading the socket library is a bit odd (old stuff). */
1188        enginelib_luaopen_liblist(L, lmt_libs_socket_function_list);
1189        /*tex This initializes the 'tex' related libraries that have some luaonly functionality */
1190        enginelib_luaopen_liblist(L, lmt_libs_more_function_list);
1191        /*tex This initializes the 'tex' related libraries. */
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        /*tex Optional stuff. */
1199        luaopen_optional(L);
1200        /*tex This initializes the 'metapost' related libraries. */
1201        enginelib_luaopen_liblist(L, lmt_libs_mp_function_list);
1202        /*tex This initializes the 'pdf' related libraries. */
1203        enginelib_luaopen_liblist(L, lmt_libs_pdf_function_list);
1204        /*tex This one can become optional! */
1205        luaextend_xcomplex(L);
1206        /*tex We're nearly done! In this table we're going to put some info: */
1207        lua_createtable(L, 0, 0);
1208        lua_setglobal(L, "texconfig");
1209        /* Maybe this will embed the checkstack function that some libs need. */
1210     /* lua_checkstack(L, 1); */
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,   /*tex The message has two parts. */
1227    int         detail,  /*tex A function slot or callback index or ... */
1228    int         is_fatal /*tex We quit if this is the case */
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; /*tex Add some slack. */
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        /*
1250            Normally a memory error from lua. The pool may overflow during the |maketexlstring()|,
1251            but we are crashing anyway so we may as well abort on the pool size. It is probably too 
1252            risky to show the error context now but we can imagine some more granularity.
1253        */
1254        tex_normal_error("lua", err ? err : where);
1255        /*tex
1256            This should never be reached, so there is no need to close, so let's not do it and leave
1257            it to the operating system to clean up the memory!
1258        */
1259        /* lua_close(L); */
1260    }
1261    else {
1262        tex_normal_warning("lua", err ? err : where);
1263    }
1264}
1265
1266/*tex
1267
1268    As with other dump related actions, this module provides its relevant properties. A dump is
1269    just that: variables written to a stream, and an undump reads instead. Some basic checking
1270    happens in these functions.
1271
1272*/
1273
1274void lmt_dump_engine_info(dumpstream f)
1275{
1276    /*tex We align |engine_name| to 4 bytes with one or more trailing |NUL|. */
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