1 /* lstatslib.c
2 
3    Copyright 2006-2011 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 
21 #include "ptexlib.h"
22 #include "lua/luatex-api.h"
23 
24 typedef struct statistic {
25     const char *name;
26     char type;
27     void *value;
28 } statistic;
29 
30 typedef const char *(*charfunc) (void);
31 typedef lua_Number(*numfunc) (void);
32 typedef int (*intfunc) (void);
33 
34 const char *last_lua_error;
35 
getbanner(void)36 static const char *getbanner(void)
37 {
38     return (const char *) luatex_banner;
39 }
40 
getlogname(void)41 static const char *getlogname(void)
42 {
43     return (const char *) texmf_log_name;
44 }
45 
46 /* Obsolete in 0.80.0                         */
47 /* static const char *get_pdftex_banner(void) */
48 /* { */
49 /*     return (const char *) pdftex_banner; */
50 /* } */
51 
get_output_file_name(void)52 static const char *get_output_file_name(void)
53 {
54     if (static_pdf != NULL)
55         return (const char *) static_pdf->file_name;
56     return NULL;
57 }
58 
getfilename(void)59 static const char *getfilename(void)
60 {
61     int t = 0;
62     int level = in_open;
63     while ((level > 0)) {
64         t = input_stack[level--].name_field;
65         if (t >= STRING_OFFSET)
66             return (const char *) str_string(t);
67     }
68     return "";
69 }
70 
getlasterror(void)71 static const char *getlasterror(void)
72 {
73     return last_error;
74 }
75 
getlastluaerror(void)76 static const char *getlastluaerror(void)
77 {
78     return last_lua_error;
79 }
80 
81 
82 
luatexrevision(void)83 static const char *luatexrevision(void)
84 {
85     return (const char *) (strrchr(luatex_version_string, '.') + 1);
86 }
87 
get_luatexhashchars(void)88 static lua_Number get_luatexhashchars(void)
89 {
90   return (lua_Number) LUAI_HASHLIMIT;
91 }
92 
get_luatexhashtype(void)93 static const char *get_luatexhashtype(void)
94 {
95 #ifdef LuajitTeX
96      return (const char *)jithash_hashname;
97 #else
98   return "lua";
99 #endif
100 }
101 
102 
get_pdf_gone(void)103 static lua_Number get_pdf_gone(void)
104 {
105     if (static_pdf != NULL)
106         return (lua_Number) static_pdf->gone;
107     return (lua_Number) 0;
108 }
109 
get_pdf_ptr(void)110 static lua_Number get_pdf_ptr(void)
111 {
112     if (static_pdf != NULL)
113         return (lua_Number) (static_pdf->buf->p - static_pdf->buf->data);
114     return (lua_Number) 0;
115 }
116 
get_pdf_os_cntr(void)117 static lua_Number get_pdf_os_cntr(void)
118 {
119     if (static_pdf != NULL)
120         return (lua_Number) static_pdf->os->ostm_ctr;
121     return (lua_Number) 0;
122 }
123 
get_pdf_os_objidx(void)124 static lua_Number get_pdf_os_objidx(void)
125 {
126     if (static_pdf != NULL)
127         return (lua_Number) static_pdf->os->idx;
128     return (lua_Number) 0;
129 }
130 
get_pdf_mem_size(void)131 static lua_Number get_pdf_mem_size(void)
132 {
133     if (static_pdf != NULL)
134         return (lua_Number) static_pdf->mem_size;
135     return (lua_Number) 0;
136 }
137 
get_pdf_mem_ptr(void)138 static lua_Number get_pdf_mem_ptr(void)
139 {
140     if (static_pdf != NULL)
141         return (lua_Number) static_pdf->mem_ptr;
142     return (lua_Number) 0;
143 }
144 
145 
get_obj_ptr(void)146 static lua_Number get_obj_ptr(void)
147 {
148     if (static_pdf != NULL)
149         return (lua_Number) static_pdf->obj_ptr;
150     return (lua_Number) 0;
151 }
152 
get_obj_tab_size(void)153 static lua_Number get_obj_tab_size(void)
154 {
155     if (static_pdf != NULL)
156         return (lua_Number) static_pdf->obj_tab_size;
157     return (lua_Number) 0;
158 }
159 
get_dest_names_size(void)160 static lua_Number get_dest_names_size(void)
161 {
162     if (static_pdf != NULL)
163         return (lua_Number) static_pdf->dest_names_size;
164     return (lua_Number) 0;
165 }
166 
get_dest_names_ptr(void)167 static lua_Number get_dest_names_ptr(void)
168 {
169     if (static_pdf != NULL)
170         return (lua_Number) static_pdf->dest_names_ptr;
171     return (lua_Number) 0;
172 }
173 
get_hash_size(void)174 static int get_hash_size(void)
175 {
176     return hash_size;           /* is a #define */
177 }
178 
179 static int luastate_max = 1;    /* fixed value */
180 
181 /* temp, for backward compat */
182 static int init_pool_ptr = 0;
183 
184 static struct statistic stats[] = {
185 
186     /* most likely accessed */
187 
188     {"output_active", 'b', &output_active},
189     {"best_page_break", 'n', &best_page_break},
190 
191     {"filename", 'S', (void *) &getfilename},
192     {"inputid", 'g', &(iname)},
193     {"linenumber", 'g', &line},
194 
195     {"lasterrorstring", 'S', (void *) &getlasterror},
196     {"lastluaerrorstring", 'S', (void *) &getlastluaerror},
197 
198     /* seldom or never accessed */
199 
200     {"pdf_gone", 'N', &get_pdf_gone},
201     {"pdf_ptr", 'N', &get_pdf_ptr},
202     {"dvi_gone", 'g', &dvi_offset},
203     {"dvi_ptr", 'g', &dvi_ptr},
204     {"total_pages", 'g', &total_pages},
205     {"output_file_name", 'S', (void *) &get_output_file_name},
206     {"log_name", 'S', (void *) &getlogname},
207     {"banner", 'S', (void *) &getbanner},
208     {"pdftex_banner", 'S', (void *) &getbanner},
209     {"luatex_svn", 'G', &get_luatexsvn},
210     {"luatex_version", 'G', &get_luatexversion},
211     {"luatex_revision", 'S', (void *) &luatexrevision},
212     {"luatex_hashtype", 'S', (void *) &get_luatexhashtype},
213     {"luatex_hashchars", 'N',  &get_luatexhashchars},
214 
215     {"ini_version", 'b', &ini_version},
216     /*
217      * mem stat
218      */
219     {"var_used", 'g', &var_used},
220     {"dyn_used", 'g', &dyn_used},
221     /*
222      * traditional tex stats
223      */
224     {"str_ptr", 'g', &str_ptr},
225     {"init_str_ptr", 'g', &init_str_ptr},
226     {"max_strings", 'g', &max_strings},
227     {"pool_ptr", 'g', &pool_size},
228     {"init_pool_ptr", 'g', &init_pool_ptr},
229     {"pool_size", 'g', &pool_size},
230     {"var_mem_max", 'g', &var_mem_max},
231     {"node_mem_usage", 'S', &sprint_node_mem_usage},
232     {"fix_mem_max", 'g', &fix_mem_max},
233     {"fix_mem_min", 'g', &fix_mem_min},
234     {"fix_mem_end", 'g', &fix_mem_end},
235     {"cs_count", 'g', &cs_count},
236     {"hash_size", 'G', &get_hash_size},
237     {"hash_extra", 'g', &hash_extra},
238     {"font_ptr", 'G', &max_font_id},
239     {"max_in_stack", 'g', &max_in_stack},
240     {"max_nest_stack", 'g', &max_nest_stack},
241     {"max_param_stack", 'g', &max_param_stack},
242     {"max_buf_stack", 'g', &max_buf_stack},
243     {"max_save_stack", 'g', &max_save_stack},
244     {"stack_size", 'g', &stack_size},
245     {"nest_size", 'g', &nest_size},
246     {"param_size", 'g', &param_size},
247     {"buf_size", 'g', &buf_size},
248     {"save_size", 'g', &save_size},
249     /* pdf stats */
250     {"obj_ptr", 'N', &get_obj_ptr},
251     {"obj_tab_size", 'N', &get_obj_tab_size},
252     {"pdf_os_cntr", 'N', &get_pdf_os_cntr},
253     {"pdf_os_objidx", 'N', &get_pdf_os_objidx},
254     {"pdf_dest_names_ptr", 'N', &get_dest_names_ptr},
255     {"dest_names_size", 'N', &get_dest_names_size},
256     {"pdf_mem_ptr", 'N', &get_pdf_mem_ptr},
257     {"pdf_mem_size", 'N', &get_pdf_mem_size},
258 
259     {"largest_used_mark", 'g', &biggest_used_mark},
260 
261     {"luabytecodes", 'g', &luabytecode_max},
262     {"luabytecode_bytes", 'g', &luabytecode_bytes},
263     {"luastates", 'g', &luastate_max},
264     {"luastate_bytes", 'g', &luastate_bytes},
265     {"callbacks", 'g', &callback_count},
266     {"indirect_callbacks", 'g', &saved_callback_count},
267 
268     {NULL, 0, 0}
269 };
270 
stats_name_to_id(const char * name)271 static int stats_name_to_id(const char *name)
272 {
273     int i;
274     for (i = 0; stats[i].name != NULL; i++) {
275         if (strcmp(stats[i].name, name) == 0)
276             return i;
277     }
278     return -1;
279 }
280 
do_getstat(lua_State * L,int i)281 static int do_getstat(lua_State * L, int i)
282 {
283     int t;
284     const char *st;
285     charfunc f;
286     intfunc g;
287     numfunc n;
288     int str;
289     t = stats[i].type;
290     switch (t) {
291     case 'S':
292         f = stats[i].value;
293         st = f();
294         lua_pushstring(L, st);
295         break;
296     case 's':
297         str = *(int *) (stats[i].value);
298         if (str) {
299             char *ss = makecstring(str);
300             lua_pushstring(L, ss);
301             free(ss);
302         } else {
303             lua_pushnil(L);
304         }
305         break;
306     case 'N':
307         n = stats[i].value;
308         lua_pushnumber(L, n());
309         break;
310     case 'G':
311         g = stats[i].value;
312         lua_pushnumber(L, g());
313         break;
314     case 'g':
315         lua_pushnumber(L, *(int *) (stats[i].value));
316         break;
317     case 'B':
318         g = stats[i].value;
319         lua_pushboolean(L, g());
320         break;
321     case 'n':
322         if (*(halfword *) (stats[i].value) != 0)
323             lua_nodelib_push_fast(L, *(halfword *) (stats[i].value));
324         else
325             lua_pushnil(L);
326         break;
327     case 'b':
328         lua_pushboolean(L, *(int *) (stats[i].value));
329         break;
330     default:
331         lua_pushnil(L);
332     }
333     return 1;
334 }
335 
getstats(lua_State * L)336 static int getstats(lua_State * L)
337 {
338     const char *st;
339     int i;
340     if (lua_isstring(L, -1)) {
341         st = lua_tostring(L, -1);
342         i = stats_name_to_id(st);
343         if (i >= 0) {
344             return do_getstat(L, i);
345         }
346     }
347     return 0;
348 }
349 
setstats(lua_State * L)350 static int setstats(lua_State * L)
351 {
352     (void) L;
353     return 0;
354 }
355 
statslist(lua_State * L)356 static int statslist(lua_State * L)
357 {
358     int i;
359     luaL_checkstack(L, 1, "out of stack space");
360     lua_newtable(L);
361     for (i = 0; stats[i].name != NULL; i++) {
362         luaL_checkstack(L, 2, "out of stack space");
363         lua_pushstring(L, stats[i].name);
364         do_getstat(L, i);
365         lua_rawset(L, -3);
366     }
367     return 1;
368 }
369 
370 
371 
372 static const struct luaL_Reg statslib[] = {
373     {"list", statslist},
374     {NULL, NULL}                /* sentinel */
375 };
376 
luaopen_stats(lua_State * L)377 int luaopen_stats(lua_State * L)
378 {
379     luaL_register(L, "status", statslib);
380     luaL_newmetatable(L, "tex.stats");
381     lua_pushstring(L, "__index");
382     lua_pushcfunction(L, getstats);
383     lua_settable(L, -3);
384     lua_pushstring(L, "__newindex");
385     lua_pushcfunction(L, setstats);
386     lua_settable(L, -3);
387     lua_setmetatable(L, -2);    /* meta to itself */
388     return 1;
389 }
390