~reviczky/luatex/luatex-svn

« back to all changes in this revision

Viewing changes to source/texk/web2c/luatexdir/lua/luainit.w

  • Committer: Adam Reviczky
  • Date: 2015-03-29 18:56:26 UTC
  • Revision ID: adam.reviczky@kclalumni.net-20150329185626-7j7tmwyfpa69lqwo
Revision 5213

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
% luainit.w
 
2
%
 
3
% Copyright 2006-2014 Taco Hoekwater <taco@@luatex.org>
 
4
%
 
5
% This file is part of LuaTeX.
 
6
%
 
7
% LuaTeX is free software; you can redistribute it and/or modify it under
 
8
% the terms of the GNU General Public License as published by the Free
 
9
% Software Foundation; either version 2 of the License, or (at your
 
10
% option) any later version.
 
11
%
 
12
% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
 
13
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
14
% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
15
% License for more details.
 
16
%
 
17
% You should have received a copy of the GNU General Public License along
 
18
% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
 
19
 
 
20
@ @c
 
21
 
 
22
 
 
23
#include "ptexlib.h"
 
24
 
 
25
#include <kpathsea/c-stat.h>
 
26
 
 
27
#include "lua/luatex-api.h"
 
28
 
 
29
/* internalized strings: see luatex-api.h */
 
30
set_make_keys; 
 
31
 
 
32
 
 
33
@
 
34
TH: TODO
 
35
 
 
36
This file is getting a bit messy, but it is not simple to fix unilaterally.
 
37
 
 
38
Better to wait until Karl has some time (after texlive 2008) so we can
 
39
synchronize with kpathsea. One problem, for instance, is that I would
 
40
like to resolve the full executable path.  |kpse_set_program_name()| does
 
41
that, indirectly (by setting SELFAUTOLOC in the environment), but it
 
42
does much more, making it hard to use for our purpose.
 
43
 
 
44
In fact, it sets three C variables:
 
45
 
 
46
  |kpse_invocation_name|  |kpse_invocation_short_name|  |kpse->program_name|
 
47
 
 
48
and five environment variables:
 
49
 
 
50
  SELFAUTOLOC  SELFAUTODIR  SELFAUTOPARENT  SELFAUTOGRANDPARENT  progname
 
51
 
 
52
@c
 
53
const_string LUATEX_IHELP[] = {
 
54
    "Usage: " my_name " --lua=FILE [OPTION]... [TEXNAME[.tex]] [COMMANDS]",
 
55
    "   or: " my_name " --lua=FILE [OPTION]... \\FIRST-LINE",
 
56
    "   or: " my_name " --lua=FILE [OPTION]... &FMT ARGS",
 
57
    "  Run " MyName " on TEXNAME, usually creating TEXNAME.pdf.",
 
58
    "  Any remaining COMMANDS are processed as luatex input, after TEXNAME is read.",
 
59
    "",
 
60
    "  Alternatively, if the first non-option argument begins with a backslash,",
 
61
    "  " my_name " interprets all non-option arguments as an input line.",
 
62
    "",
 
63
    "  Alternatively, if the first non-option argument begins with a &, the",
 
64
    "  next word is taken as the FMT to read, overriding all else.  Any",
 
65
    "  remaining arguments are processed as above.",
 
66
    "",
 
67
    "  If no arguments or options are specified, prompt for input.",
 
68
    "",
 
69
    "  The following regular options are understood: ",
 
70
    "",
 
71
    "   --8bit                        ignored, input is assumed to be in UTF-8 encoding",
 
72
    "   --credits                     display credits and exit",
 
73
    "   --debug-format                enable format debugging",
 
74
    "   --default-translate-file=     ignored, input is assumed to be in UTF-8 encoding",
 
75
    "   --disable-write18             disable \\write18{SHELL COMMAND}",
 
76
    "   --draftmode                   switch on draft mode (generates no output PDF)",
 
77
    "   --enable-write18              enable \\write18{SHELL COMMAND}",
 
78
    "   --etex                        ignored, the etex extensions are always active",
 
79
    "   --[no-]file-line-error        disable/enable file:line:error style messages",
 
80
    "   --[no-]file-line-error-style  aliases of --[no-]file-line-error",
 
81
    "   --fmt=FORMAT                  load the format file FORMAT",
 
82
    "   --halt-on-error               stop processing at the first error",
 
83
    "   --help                        display help and exit",
 
84
    "   --ini                         be ini" my_name ", for dumping formats",
 
85
    "   --interaction=STRING          set interaction mode (STRING=batchmode/nonstopmode/scrollmode/errorstopmode)",
 
86
    "   --jobname=STRING              set the job name to STRING",
 
87
    "   --kpathsea-debug=NUMBER       set path searching debugging flags according to the bits of NUMBER",
 
88
    "   --lua=s                       load and execute a lua initialization script",
 
89
    "   --[no-]mktex=FMT              disable/enable mktexFMT generation (FMT=tex/tfm)",
 
90
    "   --nosocket                    disable the lua socket library",
 
91
    "   --output-comment=STRING       use STRING for DVI file comment instead of date (no effect for PDF)",
 
92
    "   --output-directory=DIR        use existing DIR as the directory to write files in",
 
93
    "   --output-format=FORMAT        use FORMAT for job output; FORMAT is 'dvi' or 'pdf'",
 
94
    "   --[no-]parse-first-line       disable/enable parsing of the first line of the input file",
 
95
    "   --progname=STRING             set the program name to STRING",
 
96
    "   --recorder                    enable filename recorder",
 
97
    "   --safer                       disable easily exploitable lua commands",
 
98
    "   --[no-]shell-escape           disable/enable \\write18{SHELL COMMAND}",
 
99
    "   --shell-restricted            restrict \\write18 to a list of commands given in texmf.cnf",
 
100
    "   --synctex=NUMBER              enable synctex",
 
101
    "   --translate-file=             ignored, input is assumed to be in UTF-8 encoding",
 
102
    "   --version                     display version and exit",
 
103
    "",
 
104
    "Alternate behaviour models can be obtained by special switches",
 
105
    "",
 
106
    "  --luaonly                run a lua file, then exit",
 
107
    "  --luaconly               byte-compile a lua file, then exit",
 
108
    "  --luahashchars           the bits used by current Lua interpreter for strings hashing",
 
109
#ifdef LuajitTeX
 
110
    "  --jiton                  turns the JIT compiler on (default off)",
 
111
    "  --jithash=STRING         choose the hash function for the lua strings (lua51|luajit20: default lua51)",
 
112
#endif
 
113
    "",
 
114
    "See the reference manual for more information about the startup process.",
 
115
    NULL
 
116
};
 
