lmtkpse.c /size: 11 Kb    last modification: 2024-01-16 10:22
1/*
2    See license.txt in the root of this project.
3*/
4
5# include "luametatex.h"
6# include "lmtoptional.h"
7
8/*tex
9
10    As part of the lean and mean concept we have no \KPSE\ on board and as with \LUATEX\ the
11    \CONTEXT\ macro package doesn't need it. However, because we might want to play with it being
12    a runner for other engines (as we do with the \LUATEX\ binary in kpse mode), we have at least
13    an interface for it. One problem is to locate the right version of the delayed loaded kpse
14    library (but we can add some clever locating code for that if needed). We keep the interface
15    mostly the same as \LUATEX.
16
17    This is actually a left-over from an experiment, but it works okay, so I moved the code into
18    the source tree and made a proper \CONTEXT\ library wrapper too. We are less clever than in
19    \LUATEX, so there are no additional lookup functions. After all, it is just about locating
20    files and not about writing a searcher in \LUA. So, there no subdir magic either, as one has
21    \LUA\ for that kind of stuff. No \DPI\ related magic either. In \LUATEX\ there are some more
22    functions in the \type {kpse} namespace but these don't really relate to locating files.
23
24    We can actually omit the next two lists and pass numbers but then we need to store that list at
25    the \LUA\ end so we don't save much (but I might do it some day nevertheless). The nect code is
26    rather lightweight which is on purpose. Of course occationally we need to check the \API\ but
27    \KPSE\ pretty stable and we don't need the extra stuff that it provides (keep in mind that it
28    has to serve all kind of programs in the \TEX\ infrastructure so it's a complex beast).
29
30*/
31
32typedef enum kpselib_file_format_type {
33    kpse_gf_format, kpse_pk_format, kpse_any_glyph_format, kpse_tfm_format, kpse_afm_format,
34    kpse_base_format, kpse_bib_format, kpse_bst_format, kpse_cnf_format, kpse_db_format,
35    kpse_fmt_format, kpse_fontmap_format, kpse_mem_format, kpse_mf_format, kpse_mfpool_format,
36    kpse_mft_format, kpse_mp_format, kpse_mppool_format, kpse_mpsupport_format, kpse_ocp_format,
37    kpse_ofm_format, kpse_opl_format, kpse_otp_format, kpse_ovf_format, kpse_ovp_format,
38    kpse_pict_format, kpse_tex_format, kpse_texdoc_format, kpse_texpool_format,
39    kpse_texsource_format, kpse_tex_ps_header_format, kpse_troff_font_format, kpse_type1_format,
40    kpse_vf_format, kpse_dvips_config_format, kpse_ist_format, kpse_truetype_format,
41    kpse_type42_format, kpse_web2c_format, kpse_program_text_format, kpse_program_binary_format,
42    kpse_miscfonts_format, kpse_web_format, kpse_cweb_format, kpse_enc_format, kpse_cmap_format,
43    kpse_sfd_format, kpse_opentype_format, kpse_pdftex_config_format, kpse_lig_format,
44    kpse_texmfscripts_format, kpse_lua_format, kpse_fea_format, kpse_cid_format, kpse_mlbib_format,
45    kpse_mlbst_format, kpse_clua_format, /* kpse_ris_format, */ /* kpse_bltxml_format, */
46    kpse_last_format
47} kpselib_file_format_type;
48
49static const char *const kpselib_file_type_names[] = {
50    "gf", "pk", "bitmap font", "tfm", "afm", "base", "bib", "bst", "cnf", "ls-R", "fmt", "map",
51    "mem", "mf", "mfpool", "mft", "mp", "mppool", "MetaPost support", "ocp", "ofm", "opl", "otp",
52    "ovf", "ovp", "graphic/figure", "tex", "TeX system documentation", "texpool",
53    "TeX system sources", "PostScript header",  "Troff fonts", "type1 fonts", "vf", "dvips config",
54    "ist", "truetype fonts", "type42 fonts", "web2c files", "other text files", "other binary files",
55    "misc fonts", "web", "cweb", "enc files", "cmap files", "subfont definition files",
56    "opentype fonts", "pdftex config", "lig files", "texmfscripts", "lua", "font feature files",
57    "cid maps", "mlbib", "mlbst", "clua",
58    NULL
59};
60
61typedef struct kpselib_state_info {
62
63    int initialized;
64    int prognameset;
65
66    void   (*lib_kpse_set_program_name)   ( const char *prog, const char *name );
67    void   (*lib_kpse_reset_program_name) ( const char *name );
68    char * (*lib_kpse_path_expand)        ( const char *name );
69    char * (*lib_kpse_brace_expand)       ( const char *name );
70    char * (*lib_kpse_var_expand)         ( const char *name );
71    char * (*lib_kpse_var_value)          ( const char *name );
72    char * (*lib_kpse_readable_file)      ( const char *name );
73    char * (*lib_kpse_find_file)          ( const char *name, int filetype, int mustexist );
74    char **(*lib_kpse_all_path_search)    ( const char *path, const char *name );
75
76} kpselib_state_info;
77
78static kpselib_state_info kpselib_state = {
79
80    .initialized                 = 0,
81    .prognameset                 = 0,
82
83    .lib_kpse_set_program_name   = NULL,
84    .lib_kpse_reset_program_name = NULL,
85    .lib_kpse_path_expand        = NULL,
86    .lib_kpse_brace_expand       = NULL,
87    .lib_kpse_var_expand         = NULL,
88    .lib_kpse_var_value          = NULL,
89    .lib_kpse_readable_file      = NULL,
90    .lib_kpse_find_file          = NULL,
91    .lib_kpse_all_path_search    = NULL,
92
93};
94
95static int kpselib_aux_valid_progname(lua_State *L)
96{
97    (void) L;
98    if (kpselib_state.prognameset) {
99        return 1;
100    } else if (! kpselib_state.initialized) {
101        tex_normal_warning("kpse", "not yet initialized");
102        return 0;
103    } else {
104        tex_normal_warning("kpse", "no program name set");
105        return 0;
106    }
107}
108
109static int kpselib_set_program_name(lua_State *L)
110{
111    (void) L;
112    if (kpselib_state.initialized) {
113        const char *exe_name = luaL_checkstring(L, 1);
114        const char *prog_name = luaL_optstring(L, 2, exe_name);
115        if (kpselib_state.prognameset) {
116            kpselib_state.lib_kpse_reset_program_name(prog_name);
117        } else {
118            kpselib_state.lib_kpse_set_program_name(exe_name, prog_name);
119            kpselib_state.prognameset = 1;
120        }
121    }
122    return 0;
123}
124
125static int kpselib_find_file(lua_State *L)
126{
127    if (kpselib_aux_valid_progname(L)) {
128        unsigned filetype = kpse_tex_format;
129        int mustexist = 0;
130        const char *filename = luaL_checkstring(L, 1);
131        int top = lua_gettop(L);
132        for (int i = 2; i <= top; i++) {
133            switch (lua_type(L, i)) {
134                case LUA_TBOOLEAN:
135                    mustexist = lua_toboolean(L, i);
136                    break;
137                case LUA_TNUMBER:
138                    /*tex This is different from \LUATEX: we accept a filetype number. */
139                    filetype = (unsigned) lua_tointeger(L, i);
140                    break;
141                case LUA_TSTRING:
142                    filetype = luaL_checkoption(L, i, NULL, kpselib_file_type_names);
143                    break;
144            }
145            if (filetype >= kpse_last_format) {
146                filetype = kpse_tex_format;
147            }
148        }
149        lua_pushstring(L, kpselib_state.lib_kpse_find_file(filename, filetype, mustexist));
150        return 1;
151    } else {
152        return 0;
153    }
154}
155
156/*
157    I'll ask Taco about the free. For now it will do. Currently I only need to do some lookups for
158    checking clashes with other installations (issue reported on context ml).
159*/
160
161static int kpselib_find_files(lua_State *L)
162{
163    if (kpselib_aux_valid_progname(L)) {
164        const char *userpath = luaL_checkstring(L, 1);
165        const char *filename = luaL_checkstring(L, 2);
166        char *filepath = kpselib_state.lib_kpse_path_expand(userpath);
167        if (filepath) {
168            char **result = kpselib_state.lib_kpse_all_path_search(filepath, filename);
169         /* free(filepath); */ /* crashes, so it looks like def kpse keeps it */
170            if (result) {
171                lua_Integer r = 0;
172                lua_newtable(L);
173                while (result[r]) {
174                    lua_pushstring(L, result[r]);
175                    lua_rawseti(L, -2, ++r);
176                }
177             /* free(result); */ /* idem */
178                return 1;
179            }
180        } else {
181         /* free(filepath); */ /* idem */
182        }
183    }
184    return 0;
185}
186
187static int kpselib_expand_path(lua_State *L)
188{
189    if (kpselib_aux_valid_progname(L)) {
190        lua_pushstring(L, kpselib_state.lib_kpse_path_expand(luaL_checkstring(L, 1)));
191        return 1;
192    } else {
193        return 0;
194    }
195}
196
197static int kpselib_expand_braces(lua_State *L)
198{
199    if (kpselib_aux_valid_progname(L)) {
200        lua_pushstring(L, kpselib_state.lib_kpse_brace_expand(luaL_checkstring(L, 1)));
201    return 1;
202    } else {
203        return 0;
204    }
205}
206
207static int kpselib_expand_var(lua_State *L)
208{
209    if (kpselib_aux_valid_progname(L)) {
210        lua_pushstring(L, kpselib_state.lib_kpse_var_expand(luaL_checkstring(L, 1)));
211        return 1;
212    } else {
213        return 0;
214    }
215}
216
217static int kpselib_var_value(lua_State *L)
218{
219    if (kpselib_aux_valid_progname(L)) {
220        lua_pushstring(L, kpselib_state.lib_kpse_var_value(luaL_checkstring(L, 1)));
221        return 1;
222    } else {
223        return 0;
224    }
225}
226
227static int kpselib_readable_file(lua_State *L)
228{
229    if (kpselib_aux_valid_progname(L)) {
230        /* Why the dup? */
231        char *name = strdup(luaL_checkstring(L, 1));
232        lua_pushstring(L, kpselib_state.lib_kpse_readable_file(name));
233        free(name);
234        return 1;
235    } else {
236        return 0;
237    }
238}
239
240static int kpselib_get_file_types(lua_State *L)
241{
242    if (kpselib_aux_valid_progname(L)) {
243        lua_createtable(L, kpse_last_format, 0);
244        for (lua_Integer i = 0; i < kpse_last_format; i++) {
245            if (kpselib_file_type_names[i]) {
246                lua_pushstring(L, kpselib_file_type_names[i]);
247                lua_rawseti(L, -2, i + 1);
248            } else {
249                break;
250            }
251        }
252        return 1;
253    } else {
254        return 0;
255    }
256}
257
258static int kpselib_initialize(lua_State *L)
259{
260    if (! kpselib_state.initialized) {
261        const char *filename = lua_tostring(L, 1);
262        if (filename) {
263
264            lmt_library lib = lmt_library_load(filename);
265
266            kpselib_state.lib_kpse_set_program_name   = lmt_library_find(lib, "kpse_set_program_name");
267            kpselib_state.lib_kpse_reset_program_name = lmt_library_find(lib, "kpse_reset_program_name");
268            kpselib_state.lib_kpse_all_path_search    = lmt_library_find(lib, "kpse_all_path_search");
269            kpselib_state.lib_kpse_find_file          = lmt_library_find(lib, "kpse_find_file");
270            kpselib_state.lib_kpse_path_expand        = lmt_library_find(lib, "kpse_path_expand");
271            kpselib_state.lib_kpse_brace_expand       = lmt_library_find(lib, "kpse_brace_expand");
272            kpselib_state.lib_kpse_var_expand         = lmt_library_find(lib, "kpse_var_expand");
273            kpselib_state.lib_kpse_var_value          = lmt_library_find(lib, "kpse_var_value");
274            kpselib_state.lib_kpse_readable_file      = lmt_library_find(lib, "kpse_readable_file");
275
276            kpselib_state.initialized = lmt_library_okay(lib);
277        }
278    }
279    lua_pushboolean(L, kpselib_state.initialized);
280    return 1;
281}
282
283/*tex We use the official names here, with underscores. */
284
285/* init_prog           : no need         */
286/* show_path           : maybe           */
287/* lookup              : maybe           */
288/* default_texmfcnf    : not that useful */
289/* record_output_file  : makes no sense  */
290/* record_input_file   : makes no sense  */
291/* check_permissions   : luatex extra    */
292
293static struct luaL_Reg kpselib_function_list[] = {
294    { "initialize",       kpselib_initialize         },
295    { "set_program_name", kpselib_set_program_name   },
296    { "find_file",        kpselib_find_file          },
297    { "find_files",       kpselib_find_files         },
298    { "expand_path",      kpselib_expand_path        },
299    { "expand_var",       kpselib_expand_var         },
300    { "expand_braces",    kpselib_expand_braces      },
301    { "var_value",        kpselib_var_value          },
302    { "readable_file",    kpselib_readable_file      },
303    { "get_file_types",   kpselib_get_file_types     },
304    { NULL,               NULL                       },
305};
306
307int luaopen_kpse(lua_State * L)
308{
309    lmt_library_register(L, "kpse", kpselib_function_list);
310    return 0;
311}
312