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