117
 
 
118
@ The return value will be the directory of the executable, e.g.: \.{c:/TeX/bin}
 
119
@c
 
120
static char *ex_selfdir(char *argv0)
 
121
{
 
122
#if defined(WIN32)
 
123
#if defined(__MINGW32__)
 
124
    char path[PATH_MAX], *fp;
 
125
 
 
126
    /* SearchPath() always gives back an absolute directory */
 
127
    if (SearchPath(NULL, argv0, ".exe", PATH_MAX, path, NULL) == 0)
 
128
        FATAL1("Can't determine where the executable %s is.\n", argv0);
 
129
    /* slashify the dirname */
 
130
    for (fp = path; fp && *fp; fp++)
 
131
        if (IS_DIR_SEP(*fp))
 
132
            *fp = DIR_SEP;
 
133
#else /* __MINGW32__ */
 
134
#define PATH_MAX 512
 
135
    char short_path[PATH_MAX], path[PATH_MAX], *fp;
 
136
 
 
137
    /* SearchPath() always gives back an absolute directory */
 
138
    if (SearchPath(NULL, argv0, ".exe", PATH_MAX, short_path, &fp) == 0)
 
139
        FATAL1("Can't determine where the executable %s is.\n", argv0);
 
140
    if (getlongpath(path, short_path, sizeof(path)) == 0) {
 
141
        FATAL1("This path points to an invalid file : %s\n", short_path);
 
142
    }
 
143
#endif /* __MINGW32__ */
 
144
   return xdirname(path);
 
145
#else /* WIN32 */
 
146
    return kpse_selfdir(argv0);
 
147
#endif
 
148
}
 
149
 
 
150
 
 
151
 
 
152
 
 
153
@ @c
 
154
static void
 
155
prepare_cmdline(lua_State * L, char **av, int ac, int zero_offset)
 
156
{
 
157
    int i;
 
158
    char *s;
 
159
    luaL_checkstack(L, ac + 3, "too many arguments to script");
 
160
    lua_createtable(L, 0, 0);
 
161
    for (i = 0; i < ac; i++) {
 
162
        lua_pushstring(L, av[i]);
 
163
        lua_rawseti(L, -2, (i - zero_offset));
 
164
    }
 
165
    lua_setglobal(L, "arg");
 
166
    lua_getglobal(L, "os");
 
167
    s = ex_selfdir(argv[0]);
 
168
    lua_pushstring(L, s);
 
169
    xfree(s);
 
170
    lua_setfield(L, -2, "selfdir");
 
171
    return;
 
172
}
 
173
 
 
174
@ @c
 
175
string input_name = NULL;
 
176
 
 
177
static string user_progname = NULL;
 
178
 
 
179
char *startup_filename = NULL;
 
180
int lua_only = 0;
 
181
int lua_offset = 0;
 
182
unsigned char show_luahashchars = 0;
 
183
 
 
184
#ifdef LuajitTeX
 
185
int luajiton   = 0;
 
186
char *jithash_hashname = NULL;
 
187
#endif
 
188
 
 
189
int safer_option = 0;
 
190
int nosocket_option = 0;
 
191
 
 
192
@ Reading the options.
 
193
 
 
194
@ Test whether getopt found an option ``A''.
 
195
Assumes the option index is in the variable |option_index|, and the
 
196
option table in a variable |long_options|.
 
197
 
 
198
@c
 
199
#define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
 
200
 
 
201
/* SunOS cc can't initialize automatic structs, so make this static.  */
 
202
static struct option long_options[]
 
203
= { {"fmt", 1, 0, 0},
 
204
{"lua", 1, 0, 0},
 
205
{"luaonly", 0, 0, 0},
 
206
{"luahashchars", 0, 0, 0},
 
207
#ifdef LuajitTeX
 
208
{"jiton", 0, 0, 0},
 
209
{"jithash", 1, 0, 0},
 
210
#endif
 
211
{"safer", 0, &safer_option, 1},
 
212
{"nosocket", 0, &nosocket_option, 1},
 
213
{"help", 0, 0, 0},
 
214
{"ini", 0, &ini_version, 1},
 
215
{"interaction", 1, 0, 0},
 
216
{"halt-on-error", 0, &haltonerrorp, 1},
 
217
{"kpathsea-debug", 1, 0, 0},
 
218
{"progname", 1, 0, 0},
 
219
{"version", 0, 0, 0},
 
220
{"credits", 0, 0, 0},
 
221
{"recorder", 0, &recorder_enabled, 1},
 
222
{"etex", 0, 0, 0},
 
223
{"output-comment", 1, 0, 0},
 
224
{"output-directory", 1, 0, 0},
 
225
{"draftmode", 0, 0, 0},
 
226
{"output-format", 1, 0, 0},
 
227
{"shell-escape", 0, &shellenabledp, 1},
 
228
{"no-shell-escape", 0, &shellenabledp, -1},
 
229
{"enable-write18", 0, &shellenabledp, 1},
 
230
{"disable-write18", 0, &shellenabledp, -1},
 
231
{"shell-restricted", 0, 0, 0},
 
232
{"debug-format", 0, &debug_format_file, 1},
 
233
{"file-line-error-style", 0, &filelineerrorstylep, 1},
 
234
{"no-file-line-error-style", 0, &filelineerrorstylep, -1},
 
235
      /* Shorter option names for the above. */
 
236
{"file-line-error", 0, &filelineerrorstylep, 1},
 
237
{"no-file-line-error", 0, &filelineerrorstylep, -1},
 
238
{"jobname", 1, 0, 0},
 
239
{"parse-first-line", 0, &parsefirstlinep, 1},
 
240
{"no-parse-first-line", 0, &parsefirstlinep, -1},
 
241
{"translate-file", 1, 0, 0},
 
242
{"default-translate-file", 1, 0, 0},
 
243
{"8bit", 0, 0, 0},
 
244
{"mktex", 1, 0, 0},
 
245
{"no-mktex", 1, 0, 0},
 
246
/* Synchronization: just like "interaction" above */
 
247
{"synctex", 1, 0, 0},
 
248
{0, 0, 0, 0}
 
249
};
 
