1% luainit.w 2% 3% Copyright 2006-2015 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 */ 30set_make_keys; 31 32 33@ 34TH: TODO 35 36This file is getting a bit messy, but it is not simple to fix unilaterally. 37 38Better to wait until Karl has some time (after texlive 2008) so we can 39synchronize with kpathsea. One problem, for instance, is that I would 40like to resolve the full executable path. |kpse_set_program_name()| does 41that, indirectly (by setting SELFAUTOLOC in the environment), but it 42does much more, making it hard to use for our purpose. 43 44In fact, it sets three C variables: 45 46 |kpse_invocation_name| |kpse_invocation_short_name| |kpse->program_name| 47 48and five environment variables: 49 50 SELFAUTOLOC SELFAUTODIR SELFAUTOPARENT SELFAUTOGRANDPARENT progname 51 52@c 53const_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 120static 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 154static void 155prepare_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 175string input_name = NULL; 176 177static string user_progname = NULL; 178 179char *startup_filename = NULL; 180int lua_only = 0; 181int lua_offset = 0; 182unsigned char show_luahashchars = 0; 183 184#ifdef LuajitTeX 185int luajiton = 0; 186char *jithash_hashname = NULL; 187#endif 188 189int safer_option = 0; 190int nosocket_option = 0; 191 192@ Reading the options. 193 194@ Test whether getopt found an option ``A''. 195Assumes the option index is in the variable |option_index|, and the 196option 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. */ 202static 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 252int 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 265unsigned 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 280static 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 2015 Taco Hoekwater, the LuaTeX Team.\n" 426 "Libraries and JIT extensions by Luigi Scarso, the LuaTeX SwigLib team.\n"); 427#else 428 "Copyright 2015 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 542static 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 571static 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 612static 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 634static 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 653When kpathsea is not initialized, then it runs the 654normal lua function that is saved in the registry, otherwise 655it uses kpathsea. 656 657two registry ref variables are needed: one for the actual lua 658function, the other for its environment . 659 660@c 661static int lua_loader_function = 0; 662 663static 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 685static int clua_loader_function = 0; 686extern int searcher_C_luatex (lua_State *L, const char *name, const char *filename); 687 688static 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 760This replaces package.searchers[2] and package.searchers[3] with the 761functions defined above. 762 763@c 764static 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 788int tex_table_id; 789int pdf_table_id; 790int newtoken_table_id; 791int token_table_id; 792int node_table_id; 793 794@ @c 795int l_pack_type_index [PACK_TYPE_SIZE] ; 796int l_group_code_index [GROUP_CODE_SIZE]; 797int l_math_style_name_index [MATH_STYLE_NAME_SIZE]; 798int l_dir_par_index [DIR_PAR_SIZE]; 799int l_dir_text_index [DIR_TEXT_SIZE]; 800 801 802#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__) 803char **suffixlist; 804 805# define EXE_SUFFIXES ".com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh;.ws;.tcl;.py;.pyw" 806 807@ @c 808static 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 857void 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 1068void 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 1088void 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} 1105