3 Copyright 2006-2008 Taco Hoekwater <taco@luatex.org>
5 This file is part of LuaTeX.
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.
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.
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/>. */
29 # include <../lua51/lua.h>
30 # include <../lua51/lauxlib.h>
31 # include <../lua51/lualib.h>
36 #include "mppsout.h" /* for mp_edge_object */
38 static const char _svn_version[] =
39 "$Id: lmplib.c 1298 2008-05-28 14:08:27Z taco $ $URL: http://scm.foundry.supelec.fr/svn/luatex/trunk/src/texk/web2c/luatexdir/lua/lmplib.c $";
41 #define MPLIB_METATABLE "MPlib"
42 #define MPLIB_FIG_METATABLE "MPlib.fig"
43 #define MPLIB_GR_METATABLE "MPlib.gr"
45 #define mplib_init_S(a) do { \
46 lua_pushliteral(L,#a); \
47 mplib_##a##_ptr = (char *)lua_tostring(L,-1); \
48 mplib_##a##_index = luaL_ref (L,LUA_REGISTRYINDEX); \
51 #define mplib_push_S(a) do { \
52 lua_rawgeti(L,LUA_REGISTRYINDEX,mplib_##a##_index); \
55 #define mplib_is_S(a,i) (mplib_##a##_ptr==(char *)lua_tostring(L,i))
57 #define mplib_make_S(a) \
58 static int mplib_##a##_index = 0; \
59 static char *mplib_##a##_ptr = NULL
61 static int mplib_type_Ses[mp_special_code + 1] = { 0 }; /* [0] is not used */
64 mplib_make_S(outline);
66 mplib_make_S(special);
67 mplib_make_S(start_bounds);
68 mplib_make_S(stop_bounds);
69 mplib_make_S(start_clip);
70 mplib_make_S(stop_clip);
72 mplib_make_S(left_type);
73 mplib_make_S(right_type);
74 mplib_make_S(x_coord);
75 mplib_make_S(y_coord);
78 mplib_make_S(right_x);
79 mplib_make_S(right_y);
88 mplib_make_S(linecap);
89 mplib_make_S(linejoin);
90 mplib_make_S(miterlimit);
93 mplib_make_S(postscript);
94 mplib_make_S(prescript);
95 mplib_make_S(transform);
99 void mplib_init_Ses(lua_State * L)
102 mplib_init_S(outline);
104 mplib_init_S(start_bounds);
105 mplib_init_S(stop_bounds);
106 mplib_init_S(start_clip);
107 mplib_init_S(stop_clip);
108 mplib_init_S(special);
110 mplib_type_Ses[mp_fill_code] = mplib_fill_index;
111 mplib_type_Ses[mp_stroked_code] = mplib_outline_index;
112 mplib_type_Ses[mp_text_code] = mplib_text_index;
113 mplib_type_Ses[mp_start_bounds_code] = mplib_start_bounds_index;
114 mplib_type_Ses[mp_stop_bounds_code] = mplib_stop_bounds_index;
115 mplib_type_Ses[mp_start_clip_code] = mplib_start_clip_index;
116 mplib_type_Ses[mp_stop_clip_code] = mplib_stop_clip_index;
117 mplib_type_Ses[mp_special_code] = mplib_special_index;
119 mplib_init_S(left_type);
120 mplib_init_S(right_type);
121 mplib_init_S(x_coord);
122 mplib_init_S(y_coord);
123 mplib_init_S(left_x);
124 mplib_init_S(left_y);
125 mplib_init_S(right_x);
126 mplib_init_S(right_y);
133 mplib_init_S(height);
135 mplib_init_S(linecap);
136 mplib_init_S(linejoin);
137 mplib_init_S(miterlimit);
140 mplib_init_S(postscript);
141 mplib_init_S(prescript);
142 mplib_init_S(transform);
150 #define xfree(A) if ((A)!=NULL) { free((A)); A = NULL; }
152 #define is_mp(L,b) (MP *)luaL_checkudata(L,b,MPLIB_METATABLE)
153 #define is_fig(L,b) (struct mp_edge_object **)luaL_checkudata(L,b,MPLIB_FIG_METATABLE)
154 #define is_gr_object(L,b) (struct mp_graphic_object **)luaL_checkudata(L,b,MPLIB_GR_METATABLE)
156 /* Enumeration string arrays */
158 static const char *interaction_options[] =
159 { "unknown", "batch", "nonstop", "scroll", "errorstop", NULL };
161 static const char *mplib_filetype_names[] =
162 { "term", "error", "mp", "log", "ps", "mem", "tfm", "map", "pfb", "enc",
165 /* only "endpoint" and "explicit" actually happen in paths,
166 as well as "open" in elliptical pens */
168 static const char *knot_type_enum[] =
169 { "endpoint", "explicit", "given", "curl", "open", "end_cycle" };
173 static const char *fill_fields[] =
174 { "type", "path", "htap", "pen", "color", "linejoin", "miterlimit",
175 "prescript", "postscript", NULL
178 static const char *stroked_fields[] =
179 { "type", "path", "pen", "color", "linejoin", "miterlimit", "linecap",
181 "prescript", "postscript", NULL
184 static const char *text_fields[] =
185 { "type", "text", "dsize", "font", "color", "width", "height", "depth",
187 "prescript", "postscript", NULL
190 static const char *special_fields[] = { "type", "prescript", NULL };
192 static const char *start_bounds_fields[] = { "type", "path", NULL };
194 static const char *start_clip_fields[] = { "type", "path", NULL };
196 static const char *stop_bounds_fields[] = { "type", NULL };
198 static const char *stop_clip_fields[] = { "type", NULL };
200 static const char *no_fields[] = { NULL };
203 P_ERROR_LINE, P_HALF_LINE, P_MAX_LINE, P_MAIN_MEMORY,
204 P_HASH_SIZE, P_HASH_PRIME, P_PARAM_SIZE, P_IN_OPEN, P_RANDOM_SEED,
205 P_INTERACTION, P_INI_VERSION, P_TROFF_MODE, P_PRINT_NAMES, P_MEM_NAME,
206 P_JOB_NAME, P_FIND_FILE, P__SENTINEL
210 const char *name; /* parameter name */
211 mplib_parm_idx idx; /* parameter index */
214 static mplib_parm_struct mplib_parms[] = {
215 {"error_line", P_ERROR_LINE},
216 {"half_error_line", P_HALF_LINE},
217 {"max_print_line", P_MAX_LINE},
218 {"main_memory", P_MAIN_MEMORY},
219 {"hash_size", P_HASH_SIZE},
220 {"hash_prime", P_HASH_PRIME},
221 {"param_size", P_PARAM_SIZE},
222 {"max_in_open", P_IN_OPEN},
223 {"random_seed", P_RANDOM_SEED},
224 {"interaction", P_INTERACTION},
225 {"ini_version", P_INI_VERSION},
226 {"troff_mode", P_TROFF_MODE},
227 {"print_found_names", P_PRINT_NAMES},
228 {"mem_name", P_MEM_NAME},
229 {"job_name", P_JOB_NAME},
230 {"find_file", P_FIND_FILE},
234 typedef struct _FILE_ITEM {
238 typedef struct _FILE_ITEM File;
240 #define make_stream_buf(A) char *A; size_t A##_size; size_t A##_used
242 #define free_stream_buf(A) xfree(mplib_data->A); mplib_data->A##_size = 0; mplib_data->A##_used = 0
244 typedef struct _MPLIB_INSTANCE_DATA {
249 make_stream_buf(term_out);
250 make_stream_buf(error_out);
251 make_stream_buf(log_out);
252 make_stream_buf(ps_out);
254 char *input_data_ptr;
255 size_t input_data_len;
256 struct mp_edge_object *edges;
258 } _MPLIB_INSTANCE_DATA;
260 typedef struct _MPLIB_INSTANCE_DATA mplib_instance;
262 static mplib_instance *mplib_get_data(MP mp)
264 return (mplib_instance *) mp->userdata;
267 static mplib_instance *mplib_make_data(void)
269 mplib_instance *mplib_data = malloc(sizeof(mplib_instance));
270 memset(mplib_data, 0, sizeof(mplib_instance));
275 /* Start by defining all the callback routines for the library
276 * except |run_make_mpx| and |run_editor|.
280 char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ftype)
282 mplib_instance *mplib_data = mplib_get_data(mp);
283 lua_State *L = mplib_data->LL;
284 lua_checkstack(L, 4);
285 lua_getfield(L, LUA_REGISTRYINDEX, "mplib_file_finder");
286 if (lua_isfunction(L, -1)) {
287 char *s = NULL, *x = NULL;
288 lua_pushstring(L, fname);
289 lua_pushstring(L, fmode);
290 if (ftype >= mp_filetype_text) {
291 lua_pushnumber(L, ftype - mp_filetype_text);
293 lua_pushstring(L, mplib_filetype_names[ftype]);
295 if (lua_pcall(L, 3, 1, 0) != 0) {
296 fprintf(stdout, "Error in mp.find_file: %s\n",
297 (char *) lua_tostring(L, -1));
300 x = (char *) lua_tostring(L, -1);
303 lua_pop(L, 1); /* pop the string */
308 if (fmode[0] != 'r' || (!access(fname, R_OK)) || ftype) {
309 return strdup(fname);
314 static int mplib_find_file_function(lua_State * L)
316 if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) {
317 return 1; /* error */
319 lua_pushstring(L, "mplib_file_finder");
320 lua_pushvalue(L, -2);
321 lua_rawset(L, LUA_REGISTRYINDEX);
325 void *mplib_open_file(MP mp, const char *fname, const char *fmode, int ftype)
327 File *ff = malloc(sizeof(File));
329 mplib_instance *mplib_data = mplib_get_data(mp);
331 if (ftype == mp_filetype_terminal) {
332 if (fmode[0] == 'r') {
335 xfree(mplib_data->term_file_ptr);
337 mplib_data->term_file_ptr = ff->f;
339 } else if (ftype == mp_filetype_error) {
340 xfree(mplib_data->err_file_ptr);
342 mplib_data->err_file_ptr = ff->f;
343 } else if (ftype == mp_filetype_log) {
344 xfree(mplib_data->log_file_ptr);
346 mplib_data->log_file_ptr = ff->f;
347 } else if (ftype == mp_filetype_postscript) {
348 xfree(mplib_data->ps_file_ptr);
350 mplib_data->ps_file_ptr = ff->f;
353 char *f = mplib_find_file(mp, fname, fmode, ftype);
356 realmode[0] = *fmode;
359 ff->f = fopen(f, realmode);
360 if ((fmode[0] == 'r') && (ff->f == NULL)) {
370 static int mplib_get_char(void *f, mplib_instance * mplib_data)
373 if (f == stdin && mplib_data->input_data != NULL) {
374 if (mplib_data->input_data_len == 0) {
375 if (mplib_data->input_data_ptr != NULL)
376 mplib_data->input_data_ptr = NULL;
378 mplib_data->input_data = NULL;
381 mplib_data->input_data_len--;
382 c = *(mplib_data->input_data_ptr)++;
390 static void mplib_unget_char(void *f, mplib_instance * mplib_data, int c)
392 if (f == stdin && mplib_data->input_data_ptr != NULL) {
393 mplib_data->input_data_len++;
394 mplib_data->input_data_ptr--;
401 char *mplib_read_ascii_file(MP mp, void *ff, size_t * size)
406 size_t len = 0, lim = 128;
407 mplib_instance *mplib_data = mplib_get_data(mp);
408 FILE *f = ((File *) ff)->f;
412 c = mplib_get_char(f, mplib_data);
418 while (c != EOF && c != '\n' && c != '\r') {
420 s = realloc(s, (lim + (lim >> 2)));
426 c = mplib_get_char(f, mplib_data);
429 c = mplib_get_char(f, mplib_data);
430 if (c != EOF && c != '\n')
431 mplib_unget_char(f, mplib_data, c);
439 #define APPEND_STRING(a,b) do { \
440 if ((mplib_data->a##_used+strlen(b))>=mplib_data->a##_size) { \
441 mplib_data->a##_size += 256+(mplib_data->a##_size)/5+strlen(b); \
442 mplib_data->a = realloc(mplib_data->a,mplib_data->a##_size); \
444 (void)strcpy(mplib_data->a+mplib_data->a##_used,b); \
445 mplib_data->a##_used += strlen(b); \
448 void mplib_write_ascii_file(MP mp, void *ff, const char *s)
451 void *f = ((File *) ff)->f;
452 mplib_instance *mplib_data = mplib_get_data(mp);
454 if (f == mplib_data->term_file_ptr) {
455 APPEND_STRING(term_out, s);
456 } else if (f == mplib_data->err_file_ptr) {
457 APPEND_STRING(error_out, s);
458 } else if (f == mplib_data->log_file_ptr) {
459 APPEND_STRING(log_out, s);
460 } else if (f == mplib_data->ps_file_ptr) {
461 APPEND_STRING(ps_out, s);
463 fprintf((FILE *) f, "%s", s);
469 void mplib_read_binary_file(MP mp, void *ff, void **data, size_t * size)
474 FILE *f = ((File *) ff)->f;
476 len = fread(*data, 1, *size, f);
481 void mplib_write_binary_file(MP mp, void *ff, void *s, size_t size)
485 FILE *f = ((File *) ff)->f;
487 fwrite(s, size, 1, f);
492 void mplib_close_file(MP mp, void *ff)
495 mplib_instance *mplib_data = mplib_get_data(mp);
496 void *f = ((File *) ff)->f;
497 if (f != NULL && f != mplib_data->term_file_ptr
498 && f != mplib_data->err_file_ptr && f != mplib_data->log_file_ptr
499 && f != mplib_data->ps_file_ptr) {
506 int mplib_eof_file(MP mp, void *ff)
509 mplib_instance *mplib_data = mplib_get_data(mp);
510 FILE *f = ((File *) ff)->f;
513 if (f == stdin && mplib_data->input_data != NULL) {
514 return (mplib_data->input_data_len == 0);
521 void mplib_flush_file(MP mp, void *ff)
528 #define APPEND_TO_EDGES(a) do { \
529 if (mplib_data->edges==NULL) { \
530 mplib_data->edges = hh; \
532 struct mp_edge_object *p = mplib_data->edges; \
533 while (p->_next!=NULL) { p = p->_next; } \
538 void mplib_shipout_backend(MP mp, int h)
540 struct mp_edge_object *hh = mp_gr_export(mp, h);
542 mplib_instance *mplib_data = mplib_get_data(mp);
548 static void mplib_setup_file_ops(struct MP_options *options)
550 options->find_file = mplib_find_file;
551 options->open_file = mplib_open_file;
552 options->close_file = mplib_close_file;
553 options->eof_file = mplib_eof_file;
554 options->flush_file = mplib_flush_file;
555 options->write_ascii_file = mplib_write_ascii_file;
556 options->read_ascii_file = mplib_read_ascii_file;
557 options->write_binary_file = mplib_write_binary_file;
558 options->read_binary_file = mplib_read_binary_file;
559 options->shipout_backend = mplib_shipout_backend;
562 static int mplib_new(lua_State * L)
565 mp_ptr = lua_newuserdata(L, sizeof(MP *));
568 mplib_instance *mplib_data;
569 struct MP_options *options; /* instance options */
570 options = mp_options();
571 mplib_setup_file_ops(options);
572 mplib_data = mplib_make_data();
574 options->userdata = (void *) mplib_data;
575 options->noninteractive = 1; /* required ! */
576 options->print_found_names = 0;
577 if (lua_type(L, 1) == LUA_TTABLE) {
578 for (i = 0; mplib_parms[i].name != NULL; i++) {
579 lua_getfield(L, 1, mplib_parms[i].name);
580 if (lua_isnil(L, -1)) {
582 continue; /* skip unset */
584 switch (mplib_parms[i].idx) {
586 options->error_line = lua_tointeger(L, -1);
589 options->half_error_line = lua_tointeger(L, -1);
592 options->max_print_line = lua_tointeger(L, -1);
595 options->main_memory = lua_tointeger(L, -1);
598 options->hash_size = lua_tointeger(L, -1);
601 options->hash_prime = lua_tointeger(L, -1);
604 options->param_size = lua_tointeger(L, -1);
607 options->max_in_open = lua_tointeger(L, -1);
610 options->random_seed = lua_tointeger(L, -1);
613 options->interaction =
614 luaL_checkoption(L, -1, "errorstopmode",
615 interaction_options);
618 options->ini_version = lua_toboolean(L, -1);
621 options->troff_mode = lua_toboolean(L, -1);
624 options->print_found_names = lua_toboolean(L, -1);
628 options->command_line = strdup((char *)lua_tostring(L,-1));
632 options->mem_name = strdup((char *) lua_tostring(L, -1));
635 options->job_name = strdup((char *) lua_tostring(L, -1));
638 if (mplib_find_file_function(L)) { /* error here */
640 "Invalid arguments to mp.new({find_file=...})\n");
649 *mp_ptr = mp_new(options);
650 xfree(options->command_line);
651 xfree(options->mem_name);
652 xfree(options->job_name);
655 luaL_getmetatable(L, MPLIB_METATABLE);
656 lua_setmetatable(L, -2);
664 static int mplib_collect(lua_State * L)
666 MP *mp_ptr = is_mp(L, 1);
667 if (*mp_ptr != NULL) {
674 static int mplib_tostring(lua_State * L)
676 MP *mp_ptr = is_mp(L, 1);
677 if (*mp_ptr != NULL) {
678 lua_pushfstring(L, "<MP %p>", *mp_ptr);
684 static int mplib_wrapresults(lua_State * L, mplib_instance * mplib_data, int h)
686 lua_checkstack(L, 5);
688 if (mplib_data->term_out != NULL) {
689 lua_pushstring(L, mplib_data->term_out);
690 lua_setfield(L, -2, "term");
691 free_stream_buf(term_out);
693 if (mplib_data->error_out != NULL) {
694 lua_pushstring(L, mplib_data->error_out);
695 lua_setfield(L, -2, "error");
696 free_stream_buf(error_out);
698 if (mplib_data->log_out != NULL) {
699 lua_pushstring(L, mplib_data->log_out);
700 lua_setfield(L, -2, "log");
701 free_stream_buf(log_out);
703 if (mplib_data->edges != NULL) {
704 struct mp_edge_object **v;
705 struct mp_edge_object *p = mplib_data->edges;
709 v = lua_newuserdata(L, sizeof(struct mp_edge_object *));
711 luaL_getmetatable(L, MPLIB_FIG_METATABLE);
712 lua_setmetatable(L, -2);
713 lua_rawseti(L, -2, i);
717 lua_setfield(L, -2, "fig");
718 mplib_data->edges = NULL;
720 lua_pushnumber(L, h);
721 lua_setfield(L, -2, "status");
725 static int mplib_execute(lua_State * L)
727 MP *mp_ptr = is_mp(L, 1);
728 if (*mp_ptr != NULL && lua_isstring(L, 2)) {
730 mplib_instance *mplib_data = mplib_get_data(*mp_ptr);
731 mplib_data->input_data =
732 (char *) lua_tolstring(L, 2, &(mplib_data->input_data_len));
733 mplib_data->input_data_ptr = mplib_data->input_data;
734 if ((*mp_ptr)->run_state == 0) {
735 h = mp_initialize(*mp_ptr);
737 h = mp_execute(*mp_ptr);
738 if (mplib_data->input_data_len != 0) {
739 mplib_data->input_data = NULL;
740 mplib_data->input_data_ptr = NULL;
741 mplib_data->input_data_len = 0;
743 return mplib_wrapresults(L, mplib_data, h);
750 static int mplib_finish(lua_State * L)
752 MP *mp_ptr = is_mp(L, 1);
753 if (*mp_ptr != NULL) {
754 mplib_instance *mplib_data = mplib_get_data(*mp_ptr);
755 int h = mp_finish(*mp_ptr);
758 return mplib_wrapresults(L, mplib_data, h);
765 static int mplib_statistics(lua_State * L)
767 MP *mp_ptr = is_mp(L, 1);
768 if (*mp_ptr != NULL) {
770 lua_pushnumber(L, mp_memory_usage(*mp_ptr));
771 lua_setfield(L, -2, "main_memory");
772 lua_pushnumber(L, mp_hash_usage(*mp_ptr));
773 lua_setfield(L, -2, "hash_size");
774 lua_pushnumber(L, mp_param_usage(*mp_ptr));
775 lua_setfield(L, -2, "param_size");
776 lua_pushnumber(L, mp_open_usage(*mp_ptr));
777 lua_setfield(L, -2, "max_in_open");
787 static int mplib_fig_collect(lua_State * L)
789 struct mp_edge_object **hh = is_fig(L, 1);
791 mp_gr_toss_objects(*hh);
797 static int mplib_fig_body(lua_State * L)
800 struct mp_graphic_object **v;
801 struct mp_graphic_object *p;
802 struct mp_edge_object **hh = is_fig(L, 1);
806 v = lua_newuserdata(L, sizeof(struct mp_graphic_object *));
808 luaL_getmetatable(L, MPLIB_GR_METATABLE);
809 lua_setmetatable(L, -2);
810 lua_rawseti(L, -2, i);
814 (*hh)->body = NULL; /* prevent double free */
818 static int mplib_fig_copy_body(lua_State * L)
821 struct mp_graphic_object **v;
822 struct mp_graphic_object *p;
823 struct mp_edge_object **hh = is_fig(L, 1);
827 v = lua_newuserdata(L, sizeof(struct mp_graphic_object *));
828 *v = mp_gr_copy_object((*hh)->_parent, p);
829 luaL_getmetatable(L, MPLIB_GR_METATABLE);
830 lua_setmetatable(L, -2);
831 lua_rawseti(L, -2, i);
839 static int mplib_fig_tostring(lua_State * L)
841 struct mp_edge_object **hh = is_fig(L, 1);
842 lua_pushfstring(L, "<figure %p>", *hh);
849 mp_wrapped_shipout(struct mp_edge_object *hh, int prologues, int procset)
852 if (setjmp(mp->jump_buf)) {
855 mp_gr_ship_out(hh, prologues, procset);
859 static int mplib_fig_postscript(lua_State * L)
861 struct mp_edge_object **hh = is_fig(L, 1);
862 int prologues = luaL_optnumber(L, 2, -1);
863 int procset = luaL_optnumber(L, 3, -1);
864 mplib_instance *mplib_data = mplib_get_data((*hh)->_parent);
865 if (mplib_data->ps_out == NULL) {
866 if (mp_wrapped_shipout(*hh, prologues, procset)) {
867 if (mplib_data->ps_out != NULL) {
868 lua_pushstring(L, mplib_data->ps_out);
869 free_stream_buf(ps_out);
876 lua_pushstring(L, mplib_data->log_out);
877 xfree(mplib_data->ps_out);
885 static int mplib_fig_filename(lua_State * L)
887 struct mp_edge_object **hh = is_fig(L, 1);
889 char *s = (*hh)->_filename;
890 lua_pushstring(L, s);
898 static int mplib_fig_bb(lua_State * L)
900 struct mp_edge_object **hh = is_fig(L, 1);
902 lua_pushnumber(L, (double) (*hh)->_minx / 65536.0);
903 lua_rawseti(L, -2, 1);
904 lua_pushnumber(L, (double) (*hh)->_miny / 65536.0);
905 lua_rawseti(L, -2, 2);
906 lua_pushnumber(L, (double) (*hh)->_maxx / 65536.0);
907 lua_rawseti(L, -2, 3);
908 lua_pushnumber(L, (double) (*hh)->_maxy / 65536.0);
909 lua_rawseti(L, -2, 4);
915 static int mplib_gr_collect(lua_State * L)
917 struct mp_graphic_object **hh = is_gr_object(L, 1);
919 mp_gr_toss_object(*hh);
925 static int mplib_gr_tostring(lua_State * L)
927 struct mp_graphic_object **hh = is_gr_object(L, 1);
928 lua_pushfstring(L, "<object %p>", *hh);
933 static int mplib_gr_fields(lua_State * L)
937 struct mp_graphic_object **hh = is_gr_object(L, 1);
939 switch ((*hh)->_type_field) {
941 fields = fill_fields;
943 case mp_stroked_code:
944 fields = stroked_fields;
947 fields = text_fields;
949 case mp_special_code:
950 fields = special_fields;
952 case mp_start_clip_code:
953 fields = start_clip_fields;
955 case mp_start_bounds_code:
956 fields = start_bounds_fields;
958 case mp_stop_clip_code:
959 fields = stop_clip_fields;
961 case mp_stop_bounds_code:
962 fields = stop_bounds_fields;
968 for (i = 0; fields[i] != NULL; i++) {
969 lua_pushstring(L, fields[i]);
970 lua_rawseti(L, -2, (i + 1));
979 #define mplib_push_number(L,x) lua_pushnumber(L,(lua_Number)(x)/65536.0)
984 static void mplib_push_path(lua_State * L, struct mp_knot *h, int is_pen)
986 struct mp_knot *p; /* for scanning the path */
992 lua_createtable(L, 0, 6);
994 if (p->left_type_field != mp_explicit) {
995 mplib_push_S(left_type);
996 lua_pushstring(L, knot_type_enum[p->left_type_field]);
999 if (p->right_type_field != mp_explicit) {
1000 mplib_push_S(right_type);
1001 lua_pushstring(L, knot_type_enum[p->right_type_field]);
1005 mplib_push_S(x_coord);
1006 mplib_push_number(L, p->x_coord_field);
1008 mplib_push_S(y_coord);
1009 mplib_push_number(L, p->y_coord_field);
1011 mplib_push_S(left_x);
1012 mplib_push_number(L, p->left_x_field);
1014 mplib_push_S(left_y);
1015 mplib_push_number(L, p->left_y_field);
1017 mplib_push_S(right_x);
1018 mplib_push_number(L, p->right_x_field);
1020 mplib_push_S(right_y);
1021 mplib_push_number(L, p->right_y_field);
1023 lua_rawseti(L, -2, i);
1025 if (p->right_type_field == mp_endpoint) {
1035 /* this assumes that the top of the stack is a table
1036 or nil already in the case
1038 static void mplib_push_pentype(lua_State * L, struct mp_knot *h)
1040 struct mp_knot *p; /* for scanning the path */
1044 } else if (p == p->next_field) {
1046 lua_pushstring(L, "elliptical");
1052 #define set_color_objects(pq) \
1053 object_color_model = pq->color_model_field; \
1054 object_color_a = pq->color_field._a_val; \
1055 object_color_b = pq->color_field._b_val; \
1056 object_color_c = pq->color_field._c_val; \
1057 object_color_d = pq->color_field._d_val;
1060 static void mplib_push_color(lua_State * L, struct mp_graphic_object *p)
1062 int object_color_model;
1063 int object_color_a, object_color_b, object_color_c, object_color_d;
1065 if (p->_type_field == mp_fill_code) {
1066 mp_fill_object *h = (mp_fill_object *) p;
1067 set_color_objects(h);
1068 } else if (p->_type_field == mp_stroked_code) {
1069 mp_stroked_object *h = (mp_stroked_object *) p;
1070 set_color_objects(h);
1072 mp_text_object *h = (mp_text_object *) p;
1073 set_color_objects(h);
1076 if (object_color_model >= mp_grey_model) {
1077 mplib_push_number(L, object_color_a);
1078 lua_rawseti(L, -2, 1);
1079 if (object_color_model >= mp_rgb_model) {
1080 mplib_push_number(L, object_color_b);
1081 lua_rawseti(L, -2, 2);
1082 mplib_push_number(L, object_color_c);
1083 lua_rawseti(L, -2, 3);
1084 if (object_color_model == mp_cmyk_model) {
1085 mplib_push_number(L, object_color_d);
1086 lua_rawseti(L, -2, 4);
1095 /* the dash scale is not exported, the field has no external value */
1096 static void mplib_push_dash(lua_State * L, struct mp_stroked_object *h)
1100 if (h != NULL && h->dash_p_field != NULL) {
1101 d = h->dash_p_field;
1103 mplib_push_number(L, d->offset_field);
1104 lua_setfield(L, -2, "offset");
1105 if (d->array_field != NULL) {
1108 while (*(d->array_field + i) != -1) {
1109 ds = *(d->array_field + 1) / 65536.0;
1110 lua_pushnumber(L, ds);
1112 lua_rawseti(L, -2, i);
1114 lua_setfield(L, -2, "dashes");
1121 static void mplib_push_transform(lua_State * L, struct mp_text_object *h)
1125 lua_createtable(L, 6, 0);
1126 mplib_push_number(L, h->tx_field);
1127 lua_rawseti(L, -2, i);
1129 mplib_push_number(L, h->ty_field);
1130 lua_rawseti(L, -2, i);
1132 mplib_push_number(L, h->txx_field);
1133 lua_rawseti(L, -2, i);
1135 mplib_push_number(L, h->tyx_field);
1136 lua_rawseti(L, -2, i);
1138 mplib_push_number(L, h->txy_field);
1139 lua_rawseti(L, -2, i);
1141 mplib_push_number(L, h->tyy_field);
1142 lua_rawseti(L, -2, i);
1149 #define FIELD(A) (mplib_is_S(A,2))
1151 static void mplib_fill_field(lua_State * L, struct mp_fill_object *h)
1154 mplib_push_path(L, h->path_p_field, MPLIB_PATH);
1155 } else if (FIELD(htap)) {
1156 mplib_push_path(L, h->htap_p_field, MPLIB_PATH);
1157 } else if (FIELD(pen)) {
1158 mplib_push_path(L, h->pen_p_field, MPLIB_PEN);
1159 mplib_push_pentype(L, h->pen_p_field);
1160 } else if (FIELD(color)) {
1161 mplib_push_color(L, (mp_graphic_object *) h);
1162 } else if (FIELD(linejoin)) {
1163 lua_pushnumber(L, h->ljoin_field);
1164 } else if (FIELD(miterlimit)) {
1165 mplib_push_number(L, h->miterlim_field);
1166 } else if (FIELD(prescript)) {
1167 lua_pushstring(L, h->pre_script_field);
1168 } else if (FIELD(postscript)) {
1169 lua_pushstring(L, h->post_script_field);
1175 static void mplib_stroked_field(lua_State * L, struct mp_stroked_object *h)
1178 mplib_push_path(L, h->path_p_field, MPLIB_PATH);
1179 } else if (FIELD(pen)) {
1180 mplib_push_path(L, h->pen_p_field, MPLIB_PEN);
1181 mplib_push_pentype(L, h->pen_p_field);
1182 } else if (FIELD(color)) {
1183 mplib_push_color(L, (mp_graphic_object *) h);
1184 } else if (FIELD(dash)) {
1185 mplib_push_dash(L, h);
1186 } else if (FIELD(linecap)) {
1187 lua_pushnumber(L, h->lcap_field);
1188 } else if (FIELD(linejoin)) {
1189 lua_pushnumber(L, h->ljoin_field);
1190 } else if (FIELD(miterlimit)) {
1191 mplib_push_number(L, h->miterlim_field);
1192 } else if (FIELD(prescript)) {
1193 lua_pushstring(L, h->pre_script_field);
1194 } else if (FIELD(postscript)) {
1195 lua_pushstring(L, h->post_script_field);
1201 static void mplib_text_field(lua_State * L, struct mp_text_object *h)
1204 lua_pushstring(L, h->text_p_field);
1205 } else if (FIELD(dsize)) {
1206 mplib_push_number(L, (h->font_dsize_field / 16));
1207 } else if (FIELD(font)) {
1208 lua_pushstring(L, h->font_name_field);
1209 } else if (FIELD(color)) {
1210 mplib_push_color(L, (mp_graphic_object *) h);
1211 } else if (FIELD(width)) {
1212 mplib_push_number(L, h->width_field);
1213 } else if (FIELD(height)) {
1214 mplib_push_number(L, h->height_field);
1215 } else if (FIELD(depth)) {
1216 mplib_push_number(L, h->depth_field);
1217 } else if (FIELD(transform)) {
1218 mplib_push_transform(L, h);
1219 } else if (FIELD(prescript)) {
1220 lua_pushstring(L, h->pre_script_field);
1221 } else if (FIELD(postscript)) {
1222 lua_pushstring(L, h->post_script_field);
1228 static void mplib_special_field(lua_State * L, struct mp_special_object *h)
1230 if (FIELD(prescript)) {
1231 lua_pushstring(L, h->pre_script_field);
1237 static void mplib_start_bounds_field(lua_State * L, struct mp_bounds_object *h)
1240 mplib_push_path(L, h->path_p_field, MPLIB_PATH);
1246 static void mplib_start_clip_field(lua_State * L, struct mp_clip_object *h)
1249 mplib_push_path(L, h->path_p_field, MPLIB_PATH);
1255 static int mplib_gr_index(lua_State * L)
1257 struct mp_graphic_object **hh = is_gr_object(L, 1);
1259 struct mp_graphic_object *h = *hh;
1261 if (mplib_is_S(type, 2)) {
1262 lua_rawgeti(L, LUA_REGISTRYINDEX, mplib_type_Ses[h->_type_field]);
1264 switch (h->_type_field) {
1266 mplib_fill_field(L, (mp_fill_object *) h);
1268 case mp_stroked_code:
1269 mplib_stroked_field(L, (mp_stroked_object *) h);
1272 mplib_text_field(L, (mp_text_object *) h);
1274 case mp_special_code:
1275 mplib_special_field(L, (mp_special_object *) h);
1277 case mp_start_clip_code:
1278 mplib_start_clip_field(L, (mp_clip_object *) h);
1280 case mp_start_bounds_code:
1281 mplib_start_bounds_field(L, (mp_bounds_object *) h);
1283 /* case mp_stop_clip_code: */
1284 /* case mp_stop_bounds_code: */
1296 static const struct luaL_reg mplib_meta[] = {
1297 {"__gc", mplib_collect},
1298 {"__tostring", mplib_tostring},
1299 {NULL, NULL} /* sentinel */
1302 static const struct luaL_reg mplib_fig_meta[] = {
1303 {"__gc", mplib_fig_collect},
1304 {"__tostring", mplib_fig_tostring},
1305 {"objects", mplib_fig_body},
1306 {"copy_objects", mplib_fig_copy_body},
1307 {"filename", mplib_fig_filename},
1308 {"postscript", mplib_fig_postscript},
1309 {"boundingbox", mplib_fig_bb},
1310 {NULL, NULL} /* sentinel */
1313 static const struct luaL_reg mplib_gr_meta[] = {
1314 {"__gc", mplib_gr_collect},
1315 {"__tostring", mplib_gr_tostring},
1316 {"__index", mplib_gr_index},
1317 {NULL, NULL} /* sentinel */
1321 static const struct luaL_reg mplib_d[] = {
1322 {"execute", mplib_execute},
1323 {"finish", mplib_finish},
1324 {"statistics", mplib_statistics},
1325 {NULL, NULL} /* sentinel */
1329 static const struct luaL_reg mplib_m[] = {
1331 {"fields", mplib_gr_fields},
1332 {NULL, NULL} /* sentinel */
1336 int luaopen_mp(lua_State * L)
1340 luaL_newmetatable(L, MPLIB_GR_METATABLE);
1341 lua_pushvalue(L, -1); /* push metatable */
1342 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1343 luaL_register(L, NULL, mplib_gr_meta); /* object meta methods */
1346 luaL_newmetatable(L, MPLIB_FIG_METATABLE);
1347 lua_pushvalue(L, -1); /* push metatable */
1348 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1349 luaL_register(L, NULL, mplib_fig_meta); /* figure meta methods */
1352 luaL_newmetatable(L, MPLIB_METATABLE);
1353 lua_pushvalue(L, -1); /* push metatable */
1354 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1355 luaL_register(L, NULL, mplib_meta); /* meta methods */
1356 luaL_register(L, NULL, mplib_d); /* dict methods */
1357 luaL_register(L, "mplib", mplib_m); /* module functions */