250
 
 
251
@ @c
 
252
int lua_numeric_field_by_index(lua_State * L, int name_index, int dflt)
 
253
{
 
254
    register int i = dflt;
 
255
    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
 
256
    lua_rawget(L, -2);
 
257
    if (lua_type(L, -1) == LUA_TNUMBER) {
 
258
        i = lua_roundnumber(L, -1);
 
259
    }
 
260
    lua_pop(L, 1);
 
261
    return i;
 
262
}
 
263
 
 
264
@ @c
 
265
unsigned int lua_unsigned_numeric_field_by_index(lua_State * L, int name_index, int dflt)
 
266
{
 
267
    register unsigned int i = dflt;
 
268
    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
 
269
    lua_rawget(L, -2);
 
270
    if (lua_type(L, -1) == LUA_TNUMBER) {
 
271
        i = lua_uroundnumber(L, -1);
 
272
    }
 
273
    lua_pop(L, 1);
 
274
    return i;
 
275
}
 
276
 
 
277
 
 
278
 
 
279
@ @c
 
280
static void parse_options(int ac, char **av)
 
281
{
 
282
#ifdef WIN32
 
283
/* save argc and argv */
 
284
    int sargc = argc;
 
285
    char **sargv = argv;
 
286
#endif
 
287
    int g;                      /* `getopt' return code.  */
 
288
    int option_index;
 
289
    char *firstfile = NULL;
 
290
    opterr = 0;                 /* dont whine */
 
291
#ifdef LuajitTeX
 
292
    if ((strstr(argv[0], "luajittexlua") != NULL) ||
 
293
        (strstr(argv[0], "texluajit") != NULL)) {
 
294
#else
 
295
    if ((strstr(argv[0], "luatexlua") != NULL) ||
 
296
        (strstr(argv[0], "texlua") != NULL)) {
 
297
#endif
 
298
        lua_only = 1;
 
299
        luainit = 1;
 
300
    }
 
301
    for (;;) {
 
302
        g = getopt_long_only(ac, av, "+", long_options, &option_index);
 
303
 
 
304
        if (g == -1)            /* End of arguments, exit the loop.  */
 
305
            break;
 
306
        if (g == '?')  {         /* Unknown option.  */
 
307
          if (!luainit)
 
308
            fprintf(stderr,"%s: unrecognized option '%s'\n", argv[0], argv[optind-1]);
 
309
          continue;
 
310
        }
 
311
 
 
312
        assert(g == 0);         /* We have no short option names.  */
 
313
 
 
314
        if (ARGUMENT_IS("luaonly")) {
 
315
            lua_only = 1;
 
316
            lua_offset = optind;
 
317
            luainit = 1;
 
318
        } else if (ARGUMENT_IS("lua")) {
 
319
            startup_filename = optarg;
 
320
            lua_offset = (optind - 1);
 
321
            luainit = 1;
 
322
#ifdef LuajitTeX
 
323
        } else if (ARGUMENT_IS("jiton")) {
 
324
            luajiton = 1;
 
325
        } else if (ARGUMENT_IS("jithash")) {
 
326
              size_t len = strlen(optarg);
 
327
              if (len<16)
 
328
                jithash_hashname = optarg;
 
329
              else{
 
330
                WARNING2("hash name truncated to 15 characters from %d. (%s)",
 
331
                         (int) len, optarg);
 
332
                jithash_hashname = (string) xmalloc(16);
 
333
                strncpy(jithash_hashname, optarg, 15);
 
334
                jithash_hashname[15] = 0;
 
335
              }
 
336
#endif
 
337
 
 
338
        } else if (ARGUMENT_IS("luahashchars")) {
 
339
            show_luahashchars = 1;
 
340
 
 
341
        } else if (ARGUMENT_IS("kpathsea-debug")) {
 
342
            kpathsea_debug |= atoi(optarg);
 
343
 
 
344
        } else if (ARGUMENT_IS("progname")) {
 
345
            user_progname = optarg;
 
346
 
 
347
        } else if (ARGUMENT_IS("jobname")) {
 
348
            c_job_name = optarg;
 
349
 
 
350
        } else if (ARGUMENT_IS("fmt")) {
 
351
            dump_name = optarg;
 
352
 
 
353
        } else if (ARGUMENT_IS("output-directory")) {
 
354
            output_directory = optarg;
 
355
 
 
356
        } else if (ARGUMENT_IS("output-comment")) {
 
357
            size_t len = strlen(optarg);
 
358
            if (len < 256) {
 
359
                output_comment = optarg;
 
360
            } else {
 
361
                WARNING2("Comment truncated to 255 characters from %d. (%s)",
 
362
                         (int) len, optarg);
 
363
                output_comment = (string) xmalloc(256);
 
364
                strncpy(output_comment, optarg, 255);
 
365
                output_comment[255] = 0;
 
366
            }
 
367
 
 
368
        } else if (ARGUMENT_IS("shell-restricted")) {
 
369
            shellenabledp = 1;
 
370
            restrictedshell = 1;
 
371
 
 
372
        } else if (ARGUMENT_IS("output-format")) {
 
373
            pdf_output_option = 1;
 
374
            if (strcmp(optarg, "dvi") == 0) {
 
375
                pdf_output_value = 0;
 
376
            } else if (strcmp(optarg, "pdf") == 0) {
 
377
                pdf_output_value = 2;
 
378
            } else {
 
379
                WARNING1("Ignoring unknown value `%s' for --output-format",
 
380
                         optarg);
 
381
                pdf_output_option = 0;
 
382
            }
 
383
 
 
384
        } else if (ARGUMENT_IS("draftmode")) {
 
385
            pdf_draftmode_option = 1;
 
386
            pdf_draftmode_value = 1;
 
387
 
 
388
        } else if (ARGUMENT_IS("mktex")) {
 
389
            kpse_maketex_option(optarg, true);
 
390
 
 
391
        } else if (ARGUMENT_IS("no-mktex")) {
 
392
            kpse_maketex_option(optarg, false);
 
393
 
 
394
        } else if (ARGUMENT_IS("interaction")) {
 
395
            /* These numbers match CPP defines */
 
396
            if (STREQ(optarg, "batchmode")) {
 
397
                interactionoption = 0;
 
398
            } else if (STREQ(optarg, "nonstopmode")) {
 
399
                interactionoption = 1;
 
400
            } else if (STREQ(optarg, "scrollmode")) {
 
401
                interactionoption = 2;
 
402
            } else if (STREQ(optarg, "errorstopmode")) {
 
403
                interactionoption = 3;
 
404
            } else {
 
405
                WARNING1("Ignoring unknown argument `%s' to --interaction",
 
406
                         optarg);
 
407
            }
 
408
 
 
409
        } else if (ARGUMENT_IS("synctex")) {
 
410
            /* Synchronize TeXnology: catching the command line option as a long  */
 
411
            synctexoption = (int) strtol(optarg, NULL, 0);
 
412
 
 
413
        } else if (ARGUMENT_IS("help")) {
 
414
            usagehelp(LUATEX_IHELP, BUG_ADDRESS);
 
415
 
 
416
        } else if (ARGUMENT_IS("version")) {
 
417
            print_version_banner();
 
418
            /* *INDENT-OFF* */
 
419
            puts("\n\nExecute  '" my_name " --credits'  for credits and version details.\n\n"
 
420
                 "There is NO warranty. Redistribution of this software is covered by\n"
 
421
                 "the terms of the GNU General Public License, version 2 or (at your option)\n"
 
422
                 "any later version. For more information about these matters, see the file\n"
 
423
                 "named COPYING and the LuaTeX source.\n\n"
 
424
#ifdef LuajitTeX
 
425
                 "LuaTeX is Copyright 2014 Taco Hoekwater, the LuaTeX Team.\n"
 
426
                 "Libraries and JIT extensions by Luigi Scarso, the LuaTeX SwigLib team.\n");
 
427
#else
 
428
                 "Copyright 2014 Taco Hoekwater, the LuaTeX Team.\n");
 
429
#endif
 
430
            /* *INDENT-ON* */
 
431
            uexit(0);
 
432
        } else if (ARGUMENT_IS("credits")) {
 
433
            char *versions;
 
434
            initversionstring(&versions);
 
435
            print_version_banner();
 
436
            /* *INDENT-OFF* */
 
437
            puts("\n\nThe LuaTeX team is Hans Hagen, Hartmut Henkel, Taco Hoekwater.\n"
 
438
                 MyName " merges and builds upon (parts of) the code from these projects:\n\n"
 
439
                 "tex       by Donald Knuth\n"
 
440
                 "etex      by Peter Breitenlohner, Phil Taylor and friends\n"
 
441
                 "omega     by John Plaice and Yannis Haralambous\n"
 
442
                 "aleph     by Giuseppe Bilotta\n"
 
443
                 "pdftex    by Han The Thanh and friends\n"
 
444
                 "kpathsea  by Karl Berry, Olaf Weber and others\n"
 
445
                 "lua       by Roberto Ierusalimschy, Waldemar Celes\n"
 
446
                 "             and Luiz Henrique de Figueiredo\n"
 
447
                 "metapost  by John Hobby, Taco Hoekwater and friends.\n"
 
448
                 "poppler   by Derek Noonburg, Kristian H\\ogsberg (partial)\n"
 
449
#ifdef LuajitTeX
 
450
                 "fontforge by George Williams (partial)\n"
 
451
                 "luajit    by Mike Pall\n\n"
 
452
#else
 
453
                 "fontforge by George Williams (partial)\n\n"
 
454
#endif
 
455
                 "Some extensions to lua and additional lua libraries are used, as well as\n"
 
456
                 "libraries for graphic inclusion. More details can be found in the source.\n"
 
457
                 "Code development was sponsored by a grant from Colorado State University\n"
 
458
#ifdef LuajitTeX
 
459
                 "via the 'oriental tex' project, the TeX User Groups, and donations.\n"
 
460
                 "The additional libraries and the LuaJIT extensions are provided by the LuaTeX SwigLib project.\n");
 
461
#else
 
462
                 "via the 'oriental tex' project, the TeX User Groups, and donations.\n");
 
463
#endif
 
464
            /* *INDENT-ON* */
 
465
            puts(versions);
 
466
            uexit(0);
 
467
        }
 
468
    }
 
