texfileio.c /size: 38 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
7fileio_state_info lmt_fileio_state = {
8   .io_buffer        = NULL,
9   .io_buffer_data   = {
10        .minimum   = min_buffer_size,
11        .maximum   = max_buffer_size,
12        .size      = siz_buffer_size,
13        .step      = stp_buffer_size,
14        .allocated = 0,
15        .itemsize  = sizeof(unsigned char),
16        .top       = 0,
17        .ptr       = 0,
18        .initial   = memory_data_unset,
19        .offset    = 0,
20        .extra     = 0, 
21   },
22   .io_first         = 0,
23   .io_last          = 0,
24   .name_in_progress = 0,
25   .log_opened       = 0,
26   .job_name         = NULL,
27   .log_name         = NULL,
28   .fmt_name         = NULL
29};
30
31/*tex
32
33    Once \TEX\ is working, you should be able to diagnose most errors with the |\show| commands and
34    other diagnostic features. Because we have made some internal changes the optional debug interface
35    has been removed.
36
37*/
38
39# define reserved_io_buffer_slots 256
40
41void tex_initialize_fileio_state(void)
42{
43    int size = lmt_fileio_state.io_buffer_data.minimum;
44    lmt_fileio_state.io_buffer = aux_allocate_clear_array(sizeof(unsigned char), size, reserved_io_buffer_slots);
45    if (lmt_fileio_state.io_buffer) {
46        lmt_fileio_state.io_buffer_data.allocated = size;
47    } else {
48        tex_overflow_error("buffer", size);
49    }
50}
51
52bool tex_room_in_buffer(int top)
53{
54    /*tex Beware: |top| can exceed the old size plus the step. */
55    if (top > lmt_fileio_state.io_buffer_data.top) {
56       lmt_fileio_state.io_buffer_data.top = top;
57        if (top > lmt_fileio_state.io_buffer_data.allocated) {
58            unsigned char *tmp = NULL;
59            if (top <= lmt_fileio_state.io_buffer_data.size) {
60                if (lmt_fileio_state.io_buffer_data.allocated + lmt_fileio_state.io_buffer_data.step > top) {
61                    top = lmt_fileio_state.io_buffer_data.allocated + lmt_fileio_state.io_buffer_data.step;
62                    if (top > lmt_fileio_state.io_buffer_data.size) {
63                        top = lmt_fileio_state.io_buffer_data.size;
64                    }
65                }
66                if (top > lmt_fileio_state.io_buffer_data.allocated) {
67                    lmt_fileio_state.io_buffer_data.allocated = top;
68                    tmp = aux_reallocate_array(lmt_fileio_state.io_buffer, sizeof(unsigned char), top, reserved_io_buffer_slots);
69                    lmt_fileio_state.io_buffer = tmp;
70                }
71            }
72            lmt_run_memory_callback("buffer", tmp ? 1 : 0);
73            if (! tmp) {
74                tex_overflow_error("buffer", top);
75                return false;
76            }
77        }
78    }
79    return true;
80}
81
82static int tex_aux_open_outfile(FILE **f, const char *name, const char *mode)
83{
84    FILE *res = aux_utf8_fopen(name, mode);
85    if (res) {
86        *f = res;
87        return 1;
88    }
89    return 0;
90}
91
92/*tex
93
94    We conform to the way \WEBC\ does handle trailing tabs and spaces. This decade old behaviour
95    was changed in September 2017 and can introduce compatibility issues in existing workflows.
96    Because we don't want too many differences with upstream \TEX live we just follow up on that
97    patch and it's up to macro packages to deal with possible issues (which can be done via the
98    usual callbacks. One can wonder why we then still prune spaces but we leave that to the reader.
99
100    Patched original comment:
101
102    Make last be one past the last non-space character in \quote {buffer}, ignoring line
103    terminators (but not, e.g., tabs). This is because we are supposed to treat this like a line of
104    TeX input. Although there are pathological cases (|SP CR SC CR|) where this differs from
105    input_line below, and from previous behavior of removing all whitespace, the simplicity of
106    removing all trailing line terminators seems more in keeping with actual command line
107    processing.
108
109    The |IS_SPC_OR_EOL| macro deals with space characters (|SPACE 32|) and newlines (|CR| and |LF|)
110    and no longer looks at tabs (|TAB 9|).
111
112*/
113
114/*
115    The terminal input code is gone as is the read related code (that had already been nicely
116    cleaned up and abstracted but that is the price we pay for stepwise progress. That code is
117    still in the git repository of course.
118
119    At some point I might do the same as we do in mplib: four callbacks for open, close, read
120    and write (in which case the log goes via write). Part of the management is them moved to
121    \LUA\ and we save a lookup.
122
123    When I adapted the code in this module and the one dealing with errors, I decided to delegate
124    all interaction to \LUA, also because the sometimes tight integration in the scanning and
125    expansion mechanisms. In the 2021 TeX tuneup there have been some patches in the interaction
126    code and some remarks ring a bell: especially the relation between offering feedback and
127    waiting for input. However, because we delegate to \LUA, the engine is no longer responsible
128    for what the macro package lets the user do in case of an error. For instance, in \CONTEXT\ we
129    just abort the run: it makes no sense to carry on the wrong way. Computers are fast enough for
130    a \quotation {Fix and run again.} approach. But we do offer the message and optional help as
131    cue. On the agenda is a further abstraction of error handling. This deviation is fine as we
132    obey Don's wish to not call it \TEX\ but instead add some more letters to the name.
133
134*/
135
136int tex_lua_a_open_in(const char *fn)
137{
138    int callback_id = lmt_callback_defined(open_data_file_callback);
139    if (callback_id > 0) {
140        int k = lmt_run_and_save_callback(lmt_lua_state.lua_instance, callback_id, "S->", fn);
141        lmt_input_state.in_stack[lmt_input_state.cur_input.index].input_file_callback_id = k;
142        return k > 0;
143    } else {
144        tex_emergency_message("startup error", "missing open_data_file callback");
145        tex_emergency_exit();
146        return 0;
147    }
148}
149
150void tex_lua_a_close_in()
151{
152    int k = lmt_input_state.in_stack[lmt_input_state.cur_input.index].input_file_callback_id;
153    if (k > 0) {
154        lmt_run_saved_callback_close(lmt_lua_state.lua_instance, k);
155        lmt_destroy_saved_callback(lmt_lua_state.lua_instance, k);
156        lmt_input_state.in_stack[lmt_input_state.cur_input.index].input_file_callback_id = 0;
157    }
158}
159
160/*tex
161
162    Binary input and output are done with \CCODE's ordinary procedures, so we don't have to make
163    any other special arrangements for binary \IO. Text output is also easy to do with standard
164    routines. The treatment of text input is more difficult, however, because of the necessary
165    translation to |unsigned char| values. \TEX's conventions should be efficient, and they should
166    blend nicely with the user's operating environment.
167
168    Input from text files is read one line at a time, using a routine called |lua_input_ln|. This
169    function is defined in terms of global variables called |buffer|, |first|, and |last| that will
170    be described in detail later; for now, it suffices for us to know that |buffer| is an array of
171    |unsigned char| values, and that |first| and |last| are indices into this array representing
172    the beginning and ending of a line of text.
173
174    The lines of characters being read: |buffer|, the first unused position in |first|, the end of
175    the line just input |last|, the largest index used in |buffer|: |max_buf_stack|.
176
177    The |lua_input_ln| function brings the next line of input from the specified file into available
178    positions of the buffer array and returns the value |true|, unless the file has already been
179    entirely read, in which case it returns |false| and sets |last:=first|. In general, the
180    |unsigned char| numbers that represent the next line of the file are input into |buffer[first]|,
181    |buffer[first + 1]|, \dots, |buffer[last - 1]|; and the global variable |last| is set equal to
182    |first| plus the length of the line. Trailing blanks are removed from the line; thus, either
183    |last = first| (in which case the line was entirely blank) or |buffer[last - 1] <> " "|.
184
185    An overflow error is given, however, if the normal actions of |lua_input_ln| would make |last
186    >= buf_size|; this is done so that other parts of \TEX\ can safely look at the contents of
187    |buffer[last+1]| without overstepping the bounds of the |buffer| array. Upon entry to
188    |lua_input_ln|, the condition |first < buf_size| will always hold, so that there is always room
189    for an \quote {empty} line.
190
191    The variable |max_buf_stack|, which is used to keep track of how large the |buf_size| parameter
192    must be to accommodate the present job, is also kept up to date by |lua_input_ln|.
193
194    If the |bypass_eoln| parameter is |true|, |lua_input_ln| will do a |get| before looking at the
195    first character of the line; this skips over an |eoln| that was in |f^|. The procedure does not
196    do a |get| when it reaches the end of the line; therefore it can be used to acquire input from
197    the user's terminal as well as from ordinary text files.
198
199    Since the inner loop of |lua_input_ln| is part of \TEX's \quote {inner loop} --- each character
200    of input comes in at this place --- it is wise to reduce system overhead by making use of
201    special routines that read in an entire array of characters at once, if such routines are
202    available.
203
204*/
205
206int tex_lua_input_ln(void) /*tex |bypass_eoln| was not used */
207{
208    int callback_id = lmt_input_state.in_stack[lmt_input_state.cur_input.index].input_file_callback_id;
209    if (callback_id > 0) {
210        lua_State *L = lmt_lua_state.lua_instance;
211        int last_ptr = 0;
212        lmt_fileio_state.io_last = lmt_fileio_state.io_first;
213        last_ptr = lmt_run_saved_callback_line(L, callback_id, lmt_fileio_state.io_first);
214        if (last_ptr < 0) {
215            return 0;
216        } else if (last_ptr > 0) {
217            lmt_fileio_state.io_last = last_ptr;
218            if (last_ptr > lmt_fileio_state.io_buffer_data.top) {
219                lmt_fileio_state.io_buffer_data.top = last_ptr;
220            }
221        }
222        return 1;
223    } else {
224        return 0;
225    }
226}
227
228/*tex
229
230    We need a special routine to read the first line of \TEX\ input from the user's terminal.
231    This line is different because it is read before we have opened the transcript file; there is
232    sort of a \quote {chicken and egg} problem here. If the user types |\input paper| on the first
233    line, or if some macro invoked by that line does such an |\input|, the transcript file will be
234    named |paper.log|; but if no |\input| commands are performed during the first line of terminal
235    input, the transcript file will acquire its default name |texput.log|. (The transcript file
236    will not contain error messages generated by the first line before the first |\input| command.)
237
238    The first line is special also because it may be read before \TEX\ has input a format file. In
239    such cases, normal error messages cannot yet be given. The following code uses concepts that
240    will be explained later.
241
242    Different systems have different ways to get started. But regardless of what conventions are
243    adopted, the routine that initializes the terminal should satisfy the following specifications:
244
245    \startitemize[n]
246
247        \startitem
248            It should open file |term_in| for input from the terminal.
249        \stopitem
250
251        \startitem
252            If the user has given a command line, this line should be considered the first line of
253            terminal input. Otherwise the user should be prompted with |**|, and the first line of
254            input should be whatever is typed in response.
255        \stopitem
256
257        \startitem
258            The first line of input, which might or might not be a command line, should appear in
259            locations |first| to |last-1| of the |buffer| array.
260        \stopitem
261
262        \startitem
263            The global variable |loc| should be set so that the character to be read next by \TEX\
264            is in |buffer[loc]|. This character should not be blank, and we should have |loc < last|.
265        \stopitem
266
267    \stopitemize
268
269    It may be necessary to prompt the user several times before a non-blank line comes in. The
270    prompt is |**| instead of the later |*| because the meaning is slightly different: |\input|
271    need not be typed immediately after |**|.)
272
273    The following code does the required initialization. If anything has been specified on the
274    command line, then |t_open_in| will return with |last > first|.
275
276    This code has been adapted and we no longer ask for a name. It makes no sense because one needs
277    to initialize the primitives and backend anyway and no one is going to do that interactively.
278    Of course one can implement a session in \LUA. We keep the \TEX\ trick to push the name into
279    the input buffer and then exercise an |\input| which ensures proper housekeeping. There is a
280    bit overkill in the next function but for now we keep it (as reference).
281
282    For a while copying the argument to th ebuffer lived in the engine lib but it made no sense
283    to duplicate code, so now it's here. Anyway, the following does no longer apply:
284
285    \startquotation
286    This is supposed to open the terminal for input, but what we really do is copy command line
287    arguments into \TEX's buffer, so it can handle them. If nothing is available, or we've been
288    called already (and hence, |argc == 0|), we return with |last = first|.
289    \stopquotation
290
291    In \LUAMETATEX\ we don't really have a terminal. In the \LUATEX\ precursor we used to append
292    all the remaining arguments but now we just take the first one. If one wants filenames with
293    spaces \unknown\ use quotes. Keep in mind that original \TEX\ permits this:
294
295    \starttyping
296    tex ... filename \\hbox{!} \\end
297    \stoptyping
298
299    But we don't follow that route in the situation where \LUA\ is mostly in charge of passing
300    input from files and the console.
301
302    In the end I went for an easier solution: just pass the name to the file reader. But we keep
303    this as nostalgic reference to how \TEX\ originally kin dof did these things.
304
305    \starttyping
306    int input_file_name_pushed(void)
307    {
308        const char *ptr = engine_input_filename();
309        if (ptr) {
310            int len = strlen(ptr);
311            fileio_state.io_buffer[fileio_state.io_first] = 0;
312            if (len > 0 && room_in_buffer(len + 1)) {
313                // We cannot use strcat, because we have multibyte UTF-8 input. Hm, why not.
314                fileio_state.io_last= fileio_state.io_first;
315                while (*ptr) {
316                    fileio_state.io_buffer[fileio_state.io_last++] = (unsigned char) * (ptr++);
317                }
318                // Backtrack over spaces and newlines.
319                for (
320                    --fileio_state.io_last;
321                    fileio_state.io_last >= fileio_state.io_first && IS_SPC_OR_EOL(fileio_state.io_buffer[fileio_state.io_last]);
322                    --fileio_state.io_last
323                );
324                // Terminate the string.
325                fileio_state.io_buffer[++fileio_state.io_last] = 0;
326                // One more time, this time converting to \TEX's internal character representation.
327                if (fileio_state.io_last > fileio_state.io_first) {
328                    input_state.cur_input.loc = fileio_state.io_first;
329                    while ((input_state.cur_input.loc < fileio_state.io_last) && (fileio_state.io_buffer[input_state.cur_input.loc] == ' ')) {
330                        ++input_state.cur_input.loc;
331                    }
332                    if (input_state.cur_input.loc < fileio_state.io_last) {
333                        input_state.cur_input.limit = fileio_state.io_last;
334                        fileio_state.io_first = fileio_state.io_last + 1;
335                    }
336                    if (input_state.cur_input.loc < input_state.cur_input.limit) {
337                        return 1;
338                    }
339                }
340            }
341        }
342        fileio_state.io_first = 1;
343        fileio_state.io_last = 1;
344        return 0;
345    }
346    \stopttyping
347
348    It's this kind of magic that can take lots of time to play with and figure out, also because
349    we cannot break expectations too much.
350
351*/
352
353/*tex
354
355    Per June 22 2020 the terminal code is gone. See |texlegacy.c| for the old, already adapted
356    long ago, code. It was already shedulded for removal a while. We only keep the update.
357
358*/
359
360void tex_terminal_update(void) /* renamed, else conflict in |lmplib|. */
361{
362    fflush(stdout);
363}
364
365/*tex
366
367    It's time now to fret about file names. Besides the fact that different operating systems treat
368    files in different ways, we must cope with the fact that completely different naming conventions
369    are used by different groups of people. The following programs show what is required for one
370    particular operating system; similar routines for other systems are not difficult to devise.
371
372    \TEX\ assumes that a file name has three parts: the name proper; its \quote {extension}; and a
373    \quote {file area} where it is found in an external file system. The extension of an input file
374    or a write file is assumed to be |.tex| unless otherwise specified; it is |transcript_extension|
375    on the transcript file that records each run of \TEX; it is |.tfm| on the font metric files that
376    describe characters in the fonts \TEX\ uses; it is |.dvi| on the output files that specify
377    typesetting information; and it is |format_extension| on the format files written by \INITEX\
378    to initialize \TEX. The file area can be arbitrary on input files, but files are usually output
379    to the user's current area.
380
381    Simple uses of \TEX\ refer only to file names that have no explicit extension or area. For
382    example, a person usually says |\input paper| or |\font \tenrm = helvetica| instead of |\input
383    {paper.new}| or |\font \tenrm = {test}|. Simple file names are best, because they make the \TEX\
384    source files portable; whenever a file name consists entirely of letters and digits, it should be
385    treated in the same way by all implementations of \TEX. However, users need the ability to refer
386    to other files in their environment, especially when responding to error messages concerning
387    unopenable files; therefore we want to let them use the syntax that appears in their favorite
388    operating system.
389
390    The following procedures don't allow spaces to be part of file names; but some users seem to like
391    names that are spaced-out. System-dependent changes to allow such things should probably be made
392    with reluctance, and only when an entire file name that includes spaces is \quote {quoted} somehow.
393
394    Here are the global values that file names will be scanned into.
395
396    \starttyping
397    strnumber cur_name;
398    strnumber cur_area;
399    strnumber cur_ext;
400    \stoptyping
401
402    The file names we shall deal with have the following structure: If the name contains |/| or |:|
403    (for Amiga only), the file area consists of all characters up to and including the final such
404    character; otherwise the file area is null. If the remaining file name contains |.|, the file
405    extension consists of all such characters from the last |.| to the end, otherwise the file
406    extension is null.
407
408    We can scan such file names easily by using two global variables that keep track of the
409    occurrences of area and extension delimiters:
410
411    Input files that can't be found in the user's area may appear in a standard system area called
412    |TEX_area|. Font metric files whose areas are not given explicitly are assumed to appear in a
413    standard system area called |TEX_font_area|. These system area names will, of course, vary from
414    place to place.
415
416    This whole model has been adapted a little but we do keep the |area|, |name|, |ext| distinction
417    for now although we don't use the string pool.
418
419*/
420
421static char *tex_aux_pack_file_name(char *s, int l, const char *name, const char *ext)
422{
423    const char *fn = (char *) s;
424    if ((! fn) || (l <= 0)) {
425        fn = name;
426    }
427    if (! fn) {
428        return NULL;
429    } else if (! ext) {
430        return lmt_memory_strdup(fn);
431    } else {
432        int e = -1;
433        for (int i = 0; i < l; i++) {
434            if (IS_DIR_SEP(fn[i])) {
435                e = -1;
436            } else if (fn[i] == '.') {
437                e = i;
438            }
439        }
440        if (e >= 0) {
441            return lmt_memory_strdup(fn);
442        } else {
443            char *f = lmt_memory_malloc(strlen(fn) + strlen(ext) + 1);
444            if (f) {
445                sprintf(f, "%s%s", fn, ext);
446            }
447            return f;
448        }
449    }
450}
451
452/*tex
453
454    Here is a routine that manufactures the output file names, assuming that |job_name <> 0|. It
455    ignores and changes the current settings of |cur_area| and |cur_ext|; |s = transcript_extension|,
456    |".dvi"|, or |format_extension|
457
458    The packer does split the basename every time but isn't called that often so we can use it in
459    the checker too.
460
461*/
462
463static char *tex_aux_pack_job_name(const char *e, int keeppath, int keepsuffix)
464{
465    char *n = lmt_fileio_state.job_name;
466    int ln = (n) ? (int) strlen(n) : 0;
467    if (! ln) {
468        tex_fatal_error("bad jobname");
469        return NULL;
470    } else {
471        int le = (e) ? (int) strlen(e) : 0;
472        int f = -1; /* first */
473        int l = -1; /* last */
474        char *fn = NULL;
475        int k = 0;
476        for (int i = 0; i < ln; i++) {
477            if (IS_DIR_SEP(n[i])) {
478                f = i;
479                l = -1;
480            } else if (n[i] == '.') {
481                l = i;
482            }
483        }
484        if (keeppath) {
485            f = 0;
486        } else if (f < 0) {
487            f = 0;
488        } else {
489            f += 1;
490        }
491        if (keepsuffix || l < 0) {
492            l = ln;
493        }
494        fn = (char*) lmt_memory_malloc((l - f) + le + 2); /* a bit too much */
495        if (fn) {
496            for (int i = f; i < l; i++) {
497                fn[k++] = n[i];
498            }
499            for (int i = 0; i < le; i++) {
500                fn[k++] = e[i];
501            }
502            fn[k] = 0;
503        }
504        return fn;
505    }
506}
507
508/*tex
509
510    The following comment is obsolete but we keep it as reference because it tells some history.
511
512    \startquotation
513    Because the format is zipped we read and write dump files through zlib. Earlier versions recast
514    |*f| from |FILE *| to |gzFile|, but there is no guarantee that these have the same size, so a
515    static variable is needed.
516
517    We no longer do byte-swapping so formats are generated for the system and not shared. It
518    actually slowed down loading of the format on the majority of used platforms (intel).
519
520    A \CONTEXT\ format is uncompressed some 16 MB but that used to be over 30MB due to more
521    (preallocated) memory usage. A compressed format is 11 MB so the saving is not that much. If
522    we were in lua I'd load the whole file in one go and use a fast decompression after which we
523    could access the bytes in memory. But it's not worth the trouble.
524
525    Tests has shown that a level 3 compression is the most optimal tradeoff between file size and
526    load time.
527
528    So, in principle we can undefine |FMT_COMPRESSION| below and experiment a bit with it. With
529    SSD's it makes no dent, but on a network it still might.
530
531    Per end May 2019 the |FMT_COMPRESSION| branch is gone so that we can simplify the opener and
532    closer.
533    \stopquotation
534
535*/
536
537void tex_check_fmt_name(void)
538{
539    if (lmt_engine_state.dump_name) {
540        char *tmp = lmt_fileio_state.job_name;
541        lmt_fileio_state.job_name = lmt_engine_state.dump_name;
542        lmt_fileio_state.fmt_name = tex_aux_pack_job_name(format_extension, 1, 0);
543        lmt_fileio_state.job_name = tmp;
544    } else if (lmt_main_state.run_state != initializing_state) {
545        /*tex For |dump_name| to be NULL is a bug. */
546        tex_emergency_message("startup error", "no format file given, quitting");
547        tex_emergency_exit();
548    }
549}
550
551void tex_check_job_name(char * fn)
552{
553    if (! lmt_fileio_state.job_name) {
554        if (lmt_engine_state.startup_jobname) {
555            lmt_fileio_state.job_name = lmt_engine_state.startup_jobname; /* not freed here */
556            lmt_fileio_state.job_name = tex_aux_pack_job_name(NULL, 0, 0);
557        } else if (fn) {
558            lmt_fileio_state.job_name = fn;
559            lmt_fileio_state.job_name = tex_aux_pack_job_name(NULL, 0, 0); /* not freed here */
560        } else {
561            tex_emergency_message("startup warning", "using fallback jobname 'texput', continuing");
562            lmt_fileio_state.job_name = lmt_memory_strdup("texput");
563        }
564    }
565    if (! lmt_fileio_state.log_name) {
566        lmt_fileio_state.log_name = tex_aux_pack_job_name(transcript_extension, 0, 1);
567    }
568    if (! lmt_fileio_state.fmt_name) {
569        lmt_fileio_state.fmt_name = tex_aux_pack_job_name(format_extension, 0, 1);
570    }
571}
572
573/*tex
574
575    A messier routine is also needed, since format file names must be scanned before \TEX's
576    string mechanism has been initialized. We shall use the global variable |TEX_format_default|
577    to supply the text for default system areas and extensions related to format files.
578
579    Under \UNIX\ we don't give the area part, instead depending on the path searching that will
580    happen during file opening. Also, the length will be set in the main program.
581
582    \starttyping
583    char *TEX_format_default;
584    \stoptyping
585
586    This part of the program becomes active when a \quote {virgin} \TEX\ is trying to get going,
587    just after the preliminary initialization, or when the user is substituting another format file
588    by typing |&| after the initial |**| prompt. The buffer contains the first line of input in
589    |buffer[loc .. (last - 1)]|, where |loc < last| and |buffer[loc] <> " "|.
590
591*/
592
593dumpstream tex_open_fmt_file(int writemode)
594{
595    dumpstream f = NULL;
596    if (! lmt_fileio_state.fmt_name) {
597        /* this can't happen */
598        tex_emergency_message("startup error", "no format output file '%s' given, quitting", emergency_fmt_name);
599        tex_emergency_exit();
600    } else if (writemode) {
601        f = aux_utf8_fopen(lmt_fileio_state.fmt_name, FOPEN_WBIN_MODE);
602        if (! f) {
603            tex_emergency_message("startup error", "invalid format output file '%s' given, quitting", lmt_fileio_state.fmt_name);
604            tex_emergency_exit();
605        }
606    } else {
607        int callbackid = lmt_callback_defined(find_format_file_callback);
608        if (callbackid > 0) {
609            char *fnam = NULL;
610            int test = lmt_run_callback(lmt_lua_state.lua_instance, callbackid, "S->R", lmt_fileio_state.fmt_name, &fnam);
611            if (test && fnam && strlen(fnam) > 0) {
612                lmt_memory_free(lmt_fileio_state.fmt_name);
613                lmt_fileio_state.fmt_name = fnam;
614            } else {
615                lmt_memory_free(fnam);
616            }
617            f = aux_utf8_fopen(lmt_fileio_state.fmt_name, FOPEN_RBIN_MODE);
618            if (! f) {
619                tex_emergency_message("startup error", "invalid format input file '%s' given, quitting", emergency_fmt_name);
620                tex_emergency_exit();
621            }
622        } else {
623            /*tex For the moment we make this mandate! */
624            tex_emergency_message("startup error", "missing find_format_file callback");
625            tex_emergency_exit();
626        }
627    }
628    return f;
629}
630
631void tex_close_fmt_file(dumpstream f)
632{
633    if (f) {
634        fclose(f);
635    }
636}
637
638/*tex
639
640    The variable |name_in_progress| is used to prevent recursive use of |scan_file_name|, since the
641    |begin_name| and other procedures communicate via global variables. Recursion would arise only
642    by devious tricks like |\input \input f|; such attempts at sabotage must be thwarted.
643    Furthermore, |name_in_progress| prevents |\input| from being initiated when a font size
644    specification is being scanned.
645
646    Another variable, |job_name|, contains the file name that was first |\input| by the user. This
647    name is extended by |transcript_extension| and |.dvi| and |format_extension| in the names of
648    \TEX's output files. The fact if the transcript file been opened is registered in
649    |log_opened_global|.
650
651    Initially |job_name = 0|; it becomes nonzero as soon as the true name is known. We have
652    |job_name = 0| if and only if the |log| file has not been opened, except of course for a short
653    time just after |job_name| has become nonzero.
654
655    The full name of the log file is stored in |log_name|. The |open_log_file| routine is used to
656    open the transcript file and to help it catch up to what has previously been printed on the
657    terminal.
658
659*/
660
661void tex_open_log_file(void)
662{
663    if (! lmt_fileio_state.log_opened) {
664        int callback_id = lmt_callback_defined(find_log_file_callback);
665        if (callback_id > 0) {
666            char *filename = NULL;
667            int okay = 0;
668            tex_check_job_name(NULL);
669            okay = lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "S->R", lmt_fileio_state.log_name, &filename);
670            if (okay && filename && (strlen(filename) > 0)) {
671                lmt_memory_free(lmt_fileio_state.log_name);
672                lmt_fileio_state.log_name = filename;
673            } else {
674                lmt_memory_free(filename);
675            }
676        } else {
677            /*tex For the moment we make this mandate! */
678            tex_emergency_message("startup error", "missing find_log_file callback");
679            tex_emergency_exit();
680        }
681        if (tex_aux_open_outfile(&lmt_print_state.logfile, lmt_fileio_state.log_name, FOPEN_W_MODE)) {
682            /*tex The previous |selector| setting is saved:*/
683            int saved_selector = lmt_print_state.selector;
684            lmt_print_state.selector = logfile_selector_code;
685            lmt_fileio_state.log_opened = 1;
686            /*tex Again we resolve a callback id: */
687            callback_id = lmt_callback_defined(start_run_callback);
688            /*tex There is no need to free |fn|! */
689            if (callback_id == 0) {
690                tex_print_banner();
691                /*tex Print the banner line, including current date and time. */
692                tex_print_log_banner();
693                /*tex Make sure bottom level is in memory. */
694                lmt_input_state.input_stack[lmt_input_state.input_stack_data.ptr] = lmt_input_state.cur_input;
695                /*tex We don't have a first line so that code is gone. */
696                tex_print_ln();
697            } else if (callback_id > 0) {
698                lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "->");
699            } else {
700                tex_print_banner();
701            }
702            /*tex should be done always */
703            if (lmt_print_state.loggable_info) {
704                fprintf(lmt_print_state.logfile, "%s\n", lmt_print_state.loggable_info);
705                lmt_memory_free(lmt_print_state.loggable_info);
706                lmt_print_state.loggable_info = NULL;
707            }
708            switch (saved_selector) {
709                case no_print_selector_code : lmt_print_state.selector = logfile_selector_code; break;
710                case terminal_selector_code : lmt_print_state.selector = terminal_and_logfile_selector_code; break;
711                default                     : lmt_print_state.selector = saved_selector; break;
712            }
713        } else {
714            tex_emergency_message("startup error", "log file '%s' cannot be opened, quitting", emergency_log_name);
715            tex_emergency_exit();
716        }
717    }
718}
719
720void tex_close_log_file(void)
721{
722    fclose(lmt_print_state.logfile);
723    lmt_fileio_state.log_opened = 0;
724}
725
726/*tex
727
728    Let's turn now to the procedure that is used to initiate file reading when an |\input| command
729    is being processed. This function is used with |\\input| as well as in the start up.
730
731*/
732
733void tex_start_input(char *fn, halfword at_end_of_file)
734{
735    /*tex Set up |cur_file| and new level of input. */
736    tex_begin_file_reading();
737    if (! tex_lua_a_open_in(fn)) {
738        /*tex
739            Normally this is catched earler, as we have lookup callbacks but the first file, the
740            one passed on the command line can fall though this checking.
741        */
742        tex_end_file_reading();
743        tex_emergency_message("runtime error", "input file '%s' is not found, quitting", fn);
744        tex_emergency_exit();
745    }
746    lmt_input_state.in_stack[lmt_input_state.in_stack_data.ptr].full_source_filename = fn;
747    lmt_input_state.cur_input.name = io_file_input_code;
748    lmt_input_state.in_stack[lmt_input_state.cur_input.index].at_end_of_file = at_end_of_file;
749    /*tex
750        |open_log_file| doesn't |show_context|, so |limit| and |loc| needn't be set to meaningful
751        values yet.
752    */
753    tex_report_start_file((unsigned char *) fn);
754    ++lmt_input_state.open_files;
755    tex_terminal_update();
756    lmt_input_state.cur_input.state = new_line_state;
757    /*tex
758
759        Read the first line of the new file. Here we have to remember to tell the |lua_input_ln|
760        routine not to start with a |get|. If the file is empty, it is considered to contain a
761        single blank line.
762
763    */
764    lmt_input_state.input_line = 1;
765    tex_lua_input_ln();
766    lmt_input_state.cur_input.limit = lmt_fileio_state.io_last; /*tex Was |firm_up_the_line();|. */
767    if (end_line_char_inactive) {
768        --lmt_input_state.cur_input.limit;
769    } else {
770        lmt_fileio_state.io_buffer[lmt_input_state.cur_input.limit] = (unsigned char) end_line_char_par;
771    }
772    lmt_fileio_state.io_first = lmt_input_state.cur_input.limit + 1;
773    lmt_input_state.cur_input.loc = lmt_input_state.cur_input.start;
774}
775
776/*tex
777
778    In order to isolate the system-dependent aspects of file names, the system-independent parts of
779    \TEX\ are expressed in terms of three system-dependent procedures called |begin_name|,
780    |more_name|, and |end_name|. In essence, if the user-specified characters of the file name are
781    |c_1|\unknown|c_n|, the system-independent driver program does the operations
782
783    \starttyping
784    |begin_name|;
785    |more_name|(c_1);
786    .....
787    |more_name|(c_n);
788    |end_name|
789    \stoptyping
790
791    These three procedures communicate with each other via global variables. Afterwards the file
792    name will appear in the string pool as three strings called |cur_name|, |cur_area|, and
793    |cur_ext|; the latter two are null (i.e., |""|), unless they were explicitly specified by the
794    user.
795
796    Actually the situation is slightly more complicated, because \TEX\ needs to know when the file
797    name ends. The |more_name| routine is a function (with side effects) that returns |true| on the
798    calls |more_name (c_1)|, \dots, |more_name (c_{n - 1})|. The final call |more_name(c_n)| returns
799    |false|; or, it returns |true| and the token following |c_n| is something like |\hbox| (i.e.,
800    not a character). In other words, |more_name| is supposed to return |true| unless it is sure that
801    the file name has been completely scanned; and |end_name| is supposed to be able to finish the
802    assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of whether |more_name (c_n)|
803    returned |true| or |false|.
804
805    This code has been adapted and the string pool is no longer used. We also don't ask for another
806    name on the console.
807
808*/
809
810/*tex
811
812    And here's the second. The string pool might change as the file name is being scanned, since a
813    new |\csname| might be entered; therefore we keep |area_delimiter| and |ext_delimiter| relative
814    to the beginning of the current string, instead of assigning an absolute address like |pool_ptr|
815    to them.
816
817    Now let's consider the \quote {driver} routines by which \TEX\ deals with file names in a
818    system-independent manner. First comes a procedure that looks for a file name in the input by
819    calling |get_x_token| for the information.
820
821*/
822
823char *tex_read_file_name(int optionalequal, const char * name, const char* ext)
824{
825    halfword result;
826    if (optionalequal) {
827        tex_scan_optional_equals();
828    }
829    do {
830        tex_get_x_token();
831    } while (cur_cmd == spacer_cmd || cur_cmd == relax_cmd);
832    if (cur_cmd == left_brace_cmd) {
833        result = tex_scan_toks_expand(1, NULL, 0, 0);
834    } else {
835        char quote = 0;
836        halfword p = get_reference_token();
837        result = p;
838        while (1) {
839            switch (cur_cmd) {
840                case escape_cmd:
841                case left_brace_cmd:
842                case right_brace_cmd:
843                case math_shift_cmd:
844                case alignment_tab_cmd:
845                case parameter_cmd:
846                case superscript_cmd:
847                case subscript_cmd:
848                case letter_cmd:
849                case other_char_cmd:
850                    switch (cur_chr) { 
851                        case double_quote:
852                            if (quote == double_quote) {
853                                goto DONE;
854                            } else {
855                                quote = double_quote;
856                            }
857                            break;
858                        case single_quote:
859                            if (quote == single_quote) {
860                                goto DONE;
861                            } else {
862                                quote = single_quote;
863                            }
864                            break;
865                        default:
866                            p = tex_store_new_token(p, cur_tok);
867                    }
868                    break;
869                case spacer_cmd:
870                case end_line_cmd:
871                    if (quote) {
872                        p = tex_store_new_token(p, token_val(spacer_cmd, ' '));
873                    } else {
874                        goto DONE;
875                    }
876                case ignore_cmd:
877                    break;
878                default:
879                    tex_back_input(cur_tok);
880                    goto DONE;
881            }
882            tex_get_x_token();
883        }
884    }
885  DONE:
886    {
887        int l = 0;
888        char *s = tex_tokenlist_to_tstring(result, 1, &l, 0, 0, 0, 1, 1); /* single hashes */
889        char *fn = s ? tex_aux_pack_file_name(s, l, name, ext) : NULL;
890        return fn;
891    }
892}
893
894void tex_print_file_name(unsigned char *name)
895{
896    int must_quote = 0;
897    if (name) {
898        unsigned char *j = name;
899        while (*j) {
900            if (*j == ' ') {
901                must_quote = 1;
902                break;
903            } else {
904                j++;
905            }
906        }
907    }
908    if (must_quote) {
909        /* initial quote */
910        tex_print_char('"');
911    }
912    if (name) {
913        unsigned char *j = name;
914        while (*j) {
915            if (*j == '"') {
916                /* skip embedded quote, maybe escape */
917            } else {
918                tex_print_char(*j);
919            }
920            j++;
921        }
922    }
923    if (must_quote) {
924        /* final quote */
925        tex_print_char('"');
926    }
927}
928
929void tex_report_start_file(unsigned char *name)
930{
931    int callback_id = lmt_callback_defined(start_file_callback);
932    if (callback_id) {
933        lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "S->", name);
934    } else {
935        tex_print_char('(');
936        tex_print_file_name((unsigned char *) name);
937    }
938}
939
940void tex_report_stop_file(void)
941{
942    int callback_id = lmt_callback_defined(stop_file_callback);
943    if (callback_id) {
944        lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "->");
945    } else {
946        tex_print_char(')');
947    }
948}
949