diff --git a/luametalatex-kpse/lkpselib.c b/luametalatex-kpse/lkpselib.c new file mode 100644 index 0000000..1b71632 --- /dev/null +++ b/luametalatex-kpse/lkpselib.c @@ -0,0 +1,875 @@ +/* lkpselib.c + + Copyright 2020 Marcel Krüger + + This file is based on a file from LuaTeX. + + LuaTeX is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + LuaTeX is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU General Public License along + with LuaTeX; if not, see . */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static const char *const filetypenames[] = { + "gf", + "pk", + "bitmap font", + "tfm", + "afm", + "base", + "bib", + "bst", + "cnf", + "ls-R", + "fmt", + "map", + "mem", + "mf", + "mfpool", + "mft", + "mp", + "mppool", + "MetaPost support", + "ocp", + "ofm", + "opl", + "otp", + "ovf", + "ovp", + "graphic/figure", + "tex", + "TeX system documentation", + "texpool", + "TeX system sources", + "PostScript header", + "Troff fonts", + "type1 fonts", + "vf", + "dvips config", + "ist", + "truetype fonts", + "type42 fonts", + "web2c files", + "other text files", + "other binary files", + "misc fonts", + "web", + "cweb", + "enc files", + "cmap files", + "subfont definition files", + "opentype fonts", + "pdftex config", + "lig files", + "texmfscripts", + "lua", + "font feature files", + "cid maps", + "mlbib", + "mlbst", + "clua", + "ris", + "bltxml", + NULL +}; + +_Static_assert(kpse_last_format == sizeof(filetypenames)/sizeof(*filetypenames) - 1, "Mismatch in format types"); + +static const char *const srcnames[] = { + "implicit", /* C initialization to zero */ + "compile", /* configure/compile-time default */ + "texmf_cnf", /* texmf.cnf, the kpathsea config file */ + "client_cnf", /* application config file, e.g., config.ps */ + "env", /* environment variable */ + "x", /* X Window System resource */ + "cmdline", /* command-line option */ + NULL +}; + +_Static_assert(kpse_src_cmdline == sizeof(srcnames)/sizeof(*srcnames) - 2, "Mismatch in configuration sources"); + + + +#define KPATHSEA_METATABLE "luametalatex.kpathsea" + +/* set to 1 by the |program_name| function */ + +int program_name_set = 0; + +#define TEST_PROGRAM_NAME_SET do { \ + if (! program_name_set) { \ + return luaL_error(L, "Please call kpse.set_program_name() before using the library"); \ + } \ + } while (0) + +static int find_file(lua_State * L) +{ + int i, t; + const char *st; + unsigned ftype = kpse_tex_format; + int mexist = 0; + TEST_PROGRAM_NAME_SET; + if (lua_type(L, 1) != LUA_TSTRING) { + luaL_error(L, "not a file name"); + } + st = lua_tostring(L, 1); + i = lua_gettop(L); + while (i > 1) { + t = lua_type(L, i) ; + if (t == LUA_TBOOLEAN) { + mexist = lua_toboolean(L, i); + } else if (t == LUA_TNUMBER) { + mexist = (int) lua_tointeger(L, i); + } else if (t == LUA_TSTRING) { + ftype = luaL_checkoption(L, i, NULL, filetypenames); + } else { + /* ignore */ + } + i--; + } + if (ftype == kpse_pk_format || + ftype == kpse_gf_format || ftype == kpse_any_glyph_format) { + /* ret.format, ret.name, ret.dpi */ + kpse_glyph_file_type ret; + lua_pushstring(L, kpse_find_glyph(st, (unsigned) mexist, ftype, &ret)); + } else { + if (mexist > 0) + mexist = 1; + if (mexist < 0) + mexist = 0; + lua_pushstring(L, kpse_find_file(st, ftype, mexist)); + } + return 1; +} + + +static int lua_kpathsea_find_file(lua_State * L) +{ + int i, t; + unsigned ftype = kpse_tex_format; + int mexist = 0; + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + const char *st = luaL_checkstring(L, 2); + i = lua_gettop(L); + while (i > 2) { + t = lua_type(L, i) ; + if (t == LUA_TBOOLEAN) { + mexist = (boolean) lua_toboolean(L, i); + } else if (t == LUA_TNUMBER) { + mexist = (int) lua_tointeger(L, i); + } else if (t == LUA_TSTRING) { + ftype = luaL_checkoption(L, i, NULL, filetypenames); + } else { + /* ignore */ + } + i--; + } + if (ftype == kpse_pk_format || ftype == kpse_gf_format || ftype == kpse_any_glyph_format) { + /* ret.format, ret.name, ret.dpi */ + kpse_glyph_file_type ret; + lua_pushstring(L, kpathsea_find_glyph(*kp, st, (unsigned) mexist, ftype, &ret)); + } else { + if (mexist > 0) + mexist = 1; + if (mexist < 0) + mexist = 0; + lua_pushstring(L, kpathsea_find_file(*kp, st, ftype, mexist)); + } + return 1; + +} + +static int show_texmfcnf(lua_State * L) +{ + lua_pushstring(L, DEFAULT_TEXMFCNF); + return 1; +} + +static int show_path(lua_State * L) +{ + unsigned user_format = luaL_checkoption(L, -1, "tex", filetypenames); + TEST_PROGRAM_NAME_SET; + if (!kpse_format_info[user_format].type) /* needed if arg was numeric */ + kpse_init_format(user_format); + lua_pushstring(L, kpse_format_info[user_format].path); + return 1; +} + +static int lua_kpathsea_show_path(lua_State * L) +{ + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + unsigned user_format = luaL_checkoption(L, -1, "tex", filetypenames); + if (!(*kp)->format_info[user_format].type) /* needed if arg was numeric */ + kpathsea_init_format(*kp, user_format); + lua_pushstring(L, (*kp)->format_info[user_format].path); + return 1; +} + +static int expand_path(lua_State * L) +{ + const char *st = luaL_checkstring(L, 1); + TEST_PROGRAM_NAME_SET; + lua_pushstring(L, kpse_path_expand(st)); + return 1; +} + +static int lua_kpathsea_expand_path(lua_State * L) +{ + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + const char *st = luaL_checkstring(L, 2); + lua_pushstring(L, kpathsea_path_expand(*kp, st)); + return 1; +} + +static int expand_braces(lua_State * L) +{ + const char *st = luaL_checkstring(L, 1); + TEST_PROGRAM_NAME_SET; + lua_pushstring(L, kpse_brace_expand(st)); + return 1; +} + +static int lua_kpathsea_expand_braces(lua_State * L) +{ + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + const char *st = luaL_checkstring(L, 2); + lua_pushstring(L, kpathsea_brace_expand(*kp, st)); + return 1; +} + + +static int expand_var(lua_State * L) +{ + const char *st = luaL_checkstring(L, 1); + TEST_PROGRAM_NAME_SET; + lua_pushstring(L, kpse_var_expand(st)); + return 1; +} + +static int lua_kpathsea_expand_var(lua_State * L) +{ + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + const char *st = luaL_checkstring(L, 2); + lua_pushstring(L, kpathsea_var_expand(*kp, st)); + return 1; +} + + +static int var_value(lua_State * L) +{ + const char *st = luaL_checkstring(L, 1); + TEST_PROGRAM_NAME_SET; + lua_pushstring(L, kpse_var_value(st)); + return 1; +} + +static int lua_kpathsea_var_value(lua_State * L) +{ + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + const char *st = luaL_checkstring(L, 2); + lua_pushstring(L, kpathsea_var_value(*kp, st)); + return 1; +} + +static int is_absolute(lua_State * L) +{ + const char *path = luaL_checkstring(L, 1); + boolean accept_relative = lua_toboolean(L, 2); + TEST_PROGRAM_NAME_SET; + lua_pushboolean(L, kpse_absolute_p(path, accept_relative)); + return 1; +} + +static int lua_kpathsea_is_absolute(lua_State * L) +{ + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + const char *path = luaL_checkstring(L, 2); + boolean accept_relative = lua_toboolean(L, 3); + lua_pushboolean(L, kpathsea_absolute_p(*kp, path, accept_relative)); + return 1; +} + +static unsigned find_dpi(const_string s) +{ + unsigned dpi_number = 0; + const_string extension = find_suffix(s); + + if (extension != NULL) + sscanf(extension, "%u", &dpi_number); + + return dpi_number; +} + +/* + Return newly-allocated NULL-terminated list of strings from MATCHES + that are prefixed with any of the subdirectories in SUBDIRS. That + is, for a string S in MATCHES, its dirname must end with one of the + elements in SUBDIRS. For instance, if subdir=foo/bar, that will + match a string foo/bar/baz or /some/texmf/foo/bar/baz. + + We don't reallocate the actual strings, just the list elements. + Perhaps later we will implement wildcards or "//" or something. +*/ + +static string *subdir_match(str_list_type subdirs, string * matches) +{ + string *ret = XTALLOC1(string); + unsigned len = 1; + unsigned m; + + for (m = 0; matches[m]; m++) { + size_t loc; + unsigned e; + string s = xstrdup(matches[m]); + for (loc = strlen(s); loc > 0 && !IS_DIR_SEP(s[loc - 1]); loc--); + while (loc > 0 && IS_DIR_SEP(s[loc - 1])) { + loc--; + } + s[loc] = 0; /* wipe out basename */ + + for (e = 0; e < STR_LIST_LENGTH(subdirs); e++) { + string subdir = STR_LIST_ELT(subdirs, e); + size_t subdir_len = strlen(subdir); + while (subdir_len > 0 && IS_DIR_SEP(subdir[subdir_len - 1])) { + subdir_len--; + subdir[subdir_len] = 0; /* remove trailing slashes from subdir spec */ + } + if (FILESTRCASEEQ(subdir, s + loc - subdir_len)) { + /* matched, save this one. */ + XRETALLOC(ret, len + 1, string); + ret[len - 1] = matches[m]; + len++; + } + } + free(s); + } + ret[len - 1] = NULL; + return ret; +} + +/* Use the file type from -format if that was specified (i.e., the + user_format global variable), else guess dynamically from NAME. + Return kpse_last_format if undeterminable. This function is also + used to parse the -format string, a case which we distinguish by + setting is_filename to false. + + A few filenames have been hard-coded for format types that + differ from what would be inferred from their extensions. */ + +static kpse_file_format_type +find_format(kpathsea kpse, const_string name, boolean is_filename) +{ + kpse_file_format_type ret; + + if (FILESTRCASEEQ(name, "config.ps")) { + ret = kpse_dvips_config_format; + } else if (FILESTRCASEEQ(name, "dvipdfmx.cfg")) { + ret = kpse_program_text_format; + } else if (FILESTRCASEEQ(name, "fmtutil.cnf")) { + ret = kpse_web2c_format; + } else if (FILESTRCASEEQ(name, "glyphlist.txt")) { + ret = kpse_fontmap_format; + } else if (FILESTRCASEEQ(name, "mktex.cnf")) { + ret = kpse_web2c_format; + } else if (FILESTRCASEEQ(name, "pdfglyphlist.txt")) { + ret = kpse_fontmap_format; + } else if (FILESTRCASEEQ(name, "pdftex.cfg")) { + ret = kpse_pdftex_config_format; + } else if (FILESTRCASEEQ(name, "texmf.cnf")) { + ret = kpse_cnf_format; + } else if (FILESTRCASEEQ(name, "updmap.cfg")) { + ret = kpse_web2c_format; + } else if (FILESTRCASEEQ(name, "XDvi")) { + ret = kpse_program_text_format; + } else { + int f = 0; /* kpse_file_format_type */ + size_t name_len = strlen(name); + +/* Have to rely on `try_len' being declared here, since we can't assume + GNU C and statement expressions. */ +#define TRY_SUFFIX(ftry) (\ + try_len = (ftry) ? strlen (ftry) : 0, \ + (ftry) && try_len <= name_len \ + && FILESTRCASEEQ (ftry, name + name_len - try_len)) + + while (f != kpse_last_format) { + size_t try_len; + const_string *ext; + const_string ftry; + boolean found = false; + + if (!kpse->format_info[f].type) + kpathsea_init_format(kpse, (kpse_file_format_type) f); + + if (!is_filename) { + /* Allow the long name, but only in the -format option. We don't + want a filename confused with a format name. */ + ftry = kpse->format_info[f].type; + found = TRY_SUFFIX(ftry); + } + for (ext = kpse->format_info[f].suffix; !found && ext && *ext; + ext++) { + found = TRY_SUFFIX(*ext); + } + for (ext = kpse->format_info[f].alt_suffix; !found && ext && *ext; + ext++) { + found = TRY_SUFFIX(*ext); + } + + if (found) + break; + + /* Some trickery here: the extensions for kpse_fmt_format can + * clash with other extensions in use, and we prefer for those + * others to be preferred. And we don't want to change the + * integer value of kpse_fmt_format. So skip it when first + * enountered, then use it when we've done everything else, + * and use it as the end-guard. + */ + if (f == kpse_fmt_format) { + f = kpse_last_format; + } else if (++f == kpse_fmt_format) { + f++; + } else if (f == kpse_last_format) { + f = kpse_fmt_format; + } + } + + /* If there was a match, f will be one past the correct value. */ + ret = f; + } + + return ret; +} + +/* kpse:lookup("plain.tex", {}) */ +static int do_lua_kpathsea_lookup(lua_State * L, kpathsea kpse, int idx) +{ + int i; + string ret = NULL; + string *ret_list = NULL; + const_string name = NULL; + string user_path = NULL; + boolean show_all = false; + boolean must_exist = false; + kpse_file_format_type user_format = kpse_last_format; + int dpi = 600; + str_list_type subdir_paths = { 0, NULL }; + unsigned saved_debug = kpse->debug; + int saved_mktexpk = kpse->format_info[kpse_pk_format].program_enabled_p; + int saved_mktexmf = kpse->format_info[kpse_mf_format].program_enabled_p; + int saved_mktextex = kpse->format_info[kpse_tex_format].program_enabled_p; + int saved_mktextfm = kpse->format_info[kpse_tfm_format].program_enabled_p; + name = luaL_checkstring(L, idx); + /* todo: fetch parameter values */ + + if (lua_type(L, idx + 1) == LUA_TTABLE) { + lua_pushstring(L, "format"); + lua_gettable(L, idx + 1); + if (lua_type(L, -1) == LUA_TSTRING) { + user_format = luaL_checkoption(L, -1, NULL, filetypenames); + } + lua_pop(L, 1); + lua_pushstring(L, "dpi"); + lua_gettable(L, idx + 1); + if (lua_type(L, -1) == LUA_TNUMBER) { + dpi = (int) lua_tointeger(L, -1); + } + lua_pop(L, 1); + lua_pushstring(L, "debug"); + lua_gettable(L, idx + 1); + if (lua_type(L, -1) == LUA_TNUMBER) { + int d = 0; + d = (int) lua_tointeger(L, -1); + kpse->debug |= d; + } + lua_pop(L, 1); + lua_pushstring(L, "path"); + lua_gettable(L, idx + 1); + if (lua_type(L, -1) == LUA_TSTRING) { + user_path = xstrdup(lua_tostring(L, -1)); + } + lua_pop(L, 1); + lua_pushstring(L, "all"); + lua_gettable(L, idx + 1); + if (lua_type(L, -1) == LUA_TBOOLEAN) { + show_all = lua_toboolean(L, -1); + } + lua_pop(L, 1); + + lua_pushstring(L, "mktexpk"); + lua_gettable(L, idx + 1); + if (lua_type(L, -1) == LUA_TBOOLEAN) { + kpathsea_maketex_option(kpse, "pk", lua_toboolean(L, -1)); + } + lua_pop(L, 1); + + lua_pushstring(L, "mktextex"); + lua_gettable(L, idx + 1); + if (lua_type(L, -1) == LUA_TBOOLEAN) { + kpathsea_maketex_option(kpse, "tex", lua_toboolean(L, -1)); + } + lua_pop(L, 1); + + lua_pushstring(L, "mktexmf"); + lua_gettable(L, idx + 1); + if (lua_type(L, -1) == LUA_TBOOLEAN) { + kpathsea_maketex_option(kpse, "mf", lua_toboolean(L, -1)); + } + lua_pop(L, 1); + + lua_pushstring(L, "mktextfm"); + lua_gettable(L, idx + 1); + if (lua_type(L, -1) == LUA_TBOOLEAN) { + kpathsea_maketex_option(kpse, "tfm", lua_toboolean(L, -1)); + } + lua_pop(L, 1); + + + lua_pushstring(L, "mustexist"); + lua_gettable(L, idx + 1); + if (lua_type(L, -1) == LUA_TBOOLEAN) { + must_exist = lua_toboolean(L, -1); + } + lua_pop(L, 1); + lua_pushstring(L, "subdir"); + lua_gettable(L, idx + 1); + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { /* numeric value */ + if (lua_type(L, -1) == LUA_TSTRING) { + char *s = xstrdup(lua_tostring(L, -1)); + str_list_add(&subdir_paths, s); + free(s); + } + lua_pop(L, 1); + } + } else if (lua_type(L, -1) == LUA_TSTRING) { + char *s = xstrdup(lua_tostring(L, -1)); + str_list_add(&subdir_paths, s); + free(s); + } + lua_pop(L, 1); + if (STR_LIST_LENGTH(subdir_paths) > 0) { + show_all = 1; + } + } + if (user_path) { + /* Translate ; to : if that's our ENV_SEP. See cnf.c. */ + if (IS_ENV_SEP(':')) { + string loc; + for (loc = user_path; *loc; loc++) { + if (*loc == ';') + *loc = ':'; + } + } + user_path = kpathsea_path_expand(kpse, user_path); + if (show_all) { + ret_list = kpathsea_all_path_search(kpse, user_path, name); + } else { + ret = kpathsea_path_search(kpse, user_path, name, must_exist); + } + free(user_path); + } else { + /* No user-specified search path, check user format or guess from NAME. */ + kpse_file_format_type fmt; + if (user_format != kpse_last_format) + fmt = user_format; + else + fmt = find_format(kpse, name, true); + + switch (fmt) { + case kpse_pk_format: + case kpse_gf_format: + case kpse_any_glyph_format: + { + kpse_glyph_file_type glyph_ret; + string temp = remove_suffix (name); + /* Try to extract the resolution from the name. */ + unsigned local_dpi = find_dpi(name); + if (!local_dpi) + local_dpi = (unsigned) dpi; + ret = + kpathsea_find_glyph(kpse, temp, local_dpi, + fmt, &glyph_ret); + if (temp != name) + free (temp); + } + break; + + case kpse_last_format: + /* If the suffix isn't recognized, assume it's a tex file. */ + fmt = kpse_tex_format; + /* fall through */ + + default: + if (show_all) { + ret_list = + kpathsea_find_file_generic(kpse, name, fmt, must_exist, + true); + } else { + ret = kpathsea_find_file(kpse, name, fmt, must_exist); + } + } + } + + /* Turn single return into a null-terminated list for uniform treatment. */ + if (ret) { + ret_list = XTALLOC(2, string); + ret_list[0] = ret; + ret_list[1] = NULL; + } + + /* Filter by subdirectories, if specified. */ + if (STR_LIST_LENGTH(subdir_paths) > 0) { + string *new_list = subdir_match(subdir_paths, ret_list); + free(ret_list); + ret_list = new_list; + } + kpse->debug = saved_debug; + kpse->format_info[kpse_pk_format].program_enabled_p = saved_mktexpk; + kpse->format_info[kpse_mf_format].program_enabled_p = saved_mktexmf; + kpse->format_info[kpse_tex_format].program_enabled_p = saved_mktextex; + kpse->format_info[kpse_tfm_format].program_enabled_p = saved_mktextfm; + + /* Print output. */ + i = 0; + if (ret_list) { + for (; ret_list[i]; i++) { + lua_pushstring(L, ret_list[i]); + } + free(ret_list); + } + if (i == 0) { + i++; + lua_pushnil(L); + } + return i; +} + + +static int lua_kpathsea_lookup(lua_State * L) +{ + kpathsea *kpsep = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + kpathsea kpse = *kpsep; + return do_lua_kpathsea_lookup(L, kpse, 2); +} + +static int lua_kpse_lookup(lua_State * L) +{ + TEST_PROGRAM_NAME_SET; + return do_lua_kpathsea_lookup(L, kpse_def, 1); +} + + +/* Engine support is a bit of a problem, because we do not want + * to interfere with the normal format discovery of |luatex|. + * Current approach: run |os.setenv()| if you have to. + */ + +static int set_program_name(lua_State * L) +{ + const char *exe_name = luaL_checkstring(L, 1); + const char *prog_name = luaL_optstring(L, 2, exe_name); + if (!program_name_set) { + kpse_set_program_name(exe_name, prog_name); + program_name_set = 1; + } else { + kpse_reset_program_name(prog_name); + } + /* fix up the texconfig entry */ + lua_checkstack(L, 3); + lua_getglobal(L, "texconfig"); + if (lua_istable(L, -1)) { + lua_pushstring(L, "kpse_init"); + lua_pushboolean(L, 0); + lua_rawset(L, -3); + } + lua_pop(L, 1); + return 0; +} + +static int init_prog(lua_State * L) +{ + const char *prefix = luaL_checkstring(L, 1); + unsigned dpi = (unsigned) luaL_checkinteger(L, 2); + const char *mode = luaL_optstring(L, 3, NULL); + const char *fallback = luaL_optstring(L, 4, NULL); + TEST_PROGRAM_NAME_SET; + kpse_init_prog(prefix, dpi, mode, fallback); + return 0; +} + +static int lua_kpathsea_init_prog(lua_State * L) +{ + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + const char *prefix = luaL_checkstring(L, 2); + unsigned dpi = (unsigned) luaL_checkinteger(L, 3); + const char *mode = luaL_optstring(L, 4, NULL); + const char *fallback = luaL_optstring(L, 5, NULL); + kpathsea_init_prog(*kp, prefix, dpi, mode, fallback); + return 0; +} + +static int lua_set_maketex(lua_State * L) +{ + int ftype = luaL_checkoption(L, 1, NULL, filetypenames); + boolean enable = lua_toboolean(L, 2); + boolean src = luaL_checkoption(L, 3, "cmdline", srcnames); + kpse_set_program_enabled(ftype, enable, src); + return 0; +} + +static int lua_kpathsea_set_maketex(lua_State * L) +{ + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + int ftype = luaL_checkoption(L, 2, NULL, filetypenames); + boolean enable = lua_toboolean(L, 3); + boolean src = luaL_checkoption(L, 4, "cmdline", srcnames); + kpathsea_set_program_enabled(*kp, ftype, enable, src); + return 0; +} + +static int lua_kpse_version(lua_State * L) +{ + lua_pushstring(L, kpathsea_version_string); + return 1; +} + +static int readable_file(lua_State * L) +{ + char *name = xstrdup(luaL_checkstring(L, 1)); + TEST_PROGRAM_NAME_SET; + lua_pushstring(L, kpse_readable_file(name)); + free(name); + return 1; +} + +static int lua_kpathsea_readable_file(lua_State * L) +{ + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + char *name = xstrdup(luaL_checkstring(L, 2)); + lua_pushstring(L, kpathsea_readable_file(*kp, name)); + free(name); + return 1; +} + + +static int lua_kpathsea_finish(lua_State * L) +{ + kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); + kpathsea_finish(*kp); + return 0; +} + +static int lua_kpathsea_new(lua_State * L) +{ + kpathsea kpse = NULL; + kpathsea *kp = NULL; + const char *av = luaL_checkstring(L, 1); + const char *liar = luaL_optstring(L, 2, av); + kpse = kpathsea_new(); + kpathsea_set_program_name(kpse, av, liar); + kp = (kpathsea *) lua_newuserdata(L, sizeof(kpathsea *)); + *kp = kpse; + luaL_getmetatable(L, KPATHSEA_METATABLE); + lua_setmetatable(L, -2); + return 1; +} + +static int lua_record_input_file(lua_State * L) +{ + const char *name = lua_tostring(L, 1); + if (name != NULL) { + kpse_record_input(name); + } + return 0; +} + +static int lua_record_output_file(lua_State * L) +{ + const char *name = lua_tostring(L, 1); + if (name != NULL) { + kpse_record_output(name); + } + return 0; +} + +static const struct luaL_Reg kpselib_m[] = { + {"__gc", lua_kpathsea_finish}, + {"init_prog", lua_kpathsea_init_prog}, + {"readable_file", lua_kpathsea_readable_file}, + {"find_file", lua_kpathsea_find_file}, + {"expand_path", lua_kpathsea_expand_path}, + {"expand_var", lua_kpathsea_expand_var}, + {"expand_braces", lua_kpathsea_expand_braces}, + {"var_value", lua_kpathsea_var_value}, + {"show_path", lua_kpathsea_show_path}, + {"lookup", lua_kpathsea_lookup}, + {"set_maketex", lua_kpathsea_set_maketex}, + {"version", lua_kpse_version}, + {"default_texmfcnf", show_texmfcnf}, + {"record_input_file", lua_record_input_file}, + {"record_output_file", lua_record_output_file}, + {"is_absolute", lua_kpathsea_is_absolute}, + {NULL, NULL} /* sentinel */ +}; + +static const struct luaL_Reg kpselib_l[] = { + {"new", lua_kpathsea_new}, + {"set_program_name", set_program_name}, + {"init_prog", init_prog}, + {"readable_file", readable_file}, + {"find_file", find_file}, + {"expand_path", expand_path}, + {"expand_var", expand_var}, + {"expand_braces", expand_braces}, + {"var_value", var_value}, + {"show_path", show_path}, + {"lookup", lua_kpse_lookup}, + {"set_maketex", lua_set_maketex}, + {"version", lua_kpse_version}, + {"default_texmfcnf", show_texmfcnf}, + {"is_absolute", is_absolute}, + {NULL, NULL} /* sentinel */ +}; + +int luaopen_kpse(lua_State * L) +{ + luaL_newmetatable(L, KPATHSEA_METATABLE); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, kpselib_m, 0); + lua_newtable(L); + luaL_setfuncs(L, kpselib_l, 0); + return 1; +} diff --git a/luametalatex-kpse/versionscript b/luametalatex-kpse/versionscript new file mode 100644 index 0000000..7a0fa05 --- /dev/null +++ b/luametalatex-kpse/versionscript @@ -0,0 +1,4 @@ +{ + global: luaopen_kpse; + local: *; +};