469
    /* attempt to find |input_name| / |dump_name| */
 
470
    if (lua_only) {
 
471
        if (argv[optind]) {
 
472
           startup_filename = xstrdup(argv[optind]);
 
473
           lua_offset = optind;
 
474
        }
 
475
    } else if (argv[optind] && argv[optind][0] == '&') {
 
476
        dump_name = xstrdup(argv[optind] + 1);
 
477
    } else if (argv[optind] && argv[optind][0] != '\\') {
 
478
        if (argv[optind][0] == '*') {
 
479
            input_name = xstrdup(argv[optind] + 1);
 
480
        } else {
 
481
            firstfile = xstrdup(argv[optind]);
 
482
            if ((strstr(firstfile, ".lua") ==
 
483
                 firstfile + strlen(firstfile) - 4)
 
484
                || (strstr(firstfile, ".luc") ==
 
485
                    firstfile + strlen(firstfile) - 4)
 
486
                || (strstr(firstfile, ".LUA") ==
 
487
                    firstfile + strlen(firstfile) - 4)
 
488
                || (strstr(firstfile, ".LUC") ==
 
489
                    firstfile + strlen(firstfile) - 4)) {
 
490
                if (startup_filename == NULL) {
 
491
                   startup_filename = firstfile;
 
492
                   lua_offset = optind;
 
493
                   lua_only = 1;
 
494
                   luainit = 1;
 
495
                }
 
496
            } else {
 
497
                input_name = firstfile;
 
498
            }
 
499
        }
 
500
#ifdef WIN32
 
501
    } else if (sargv[sargc-1] && sargv[sargc-1][0] != '-' &&
 
502
               sargv[sargc-1][0] != '\\') {
 
503
        if (sargv[sargc-1][0] == '&')
 
504
            dump_name = xstrdup(sargv[sargc-1] + 1);
 
505
        else  {
 
506
            char *p;
 
507
            if (sargv[sargc-1][0] == '*')
 
508
                input_name = xstrdup(sargv[sargc-1] + 1);
 
509
            else
 
510
                input_name = xstrdup(sargv[sargc-1]);
 
511
            sargv[sargc-1] = normalize_quotes(input_name, "argument");
 
512
            /* Same as
 
513
                  input_name = (char *)xbasename(input_name);
 
514
               but without cast const => non-const.  */
 
515
            input_name += xbasename(input_name) - input_name;
 
516
            p = strrchr(input_name, '.');
 
517
            if (p != NULL && strcasecmp(p, ".tex") == 0)
 
518
                *p = '\0';
 
519
            if (!c_job_name)
 
520
                c_job_name = normalize_quotes(input_name, "jobname");
 
521
        }
 
522
        if (safer_option)      /* --safer implies --nosocket */
 
523
            nosocket_option = 1;
 
524
        return;
 
525
#endif
 
526
    }
 
