3 Copyright 2006-2008 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/>. */
23 #include "mfluajitd.h"
27 #include <kpathsea/version.h>
28 #define xfree(p) do { if (p != NULL) free(p); p = NULL; } while (0)
31 #include "lua/luatex-api.h"
33 #include <kpathsea/expand.h>
34 #include <kpathsea/variable.h>
35 #include <kpathsea/tex-glyph.h>
36 #include <kpathsea/readable.h>
37 #include <kpathsea/pathsearch.h>
38 #include <kpathsea/str-list.h>
39 #include <kpathsea/tex-file.h>
40 #include <kpathsea/paths.h>
43 static const unsigned filetypes
[] = {
46 kpse_any_glyph_format
,
62 kpse_mpsupport_format
,
73 kpse_texsource_format
,
74 kpse_tex_ps_header_format
,
75 kpse_troff_font_format
,
78 kpse_dvips_config_format
,
83 kpse_program_text_format
,
84 kpse_program_binary_format
,
85 kpse_miscfonts_format
,
92 kpse_pdftex_config_format
,
94 kpse_texmfscripts_format
,
103 static const char *const filetypenames
[] = {
131 "TeX system documentation",
133 "TeX system sources",
144 "other binary files",
150 "subfont definition files",
156 "font feature files",
166 #define KPATHSEA_METATABLE "mflua.kpathsea"
168 #define KPATHSEA_METATABLE "luatex.kpathsea"
171 /* set to 1 by the |program_name| function */
174 int program_name_set
= 1;
176 int program_name_set
= 0;
179 #define TEST_PROGRAM_NAME_SET do { \
180 if (! program_name_set) { \
181 return luaL_error(L, "Please call kpse.set_program_name() before using the library"); \
185 static int find_file(lua_State
* L
)
189 unsigned ftype
= kpse_tex_format
;
191 TEST_PROGRAM_NAME_SET
;
192 if (lua_type(L
, 1) != LUA_TSTRING
) {
193 luaL_error(L
, "not a file name");
195 st
= lua_tostring(L
, 1);
199 if (t
== LUA_TBOOLEAN
) {
200 mexist
= lua_toboolean(L
, i
);
201 } else if (t
== LUA_TNUMBER
) {
202 mexist
= (int) lua_tointeger(L
, i
);
203 } else if (t
== LUA_TSTRING
) {
204 int op
= luaL_checkoption(L
, i
, NULL
, filetypenames
);
205 ftype
= filetypes
[op
];
211 if (ftype
== kpse_pk_format
||
212 ftype
== kpse_gf_format
|| ftype
== kpse_any_glyph_format
) {
213 /* ret.format, ret.name, ret.dpi */
214 kpse_glyph_file_type ret
;
215 lua_pushstring(L
, kpse_find_glyph(st
, (unsigned) mexist
, ftype
, &ret
));
221 lua_pushstring(L
, kpse_find_file(st
, ftype
, mexist
));
227 static int lua_kpathsea_find_file(lua_State
* L
)
230 unsigned ftype
= kpse_tex_format
;
232 kpathsea
*kp
= (kpathsea
*) luaL_checkudata(L
, 1, KPATHSEA_METATABLE
);
233 const char *st
= luaL_checkstring(L
, 2);
237 if (t
== LUA_TBOOLEAN
) {
238 mexist
= (boolean
) lua_toboolean(L
, i
);
239 } else if (t
== LUA_TNUMBER
) {
240 mexist
= (int) lua_tointeger(L
, i
);
241 } else if (t
== LUA_TSTRING
) {
242 int op
= luaL_checkoption(L
, i
, NULL
, filetypenames
);
243 ftype
= filetypes
[op
];
249 if (ftype
== kpse_pk_format
|| ftype
== kpse_gf_format
|| ftype
== kpse_any_glyph_format
) {
250 /* ret.format, ret.name, ret.dpi */
251 kpse_glyph_file_type ret
;
252 lua_pushstring(L
, kpathsea_find_glyph(*kp
, st
, (unsigned) mexist
, ftype
, &ret
));
258 lua_pushstring(L
, kpathsea_find_file(*kp
, st
, ftype
, mexist
));
264 static int show_texmfcnf(lua_State
* L
)
266 lua_pushstring(L
, DEFAULT_TEXMFCNF
);
270 static int show_path(lua_State
* L
)
272 int op
= luaL_checkoption(L
, -1, "tex", filetypenames
);
273 unsigned user_format
= filetypes
[op
];
274 TEST_PROGRAM_NAME_SET
;
275 if (!kpse_format_info
[user_format
].type
) /* needed if arg was numeric */
276 kpse_init_format(user_format
);
277 lua_pushstring(L
, kpse_format_info
[user_format
].path
);
281 static int lua_kpathsea_show_path(lua_State
* L
)
283 kpathsea
*kp
= (kpathsea
*) luaL_checkudata(L
, 1, KPATHSEA_METATABLE
);
284 int op
= luaL_checkoption(L
, -1, "tex", filetypenames
);
285 unsigned user_format
= filetypes
[op
];
286 if (!(*kp
)->format_info
[user_format
].type
) /* needed if arg was numeric */
287 kpathsea_init_format(*kp
, user_format
);
288 lua_pushstring(L
, (*kp
)->format_info
[user_format
].path
);
292 static int expand_path(lua_State
* L
)
294 const char *st
= luaL_checkstring(L
, 1);
295 TEST_PROGRAM_NAME_SET
;
296 lua_pushstring(L
, kpse_path_expand(st
));
300 static int lua_kpathsea_expand_path(lua_State
* L
)
302 kpathsea
*kp
= (kpathsea
*) luaL_checkudata(L
, 1, KPATHSEA_METATABLE
);
303 const char *st
= luaL_checkstring(L
, 2);
304 lua_pushstring(L
, kpathsea_path_expand(*kp
, st
));
308 static int expand_braces(lua_State
* L
)
310 const char *st
= luaL_checkstring(L
, 1);
311 TEST_PROGRAM_NAME_SET
;
312 lua_pushstring(L
, kpse_brace_expand(st
));
316 static int lua_kpathsea_expand_braces(lua_State
* L
)
318 kpathsea
*kp
= (kpathsea
*) luaL_checkudata(L
, 1, KPATHSEA_METATABLE
);
319 const char *st
= luaL_checkstring(L
, 2);
320 lua_pushstring(L
, kpathsea_brace_expand(*kp
, st
));
325 static int expand_var(lua_State
* L
)
327 const char *st
= luaL_checkstring(L
, 1);
328 TEST_PROGRAM_NAME_SET
;
329 lua_pushstring(L
, kpse_var_expand(st
));
333 static int lua_kpathsea_expand_var(lua_State
* L
)
335 kpathsea
*kp
= (kpathsea
*) luaL_checkudata(L
, 1, KPATHSEA_METATABLE
);
336 const char *st
= luaL_checkstring(L
, 2);
337 lua_pushstring(L
, kpathsea_var_expand(*kp
, st
));
342 static int var_value(lua_State
* L
)
344 const char *st
= luaL_checkstring(L
, 1);
345 TEST_PROGRAM_NAME_SET
;
346 lua_pushstring(L
, kpse_var_value(st
));
350 static int lua_kpathsea_var_value(lua_State
* L
)
352 kpathsea
*kp
= (kpathsea
*) luaL_checkudata(L
, 1, KPATHSEA_METATABLE
);
353 const char *st
= luaL_checkstring(L
, 2);
354 lua_pushstring(L
, kpathsea_var_value(*kp
, st
));
358 static unsigned find_dpi(const_string s
)
360 unsigned dpi_number
= 0;
361 const_string extension
= find_suffix(s
);
363 if (extension
!= NULL
)
364 sscanf(extension
, "%u", &dpi_number
);
370 Return newly-allocated NULL-terminated list of strings from MATCHES
371 that are prefixed with any of the subdirectories in SUBDIRS. That
372 is, for a string S in MATCHES, its dirname must end with one of the
373 elements in SUBDIRS. For instance, if subdir=foo/bar, that will
374 match a string foo/bar/baz or /some/texmf/foo/bar/baz.
376 We don't reallocate the actual strings, just the list elements.
377 Perhaps later we will implement wildcards or "//" or something.
380 static string
*subdir_match(str_list_type subdirs
, string
* matches
)
382 string
*ret
= XTALLOC1(string
);
386 for (m
= 0; matches
[m
]; m
++) {
389 string s
= xstrdup(matches
[m
]);
390 for (loc
= strlen(s
); loc
> 0 && !IS_DIR_SEP(s
[loc
- 1]); loc
--);
391 while (loc
> 0 && IS_DIR_SEP(s
[loc
- 1])) {
394 s
[loc
] = 0; /* wipe out basename */
396 for (e
= 0; e
< STR_LIST_LENGTH(subdirs
); e
++) {
397 string subdir
= STR_LIST_ELT(subdirs
, e
);
398 size_t subdir_len
= strlen(subdir
);
399 while (subdir_len
> 0 && IS_DIR_SEP(subdir
[subdir_len
- 1])) {
401 subdir
[subdir_len
] = 0; /* remove trailing slashes from subdir spec */
403 if (FILESTRCASEEQ(subdir
, s
+ loc
- subdir_len
)) {
404 /* matched, save this one. */
405 XRETALLOC(ret
, len
+ 1, string
);
406 ret
[len
- 1] = matches
[m
];
416 /* Use the file type from -format if that was specified (i.e., the
417 user_format global variable), else guess dynamically from NAME.
418 Return kpse_last_format if undeterminable. This function is also
419 used to parse the -format string, a case which we distinguish by
420 setting is_filename to false.
422 A few filenames have been hard-coded for format types that
423 differ from what would be inferred from their extensions. */
425 static kpse_file_format_type
426 find_format(kpathsea kpse
, const_string name
, boolean is_filename
)
428 kpse_file_format_type ret
;
430 if (FILESTRCASEEQ(name
, "config.ps")) {
431 ret
= kpse_dvips_config_format
;
432 } else if (FILESTRCASEEQ(name
, "dvipdfmx.cfg")) {
433 ret
= kpse_program_text_format
;
434 } else if (FILESTRCASEEQ(name
, "fmtutil.cnf")) {
435 ret
= kpse_web2c_format
;
436 } else if (FILESTRCASEEQ(name
, "glyphlist.txt")) {
437 ret
= kpse_fontmap_format
;
438 } else if (FILESTRCASEEQ(name
, "mktex.cnf")) {
439 ret
= kpse_web2c_format
;
440 } else if (FILESTRCASEEQ(name
, "pdfglyphlist.txt")) {
441 ret
= kpse_fontmap_format
;
442 } else if (FILESTRCASEEQ(name
, "pdftex.cfg")) {
443 ret
= kpse_pdftex_config_format
;
444 } else if (FILESTRCASEEQ(name
, "texmf.cnf")) {
445 ret
= kpse_cnf_format
;
446 } else if (FILESTRCASEEQ(name
, "updmap.cfg")) {
447 ret
= kpse_web2c_format
;
448 } else if (FILESTRCASEEQ(name
, "XDvi")) {
449 ret
= kpse_program_text_format
;
451 int f
= 0; /* kpse_file_format_type */
452 size_t name_len
= strlen(name
);
454 /* Have to rely on `try_len' being declared here, since we can't assume
455 GNU C and statement expressions. */
456 #define TRY_SUFFIX(ftry) (\
457 try_len = (ftry) ? strlen (ftry) : 0, \
458 (ftry) && try_len <= name_len \
459 && FILESTRCASEEQ (ftry, name + name_len - try_len))
461 while (f
!= kpse_last_format
) {
465 boolean found
= false;
467 if (!kpse
->format_info
[f
].type
)
468 kpathsea_init_format(kpse
, (kpse_file_format_type
) f
);
471 /* Allow the long name, but only in the -format option. We don't
472 want a filename confused with a format name. */
473 ftry
= kpse
->format_info
[f
].type
;
474 found
= TRY_SUFFIX(ftry
);
476 for (ext
= kpse
->format_info
[f
].suffix
; !found
&& ext
&& *ext
;
478 found
= TRY_SUFFIX(*ext
);
480 for (ext
= kpse
->format_info
[f
].alt_suffix
; !found
&& ext
&& *ext
;
482 found
= TRY_SUFFIX(*ext
);
488 /* Some trickery here: the extensions for kpse_fmt_format can
489 * clash with other extensions in use, and we prefer for those
490 * others to be preferred. And we don't want to change the
491 * integer value of kpse_fmt_format. So skip it when first
492 * enountered, then use it when we've done everything else,
493 * and use it as the end-guard.
495 if (f
== kpse_fmt_format
) {
496 f
= kpse_last_format
;
497 } else if (++f
== kpse_fmt_format
) {
499 } else if (f
== kpse_last_format
) {
504 /* If there was a match, f will be one past the correct value. */
511 /* kpse:lookup("plain.tex", {}) */
512 static int do_lua_kpathsea_lookup(lua_State
* L
, kpathsea kpse
, int idx
)
516 string
*ret_list
= NULL
;
517 const_string name
= NULL
;
518 string user_path
= NULL
;
519 boolean show_all
= false;
520 boolean must_exist
= false;
521 kpse_file_format_type user_format
= kpse_last_format
;
523 str_list_type subdir_paths
= { 0, NULL
};
524 unsigned saved_debug
= kpse
->debug
;
525 int saved_mktexpk
= kpse
->format_info
[kpse_pk_format
].program_enabled_p
;
526 int saved_mktexmf
= kpse
->format_info
[kpse_mf_format
].program_enabled_p
;
527 int saved_mktextex
= kpse
->format_info
[kpse_tex_format
].program_enabled_p
;
528 int saved_mktextfm
= kpse
->format_info
[kpse_tfm_format
].program_enabled_p
;
529 name
= luaL_checkstring(L
, idx
);
530 /* todo: fetch parameter values */
532 if (lua_type(L
, idx
+ 1) == LUA_TTABLE
) {
533 lua_pushstring(L
, "format");
534 lua_gettable(L
, idx
+ 1);
535 if (lua_type(L
, -1) == LUA_TSTRING
) {
536 int op
= luaL_checkoption(L
, -1, NULL
, filetypenames
);
537 user_format
= filetypes
[op
];
540 lua_pushstring(L
, "dpi");
541 lua_gettable(L
, idx
+ 1);
542 if (lua_type(L
, -1) == LUA_TNUMBER
) {
543 dpi
= (int) lua_tointeger(L
, -1);
546 lua_pushstring(L
, "debug");
547 lua_gettable(L
, idx
+ 1);
548 if (lua_type(L
, -1) == LUA_TNUMBER
) {
550 d
= (int) lua_tointeger(L
, -1);
554 lua_pushstring(L
, "path");
555 lua_gettable(L
, idx
+ 1);
556 if (lua_type(L
, -1) == LUA_TSTRING
) {
557 user_path
= xstrdup(lua_tostring(L
, -1));
560 lua_pushstring(L
, "all");
561 lua_gettable(L
, idx
+ 1);
562 if (lua_type(L
, -1) == LUA_TBOOLEAN
) {
563 show_all
= lua_toboolean(L
, -1);
567 lua_pushstring(L
, "mktexpk");
568 lua_gettable(L
, idx
+ 1);
569 if (lua_type(L
, -1) == LUA_TBOOLEAN
) {
570 kpathsea_maketex_option(kpse
, "pk", lua_toboolean(L
, -1));
574 lua_pushstring(L
, "mktextex");
575 lua_gettable(L
, idx
+ 1);
576 if (lua_type(L
, -1) == LUA_TBOOLEAN
) {
577 kpathsea_maketex_option(kpse
, "tex", lua_toboolean(L
, -1));
581 lua_pushstring(L
, "mktexmf");
582 lua_gettable(L
, idx
+ 1);
583 if (lua_type(L
, -1) == LUA_TBOOLEAN
) {
584 kpathsea_maketex_option(kpse
, "mf", lua_toboolean(L
, -1));
588 lua_pushstring(L
, "mktextfm");
589 lua_gettable(L
, idx
+ 1);
590 if (lua_type(L
, -1) == LUA_TBOOLEAN
) {
591 kpathsea_maketex_option(kpse
, "tfm", lua_toboolean(L
, -1));
596 lua_pushstring(L
, "mustexist");
597 lua_gettable(L
, idx
+ 1);
598 if (lua_type(L
, -1) == LUA_TBOOLEAN
) {
599 must_exist
= lua_toboolean(L
, -1);
602 lua_pushstring(L
, "subdir");
603 lua_gettable(L
, idx
+ 1);
604 if (lua_istable(L
, -1)) {
606 while (lua_next(L
, -2) != 0) { /* numeric value */
607 if (lua_type(L
, -1) == LUA_TSTRING
) {
608 char *s
= xstrdup(lua_tostring(L
, -1));
609 str_list_add(&subdir_paths
, s
);
614 } else if (lua_type(L
, -1) == LUA_TSTRING
) {
615 char *s
= xstrdup(lua_tostring(L
, -1));
616 str_list_add(&subdir_paths
, s
);
620 if (STR_LIST_LENGTH(subdir_paths
) > 0) {
625 /* Translate ; to : if that's our ENV_SEP. See cnf.c. */
626 if (IS_ENV_SEP(':')) {
628 for (loc
= user_path
; *loc
; loc
++) {
633 user_path
= kpathsea_path_expand(kpse
, user_path
);
635 ret_list
= kpathsea_all_path_search(kpse
, user_path
, name
);
637 ret
= kpathsea_path_search(kpse
, user_path
, name
, must_exist
);
641 /* No user-specified search path, check user format or guess from NAME. */
642 kpse_file_format_type fmt
;
643 if (user_format
!= kpse_last_format
)
646 fmt
= find_format(kpse
, name
, true);
651 case kpse_any_glyph_format
:
653 kpse_glyph_file_type glyph_ret
;
654 string temp
= remove_suffix (name
);
655 /* Try to extract the resolution from the name. */
656 unsigned local_dpi
= find_dpi(name
);
658 local_dpi
= (unsigned) dpi
;
660 kpathsea_find_glyph(kpse
, temp
, local_dpi
,
667 case kpse_last_format
:
668 /* If the suffix isn't recognized, assume it's a tex file. */
669 fmt
= kpse_tex_format
;
675 kpathsea_find_file_generic(kpse
, name
, fmt
, must_exist
,
678 ret
= kpathsea_find_file(kpse
, name
, fmt
, must_exist
);
683 /* Turn single return into a null-terminated list for uniform treatment. */
685 ret_list
= XTALLOC(2, string
);
690 /* Filter by subdirectories, if specified. */
691 if (STR_LIST_LENGTH(subdir_paths
) > 0) {
692 string
*new_list
= subdir_match(subdir_paths
, ret_list
);
696 kpse
->debug
= saved_debug
;
697 kpse
->format_info
[kpse_pk_format
].program_enabled_p
= saved_mktexpk
;
698 kpse
->format_info
[kpse_mf_format
].program_enabled_p
= saved_mktexmf
;
699 kpse
->format_info
[kpse_tex_format
].program_enabled_p
= saved_mktextex
;
700 kpse
->format_info
[kpse_tfm_format
].program_enabled_p
= saved_mktextfm
;
705 for (; ret_list
[i
]; i
++) {
706 lua_pushstring(L
, ret_list
[i
]);
718 static int lua_kpathsea_lookup(lua_State
* L
)
720 kpathsea
*kpsep
= (kpathsea
*) luaL_checkudata(L
, 1, KPATHSEA_METATABLE
);
721 kpathsea kpse
= *kpsep
;
722 return do_lua_kpathsea_lookup(L
, kpse
, 2);
725 static int lua_kpse_lookup(lua_State
* L
)
727 TEST_PROGRAM_NAME_SET
;
728 return do_lua_kpathsea_lookup(L
, kpse_def
, 1);
732 /* Engine support is a bit of a problem, because we do not want
733 * to interfere with the normal format discovery of |luatex|.
734 * Current approach: run |os.setenv()| if you have to.
737 static int set_program_name(lua_State
* L
)
739 const char *exe_name
= luaL_checkstring(L
, 1);
740 const char *prog_name
= luaL_optstring(L
, 2, exe_name
);
741 if (!program_name_set
) {
742 kpse_set_program_name(exe_name
, prog_name
);
743 program_name_set
= 1;
745 kpse_reset_program_name(prog_name
);
747 /* fix up the texconfig entry */
748 lua_checkstack(L
, 3);
749 lua_getglobal(L
, "texconfig");
750 if (lua_istable(L
, -1)) {
751 lua_pushstring(L
, "kpse_init");
752 lua_pushboolean(L
, 0);
759 static int init_prog(lua_State
* L
)
761 const char *prefix
= luaL_checkstring(L
, 1);
762 unsigned dpi
= (unsigned) luaL_checkinteger(L
, 2);
763 const char *mode
= luaL_checkstring(L
, 3);
764 const char *fallback
= luaL_optstring(L
, 4, NULL
);
765 TEST_PROGRAM_NAME_SET
;
766 kpse_init_prog(prefix
, dpi
, mode
, fallback
);
770 static int lua_kpathsea_init_prog(lua_State
* L
)
772 kpathsea
*kp
= (kpathsea
*) luaL_checkudata(L
, 1, KPATHSEA_METATABLE
);
773 const char *prefix
= luaL_checkstring(L
, 2);
774 unsigned dpi
= (unsigned) luaL_checkinteger(L
, 3);
775 const char *mode
= luaL_checkstring(L
, 4);
776 const char *fallback
= luaL_optstring(L
, 5, NULL
);
777 kpathsea_init_prog(*kp
, prefix
, dpi
, mode
, fallback
);
781 static int lua_kpse_version(lua_State
* L
)
783 lua_pushstring(L
, kpathsea_version_string
);
787 static int readable_file(lua_State
* L
)
789 char *name
= xstrdup(luaL_checkstring(L
, 1));
790 TEST_PROGRAM_NAME_SET
;
791 lua_pushstring(L
, kpse_readable_file(name
));
796 static int lua_kpathsea_readable_file(lua_State
* L
)
798 kpathsea
*kp
= (kpathsea
*) luaL_checkudata(L
, 1, KPATHSEA_METATABLE
);
799 char *name
= xstrdup(luaL_checkstring(L
, 2));
800 lua_pushstring(L
, kpathsea_readable_file(*kp
, name
));
806 static int lua_kpathsea_finish(lua_State
* L
)
808 kpathsea
*kp
= (kpathsea
*) luaL_checkudata(L
, 1, KPATHSEA_METATABLE
);
809 kpathsea_finish(*kp
);
813 static int lua_kpathsea_new(lua_State
* L
)
815 kpathsea kpse
= NULL
;
817 const char *av
= luaL_checkstring(L
, 1);
818 const char *liar
= luaL_optstring(L
, 2, av
);
819 kpse
= kpathsea_new();
820 kpathsea_set_program_name(kpse
, av
, liar
);
821 kp
= (kpathsea
*) lua_newuserdata(L
, sizeof(kpathsea
*));
823 luaL_getmetatable(L
, KPATHSEA_METATABLE
);
824 lua_setmetatable(L
, -2);
828 static const struct luaL_Reg kpselib_m
[] = {
829 {"__gc", lua_kpathsea_finish
},
830 {"init_prog", lua_kpathsea_init_prog
},
831 {"readable_file", lua_kpathsea_readable_file
},
832 {"find_file", lua_kpathsea_find_file
},
833 {"expand_path", lua_kpathsea_expand_path
},
834 {"expand_var", lua_kpathsea_expand_var
},
835 {"expand_braces", lua_kpathsea_expand_braces
},
836 {"var_value", lua_kpathsea_var_value
},
837 {"show_path", lua_kpathsea_show_path
},
838 {"lookup", lua_kpathsea_lookup
},
839 {"version", lua_kpse_version
},
840 {"default_texmfcnf", show_texmfcnf
},
841 {NULL
, NULL
} /* sentinel */
844 static const struct luaL_Reg kpselib_l
[] = {
845 {"new", lua_kpathsea_new
},
846 {"set_program_name", set_program_name
},
847 {"init_prog", init_prog
},
848 {"readable_file", readable_file
},
849 {"find_file", find_file
},
850 {"expand_path", expand_path
},
851 {"expand_var", expand_var
},
852 {"expand_braces", expand_braces
},
853 {"var_value", var_value
},
854 {"show_path", show_path
},
855 {"lookup", lua_kpse_lookup
},
856 {"version", lua_kpse_version
},
857 {"default_texmfcnf", show_texmfcnf
},
858 {NULL
, NULL
} /* sentinel */
861 int luaopen_kpse(lua_State
* L
)
863 luaL_newmetatable(L
, KPATHSEA_METATABLE
);
864 lua_pushvalue(L
, -1);
865 lua_setfield(L
, -2, "__index");
866 luaL_register(L
, NULL
, kpselib_m
);
867 luaL_register(L
, "kpse", kpselib_l
);