1
4
5# include "luametatex.h"
6
7
14
15callback_state_info lmt_callback_state = {
16 .metatable_id = 0,
17 .padding = 0,
18 .values = { 0 },
19};
20
21
22
23static const char *callbacklib_names[total_callbacks] = {
24 "",
25 "find_log_file",
26 "find_format_file",
27 "open_data_file",
28 "process_jobname",
29 "start_run",
30 "stop_run",
31 "define_font",
32 "quality_font",
33 "pre_output_filter",
34 "buildpage_filter",
35 "hpack_filter",
36 "vpack_filter",
37 "hyphenate",
38 "ligaturing",
39 "kerning",
40 "glyph_run",
41 "pre_linebreak_filter",
42 "linebreak_filter",
43 "post_linebreak_filter",
44 "append_to_vlist_filter",
45 "alignment_filter",
46 "local_box_filter",
47 "packed_vbox_filter",
48 "mlist_to_hlist",
49 "pre_dump",
50 "start_file",
51 "stop_file",
52 "intercept_tex_error",
53 "intercept_lua_error",
54 "show_error_message",
55 "show_warning_message",
56 "hpack_quality",
57 "vpack_quality",
58 "show_break",
59 "show_build",
60 "insert_par",
61 "append_line_filter",
62 "insert_distance",
63
64 "wrapup_run",
65 "begin_paragraph",
66 "paragraph_context",
67
68 "math_rule",
69 "make_extensible",
70 "register_extensible",
71 "show_whatsit",
72 "get_attribute",
73 "get_noad_class",
74 "get_math_dictionary",
75 "show_lua_call",
76 "trace_memory",
77 "handle_overload",
78 "missing_character",
79 "process_character",
80 "linebreak_quality",
81 "paragraph_pass",
82 "handle_uleader",
83 "italic_correction",
84};
85
86
92
93static int callbacklib_aux_run(lua_State *L, int id, int special, const char *values, va_list vl, int top, int base)
94{
95 int narg = 0;
96 int nres = 0;
97 if (special == 2) {
98
99 lua_pushvalue(L, -2);
100 }
101 for (narg = 0; *values; narg++) {
102 switch (*values++) {
103 case callback_boolean_key:
104
105 lua_pushboolean(L, va_arg(vl, int));
106 break;
107 case callback_charnum_key:
108
109 {
110 char cs = (char) va_arg(vl, int);
111 lua_pushlstring(L, &cs, 1);
112 }
113 break;
114 case callback_integer_key:
115
116 lua_pushinteger(L, va_arg(vl, int));
117 break;
118 case callback_line_key:
119
120 lua_pushlstring(L, (char *) (lmt_fileio_state.io_buffer + lmt_fileio_state.io_first), (size_t) va_arg(vl, int));
121 break;
122 case callback_strnumber_key:
123
124 {
125 size_t len;
126 const char *s = tex_makeclstring(va_arg(vl, int), &len);
127 lua_pushlstring(L, s, len);
128 }
129 break;
130 case callback_lstring_key:
131
132 {
133 lstring *lstr = va_arg(vl, lstring *);
134 lua_pushlstring(L, (const char *) lstr->s, lstr->l);
135 }
136 break;
137 case callback_node_key:
138
139 lmt_push_node_fast(L, va_arg(vl, int));
140 break;
141 case callback_string_key:
142
143 lua_pushstring(L, va_arg(vl, char *));
144 break;
145 case '-':
146 narg--;
147 break;
148 case '>':
149 goto ENDARGS;
150 default:
151 ;
152 }
153 }
154 ENDARGS:
155 nres = (int) strlen(values);
156 if (special == 1) {
157 nres++;
158 } else if (special == 2) {
159 narg++;
160 }
161 lmt_lua_state.saved_callback_count++;
162 {
163 int i = lua_pcall(L, narg, nres, base);
164 if (i) {
165
169 lua_remove(L, top + 2);
170 lmt_error(L, "run callback", id, (i == LUA_ERRRUN ? 0 : 1));
171 lua_settop(L, top);
172 return 0;
173 }
174 }
175 if (nres == 0) {
176 return 1;
177 }
178 nres = -nres;
179 while (*values) {
180 int t = lua_type(L, nres);
181 switch (*values++) {
182 case callback_boolean_key:
183 switch (t) {
184 case LUA_TBOOLEAN:
185 *va_arg(vl, int *) = lua_toboolean(L, nres);
186 break;
187 case LUA_TNIL:
188 *va_arg(vl, int *) = 0;
189 break;
190 default:
191 return tex_formatted_error("callback", "boolean or nil expected, false or nil, not: %s\n", lua_typename(L, t));
192 }
193 break;
194
198 case callback_integer_key:
199 switch (t) {
200 case LUA_TNUMBER:
201 *va_arg(vl, int *) = lmt_tointeger(L, nres);
202 break;
203 default:
204 return tex_formatted_error("callback", "number expected, not: %s\n", lua_typename(L, t));
205 }
206 break;
207 case callback_line_key:
208 switch (t) {
209 case LUA_TSTRING:
210 {
211 size_t len;
212 const char *s = lua_tolstring(L, nres, &len);
213 if (s && (len > 0)) {
214 int *bufloc = va_arg(vl, int *);
215 int ret = *bufloc;
216 if (tex_room_in_buffer(ret + (int) len)) {
217 strncpy((char *) (lmt_fileio_state.io_buffer + ret), s, len);
218 *bufloc += (int) len;
219
220 while ((*bufloc) - 1 > ret && lmt_fileio_state.io_buffer[(*bufloc) - 1] == ' ') {
221 (*bufloc)--;
222 }
223 } else {
224 return 0;
225 }
226 }
227
228 }
229 break;
230 case LUA_TNIL:
231
232 return 0;
233 default:
234 return tex_formatted_error("callback", "string or nil expected, not: %s\n", lua_typename(L, t));
235 }
236 break;
237 case callback_strnumber_key:
238 switch (t) {
239 case LUA_TSTRING:
240 {
241 size_t len;
242 const char *s = lua_tolstring(L, nres, &len);
243 if (s) {
244 *va_arg(vl, int *) = tex_maketexlstring(s, len);
245 } else {
246
247 *va_arg(vl, int *) = 0;
248 }
249 }
250 break;
251 default:
252 return tex_formatted_error("callback", "string expected, not: %s\n", lua_typename(L, t));
253 }
254 break;
255 case callback_lstring_key:
256 switch (t) {
257 case LUA_TSTRING:
258 {
259 size_t len;
260 const char *s = lua_tolstring(L, nres, &len);
261 if (s && len > 0) {
262 lstring *lsret = lmt_memory_malloc(sizeof(lstring));
263 if (lsret) {
264 lsret->s = lmt_memory_malloc((unsigned) (len + 1));
265 if (lsret->s) {
266 (void) memcpy(lsret->s, s, (len + 1));
267 lsret->l = len;
268 *va_arg(vl, lstring **) = lsret;
269 } else {
270 *va_arg(vl, int *) = 0;
271 }
272 } else {
273 *va_arg(vl, int *) = 0;
274 }
275 } else {
276
277 *va_arg(vl, int *) = 0;
278 }
279 }
280 break;
281 default:
282 return tex_formatted_error("callback", "string expected, not: %s\n", lua_typename(L, t));
283 }
284 break;
285 case callback_node_key:
286 switch (t) {
287 case LUA_TUSERDATA:
288 *va_arg(vl, int *) = lmt_check_isnode(L, nres);
289 break;
290 default:
291 *va_arg(vl, int *) = null;
292 break;
293 }
294 break;
295 case callback_string_key:
296 switch (t) {
297 case LUA_TSTRING:
298 {
299 size_t len;
300 const char *s = lua_tolstring(L, nres, &len);
301 if (s) {
302 char *ss = lmt_memory_malloc((unsigned) (len + 1));
303 if (ss) {
304 memcpy(ss, s, (len + 1));
305 }
306 *va_arg(vl, char **) = ss;
307 } else {
308 *va_arg(vl, char **) = NULL;
309
310 }
311 }
312 break;
313 default:
314 return tex_formatted_error("callback", "string expected, not: %s\n", lua_typename(L, t));
315 }
316 break;
317 case callback_result_s_key:
318 switch (t) {
319 case LUA_TNIL:
320 *va_arg(vl, int *) = 0;
321 break;
322 case LUA_TBOOLEAN:
323 if (lua_toboolean(L, nres) == 0) {
324 *va_arg(vl, int *) = 0;
325 break;
326 } else {
327 return tex_formatted_error("callback", "string, false or nil expected, not: %s\n", lua_typename(L, t));
328 }
329 case LUA_TSTRING:
330 {
331 size_t len;
332 const char *s = lua_tolstring(L, nres, &len);
333 if (s) {
334 char *ss = lmt_memory_malloc((unsigned) (len + 1));
335 if (ss) {
336 memcpy(ss, s, (len + 1));
337 *va_arg(vl, char **) = ss;
338 } else {
339 *va_arg(vl, char **) = NULL;
340
341 }
342 } else {
343 *va_arg(vl, char **) = NULL;
344
345 }
346 }
347 break;
348 default:
349 return tex_formatted_error("callback", "string, false or nil expected, not: %s\n", lua_typename(L, t));
350 }
351 break;
352 case callback_result_i_key:
353 switch (t) {
354 case LUA_TNUMBER:
355 *va_arg(vl, int *) = lmt_tointeger(L, nres);
356 break;
357 default:
358
359 break;
360 }
361 break;
362 default:
363 return tex_formatted_error("callback", "invalid value type returned\n");
364 }
365 nres++;
366 }
367 return 1;
368}
369
370
374
375int lmt_run_saved_callback_close(lua_State *L, int r)
376{
377 int ret = 0;
378 int stacktop = lua_gettop(L);
379 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
380 lua_push_key(close);
381 if (lua_rawget(L, -2) == LUA_TFUNCTION) {
382 ret = lua_pcall(L, 0, 0, 0);
383 if (ret) {
384 return tex_formatted_error("lua", "error in close file callback") - 1;
385 }
386 }
387 lua_settop(L, stacktop);
388 return ret;
389}
390
391int lmt_run_saved_callback_line(lua_State *L, int r, int firstpos)
392{
393 int ret = -1;
394 int stacktop = lua_gettop(L);
395 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
396 lua_push_key(reader);
397 if (lua_rawget(L, -2) == LUA_TFUNCTION) {
398 lua_pushvalue(L, -2);
399 lmt_lua_state.file_callback_count++;
400 ret = lua_pcall(L, 1, 1, 0);
401 if (ret) {
402 ret = tex_formatted_error("lua", "error in read line callback") - 1;
403 } else if (lua_type(L, -1) == LUA_TSTRING) {
404 size_t len;
405 const char *s = lua_tolstring(L, -1, &len);
406 if (s && len > 0) {
407 while (len >= 1 && s[len-1] == ' ') {
408 len--;
409 }
410 if (len > 0) {
411 if (tex_room_in_buffer(firstpos + (int) len)) {
412 strncpy((char *) (lmt_fileio_state.io_buffer + firstpos), s, len);
413 ret = firstpos + (int) len;
414 } else {
415 tex_overflow_error("buffer", (int) len);
416 ret = 0;
417 }
418 } else {
419 ret = 0;
420 }
421 } else {
422 ret = 0;
423 }
424 } else {
425 ret = -1;
426 }
427 }
428 lua_settop(L, stacktop);
429 return ret;
430}
431
432
439
440int lmt_callback_okay(lua_State *L, int i, int *top)
441{
442 *top = lua_gettop(L);
443 lua_rawgeti(L, LUA_REGISTRYINDEX, lmt_callback_state.metatable_id);
444 lua_pushcfunction(L, lmt_traceback);
445 if (lua_rawgeti(L, -2, i) == LUA_TFUNCTION) {
446 lmt_lua_state.saved_callback_count++;
447 return 1;
448 } else {
449 lua_pop(L, 3);
450 return 0;
451 }
452}
453
454void lmt_callback_error(lua_State *L, int top, int i)
455{
456 lua_remove(L, top + 2);
457 lmt_error(L, "callback error", -1, (i == LUA_ERRRUN ? 0 : 1));
458 lua_settop(L, top);
459}
460
461int lmt_run_and_save_callback(lua_State *L, int i, const char *values, ...)
462{
463 int top = 0;
464 int ret = 0;
465 if (lmt_callback_okay(L, i, &top)) {
466 va_list args;
467 va_start(args, values);
468 ret = callbacklib_aux_run(L, i, 1, values, args, top, top + 2);
469 va_end(args);
470 if (ret > 0) {
471 ret = lua_type(L, -1) == LUA_TTABLE ? luaL_ref(L, LUA_REGISTRYINDEX) : 0;
472 }
473 lua_settop(L, top);
474 }
475 return ret;
476}
477
478int lmt_run_callback(lua_State *L, int i, const char *values, ...)
479{
480 int top = 0;
481 int ret = 0;
482 if (lmt_callback_okay(L, i, &top)) {
483 va_list args;
484 va_start(args, values);
485 ret = callbacklib_aux_run(L, i, 0, values, args, top, top + 2);
486 va_end(args);
487 lua_settop(L, top);
488 }
489 return ret;
490}
491
492void lmt_destroy_saved_callback(lua_State *L, int i)
493{
494 luaL_unref(L, LUA_REGISTRYINDEX, i);
495}
496
497static int callbacklib_callback_found(const char *s)
498{
499 if (s) {
500 for (int cb = 0; cb < total_callbacks; cb++) {
501 if (strcmp(callbacklib_names[cb], s) == 0) {
502 return cb;
503 }
504 }
505 }
506 return -1;
507}
508
509static int callbacklib_callback_register(lua_State *L)
510{
511 const char *s = lua_tostring(L, 1);
512 int cb = callbacklib_callback_found(s);
513 if (cb >= 0) {
514 switch (lua_type(L, 2)) {
515 case LUA_TFUNCTION:
516 lmt_callback_state.values[cb] = cb;
517 break;
518 case LUA_TBOOLEAN:
519 if (lua_toboolean(L, 2)) {
520 goto BAD;
521 }
522
523 case LUA_TNIL:
524 lmt_callback_state.values[cb] = -1;
525 break;
526 }
527 lua_rawgeti(L, LUA_REGISTRYINDEX, lmt_callback_state.metatable_id);
528 lua_pushvalue(L, 2);
529 lua_rawseti(L, -2, cb);
530 lua_rawseti(L, LUA_REGISTRYINDEX, lmt_callback_state.metatable_id);
531 lua_pushinteger(L, cb);
532 return 1;
533 }
534 BAD:
535 lua_pushnil(L);
536 return 1;
537}
538
539void lmt_run_memory_callback(const char* what, int success)
540{
541 lmt_run_callback(lmt_lua_state.lua_instance, trace_memory_callback, "Sb->", what, success);
542 fflush(stdout);
543}
544
545
551
552static int callbacklib_callback_find(lua_State *L)
553{
554 const char *s = lua_tostring(L, 1);
555 if (s) {
556 int cb = callbacklib_callback_found(s);
557 if (cb >= 0) {
558 lua_rawgeti(L, LUA_REGISTRYINDEX, lmt_callback_state.metatable_id);
559 lua_rawgeti(L, -1, cb);
560 return 1;
561 }
562 }
563 lua_pushnil(L);
564 return 1;
565}
566
567static int callbacklib_callback_known(lua_State *L)
568{
569 const char *s = lua_tostring(L, 1);
570 lua_pushboolean(L, s && (callbacklib_callback_found(s) >= 0));
571 return 1;
572}
573
574static int callbacklib_callback_list(lua_State *L)
575{
576 lua_createtable(L, 0, total_callbacks);
577 for (int cb = 1; cb < total_callbacks; cb++) {
578 lua_pushstring(L, callbacklib_names[cb]);
579 lua_pushboolean(L, lmt_callback_defined(cb));
580 lua_rawset(L, -3);
581 }
582 return 1;
583}
584
585
586
587void lmt_push_callback_usage(lua_State *L)
588{
589 lua_createtable(L, 0, 9);
590 lua_push_integer_at_key(L, saved, lmt_lua_state.saved_callback_count);
591 lua_push_integer_at_key(L, file, lmt_lua_state.file_callback_count);
592 lua_push_integer_at_key(L, direct, lmt_lua_state.direct_callback_count);
593 lua_push_integer_at_key(L, function, lmt_lua_state.function_callback_count);
594 lua_push_integer_at_key(L, value, lmt_lua_state.value_callback_count);
595 lua_push_integer_at_key(L, local, lmt_lua_state.local_callback_count);
596 lua_push_integer_at_key(L, bytecode, lmt_lua_state.bytecode_callback_count);
597 lua_push_integer_at_key(L, message, lmt_lua_state.message_callback_count);
598 lua_push_integer_at_key(L, count,
599 lmt_lua_state.saved_callback_count
600 + lmt_lua_state.file_callback_count
601 + lmt_lua_state.direct_callback_count
602 + lmt_lua_state.function_callback_count
603 + lmt_lua_state.value_callback_count
604 + lmt_lua_state.local_callback_count
605 + lmt_lua_state.bytecode_callback_count
606 + lmt_lua_state.message_callback_count
607 );
608}
609
610static int callbacklib_callback_usage(lua_State *L)
611{
612 lmt_push_callback_usage(L);
613 return 1;
614}
615
616static const struct luaL_Reg callbacklib_function_list[] = {
617 { "find", callbacklib_callback_find },
618 { "known", callbacklib_callback_known },
619 { "register", callbacklib_callback_register },
620 { "list", callbacklib_callback_list },
621 { "usage", callbacklib_callback_usage },
622 { NULL, NULL },
623};
624
625int luaopen_callback(lua_State *L)
626{
627 lua_newtable(L);
628 luaL_setfuncs(L, callbacklib_function_list, 0);
629 lua_newtable(L);
630 lmt_callback_state.metatable_id = luaL_ref(L, LUA_REGISTRYINDEX);
631 return 1;
632}
633 |