527
    if (safer_option)           /* --safer implies --nosocket */
 
528
        nosocket_option = 1;
 
529
 
 
530
    /* Finalize the input filename. */
 
531
    if (input_name != NULL) {
 
532
        argv[optind] = normalize_quotes(input_name, "argument");
 
533
    }
 
534
}
 
535
 
 
536
@ test for readability
 
537
@c
 
538
#define is_readable(a) (stat(a,&finfo)==0) && S_ISREG(finfo.st_mode) &&  \
 
539
  (f=fopen(a,"r")) != NULL && !fclose(f)
 
540
 
 
541
@ @c
 
542
static char *find_filename(char *name, const char *envkey)
 
543
{
 
544
    struct stat finfo;
 
545
    char *dirname = NULL;
 
546
    char *filename = NULL;
 
547
    FILE *f;
 
548
    if (is_readable(name)) {
 
549
        return name;
 
550
    } else {
 
551
        dirname = getenv(envkey);
 
552
        if ((dirname != NULL) && strlen(dirname)) {
 
553
            dirname = xstrdup(getenv(envkey));
 
554
            if (*(dirname + strlen(dirname) - 1) == '/') {
 
555
                *(dirname + strlen(dirname) - 1) = 0;
 
556
            }
 
557
            filename = xmalloc((unsigned) (strlen(dirname) + strlen(name) + 2));
 
558
            filename = concat3(dirname, "/", name);
 
559
            if (is_readable(filename)) {
 
560
                xfree(dirname);
 
561
                return filename;
 
562
            }
 
563
            xfree(filename);
 
564
        }
 
565
    }
 
566
    return NULL;
 
567
}
 
568
 
 
569
 
 
570
@ @c
 
571
static void init_kpse(void)
 
572
{
 
573
 
 
574
    if (!user_progname) {
 
575
        user_progname = dump_name;
 
576
    } else if (!dump_name) {
 
577
        dump_name = user_progname;
 
578
    }
 
579
    if (!user_progname) {
 
580
        if (ini_version) {
 
581
            if (input_name) {
 
582
                char *p = input_name + strlen(input_name) - 1;
 
583
                while (p >= input_name) {
 
584
                    if (IS_DIR_SEP (*p)) {
 
585
                        p++;
 
586
                        input_name = p;
 
587
                        break;
 
588
                    }
 
589
                    p--;
 
590
                }
 
591
                user_progname = remove_suffix (input_name);
 
592
            }
 
593
            if (!user_progname) {
 
594
                user_progname = kpse_program_basename(argv[0]);
 
595
            }
 
596
        } else {
 
597
            if (!dump_name) {
 
598
                dump_name = kpse_program_basename(argv[0]);
 
599
            }
 
600
            user_progname = dump_name;
 
601
        }
 
602
    }
 
603
    kpse_set_program_enabled(kpse_fmt_format, MAKE_TEX_FMT_BY_DEFAULT,
 
604
                             kpse_src_compile);
 
605
 
 
606
    kpse_set_program_name(argv[0], user_progname);
 
607
    init_shell_escape();        /* set up 'restrictedshell' */
 
608
    program_name_set = 1;
 
609
}
 
610
 
 
611
@ @c
 
612
static void fix_dumpname(void)
 
613
{
 
614
    int dist;
 
615
    if (dump_name) {
 
616
        /* adjust array for Pascal and provide extension, if needed */
 
617
        dist = (int) (strlen(dump_name) - strlen(DUMP_EXT));
 
618
        if (strstr(dump_name, DUMP_EXT) == dump_name + dist)
 
619
            TEX_format_default = dump_name;
 
620
        else
 
621
            TEX_format_default = concat(dump_name, DUMP_EXT);
 
622
    } else {
 
623
        /* For |dump_name| to be NULL is a bug.  */
 
624
        if (!ini_version)
 
625
            abort();
 
626
    }
 
627
}
 
628
 
 
629
@ lua require patch
 
630
 
 
631
@ Auxiliary function for kpse search
 
632
 
 
633
@c
 
634
static const char *luatex_kpse_find_aux(lua_State *L, const char *name,
 
635
        kpse_file_format_type format, const char *errname)
 
636
{
 
637
    const char *filename;
 
638
    const char *altname;
 
639
    altname = luaL_gsub(L, name, ".", "/"); /* Lua convention */
 
640
    filename = kpse_find_file(altname, format, false);
 
641
    if (filename == NULL) {
 
642
        filename = kpse_find_file(name, format, false);
 
643
    }
 
644
    if (filename == NULL) {
 
645
        lua_pushfstring(L, "\n\t[kpse %s searcher] file not found: " LUA_QS,
 
646
                        errname, name);
 
647
    }
 
648
    return filename;
 
649
}
 
650
 
 
651
@ The lua search function.
 
652
 
 
653
When kpathsea is not initialized, then it runs the
 
654
normal lua function that is saved in the registry, otherwise
 
655
it uses kpathsea.
 
656
 
 
657
two registry ref variables are needed: one for the actual lua
 
658
function, the other for its environment .
 
659
 
 
660
@c
 
661
static int lua_loader_function = 0;
 
662
 
 
663
static int luatex_kpse_lua_find(lua_State * L)
 
