lmtenginelib.c /size: 44 Kb    last modification: 2024-01-16 10:22
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    We assume that the strings are proper \UTF\ and in \MSWINDOWS\ we handle wide characters to get
21    that right.
22*/
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/*tex todo: make helpers in loslibext which has similar code */
59
60static void enginelib_splitnames(void)
61{
62    char *p = lmt_memory_strdup(lmt_environment_state.ownpath); /*tex We need to make copies! */
63    /*
64        We loose some here but not enough to worry about. Maybe eventually we will use our own
65        |basename| and |dirname| anyway. I need to check if all are set to something we can 
66        indeed free. 
67    */
68    /*
69    if (lmt_environment_state.ownbase) { lmt_memory_free(lmt_environment_state.ownbase); }
70    if (lmt_environment_state.ownname) { lmt_memory_free(lmt_environment_state.ownbase); }
71    if (lmt_environment_state.ownpath) { lmt_memory_free(lmt_environment_state.ownbase); }
72    if (lmt_environment_state.ownlink) { lmt_memory_free(lmt_environment_state.ownlink); }
73    */
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)); /* We could use p and not free later, but this is cleaner. */
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/*tex A bunch of internalized strings: see |linterface.h |.*/
91
92/* declare_shared_lua_keys; */
93/* declare_metapost_lua_keys; */
94
95char *tex_engine_input_filename(void)
96{
97    /*tex When npos equals zero we have no filename i.e. nothing that doesn't start with |--|. */
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/*tex
102
103    Filenames can have spaces in which case (double) quotes are used to indicate the bounds of the
104    string. At the \TEX\ level curly braces are also an option but these are dealt with in the
105    scanner.
106
107    Comment: maybe we should also support single quotes, so that we're consistent with \LUA\ quoting.
108
109*/
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        /* Leave room for quotes and NUL. */
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/*
142
143    We support a minimum set of options but more can be supported by supplying an (startup)
144    initialization script and/or by setting values in the |texconfig| table. At some point we might
145    provide some default initiazation script but that's for later. In fact, a bug in \LUATEX\ <
146    1.10 made some of the command line options get lost anyway due to setting their values before
147    checking the config table (probably introduced at some time). As no one noticed that anyway,
148    removing these from the commandline is okay.
149
150    Part of the commandline handler is providing (minimal) help information and reporting credits
151    (more credits can be found in the source file). Here comes the basic help.
152
153    At some point I will likely add a |--permitloadlib| flag and block loading of libraries when
154    that flag is not given so that we satisfy operating systems and/or distributions that have some
155    restrictions on loading libraries. It also means that the optional modules will be (un)locked,
156    but we can control that in the runners so it's no big deal because we will never depend on
157    external code for the \CONTEXT\ core features.
158
159*/
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/*tex
206
207    This is the minimal version info display.  The credits option provides a bit more information.
208*/
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/*tex
236
237    We only mention the most relevelant credits here. The first part is there to indicate a bit of
238    history. A very large part of the code, of course, comes from Don Knuths original \TEX, and the
239    same is true for most documentation!
240
241    Most of the \ETEX\ extensions are present too. Much of the expansion and protrusion code
242    originates in \PDFTEX\ but we don't have any of its backend code. From \OMEGA\ (\ALEPH) we took
243    bits and pieces too, for instance the basics of handling directions but at this point we only
244    have two directions left (that don't need much code). One features that sticks are the left-
245    and right boxes.
246
247    The \METAPOST\ library is an important component and also add quite some code. Here we use a
248    stripped down version of the version 2 library with some extra additions.
249
250    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
251    on what makes sense. For as far as possible no changes are made but there are some configuration
252    options in use. We use an \UTF8\ aware setup. Of course \LPEG\ is part of the deal.
253
254    The lean and mean \PDF\ library is made for \LUATEX\ and we use that one here too. In
255    \LUAMETATEX\ we use some of its helpers to implement for instance md5 and sha support. In
256    \LUAMETATEX\ there are some more than mentioned here but they are {\em not} part of the default
257    binary. Some libraries mentioned below can become loaded on demand.
258
259*/
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" /* not enabled for arm yet */
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/*tex
348
349    Some properties of the command line (and startup call) are reflected in variables that start
350    with \type {self}.
351
352*/
353
354static void enginelib_prepare_cmdline(int zero_offset)
355{
356    lua_State *L = lmt_lua_state.lua_instance;
357    /*tex We keep this reorganized |arg| table, which can start at -3! */
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); /* for old times sake */
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/*tex
379
380    Argument checking is somewhat tricky because it can interfere with the used console (shell). It
381    makes sense to combine this with the \LUA\ command line parser code but even that is no real way
382    out. For instance, on \MSWINDOWS\ we need to deal with wide characters.
383
384    The code below is as independent from libraries as possible and differs from the the code used
385    in other \TEX\ engine.  We issue no warnings and silently recover, because in the end the macro
386    package (and its \LUA\ code) can deal with that.
387
388*/
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/*tex
435
436    The |lmt| suffix is actually a \CONTEXT\ thing but it permits us to have \LUA\ files for
437    \LUAMETATEX\ and \LUATEX\ alongside. The ones for this engine can use a more recent variant of
438    \LUA\ and thereby be not compatible. Especially syntax extension complicates this like using
439    |<const>| in \LUA 5.4+ or before that bitwise operators in \LUA\ 5.3 (not/never in \LUAJIT).
440
441*/
442
443static const char *suffixes[] = { "lmt", "lua", NULL };
444
445static void enginelib_parse_options(void)
446{
447    /*tex We add 5 chars (separator and suffix) so we reserve 6. */
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        /* stat */
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    /*tex This is an attempt to find |input_name| or |dump_name|. */
512    if (lmt_environment_state.argv[lmt_environment_state.npos]) { /* aka name */
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            /*tex This is historic but and might go away. */
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            /*tex This is historic but and might go away. */
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            /*tex We have a command but this and might go away. */
530        } else {
531            /*tex We check for some suffixes first. */
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    /*tex Finalize the input filename. */
555    if (lmt_environment_state.input_name) {
556        /* probably not ok */
557        lmt_environment_state.argv[lmt_environment_state.npos] = enginelib_normalize_quotes(lmt_environment_state.input_name, "argument");
558    }
559}
560
561/*tex
562
563    Being a general purpose typesetting system, a \TEX\ system normally has its own way of dealing
564    with language, script, country etc.\ specific properties. It is for that reason that we disable
565    locales.
566
567*/
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/*tex
600
601    We have now arrived at the main initializer. What happens after this is determined by what
602    callbacks are set. The engine can behave as just a \LUA\ interpreter, startup the \TEX\
603    machinery in so called virgin mode, or load a format and carry on from that.
604
605*/
606
607void tex_engine_initialize(int ac, char **av)
608{
609    /*tex Save to pass along to topenin. */
610    lmt_print_state.selector = terminal_selector_code;
611    lmt_environment_state.argc = aux_utf8_setargv(&lmt_environment_state.argv, av, ac);
612    /* initializations */
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    /* preparations */
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    /*tex
626        Some options must be initialized before options are parsed. We don't need that many as we
627        can delegate to \LUA.
628    */
629    /*tex Parse the commandline. */
630    enginelib_parse_options();
631    /*tex Forget about locales. */
632    enginelib_set_locale();
633    /*tex Initialize the \LUA\ instance and keys. */
634    lmt_initialize();
635    /*tex This can be redone later. */
636    lmt_initialize_functions(0);
637    lmt_initialize_properties(0);
638    /*tex For word handlers. */
639    lmt_initialize_languages();
640    /*tex Here start the key definitions (will become functions). */
641    lmt_initialize_interface();
642    lmt_nodelib_initialize();
643    lmt_tokenlib_initialize();
644    lmt_fontlib_initialize();
645    /*tex Collect arguments. */
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    /*tex
652        Now run the file (in \LUATEX\ there is a special \TEX\ table pushed with limited
653        functionality (initialize, run, finish) but the normal tex helpers are not unhidden so
654        basically one has no \TEX. We no longer have that.
655    */
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                /*tex We're okay. */
668                exit(lmt_error_state.default_exit_code);
669            }
670        } else {
671            /*tex a normal tex run */
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/*tex
692
693    For practical and historical reasons some of the initalization and checking is split. The
694    mainbody routine call out to these functions. The timing is sort of tricky: we can use a start
695    up script, that sets some configuration parameters, and for sure some callbacks, and these, in
696    turn, are then responsible for follow up actions like telling where to find the format file
697    (when a dump is loaded) or startup file (when we're in virgin mode). When we are in neither of
698    these modes the engine is just a \LUA\ interpreter which means that only a subset of libraries
699    is initialized.
700
701*/
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                    /*tex
800                        We can't be more precise here as it's called before \TEX\ initialization
801                        happens.
802                    */
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);          /*tex |[{<tex>},"dimen"]| */
826    lua_newtable(L);                 /*tex |[{<tex>},"dimen",{}]| */
827    lua_settable(L, -3);             /*tex |[{<tex>}]| */
828    lua_pushstring(L, tab);          /*tex |[{<tex>},"dimen"]| */
829    lua_gettable(L, -2);             /*tex |[{<tex>},{<dimen>}]| */
830    luaL_newmetatable(L, mttab);     /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
831    lua_pushstring(L, "__index");    /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__index"]| */
832    lua_pushcfunction(L, getfunc);   /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__index","getdimen"]| */
833    lua_settable(L, -3);             /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
834    lua_pushstring(L, "__newindex"); /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__newindex"]| */
835    lua_pushcfunction(L, setfunc);   /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__newindex","setdimen"]| */
836    lua_settable(L, -3);             /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
837    lua_setmetatable(L, -2);         /*tex |[{<tex>},{<dimen>}]| : assign the metatable */
838    lua_pop(L, 1);                   /*tex |[{<tex>}]| : clean the stack */
839}
840
841static void *enginelib_aux_luaalloc(
842    void   *ud,    /*tex Not used, but passed by \LUA. */
843    void   *ptr,   /*tex The old pointer. */
844    size_t  osize, /*tex The old size. */
845    size_t  nsize  /*tex The new size. */
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    /*tex Quite some reallocs happen in \LUA. */
854    if (nsize == 0) {
855        /* printf("free %i\n",(int) osize); */
856        lmt_memory_free(ptr);
857        return NULL;
858    } else if (osize == 0) {
859        /* printf("malloc %i\n",(int) nsize); */
860        return lmt_memory_malloc(nsize);
861    } else {
862        /* printf("realloc %i -> %i\n",(int)osize,(int)nsize); */
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  }, /* for practical reasons we keep this namespace */
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/*tex
944
945    So, we have different library initialization lists for the the two \TEX\ modes (ini and normal)
946    and \LUA\ mode (interpeter). It's not pretty yet but it might become better over time.
947
948 */
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/*tex
959
960    In order to overcome (expected) debates about security we disable loading libraries unless
961    explicitly enabled (as in \LUATEX). An exception are the optional libraries, but as these
962    interfaces are rather bound to the cannonical \LUAMETATEX\ source code we can control these
963    from \CONTEXT\ of needed because before users can run code, we can block support of these
964    libraries. On the other hand, we have no reason to distrust the few that can (optionally) be
965    used (they also cannot clash with different \LUA\ versions).
966
967    \starttyping
968    package.loadlib = nil|
969    package.searchers[4] = nil
970    package.searchers[3] = nil
971    \stoptyping
972
973*/
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        /*tex By default we use the generational garbage collector. */
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        /*tex Initialize the internalized strings. */
1011        lmt_initialize_shared_keys(L);
1012        lmt_initialize_metapost_keys(L);
1013        /*tex This initializes all the 'simple' libraries: */
1014        enginelib_luaopen_liblist(L, lmt_libs_lua_function_list);
1015        /*tex This initializes all the 'extra' libraries: */
1016        enginelib_luaopen_liblist(L, lmt_libs_extra_function_list);
1017        /*tex These are special: we extend them. */
1018        luaextend_os(L);
1019        luaextend_io(L);
1020        luaextend_string(L);
1021        /*tex Loading the socket library is a bit odd (old stuff). */
1022        enginelib_luaopen_liblist(L, lmt_libs_socket_function_list);
1023        /*tex This initializes the 'tex' related libraries that have some luaonly functionality */
1024        enginelib_luaopen_liblist(L, lmt_libs_more_function_list);
1025        /*tex This initializes the 'tex' related libraries. */
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        /*tex Optional stuff. */
1033        luaopen_optional(L);
1034        /*tex This initializes the 'metapost' related libraries. */
1035        enginelib_luaopen_liblist(L, lmt_libs_mp_function_list);
1036        /*tex This initializes the 'pdf' related libraries. */
1037        enginelib_luaopen_liblist(L, lmt_libs_pdf_function_list);
1038        /*tex This one can become optional! */
1039        luaextend_xcomplex(L);
1040        /*tex We're nearly done! In this table we're going to put some info: */
1041        lua_createtable(L, 0, 0);
1042        lua_setglobal(L, "texconfig");
1043        /* Maybe this will embed the checkstack function that some libs need. */
1044     /* lua_checkstack(L, 1); */
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,   /*tex The message has two parts. */
1061    int         detail,  /*tex A function slot or callback index or ... */
1062    int         is_fatal /*tex We quit if this is the case */
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; /*tex Add some slack. */
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        /*
1084            Normally a memory error from lua. The pool may overflow during the |maketexlstring()|,
1085            but we are crashing anyway so we may as well abort on the pool size. It is probably
1086            too risky to show the error context now but we can imagine some more granularity.
1087        */
1088        tex_normal_error("lua", err ? err : where);
1089        /*tex
1090            This should never be reached, so there is no need to close, so let's make sure of
1091            that!
1092        */
1093        /* lua_close(L); */
1094    }
1095    else {
1096        tex_normal_warning("lua", err ? err : where);
1097    }
1098}
1099
1100/*tex
1101
1102    As with other dump related actions, this module provides its relevant properties. A dump is
1103    just that: variables written to a stream, and an undump reads instead. Some basic checking
1104    happens in these functions.
1105
1106*/
1107
1108void lmt_dump_engine_info(dumpstream f)
1109{
1110    /*tex We align |engine_name| to 4 bytes with one or more trailing |NUL|. */
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