1
4
5
23
24# include "mpconfig.h"
25
26# include "mp.h"
27
28
33
34# include "luametatex.h"
35
36
42
43# define MPLIB_PATH 0
44# define MPLIB_PEN 1
45# define MPLIB_PATH_SIZE 8
46
47static const char *mplib_math_options[] = {
48 "scaled",
49 "double",
50 "binary",
51 "decimal",
52 "posit",
53 NULL
54};
55
56static const char *mplib_interaction_options[] = {
57 "unknown",
58 "batch",
59 "nonstop",
60 "scroll",
61 "errorstop",
62 "silent",
63 NULL
64};
65
66static const char *mplib_filetype_names[] = {
67 "terminal",
68 "mp",
69 "data",
70 NULL
71};
72
73
78
79static const char *mplib_fill_fields[] = {
80 "type",
81 "path", "htap",
82 "pen", "color",
83 "linejoin", "miterlimit",
84 "prescript", "postscript",
85 "stacking",
86 NULL
87};
88
89static const char *mplib_stroked_fields[] = {
90 "type",
91 "path",
92 "pen", "color",
93 "linejoin", "miterlimit", "linecap",
94 "dash",
95 "prescript", "postscript",
96 "stacking",
97 NULL
98};
99
100static const char *mplib_start_clip_fields[] = {
101 "type",
102 "path",
103 "prescript", "postscript",
104 "stacking",
105 NULL
106};
107
108static const char *mplib_start_group_fields[] = {
109 "type",
110 "path",
111 "prescript", "postscript",
112 "stacking",
113 NULL
114};
115
116static const char *mplib_start_bounds_fields[] = {
117 "type",
118 "path",
119 "prescript", "postscript",
120 "stacking",
121 NULL
122};
123
124static const char *mplib_stop_clip_fields[] = {
125 "type",
126 "stacking",
127 NULL
128};
129
130static const char *mplib_stop_group_fields[] = {
131 "type",
132 "stacking",
133 NULL
134};
135
136static const char *mplib_stop_bounds_fields[] = {
137 "type",
138 "stacking",
139 NULL
140};
141
142static const char *mplib_no_fields[] = {
143 NULL
144};
145
146static const char *mplib_codes[] = {
147 "undefined",
148 "btex",
149 "etex",
150 "if",
151 "fiorelse",
152 "input",
153 "iteration",
154 "repeatloop",
155 "exittest",
156 "relax",
157 "scantokens",
158 "runscript",
159 "maketext",
160 "expandafter",
161 "definedmacro",
162 "save",
163 "interim",
164 "let",
165 "newinternal",
166 "macrodef",
167 "shipout",
168 "addto",
169 "setbounds",
170 "protection",
171 "property",
172 "show",
173 "mode",
174 "onlyset",
175 "message",
176 "everyjob",
177 "delimiters",
178 "write",
179 "typename",
180 "leftdelimiter",
181 "begingroup",
182 "nullary",
183 "unary",
184 "str",
185 "void",
186 "cycle",
187 "ofbinary",
188 "capsule",
189 "string",
190 "internal",
191 "tag",
192 "numeric",
193 "plusorminus",
194 "secondarydef",
195 "tertiarybinary",
196 "leftbrace",
197 "pathjoin",
198 "ampersand",
199 "tertiarydef",
200 "primarybinary",
201 "equals",
202 "and",
203 "primarydef",
204 "slash",
205 "secondarybinary",
206 "parametertype",
207 "controls",
208 "tension",
209 "atleast",
210 "curl",
211 "macrospecial",
212 "rightdelimiter",
213 "leftbracket",
214 "rightbracket",
215 "rightbrace",
216 "with",
217 "thingstoadd",
218 "of",
219 "to",
220 "step",
221 "until",
222 "within",
223 "assignment",
224 "colon",
225 "comma",
226 "semicolon",
227 "endgroup",
228 "stop",
229
230 "undefinedcs",
231 NULL
232};
233
234static const char *mplib_states[] = {
235 "normal",
236 "skipping",
237 "flushing",
238 "absorbing",
239 "var_defining",
240 "op_defining",
241 "loop_defining",
242 NULL
243};
244
245static const char *mplib_types[] = {
246 "undefined",
247 "vacuous",
248 "boolean",
249 "unknownboolean",
250 "string",
251 "unknownstring",
252 "pen",
253 "unknownpen",
254 "nep",
255 "unknownnep",
256 "path",
257 "unknownpath",
258 "picture",
259 "unknownpicture",
260 "transform",
261 "color",
262 "cmykcolor",
263 "pair",
264
265 "numeric",
266 "known",
267 "dependent",
268 "protodependent",
269 "independent",
270 "tokenlist",
271 "structured",
272 "unsuffixedmacro",
273 "suffixedmacro",
274 NULL
275};
276
277static const char *mplib_colormodels[] = {
278 "no",
279 "grey",
280 "rgb",
281 "cmyk",
282 NULL
283};
284
285
286
287typedef struct mplib_state_info {
288 int file_callbacks;
289 int text_callbacks;
290 int script_callbacks;
291 int log_callbacks;
292 int overload_callbacks;
293 int error_callbacks;
294 int warning_callbacks;
295} mplib_state_info;
296
297static mplib_state_info mplib_state = {
298 .file_callbacks = 0,
299 .text_callbacks = 0,
300 .script_callbacks = 0,
301 .log_callbacks = 0,
302 .overload_callbacks = 0,
303 .error_callbacks = 0,
304 .warning_callbacks = 0,
305};
306
307
313
314
319
320
332
333# define default_bend_tolerance 131/65536.0
334# define default_move_tolerance 131/65536.0
335
336typedef enum mp_variables {
337 mp_bend_tolerance = 1,
338 mp_move_tolerance = 2,
339} mp_variables;
340
341static lua_Number mplib_aux_get_bend_tolerance(lua_State *L, int slot)
342{
343 lua_Number tolerance;
344 lua_getiuservalue(L, slot, mp_bend_tolerance);
345 tolerance = lua_tonumber(L, -1);
346 lua_pop(L, 1);
347 return tolerance;
348}
349
350static lua_Number mplib_aux_get_move_tolerance(lua_State *L, int slot)
351{
352 lua_Number tolerance;
353 lua_getiuservalue(L, slot, mp_move_tolerance);
354 tolerance = lua_tonumber(L, -1);
355 lua_pop(L, 1);
356 return tolerance;
357}
358
359static void mplib_aux_set_bend_tolerance(lua_State *L, lua_Number tolerance)
360{
361 lua_pushnumber(L, tolerance);
362 lua_setiuservalue(L, -2, mp_bend_tolerance);
363}
364
365static void mplib_aux_set_move_tolerance(lua_State *L, lua_Number tolerance)
366{
367 lua_pushnumber(L, tolerance);
368 lua_setiuservalue(L, -2, mp_move_tolerance);
369}
370
371inline static char *lmt_string_from_index(lua_State *L, int n)
372{
373 size_t l;
374 const char *x = lua_tolstring(L, n, &l);
375
376 return (x && l > 0) ? lmt_memory_strdup(x) : NULL;
377}
378
379inline static char *lmt_lstring_from_index(lua_State *L, int n, size_t *l)
380{
381 const char *x = lua_tolstring(L, n, l);
382
383 return (x && l > 0) ? lmt_memory_strdup(x) : NULL;
384}
385
386static void mplib_aux_invalid_object_warning(const char * detail)
387{
388 tex_formatted_warning("mp lib","lua <mp %s> expected", detail);
389}
390
391static void mplib_aux_invalid_object_error(const char * detail)
392{
393 tex_formatted_error("mp lib","lua <mp %s> expected", detail);
394}
395
396inline static MP *mplib_aux_is_mpud(lua_State *L, int n)
397{
398 MP *p = (MP *) lua_touserdata(L, n);
399 if (p && lua_getmetatable(L, n)) {
400 lua_get_metatablelua(mplib_instance);
401 if (! lua_rawequal(L, -1, -2)) {
402 p = NULL;
403 }
404 lua_pop(L, 2);
405 if (p) {
406 return p;
407 }
408 }
409 mplib_aux_invalid_object_error("instance");
410 return NULL;
411}
412
413inline static MP mplib_aux_is_mp(lua_State *L, int n)
414{
415 MP *p = (MP *) lua_touserdata(L, n);
416 if (p && lua_getmetatable(L, n)) {
417 lua_get_metatablelua(mplib_instance);
418 if (! lua_rawequal(L, -1, -2)) {
419 p = NULL;
420 }
421 lua_pop(L, 2);
422 if (p) {
423 return *p;
424 }
425 }
426 mplib_aux_invalid_object_error("instance");
427 return NULL;
428}
429
430inline static mp_edge_object **mplib_aux_is_figure(lua_State *L, int n)
431{
432 mp_edge_object **p = (mp_edge_object **) lua_touserdata(L, n);
433 if (p && lua_getmetatable(L, n)) {
434 lua_get_metatablelua(mplib_figure);
435 if (! lua_rawequal(L, -1, -2)) {
436 p = NULL;
437 }
438 lua_pop(L, 2);
439 if (p) {
440 return p;
441 }
442 }
443 mplib_aux_invalid_object_warning("figure");
444 return NULL;
445}
446
447inline static mp_graphic_object **mplib_aux_is_gr_object(lua_State *L, int n)
448{
449 mp_graphic_object **p = (mp_graphic_object **) lua_touserdata(L, n);
450 if (p && lua_getmetatable(L, n)) {
451 lua_get_metatablelua(mplib_object);
452 if (! lua_rawequal(L, -1, -2)) {
453 p = NULL;
454 }
455 lua_pop(L, 2);
456 if (p) {
457 return p;
458 }
459 }
460 mplib_aux_invalid_object_warning("object");
461 return NULL;
462}
463
464
465
466static int mplib_values_type[mp_stop_bounds_code + 1] = { 0 };
467static int mplib_values_knot[6] = { 0 };
468
469static void mplib_aux_initialize_lua(lua_State *L)
470{
471 (void) L;
472 mplib_values_type[mp_fill_code] = lua_key_index(fill);
473 mplib_values_type[mp_stroked_code] = lua_key_index(outline);
474 mplib_values_type[mp_start_clip_code] = lua_key_index(start_clip);
475 mplib_values_type[mp_start_group_code] = lua_key_index(start_group);
476 mplib_values_type[mp_start_bounds_code] = lua_key_index(start_bounds);
477 mplib_values_type[mp_stop_clip_code] = lua_key_index(stop_clip);
478 mplib_values_type[mp_stop_group_code] = lua_key_index(stop_group);
479 mplib_values_type[mp_stop_bounds_code] = lua_key_index(stop_bounds);
480
481 mplib_values_knot[mp_endpoint_knot] = lua_key_index(endpoint);
482 mplib_values_knot[mp_explicit_knot] = lua_key_index(explicit);
483 mplib_values_knot[mp_given_knot] = lua_key_index(given);
484 mplib_values_knot[mp_curl_knot] = lua_key_index(curl);
485 mplib_values_knot[mp_open_knot] = lua_key_index(open);
486 mplib_values_knot[mp_end_cycle_knot] = lua_key_index(end_cycle);
487}
488
489static void mplib_aux_push_pentype(lua_State *L, mp_gr_knot h)
490{
491 if (h && h == h->next) {
492 lua_push_value_at_key(L, type, elliptical);
493 }
494}
495
496static int mplib_set_tolerance(lua_State *L)
497{
498 MP mp = mplib_aux_is_mp(L, 1);
499 if (mp) {
500 mplib_aux_set_bend_tolerance(L, luaL_optnumber(L, 2, default_bend_tolerance));
501 mplib_aux_set_move_tolerance(L, luaL_optnumber(L, 3, default_move_tolerance));
502 }
503 return 0;
504}
505
506static int mplib_get_tolerance(lua_State *L)
507{
508
509 if (lua_type(L, 1) == LUA_TUSERDATA) {
510 MP mp = mplib_aux_is_mp(L, 1);
511 if (mp) {
512 lua_pushnumber(L, mplib_aux_get_bend_tolerance(L, 1));
513 lua_pushnumber(L, mplib_aux_get_move_tolerance(L, 1));
514 return 2;
515 } else {
516 return 0;
517 }
518 } else {
519 lua_pushnumber(L, default_bend_tolerance);
520 lua_pushnumber(L, default_move_tolerance);
521 return 2;
522 }
523}
524
525
531
532static int mplib_aux_register_function(lua_State *L, int old_id)
533{
534 if (! (lua_isfunction(L, -1) || lua_isnil(L, -1))) {
535 return 0;
536 } else {
537 lua_pushvalue(L, -1);
538 if (old_id) {
539 luaL_unref(L, LUA_REGISTRYINDEX, old_id);
540 }
541 return luaL_ref(L, LUA_REGISTRYINDEX);
542 }
543}
544
545static int mplib_aux_find_file_function(lua_State *L, MP_options *options)
546{
547 options->find_file_id = mplib_aux_register_function(L, options->find_file_id);
548 return (! options->find_file_id);
549}
550
551static int mplib_aux_run_script_function(lua_State *L, MP_options *options)
552{
553 options->run_script_id = mplib_aux_register_function(L, options->run_script_id);
554 return (! options->run_script_id);
555}
556
557static int mplib_aux_run_internal_function(lua_State *L, MP_options *options)
558{
559 options->run_internal_id = mplib_aux_register_function(L, options->run_internal_id);
560 return (! options->run_internal_id);
561}
562
563static int mplib_aux_make_text_function(lua_State *L, MP_options *options)
564{
565 options->make_text_id = mplib_aux_register_function(L, options->make_text_id);
566 return (! options->make_text_id);
567}
568
569static int mplib_aux_run_logger_function(lua_State *L, MP_options *options)
570{
571 options->run_logger_id = mplib_aux_register_function(L, options->run_logger_id);
572 return (! options->run_logger_id);
573}
574
575static int mplib_aux_run_overload_function(lua_State *L, MP_options *options)
576{
577 options->run_overload_id = mplib_aux_register_function(L, options->run_overload_id);
578 return (! options->run_overload_id);
579}
580
581static int mplib_aux_run_error_function(lua_State *L, MP_options *options)
582{
583 options->run_error_id = mplib_aux_register_function(L, options->run_error_id);
584 return (! options->run_error_id);
585}
586
587static int mplib_aux_open_file_function(lua_State *L, MP_options *options)
588{
589 options->open_file_id = mplib_aux_register_function(L, options->open_file_id);
590 return (! options->open_file_id);
591}
592
593static char *mplib_aux_find_file(MP mp, const char *fname, const char *fmode, int ftype)
594{
595 if (mp->find_file_id) {
596 lua_State *L = (lua_State *) mp_userdata(mp);
597 int stacktop = lua_gettop(L);
598 char *s = NULL;
599 lua_rawgeti(L, LUA_REGISTRYINDEX, mp->find_file_id);
600 lua_pushstring(L, fname);
601 lua_pushstring(L, fmode);
602 if (ftype > mp_filetype_text) {
603 lua_pushinteger(L, (lua_Integer) ftype - mp_filetype_text);
604 } else {
605 lua_pushstring(L, mplib_filetype_names[ftype]);
606 }
607 ++mplib_state.file_callbacks;
608 if (lua_pcall(L, 3, 1, 0)) {
609 tex_formatted_warning("mplib", "find file: %s", lua_tostring(L, -1));
610 } else {
611 s = lmt_string_from_index(L, -1);
612 }
613 lua_settop(L, stacktop);
614 return s;
615 } else if (fmode[0] != 'r' || (! access(fname, R_OK)) || ftype) {
616
617 return lmt_memory_strdup(fname);
618 }
619 return NULL;
620}
621
622
642
643static int mplib_aux_with_path(lua_State *L, MP mp, int index, int what, int multiple);
644
645static void mplib_aux_inject_whatever(lua_State *L, MP mp, int index)
646{
647 switch (lua_type(L, index)) {
648 case LUA_TBOOLEAN:
649 mp_push_boolean_value(mp, lua_toboolean(L, index));
650 break;
651 case LUA_TNUMBER:
652 mp_push_numeric_value(mp, lua_tonumber(L, index));
653 break;
654 case LUA_TSTRING:
655 {
656 size_t l;
657 const char *s = lua_tolstring(L, index, &l);
658 mp_push_string_value(mp, s, (int) l);
659 break;
660 }
661 case LUA_TTABLE:
662 {
663 if (lua_rawgeti(L, index, 1) == LUA_TTABLE) {
664
665 lua_pop(L, 1);
666 mplib_aux_with_path(L, mp, index, 1, 0);
667 } else {
668 lua_pop(L, 1);
669 switch (lua_rawlen(L, index)) {
670 case 2 :
671 mp_push_pair_value(mp,
672 lmt_number_from_table(L, index, 1, 0.0),
673 lmt_number_from_table(L, index, 2, 0.0)
674 );
675 break;
676 case 3 :
677 mp_push_color_value(mp,
678 lmt_number_from_table(L, index, 1, 0.0),
679 lmt_number_from_table(L, index, 2, 0.0),
680 lmt_number_from_table(L, index, 3, 0.0)
681 );
682 break;
683 case 4 :
684 mp_push_cmykcolor_value(mp,
685 lmt_number_from_table(L, index, 1, 0.0),
686 lmt_number_from_table(L, index, 2, 0.0),
687 lmt_number_from_table(L, index, 3, 0.0),
688 lmt_number_from_table(L, index, 4, 0.0)
689 );
690 break;
691 case 6 :
692 mp_push_transform_value(mp,
693 lmt_number_from_table(L, index, 1, 0.0),
694 lmt_number_from_table(L, index, 2, 0.0),
695 lmt_number_from_table(L, index, 3, 0.0),
696 lmt_number_from_table(L, index, 4, 0.0),
697 lmt_number_from_table(L, index, 5, 0.0),
698 lmt_number_from_table(L, index, 6, 0.0)
699 );
700 break;
701 }
702 }
703 break;
704 }
705 }
706}
707
708static char *mplib_aux_return_whatever(lua_State *L, MP mp, int index)
709{
710 switch (lua_type(L, index)) {
711 case LUA_TBOOLEAN:
712 mp_push_boolean_value(mp, lua_toboolean(L, index));
713 break;
714 case LUA_TNUMBER:
715 mp_push_numeric_value(mp, lua_tonumber(L, index));
716 break;
717
718 case LUA_TSTRING:
719 return lmt_string_from_index(L, index);
720
721 case LUA_TTABLE:
722 {
723 luaL_Buffer b;
724 lua_Integer n = (lua_Integer) lua_rawlen(L, index);
725 luaL_buffinit(L, &b);
726 for (lua_Integer i = 1; i <= n; i++) {
727 lua_rawgeti(L, index, i);
728 luaL_addvalue(&b);
729 lua_pop(L, 1);
730 }
731 luaL_pushresult(&b);
732 return lmt_string_from_index(L, -1);
733 }
734 }
735 return NULL;
736}
737
738static char *mplib_aux_run_script(MP mp, const char *str, size_t len, int n)
739{
740 if (mp->run_script_id) {
741 lua_State *L = (lua_State *) mp_userdata(mp);
742 int stacktop = lua_gettop(L);
743 lua_rawgeti(L, LUA_REGISTRYINDEX, mp->run_script_id);
744 if (str) {
745 lua_pushlstring(L, str, len);
746 } else if (n > 0) {
747 lua_pushinteger(L, n);
748 } else {
749 lua_pushnil(L);
750 }
751 ++mplib_state.script_callbacks;
752 if (lua_pcall(L, 1, 2, 0)) {
753 tex_formatted_warning("mplib", "run script: %s", lua_tostring(L, -1));
754 } else if (lua_toboolean(L, -1)) {
755
756 mplib_aux_inject_whatever(L, mp, -2);
757 lua_settop(L, stacktop);
758 return NULL;
759 } else {
760
761 char *s = mplib_aux_return_whatever(L, mp, -2);
762 lua_settop(L, stacktop);
763 return s;
764 }
765 }
766 return NULL;
767}
768
769static void mplib_aux_run_internal(MP mp, int action, int n, int type, const char *name)
770{
771 if (mp->run_internal_id) {
772 lua_State *L = (lua_State *) mp_userdata(mp);
773 ++mplib_state.script_callbacks;
774 lua_rawgeti(L, LUA_REGISTRYINDEX, mp->run_internal_id);
775 lua_pushinteger(L, action);
776 lua_pushinteger(L, n);
777 if (name) {
778 lua_pushinteger(L, type);
779 lua_pushstring(L, name);
780 if (! lua_pcall(L, 4, 0, 0)) {
781 return;
782 }
783 } else {
784 if (lua_pcall(L, 2, 0, 0)) {
785 return;
786 }
787 }
788 tex_formatted_warning("mplib", "run internal: %s", lua_tostring(L, -1));
789 }
790}
791
792static char *mplib_aux_make_text(MP mp, const char *str, size_t len, int mode)
793{
794 if (mp->make_text_id) {
795 lua_State *L = (lua_State *) mp_userdata(mp);
796 int stacktop = lua_gettop(L);
797 char *s = NULL;
798 lua_rawgeti(L, LUA_REGISTRYINDEX, mp->make_text_id);
799 lua_pushlstring(L, str, len);
800 lua_pushinteger(L, mode);
801 ++mplib_state.text_callbacks;
802 if (lua_pcall(L, 2, 1, 0)) {
803 tex_formatted_warning("mplib", "make text: %s", lua_tostring(L, -1));
804 } else {
805 s = lmt_string_from_index(L, -1);
806 }
807 lua_settop(L, stacktop);
808 return s;
809 }
810 return NULL;
811}
812
813static void mplib_aux_run_logger(MP mp, int target, const char *str, size_t len)
814{
815 if (mp->run_logger_id) {
816 lua_State *L = (lua_State *) mp_userdata(mp);
817 int stacktop = lua_gettop(L);
818 lua_rawgeti(L, LUA_REGISTRYINDEX, mp->run_logger_id);
819 lua_pushinteger(L, target);
820 lua_pushlstring(L, str, len);
821 ++mplib_state.log_callbacks;
822 if (lua_pcall(L, 2, 0, 0)) {
823 tex_formatted_warning("mplib", "run logger: %s", lua_tostring(L, -1));
824 }
825 lua_settop(L, stacktop);
826 }
827}
828
829static int mplib_aux_run_overload(MP mp, int property, const char *str, int mode)
830{
831 int quit = 0;
832 if (mp->run_overload_id) {
833 lua_State *L = (lua_State *) mp_userdata(mp);
834 int stacktop = lua_gettop(L);
835 lua_rawgeti(L, LUA_REGISTRYINDEX, mp->run_overload_id);
836 lua_pushinteger(L, property);
837 lua_pushstring(L, str);
838 lua_pushinteger(L, mode);
839 ++mplib_state.overload_callbacks;
840 if (lua_pcall(L, 3, 1, 0)) {
841 tex_formatted_warning("mplib", "run overload: %s", lua_tostring(L, -1));
842 quit = 1;
843 } else {
844 quit = lua_toboolean(L, -1);
845 }
846 lua_settop(L, stacktop);
847 }
848 return quit;
849}
850
851static void mplib_aux_run_error(MP mp, const char *str, const char *help, int interaction)
852{
853 if (mp->run_error_id) {
854 lua_State *L = (lua_State *) mp_userdata(mp);
855 int stacktop = lua_gettop(L);
856 lua_rawgeti(L, LUA_REGISTRYINDEX, mp->run_error_id);
857 lua_pushstring(L, str);
858 lua_pushstring(L, help);
859 lua_pushinteger(L, interaction);
860 ++mplib_state.error_callbacks;
861 if (lua_pcall(L, 3, 0, 0)) {
862 tex_formatted_warning("mplib", "run error: %s", lua_tostring(L, -1));
863 }
864 lua_settop(L, stacktop);
865 }
866}
867
868
875
876
877
878static void *mplib_aux_open_file(MP mp, const char *fname, const char *fmode, int ftype)
879{
880 if (mp->open_file_id) {
881 int *index = mp_memory_allocate(sizeof(int));
882 if (index) {
883 lua_State *L = (lua_State *) mp_userdata(mp);
884 int stacktop = lua_gettop(L);
885 lua_rawgeti(L, LUA_REGISTRYINDEX, mp->open_file_id);
886 lua_pushstring(L, fname);
887 lua_pushstring(L, fmode);
888 if (ftype > mp_filetype_text) {
889 lua_pushinteger(L, (lua_Integer) ftype - mp_filetype_text);
890 } else {
891 lua_pushstring(L, mplib_filetype_names[ftype]);
892 }
893 ++mplib_state.file_callbacks;
894 if (lua_pcall(L, 3, 1, 0)) {
895 *((int*) index) = 0;
896 } else if (lua_istable(L, -1)) {
897 lua_pushvalue(L, -1);
898 *((int*) index) = luaL_ref(L, LUA_REGISTRYINDEX);
899 } else {
900 tex_normal_warning("mplib", "open file: table expected");
901 *((int*) index) = 0;
902 }
903 lua_settop(L, stacktop);
904 return index;
905 }
906 }
907 return NULL;
908}
909
910# define mplib_pop_function(idx,tag) \
911 lua_rawgeti(L, LUA_REGISTRYINDEX, idx); \
912 lua_push_key(tag); \
913 lua_rawget(L, -2);
914
915static void mplib_aux_close_file(MP mp, void *index)
916{
917 if (mp->open_file_id && index) {
918 int idx = *((int*) index);
919 lua_State *L = (lua_State *) mp_userdata(mp);
920 int stacktop = lua_gettop(L);
921 mplib_pop_function(idx, close)
922 if (lua_isfunction(L, -1)) {
923 ++mplib_state.file_callbacks;
924 if (lua_pcall(L, 0, 0, 0)) {
925
926 } else {
927
928 }
929 }
930
935 lua_settop(L, stacktop);
936 mp_memory_free(index);
937 }
938}
939
940static char *mplib_aux_read_file(MP mp, void *index, size_t *size)
941{
942 if (mp->open_file_id && index) {
943 lua_State *L = (lua_State *) mp_userdata(mp);
944 int stacktop = lua_gettop(L);
945 int idx = *((int*) index);
946 char *s = NULL;
947 mplib_pop_function(idx, reader)
948 if (lua_isfunction(L, -1)) {
949 ++mplib_state.file_callbacks;
950 if (lua_pcall(L, 0, 1, 0)) {
951 *size = 0;
952 } else if (lua_type(L, -1) == LUA_TSTRING) {
953 s = lmt_lstring_from_index(L, -1, size);
954 }
955 }
956 lua_settop(L, stacktop);
957 return s;
958 }
959 return NULL;
960}
961
962static void mplib_aux_write_file(MP mp, void *index, const char *s)
963{
964 if (mp->open_file_id && index) {
965 lua_State *L = (lua_State *) mp_userdata(mp);
966 int stacktop = lua_gettop(L);
967 int idx = *((int*) index);
968 mplib_pop_function(idx, writer)
969 if (lua_isfunction(L, -1)) {
970 lua_pushstring(L, s);
971 ++mplib_state.file_callbacks;
972 if (lua_pcall(L, 1, 0, 0)) {
973
974 } else {
975
976 }
977 }
978 lua_settop(L, stacktop);
979 }
980}
981
982static int mplib_scan_next(lua_State *L)
983{
984 MP mp = mplib_aux_is_mp(L, 1);
985 int token = 0;
986 int mode = 0;
987 int kind = 0;
988 if (mp) {
989 int keep = 0 ;
990 if (lua_gettop(L) > 1) {
991 keep = lua_toboolean(L, 2);
992 }
993 mp_scan_next_value(mp, keep, &token, &mode, &kind);
994 }
995 lua_pushinteger(L, token);
996 lua_pushinteger(L, mode);
997 lua_pushinteger(L, kind);
998 return 3;
999}
1000
1001static int mplib_scan_expression(lua_State *L)
1002{
1003 MP mp = mplib_aux_is_mp(L, 1);
1004 int kind = 0;
1005 if (mp) {
1006 int keep = 0 ;
1007 if (lua_gettop(L) > 1) {
1008 keep = lua_toboolean(L, 2);
1009 }
1010 mp_scan_expr_value(mp, keep, &kind);
1011 }
1012 lua_pushinteger(L, kind);
1013 return 1;
1014}
1015
1016static int mplib_scan_token(lua_State *L)
1017{
1018 MP mp = mplib_aux_is_mp(L, 1);
1019 int token = 0;
1020 int mode = 0;
1021 int kind = 0;
1022 if (mp) {
1023 int keep = 0 ;
1024 if (lua_gettop(L) > 1) {
1025 keep = lua_toboolean(L, 2);
1026 }
1027 mp_scan_token_value(mp, keep, &token, &mode, &kind);
1028 }
1029 lua_pushinteger(L, token);
1030 lua_pushinteger(L, mode);
1031 lua_pushinteger(L, kind);
1032 return 3;
1033}
1034
1035static int mplib_skip_token(lua_State *L)
1036{
1037 MP mp = mplib_aux_is_mp(L, 1);
1038 lua_pushboolean(L, mp ? mp_skip_token_value(mp, lmt_tointeger(L, 2)) : 0);
1039 return 1;
1040}
1041
1042static int mplib_scan_symbol(lua_State *L)
1043{
1044 MP mp = mplib_aux_is_mp(L, 1);
1045 if (mp) {
1046 int keep = 0 ;
1047 int expand = 1 ;
1048 int top = lua_gettop(L) ;
1049 char *s = NULL;
1050 if (top > 2) {
1051 expand = lua_toboolean(L, 3);
1052 }
1053 if (top > 1) {
1054 keep = lua_toboolean(L, 2);
1055 }
1056 mp_scan_symbol_value(mp, keep, &s, expand) ;
1057 if (s) {
1058
1059 lua_pushstring(L, s);
1060 mp_memory_free(s);
1061 return 1;
1062 }
1063 }
1064 lua_pushliteral(L,"");
1065 return 1;
1066}
1067
1068static int mplib_scan_property(lua_State *L)
1069{
1070 MP mp = mplib_aux_is_mp(L, 1);
1071 if (mp) {
1072 int keep = 0 ;
1073 int top = lua_gettop(L) ;
1074 int type = 0 ;
1075 int property = 0 ;
1076 int detail = 0 ;
1077 char *s = NULL;
1078 if (top > 1) {
1079 keep = lua_toboolean(L, 2);
1080 }
1081 mp_scan_property_value(mp, keep, &type, &s, &property, &detail);
1082 if (s) {
1083 lua_pushinteger(L, type);
1084 lua_pushstring(L, s);
1085 lua_pushinteger(L, property);
1086 lua_pushinteger(L, detail);
1087 mp_memory_free(s);
1088 return 4;
1089 }
1090 }
1091 return 0;
1092}
1093
1094
1097
1098static int aux_is_curved_gr(mp_gr_knot ith, mp_gr_knot pth, lua_Number tolerance)
1099{
1100 lua_Number d = pth->left_x - ith->right_x;
1101 if (fabs(ith->right_x - ith->x_coord - d) <= tolerance && fabs(pth->x_coord - pth->left_x - d) <= tolerance) {
1102 d = pth->left_y - ith->right_y;
1103 if (fabs(ith->right_y - ith->y_coord - d) <= tolerance && fabs(pth->y_coord - pth->left_y - d) <= tolerance) {
1104 return 0;
1105 }
1106 }
1107 return 1;
1108}
1109
1110static int aux_is_duplicate_gr(mp_gr_knot pth, mp_gr_knot nxt, lua_Number tolerance)
1111{
1112 return (fabs(pth->x_coord - nxt->x_coord) <= tolerance && fabs(pth->y_coord - nxt->y_coord) <= tolerance);
1113}
1114
1115# define valid_knot_type(t) (t >= mp_endpoint_knot && t <= mp_end_cycle_knot)
1116
1117
1118
1119
1120static void mplib_aux_push_path(lua_State *L, mp_gr_knot h, int ispen, lua_Number bendtolerance, lua_Number movetolerance)
1121{
1122 if (h) {
1123 int i = 0;
1124 mp_gr_knot p = h;
1125 mp_gr_knot q = h;
1126 int iscycle = 1;
1127 lua_createtable(L, ispen ? 1 : MPLIB_PATH_SIZE, ispen ? 2 : 1);
1128 do {
1129 mp_gr_knot n = p->next;
1130 int lt = p->left_type;
1131 int rt = p->right_type;
1132 if (ispen) {
1133 lua_createtable(L, 0, 6);
1134
1135 } else if (i > 0 && p != h && n != h && aux_is_duplicate_gr(p, n, movetolerance) && ! aux_is_curved_gr(p, n, bendtolerance) ) {
1136 n->left_x = p->left_x;
1137 n->left_y = p->left_y;
1138 goto NEXTONE;
1139 } else {
1140 int ln = lt != mp_explicit_knot;
1141 int rn = rt != mp_explicit_knot;
1142 int ic = i > 0 && aux_is_curved_gr(q, p, bendtolerance);
1143 int st = p->state;
1144 lua_createtable(L, 0, 6 + (ic ? 1 : 0) + (ln ? 1 : 0) + (rn ? 1 : 0) + (st ? 1: 0));
1145 if (ln && valid_knot_type(lt)) {
1146 lua_push_svalue_at_key(L, left_type, mplib_values_knot[lt]);
1147 }
1148 if (rn && valid_knot_type(rt)) {
1149 lua_push_svalue_at_key(L, right_type, mplib_values_knot[rt]);
1150 }
1151 if (ic) {
1152 lua_push_boolean_at_key(L, curved, 1);
1153 }
1154 if (st) {
1155 lua_push_integer_at_key(L, state, st);
1156 }
1157 lua_push_number_at_key(L, x_coord, p->x_coord);
1158 lua_push_number_at_key(L, y_coord, p->y_coord);
1159 lua_push_number_at_key(L, left_x, p->left_x);
1160 lua_push_number_at_key(L, left_y, p->left_y);
1161 lua_push_number_at_key(L, right_x, p->right_x);
1162 lua_push_number_at_key(L, right_y, p->right_y);
1163 lua_rawseti(L, -2, ++i);
1164 if (rt == mp_endpoint_knot) {
1165 iscycle = 0;
1166 break;
1167 }
1168 }
1169 NEXTONE:
1170 q = p;
1171 p = n;
1172 } while (p && p != h);
1173 if (iscycle && i > 1 && aux_is_curved_gr(q, h, bendtolerance)) {
1174 lua_rawgeti(L, -1, 1);
1175 lua_push_boolean_at_key(L, curved, 1);
1176 lua_pop(L, 1);
1177 }
1178 if (ispen) {
1179 lua_push_boolean_at_key(L, pen, 1);
1180 }
1181 lua_push_boolean_at_key(L, cycle, iscycle);
1182 } else {
1183 lua_pushnil(L);
1184 }
1185}
1186
1187static int aux_is_curved(MP mp, mp_knot ith, mp_knot pth, lua_Number tolerance)
1188{
1189 lua_Number d = mp_number_as_double(mp, pth->left_x) - mp_number_as_double(mp, ith->right_x);
1190 if (fabs(mp_number_as_double(mp, ith->right_x) - mp_number_as_double(mp, ith->x_coord) - d) <= tolerance && fabs(mp_number_as_double(mp, pth->x_coord) - mp_number_as_double(mp, pth->left_x) - d) <= tolerance) {
1191 d = mp_number_as_double(mp, pth->left_y) - mp_number_as_double(mp, ith->right_y);
1192 if (fabs(mp_number_as_double(mp, ith->right_y) - mp_number_as_double(mp, ith->y_coord) - d) <= tolerance && fabs(mp_number_as_double(mp, pth->y_coord) - mp_number_as_double(mp, pth->left_y) - d) <= tolerance) {
1193 return 0;
1194 }
1195 }
1196 return 1;
1197}
1198
1199static void aux_mplib_knot_to_path(lua_State *L, MP mp, mp_knot h, int ispen, int compact, int check, lua_Number bendtolerance)
1200{
1201 int i = 1;
1202 mp_knot p = h;
1203 mp_knot q = h;
1204 int iscycle = 1;
1205 lua_createtable(L, ispen ? 1 : MPLIB_PATH_SIZE, ispen ? 2 : 1);
1206 if (compact) {
1207 do {
1208 lua_createtable(L, 2, 0);
1209 lua_push_number_at_index(L, 1, mp_number_as_double(mp, p->x_coord));
1210 lua_push_number_at_index(L, 2, mp_number_as_double(mp, p->y_coord));
1211 lua_rawseti(L, -2, i++);
1212 if (p->right_type == mp_endpoint_knot) {
1213 iscycle = 0;
1214 break;
1215 } else {
1216 p = p->next;
1217 }
1218 } while (p && p != h);
1219 } else {
1220 do {
1221 int lt = p->left_type;
1222 int rt = p->right_type;
1223 int ln = lt != mp_explicit_knot;
1224 int rn = rt != mp_explicit_knot;
1225 int ic = check && (i > 1) && aux_is_curved(mp, q, p, bendtolerance);
1226 lua_createtable(L, 0, 6 + (ic ? 1 : 0) + (ln ? 1 : 0) + (rn ? 1 : 0));
1227 if (ln && valid_knot_type(lt)) {
1228 lua_push_svalue_at_key(L, left_type, mplib_values_knot[lt]);
1229 } else {
1230
1231 }
1232 if (rn && valid_knot_type(rt)) {
1233 lua_push_svalue_at_key(L, right_type, mplib_values_knot[rt]);
1234 } else {
1235
1236 }
1237 if (ic) {
1238 lua_push_boolean_at_key(L, curved, 1);
1239 }
1240 lua_push_number_at_index(L, 1, mp_number_as_double(mp, p->x_coord));
1241 lua_push_number_at_index(L, 2, mp_number_as_double(mp, p->y_coord));
1242 lua_push_number_at_index(L, 3, mp_number_as_double(mp, p->left_x));
1243 lua_push_number_at_index(L, 4, mp_number_as_double(mp, p->left_y));
1244 lua_push_number_at_index(L, 5, mp_number_as_double(mp, p->right_x));
1245 lua_push_number_at_index(L, 6, mp_number_as_double(mp, p->right_y));
1246 lua_rawseti(L, -2, i++);
1247 if (rt == mp_endpoint_knot) {
1248 iscycle = 0;
1249 break;
1250 } else {
1251 q = p;
1252 p = p->next;
1253 }
1254 } while (p && p != h);
1255 if (check && iscycle && i > 1 && aux_is_curved(mp, q, h, bendtolerance)) {
1256 lua_rawgeti(L, -1, 1);
1257 lua_push_boolean_at_key(L, curved, 1);
1258 lua_pop(L, 1);
1259 }
1260 }
1261 if (ispen) {
1262 lua_push_boolean_at_key(L, pen, 1);
1263 }
1264 lua_push_boolean_at_key(L, cycle, iscycle);
1265}
1266
1267
1273
1274# define push_number_in_slot(L,i,n) \
1275 lua_pushnumber(L, n); \
1276 lua_rawseti(L, -2, i);
1277
1278# define kind_of_expression(n) \
1279 lmt_optinteger(L, n, 0)
1280
1281static int mplib_scan_string(lua_State *L)
1282{
1283 MP mp = mplib_aux_is_mp(L, 1);
1284 if (mp) {
1285 char *s = NULL;
1286 size_t l = 0;
1287 mp_scan_string_value(mp, kind_of_expression(2), &s, &l) ;
1288 if (s) {
1289 lua_pushlstring(L, s, l);
1290 return 1;
1291 }
1292 }
1293 lua_pushliteral(L,"");
1294 return 1;
1295}
1296
1297static int mplib_scan_boolean(lua_State *L)
1298{
1299 MP mp = mplib_aux_is_mp(L, 1);
1300 int b = 0;
1301 if (mp) {
1302 mp_scan_boolean_value(mp, kind_of_expression(2), &b);
1303 }
1304 lua_pushboolean(L, b);
1305 return 1;
1306}
1307
1308static int mplib_scan_numeric(lua_State *L)
1309{
1310 MP mp = mplib_aux_is_mp(L, 1);
1311 double d = 0.0;
1312 if (mp) {
1313 mp_scan_numeric_value(mp, kind_of_expression(2), &d);
1314 }
1315 lua_pushnumber(L, d);
1316 return 1;
1317}
1318
1319static int mplib_scan_integer(lua_State *L)
1320{
1321 MP mp = mplib_aux_is_mp(L, 1);
1322 double d = 0.0;
1323 if (mp) {
1324 mp_scan_numeric_value(mp, kind_of_expression(2), &d);
1325 }
1326 lua_pushinteger(L, (int) d);
1327 return 1;
1328}
1329
1330static int mplib_scan_pair(lua_State *L)
1331{
1332 MP mp = mplib_aux_is_mp(L, 1);
1333 double x = 0.0;
1334 double y = 0.0;
1335 if (mp) {
1336 mp_scan_pair_value(mp, kind_of_expression(3), &x, &y);
1337 }
1338 if (lua_toboolean(L, 2)) {
1339 lua_createtable(L, 2, 0);
1340 push_number_in_slot(L, 1, x);
1341 push_number_in_slot(L, 2, y);
1342 return 1;
1343 } else {
1344 lua_pushnumber(L, x);
1345 lua_pushnumber(L, y);
1346 return 2;
1347 }
1348}
1349
1350static int mplib_scan_color(lua_State *L)
1351{
1352 MP mp = mplib_aux_is_mp(L, 1);
1353 double r = 0.0;
1354 double g = 0.0;
1355 double b = 0.0;
1356 if (mp) {
1357 mp_scan_color_value(mp, kind_of_expression(3), &r, &g, &b);
1358 }
1359 if (lua_toboolean(L, 2)) {
1360 lua_createtable(L, 3, 0);
1361 push_number_in_slot(L, 1, r);
1362 push_number_in_slot(L, 2, g);
1363 push_number_in_slot(L, 3, b);
1364 return 1;
1365 } else {
1366 lua_pushnumber(L, r);
1367 lua_pushnumber(L, g);
1368 lua_pushnumber(L, b);
1369 return 3;
1370 }
1371}
1372
1373static int mplib_scan_cmykcolor(lua_State *L)
1374{
1375 MP mp = mplib_aux_is_mp(L, 1);
1376 double c = 0.0;
1377 double m = 0.0;
1378 double y = 0.0;
1379 double k = 0.0;
1380 if (mp) {
1381 mp_scan_cmykcolor_value(mp, kind_of_expression(3), &c, &m, &y, &k);
1382 }
1383 if (lua_toboolean(L, 2)) {
1384 lua_createtable(L, 4, 0);
1385 push_number_in_slot(L, 1, c);
1386 push_number_in_slot(L, 2, m);
1387 push_number_in_slot(L, 3, y);
1388 push_number_in_slot(L, 4, k);
1389 return 1;
1390 } else {
1391 lua_pushnumber(L, c);
1392 lua_pushnumber(L, m);
1393 lua_pushnumber(L, y);
1394 lua_pushnumber(L, k);
1395 return 4;
1396 }
1397}
1398
1399static int mplib_scan_transform(lua_State *L)
1400{
1401 MP mp = mplib_aux_is_mp(L, 1);
1402 double x = 0.0;
1403 double y = 0.0;
1404 double xx = 0.0;
1405 double xy = 0.0;
1406 double yx = 0.0;
1407 double yy = 0.0;
1408 if (mp) {
1409 mp_scan_transform_value(mp, kind_of_expression(3), &x, &y, &xx, &xy, &yx, &yy);
1410 }
1411 if (lua_toboolean(L, 2)) {
1412 lua_createtable(L, 6, 0);
1413 push_number_in_slot(L, 1, x);
1414 push_number_in_slot(L, 2, y);
1415 push_number_in_slot(L, 3, xx);
1416 push_number_in_slot(L, 4, xy);
1417 push_number_in_slot(L, 5, yx);
1418 push_number_in_slot(L, 6, yy);
1419 return 1;
1420 } else {
1421 lua_pushnumber(L, x);
1422 lua_pushnumber(L, y);
1423 lua_pushnumber(L, xx);
1424 lua_pushnumber(L, xy);
1425 lua_pushnumber(L, yx);
1426 lua_pushnumber(L, yy);
1427 return 6;
1428 }
1429}
1430
1431static int mplib_scan_path(lua_State *L)
1432{
1433 MP mp = mplib_aux_is_mp(L, 1);
1434 if (mp) {
1435 mp_knot p = NULL;
1436 lua_Number t = mplib_aux_get_bend_tolerance(L, 1);
1437 mp_scan_path_value(mp, kind_of_expression(3), &p);
1438 if (p) {
1439 aux_mplib_knot_to_path(L, mp, p, 0, lua_toboolean(L, 2), lua_toboolean(L, 4), t);
1440 return 1;
1441 }
1442 }
1443 return 0;
1444}
1445
1446static int mplib_scan_pen(lua_State *L)
1447{
1448 MP mp = mplib_aux_is_mp(L, 1);
1449 if (mp) {
1450 mp_knot p = NULL ;
1451 lua_Number t = mplib_aux_get_bend_tolerance(L, 1);
1452 mp_scan_path_value(mp, kind_of_expression(3), &p) ;
1453 if (p) {
1454 aux_mplib_knot_to_path(L, mp, p, 1, lua_toboolean(L, 2), lua_toboolean(L, 4), t);
1455 return 1;
1456 }
1457 }
1458 return 0;
1459}
1460
1461static int mplib_inject_string(lua_State *L)
1462{
1463 MP mp = mplib_aux_is_mp(L, 1);
1464 if (mp) {
1465 size_t l = 0;
1466 const char *s = lua_tolstring(L, 2, &l);
1467 mp_push_string_value(mp, s, (int) l);
1468 }
1469 return 0;
1470}
1471
1472static int mplib_inject_boolean(lua_State *L)
1473{
1474 MP mp = mplib_aux_is_mp(L, 1);
1475 if (mp) {
1476 int b = lua_toboolean(L, 2);
1477 mp_push_boolean_value(mp, b);
1478 }
1479 return 0;
1480}
1481
1482static int mplib_inject_numeric(lua_State *L)
1483{
1484 MP mp = mplib_aux_is_mp(L, 1);
1485 if (mp) {
1486 double d = lua_tonumber(L, 2);
1487 mp_push_numeric_value(mp, d);
1488 }
1489 return 0;
1490}
1491
1492static int mplib_inject_integer(lua_State *L)
1493{
1494 MP mp = mplib_aux_is_mp(L, 1);
1495 if (mp) {
1496 int i = lmt_tointeger(L, 2);
1497 mp_push_integer_value(mp, i);
1498 }
1499 return 0;
1500}
1501
1502static int mplib_inject_pair(lua_State *L)
1503{
1504 MP mp = mplib_aux_is_mp(L, 1);
1505 if (mp) {
1506 switch (lua_type(L, 2)) {
1507 case LUA_TNUMBER:
1508 mp_push_pair_value(mp,
1509 luaL_optnumber(L, 2, 0),
1510 luaL_optnumber(L, 3, 0)
1511 );
1512 break;
1513 case LUA_TTABLE:
1514 mp_push_pair_value(mp,
1515 lmt_number_from_table(L, 2, 1, 0.0),
1516 lmt_number_from_table(L, 2, 2, 0.0)
1517 );
1518 break;
1519 }
1520 }
1521 return 0;
1522}
1523
1524static int mplib_inject_color(lua_State *L)
1525{
1526 MP mp = mplib_aux_is_mp(L, 1);
1527 if (mp) {
1528 switch (lua_type(L, 2)) {
1529 case LUA_TNUMBER:
1530 mp_push_color_value(mp,
1531 luaL_optnumber(L, 2, 0),
1532 luaL_optnumber(L, 3, 0),
1533 luaL_optnumber(L, 4, 0)
1534 );
1535 break;
1536 case LUA_TTABLE:
1537 mp_push_color_value(mp,
1538 lmt_number_from_table(L, 2, 1, 0.0),
1539 lmt_number_from_table(L, 2, 2, 0.0),
1540 lmt_number_from_table(L, 2, 3, 0.0)
1541 );
1542 break;
1543 }
1544 }
1545 return 0;
1546}
1547
1548static int mplib_inject_cmykcolor(lua_State *L)
1549{
1550 MP mp = mplib_aux_is_mp(L, 1);
1551 if (mp) {
1552 switch (lua_type(L, 2)) {
1553 case LUA_TNUMBER:
1554 mp_push_cmykcolor_value(mp,
1555 luaL_optnumber(L, 2, 0),
1556 luaL_optnumber(L, 3, 0),
1557 luaL_optnumber(L, 4, 0),
1558 luaL_optnumber(L, 5, 0)
1559 );
1560 break;
1561 case LUA_TTABLE:
1562 mp_push_cmykcolor_value(mp,
1563 lmt_number_from_table(L, 2, 1, 0.0),
1564 lmt_number_from_table(L, 2, 2, 0.0),
1565 lmt_number_from_table(L, 2, 3, 0.0),
1566 lmt_number_from_table(L, 2, 4, 0.0)
1567 );
1568 break;
1569 }
1570 }
1571 return 0;
1572}
1573
1574static int mplib_inject_transform(lua_State *L)
1575{
1576 MP mp = mplib_aux_is_mp(L, 1);
1577 if (mp) {
1578 switch (lua_type(L, 2)) {
1579 case LUA_TNUMBER:
1580 mp_push_transform_value(mp,
1581 luaL_optnumber(L, 2, 0),
1582 luaL_optnumber(L, 3, 0),
1583 luaL_optnumber(L, 4, 0),
1584 luaL_optnumber(L, 5, 0),
1585 luaL_optnumber(L, 6, 0),
1586 luaL_optnumber(L, 7, 0)
1587 );
1588 break;
1589 case LUA_TTABLE:
1590 mp_push_transform_value(mp,
1591 lmt_number_from_table(L, 2, 1, 0.0),
1592 lmt_number_from_table(L, 2, 2, 0.0),
1593 lmt_number_from_table(L, 2, 3, 0.0),
1594 lmt_number_from_table(L, 2, 4, 0.0),
1595 lmt_number_from_table(L, 2, 5, 0.0),
1596 lmt_number_from_table(L, 2, 6, 0.0)
1597 );
1598 break;
1599 }
1600 }
1601 return 0;
1602}
1603
1604static int mplib_new(lua_State *L)
1605{
1606 MP *mpud = lua_newuserdatauv(L, sizeof(MP *), 2);
1607 if (mpud) {
1608 MP mp = NULL;
1609 struct MP_options *options = mp_options();
1610 lua_Number bendtolerance = default_bend_tolerance;
1611 lua_Number movetolerance = default_move_tolerance;
1612 options->userdata = (void *) L;
1613 options->job_name = NULL;
1614 options->extensions = 0 ;
1615 options->utf8_mode = 0;
1616 options->text_mode = 0;
1617 options->show_mode = 0;
1618 options->halt_on_error = 0;
1619 options->find_file = mplib_aux_find_file;
1620 options->run_script = mplib_aux_run_script;
1621 options->run_internal = mplib_aux_run_internal;
1622 options->run_logger = mplib_aux_run_logger;
1623 options->run_overload = mplib_aux_run_overload;
1624 options->run_error = mplib_aux_run_error;
1625 options->make_text = mplib_aux_make_text;
1626 options->open_file = mplib_aux_open_file;
1627 options->close_file = mplib_aux_close_file;
1628 options->read_file = mplib_aux_read_file;
1629 options->write_file = mplib_aux_write_file;
1630 options->shipout_backend = mplib_shipout_backend;
1631 if (lua_type(L, 1) == LUA_TTABLE) {
1632 lua_pushnil(L);
1633 while (lua_next(L, 1)) {
1634 if (lua_type(L, -2) == LUA_TSTRING) {
1635 const char *s = lua_tostring(L, -2);
1636 if (lua_key_eq(s, random_seed)) {
1637 options->random_seed = (int) lua_tointeger(L, -1);
1638 } else if (lua_key_eq(s, interaction)) {
1639 options->interaction = luaL_checkoption(L, -1, "silent", mplib_interaction_options);
1640 } else if (lua_key_eq(s, job_name)) {
1641
1642 options->job_name = lmt_memory_strdup(lua_tostring(L, -1));
1643 } else if (lua_key_eq(s, find_file)) {
1644 if (mplib_aux_find_file_function(L, options)) {
1645 tex_normal_warning("mplib", "find file: function expected");
1646 }
1647 } else if (lua_key_eq(s, run_script)) {
1648 if (mplib_aux_run_script_function(L, options)) {
1649 tex_normal_warning("mplib", "run script: function expected");
1650 }
1651 } else if (lua_key_eq(s, run_internal)) {
1652 if (mplib_aux_run_internal_function(L, options)) {
1653 tex_normal_warning("mplib", "run internal: function expected");
1654 }
1655 } else if (lua_key_eq(s, make_text)) {
1656 if (mplib_aux_make_text_function(L, options)) {
1657 tex_normal_warning("mplib", "make text: function expected");
1658 }
1659 } else if (lua_key_eq(s, extensions)) {
1660 options->extensions = (int) lua_tointeger(L, -1);
1661 } else if (lua_key_eq(s, math_mode)) {
1662 options->math_mode = luaL_checkoption(L, -1, "scaled", mplib_math_options);
1663 } else if (lua_key_eq(s, utf8_mode)) {
1664 options->utf8_mode = (int) lua_toboolean(L, -1);
1665 } else if (lua_key_eq(s, text_mode)) {
1666 options->text_mode = (int) lua_toboolean(L, -1);
1667 } else if (lua_key_eq(s, show_mode)) {
1668 options->show_mode = (int) lua_toboolean(L, -1);
1669 } else if (lua_key_eq(s, halt_on_error)) {
1670 options->halt_on_error = (int) lua_toboolean(L, -1);
1671 } else if (lua_key_eq(s, run_logger)) {
1672 if (mplib_aux_run_logger_function(L, options)) {
1673 tex_normal_warning("mplib", "run logger: function expected");
1674 }
1675 } else if (lua_key_eq(s, run_overload)) {
1676 if (mplib_aux_run_overload_function(L, options)) {
1677 tex_normal_warning("mplib", "run overload: function expected");
1678 }
1679 } else if (lua_key_eq(s, run_error)) {
1680 if (mplib_aux_run_error_function(L, options)) {
1681 tex_normal_warning("mplib", "run error: function expected");
1682 }
1683 } else if (lua_key_eq(s, open_file)) {
1684 if (mplib_aux_open_file_function(L, options)) {
1685 tex_normal_warning("mplib", "open file: function expected");
1686 }
1687 } else if (lua_key_eq(s, bend_tolerance)) {
1688 bendtolerance = lua_tonumber(L, -1);
1689 } else if (lua_key_eq(s, move_tolerance)) {
1690 movetolerance = lua_tonumber(L, -1);
1691 }
1692 }
1693 lua_pop(L, 1);
1694 }
1695 }
1696 if (! options->job_name || ! *(options->job_name)) {
1697 mp_memory_free(options);
1698 tex_normal_warning("mplib", "job_name is not set");
1699 goto BAD;
1700 }
1701 mp = mp_initialize(options);
1702 mp_memory_free(options);
1703 if (mp) {
1704 *mpud = mp;
1705 mplib_aux_set_bend_tolerance(L, bendtolerance);
1706 mplib_aux_set_move_tolerance(L, movetolerance);
1707
1708 lua_get_metatablelua(mplib_instance);
1709 lua_setmetatable(L, -2);
1710 return 1;
1711 }
1712 }
1713 BAD:
1714 lua_pushnil(L);
1715 return 1;
1716}
1717
1718# define mplib_collect_id(id) do { \
1719 if (id) { \
1720 luaL_unref(L, LUA_REGISTRYINDEX, id); \
1721 } \
1722} while(0)
1723
1724static int mplib_instance_collect(lua_State *L)
1725{
1726 MP *mpud = mplib_aux_is_mpud(L, 1);
1727 if (*mpud) {
1728 MP mp = *mpud;
1729 int run_logger_id = (mp)->run_logger_id;
1730 mplib_collect_id((mp)->find_file_id);
1731 mplib_collect_id((mp)->run_script_id);
1732 mplib_collect_id((mp)->run_internal_id);
1733 mplib_collect_id((mp)->run_overload_id);
1734 mplib_collect_id((mp)->run_error_id);
1735 mplib_collect_id((mp)->make_text_id);
1736 mplib_collect_id((mp)->open_file_id);
1737 mp_finish(mp);
1738 *mpud = NULL;
1739 mplib_collect_id(run_logger_id);
1740 }
1741 return 0;
1742}
1743
1744static int mplib_instance_tostring(lua_State *L)
1745{
1746 MP mp = mplib_aux_is_mp(L, 1);
1747 if (mp) {
1748 lua_pushfstring(L, "<mp.instance %p>", mp);
1749 } else {
1750 lua_pushnil(L);
1751 }
1752 return 1;
1753}
1754
1755static int mplib_aux_wrapresults(lua_State *L, mp_run_data *res, int status, lua_Number bendtolerance, lua_Number movetolerance)
1756{
1757 lua_newtable(L);
1758 if (res->edges) {
1759 struct mp_edge_object *p = res->edges;
1760 int i = 1;
1761 lua_push_key(fig);
1762 lua_newtable(L);
1763 while (p) {
1764 struct mp_edge_object **v = lua_newuserdatauv(L, sizeof(struct mp_edge_object *), 2);
1765 *v = p;
1766 mplib_aux_set_bend_tolerance(L, bendtolerance);
1767 mplib_aux_set_move_tolerance(L, movetolerance);
1768
1769 lua_get_metatablelua(mplib_figure);
1770 lua_setmetatable(L, -2);
1771 lua_rawseti(L, -2, i);
1772 i++;
1773 p = p->next;
1774 }
1775 lua_rawset(L,-3);
1776 res->edges = NULL;
1777 }
1778 lua_push_integer_at_key(L, status, status);
1779 return 1;
1780}
1781
1782static int mplib_execute(lua_State *L)
1783{
1784 MP mp = mplib_aux_is_mp(L, 1);
1785 if (mp) {
1786
1787 size_t l = 0;
1788 lua_Number bendtolerance = mplib_aux_get_bend_tolerance(L, 1);
1789 lua_Number movetolerance = mplib_aux_get_move_tolerance(L, 1);
1790 const char *s = lua_isstring(L, 2) ? lua_tolstring(L, 2, &l) : NULL;
1791 int h = mp_execute(mp, s, l);
1792 mp_run_data *res = mp_rundata(mp);
1793 return mplib_aux_wrapresults(L, res, h, bendtolerance, movetolerance);
1794 }
1795 lua_pushnil(L);
1796 return 1;
1797}
1798
1799static int mplib_finish(lua_State *L)
1800{
1801 MP *mpud = mplib_aux_is_mpud(L, 1);
1802 if (*mpud) {
1803 MP mp = *mpud;
1804 lua_Number bendtolerance = mplib_aux_get_bend_tolerance(L, 1);
1805 lua_Number movetolerance = mplib_aux_get_move_tolerance(L, 1);
1806 int h = mp_execute(mp, NULL, 0);
1807 mp_run_data *res = mp_rundata(mp);
1808 int i = mplib_aux_wrapresults(L, res, h, bendtolerance, movetolerance);
1809 mp_finish(mp);
1810 *mpud = NULL;
1811 return i;
1812 } else {
1813 lua_pushnil(L);
1814 }
1815 return 1;
1816}
1817
1818static int mplib_showcontext(lua_State *L)
1819{
1820 MP *mpud = mplib_aux_is_mpud(L, 1);
1821 if (*mpud) {
1822 MP mp = *mpud;
1823 mp_show_context(mp);
1824 }
1825 return 0;
1826}
1827
1828static int mplib_gethashentry(lua_State *L)
1829{
1830 MP *mpud = mplib_aux_is_mpud(L, 1);
1831 if (*mpud) {
1832 MP mp = *mpud;
1833 char *name = (char *) lua_tostring(L, 2);
1834 if (name) {
1835 mp_symbol_entry *s = (mp_symbol_entry *) mp_fetch_symbol(mp, name);
1836 if (s) {
1837 mp_node q = s->type == mp_tag_command ? s->v.data.node : NULL;
1838 lua_pushinteger(L, s->type);
1839 lua_pushinteger(L, s->property);
1840 if (q) {
1841 lua_pushinteger(L, q->type);
1842 return 3;
1843 } else {
1844 return 2;
1845 }
1846 }
1847 }
1848 }
1849 return 0;
1850}
1851
1852static int mplib_gethashentries(lua_State *L)
1853{
1854 MP *mpud = mplib_aux_is_mpud(L, 1);
1855 if (*mpud) {
1856 MP mp = *mpud;
1857 int full = lua_toboolean(L, 2);
1858 if (mp_initialize_symbol_traverse(mp)) {
1859 size_t n = 0;
1860 lua_newtable(L);
1861 while (1) {
1862 mp_symbol_entry *s = (mp_symbol_entry *) mp_fetch_symbol_traverse(mp);
1863 if (s) {
1864 if (full) {
1865 mp_node q = s->type == mp_tag_command ? s->v.data.node : NULL;
1866 lua_createtable(L, (q || s->property == 0x1) ? 4 : 3, 0);
1867 lua_pushinteger(L, s->type);
1868 lua_rawseti(L, -2, 1);
1869 lua_pushinteger(L, s->property);
1870 lua_rawseti(L, -2, 2);
1871 lua_pushlstring(L, (const char *) s->text->str, s->text->len);
1872 lua_rawseti(L, -2, 3);
1873 if (q) {
1874 lua_pushinteger(L, q->type);
1875 lua_rawseti(L, -2, 4);
1876 } else if (s->property == 0x1) {
1877 lua_pushinteger(L, s->v.data.indep.serial);
1878 lua_rawseti(L, -2, 4);
1879 }
1880 } else {
1881 lua_pushlstring(L, (const char *) s->text->str, s->text->len);
1882 }
1883 lua_rawseti(L, -2, ++n);
1884 } else {
1885 break;
1886 }
1887 }
1888 mp_kill_symbol_traverse(mp);
1889 return 1;
1890 }
1891 }
1892 return 0;
1893}
1894
1895static int mplib_version(lua_State *L)
1896{
1897 char *s = mp_metapost_version();
1898 lua_pushstring(L, s);
1899 mp_memory_free(s);
1900 return 1;
1901}
1902
1903static int mplib_getstatistics(lua_State *L)
1904{
1905 MP mp = mplib_aux_is_mp(L, 1);
1906 if (mp) {
1907 lua_createtable(L, 0, 9);
1908 lua_push_integer_at_key(L, memory, mp->var_used);
1909 lua_push_integer_at_key(L, hash, mp->st_count);
1910 lua_push_integer_at_key(L, parameters, mp->max_param_stack);
1911 lua_push_integer_at_key(L, input, mp->max_in_stack);
1912 lua_push_integer_at_key(L, tokens, mp->num_token_nodes);
1913 lua_push_integer_at_key(L, pairs, mp->num_pair_nodes);
1914 lua_push_integer_at_key(L, knots, mp->num_knot_nodes);
1915 lua_push_integer_at_key(L, nodes, mp->num_value_nodes);
1916 lua_push_integer_at_key(L, symbols, mp->num_symbolic_nodes);
1917 lua_push_integer_at_key(L, characters, mp->max_pl_used);
1918 lua_push_integer_at_key(L, strings, mp->max_strs_used);
1919 lua_push_integer_at_key(L, internals, mp->int_ptr);
1920
1921
1922 } else {
1923 lua_pushnil(L);
1924 }
1925 return 1;
1926}
1927
1928static int mplib_getstatus(lua_State *L)
1929{
1930 MP mp = mplib_aux_is_mp(L, 1);
1931 if (mp) {
1932 lua_pushinteger(L, mp->scanner_status);
1933 return 1;
1934 } else {
1935 return 0;
1936 }
1937}
1938
1939static int mplib_aux_set_direction(lua_State *L, MP mp, mp_knot p) {
1940 double direction_x = (double) lua_tonumber(L, -1);
1941 double direction_y = 0;
1942 lua_pop(L, 1);
1943 lua_push_key(direction_y);
1944 if (lua_rawget(L, -2) == LUA_TNUMBER) {
1945 direction_y = (double) lua_tonumber(L, -1);
1946 lua_pop(L, 1);
1947 return mp_set_knot_direction(mp, p, direction_x, direction_y) ? 1 : 0;
1948 } else {
1949 return 0;
1950 }
1951}
1952
1953static int mplib_aux_set_left_curl(lua_State *L, MP mp, mp_knot p) {
1954 double curl = (double) lua_tonumber(L, -1);
1955 lua_pop(L, 1);
1956 return mp_set_knot_left_curl(mp, p, curl) ? 1 : 0;
1957}
1958
1959static int mplib_aux_set_left_tension(lua_State *L, MP mp, mp_knot p) {
1960 double tension = (double) lua_tonumber(L, -1);
1961 lua_pop(L, 1);
1962 return mp_set_knot_left_tension(mp, p, tension) ? 1 : 0;
1963}
1964
1965static int mplib_aux_set_left_control(lua_State *L, MP mp, mp_knot p) {
1966 double x = (double) lua_tonumber(L, -1);
1967 double y = 0;
1968 lua_pop(L, 1);
1969 lua_push_key(left_y);
1970 if (lua_rawget(L, -2) == LUA_TNUMBER) {
1971 y = (double) lua_tonumber(L, -1);
1972 lua_pop(L, 1);
1973 return mp_set_knot_left_control(mp, p, x, y) ? 1 : 0;
1974 } else {
1975 return 0;
1976 }
1977}
1978
1979static int mplib_aux_set_right_curl(lua_State *L, MP mp, mp_knot p) {
1980 double curl = (double) lua_tonumber(L, -1);
1981 lua_pop(L, 1);
1982 return mp_set_knot_right_curl(mp, p, curl) ? 1 : 0;
1983}
1984
1985static int mplib_aux_set_right_tension(lua_State *L, MP mp, mp_knot p) {
1986 double tension = (double) lua_tonumber(L, -1);
1987 lua_pop(L, 1);
1988 return mp_set_knot_right_tension(mp, p, tension) ? 1 : 0;
1989}
1990
1991static int mplib_aux_set_right_control(lua_State *L, MP mp, mp_knot p) {
1992 double x = (double) lua_tonumber(L, -1);
1993 lua_pop(L, 1);
1994 lua_push_key(right_y);
1995 if (lua_rawget(L, -2) == LUA_TNUMBER) {
1996 double y = (double) lua_tonumber(L, -1);
1997 lua_pop(L, 1);
1998 return mp_set_knot_right_control(mp, p, x, y) ? 1 : 0;
1999 } else {
2000 return 0;
2001 }
2002}
2003
2004static int mplib_aux_with_path(lua_State *L, MP mp, int index, int inject, int multiple)
2005{
2006
2007 if (! mp) {
2008 lua_pushboolean(L, 0);
2009 lua_pushstring(L, "valid instance expected");
2010 return 2;
2011 } else if (! lua_istable(L, index) || lua_rawlen(L, index) <= 0) {
2012 lua_pushboolean(L, 0);
2013 lua_pushstring(L, "non empty table expected");
2014 return 2;
2015 } else {
2016 mp_knot p = NULL;
2017 mp_knot q = NULL;
2018 mp_knot first = NULL;
2019 const char *errormsg = NULL;
2020 int cyclic = 0;
2021 int curled = 0;
2022 int solve = 0;
2023 int numpoints = (int) lua_rawlen(L, index);
2024
2028 if (multiple && lua_type(L, index + 1) == LUA_TBOOLEAN) {
2029 cyclic = lua_toboolean(L, index + 1);
2030 } else {
2031 lua_push_key(close);
2032 if (lua_rawget(L, index - 1) == LUA_TBOOLEAN) {
2033 cyclic = lua_toboolean(L, -1);
2034 }
2035 lua_pop(L, 1);
2036 lua_push_key(cycle);
2037 if (lua_rawget(L, index - 1) == LUA_TBOOLEAN) {
2038 cyclic = lua_toboolean(L, -1);
2039 }
2040 lua_pop(L, 1);
2041 }
2042 if (multiple && lua_type(L, index + 2) == LUA_TBOOLEAN) {
2043 curled = lua_toboolean(L, index + 2);
2044 } else {
2045 lua_push_key(curled);
2046 if (lua_rawget(L, index - 1) == LUA_TBOOLEAN) {
2047 curled = lua_toboolean(L, -1);
2048 }
2049 lua_pop(L, 1);
2050 }
2051
2052 if (lua_rawgeti(L, index, 1) == LUA_TTABLE) {
2053 lua_Unsigned len = lua_rawlen(L, -1);
2054 lua_pop(L, 1);
2055 if (len >= 2) {
2056
2057
2058 for (int i = 1; i <= numpoints; i++) {
2059 if (lua_rawgeti(L, index, i) == LUA_TTABLE) {
2060 double x0, y0;
2061 lua_rawgeti(L, -1, 1);
2062 lua_rawgeti(L, -2, 2);
2063 x0 = lua_tonumber(L, -2);
2064 y0 = lua_tonumber(L, -1);
2065 q = p;
2066 p = mp_append_knot_xy(mp, p, x0, y0);
2067 lua_pop(L, 2);
2068 if (p) {
2069 double x1, y1, x2, y2;
2070 if (curled) {
2071 x1 = x0;
2072 y1 = y0;
2073 x2 = x0;
2074 y2 = y0;
2075 } else {
2076 lua_rawgeti(L, -1, 3);
2077 lua_rawgeti(L, -2, 4);
2078 lua_rawgeti(L, -3, 5);
2079 lua_rawgeti(L, -4, 6);
2080 x1 = luaL_optnumber(L, -4, x0);
2081 y1 = luaL_optnumber(L, -3, y0);
2082 x2 = luaL_optnumber(L, -2, x0);
2083 y2 = luaL_optnumber(L, -1, y0);
2084 lua_pop(L, 4);
2085 }
2086 mp_set_knot_left_control(mp, p, x1, y1);
2087 mp_set_knot_right_control(mp, p, x2, y2);
2088 if (! first) {
2089 first = p;
2090 }
2091 } else {
2092 errormsg = "knot creation failure";
2093 goto BAD;
2094 }
2095 }
2096
2097 lua_pop(L, 1);
2098 }
2099 } else if (len > 0) {
2100 errormsg = "messy table";
2101 goto BAD;
2102 } else {
2103 for (int i = 1; i <= numpoints; i++) {
2104 if (lua_rawgeti(L, index, i) == LUA_TTABLE) {
2105
2106 int left_set = 0;
2107 int right_set = 0;
2108 double x_coord, y_coord;
2109 if (! lua_istable(L, -1)) {
2110 errormsg = "wrong argument types";
2111 goto BAD;
2112 }
2113 lua_push_key(x_coord);
2114 if (lua_rawget(L, -2) != LUA_TNUMBER) {
2115 errormsg = "missing x coordinate";
2116 goto BAD;
2117 }
2118 x_coord = (double) lua_tonumber(L, -1);
2119 lua_pop(L, 1);
2120 lua_push_key(y_coord);
2121 if (lua_rawget(L, -2) != LUA_TNUMBER) {
2122 errormsg = "missing y coordinate";
2123 goto BAD;
2124 }
2125 y_coord = (double) lua_tonumber(L, -1);
2126 lua_pop(L, 1);
2127
2128 q = p;
2129 if (q) {
2130
2134 double saved_tension = mp_number_as_double(mp, p->right_tension);
2135 p = mp_append_knot(mp, p, x_coord, y_coord);
2136 if (p) {
2137 mp_set_knot_right_tension(mp, q, saved_tension);
2138 }
2139 } else {
2140 p = mp_append_knot(mp, p, x_coord, y_coord);
2141 }
2142 if (p) {
2143 errormsg = "knot creation failure";
2144 goto BAD;
2145 }
2146
2147 if (! first) {
2148 first = p;
2149 }
2150 lua_push_key(left_curl);
2151 if (lua_rawget(L, -2) != LUA_TNUMBER) {
2152 lua_pop(L, 1);
2153 } else if (! mplib_aux_set_left_curl(L, mp, p)) {
2154 errormsg = "failed to set left curl";
2155 goto BAD;
2156 } else {
2157 left_set = 1;
2158 solve = 1;
2159 }
2160 lua_push_key(left_tension);
2161 if (lua_rawget(L, -2) != LUA_TNUMBER) {
2162 lua_pop(L, 1);
2163 } else if (left_set) {
2164 errormsg = "left side already set";
2165 goto BAD;
2166 } else if (! mplib_aux_set_left_tension(L, mp, p)) {
2167 errormsg = "failed to set left tension";
2168 goto BAD;
2169 } else {
2170 left_set = 1;
2171 solve = 1;
2172 }
2173 lua_push_key(left_x);
2174 if (lua_rawget(L, -2) != LUA_TNUMBER) {
2175 lua_pop(L, 1);
2176 } else if (left_set) {
2177 errormsg = "left side already set";
2178 goto BAD;
2179 } else if (! mplib_aux_set_left_control(L, mp, p)) {
2180 errormsg = "failed to set left control";
2181 goto BAD;
2182 }
2183 lua_push_key(right_curl);
2184 if (lua_rawget(L, -2) != LUA_TNUMBER) {
2185 lua_pop(L, 1);
2186 } else if (! mplib_aux_set_right_curl(L, mp, p)) {
2187 errormsg = "failed to set right curl";
2188 goto BAD;
2189 } else {
2190 right_set = 1;
2191 solve = 1;
2192 }
2193 lua_push_key(right_tension);
2194 if (lua_rawget(L, -2) != LUA_TNUMBER) {
2195 lua_pop(L,1);
2196 } else if (right_set) {
2197 errormsg = "right side already set";
2198 goto BAD;
2199 } else if (! mplib_aux_set_right_tension(L, mp, p)) {
2200 errormsg = "failed to set right tension";
2201 goto BAD;
2202 } else {
2203 right_set = 1;
2204 solve = 1;
2205 }
2206 lua_push_key(right_x);
2207 if (lua_rawget(L, -2) != LUA_TNUMBER) {
2208 lua_pop(L, 1);
2209 } else if (right_set) {
2210 errormsg = "right side already set";
2211 goto BAD;
2212 } else if (! mplib_aux_set_right_control(L, mp, p)) {
2213 errormsg = "failed to set right control";
2214 goto BAD;
2215 }
2216 lua_push_key(direction_x);
2217 if (lua_rawget(L, -2) != LUA_TNUMBER) {
2218 lua_pop(L, 1);
2219 } else if (! mplib_aux_set_direction(L, mp, p)) {
2220 errormsg = "failed to set direction";
2221 goto BAD;
2222 }
2223 }
2224 lua_pop(L, 1);
2225 }
2226 }
2227 }
2228 if (first && p) {
2229
2230 if (cyclic) {
2231 p->right_type = mp_explicit_knot;
2232 first->left_type = mp_explicit_knot;
2233 } else {
2234
2235 p->right_type = mp_endpoint_knot;
2236 first->left_type = mp_endpoint_knot;
2237 }
2238 p->next = first;
2239 if (inject) {
2240 if (solve && ! mp_solve_path(mp, first)) {
2241 tex_normal_warning("lua", "failed to solve the path");
2242 }
2243 mp_push_path_value(mp, first);
2244 return 0;
2245 } else {
2246
2247 if (! mp_solve_path(mp, first)) {
2248 errormsg = "failed to solve the path";
2249 } else {
2250
2251 p = first;
2252 for (int i = 1; i <= numpoints; i++) {
2253 lua_rawgeti(L, -1, i);
2254 lua_push_number_at_key(L, left_x, mp_number_as_double(mp, p->left_x));
2255 lua_push_number_at_key(L, left_y, mp_number_as_double(mp, p->left_y));
2256 lua_push_number_at_key(L, right_x, mp_number_as_double(mp, p->right_x));
2257 lua_push_number_at_key(L, right_y, mp_number_as_double(mp, p->right_y));
2258
2259 lua_push_nil_at_key(L, left_tension);
2260 lua_push_nil_at_key(L, right_tension);
2261 lua_push_nil_at_key(L, left_curl);
2262 lua_push_nil_at_key(L, right_curl);
2263 lua_push_nil_at_key(L, direction_x);
2264 lua_push_nil_at_key(L, direction_y);
2265
2266 lua_push_svalue_at_key(L, left_type, mplib_values_knot[p->left_type]);
2267 lua_push_svalue_at_key(L, right_type, mplib_values_knot[p->right_type]);
2268 lua_pop(L, 1);
2269 p = p->next;
2270 }
2271 lua_pushboolean(L, 1);
2272 return 1;
2273 }
2274 }
2275 } else {
2276 errormsg = "invalid path";
2277 }
2278 BAD:
2279 if (p) {
2280 mp_free_path(mp, p);
2281 }
2282 lua_pushboolean(L, 0);
2283 if (errormsg) {
2284 lua_pushstring(L, errormsg);
2285 return 2;
2286 } else {
2287 return 1;
2288 }
2289 }
2290}
2291
2292static int mplib_solvepath(lua_State *L)
2293{
2294 MP mp = mplib_aux_is_mp(L, 1);
2295 if (mp) {
2296 return mplib_aux_with_path(L, mp, 2, 0, 1);
2297 } else {
2298 return 0;
2299 }
2300}
2301
2302static int mplib_inject_path(lua_State *L)
2303{
2304 MP mp = mplib_aux_is_mp(L, 1);
2305 if (mp) {
2306 return mplib_aux_with_path(L, mp, 2, 1, 1);
2307 } else {
2308 return 0;
2309 }
2310}
2311
2312static int mplib_inject_whatever(lua_State *L)
2313{
2314 MP mp = mplib_aux_is_mp(L, 1);
2315 if (mp) {
2316 mplib_aux_inject_whatever(L, mp, 2);
2317 }
2318 return 0;
2319}
2320
2321
2322
2323static int mplib_figure_collect(lua_State *L)
2324{
2325 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2326 if (*hh) {
2327 mp_gr_toss_objects(*hh);
2328 *hh = NULL;
2329 }
2330 return 0;
2331}
2332
2333static int mplib_figure_objects(lua_State *L)
2334{
2335 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2336 if (*hh) {
2337 int i = 1;
2338 struct mp_graphic_object *p = (*hh)->body;
2339 lua_Number bendtolerance = mplib_aux_get_bend_tolerance(L, 1);
2340 lua_Number movetolerance = mplib_aux_get_move_tolerance(L, 1);
2341 lua_newtable(L);
2342 while (p) {
2343 struct mp_graphic_object **v = lua_newuserdatauv(L, sizeof(struct mp_graphic_object *), 2);
2344 *v = p;
2345 mplib_aux_set_bend_tolerance(L, bendtolerance);
2346 mplib_aux_set_move_tolerance(L, movetolerance);
2347
2348 lua_get_metatablelua(mplib_object);
2349 lua_setmetatable(L, -2);
2350 lua_rawseti(L, -2, i);
2351 i++;
2352 p = p->next;
2353 }
2354
2355 (*hh)->body = NULL;
2356 } else {
2357 lua_pushnil(L);
2358 }
2359 return 1;
2360}
2361
2362static int mplib_figure_stacking(lua_State *L)
2363{
2364 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2365 int stacking = 0;
2366 if (*hh) {
2367 struct mp_graphic_object *p = (*hh)->body;
2368 while (p) {
2369 if (((mp_shape_object *) p)->stacking) {
2370 stacking = 1;
2371 break;
2372 } else {
2373 p = p->next;
2374 }
2375 }
2376 }
2377 lua_pushboolean(L, stacking);
2378 return 1;
2379}
2380
2381static int mplib_figure_tostring(lua_State *L)
2382{
2383 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2384 if (*hh) {
2385 lua_pushfstring(L, "<mp.figure %p>", *hh);
2386 } else {
2387 lua_pushnil(L);
2388 }
2389 return 1;
2390}
2391
2392static int mplib_figure_width(lua_State *L)
2393{
2394 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2395 if (*hh) {
2396 lua_pushnumber(L, (*hh)->width);
2397 } else {
2398 lua_pushnil(L);
2399 }
2400 return 1;
2401}
2402
2403static int mplib_figure_height(lua_State *L)
2404{
2405 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2406 if (*hh) {
2407 lua_pushnumber(L, (*hh)->height);
2408 } else {
2409 lua_pushnil(L);
2410 }
2411 return 1;
2412}
2413
2414static int mplib_figure_depth(lua_State *L)
2415{
2416 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2417 if (*hh) {
2418 lua_pushnumber(L, (*hh)->depth);
2419 } else {
2420 lua_pushnil(L);
2421 }
2422 return 1;
2423}
2424
2425static int mplib_figure_italic(lua_State *L)
2426{
2427 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2428 if (*hh) {
2429 lua_pushnumber(L, (*hh)->italic);
2430 } else {
2431 lua_pushnil(L);
2432 }
2433 return 1;
2434}
2435
2436static int mplib_figure_charcode(lua_State *L)
2437{
2438 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2439 if (*hh) {
2440 lua_pushinteger(L, (lua_Integer) (*hh)->charcode);
2441 } else {
2442 lua_pushnil(L);
2443 }
2444 return 1;
2445}
2446
2447static int mplib_figure_tolerance(lua_State *L)
2448{
2449 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2450 if (*hh) {
2451 lua_pushnumber(L, mplib_aux_get_bend_tolerance(L, 1));
2452 lua_pushnumber(L, mplib_aux_get_move_tolerance(L, 1));
2453 } else {
2454 lua_pushnil(L);
2455 lua_pushnil(L);
2456 }
2457 return 2;
2458}
2459
2460static int mplib_figure_bounds(lua_State *L)
2461{
2462 struct mp_edge_object **hh = mplib_aux_is_figure(L, 1);
2463 lua_createtable(L, 4, 0);
2464 lua_push_number_at_index(L, 1, (*hh)->minx);
2465 lua_push_number_at_index(L, 2, (*hh)->miny);
2466 lua_push_number_at_index(L, 3, (*hh)->maxx);
2467 lua_push_number_at_index(L, 4, (*hh)->maxy);
2468 return 1;
2469}
2470
2471
2472
2473static int mplib_object_collect(lua_State *L)
2474{
2475 struct mp_graphic_object **hh = mplib_aux_is_gr_object(L, 1);
2476 if (*hh) {
2477 mp_gr_toss_object(*hh);
2478 *hh = NULL;
2479 }
2480 return 0;
2481}
2482
2483static int mplib_object_tostring(lua_State *L)
2484{
2485 struct mp_graphic_object **hh = mplib_aux_is_gr_object(L, 1);
2486 lua_pushfstring(L, "<mp.object %p>", *hh);
2487 return 1;
2488}
2489
2490# define pyth(a,b) (sqrt((a)*(a) + (b)*(b)))
2491# define aspect_bound (10.0/65536.0)
2492# define aspect_default 1.0
2493# define eps 0.0001
2494
2495static double mplib_aux_coord_range_x(mp_gr_knot h, double dz)
2496{
2497 double zlo = 0.0;
2498 double zhi = 0.0;
2499 mp_gr_knot f = h;
2500 while (h) {
2501 double z = h->x_coord;
2502 if (z < zlo) {
2503 zlo = z;
2504 } else if (z > zhi) {
2505 zhi = z;
2506 }
2507 z = h->right_x;
2508 if (z < zlo) {
2509 zlo = z;
2510 } else if (z > zhi) {
2511 zhi = z;
2512 }
2513 z = h->left_x;
2514 if (z < zlo) {
2515 zlo = z;
2516 } else if (z > zhi) {
2517 zhi = z;
2518 }
2519 h = h->next;
2520 if (h == f) {
2521 break;
2522 }
2523 }
2524 return (zhi - zlo <= dz) ? aspect_bound : aspect_default;
2525}
2526
2527static double mplib_aux_coord_range_y(mp_gr_knot h, double dz)
2528{
2529 double zlo = 0.0;
2530 double zhi = 0.0;
2531 mp_gr_knot f = h;
2532 while (h) {
2533 double z = h->y_coord;
2534 if (z < zlo) {
2535 zlo = z;
2536 } else if (z > zhi) {
2537 zhi = z;
2538 }
2539 z = h->right_y;
2540 if (z < zlo) {
2541 zlo = z;
2542 } else if (z > zhi) {
2543 zhi = z;
2544 }
2545 z = h->left_y;
2546 if (z < zlo) {
2547 zlo = z;
2548 } else if (z > zhi) {
2549 zhi = z;
2550 }
2551 h = h->next;
2552 if (h == f) {
2553 break;
2554 }
2555 }
2556 return (zhi - zlo <= dz) ? aspect_bound : aspect_default;
2557}
2558
2559static int mplib_object_peninfo(lua_State *L)
2560{
2561 struct mp_graphic_object **hh = mplib_aux_is_gr_object(L, -1);
2562 if (! *hh) {
2563 lua_pushnil(L);
2564 return 1;
2565 } else {
2566 mp_gr_knot p = NULL;
2567 mp_gr_knot path = NULL;
2568 switch ((*hh)->type) {
2569 case mp_fill_code:
2570 case mp_stroked_code:
2571 p = ((mp_shape_object *) (*hh))->pen;
2572 path = ((mp_shape_object *) (*hh))->path;
2573 break;
2574 }
2575 if (! p || ! path) {
2576 lua_pushnil(L);
2577 return 1;
2578 } else {
2579 double wx, wy;
2580 double rx = 1.0, sx = 0.0, sy = 0.0, ry = 1.0, tx = 0.0, ty = 0.0;
2581 double width = 1.0;
2582 double x_coord = p->x_coord;
2583 double y_coord = p->y_coord;
2584 double left_x = p->left_x;
2585 double left_y = p->left_y;
2586 double right_x = p->right_x;
2587 double right_y = p->right_y;
2588 if ((right_x == x_coord) && (left_y == y_coord)) {
2589 wx = fabs(left_x - x_coord);
2590 wy = fabs(right_y - y_coord);
2591 } else {
2592 wx = pyth(left_x - x_coord, right_x - x_coord);
2593 wy = pyth(left_y - y_coord, right_y - y_coord);
2594 }
2595 if ((wy/mplib_aux_coord_range_x(path, wx)) >= (wx/mplib_aux_coord_range_y(path, wy))) {
2596 width = wy;
2597 } else {
2598 width = wx;
2599 }
2600 tx = x_coord;
2601 ty = y_coord;
2602 sx = left_x - tx;
2603 rx = left_y - ty;
2604 ry = right_x - tx;
2605 sy = right_y - ty;
2606 if (width != 1.0) {
2607 if (width == 0.0) {
2608 sx = 1.0;
2609 sy = 1.0;
2610 } else {
2611 rx /= width;
2612 ry /= width;
2613 sx /= width;
2614 sy /= width;
2615 }
2616 }
2617 if (fabs(sx) < eps) {
2618 sx = eps;
2619 }
2620 if (fabs(sy) < eps) {
2621 sy = eps;
2622 }
2623 lua_createtable(L,0,7);
2624 lua_push_number_at_key(L, width, width);
2625 lua_push_number_at_key(L, rx, rx);
2626 lua_push_number_at_key(L, sx, sx);
2627 lua_push_number_at_key(L, sy, sy);
2628 lua_push_number_at_key(L, ry, ry);
2629 lua_push_number_at_key(L, tx, tx);
2630 lua_push_number_at_key(L, ty, ty);
2631 return 1;
2632 }
2633 }
2634}
2635
2636
2637
2638static void mplib_aux_mplib_push_fields(lua_State* L, const char **fields)
2639{
2640 lua_newtable(L);
2641 for (lua_Integer i = 0; fields[i]; i++) {
2642 lua_pushstring(L, fields[i]);
2643 lua_rawseti(L, -2, i + 1);
2644 }
2645}
2646
2647static int mplib_gettype(lua_State *L)
2648{
2649 struct mp_graphic_object **hh = mplib_aux_is_gr_object(L, 1);
2650 if (*hh) {
2651 lua_pushinteger(L, (*hh)->type);
2652 } else {
2653 lua_pushnil(L);
2654 }
2655 return 1;
2656}
2657
2658static int mplib_getobjecttypes(lua_State* L)
2659{
2660 lua_createtable(L, 7, 1);
2661 lua_push_key_at_index(L, fill, mp_fill_code);
2662 lua_push_key_at_index(L, outline, mp_stroked_code);
2663 lua_push_key_at_index(L, start_clip, mp_start_clip_code);
2664 lua_push_key_at_index(L, start_group, mp_start_group_code);
2665 lua_push_key_at_index(L, start_bounds, mp_start_bounds_code);
2666 lua_push_key_at_index(L, stop_clip, mp_stop_clip_code);
2667 lua_push_key_at_index(L, stop_group, mp_stop_group_code);
2668 lua_push_key_at_index(L, stop_bounds, mp_stop_bounds_code);
2669 return 1;
2670}
2671
2672static int mplib_getfields(lua_State *L)
2673{
2674 if (lua_type(L, 1) == LUA_TUSERDATA) {
2675 struct mp_graphic_object **hh = mplib_aux_is_gr_object(L, 1);
2676 if (*hh) {
2677 const char **fields;
2678 switch ((*hh)->type) {
2679 case mp_fill_code : fields = mplib_fill_fields; break;
2680 case mp_stroked_code : fields = mplib_stroked_fields; break;
2681 case mp_start_clip_code : fields = mplib_start_clip_fields; break;
2682 case mp_start_group_code : fields = mplib_start_group_fields; break;
2683 case mp_start_bounds_code: fields = mplib_start_bounds_fields; break;
2684 case mp_stop_clip_code : fields = mplib_stop_clip_fields; break;
2685 case mp_stop_group_code : fields = mplib_stop_group_fields; break;
2686 case mp_stop_bounds_code : fields = mplib_stop_bounds_fields; break;
2687 default : fields = mplib_no_fields; break;
2688 }
2689 mplib_aux_mplib_push_fields(L, fields);
2690 } else {
2691 lua_pushnil(L);
2692 }
2693 } else {
2694 lua_createtable(L, 8, 0);
2695 mplib_aux_mplib_push_fields(L, mplib_fill_fields); lua_rawseti(L, -2, mp_fill_code);
2696 mplib_aux_mplib_push_fields(L, mplib_stroked_fields); lua_rawseti(L, -2, mp_stroked_code);
2697 mplib_aux_mplib_push_fields(L, mplib_start_clip_fields); lua_rawseti(L, -2, mp_start_clip_code);
2698 mplib_aux_mplib_push_fields(L, mplib_start_group_fields); lua_rawseti(L, -2, mp_start_group_code);
2699 mplib_aux_mplib_push_fields(L, mplib_start_bounds_fields); lua_rawseti(L, -2, mp_start_bounds_code);
2700 mplib_aux_mplib_push_fields(L, mplib_stop_clip_fields); lua_rawseti(L, -2, mp_stop_clip_code);
2701 mplib_aux_mplib_push_fields(L, mplib_stop_group_fields); lua_rawseti(L, -2, mp_stop_group_code);
2702 mplib_aux_mplib_push_fields(L, mplib_stop_bounds_fields); lua_rawseti(L, -2, mp_stop_bounds_code);
2703 }
2704 return 1;
2705}
2706
2707static int mplib_push_values(lua_State *L, const char *list[])
2708{
2709 lua_newtable(L);
2710 for (lua_Integer i = 0; list[i]; i++) {
2711 lua_pushstring(L, list[i]);
2712 lua_rawseti(L, -2, i);
2713 }
2714 return 1;
2715}
2716
2717static int mplib_getcodes(lua_State *L)
2718{
2719 return mplib_push_values(L, mplib_codes);
2720}
2721
2722static int mplib_gettypes(lua_State *L)
2723{
2724 return mplib_push_values(L, mplib_types);
2725}
2726
2727static int mplib_getcolormodels(lua_State *L)
2728{
2729 return mplib_push_values(L, mplib_colormodels);
2730}
2731
2732static int mplib_getstates(lua_State *L)
2733{
2734 return mplib_push_values(L, mplib_states);
2735}
2736
2737static int mplib_getcallbackstate(lua_State *L)
2738{
2739 lua_createtable(L, 0, 5);
2740 lua_push_integer_at_key(L, file, mplib_state.file_callbacks);
2741 lua_push_integer_at_key(L, text, mplib_state.text_callbacks);
2742 lua_push_integer_at_key(L, script, mplib_state.script_callbacks);
2743 lua_push_integer_at_key(L, log, mplib_state.log_callbacks);
2744 lua_push_integer_at_key(L, overloaded, mplib_state.overload_callbacks);
2745 lua_push_integer_at_key(L, error, mplib_state.error_callbacks);
2746 lua_push_integer_at_key(L, warning, mplib_state.warning_callbacks);
2747 lua_push_integer_at_key(L, count,
2748 mplib_state.file_callbacks + mplib_state.text_callbacks
2749 + mplib_state.script_callbacks + mplib_state.log_callbacks
2750 + mplib_state.overload_callbacks + mplib_state.error_callbacks
2751 + mplib_state.warning_callbacks
2752 );
2753 return 1;
2754}
2755
2756
2760
2761static void mplib_aux_push_color(lua_State *L, struct mp_graphic_object *p)
2762{
2763 if (p) {
2764 int object_color_model;
2765 mp_color object_color;
2766 switch (p->type) {
2767 case mp_fill_code:
2768 case mp_stroked_code:
2769 {
2770 mp_shape_object *h = (mp_shape_object *) p;
2771 object_color_model = h->color_model;
2772 object_color = h->color;
2773 }
2774 break;
2775 default:
2776 object_color_model = mp_no_model;
2777 object_color = (mp_color) { { 0.0 }, { 0.0 }, { 0.0 }, { 0.0 } };
2778 break;
2779 }
2780 switch (object_color_model) {
2781 case mp_grey_model:
2782 lua_createtable(L, 1, 0);
2783 lua_push_number_at_index(L, 1, object_color.gray);
2784 break;
2785 case mp_rgb_model:
2786 lua_createtable(L, 3, 0);
2787 lua_push_number_at_index(L, 1, object_color.red);
2788 lua_push_number_at_index(L, 2, object_color.green);
2789 lua_push_number_at_index(L, 3, object_color.blue);
2790 break;
2791 case mp_cmyk_model:
2792 lua_createtable(L, 4, 0);
2793 lua_push_number_at_index(L, 1, object_color.cyan);
2794 lua_push_number_at_index(L, 2, object_color.magenta);
2795 lua_push_number_at_index(L, 3, object_color.yellow);
2796 lua_push_number_at_index(L, 4, object_color.black);
2797 break;
2798 default:
2799 lua_pushnil(L);
2800 break;
2801 }
2802 } else {
2803 lua_pushnil(L);
2804 }
2805}
2806
2807
2808
2809static void mplib_aux_push_dash(lua_State *L, struct mp_shape_object *h)
2810{
2811 if (h && h->dash) {
2812 mp_dash_object *d = h->dash;
2813 lua_newtable(L);
2814 lua_push_number_at_key(L, offset, d->offset);
2815 if (d->array) {
2816 int i = 0;
2817 lua_push_key(dashes);
2818 lua_newtable(L);
2819 while (*(d->array + i) != -1) {
2820 double ds = *(d->array + i);
2821 lua_pushnumber(L, ds);
2822 i++;
2823 lua_rawseti(L, -2, i);
2824 }
2825 lua_rawset(L, -3);
2826 }
2827 } else {
2828 lua_pushnil(L);
2829 }
2830}
2831
2832static void mplib_aux_shape(lua_State *L, const char *s, struct mp_shape_object *h, lua_Number bendtolerance, lua_Number movetolerance)
2833{
2834 if (lua_key_eq(s, path)) {
2835 mplib_aux_push_path(L, h->path, MPLIB_PATH, bendtolerance, movetolerance);
2836 } else if (lua_key_eq(s, htap)) {
2837 mplib_aux_push_path(L, h->htap, MPLIB_PATH, bendtolerance, movetolerance);
2838 } else if (lua_key_eq(s, pen)) {
2839 mplib_aux_push_path(L, h->pen, MPLIB_PEN, bendtolerance, movetolerance);
2840
2841 mplib_aux_push_pentype(L, h->pen);
2842 } else if (lua_key_eq(s, color)) {
2843 mplib_aux_push_color(L, (mp_graphic_object *) h);
2844 } else if (lua_key_eq(s, linejoin)) {
2845 lua_pushnumber(L, (lua_Number) h->linejoin);
2846 } else if (lua_key_eq(s, linecap)) {
2847 lua_pushnumber(L, (lua_Number) h->linecap);
2848
2849
2850 } else if (lua_key_eq(s, miterlimit)) {
2851 lua_pushnumber(L, h->miterlimit);
2852 } else if (lua_key_eq(s, prescript)) {
2853 lua_pushlstring(L, h->pre_script, h->pre_length);
2854 } else if (lua_key_eq(s, postscript)) {
2855 lua_pushlstring(L, h->post_script, h->post_length);
2856 } else if (lua_key_eq(s, dash)) {
2857 mplib_aux_push_dash(L, h);
2858 } else {
2859 lua_pushnil(L);
2860 }
2861}
2862
2863static void mplib_aux_start(lua_State *L, const char *s, struct mp_start_object *h, lua_Number bendtolerance, lua_Number movetolerance)
2864{
2865 if (lua_key_eq(s, path)) {
2866 mplib_aux_push_path(L, h->path, MPLIB_PATH, bendtolerance, movetolerance);
2867 } else if (lua_key_eq(s, prescript)) {
2868 lua_pushlstring(L, h->pre_script, h->pre_length);
2869 } else if (lua_key_eq(s, postscript)) {
2870 lua_pushlstring(L, h->post_script, h->post_length);
2871
2872
2873 } else {
2874 lua_pushnil(L);
2875 }
2876}
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887static int mplib_object_index(lua_State *L)
2888{
2889 struct mp_graphic_object **hh = mplib_aux_is_gr_object(L, 1);
2890 if (*hh) {
2891 struct mp_graphic_object *h = *hh;
2892 const char *s = lua_tostring(L, 2);
2893
2894 if (lua_key_eq(s, type)) {
2895 lua_push_key_by_index(mplib_values_type[h->type]);
2896 } else if (lua_key_eq(s, stacking)) {
2897 lua_pushinteger(L, (lua_Integer) h->stacking);
2898 } else {
2899 lua_Number bendtolerance = mplib_aux_get_bend_tolerance(L, 1);
2900 lua_Number movetolerance = mplib_aux_get_move_tolerance(L, 1);
2901
2902 switch (h->type) {
2903 case mp_fill_code:
2904 case mp_stroked_code:
2905 mplib_aux_shape(L, s, (mp_shape_object *) h, bendtolerance, movetolerance);
2906 break;
2907 case mp_start_clip_code:
2908 case mp_start_group_code:
2909 case mp_start_bounds_code:
2910 mplib_aux_start(L, s, (mp_start_object *) h, bendtolerance, movetolerance);
2911 break;
2912
2913
2914
2915
2916
2917 default:
2918 lua_pushnil(L);
2919 break;
2920 }
2921 }
2922 } else {
2923 lua_pushnil(L);
2924 }
2925 return 1;
2926}
2927
2928
2929
2930static int mplib_expand_tex(lua_State *L)
2931{
2932 MP mp = mplib_aux_is_mp(L, 1);
2933 if (mp) {
2934 int kind = lmt_tointeger(L, 2);
2935 halfword tail = null;
2936 halfword head = lmt_macro_to_tok(L, 3, &tail);
2937 if (head) {
2938 switch (kind) {
2939 case lua_value_none_code:
2940 case lua_value_dimension_code:
2941 {
2942 halfword value = 0;
2943 halfword space = tex_get_available_token(space_token);
2944 halfword relax = tex_get_available_token(deep_frozen_relax_token);
2945 token_link(tail) = space;
2946 token_link(space) = relax;
2947 tex_begin_inserted_list(head);
2948 lmt_error_state.intercept = 1;
2949 lmt_error_state.last_intercept = 0;
2950 value = tex_scan_dimension(0, 0, 0, 0, NULL);
2951 lmt_error_state.intercept = 0;
2952 while (cur_tok != deep_frozen_relax_token) {
2953 tex_get_token();
2954 }
2955 if (! lmt_error_state.last_intercept) {
2956 mp_push_numeric_value(mp, (double) value * (7200.0/7227.0) / 65536.0);
2957 break;
2958 } else if (kind == lua_value_none_code) {
2959 head = lmt_macro_to_tok(L, 3, &tail);
2960 goto TRYAGAIN;
2961 } else {
2962
2963
2964 lua_pushboolean(L, 0);
2965 return 1;
2966 }
2967 }
2968 case lua_value_integer_code:
2969 case lua_value_cardinal_code:
2970 case lua_value_boolean_code:
2971 TRYAGAIN:
2972 {
2973 halfword value = 0;
2974 halfword space = tex_get_available_token(space_token);
2975 halfword relax = tex_get_available_token(deep_frozen_relax_token);
2976 token_link(tail) = space;
2977 token_link(space) = relax;
2978 tex_begin_inserted_list(head);
2979 lmt_error_state.intercept = 1;
2980 lmt_error_state.last_intercept = 0;
2981 value = tex_scan_integer(0, NULL);
2982 lmt_error_state.intercept = 0;
2983 while (cur_tok != deep_frozen_relax_token) {
2984 tex_get_token();
2985 }
2986 if (lmt_error_state.last_intercept) {
2987
2988
2989 lua_pushboolean(L, 0);
2990 return 1;
2991 } else if (kind == lua_value_boolean_code) {
2992 mp_push_boolean_value(mp, value);
2993 break;
2994 } else {
2995 mp_push_numeric_value(mp, value);
2996 break;
2997 }
2998 }
2999 default:
3000
3001 {
3002 int len = 0;
3003 const char *str = (const char *) lmt_get_expansion(head, &len);
3004 mp_push_string_value(mp, str, str ? len : 0);
3005 break;
3006 }
3007 }
3008 }
3009 }
3010 lua_pushboolean(L, 1);
3011 return 1;
3012}
3013
3014
3015
3016static const struct luaL_Reg mplib_instance_metatable[] = {
3017 { "__gc", mplib_instance_collect },
3018 { "__tostring", mplib_instance_tostring },
3019 { NULL, NULL },
3020};
3021
3022static const struct luaL_Reg mplib_figure_metatable[] = {
3023 { "__gc", mplib_figure_collect },
3024 { "__tostring", mplib_figure_tostring },
3025 { "objects", mplib_figure_objects },
3026 { "boundingbox", mplib_figure_bounds },
3027 { "width", mplib_figure_width },
3028 { "height", mplib_figure_height },
3029 { "depth", mplib_figure_depth },
3030 { "italic", mplib_figure_italic },
3031 { "charcode", mplib_figure_charcode },
3032 { "tolerance", mplib_figure_tolerance },
3033 { "stacking", mplib_figure_stacking },
3034 { NULL, NULL },
3035};
3036
3037static const struct luaL_Reg mplib_object_metatable[] = {
3038 { "__gc", mplib_object_collect },
3039 { "__tostring", mplib_object_tostring },
3040 { "__index", mplib_object_index },
3041 { NULL, NULL },
3042};
3043
3044static const struct luaL_Reg mplib_instance_functions_list[] = {
3045 { "execute", mplib_execute },
3046 { "finish", mplib_finish },
3047 { "getstatistics", mplib_getstatistics },
3048 { "getstatus", mplib_getstatus },
3049 { "solvepath", mplib_solvepath },
3050 { NULL, NULL },
3051};
3052
3053static const struct luaL_Reg mplib_functions_list[] = {
3054 { "new", mplib_new },
3055 { "version", mplib_version },
3056
3057 { "getfields", mplib_getfields },
3058 { "gettype", mplib_gettype },
3059 { "gettypes", mplib_gettypes },
3060 { "getcolormodels", mplib_getcolormodels },
3061 { "getcodes", mplib_getcodes },
3062 { "getstates", mplib_getstates },
3063 { "getobjecttypes", mplib_getobjecttypes },
3064 { "getcallbackstate", mplib_getcallbackstate },
3065
3066 { "settolerance", mplib_set_tolerance },
3067 { "gettolerance", mplib_get_tolerance },
3068
3069 { "execute", mplib_execute },
3070 { "finish", mplib_finish },
3071 { "showcontext", mplib_showcontext },
3072 { "gethashentries", mplib_gethashentries },
3073 { "gethashentry", mplib_gethashentry },
3074 { "getstatistics", mplib_getstatistics },
3075 { "getstatus", mplib_getstatus },
3076 { "solvepath", mplib_solvepath },
3077
3078 { "peninfo", mplib_object_peninfo },
3079
3080 { "scannext", mplib_scan_next },
3081 { "scanexpression", mplib_scan_expression },
3082 { "scantoken", mplib_scan_token },
3083 { "scansymbol", mplib_scan_symbol },
3084 { "scanproperty", mplib_scan_property },
3085 { "scannumeric", mplib_scan_numeric },
3086 { "scannumber", mplib_scan_numeric },
3087 { "scaninteger", mplib_scan_integer },
3088 { "scanboolean", mplib_scan_boolean },
3089 { "scanstring", mplib_scan_string },
3090 { "scanpair", mplib_scan_pair },
3091 { "scancolor", mplib_scan_color },
3092 { "scancmykcolor", mplib_scan_cmykcolor },
3093 { "scantransform", mplib_scan_transform },
3094 { "scanpath", mplib_scan_path },
3095 { "scanpen", mplib_scan_pen },
3096
3097 { "skiptoken", mplib_skip_token },
3098
3099 { "injectnumeric", mplib_inject_numeric },
3100 { "injectnumber", mplib_inject_numeric },
3101 { "injectinteger", mplib_inject_integer },
3102 { "injectboolean", mplib_inject_boolean },
3103 { "injectstring", mplib_inject_string },
3104 { "injectpair", mplib_inject_pair },
3105 { "injectcolor", mplib_inject_color },
3106 { "injectcmykcolor", mplib_inject_cmykcolor },
3107 { "injecttransform", mplib_inject_transform },
3108 { "injectpath", mplib_inject_path },
3109 { "injectwhatever", mplib_inject_whatever },
3110
3111 { "expandtex", mplib_expand_tex },
3112
3113 { NULL, NULL },
3114};
3115
3116int luaopen_mplib(lua_State *L)
3117{
3118 mplib_aux_initialize_lua(L);
3119
3120 luaL_newmetatable(L, MP_METATABLE_OBJECT);
3121 lua_pushvalue(L, -1);
3122 lua_setfield(L, -2, "__index");
3123 luaL_setfuncs(L, mplib_object_metatable, 0);
3124 luaL_newmetatable(L, MP_METATABLE_FIGURE);
3125 lua_pushvalue(L, -1);
3126 lua_setfield(L, -2, "__index");
3127 luaL_setfuncs(L, mplib_figure_metatable, 0);
3128 luaL_newmetatable(L, MP_METATABLE_INSTANCE);
3129 lua_pushvalue(L, -1);
3130 lua_setfield(L, -2, "__index");
3131 luaL_setfuncs(L, mplib_instance_metatable, 0);
3132 luaL_setfuncs(L, mplib_instance_functions_list, 0);
3133 lua_newtable(L);
3134 luaL_setfuncs(L, mplib_functions_list, 0);
3135 return 1;
3136}
3137 |