664
{
 
665
    const char *filename;
 
666
    const char *name;
 
667
    name = luaL_checkstring(L, 1);
 
668
    if (program_name_set == 0) {
 
669
        lua_rawgeti(L, LUA_REGISTRYINDEX, lua_loader_function);
 
670
        lua_pushvalue(L, -2);
 
671
        lua_call(L, 1, 1);
 
672
        return 1;
 
673
    }
 
674
    filename = luatex_kpse_find_aux(L, name, kpse_lua_format, "lua");
 
675
    if (filename == NULL)
 
676
        return 1;               /* library not found in this path */
 
677
    if (luaL_loadfile(L, filename) != 0) {
 
678
        luaL_error(L, "error loading module %s from file %s:\n\t%s",
 
679
                   lua_tostring(L, 1), filename, lua_tostring(L, -1));
 
680
    }
 
681
    return 1;                   /* library loaded successfully */
 
682
}
 
683
 
 
684
@ @c
 
685
static int clua_loader_function = 0;
 
686
extern int searcher_C_luatex (lua_State *L, const char *name, const char *filename);
 
687
 
 
688
static int luatex_kpse_clua_find(lua_State * L)
 
689
{
 
690
    const char *filename;
 
691
    const char *name;
 
692
    if (safer_option) {
 
693
        lua_pushliteral(L, "\n\t[C searcher disabled in safer mode]");
 
694
        return 1;               /* library not found in this path */
 
695
    }
 
696
    name = luaL_checkstring(L, 1);
 
697
    if (program_name_set == 0) {
 
698
        lua_rawgeti(L, LUA_REGISTRYINDEX, clua_loader_function);
 
699
        lua_pushvalue(L, -2);
 
700
        lua_call(L, 1, 1);
 
701
        return 1;
 
702
    } else {
 
703
        const char *path_saved;
 
704
        char *prefix, *postfix, *p, *total;
 
705
        char *extensionless;
 
706
        char *temp_name;
 
707
        int j;
 
708
        filename = luatex_kpse_find_aux(L, name, kpse_clua_format, "C");
 
709
        if (filename == NULL)
 
710
           return 1;               /* library not found in this path */
 
711
        extensionless = strdup(filename);
 
712
        if (!extensionless) return 1;  /* allocation failure */
 
713
        /* Fix Issue 850: replace '.' with LUA_DIRSEP */
 
714
        temp_name = strdup(name);
 
715
        for(j=0; ; j++){
 
716
          if ((unsigned char)temp_name[j]=='\0') {
 
717
            break;
 
718
          }
 
719
          if ((unsigned char)temp_name[j]=='.'){
 
720
            temp_name[j]=LUA_DIRSEP[0];
 
721
          }
 
722
        }
 
723
        p = strstr(extensionless, temp_name);
 
724
        if (!p) return 1;  /* this would be exceedingly weird */
 
725
        *p = '\0';
 
726
        prefix = strdup(extensionless);
 
727
        if (!prefix) return 1;  /* allocation failure */
 
728
        postfix = strdup(p+strlen(name));
 
729
        if (!postfix) return 1;  /* allocation failure */
 
730
        total = malloc(strlen(prefix)+strlen(postfix)+2);
 
731
        if (!total) return 1;  /* allocation failure */
 
732
        snprintf(total,strlen(prefix)+strlen(postfix)+2, "%s?%s", prefix, postfix);
 
733
        /* save package.path */
 
734
        lua_getglobal(L,"package");
 
735
        lua_getfield(L,-1,"cpath");
 
736
        path_saved = lua_tostring(L,-1);
 
737
        lua_pop(L,1);
 
738
        /* set package.path = "?" */
 
739
        lua_pushstring(L,total);
 
740
        lua_setfield(L,-2,"cpath");
 
741
        lua_pop(L,1); /* pop "package" */
 
742
        /* run function */
 
743
        lua_rawgeti(L, LUA_REGISTRYINDEX, clua_loader_function);
 
744
        lua_pushstring(L, name);
 
745
        lua_call(L, 1, 1);
 
746
        /* restore package.path */
 
747
        lua_getglobal(L,"package");
 
748
        lua_pushstring(L,path_saved);
 
749
        lua_setfield(L,-2,"cpath");
 
750
        lua_pop(L,1); /* pop "package" */
 
751
        free(extensionless);
 
752
        free(total);
 
753
        free(temp_name);
 
754
        return 1;
 
755
    }
 
756
}
 
757
 
 
758
@ Setting up the new search functions.
 
759
 
 
760
This replaces package.searchers[2] and package.searchers[3] with the
 
761
functions defined above.
 
762
 
 
763
@c
 
764
static void setup_lua_path(lua_State * L)
 
765
{
 
766
    lua_getglobal(L, "package");
 
767
#ifdef LuajitTeX
 
768
    lua_getfield(L, -1, "loaders");
 
769
#else
 
770
    lua_getfield(L, -1, "searchers");
 
771
#endif
 
772
    lua_rawgeti(L, -1, 2);      /* package.searchers[2] */
 
773
    lua_loader_function = luaL_ref(L, LUA_REGISTRYINDEX);
 
774
    lua_pushcfunction(L, luatex_kpse_lua_find);
 
775
    lua_rawseti(L, -2, 2);      /* replace the normal lua loader */
 
776
 
 
777
    lua_rawgeti(L, -1, 3);      /* package.searchers[3] */
 
778
    clua_loader_function = luaL_ref(L, LUA_REGISTRYINDEX);
 
779
    lua_pushcfunction(L, luatex_kpse_clua_find);
 
780
    lua_rawseti(L, -2, 3);      /* replace the normal lua lib loader */
 
781
 
 
782
    lua_pop(L, 2);              /* pop the array and table */
 
783
}
 
784
 
 
785
@ helper variables for the safe keeping of table ids
 
786
 
 
787
@c
 
788
int tex_table_id;
 
789
int pdf_table_id;
 
790
int newtoken_table_id;
 
791
int token_table_id;
 
792
int node_table_id;
 
793
 
 
794
@ @c
 
795
int l_pack_type_index       [PACK_TYPE_SIZE] ;
 
796
int l_group_code_index      [GROUP_CODE_SIZE];
 
797
int l_math_style_name_index [MATH_STYLE_NAME_SIZE];
 
798
int l_dir_par_index         [DIR_PAR_SIZE];
 
799
int l_dir_text_index        [DIR_TEXT_SIZE];
 
800
 
 
801
 
 
802
#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
 
803
char **suffixlist;
 
804
 
 
805
#  define EXE_SUFFIXES ".com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh;.ws;.tcl;.py;.pyw"
 
