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