1 /* lcallbacklib.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
23
24 int callback_count = 0;
25 int saved_callback_count = 0;
26
27 int callback_set[total_callbacks] = { 0 };
28
29 /* See also callback_callback_type in luatexcallbackids.h: they must have the same order ! */
30 static const char *const callbacknames[] = {
31 "", /* empty on purpose */
32 "find_write_file",
33 "find_output_file",
34 "find_image_file",
35 "find_format_file",
36 "find_read_file", "open_read_file",
37 "find_vf_file", "read_vf_file",
38 "find_data_file", "read_data_file",
39 "find_font_file", "read_font_file",
40 "find_map_file", "read_map_file",
41 "find_enc_file", "read_enc_file",
42 "find_type1_file", "read_type1_file",
43 "find_truetype_file", "read_truetype_file",
44 "find_opentype_file", "read_opentype_file",
45 "find_sfd_file", "read_sfd_file",
46 "find_cidmap_file", "read_cidmap_file",
47 "find_pk_file", "read_pk_file",
48 "show_error_hook",
49 "process_input_buffer", "process_output_buffer",
50 "process_jobname",
51 "start_page_number", "stop_page_number",
52 "start_run", "stop_run",
53 "define_font",
54 "token_filter",
55 "pre_output_filter",
56 "buildpage_filter",
57 "hpack_filter", "vpack_filter",
58 "char_exists",
59 "hyphenate",
60 "ligaturing",
61 "kerning",
62 "pre_linebreak_filter",
63 "linebreak_filter",
64 "post_linebreak_filter",
65 "mlist_to_hlist",
66 "finish_pdffile",
67 "finish_pdfpage",
68 "pre_dump","start_file", "stop_file",
69 "show_error_message","show_lua_error_hook",
70 "pdf_stream_filter_callback",
71 NULL
72 };
73
74 int callback_callbacks_id = 0;
75
debug_callback_defined(int i)76 int debug_callback_defined(int i)
77 {
78 printf ("callback_defined(%s)\n", callbacknames[i]);
79 return callback_set[i];
80 }
81
get_lua_boolean(const char * table,const char * name,boolean * target)82 void get_lua_boolean(const char *table, const char *name, boolean * target)
83 {
84 int stacktop;
85 stacktop = lua_gettop(Luas);
86 luaL_checkstack(Luas, 2, "out of stack space");
87 lua_getglobal(Luas, table);
88 if (lua_istable(Luas, -1)) {
89 lua_getfield(Luas, -1, name);
90 if (lua_isboolean(Luas, -1)) {
91 *target = (boolean) (lua_toboolean(Luas, -1));
92 } else if (lua_isnumber(Luas, -1)) {
93 *target = (boolean) (lua_tonumber(Luas, -1) == 0 ? 0 : 1);
94 }
95 }
96 lua_settop(Luas, stacktop);
97 return;
98 }
99
get_saved_lua_boolean(int r,const char * name,boolean * target)100 void get_saved_lua_boolean(int r, const char *name, boolean * target)
101 {
102 int stacktop;
103 stacktop = lua_gettop(Luas);
104 luaL_checkstack(Luas, 2, "out of stack space");
105 lua_rawgeti(Luas, LUA_REGISTRYINDEX, r);
106 if (lua_istable(Luas, -1)) {
107 lua_getfield(Luas, -1, name);
108 if (lua_isboolean(Luas, -1)) {
109 *target = (boolean) lua_toboolean(Luas, -1);
110 } else if (lua_isnumber(Luas, -1)) {
111 *target = (boolean) (lua_tonumber(Luas, -1) == 0 ? 0 : 1);
112 }
113 }
114 lua_settop(Luas, stacktop);
115 return;
116 }
117
get_lua_number(const char * table,const char * name,int * target)118 void get_lua_number(const char *table, const char *name, int *target)
119 {
120 int stacktop;
121 stacktop = lua_gettop(Luas);
122 luaL_checkstack(Luas, 2, "out of stack space");
123 lua_getglobal(Luas, table);
124 if (lua_istable(Luas, -1)) {
125 lua_getfield(Luas, -1, name);
126 if (lua_isnumber(Luas, -1)) {
127 *target = (int)lua_tonumber(Luas, -1);
128 }
129 }
130 lua_settop(Luas, stacktop);
131 return;
132 }
133
get_saved_lua_number(int r,const char * name,int * target)134 void get_saved_lua_number(int r, const char *name, int *target)
135 {
136 int stacktop;
137 stacktop = lua_gettop(Luas);
138 luaL_checkstack(Luas, 2, "out of stack space");
139 lua_rawgeti(Luas, LUA_REGISTRYINDEX, r);
140 if (lua_istable(Luas, -1)) {
141 lua_getfield(Luas, -1, name);
142 if (lua_isnumber(Luas, -1)) {
143 *target=(int)lua_tonumber(Luas, -1);
144 }
145 }
146 lua_settop(Luas, stacktop);
147 return;
148 }
149
150
get_lua_string(const char * table,const char * name,char ** target)151 void get_lua_string(const char *table, const char *name, char **target)
152 {
153 int stacktop;
154 stacktop = lua_gettop(Luas);
155 luaL_checkstack(Luas, 2, "out of stack space");
156 lua_getglobal(Luas, table);
157 if (lua_istable(Luas, -1)) {
158 lua_getfield(Luas, -1, name);
159 if (lua_isstring(Luas, -1)) {
160 *target = xstrdup(lua_tostring(Luas, -1));
161 }
162 }
163 lua_settop(Luas, stacktop);
164 return;
165 }
166
get_saved_lua_string(int r,const char * name,char ** target)167 void get_saved_lua_string(int r, const char *name, char **target)
168 {
169 int stacktop;
170 stacktop = lua_gettop(Luas);
171 luaL_checkstack(Luas, 2, "out of stack space");
172 lua_rawgeti(Luas, LUA_REGISTRYINDEX, r);
173 if (lua_istable(Luas, -1)) {
174 lua_getfield(Luas, -1, name);
175 if (lua_isstring(Luas, -1)) {
176 *target = xstrdup(lua_tostring(Luas, -1));
177 }
178 }
179 lua_settop(Luas, stacktop);
180 return;
181 }
182
183
184 #define CALLBACK_BOOLEAN 'b'
185 #define CALLBACK_INTEGER 'd'
186 #define CALLBACK_LINE 'l'
187 #define CALLBACK_STRNUMBER 's'
188 #define CALLBACK_STRING 'S'
189 #define CALLBACK_CHARNUM 'c'
190 #define CALLBACK_LSTRING 'L'
191
192
run_saved_callback(int r,const char * name,const char * values,...)193 int run_saved_callback(int r, const char *name, const char *values, ...)
194 {
195 va_list args;
196 int ret = 0;
197 lua_State *L = Luas;
198 int stacktop = lua_gettop(L);
199 va_start(args, values);
200 luaL_checkstack(L, 2, "out of stack space");
201 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
202 lua_pushstring(L, name);
203 lua_rawget(L, -2);
204 if (lua_isfunction(L, -1)) {
205 saved_callback_count++;
206 callback_count++;
207 ret = do_run_callback(2, values, args);
208 }
209 va_end(args);
210 lua_settop(L, stacktop);
211 return ret;
212 }
213
214
get_callback(lua_State * L,int i)215 boolean get_callback(lua_State * L, int i)
216 {
217 luaL_checkstack(L, 2, "out of stack space");
218 lua_rawgeti(L, LUA_REGISTRYINDEX, callback_callbacks_id);
219 lua_rawgeti(L, -1, i);
220 if (lua_isfunction(L, -1)) {
221 callback_count++;
222 return true;
223 } else {
224 return false;
225 }
226 }
227
run_and_save_callback(int i,const char * values,...)228 int run_and_save_callback(int i, const char *values, ...)
229 {
230 va_list args;
231 int ret = 0;
232 lua_State *L = Luas;
233 int stacktop = lua_gettop(L);
234 va_start(args, values);
235 if (get_callback(L, i)) {
236 ret = do_run_callback(1, values, args);
237 }
238 va_end(args);
239 if (ret > 0) {
240 ret = luaL_ref(L, LUA_REGISTRYINDEX);
241 }
242 lua_settop(L, stacktop);
243 return ret;
244 }
245
246
run_callback(int i,const char * values,...)247 int run_callback(int i, const char *values, ...)
248 {
249 va_list args;
250 int ret = 0;
251 lua_State *L = Luas;
252 int stacktop = lua_gettop(L);
253 va_start(args, values);
254 if (get_callback(L, i)) {
255 ret = do_run_callback(0, values, args);
256 }
257 va_end(args);
258 lua_settop(L, stacktop);
259 return ret;
260 }
261
do_run_callback(int special,const char * values,va_list vl)262 int do_run_callback(int special, const char *values, va_list vl)
263 {
264 int ret;
265 size_t len;
266 int narg, nres;
267 const char *s;
268 lstring *lstr;
269 char cs;
270 int *bufloc;
271 char *ss = NULL;
272 int retval = 0;
273 lua_State *L = Luas;
274 if (special == 2) { /* copy the enclosing table */
275 luaL_checkstack(L, 1, "out of stack space");
276 lua_pushvalue(L, -2);
277 }
278 ss = strchr(values, '>');
279 assert(ss);
280 luaL_checkstack(L, (int) (ss - values + 1), "out of stack space");
281 ss = NULL;
282 for (narg = 0; *values; narg++) {
283 switch (*values++) {
284 case CALLBACK_CHARNUM: /* an ascii char! */
285 cs = (char) va_arg(vl, int);
286 lua_pushlstring(L, &cs, 1);
287 break;
288 case CALLBACK_STRING: /* C string */
289 s = va_arg(vl, char *);
290 lua_pushstring(L, s);
291 break;
292 case CALLBACK_LSTRING: /* 'lstring' */
293 lstr = va_arg(vl, lstring *);
294 lua_pushlstring(L, (const char *)lstr->s, lstr->l);
295 break;
296 case CALLBACK_INTEGER: /* int */
297 lua_pushnumber(L, va_arg(vl, int));
298 break;
299 case CALLBACK_STRNUMBER: /* TeX string */
300 s = makeclstring(va_arg(vl, int), &len);
301 lua_pushlstring(L, s, len);
302 break;
303 case CALLBACK_BOOLEAN: /* boolean */
304 lua_pushboolean(L, va_arg(vl, int));
305 break;
306 case CALLBACK_LINE: /* a buffer section, with implied start */
307 lua_pushlstring(L, (char *) (buffer + first),
308 (size_t) va_arg(vl, int));
309 break;
310 case '-':
311 narg--;
312 break;
313 case '>':
314 goto ENDARGS;
315 default:
316 ;
317 }
318 }
319 ENDARGS:
320 nres = (int) strlen(values);
321 if (special == 1) {
322 nres++;
323 }
324 if (special == 2) {
325 narg++;
326 }
327 {
328 int i;
329 lua_active++;
330 i = lua_pcall(L, narg, nres, 0);
331 lua_active--;
332 /* lua_remove(L, base); *//* remove traceback function */
333 if (i != 0) {
334 /* Can't be more precise here, could be called before
335 * TeX initialization is complete
336 */
337 if (!log_opened_global) {
338 fprintf(stderr, "This went wrong: %s\n", lua_tostring(L, -1));
339 error();
340 } else {
341 lua_gc(L, LUA_GCCOLLECT, 0);
342 luatex_error(L, (i == LUA_ERRRUN ? 0 : 1));
343 }
344 return 0;
345 }
346 }
347 if (nres == 0) {
348 return 1;
349 }
350 nres = -nres;
351 while (*values) {
352 int b;
353 switch (*values++) {
354 case CALLBACK_BOOLEAN:
355 if (!lua_isboolean(L, nres)) {
356 fprintf(stderr, "Expected a boolean, not: %s\n",
357 lua_typename(L, lua_type(L, nres)));
358 goto EXIT;
359 }
360 b = lua_toboolean(L, nres);
361 *va_arg(vl, boolean *) = (boolean) b;
362 break;
363 case CALLBACK_INTEGER:
364 if (!lua_isnumber(L, nres)) {
365 fprintf(stderr, "Expected a number, not: %s\n",
366 lua_typename(L, lua_type(L, nres)));
367 goto EXIT;
368 }
369 b=(int)lua_tonumber(L, nres);
370 *va_arg(vl, int *) = b;
371 break;
372 case CALLBACK_LINE: /* TeX line */
373 if (!lua_isstring(L, nres)) {
374 if (!lua_isnil(L, nres))
375 fprintf(stderr, "Expected a string for (l), not: %s\n",
376 lua_typename(L, lua_type(L, nres)));
377 goto EXIT;
378 }
379 s = lua_tolstring(L, nres, &len);
380 if (s != NULL) { /* |len| can be zero */
381 bufloc = va_arg(vl, int *);
382 if (len != 0) {
383 ret = *bufloc;
384 check_buffer_overflow(ret + (int) len);
385 strncpy((char *) (buffer + ret), s, len);
386 *bufloc += (int) len;
387 /* while (len--) { buffer[(*bufloc)++] = *s++; } */
388 while ((*bufloc) - 1 > ret && buffer[(*bufloc) - 1] == ' ')
389 (*bufloc)--;
390 }
391 } else {
392 bufloc = 0;
393 }
394 break;
395 case CALLBACK_STRNUMBER: /* TeX string */
396 if (!lua_isstring(L, nres)) {
397 if (!lua_isnil(L, nres)) {
398 fprintf(stderr, "Expected a string for (s), not: %s\n",
399 lua_typename(L, lua_type(L, nres)));
400 goto EXIT;
401 }
402 }
403 s = lua_tolstring(L, nres, &len);
404 if (s == NULL) /* |len| can be zero */
405 *va_arg(vl, int *) = 0;
406 else {
407 *va_arg(vl, int *) = maketexlstring(s, len);
408 }
409 break;
410 case CALLBACK_STRING: /* C string aka buffer */
411 if (!lua_isstring(L, nres)) {
412 if (!lua_isnil(L, nres)) {
413 fprintf(stderr, "Expected a string for (S), not: %s\n",
414 lua_typename(L, lua_type(L, nres)));
415 goto EXIT;
416 }
417 }
418 s = lua_tolstring(L, nres, &len);
419
420 if (s == NULL) /* |len| can be zero */
421 *va_arg(vl, int *) = 0;
422 else {
423 ss = xmalloc((unsigned) (len + 1));
424 (void) memcpy(ss, s, (len + 1));
425 *va_arg(vl, char **) = ss;
426 }
427 break;
428 case CALLBACK_LSTRING: /* lstring */
429 if (!lua_isstring(L, nres)) {
430 if (!lua_isnil(L, nres)) {
431 fprintf(stderr, "Expected a string for (S), not: %s\n",
432 lua_typename(L, lua_type(L, nres)));
433 goto EXIT;
434 }
435 }
436 s = lua_tolstring(L, nres, &len);
437
438 if (s == NULL) /* |len| can be zero */
439 *va_arg(vl, int *) = 0;
440 else {
441 lstring *ret = xmalloc(sizeof(lstring));
442 ret->s = xmalloc((unsigned) (len + 1));
443 (void) memcpy(ret->s, s, (len + 1));
444 ret->l = len;
445 *va_arg(vl, lstring **) = ret;
446 }
447 break;
448 default:
449 fprintf(stdout, "invalid return value type");
450 goto EXIT;
451 }
452 nres++;
453 }
454 retval = 1;
455 EXIT:
456 return retval;
457 }
458
destroy_saved_callback(int i)459 void destroy_saved_callback(int i)
460 {
461 luaL_unref(Luas, LUA_REGISTRYINDEX, i);
462 }
463
callback_register(lua_State * L)464 static int callback_register(lua_State * L)
465 {
466 int cb;
467 const char *s;
468 if (!lua_isstring(L, 1) ||
469 ((!lua_isfunction(L, 2)) &&
470 (!lua_isnil(L, 2)) &&
471 (!(lua_isboolean(L, 2) && lua_toboolean(L, 2) == 0)))) {
472 lua_pushnil(L);
473 lua_pushstring(L, "Invalid arguments to callback.register.");
474 return 2;
475 }
476 s = lua_tostring(L, 1);
477 for (cb = 0; cb < total_callbacks; cb++) {
478 if (strcmp(callbacknames[cb], s) == 0)
479 break;
480 }
481 if (cb == total_callbacks) {
482 lua_pushnil(L);
483 lua_pushstring(L, "No such callback exists.");
484 return 2;
485 }
486 if (lua_isfunction(L, 2)) {
487 callback_set[cb] = cb;
488 } else if (lua_isboolean(L, 2)) {
489 callback_set[cb] = -1;
490 } else {
491 callback_set[cb] = 0;
492 }
493 luaL_checkstack(L, 2, "out of stack space");
494 lua_rawgeti(L, LUA_REGISTRYINDEX, callback_callbacks_id); /* push the table */
495 lua_pushvalue(L, 2); /* the function or nil */
496 lua_rawseti(L, -2, cb);
497 lua_rawseti(L, LUA_REGISTRYINDEX, callback_callbacks_id);
498 lua_pushnumber(L, cb);
499 return 1;
500 }
501
callback_find(lua_State * L)502 static int callback_find(lua_State * L)
503 {
504 int cb;
505 const char *s;
506 if (!lua_isstring(L, 1)) {
507 lua_pushnil(L);
508 lua_pushstring(L, "Invalid arguments to callback.find.");
509 return 2;
510 }
511 s = lua_tostring(L, 1);
512 for (cb = 0; cb < total_callbacks; cb++) {
513 if (strcmp(callbacknames[cb], s) == 0)
514 break;
515 }
516 if (cb == total_callbacks) {
517 lua_pushnil(L);
518 lua_pushstring(L, "No such callback exists.");
519 return 2;
520 }
521 luaL_checkstack(L, 2, "out of stack space");
522 lua_rawgeti(L, LUA_REGISTRYINDEX, callback_callbacks_id); /* push the table */
523 lua_rawgeti(L, -1, cb);
524 return 1;
525 }
526
527
callback_listf(lua_State * L)528 static int callback_listf(lua_State * L)
529 {
530 int i;
531 luaL_checkstack(L, 3, "out of stack space");
532 lua_newtable(L);
533 for (i = 1; callbacknames[i]; i++) {
534 lua_pushstring(L, callbacknames[i]);
535 if (callback_defined(i)) {
536 lua_pushboolean(L, 1);
537 } else {
538 lua_pushboolean(L, 0);
539 }
540 lua_rawset(L, -3);
541 }
542 return 1;
543 }
544
545 static const struct luaL_Reg callbacklib[] = {
546 {"find", callback_find},
547 {"register", callback_register},
548 {"list", callback_listf},
549 {NULL, NULL} /* sentinel */
550 };
551
luaopen_callback(lua_State * L)552 int luaopen_callback(lua_State * L)
553 {
554 luaL_register(L, "callback", callbacklib);
555 luaL_checkstack(L, 1, "out of stack space");
556 lua_newtable(L);
557 callback_callbacks_id = luaL_ref(L, LUA_REGISTRYINDEX);
558 return 1;
559 }
560