806
 
 
807
@ @c
 
808
static void mk_suffixlist(void)
 
809
{
 
810
    char **p;
 
811
    char *q, *r, *v;
 
812
    int n;
 
813
 
 
814
#  if defined(__CYGWIN__)
 
815
    v = xstrdup(EXE_SUFFIXES);
 
816
#  else
 
817
    v = (char *) getenv("PATHEXT");
 
818
    if (v)                      /* strlwr() exists also in MingW */
 
819
        v = (char *) strlwr(xstrdup(v));
 
820
    else
 
821
        v = xstrdup(EXE_SUFFIXES);
 
822
#  endif
 
823
 
 
824
    q = v;
 
825
    n = 0;
 
826
 
 
827
    while ((r = strchr(q, ';')) != NULL) {
 
828
        n++;
 
829
        r++;
 
830
        q = r;
 
831
    }
 
832
    if (*q)
 
833
        n++;
 
834
    suffixlist = (char **) xmalloc((n + 2) * sizeof(char *));
 
835
    p = suffixlist;
 
836
    *p = xstrdup(".dll");
 
837
    p++;
 
838
    q = v;
 
839
    while ((r = strchr(q, ';')) != NULL) {
 
840
        *r = '\0';
 
841
        *p = xstrdup(q);
 
842
        p++;
 
843
        r++;
 
844
        q = r;
 
845
    }
 
846
    if (*q) {
 
847
        *p = xstrdup(q);
 
848
        p++;
 
849
    }
 
850
    *p = NULL;
 
851
    free(v);
 
852
}
 
853
#endif
 
854
 
 
855
 
 
856
@ @c
 
857
void lua_initialize(int ac, char **av)
 
