1 /* lkpselib.c
2 
3    Copyright 2006-2008 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 #include "ptexlib.h"
21 #include "lua/luatex-api.h"
22 #include <kpathsea/expand.h>
23 #include <kpathsea/variable.h>
24 #include <kpathsea/tex-glyph.h>
25 #include <kpathsea/readable.h>
26 #include <kpathsea/pathsearch.h>
27 #include <kpathsea/str-list.h>
28 #include <kpathsea/tex-file.h>
29 #include <kpathsea/paths.h>
30 
31 
32 static const unsigned filetypes[] = {
33     kpse_gf_format,
34     kpse_pk_format,
35     kpse_any_glyph_format,
36     kpse_tfm_format,
37     kpse_afm_format,
38     kpse_base_format,
39     kpse_bib_format,
40     kpse_bst_format,
41     kpse_cnf_format,
42     kpse_db_format,
43     kpse_fmt_format,
44     kpse_fontmap_format,
45     kpse_mem_format,
46     kpse_mf_format,
47     kpse_mfpool_format,
48     kpse_mft_format,
49     kpse_mp_format,
50     kpse_mppool_format,
51     kpse_mpsupport_format,
52     kpse_ocp_format,
53     kpse_ofm_format,
54     kpse_opl_format,
55     kpse_otp_format,
56     kpse_ovf_format,
57     kpse_ovp_format,
58     kpse_pict_format,
59     kpse_tex_format,
60     kpse_texdoc_format,
61     kpse_texpool_format,
62     kpse_texsource_format,
63     kpse_tex_ps_header_format,
64     kpse_troff_font_format,
65     kpse_type1_format,
66     kpse_vf_format,
67     kpse_dvips_config_format,
68     kpse_ist_format,
69     kpse_truetype_format,
70     kpse_type42_format,
71     kpse_web2c_format,
72     kpse_program_text_format,
73     kpse_program_binary_format,
74     kpse_miscfonts_format,
75     kpse_web_format,
76     kpse_cweb_format,
77     kpse_enc_format,
78     kpse_cmap_format,
79     kpse_sfd_format,
80     kpse_opentype_format,
81     kpse_pdftex_config_format,
82     kpse_lig_format,
83     kpse_texmfscripts_format,
84     kpse_lua_format,
85     kpse_fea_format,
86     kpse_cid_format,
87     kpse_mlbib_format,
88     kpse_mlbst_format,
89     kpse_clua_format
90 };
91 
92 static const char *const filetypenames[] = {
93     "gf",
94     "pk",
95     "bitmap font",
96     "tfm",
97     "afm",
98     "base",
99     "bib",
100     "bst",
101     "cnf",
102     "ls-R",
103     "fmt",
104     "map",
105     "mem",
106     "mf",
107     "mfpool",
108     "mft",
109     "mp",
110     "mppool",
111     "MetaPost support",
112     "ocp",
113     "ofm",
114     "opl",
115     "otp",
116     "ovf",
117     "ovp",
118     "graphic/figure",
119     "tex",
120     "TeX system documentation",
121     "texpool",
122     "TeX system sources",
123     "PostScript header",
124     "Troff fonts",
125     "type1 fonts",
126     "vf",
127     "dvips config",
128     "ist",
129     "truetype fonts",
130     "type42 fonts",
131     "web2c files",
132     "other text files",
133     "other binary files",
134     "misc fonts",
135     "web",
136     "cweb",
137     "enc files",
138     "cmap files",
139     "subfont definition files",
140     "opentype fonts",
141     "pdftex config",
142     "lig files",
143     "texmfscripts",
144     "lua",
145     "font feature files",
146     "cid maps",
147     "mlbib",
148     "mlbst",
149     "clua",
150     NULL
151 };
152 
153 
154 #define KPATHSEA_METATABLE  "luatex.kpathsea"
155 
156 /* set to 1 by the |program_name| function */
157 
158 int program_name_set = 0;
159 
160 #define TEST_PROGRAM_NAME_SET do {                                      \
161     if (! program_name_set) {                                           \
162       return luaL_error(L, "Please call kpse.set_program_name() before using the library"); \
163     }                                                                   \
164   } while (0)
165 
find_file(lua_State * L)166 static int find_file(lua_State * L)
167 {
168     int i;
169     const char *st;
170     unsigned ftype = kpse_tex_format;
171     int mexist = 0;
172     TEST_PROGRAM_NAME_SET;
173     if (!lua_isstring(L, 1)) {
174         luaL_error(L, "not a file name");
175     }
176     st = lua_tostring(L, 1);
177     i = lua_gettop(L);
178     while (i > 1) {
179         if (lua_isboolean(L, i)) {
180             mexist = lua_toboolean(L, i);
181         } else if (lua_isnumber(L, i)) {
182             mexist=(int)lua_tonumber(L, i);
183         } else if (lua_isstring(L, i)) {
184             int op = luaL_checkoption(L, i, NULL, filetypenames);
185             ftype = filetypes[op];
186         }
187         i--;
188     }
189     if (ftype == kpse_pk_format ||
190         ftype == kpse_gf_format || ftype == kpse_any_glyph_format) {
191         /* ret.format, ret.name, ret.dpi */
192         kpse_glyph_file_type ret;
193         lua_pushstring(L, kpse_find_glyph(st, (unsigned) mexist, ftype, &ret));
194     } else {
195         if (mexist > 0)
196             mexist = 1;
197         if (mexist < 0)
198             mexist = 0;
199         lua_pushstring(L, kpse_find_file(st, ftype, mexist));
200     }
201     return 1;
202 }
203 
204 
lua_kpathsea_find_file(lua_State * L)205 static int lua_kpathsea_find_file(lua_State * L)
206 {
207     int i;
208     unsigned ftype = kpse_tex_format;
209     int mexist = 0;
210     kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
211     const char *st = luaL_checkstring(L, 2);
212     i = lua_gettop(L);
213     while (i > 2) {
214         if (lua_isboolean(L, i)) {
215             mexist = (boolean) lua_toboolean(L, i);
216         } else if (lua_isnumber(L, i)) {
217             mexist=(int)lua_tonumber(L, i);
218         } else if (lua_isstring(L, i)) {
219             int op = luaL_checkoption(L, i, NULL, filetypenames);
220             ftype = filetypes[op];
221         }
222         i--;
223     }
224     if (ftype == kpse_pk_format ||
225         ftype == kpse_gf_format || ftype == kpse_any_glyph_format) {
226         /* ret.format, ret.name, ret.dpi */
227         kpse_glyph_file_type ret;
228         lua_pushstring(L,
229                        kpathsea_find_glyph(*kp, st, (unsigned) mexist, ftype,
230                                            &ret));
231     } else {
232         if (mexist > 0)
233             mexist = 1;
234         if (mexist < 0)
235             mexist = 0;
236         lua_pushstring(L, kpathsea_find_file(*kp, st, ftype, mexist));
237     }
238     return 1;
239 
240 }
241 
show_texmfcnf(lua_State * L)242 static int show_texmfcnf(lua_State * L)
243 {
244     lua_pushstring(L, DEFAULT_TEXMFCNF);
245     return 1;
246 }
247 
show_path(lua_State * L)248 static int show_path(lua_State * L)
249 {
250     int op = luaL_checkoption(L, -1, "tex", filetypenames);
251     unsigned user_format = filetypes[op];
252     TEST_PROGRAM_NAME_SET;
253     if (!kpse_format_info[user_format].type)    /* needed if arg was numeric */
254         kpse_init_format(user_format);
255     lua_pushstring(L, kpse_format_info[user_format].path);
256     return 1;
257 }
258 
lua_kpathsea_show_path(lua_State * L)259 static int lua_kpathsea_show_path(lua_State * L)
260 {
261     kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
262     int op = luaL_checkoption(L, -1, "tex", filetypenames);
263     unsigned user_format = filetypes[op];
264     if (!(*kp)->format_info[user_format].type)  /* needed if arg was numeric */
265         kpathsea_init_format(*kp, user_format);
266     lua_pushstring(L, (*kp)->format_info[user_format].path);
267     return 1;
268 }
269 
expand_path(lua_State * L)270 static int expand_path(lua_State * L)
271 {
272     const char *st = luaL_checkstring(L, 1);
273     TEST_PROGRAM_NAME_SET;
274     lua_pushstring(L, kpse_path_expand(st));
275     return 1;
276 }
277 
lua_kpathsea_expand_path(lua_State * L)278 static int lua_kpathsea_expand_path(lua_State * L)
279 {
280     kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
281     const char *st = luaL_checkstring(L, 2);
282     lua_pushstring(L, kpathsea_path_expand(*kp, st));
283     return 1;
284 }
285 
expand_braces(lua_State * L)286 static int expand_braces(lua_State * L)
287 {
288     const char *st = luaL_checkstring(L, 1);
289     TEST_PROGRAM_NAME_SET;
290     lua_pushstring(L, kpse_brace_expand(st));
291     return 1;
292 }
293 
lua_kpathsea_expand_braces(lua_State * L)294 static int lua_kpathsea_expand_braces(lua_State * L)
295 {
296     kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
297     const char *st = luaL_checkstring(L, 2);
298     lua_pushstring(L, kpathsea_brace_expand(*kp, st));
299     return 1;
300 }
301 
302 
expand_var(lua_State * L)303 static int expand_var(lua_State * L)
304 {
305     const char *st = luaL_checkstring(L, 1);
306     TEST_PROGRAM_NAME_SET;
307     lua_pushstring(L, kpse_var_expand(st));
308     return 1;
309 }
310 
lua_kpathsea_expand_var(lua_State * L)311 static int lua_kpathsea_expand_var(lua_State * L)
312 {
313     kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
314     const char *st = luaL_checkstring(L, 2);
315     lua_pushstring(L, kpathsea_var_expand(*kp, st));
316     return 1;
317 }
318 
319 
var_value(lua_State * L)320 static int var_value(lua_State * L)
321 {
322     const char *st = luaL_checkstring(L, 1);
323     TEST_PROGRAM_NAME_SET;
324     lua_pushstring(L, kpse_var_value(st));
325     return 1;
326 }
327 
lua_kpathsea_var_value(lua_State * L)328 static int lua_kpathsea_var_value(lua_State * L)
329 {
330     kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
331     const char *st = luaL_checkstring(L, 2);
332     lua_pushstring(L, kpathsea_var_value(*kp, st));
333     return 1;
334 }
335 
find_dpi(const_string s)336 static unsigned find_dpi(const_string s)
337 {
338     unsigned dpi_number = 0;
339     const_string extension = find_suffix(s);
340 
341     if (extension != NULL)
342         sscanf(extension, "%u", &dpi_number);
343 
344     return dpi_number;
345 }
346 
347 /* Return newly-allocated NULL-terminated list of strings from MATCHES
348    that are prefixed with any of the subdirectories in SUBDIRS.  That
349    is, for a string S in MATCHES, its dirname must end with one of the
350    elements in SUBDIRS.  For instance, if subdir=foo/bar, that will
351    match a string foo/bar/baz or /some/texmf/foo/bar/baz.
352 
353    We don't reallocate the actual strings, just the list elements.
354    Perhaps later we will implement wildcards or // or something.  */
355 
subdir_match(str_list_type subdirs,string * matches)356 static string *subdir_match(str_list_type subdirs, string * matches)
357 {
358     string *ret = XTALLOC1(string);
359     unsigned len = 1;
360     unsigned m;
361 
362     for (m = 0; matches[m]; m++) {
363         size_t loc;
364         unsigned e;
365         string s = xstrdup(matches[m]);
366         for (loc = strlen(s); loc > 0 && !IS_DIR_SEP(s[loc - 1]); loc--);
367         while (loc > 0 && IS_DIR_SEP(s[loc - 1])) {
368             loc--;
369         }
370         s[loc] = 0;             /* wipe out basename */
371 
372         for (e = 0; e < STR_LIST_LENGTH(subdirs); e++) {
373             string subdir = STR_LIST_ELT(subdirs, e);
374             size_t subdir_len = strlen(subdir);
375             while (subdir_len > 0 && IS_DIR_SEP(subdir[subdir_len - 1])) {
376                 subdir_len--;
377                 subdir[subdir_len] = 0; /* remove trailing slashes from subdir spec */
378             }
379             if (FILESTRCASEEQ(subdir, s + loc - subdir_len)) {
380                 /* matched, save this one.  */
381                 XRETALLOC(ret, len + 1, string);
382                 ret[len - 1] = matches[m];
383                 len++;
384             }
385         }
386         free(s);
387     }
388     ret[len - 1] = NULL;
389     return ret;
390 }
391 
392 /* Use the file type from -format if that was specified (i.e., the
393    user_format global variable), else guess dynamically from NAME.
394    Return kpse_last_format if undeterminable.  This function is also
395    used to parse the -format string, a case which we distinguish by
396    setting is_filename to false.
397 
398    A few filenames have been hard-coded for format types that
399    differ from what would be inferred from their extensions. */
400 
401 static kpse_file_format_type
find_format(kpathsea kpse,const_string name,boolean is_filename)402 find_format(kpathsea kpse, const_string name, boolean is_filename)
403 {
404     kpse_file_format_type ret;
405 
406     if (FILESTRCASEEQ(name, "config.ps")) {
407         ret = kpse_dvips_config_format;
408     } else if (FILESTRCASEEQ(name, "dvipdfmx.cfg")) {
409         ret = kpse_program_text_format;
410     } else if (FILESTRCASEEQ(name, "fmtutil.cnf")) {
411         ret = kpse_web2c_format;
412     } else if (FILESTRCASEEQ(name, "glyphlist.txt")) {
413         ret = kpse_fontmap_format;
414     } else if (FILESTRCASEEQ(name, "mktex.cnf")) {
415         ret = kpse_web2c_format;
416     } else if (FILESTRCASEEQ(name, "pdfglyphlist.txt")) {
417         ret = kpse_fontmap_format;
418     } else if (FILESTRCASEEQ(name, "pdftex.cfg")) {
419         ret = kpse_pdftex_config_format;
420     } else if (FILESTRCASEEQ(name, "texmf.cnf")) {
421         ret = kpse_cnf_format;
422     } else if (FILESTRCASEEQ(name, "updmap.cfg")) {
423         ret = kpse_web2c_format;
424     } else if (FILESTRCASEEQ(name, "XDvi")) {
425         ret = kpse_program_text_format;
426     } else {
427         int f = 0;              /* kpse_file_format_type */
428         size_t name_len = strlen(name);
429 
430 /* Have to rely on `try_len' being declared here, since we can't assume
431    GNU C and statement expressions.  */
432 #define TRY_SUFFIX(ftry) (\
433   try_len = (ftry) ? strlen (ftry) : 0, \
434   (ftry) && try_len <= name_len \
435      && FILESTRCASEEQ (ftry, name + name_len - try_len))
436 
437         while (f != kpse_last_format) {
438             size_t try_len;
439             const_string *ext;
440             const_string ftry;
441             boolean found = false;
442 
443             if (!kpse->format_info[f].type)
444                 kpathsea_init_format(kpse, (kpse_file_format_type) f);
445 
446             if (!is_filename) {
447                 /* Allow the long name, but only in the -format option.  We don't
448                    want a filename confused with a format name.  */
449                 ftry = kpse->format_info[f].type;
450                 found = TRY_SUFFIX(ftry);
451             }
452             for (ext = kpse->format_info[f].suffix; !found && ext && *ext;
453                  ext++) {
454                 found = TRY_SUFFIX(*ext);
455             }
456             for (ext = kpse->format_info[f].alt_suffix; !found && ext && *ext;
457                  ext++) {
458                 found = TRY_SUFFIX(*ext);
459             }
460 
461             if (found)
462                 break;
463 
464             /* Some trickery here: the extensions for kpse_fmt_format can
465              * clash with other extensions in use, and we prefer for those
466              * others to be preferred.  And we don't want to change the
467              * integer value of kpse_fmt_format.  So skip it when first
468              * enountered, then use it when we've done everything else,
469              * and use it as the end-guard.
470              */
471             if (f == kpse_fmt_format) {
472                 f = kpse_last_format;
473             } else if (++f == kpse_fmt_format) {
474                 f++;
475             } else if (f == kpse_last_format) {
476                 f = kpse_fmt_format;
477             }
478         }
479 
480         /* If there was a match, f will be one past the correct value.  */
481         ret = f;
482     }
483 
484     return ret;
485 }
486 
487 /* kpse:lookup("plain.tex", {}) */
do_lua_kpathsea_lookup(lua_State * L,kpathsea kpse,int idx)488 static int do_lua_kpathsea_lookup(lua_State * L, kpathsea kpse, int idx)
489 {
490     int i;
491     string ret = NULL;
492     string *ret_list = NULL;
493     const_string name = NULL;
494     string user_path = NULL;
495     boolean show_all = false;
496     boolean must_exist = false;
497     kpse_file_format_type user_format = kpse_last_format;
498     int dpi = 600;
499     str_list_type subdir_paths = { 0, NULL };
500     unsigned saved_debug = kpse->debug;
501     int saved_mktexpk = kpse->format_info[kpse_pk_format].program_enabled_p;
502     int saved_mktexmf = kpse->format_info[kpse_mf_format].program_enabled_p;
503     int saved_mktextex = kpse->format_info[kpse_tex_format].program_enabled_p;
504     int saved_mktextfm = kpse->format_info[kpse_tfm_format].program_enabled_p;
505     name = luaL_checkstring(L, idx);
506     /* todo: fetch parameter values */
507 
508     if (lua_type(L, idx + 1) == LUA_TTABLE) {
509         lua_pushstring(L, "format");
510         lua_gettable(L, idx + 1);
511         if (lua_type(L, -1) == LUA_TSTRING) {
512             int op = luaL_checkoption(L, -1, NULL, filetypenames);
513             user_format = filetypes[op];
514         }
515         lua_pop(L, 1);
516         lua_pushstring(L, "dpi");
517         lua_gettable(L, idx + 1);
518         if (lua_type(L, -1) == LUA_TNUMBER) {
519             dpi=(int)lua_tonumber(L, -1);
520         }
521         lua_pop(L, 1);
522         lua_pushstring(L, "debug");
523         lua_gettable(L, idx + 1);
524         if (lua_type(L, -1) == LUA_TNUMBER) {
525             int d = 0;
526             d=(int)lua_tonumber(L, -1);
527             kpse->debug |= d;
528         }
529         lua_pop(L, 1);
530         lua_pushstring(L, "path");
531         lua_gettable(L, idx + 1);
532         if (lua_type(L, -1) == LUA_TSTRING) {
533             user_path = xstrdup(lua_tostring(L, -1));
534         }
535         lua_pop(L, 1);
536         lua_pushstring(L, "all");
537         lua_gettable(L, idx + 1);
538         if (lua_type(L, -1) == LUA_TBOOLEAN) {
539             show_all = lua_toboolean(L, -1);
540         }
541         lua_pop(L, 1);
542 
543         lua_pushstring(L, "mktexpk");
544         lua_gettable(L, idx + 1);
545         if (lua_type(L, -1) == LUA_TBOOLEAN) {
546             kpathsea_maketex_option(kpse, "pk", lua_toboolean(L, -1));
547         }
548         lua_pop(L, 1);
549 
550         lua_pushstring(L, "mktextex");
551         lua_gettable(L, idx + 1);
552         if (lua_type(L, -1) == LUA_TBOOLEAN) {
553             kpathsea_maketex_option(kpse, "tex", lua_toboolean(L, -1));
554         }
555         lua_pop(L, 1);
556 
557         lua_pushstring(L, "mktexmf");
558         lua_gettable(L, idx + 1);
559         if (lua_type(L, -1) == LUA_TBOOLEAN) {
560             kpathsea_maketex_option(kpse, "mf", lua_toboolean(L, -1));
561         }
562         lua_pop(L, 1);
563 
564         lua_pushstring(L, "mktextfm");
565         lua_gettable(L, idx + 1);
566         if (lua_type(L, -1) == LUA_TBOOLEAN) {
567             kpathsea_maketex_option(kpse, "tfm", lua_toboolean(L, -1));
568         }
569         lua_pop(L, 1);
570 
571 
572         lua_pushstring(L, "mustexist");
573         lua_gettable(L, idx + 1);
574         if (lua_type(L, -1) == LUA_TBOOLEAN) {
575             must_exist = lua_toboolean(L, -1);
576         }
577         lua_pop(L, 1);
578         lua_pushstring(L, "subdir");
579         lua_gettable(L, idx + 1);
580         if (lua_istable(L, -1)) {
581             lua_pushnil(L);
582             while (lua_next(L, -2) != 0) {      /* numeric value */
583                 if (lua_isstring(L, -1)) {
584 		    char *s = xstrdup(lua_tostring(L, -1));
585                     str_list_add(&subdir_paths, s);
586 		    xfree(s);
587                 }
588                 lua_pop(L, 1);
589             }
590         } else if (lua_isstring(L, -1)) {
591 	    char *s = xstrdup(lua_tostring(L, -1));
592             str_list_add(&subdir_paths, s);
593 	    xfree(s);
594         }
595         lua_pop(L, 1);
596         if (STR_LIST_LENGTH(subdir_paths) > 0) {
597             show_all = 1;
598         }
599     }
600     if (user_path) {
601         /* Translate ; to : if that's our ENV_SEP.  See cnf.c.  */
602         if (IS_ENV_SEP(':')) {
603             string loc;
604             for (loc = user_path; *loc; loc++) {
605                 if (*loc == ';')
606                     *loc = ':';
607             }
608         }
609         user_path = kpathsea_path_expand(kpse, user_path);
610         if (show_all) {
611             ret_list = kpathsea_all_path_search(kpse, user_path, name);
612         } else {
613             ret = kpathsea_path_search(kpse, user_path, name, must_exist);
614         }
615         free(user_path);
616     } else {
617         /* No user-specified search path, check user format or guess from NAME.  */
618         kpse_file_format_type fmt;
619         if (user_format != kpse_last_format)
620             fmt = user_format;
621         else
622             fmt = find_format(kpse, name, true);
623 
624         switch (fmt) {
625         case kpse_pk_format:
626         case kpse_gf_format:
627         case kpse_any_glyph_format:
628             {
629                 kpse_glyph_file_type glyph_ret;
630                 string temp = remove_suffix (name);
631                 /* Try to extract the resolution from the name.  */
632                 unsigned local_dpi = find_dpi(name);
633                 if (!local_dpi)
634                     local_dpi = (unsigned) dpi;
635                 ret =
636                     kpathsea_find_glyph(kpse, temp, local_dpi,
637                                         fmt, &glyph_ret);
638                 if (temp != name)
639                     free (temp);
640             }
641             break;
642 
643         case kpse_last_format:
644             /* If the suffix isn't recognized, assume it's a tex file. */
645             fmt = kpse_tex_format;
646             /* fall through */
647 
648         default:
649             if (show_all) {
650                 ret_list =
651                     kpathsea_find_file_generic(kpse, name, fmt, must_exist,
652                                                true);
653             } else {
654                 ret = kpathsea_find_file(kpse, name, fmt, must_exist);
655             }
656         }
657     }
658 
659     /* Turn single return into a null-terminated list for uniform treatment.  */
660     if (ret) {
661         ret_list = XTALLOC(2, string);
662         ret_list[0] = ret;
663         ret_list[1] = NULL;
664     }
665 
666     /* Filter by subdirectories, if specified.  */
667     if (STR_LIST_LENGTH(subdir_paths) > 0) {
668         string *new_list = subdir_match(subdir_paths, ret_list);
669         free(ret_list);
670         ret_list = new_list;
671     }
672     kpse->debug = saved_debug;
673     kpse->format_info[kpse_pk_format].program_enabled_p = saved_mktexpk;
674     kpse->format_info[kpse_mf_format].program_enabled_p = saved_mktexmf;
675     kpse->format_info[kpse_tex_format].program_enabled_p = saved_mktextex;
676     kpse->format_info[kpse_tfm_format].program_enabled_p = saved_mktextfm;
677 
678     /* Print output.  */
679     i = 0;
680     if (ret_list) {
681         for (; ret_list[i]; i++) {
682             lua_pushstring(L, ret_list[i]);
683         }
684         free(ret_list);
685     }
686     if (i == 0) {
687         i++;
688         lua_pushnil(L);
689     }
690     return i;
691 }
692 
693 
lua_kpathsea_lookup(lua_State * L)694 static int lua_kpathsea_lookup(lua_State * L)
695 {
696     kpathsea *kpsep = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
697     kpathsea kpse = *kpsep;
698     return do_lua_kpathsea_lookup(L, kpse, 2);
699 }
700 
lua_kpse_lookup(lua_State * L)701 static int lua_kpse_lookup(lua_State * L)
702 {
703     TEST_PROGRAM_NAME_SET;
704     return do_lua_kpathsea_lookup(L, kpse_def, 1);
705 }
706 
707 
708 /* Engine support is a bit of a problem, because we do not want
709  * to interfere with the normal format discovery of |luatex|.
710  * Current approach: run |os.setenv()| if you have to.
711  */
712 
set_program_name(lua_State * L)713 static int set_program_name(lua_State * L)
714 {
715     const char *exe_name = luaL_checkstring(L, 1);
716     const char *prog_name = luaL_optstring(L, 2, exe_name);
717     if (!program_name_set) {
718         kpse_set_program_name(exe_name, prog_name);
719         program_name_set = 1;
720     } else {
721         kpse_reset_program_name(prog_name);
722     }
723     /* fix up the texconfig entry */
724     lua_checkstack(L, 3);
725     lua_getglobal(L, "texconfig");
726     if (lua_istable(L, -1)) {
727         lua_pushstring(L, "kpse_init");
728         lua_pushboolean(L, 0);
729         lua_rawset(L, -3);
730     }
731     lua_pop(L, 1);
732     return 0;
733 }
734 
init_prog(lua_State * L)735 static int init_prog(lua_State * L)
736 {
737     const char *prefix = luaL_checkstring(L, 1);
738     unsigned dpi = (unsigned) luaL_checkinteger(L, 2);
739     const char *mode = luaL_checkstring(L, 3);
740     const char *fallback = luaL_optstring(L, 4, NULL);
741     TEST_PROGRAM_NAME_SET;
742     kpse_init_prog(prefix, dpi, mode, fallback);
743     return 0;
744 }
745 
lua_kpathsea_init_prog(lua_State * L)746 static int lua_kpathsea_init_prog(lua_State * L)
747 {
748     kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
749     const char *prefix = luaL_checkstring(L, 2);
750     unsigned dpi = (unsigned) luaL_checkinteger(L, 3);
751     const char *mode = luaL_checkstring(L, 4);
752     const char *fallback = luaL_optstring(L, 5, NULL);
753     kpathsea_init_prog(*kp, prefix, dpi, mode, fallback);
754     return 0;
755 }
756 
lua_kpse_version(lua_State * L)757 static int lua_kpse_version(lua_State * L)
758 {
759     lua_pushstring(L, kpathsea_version_string);
760     return 1;
761 }
762 
readable_file(lua_State * L)763 static int readable_file(lua_State * L)
764 {
765     char *name = xstrdup(luaL_checkstring(L, 1));
766     TEST_PROGRAM_NAME_SET;
767     lua_pushstring(L, kpse_readable_file(name));
768     free(name);
769     return 1;
770 }
771 
lua_kpathsea_readable_file(lua_State * L)772 static int lua_kpathsea_readable_file(lua_State * L)
773 {
774     kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
775     char *name = xstrdup(luaL_checkstring(L, 2));
776     lua_pushstring(L, kpathsea_readable_file(*kp, name));
777     free(name);
778     return 1;
779 }
780 
781 
lua_kpathsea_finish(lua_State * L)782 static int lua_kpathsea_finish(lua_State * L)
783 {
784     kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
785     kpathsea_finish(*kp);
786     return 0;
787 }
788 
lua_kpathsea_new(lua_State * L)789 static int lua_kpathsea_new(lua_State * L)
790 {
791     kpathsea kpse = NULL;
792     kpathsea *kp = NULL;
793     const char *av = luaL_checkstring(L, 1);
794     const char *liar = luaL_optstring(L, 2, av);
795     kpse = kpathsea_new();
796     kpathsea_set_program_name(kpse, av, liar);
797     kp = (kpathsea *) lua_newuserdata(L, sizeof(kpathsea *));
798     *kp = kpse;
799     luaL_getmetatable(L, KPATHSEA_METATABLE);
800     lua_setmetatable(L, -2);
801     return 1;
802 }
803 
804 static const struct luaL_Reg kpselib_m[] = {
805     {"__gc", lua_kpathsea_finish},
806     {"init_prog", lua_kpathsea_init_prog},
807     {"readable_file", lua_kpathsea_readable_file},
808     {"find_file", lua_kpathsea_find_file},
809     {"expand_path", lua_kpathsea_expand_path},
810     {"expand_var", lua_kpathsea_expand_var},
811     {"expand_braces", lua_kpathsea_expand_braces},
812     {"var_value", lua_kpathsea_var_value},
813     {"show_path", lua_kpathsea_show_path},
814     {"lookup", lua_kpathsea_lookup},
815     {"version", lua_kpse_version},
816     {"default_texmfcnf", show_texmfcnf},
817     {NULL, NULL}                /* sentinel */
818 };
819 
820 static const struct luaL_Reg kpselib_l[] = {
821     {"new", lua_kpathsea_new},
822     {"set_program_name", set_program_name},
823     {"init_prog", init_prog},
824     {"readable_file", readable_file},
825     {"find_file", find_file},
826     {"expand_path", expand_path},
827     {"expand_var", expand_var},
828     {"expand_braces", expand_braces},
829     {"var_value", var_value},
830     {"show_path", show_path},
831     {"lookup", lua_kpse_lookup},
832     {"version", lua_kpse_version},
833     {"default_texmfcnf", show_texmfcnf},
834     {NULL, NULL}                /* sentinel */
835 };
836 
luaopen_kpse(lua_State * L)837 int luaopen_kpse(lua_State * L)
838 {
839     luaL_newmetatable(L, KPATHSEA_METATABLE);
840     lua_pushvalue(L, -1);
841     lua_setfield(L, -2, "__index");
842     luaL_register(L, NULL, kpselib_m);
843     luaL_register(L, "kpse", kpselib_l);
844     return 1;
845 }
846