lmtstatuslib.c /size: 32 Kb    last modification: 2024-01-16 10:22
1/*
2    See license.txt in the root of this project.
3*/
4
5/*tex
6
7    This module has been there from the start and provides some information that doesn't really
8    fit elsewhere. In \LUATEX\ the module got extended ovet time, and in \LUAMETATEX\ most of what
9    is here has been redone, also because we want different statistics.
10
11*/
12
13# include "luametatex.h"
14
15# define STATS_METATABLE "tex.stats"
16
17typedef struct statistic_entry {
18    const char *name;
19    void       *value;
20    int         type;
21    int         padding;
22} statistic_entry;
23
24typedef const char *(*constfunc) (void);
25typedef char       *(*charfunc)  (void);
26typedef lua_Number  (*numfunc)   (void);
27typedef int         (*intfunc)   (void);
28typedef int         (*luafunc)   (lua_State *L);
29
30static int statslib_callbackstate(lua_State *L)
31{
32    lmt_push_callback_usage(L);
33    return 1;
34}
35
36static int statslib_texstate(lua_State *L)
37{
38    lua_Integer approximate = 0
39        + (lua_Integer) lmt_string_pool_state .string_pool_data    .allocated * (lua_Integer) lmt_string_pool_state .string_pool_data    .itemsize
40        + (lua_Integer) lmt_string_pool_state .string_body_data    .allocated * (lua_Integer) lmt_string_pool_state .string_body_data    .itemsize
41        + (lua_Integer) lmt_node_memory_state .nodes_data          .allocated * (lua_Integer) lmt_node_memory_state .nodes_data          .itemsize
42        + (lua_Integer) lmt_node_memory_state .extra_data          .allocated * (lua_Integer) lmt_node_memory_state .extra_data          .itemsize
43        + (lua_Integer) lmt_token_memory_state.tokens_data         .allocated * (lua_Integer) lmt_token_memory_state.tokens_data         .itemsize
44        + (lua_Integer) lmt_fileio_state      .io_buffer_data      .allocated * (lua_Integer) lmt_fileio_state      .io_buffer_data      .itemsize
45        + (lua_Integer) lmt_input_state       .input_stack_data    .allocated * (lua_Integer) lmt_input_state       .input_stack_data    .itemsize
46        + (lua_Integer) lmt_input_state       .in_stack_data       .allocated * (lua_Integer) lmt_input_state       .in_stack_data       .itemsize
47        + (lua_Integer) lmt_nest_state        .nest_data           .allocated * (lua_Integer) lmt_nest_state        .nest_data           .itemsize
48        + (lua_Integer) lmt_input_state       .parameter_stack_data.allocated * (lua_Integer) lmt_input_state       .parameter_stack_data.itemsize
49        + (lua_Integer) lmt_save_state        .save_stack_data     .allocated * (lua_Integer) lmt_save_state        .save_stack_data     .itemsize
50        + (lua_Integer) lmt_hash_state        .hash_data           .allocated * (lua_Integer) lmt_hash_state        .hash_data           .itemsize
51        + (lua_Integer) lmt_fileio_state      .io_buffer_data      .allocated * (lua_Integer) lmt_fileio_state      .io_buffer_data      .itemsize
52        + (lua_Integer) lmt_font_state        .font_data           .allocated * (lua_Integer) lmt_font_state        .font_data           .itemsize
53        + (lua_Integer) lmt_language_state    .language_data       .allocated * (lua_Integer) lmt_language_state    .language_data       .itemsize
54        + (lua_Integer) lmt_mark_state        .mark_data           .allocated * (lua_Integer) lmt_mark_state        .mark_data           .itemsize
55        + (lua_Integer) lmt_insert_state      .insert_data         .allocated * (lua_Integer) lmt_insert_state      .insert_data         .itemsize
56        + (lua_Integer) lmt_sparse_state      .sparse_data         .allocated * (lua_Integer) lmt_sparse_state      .sparse_data         .itemsize
57    ;
58    lua_createtable(L, 0, 4);
59    lua_set_integer_by_key(L, "approximate", (int) approximate);
60    return 1;
61}
62
63static int statslib_luastate(lua_State *L)
64{
65    lua_createtable(L, 0, 6);
66    lua_set_integer_by_key(L, "functionsize",   lmt_lua_state.function_table_size);
67    lua_set_integer_by_key(L, "propertiessize", lmt_node_memory_state.node_properties_table_size);
68    lua_set_integer_by_key(L, "bytecodes",      lmt_lua_state.bytecode_max);
69    lua_set_integer_by_key(L, "bytecodebytes",  lmt_lua_state.bytecode_bytes);
70    lua_set_integer_by_key(L, "statebytes",     lmt_lua_state.used_bytes);
71    lua_set_integer_by_key(L, "statebytesmax",  lmt_lua_state.used_bytes_max);
72    return 1;
73}
74
75static int statslib_errorstate(lua_State* L)
76{
77    lua_createtable(L, 0, 3);
78    lua_set_string_by_key(L, "error",         lmt_error_state.last_error);
79    lua_set_string_by_key(L, "errorcontext",  lmt_error_state.last_error_context);
80    lua_set_string_by_key(L, "luaerror",      lmt_error_state.last_lua_error);
81    return 1;
82}
83
84static int statslib_warningstate(lua_State* L)
85{
86    lua_createtable(L, 0, 2);
87    lua_set_string_by_key(L, "warningtag",    lmt_error_state.last_warning_tag);
88    lua_set_string_by_key(L, "warning",       lmt_error_state.last_warning);
89    return 1;
90}
91
92static int statslib_aux_stats_name_to_id(const char *name, statistic_entry stats[])
93{
94    for (int i = 0; stats[i].name; i++) {
95        if (strcmp (stats[i].name, name) == 0) {
96            return i;
97        }
98    }
99    return -1;
100}
101
102static int statslib_aux_limits_state(lua_State* L, limits_data *data)
103{
104    lua_createtable(L, 0, 4);
105    lua_set_integer_by_key(L, "set", data->size);
106    lua_set_integer_by_key(L, "min", data->minimum);
107    lua_set_integer_by_key(L, "max", data->maximum);
108    lua_set_integer_by_key(L, "top", data->top);
109    return 1;
110}
111
112static int statslib_aux_memory_state(lua_State* L, memory_data *data)
113{
114    lua_createtable(L, 0, 9);
115    lua_set_integer_by_key(L, "set", data->size); /*tex Can |memory_data_unset|. */
116    lua_set_integer_by_key(L, "min", data->minimum);
117    lua_set_integer_by_key(L, "max", data->maximum);
118    lua_set_integer_by_key(L, "mem", data->allocated);
119    lua_set_integer_by_key(L, "all", data->allocated > 0 ? (int) lmt_rounded(((double) data->allocated) * ((double) data->itemsize)) : data->allocated);
120    lua_set_integer_by_key(L, "top", data->top - data->offset);
121    lua_set_integer_by_key(L, "ptr", data->ptr - data->offset);
122    lua_set_integer_by_key(L, "ini", data->initial); /*tex Can |memory_data_unset|. */
123    lua_set_integer_by_key(L, "stp", data->step);
124 // lua_set_integer_by_key(L, "off", data->offset);
125    return 1;
126}
127
128static int statslib_errorlinestate    (lua_State* L) { return statslib_aux_limits_state(L, &lmt_error_state       .line_limits);  }
129static int statslib_halferrorlinestate(lua_State* L) { return statslib_aux_limits_state(L, &lmt_error_state       .half_line_limits); }
130static int statslib_expandstate       (lua_State* L) { return statslib_aux_limits_state(L, &lmt_expand_state      .limits); }
131static int statslib_stringstate       (lua_State* L) { return statslib_aux_memory_state(L, &lmt_string_pool_state .string_pool_data); }
132static int statslib_poolstate         (lua_State* L) { return statslib_aux_memory_state(L, &lmt_string_pool_state .string_body_data); }
133static int statslib_lookupstate       (lua_State* L) { return statslib_aux_memory_state(L, &lmt_hash_state        .eqtb_data); }
134static int statslib_hashstate         (lua_State* L) { return statslib_aux_memory_state(L, &lmt_hash_state        .hash_data); }
135static int statslib_nodestate         (lua_State* L) { return statslib_aux_memory_state(L, &lmt_node_memory_state .nodes_data); }
136static int statslib_extrastate        (lua_State* L) { return statslib_aux_memory_state(L, &lmt_node_memory_state .extra_data); }
137static int statslib_tokenstate        (lua_State* L) { return statslib_aux_memory_state(L, &lmt_token_memory_state.tokens_data); }
138static int statslib_inputstate        (lua_State* L) { return statslib_aux_memory_state(L, &lmt_input_state       .input_stack_data); }
139static int statslib_filestate         (lua_State* L) { return statslib_aux_memory_state(L, &lmt_input_state       .in_stack_data); }
140static int statslib_parameterstate    (lua_State* L) { return statslib_aux_memory_state(L, &lmt_input_state       .parameter_stack_data); }
141static int statslib_neststate         (lua_State* L) { return statslib_aux_memory_state(L, &lmt_nest_state        .nest_data); }
142static int statslib_savestate         (lua_State* L) { return statslib_aux_memory_state(L, &lmt_save_state        .save_stack_data); }
143static int statslib_bufferstate       (lua_State* L) { return statslib_aux_memory_state(L, &lmt_fileio_state      .io_buffer_data); }
144static int statslib_fontstate         (lua_State* L) { return statslib_aux_memory_state(L, &lmt_font_state        .font_data); }
145static int statslib_languagestate     (lua_State* L) { return statslib_aux_memory_state(L, &lmt_language_state    .language_data); }
146static int statslib_markstate         (lua_State* L) { return statslib_aux_memory_state(L, &lmt_mark_state        .mark_data); }
147static int statslib_insertstate       (lua_State* L) { return statslib_aux_memory_state(L, &lmt_insert_state      .insert_data); }
148static int statslib_sparsestate       (lua_State* L) { return statslib_aux_memory_state(L, &lmt_sparse_state      .sparse_data); }
149
150static int statslib_readstate(lua_State *L)
151{
152    lua_createtable(L, 0, 4);
153    lua_set_string_by_key (L, "filename",       tex_current_input_file_name());
154    lua_set_integer_by_key(L, "iocode",         lmt_input_state.cur_input.name > io_file_input_code ? io_file_input_code : lmt_input_state.cur_input.name);
155    lua_set_integer_by_key(L, "linenumber",     lmt_input_state.input_line);
156    lua_set_integer_by_key(L, "skiplinenumber", lmt_condition_state.skip_line);
157    return 1;
158}
159
160static int statslib_enginestate(lua_State *L)
161{
162    lua_createtable(L, 0, 15);
163    lua_set_string_by_key (L, "logfilename",     lmt_fileio_state.log_name);
164    lua_set_string_by_key (L, "banner",          lmt_engine_state.luatex_banner);
165    lua_set_number_by_key (L, "version",         lmt_version_state.luatexversion);
166    lua_set_string_by_key (L, "luatex_engine",   lmt_engine_state.engine_name);
167    lua_set_integer_by_key(L, "luatex_version",  lmt_version_state.version);
168    lua_set_integer_by_key(L, "luatex_revision", lmt_version_state.revision);
169    lua_set_integer_by_key(L, "luatex_release",  lmt_version_state.release);
170    lua_set_string_by_key(L,  "luatex_verbose",  lmt_version_state.verbose);
171    lua_set_integer_by_key(L, "development_id",  lmt_version_state.developmentid);
172    lua_set_string_by_key (L, "copyright",       lmt_version_state.copyright);
173    lua_set_integer_by_key(L, "format_id",       lmt_version_state.formatid);
174    lua_set_integer_by_key(L, "tex_hash_size",   hash_size);
175    lua_set_string_by_key (L, "used_compiler",   lmt_version_state.compiler);
176 // lua_set_string_by_key (L, "used_libc",       lmt_version_state.libc);
177    lua_set_integer_by_key(L, "run_state",       lmt_main_state.run_state);
178    lua_set_boolean_by_key(L, "permit_loadlib",  lmt_engine_state.permit_loadlib);
179    return 1;
180}
181
182static int statslib_aux_getstat_indeed(lua_State *L, statistic_entry stats[], int i)
183{
184    switch (stats[i].type) {
185        case 'S':
186            /* string function pointer, no copy */
187            {
188                const char *st = (*(constfunc) stats[i].value)();
189                lua_pushstring(L, st);
190                /* No freeing here! */
191                break;
192            }
193     // case 's':
194     //     /* string function pointer, copy */
195     //     {
196     //         char *st = (*(charfunc) stats[i].value)();
197     //         lua_pushstring(L, st);
198     //         lmt_memory_free(st);
199     //         break;
200     //     }
201     // case 'N':
202     //     /* number function pointer */
203     //     lua_pushnumber(L, (*(numfunc) stats[i].value)());
204     //     break;
205     // case 'G':
206     //     /* integer function pointer */
207     //     lua_pushinteger(L, (*(intfunc) stats[i].value)());
208     //     break;
209        case 'd':
210            /* double pointer */
211            lua_pushnumber(L, *(double *) (stats[i].value));
212            break;
213        case 'g':
214            /* integer pointer */
215            lua_pushinteger(L, *(int *) (stats[i].value));
216            break;
217        case 'c':
218            /* string pointer */
219            lua_pushstring(L, *(const char **) (stats[i].value));
220            break;
221     // case 'n': /* node */
222     //     /* node pointer */
223     //     if (*(halfword*) (stats[i].value)) {
224     //         lmt_push_node_fast(L, *(halfword *) (stats[i].value));
225     //     } else {
226     //         lua_pushnil(L);
227     //     }
228     //     break;
229        case 'b':
230            /* boolean integer pointer */
231            lua_pushboolean(L, *(int *) (stats[i].value));
232            break;
233        case 'f':
234            (*(luafunc) stats[i].value)(L);
235            break;
236        default:
237            /* nothing reasonable */
238            lua_pushnil(L);
239            break;
240    }
241    return 1;
242}
243
244static int statslib_aux_getstats_indeed(lua_State *L, statistic_entry stats[])
245{
246    if (lua_type(L, -1) == LUA_TSTRING) {
247        const char *st = lua_tostring(L, -1);
248        int i = statslib_aux_stats_name_to_id(st, stats);
249        if (i >= 0) {
250            return statslib_aux_getstat_indeed(L, stats, i);
251        }
252    }
253    return 0;
254}
255
256static int statslib_getconstants(lua_State *L)
257{
258    lua_createtable(L, 0, 100);
259
260    lua_set_integer_by_key(L, "no_catcode_table",               no_catcode_table_preset);
261    lua_set_integer_by_key(L, "default_catcode_table",          default_catcode_table_preset);
262                                                                
263    lua_set_cardinal_by_key(L,"max_cardinal",                   max_cardinal);
264    lua_set_cardinal_by_key(L,"min_cardinal",                   min_cardinal);
265    lua_set_integer_by_key(L, "max_integer",                    max_integer);
266    lua_set_integer_by_key(L, "min_integer",                    min_integer);
267    lua_set_integer_by_key(L, "max_dimen",                      max_dimension); /* obsolete */
268    lua_set_integer_by_key(L, "min_dimen",                      min_dimension); /* obsolete */
269    lua_set_integer_by_key(L, "max_dimension",                  max_dimension);
270    lua_set_integer_by_key(L, "min_dimension",                  min_dimension);
271    lua_set_integer_by_key(L, "min_data_value",                 min_data_value);
272    lua_set_integer_by_key(L, "max_data_value",                 max_data_value);
273    lua_set_integer_by_key(L, "max_half_value",                 max_half_value);
274                                                                
275    lua_set_integer_by_key(L, "max_limited_scale",              max_limited_scale);
276    lua_set_integer_by_key(L, "max_math_style_scale",           max_math_style_scale);
277                                                                
278    lua_set_integer_by_key(L, "one_bp",                         one_bp);
279                                                                
280    lua_set_integer_by_key(L, "infinity",                       max_infinity);
281    lua_set_integer_by_key(L, "min_infinity",                   min_infinity);
282    lua_set_integer_by_key(L, "awful_bad",                      awful_bad);
283    lua_set_integer_by_key(L, "infinite_bad",                   infinite_bad);
284    lua_set_integer_by_key(L, "infinite_penalty",               infinite_penalty);
285    lua_set_integer_by_key(L, "eject_penalty",                  eject_penalty);
286    lua_set_integer_by_key(L, "deplorable",                     deplorable);
287    lua_set_integer_by_key(L, "large_width_excess",             large_width_excess);
288    lua_set_integer_by_key(L, "small_stretchability",           small_stretchability);
289    lua_set_integer_by_key(L, "decent_criterion",               decent_criterion);
290    lua_set_integer_by_key(L, "loose_criterion",                loose_criterion);
291                                                                
292    lua_set_integer_by_key(L, "default_rule",                   default_rule);
293    lua_set_integer_by_key(L, "ignore_depth",                   ignore_depth);
294                                                                
295    lua_set_integer_by_key(L, "min_quarterword",                min_quarterword);
296    lua_set_integer_by_key(L, "max_quarterword",                max_quarterword);
297                                                                
298    lua_set_integer_by_key(L, "min_halfword",                   min_halfword);
299    lua_set_integer_by_key(L, "max_halfword",                   max_halfword);
300                                                                
301    lua_set_integer_by_key(L, "null_flag",                      null_flag);
302    lua_set_integer_by_key(L, "zero_glue",                      zero_glue);
303    lua_set_integer_by_key(L, "unity",                          unity);
304    lua_set_integer_by_key(L, "two",                            two);
305    lua_set_integer_by_key(L, "null",                           null);
306    lua_set_integer_by_key(L, "null_font",                      null_font);
307                                                                
308    lua_set_integer_by_key(L, "unused_attribute_value",         unused_attribute_value);
309    lua_set_integer_by_key(L, "unused_state_value",             unused_state_value);
310    lua_set_integer_by_key(L, "unused_script_value",            unused_script_value);
311                                                                
312    lua_set_integer_by_key(L, "preset_rule_thickness",          preset_rule_thickness);
313    lua_set_integer_by_key(L, "running_rule",                   null_flag);
314                                                                
315    lua_set_integer_by_key(L, "min_space_factor",               min_space_factor);
316    lua_set_integer_by_key(L, "max_space_factor",               max_space_factor);
317    lua_set_integer_by_key(L, "min_scale_factor",               min_scale_factor);
318    lua_set_integer_by_key(L, "max_scale_factor",               max_scale_factor);
319    lua_set_integer_by_key(L, "default_space_factor",           default_space_factor);
320    lua_set_integer_by_key(L, "default_tolerance",              default_tolerance);
321    lua_set_integer_by_key(L, "default_hangafter",              default_hangafter);
322    lua_set_integer_by_key(L, "default_deadcycles",             default_deadcycles);
323    lua_set_integer_by_key(L, "default_pre_display_gap",        default_pre_display_gap);
324    lua_set_integer_by_key(L, "default_eqno_gap_step",          default_eqno_gap_step);
325                                                                
326    lua_set_integer_by_key(L, "default_output_box",             default_output_box);
327                                                                
328    lua_set_integer_by_key(L, "max_n_of_fonts",                 max_n_of_fonts);
329    lua_set_integer_by_key(L, "max_n_of_bytecodes",             max_n_of_bytecodes);
330    lua_set_integer_by_key(L, "max_n_of_math_families",         max_n_of_math_families);
331    lua_set_integer_by_key(L, "max_n_of_languages",             max_n_of_languages);
332    lua_set_integer_by_key(L, "max_n_of_catcode_tables",        max_n_of_catcode_tables);
333 /* lua_set_integer_by_key(L, "max_n_of_hjcode_tables",         max_n_of_hjcode_tables); */ /* meaningless */
334    lua_set_integer_by_key(L, "max_n_of_marks",                 max_n_of_marks);
335                                                                
336    lua_set_integer_by_key(L, "max_character_code",             max_character_code);
337    lua_set_integer_by_key(L, "max_mark_index",                 max_mark_index);
338                                                                
339    lua_set_integer_by_key(L, "max_toks_register_index",        max_toks_register_index);
340    lua_set_integer_by_key(L, "max_box_register_index",         max_box_register_index);
341    lua_set_integer_by_key(L, "max_int_register_index",         max_integer_register_index);   /* obsolete */
342    lua_set_integer_by_key(L, "max_integer_register_index",     max_integer_register_index);
343    lua_set_integer_by_key(L, "max_float_register_index",       max_posit_register_index);
344    lua_set_integer_by_key(L, "max_dimension_register_index",   max_dimension_register_index);
345    lua_set_integer_by_key(L, "max_dimen_register_index",       max_dimension_register_index); /* obsolete */
346    lua_set_integer_by_key(L, "max_attribute_register_index",   max_attribute_register_index);
347    lua_set_integer_by_key(L, "max_glue_register_index",        max_glue_register_index);
348    lua_set_integer_by_key(L, "max_muglue_register_index",      max_muglue_register_index);
349                                                                
350    lua_set_integer_by_key(L, "max_bytecode_index",             max_bytecode_index);
351    lua_set_integer_by_key(L, "max_math_family_index",          max_math_family_index);
352    lua_set_integer_by_key(L, "max_math_class_code",            max_math_class_code);
353    lua_set_integer_by_key(L, "max_function_reference",         max_function_reference);
354    lua_set_integer_by_key(L, "max_category_code",              max_category_code);
355                                                                
356    lua_set_integer_by_key(L, "max_newline_character",          max_newline_character);
357    lua_set_integer_by_key(L, "max_endline_character",          max_endline_character);
358                                                                
359    lua_set_integer_by_key(L, "max_size_of_word",               max_size_of_word);
360                                                                
361    lua_set_integer_by_key(L, "tex_hash_size",                  hash_size);
362    lua_set_integer_by_key(L, "tex_hash_prime",                 hash_prime);
363    lua_set_integer_by_key(L, "tex_eqtb_size",                  eqtb_size);
364                                                                
365    lua_set_integer_by_key(L, "math_begin_class",               math_begin_class);
366    lua_set_integer_by_key(L, "math_end_class",                 math_end_class);
367    lua_set_integer_by_key(L, "unused_math_family",             unused_math_family);
368    lua_set_integer_by_key(L, "unused_math_style",              unused_math_style);
369    lua_set_integer_by_key(L, "assumed_math_control",           assumed_math_control);
370                                                                
371    lua_set_integer_by_key(L, "undefined_math_parameter",       undefined_math_parameter);
372                                                                
373    lua_set_integer_by_key(L, "max_calculated_badness",         max_calculated_badness);
374                                                                
375    lua_set_integer_by_key(L, "max_math_scaling_factor",        max_math_scaling_factor);   
376    lua_set_integer_by_key(L, "math_default_penalty",           math_default_penalty);   
377
378    lua_set_integer_by_key(L, "max_font_adjust_step",           max_font_adjust_step);            
379    lua_set_integer_by_key(L, "max_font_adjust_stretch_factor", max_font_adjust_stretch_factor);
380    lua_set_integer_by_key(L, "max_font_adjust_shrink_factor",  max_font_adjust_shrink_factor);
381
382    return 1;
383}
384
385static struct statistic_entry statslib_entries[] = {
386
387    /*tex But these are now collected in tables: */
388
389    { .name = "enginestate",        .value = &statslib_enginestate,        .type = 'f' },
390    { .name = "errorlinestate",     .value = &statslib_errorlinestate,     .type = 'f' },
391    { .name = "halferrorlinestate", .value = &statslib_halferrorlinestate, .type = 'f' },
392    { .name = "expandstate",        .value = &statslib_expandstate,        .type = 'f' },
393    { .name = "stringstate",        .value = &statslib_stringstate,        .type = 'f' },
394    { .name = "poolstate",          .value = &statslib_poolstate,          .type = 'f' },
395    { .name = "hashstate",          .value = &statslib_hashstate,          .type = 'f' },
396    { .name = "lookupstate",        .value = &statslib_lookupstate,        .type = 'f' },
397    { .name = "nodestate",          .value = &statslib_nodestate,          .type = 'f' },
398    { .name = "extrastate",         .value = &statslib_extrastate,         .type = 'f' },
399    { .name = "tokenstate",         .value = &statslib_tokenstate,         .type = 'f' },
400    { .name = "inputstate",         .value = &statslib_inputstate,         .type = 'f' },
401    { .name = "filestate",          .value = &statslib_filestate,          .type = 'f' },
402    { .name = "parameterstate",     .value = &statslib_parameterstate,     .type = 'f' },
403    { .name = "neststate",          .value = &statslib_neststate,          .type = 'f' },
404    { .name = "savestate",          .value = &statslib_savestate,          .type = 'f' },
405    { .name = "bufferstate",        .value = &statslib_bufferstate,        .type = 'f' },
406    { .name = "texstate",           .value = &statslib_texstate,           .type = 'f' },
407    { .name = "luastate",           .value = &statslib_luastate,           .type = 'f' },
408    { .name = "callbackstate",      .value = &statslib_callbackstate,      .type = 'f' },
409    { .name = "errorstate",         .value = &statslib_errorstate,         .type = 'f' },
410    { .name = "warningstate",       .value = &statslib_warningstate,       .type = 'f' },
411    { .name = "readstate",          .value = &statslib_readstate,          .type = 'f' },
412    { .name = "fontstate",          .value = &statslib_fontstate,          .type = 'f' },
413    { .name = "languagestate",      .value = &statslib_languagestate,      .type = 'f' },
414    { .name = "markstate",          .value = &statslib_markstate,          .type = 'f' },
415    { .name = "insertstate",        .value = &statslib_insertstate,        .type = 'f' },
416    { .name = "sparsestate",        .value = &statslib_sparsestate,        .type = 'f' },
417
418    /*tex Lua keys: */
419
420    { .name = "lua_version_major",   .value = (void *) &lmt_version_state.luaversionmajor,   .type = 'g' },
421    { .name = "lua_version_minor",   .value = (void *) &lmt_version_state.luaversionminor,   .type = 'g' },
422    { .name = "lua_version_release", .value = (void *) &lmt_version_state.luaversionrelease, .type = 'g' },
423    { .name = "lua_version",         .value = (void *) &lmt_version_state.luaversion,        .type = 'd' },
424
425    /*tex We keep these as direct accessible keys: */
426
427    { .name = "filename",           .value = (void *) &tex_current_input_file_name,     .type = 'S' },
428    { .name = "logfilename",        .value = (void *) &lmt_fileio_state.log_name,       .type = 'c' },
429    { .name = "banner",             .value = (void *) &lmt_engine_state.luatex_banner,  .type = 'c' },
430    { .name = "version",            .value = (void *) &lmt_version_state.luatexversion, .type = 'd' },
431    { .name = "luatex_engine",      .value = (void *) &lmt_engine_state.engine_name,    .type = 'c' },
432    { .name = "luatex_version",     .value = (void *) &lmt_version_state.version,       .type = 'g' },
433    { .name = "luatex_revision",    .value = (void *) &lmt_version_state.revision,      .type = 'g' },
434    { .name = "luatex_release",     .value = (void *) &lmt_version_state.release,       .type = 'g' },
435    { .name = "luatex_verbose",     .value = (void *) &lmt_version_state.verbose,       .type = 'c' },
436    { .name = "copyright",          .value = (void *) &lmt_version_state.copyright,     .type = 'c' },
437    { .name = "development_id",     .value = (void *) &lmt_version_state.developmentid, .type = 'g' },
438    { .name = "format_id",          .value = (void *) &lmt_version_state.formatid,      .type = 'g' },
439    { .name = "used_compiler",      .value = (void *) &lmt_version_state.compiler,      .type = 'c' },
440    { .name = "run_state",          .value = (void *) &lmt_main_state.run_state,        .type = 'g' },
441    { .name = "permit_loadlib",     .value = (void *) &lmt_engine_state.permit_loadlib, .type = 'b' },
442
443    { .name = NULL,                 .value = NULL,                                      .type = 0   },
444};
445
446static struct statistic_entry statslib_entries_only[] = {
447    { .name = "filename",           .value = (void *) &tex_current_input_file_name,     .type = 'S' },
448    { .name = "banner",             .value = (void *) &lmt_engine_state.luatex_banner,  .type = 'c' },
449    { .name = "version",            .value = (void *) &lmt_version_state.luatexversion, .type = 'd' },
450    { .name = "luatex_engine",      .value = (void *) &lmt_engine_state.engine_name,    .type = 'c' },
451    { .name = "luatex_version",     .value = (void *) &lmt_version_state.version,       .type = 'g' },
452    { .name = "luatex_revision",    .value = (void *) &lmt_version_state.revision,      .type = 'g' },
453    { .name = "luatex_release",     .value = (void *) &lmt_version_state.release,       .type = 'g' },
454    { .name = "luatex_verbose",     .value = (void *) &lmt_version_state.verbose,       .type = 'c' },
455    { .name = "copyright",          .value = (void *) &lmt_version_state.copyright,     .type = 'c' },
456    { .name = "development_id",     .value = (void *) &lmt_version_state.developmentid, .type = 'g' },
457    { .name = "format_id",          .value = (void *) &lmt_version_state.formatid,      .type = 'g' },
458    { .name = "used_compiler",      .value = (void *) &lmt_version_state.compiler,      .type = 'c' },
459
460    { .name = NULL,                 .value = NULL,                                      .type = 0   },
461};
462
463static int statslib_aux_getstats(lua_State *L)
464{
465    return statslib_aux_getstats_indeed(L, statslib_entries);
466}
467
468static int statslib_aux_getstats_only(lua_State *L)
469{
470    return statslib_aux_getstats_indeed(L, statslib_entries_only);
471}
472
473static int statslib_aux_statslist(lua_State *L, statistic_entry stats[])
474{
475    lua_createtable(L, 0, 60);
476    for (int i = 0; stats[i].name; i++) {
477        lua_pushstring(L, stats[i].name);
478        statslib_aux_getstat_indeed(L, stats, i);
479        lua_rawset(L, -3);
480    }
481    return 1;
482}
483
484static int statslib_statslist(lua_State *L)
485{
486    return statslib_aux_statslist(L, statslib_entries);
487}
488
489static int statslib_statslist_only(lua_State *L)
490{
491    return statslib_aux_statslist(L, statslib_entries_only);
492}
493
494static int statslib_resetmessages(lua_State *L)
495{
496    (void) (L);
497    lmt_memory_free(lmt_error_state.last_warning);
498    lmt_memory_free(lmt_error_state.last_warning_tag);
499    lmt_memory_free(lmt_error_state.last_error);
500    lmt_memory_free(lmt_error_state.last_lua_error);
501    lmt_error_state.last_warning = NULL;
502    lmt_error_state.last_warning_tag = NULL;
503    lmt_error_state.last_error = NULL;
504    lmt_error_state.last_lua_error = NULL;
505    return 0;
506}
507
508static const struct luaL_Reg statslib_function_list[] = {
509    { "list",                  statslib_statslist          }, /* for old times sake */
510    { "getconstants",          statslib_getconstants       },
511    { "resetmessages",         statslib_resetmessages      },
512
513    { "gettexstate",           statslib_texstate           },
514    { "getluastate",           statslib_luastate           },
515    { "geterrorstate",         statslib_errorstate         },
516    { "getwarningstate",       statslib_warningstate       },
517    { "getreadstate",          statslib_readstate          },
518    { "getcallbackstate",      statslib_callbackstate      },
519
520    { "geterrorlinestate",     statslib_errorlinestate     },
521    { "gethalferrorlinestate", statslib_halferrorlinestate },
522    { "getexpandstate",        statslib_expandstate        },
523
524    { "getstringstate",        statslib_stringstate        },
525    { "getpoolstate",          statslib_poolstate          },
526    { "gethashstate",          statslib_hashstate          },
527    { "getlookupstate",        statslib_lookupstate        },
528    { "getnodestate",          statslib_nodestate          },
529    { "getextrastate",         statslib_extrastate         },
530    { "gettokenstate",         statslib_tokenstate         },
531    { "getinputstate",         statslib_inputstate         },
532    { "getfilestate",          statslib_filestate          },
533    { "getparameterstate",     statslib_parameterstate     },
534    { "getneststate",          statslib_neststate          },
535    { "getsavestate",          statslib_savestate          },
536    { "getbufferstate",        statslib_bufferstate        },
537    { "getfontstate",          statslib_fontstate          },
538    { "getlanguagestate",      statslib_languagestate      },
539    { "getmarkstate",          statslib_markstate          },
540    { "getinsertstate",        statslib_insertstate        },
541    { "getsparsestate",        statslib_sparsestate        },
542
543    { NULL,                    NULL                        },
544};
545
546static const struct luaL_Reg statslib_function_list_only[] = {
547    { "list", statslib_statslist_only },
548    { NULL,   NULL                    },
549};
550
551int luaopen_status(lua_State *L)
552{
553    lua_newtable(L);
554    luaL_setfuncs(L, lmt_engine_state.lua_only ? statslib_function_list_only : statslib_function_list, 0);
555    luaL_newmetatable(L, STATS_METATABLE);
556    lua_pushstring(L, "__index");
557    lua_pushcfunction(L, lmt_engine_state.lua_only ? statslib_aux_getstats_only : statslib_aux_getstats);
558    lua_settable(L, -3);
559    lua_setmetatable(L, -2); /*tex meta to itself */
560    return 1;
561}
562