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