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