858
{
 
859
 
 
860
    char *given_file = NULL;
 
861
    char *banner;
 
862
    int kpse_init;
 
863
    static char LC_CTYPE_C[] = "LC_CTYPE=C";
 
864
    static char LC_COLLATE_C[] = "LC_COLLATE=C";
 
865
    static char LC_NUMERIC_C[] = "LC_NUMERIC=C";
 
866
    static char engine_luatex[] = "engine=" my_name;
 
867
    /* Save to pass along to topenin.  */
 
868
    argc = ac;
 
869
    argv = av;
 
870
 
 
871
 
 
872
    if (luatex_svn < 0) {
 
873
        const char *fmt = "This is " MyName ", Version %s" WEB2CVERSION;
 
874
        size_t len;
 
875
        len = strlen(fmt) + strlen(luatex_version_string) ;
 
876
 
 
877
        banner = xmalloc(len);
 
878
        sprintf(banner, fmt, luatex_version_string);
 
879
    } else {
 
880
        const char *fmt = "This is " MyName ", Version %s" WEB2CVERSION " (rev %d)";
 
881
        size_t len;
 
882
        len = strlen(fmt) + strlen(luatex_version_string) + 6;
 
883
        banner = xmalloc(len);
 
884
        sprintf(banner, fmt, luatex_version_string, luatex_svn);
 
885
    }
 
886
    luatex_banner = banner;
 
887
    kpse_invocation_name = kpse_program_basename(argv[0]);
 
888
 
 
889
    /* be 'luac' */
 
890
    if (argc >1) {
 
891
#ifdef LuajitTeX
 
892
        if (FILESTRCASEEQ(kpse_invocation_name, "texluajitc"))
 
893
            exit(luac_main(ac, av));
 
894
        if (STREQ(argv[1], "--luaconly") || STREQ(argv[1], "--luac")) {
 
895
            char *argv1 = xmalloc (strlen ("luajittex") + 1);
 
896
            av[1] = argv1;
 
897
            strcpy (av[1], "luajittex");
 
898
            exit(luac_main(--ac, ++av));
 
899
        }
 
900
#else
 
901
        if (FILESTRCASEEQ(kpse_invocation_name, "texluac"))
 
902
            exit(luac_main(ac, av));
 
903
        if (STREQ(argv[1], "--luaconly") || STREQ(argv[1], "--luac")) {
 
904
            strcpy(av[1], "luatex");
 
905
            exit(luac_main(--ac, ++av));
 
906
        }
 
907
#endif
 
908
    }
 
909
#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
 
910
    mk_suffixlist();
 
911
#endif
 
912
 
 
913
    /* Must be initialized before options are parsed.  */
 
914
    interactionoption = 4;
 
915
    dump_name = NULL;
 
916
 
 
917
    /* 0 means "disable Synchronize TeXnology".
 
918
     synctexoption is a *.web variable.
 
919
     We initialize it to a weird value to catch the -synctex command line flag
 
920
     At runtime, if synctexoption is not |INT_MAX|, then it contains the command line option provided,
 
921
     otherwise no such option was given by the user. */
 
922
#define SYNCTEX_NO_OPTION INT_MAX
 
923
    synctexoption = SYNCTEX_NO_OPTION;
 
924
 
 
925
    /* parse commandline */
 
926
    parse_options(ac, av);
 
927
    if (lua_only)
 
928
        shellenabledp = true;
 
929
 
 
930
    /* make sure that the locale is 'sane' (for lua) */
 
931
 
 
932
    putenv(LC_CTYPE_C);
 
933
    putenv(LC_COLLATE_C);
 
934
    putenv(LC_NUMERIC_C);
 
935
 
 
936
    /* this is sometimes needed */
 
937
    putenv(engine_luatex);
 
938
 
 
939
    luainterpreter();
 
940
 
 
941
    /* init internalized strings */
 
942
    set_init_keys;
 
943
 
 
944
    lua_pushstring(Luas,"lua.functions");
 
945
    lua_newtable(Luas);
 
946
    lua_settable(Luas,LUA_REGISTRYINDEX);
 
947
 
 
948
    /* here start the key definitions */
 
949
    set_pack_type_index;
 
950
    set_l_group_code_index;
 
951
    set_l_math_style_name_index;
 
952
    set_l_dir_par_index;
 
953
    set_l_dir_text_index;
 
954
 
 
955
    prepare_cmdline(Luas, argv, argc, lua_offset);      /* collect arguments */
 
956
    setup_lua_path(Luas);
 
957
 
 
958
    if (startup_filename != NULL) {
 
959
        given_file = xstrdup(startup_filename);
 
960
        startup_filename = find_filename(startup_filename, "LUATEXDIR");
 
961
    }
 
962
    /* now run the file */
 
963
    if (startup_filename != NULL) {
 
964
        char *v1;
 
965
        /* hide the 'tex' and 'pdf' table */
 
966
        tex_table_id = hide_lua_table(Luas, "tex");
 
967
        newtoken_table_id = hide_lua_table(Luas, "newtoken");
 
968
        token_table_id = hide_lua_table(Luas, "token");
 
969
        node_table_id = hide_lua_table(Luas, "node");
 
970
        pdf_table_id = hide_lua_table(Luas, "pdf");
 
971
 
 
972
        if (luaL_loadfile(Luas, startup_filename)) {
 
973
            fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
 
974
            exit(1);
 
975
        }
 
976
        /* */
 
977
        init_tex_table(Luas);
 
978
        if (lua_pcall(Luas, 0, 0, 0)) {
 
979
            fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
 
980
            lua_traceback(Luas);
 
981
            exit(1);
 
982
        }
 
983
        /* no filename? quit now! */
 
984
        if (!input_name) {
 
985
            get_lua_string("texconfig", "jobname", &input_name);
 
986
        }
 
987
        if (!dump_name) {
 
988
            get_lua_string("texconfig", "formatname", &dump_name);
 
989
        }
 
990
        if (lua_only) {
 
991
            if (given_file)
 
992
                free(given_file);
 
993
            /* this is not strictly needed but it pleases valgrind */
 
994
            lua_close(Luas);
 
995
            exit(0);
 
996
        }
 
997
        /* unhide the 'tex' and 'pdf' table */
 
998
        unhide_lua_table(Luas, "tex", tex_table_id);
 
999
        unhide_lua_table(Luas, "pdf", pdf_table_id);
 
1000
        unhide_lua_table(Luas, "newtoken", newtoken_table_id);
 
1001
        unhide_lua_table(Luas, "token", token_table_id);
 
1002
        unhide_lua_table(Luas, "node", node_table_id);
 
1003
 
 
1004
        /* |kpse_init| */
 
1005
        kpse_init = -1;
 
1006
        get_lua_boolean("texconfig", "kpse_init", &kpse_init);
 
1007
 
 
1008
        if (kpse_init != 0) {
 
1009
            luainit = 0;        /* re-enable loading of texmf.cnf values, see luatex.ch */
 
1010
            init_kpse();
 
1011
        }
 
1012
        /* |prohibit_file_trace| (boolean) */
 
1013
        tracefilenames = 1;
 
1014
        get_lua_boolean("texconfig", "trace_file_names", &tracefilenames);
 
1015
 
 
1016
        /* |file_line_error| */
 
1017
        filelineerrorstylep = false;
 
1018
        get_lua_boolean("texconfig", "file_line_error", &filelineerrorstylep);
 
1019
 
 
1020
        /* |halt_on_error| */
 
1021
        haltonerrorp = false;
 
1022
        get_lua_boolean("texconfig", "halt_on_error", &haltonerrorp);
 
1023
 
 
1024
        /* |restrictedshell| */
 
1025
        v1 = NULL;
 
1026
        get_lua_string("texconfig", "shell_escape", &v1);
 
1027
        if (v1) {
 
1028
            if (*v1 == 't' || *v1 == 'y' || *v1 == '1') {
 
1029
                shellenabledp = 1;
 
1030
            } else if (*v1 == 'p') {
 
1031
                shellenabledp = 1;
 
1032
                restrictedshell = 1;
 
1033
            }
 
1034
            free(v1);
 
1035
        }
 
1036
        /* If shell escapes are restricted, get allowed cmds from cnf.  */
 
1037
        if (shellenabledp && restrictedshell == 1) {
 
1038
            v1 = NULL;
 
1039
            get_lua_string("texconfig", "shell_escape_commands", &v1);
 
1040
            if (v1) {
 
1041
                mk_shellcmdlist(v1);
 
1042
                free(v1);
 
1043
            }
 
1044
        }
 
1045
 
 
1046
        fix_dumpname();
 
1047
 
 
1048
    } else {
 
1049
        if (luainit) {
 
1050
            if (given_file) {
 
1051
                fprintf(stdout, "%s file %s not found\n",
 
1052
                        (lua_only ? "Script" : "Configuration"), given_file);
 
1053
                free(given_file);
 
1054
            } else {
 
1055
                fprintf(stdout, "No %s file given\n",
 
1056
                        (lua_only ? "script" : "configuration"));
 
1057
            }
 
1058
            exit(1);
 
1059
        } else {
 
1060
            /* init */
 
1061
            init_kpse();
 
1062
            fix_dumpname();
 
1063
        }
 
1064
    }
 
1065
}
 
1066
 
 
1067
@ @c
 
1068
void check_texconfig_init(void)
 
1069
{
 
1070
    if (Luas != NULL) {
 
1071
        lua_getglobal(Luas, "texconfig");
 
1072
        if (lua_istable(Luas, -1)) {
 
1073
            lua_getfield(Luas, -1, "init");
 
1074
            if (lua_isfunction(Luas, -1)) {
 
1075
                int i = lua_pcall(Luas, 0, 0, 0);
 
1076
                if (i != 0) {
 
1077
                    /* Can't be more precise here, called before TeX initialization  */
 
1078
                    fprintf(stderr, "This went wrong: %s\n",
 
1079
                            lua_tostring(Luas, -1));
 
1080
                    error();
 
1081
                }
 
1082
            }
 
1083
        }
 
1084
    }
 
1085
}
 
1086
 
 
1087
@ @c
 
1088
void write_svnversion(char *v)
 
1089
{
 
1090
    char *a_head, *n;
 
1091
    char *a = xstrdup(v);
 
1092
    size_t l = strlen("$Id: luatex.web ");
 
1093
    if (a != NULL) {
 
1094
        a_head = a;
 
1095
        if (strlen(a) > l)
 
1096
            a += l;
 
1097
        n = a;
 
1098
        while (*n != '\0' && *n != ' ')
 
1099
            n++;
 
1100
        *n = '\0';
 
1101
        fprintf(stdout, " luatex.web >= v%s", a);
 
1102
        free(a_head);
 
1103
    }
 
1104
}