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