From a7c1c3550394f81ffbf103efeb79ec02109e8bd2 Mon Sep 17 00:00:00 2001 From: luigi Date: Sat, 3 May 2014 15:24:48 +0000 Subject: [PATCH] update mplib to connect with the Lua interpreter git-svn-id: https://foundry.supelec.fr/svn/luatex/trunk@4998 0b2b3880-5936-4365-a048-eb17d2e5a6bf --- source/texk/web2c/mplibdir/lmplib.c | 3421 +- source/texk/web2c/mplibdir/mp.w | 69152 +++++++++++++++++----------------- 2 files changed, 36405 insertions(+), 36168 deletions(-) diff --git a/source/texk/web2c/mplibdir/lmplib.c b/source/texk/web2c/mplibdir/lmplib.c index ae287fe5b..a12c9db53 100644 --- a/source/texk/web2c/mplibdir/lmplib.c +++ b/source/texk/web2c/mplibdir/lmplib.c @@ -1,1645 +1,1776 @@ -/* lmplib.c - - Copyright 2012 Taco Hoekwater - - This file is part of the MetaPost tarball, but belongs to LuaTeX. - - LuaTeX is free software; you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by the Free - Software Foundation; either version 3 of the License, or (at your - option) any later version. - - LuaTeX is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - License for more details. - - You should have received a copy of the GNU Lesser General Public License along - with LuaTeX; if not, see . */ - -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include /* temporary */ - -#ifndef pdfTeX -# include -# include -# include -#else -# include "lua.h" -# include "lauxlib.h" -# include "lualib.h" -#define luaL_reg luaL_Reg -#define lua_objlen lua_rawlen -#endif - -#include "mplib.h" -#include "mplibps.h" -#include "mplibsvg.h" -#include "mplibpng.h" - - /*@unused@*/ static const char _svn_version[] = - "$Id: lmplib.c 1962 2014-03-11 13:18:08Z taco $"; - -int luaopen_mplib(lua_State * L); /* forward */ - -/* metatable identifiers and tests */ - -#define MPLIB_METATABLE "MPlib.meta" -#define MPLIB_FIG_METATABLE "MPlib.fig" -#define MPLIB_GR_METATABLE "MPlib.gr" - -#define is_mp(L,b) (MP *)luaL_checkudata(L,b,MPLIB_METATABLE) -#define is_fig(L,b) (struct mp_edge_object **)luaL_checkudata(L,b,MPLIB_FIG_METATABLE) -#define is_gr_object(L,b) (struct mp_graphic_object **)luaL_checkudata(L,b,MPLIB_GR_METATABLE) - -/* Lua string pre-hashing */ - -#define mplib_init_S(a) do { \ - lua_pushliteral(L,#a); \ - mplib_##a##_ptr = lua_tostring(L,-1); \ - mplib_##a##_index = luaL_ref (L,LUA_REGISTRYINDEX); \ - } while (0) - -#define mplib_push_S(a) do { \ - lua_rawgeti(L,LUA_REGISTRYINDEX,mplib_##a##_index); \ - } while (0) - -#define mplib_is_S(a,i) (mplib_##a##_ptr==lua_tostring(L,i)) - -#define mplib_make_S(a) \ - static int mplib_##a##_index = 0; \ - static const char *mplib_##a##_ptr = NULL - -static int mplib_type_Ses[mp_special_code + 1] = { 0 }; /* [0] is not used */ - -mplib_make_S(fill); -mplib_make_S(outline); -mplib_make_S(text); -mplib_make_S(special); -mplib_make_S(start_bounds); -mplib_make_S(stop_bounds); -mplib_make_S(start_clip); -mplib_make_S(stop_clip); - -mplib_make_S(left_type); -mplib_make_S(right_type); -mplib_make_S(x_coord); -mplib_make_S(y_coord); -mplib_make_S(left_x); -mplib_make_S(left_y); -mplib_make_S(right_x); -mplib_make_S(right_y); -mplib_make_S(left_tension); -mplib_make_S(right_tension); -mplib_make_S(left_curl); -mplib_make_S(right_curl); -mplib_make_S(direction_x); -mplib_make_S(direction_y); - -mplib_make_S(color); -mplib_make_S(dash); -mplib_make_S(depth); -mplib_make_S(dsize); -mplib_make_S(font); -mplib_make_S(height); -mplib_make_S(htap); -mplib_make_S(linecap); -mplib_make_S(linejoin); -mplib_make_S(miterlimit); -mplib_make_S(path); -mplib_make_S(pen); -mplib_make_S(postscript); -mplib_make_S(prescript); -mplib_make_S(transform); -mplib_make_S(type); -mplib_make_S(width); - -static void mplib_init_Ses(lua_State * L) -{ - mplib_init_S(fill); - mplib_init_S(outline); - mplib_init_S(text); - mplib_init_S(start_bounds); - mplib_init_S(stop_bounds); - mplib_init_S(start_clip); - mplib_init_S(stop_clip); - mplib_init_S(special); - - mplib_type_Ses[mp_fill_code] = mplib_fill_index; - mplib_type_Ses[mp_stroked_code] = mplib_outline_index; - mplib_type_Ses[mp_text_code] = mplib_text_index; - mplib_type_Ses[mp_start_bounds_code] = mplib_start_bounds_index; - mplib_type_Ses[mp_stop_bounds_code] = mplib_stop_bounds_index; - mplib_type_Ses[mp_start_clip_code] = mplib_start_clip_index; - mplib_type_Ses[mp_stop_clip_code] = mplib_stop_clip_index; - mplib_type_Ses[mp_special_code] = mplib_special_index; - - mplib_init_S(left_type); - mplib_init_S(right_type); - mplib_init_S(x_coord); - mplib_init_S(y_coord); - mplib_init_S(left_x); - mplib_init_S(left_y); - mplib_init_S(right_x); - mplib_init_S(right_y); - mplib_init_S(left_tension); - mplib_init_S(right_tension); - mplib_init_S(left_curl); - mplib_init_S(right_curl); - mplib_init_S(direction_x); - mplib_init_S(direction_y); - - mplib_init_S(color); - mplib_init_S(dash); - mplib_init_S(depth); - mplib_init_S(dsize); - mplib_init_S(font); - mplib_init_S(height); - mplib_init_S(htap); - mplib_init_S(linecap); - mplib_init_S(linejoin); - mplib_init_S(miterlimit); - mplib_init_S(path); - mplib_init_S(pen); - mplib_init_S(postscript); - mplib_init_S(prescript); - mplib_init_S(transform); - mplib_init_S(type); - mplib_init_S(width); -} - - -/* Enumeration arrays to map MPlib enums to Lua strings */ - -static const char *math_options[] = - { "scaled", "double", "binary", "decimal", NULL }; - -static const char *interaction_options[] = - { "unknown", "batch", "nonstop", "scroll", "errorstop", NULL }; - -static const char *mplib_filetype_names[] = -{ "term", "error", "mp", "log", "ps", "png", "mem", "tfm", "map", "pfb", "enc", NULL }; - -static const char *knot_type_enum[] = - { "endpoint", "explicit", "given", "curl", "open", "end_cycle" }; - -static const char *fill_fields[] = - { "type", "path", "htap", "pen", "color", "linejoin", "miterlimit", - "prescript", "postscript", NULL }; - -static const char *stroked_fields[] = - { "type", "path", "pen", "color", "linejoin", "miterlimit", "linecap", - "dash", "prescript", "postscript", NULL }; - -static const char *text_fields[] = - { "type", "text", "dsize", "font", "color", "width", "height", "depth", - "transform", "prescript", "postscript", NULL }; - -static const char *special_fields[] = - { "type", "prescript", NULL }; - -static const char *start_bounds_fields[] = - { "type", "path", NULL }; - -static const char *start_clip_fields[] = - { "type", "path", NULL }; - -static const char *stop_bounds_fields[] = - { "type", NULL }; - -static const char *stop_clip_fields[] = - { "type", NULL }; - -static const char *no_fields[] = - { NULL }; - - -/* The list of supported MPlib options (not all make sense) */ - -typedef enum { - P_ERROR_LINE, P_MAX_LINE, P_RANDOM_SEED, P_MATH_MODE, - P_INTERACTION, P_INI_VERSION, P_MEM_NAME, P_JOB_NAME, P_FIND_FILE, - P__SENTINEL } mplib_parm_idx; - -typedef struct { - const char *name; /* parameter name */ - mplib_parm_idx idx; /* parameter index */ -} mplib_parm_struct; - -static mplib_parm_struct mplib_parms[] = { - {"error_line", P_ERROR_LINE }, - {"print_line", P_MAX_LINE }, - {"random_seed", P_RANDOM_SEED }, - {"interaction", P_INTERACTION }, - {"job_name", P_JOB_NAME }, - {"find_file", P_FIND_FILE }, - {"math_mode", P_MATH_MODE }, - {NULL, P__SENTINEL } -}; - - -/* Start by defining the needed callback routines for the library */ - -static char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ftype) -{ - lua_State *L = (lua_State *)mp_userdata(mp); - lua_checkstack(L, 4); - lua_getfield(L, LUA_REGISTRYINDEX, "mplib_file_finder"); - if (lua_isfunction(L, -1)) { - char *s = NULL; - const char *x = NULL; - lua_pushstring(L, fname); - lua_pushstring(L, fmode); - if (ftype >= mp_filetype_text) { - lua_pushnumber(L, (lua_Number)(ftype - mp_filetype_text)); - } else { - lua_pushstring(L, mplib_filetype_names[ftype]); - } - if (lua_pcall(L, 3, 1, 0) != 0) { - fprintf(stdout, "Error in mp.find_file: %s\n", lua_tostring(L, -1)); - return NULL; - } - x = lua_tostring(L, -1); - if (x != NULL) - s = strdup(x); - lua_pop(L, 1); /* pop the string */ - return s; - } else { - lua_pop(L, 1); - } - if (fmode[0] != 'r' || (!access(fname, R_OK)) || ftype) { - return strdup(fname); - } - return NULL; -} - -static int mplib_find_file_function(lua_State * L) -{ - if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) { - return 1; /* error */ - } - lua_pushstring(L, "mplib_file_finder"); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); - return 0; -} - -#define xfree(A) if ((A)!=NULL) { free((A)); A = NULL; } - -static int mplib_new(lua_State * L) -{ - MP *mp_ptr; - mp_ptr = lua_newuserdata(L, sizeof(MP *)); - if (mp_ptr) { - int i; - struct MP_options *options = mp_options(); - options->userdata = (void *) L; - options->noninteractive = 1; /* required ! */ - options->find_file = mplib_find_file; - options->print_found_names = 1; - options->ini_version = 1; - if (lua_type(L, 1) == LUA_TTABLE) { - for (i = 0; mplib_parms[i].name != NULL; i++) { - lua_getfield(L, 1, mplib_parms[i].name); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - continue; /* skip unset */ - } - switch (mplib_parms[i].idx) { - case P_ERROR_LINE: - options->error_line = (int)lua_tointeger(L, -1); - if (options->error_line<60) options->error_line =60; - if (options->error_line>250) options->error_line = 250; - options->half_error_line = (options->error_line/2)+10; - break; - case P_MAX_LINE: - options->max_print_line = (int)lua_tointeger(L, -1); - if (options->max_print_line<60) options->max_print_line = 60; - break; - case P_RANDOM_SEED: - options->random_seed = (int)lua_tointeger(L, -1); - break; - case P_INTERACTION: - options->interaction = - luaL_checkoption(L, -1, "errorstopmode", - interaction_options); - break; - case P_MATH_MODE: - options->math_mode = - luaL_checkoption(L, -1, "scaled", - math_options); - break; - case P_JOB_NAME: - options->job_name = strdup(lua_tostring(L, -1)); - break; - case P_FIND_FILE: - if (mplib_find_file_function(L)) { /* error here */ - fprintf(stdout, - "Invalid arguments to mp.new({find_file=...})\n"); - } - break; - default: - break; - } - lua_pop(L, 1); - } - } - *mp_ptr = mp_initialize(options); - xfree(options->command_line); - xfree(options->mem_name); - free(options); - if (*mp_ptr) { - luaL_getmetatable(L, MPLIB_METATABLE); - lua_setmetatable(L, -2); - return 1; - } - } - lua_pushnil(L); - return 1; -} - -static int mplib_collect(lua_State * L) -{ - MP *mp_ptr = is_mp(L, 1); - if (*mp_ptr != NULL) { - (void)mp_finish(*mp_ptr); - *mp_ptr = NULL; - } - return 0; -} - -static int mplib_tostring(lua_State * L) -{ - MP *mp_ptr = is_mp(L, 1); - if (*mp_ptr != NULL) { - (void)lua_pushfstring(L, "", *mp_ptr); - return 1; - } - return 0; -} - -static int mplib_wrapresults(lua_State * L, mp_run_data *res, int status) -{ - lua_checkstack(L, 5); - lua_newtable(L); - if (res->term_out.used != 0) { - lua_pushlstring(L, res->term_out.data, res->term_out.used); - lua_setfield(L, -2, "term"); - } - if (res->error_out.used != 0) { - lua_pushlstring(L, res->error_out.data, res->error_out.used); - lua_setfield(L, -2, "error"); - } - if (res->log_out.used != 0) { - lua_pushlstring(L, res->log_out.data, res->log_out.used); - lua_setfield(L, -2, "log"); - } - if (res->edges != NULL) { - struct mp_edge_object **v; - struct mp_edge_object *p = res->edges; - int i = 1; - lua_newtable(L); - while (p != NULL) { - v = lua_newuserdata(L, sizeof(struct mp_edge_object *)); - *v = p; - luaL_getmetatable(L, MPLIB_FIG_METATABLE); - lua_setmetatable(L, -2); - lua_rawseti(L, -2, i); - i++; - p = p->next; - } - lua_setfield(L, -2, "fig"); - res->edges = NULL; - } - lua_pushnumber(L, (lua_Number)status); - lua_setfield(L, -2, "status"); - return 1; -} - -static int mplib_execute(lua_State * L) -{ - MP *mp_ptr; - if (lua_gettop(L)!=2) { - lua_pushnil(L); - return 1; - } - mp_ptr = is_mp(L, 1); - if (*mp_ptr != NULL && lua_isstring(L, 2)) { - size_t l; - char *s = xstrdup(lua_tolstring(L, 2, &l)); - int h = mp_execute(*mp_ptr, s, l); - mp_run_data *res = mp_rundata(*mp_ptr); - free(s); - return mplib_wrapresults(L, res, h); - } else { - lua_pushnil(L); - } - return 1; -} - -static int mplib_finish(lua_State * L) -{ - MP *mp_ptr = is_mp(L, 1); - if (*mp_ptr != NULL) { - int i; - int h = mp_execute(*mp_ptr,NULL,0); - mp_run_data *res = mp_rundata(*mp_ptr); - i = mplib_wrapresults(L, res, h); - (void)mp_finish(*mp_ptr); - *mp_ptr = NULL; - return i; - } else { - lua_pushnil(L); - } - return 1; -} - -static int mplib_char_dimension(lua_State * L, int t) -{ - MP *mp_ptr = is_mp(L, 1); - if (*mp_ptr != NULL) { - char *fname = xstrdup(luaL_checkstring(L,2)); - int charnum = (int)luaL_checkinteger(L,3); - if (charnum<0 || charnum>255) { - lua_pushnumber(L, (lua_Number)0); - } else { - lua_pushnumber(L,(lua_Number)mp_get_char_dimension(*mp_ptr,fname,charnum,t)); - } - free(fname); - } else { - lua_pushnumber(L, (lua_Number)0); - } - return 1; -} - -static int mplib_charwidth(lua_State * L) -{ - return mplib_char_dimension(L, 'w'); -} - -static int mplib_chardepth(lua_State * L) -{ - return mplib_char_dimension(L, 'd'); -} - -static int mplib_charheight(lua_State * L) -{ - return mplib_char_dimension(L, 'h'); -} - -static int mplib_version(lua_State * L) -{ - char *s = mp_metapost_version(); - lua_pushstring(L, s); - free(s); - return 1; -} - -static int mplib_statistics(lua_State * L) -{ - MP *mp_ptr = is_mp(L, 1); - if (*mp_ptr != NULL) { - lua_newtable(L); - lua_pushnumber(L, (lua_Number)mp_memory_usage(*mp_ptr)); - lua_setfield(L, -2, "memory"); - lua_pushnumber(L, (lua_Number)mp_hash_usage(*mp_ptr)); - lua_setfield(L, -2, "hash"); - lua_pushnumber(L, (lua_Number)mp_param_usage(*mp_ptr)); - lua_setfield(L, -2, "params"); - lua_pushnumber(L, (lua_Number)mp_open_usage(*mp_ptr)); - lua_setfield(L, -2, "open"); - } else { - lua_pushnil(L); - } - return 1; -} - - -static int set_direction (lua_State * L, MP mp, mp_knot p) { - double direction_x = 0, direction_y = 0; - direction_x = (double)lua_tonumber(L,-1); - lua_pop(L,1); - lua_pushstring(L, "direction_y"); - lua_rawget(L,-2); - if (!lua_isnumber(L,-1)) { - return 0; - } - direction_y = (double)lua_tonumber(L,-1); - lua_pop(L,1); - if (!mp_set_knot_direction(mp, p, direction_x, direction_y)) { - return 0; - } - return 1; -} - -static int set_left_curl (lua_State * L, MP mp, mp_knot p) { - double curl = (double)lua_tonumber(L,-1); - lua_pop(L,1); - if (!mp_set_knot_left_curl(mp, p, curl)) { - return 0; - } - return 1; -} - -static int set_left_tension (lua_State * L, MP mp, mp_knot p) { - double tension = (double)lua_tonumber(L,-1); - lua_pop(L,1); - if (!mp_set_knot_left_tension(mp, p, tension)) { - return 0; - } - return 1; -} - -static int set_left_control (lua_State * L, MP mp, mp_knot p) { - double x, y; - x = (double)lua_tonumber(L,-1); - lua_pop(L,1); - lua_pushstring(L, "left_y"); - lua_rawget(L,-2); - if (!lua_isnumber(L,-1)) { - return 0; - } - y = (double)lua_tonumber(L,-1); - lua_pop(L,1); - if (!mp_set_knot_left_control(mp, p, x, y)) { - return 0; - } - return 1; -} - -static int set_right_curl (lua_State * L, MP mp, mp_knot p) { - double curl = (double)lua_tonumber(L,-1); - lua_pop(L,1); - if (!mp_set_knot_right_curl(mp, p, curl)) { - return 0; - } - return 1; -} - -static int set_right_tension (lua_State * L, MP mp, mp_knot p) { - double tension = (double)lua_tonumber(L,-1); - lua_pop(L,1); - if (!mp_set_knot_right_tension(mp, p, tension)) { - return 0; - } - return 1; -} - -static int set_right_control (lua_State * L, MP mp, mp_knot p) { - double x, y; - x = (double)lua_tonumber(L,-1); - lua_pop(L,1); - lua_pushstring(L, "right_y"); - lua_rawget(L,-2); - if (!lua_isnumber(L,-1)) { - return 0; - } - y = (double)lua_tonumber(L,-1); - lua_pop(L,1); - if (!mp_set_knot_right_control(mp, p, x, y)) { - return 0; - } - return 1; -} - - -#if 0 -#define ROUNDED_ZERO(v) (fabs((v))<0.00001 ? 0 : (v)) -#define PI 3.1415926535897932384626433832795028841971 -#define RADIANS(a) (mp_number_as_double(mp,(a)) / 16.0) * PI/180.0 - -void mp_dump_path (MP mp, mp_knot h) { - mp_knot p, q; - if (h == NULL) return; - p = h; - do { - q=mp_knot_next(mp,p); - if ( (p==NULL)||(q==NULL) ) { - printf("\n???"); - return; /* this won't happen */ - } - printf ("(%g,%g)", mp_number_as_double(mp,mp_knot_x_coord(mp,p)), - mp_number_as_double(mp,mp_knot_y_coord(mp,p))); - switch (mp_knot_right_type(mp,p)) { - case mp_endpoint: - if ( mp_knot_left_type(mp,p)==mp_open ) printf("{open?}"); - if ( (mp_knot_left_type(mp,q)!=mp_endpoint)||(q!=h) ) - q=NULL; /* force an error */ - goto DONE; - break; - case mp_explicit: - printf ("..controls (%g,%g)", - mp_number_as_double(mp,mp_knot_right_x(mp,p)), - mp_number_as_double(mp,mp_knot_right_y(mp,p))); - printf(" and "); - if ( mp_knot_left_type(mp,q)!=mp_explicit ) { - printf("??"); - } else { - printf ("(%g,%g)",mp_number_as_double(mp,mp_knot_left_x(mp,q)), - mp_number_as_double(mp,mp_knot_left_y(mp,q))); - } - goto DONE; - break; - case mp_open: - if ( (mp_knot_left_type(mp,p)!=mp_explicit) - && - (mp_knot_left_type(mp,p)!=mp_open) ) { - printf("{open?}"); - } - break; - case mp_curl: - case mp_given: - if ( mp_knot_left_type(mp,p)==mp_open ) - printf("??"); - if ( mp_knot_right_type(mp,p)==mp_curl ) { - printf("{curl %g}", mp_number_as_double(mp,mp_knot_right_curl(mp,p))); - } else { - double rad = RADIANS(mp_knot_right_curl(mp,p)); - double n_cos = ROUNDED_ZERO(cos(rad)*4096); - double n_sin = ROUNDED_ZERO(sin(rad)*4096); - printf("{%g,%g}", n_cos, n_sin); - } - break; - } - if ( mp_knot_left_type(mp,q)<=mp_explicit ) { - printf("..control?"); /* can't happen */ - } else if ((mp_number_as_double(mp,mp_knot_right_tension(mp,p))!=(1.0))|| - (mp_number_as_double(mp,mp_knot_left_tension(mp,q)) !=(1.0))) { - printf("..tension "); - if ( mp_number_as_double(mp,mp_knot_right_tension(mp,p))<0.0 ) - printf("atleast "); - printf("%g", fabs(mp_number_as_double(mp,mp_knot_right_tension(mp,p)))); - if (mp_number_as_double(mp,mp_knot_right_tension(mp,p)) != - mp_number_as_double(mp,mp_knot_left_tension(mp,q))) { - printf(" and "); - if (mp_number_as_double(mp,mp_knot_left_tension(mp,q))< 0.0) - printf("atleast "); - printf("%g", fabs(mp_number_as_double(mp,mp_knot_left_tension(mp,q)))); - } - } - DONE: - p=q; - if ( p!=h || mp_knot_left_type(mp,h)!=mp_endpoint) { - printf ("\n .."); - if ( mp_knot_left_type(mp,p) == mp_given ) { - double rad = RADIANS(mp_knot_left_curl(mp,p)); - double n_cos = ROUNDED_ZERO(cos(rad)*4096); - double n_sin = ROUNDED_ZERO(sin(rad)*4096); - printf("{%g,%g}", n_cos, n_sin); - } else if ( mp_knot_left_type(mp,p) ==mp_curl ){ - printf("{curl %g}", mp_number_as_double(mp,mp_knot_left_curl(mp,p))); - } - } - } while (p!=h); - if ( mp_knot_left_type(mp,h)!=mp_endpoint ) - printf("cycle"); - printf (";\n"); -} -#endif - -static int mplib_solve_path(lua_State * L) -{ - MP *mp_ptr; - MP mp = NULL; - int cyclic; - const char *errormsg = NULL; - mp_knot p, q, first; - int numpoints, i; - p = q = first = NULL; - if (lua_gettop(L) != 3) { - errormsg = "Wrong number of arguments"; - goto BAD; - } - mp_ptr = is_mp(L, 1); - if (*mp_ptr == NULL || (!lua_istable(L,2)) || lua_objlen(L,2)<=0 || (!lua_isboolean(L,3))) { - errormsg = "Wrong argument types"; - goto BAD; - } - mp = *mp_ptr; - cyclic = lua_toboolean(L,3); - lua_pop(L,1); - - /* build up the path */ - numpoints = lua_objlen(L,2); - - first = p = NULL; - for (i=1;i<=numpoints;i++) { - int left_set = 0, right_set = 0; - double x_coord, y_coord; - lua_rawgeti(L,-1,i); - if (!lua_istable(L,-1)) { errormsg = "Wrong argument types"; goto BAD; } - - lua_pushstring(L, "x_coord"); - lua_rawget(L,-2); - if (!lua_isnumber(L,-1)) { errormsg = "Missing X coordinate"; goto BAD; } - x_coord = (double)lua_tonumber(L,-1); - lua_pop(L,1); - - lua_pushstring(L, "y_coord"); - lua_rawget(L,-2); - if (!lua_isnumber(L,-1)) { errormsg = "Missing y coordinate"; goto BAD; } - y_coord = (double)lua_tonumber(L,-1); - lua_pop(L,1); - - q = p; - if (q!=NULL) { - /* we have to save the right_tension because |mp_append_knot| trashes - it, believing that it is as yet uninitialized */ - double saved_tension = mp_number_as_double(mp, mp_knot_right_tension(mp,p)); - p = mp_append_knot(mp, p, x_coord, y_coord); - if ( ! p ) { errormsg = "knot creation failure"; goto BAD; } - (void)mp_set_knot_right_tension(mp, q, saved_tension); - } else { - p = mp_append_knot(mp, p, x_coord, y_coord); - if ( ! p ) { errormsg = "knot creation failure"; goto BAD; } - } - - if (first == NULL) first = p; - - lua_pushstring(L, "left_curl"); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { - if (!set_left_curl (L, mp, p)) { errormsg = "failed to set left curl"; goto BAD; } - left_set = 1; - } else { - lua_pop(L,1); /* a nil value */ - } - - lua_pushstring(L, "left_tension"); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { - if (left_set) { - errormsg = "Left side already set"; goto BAD; - } else { - if (!set_left_tension(L, mp, p)) { errormsg = "Failed to set left tension"; goto BAD; } - left_set = 1; - } - } else { - lua_pop(L,1); /* a nil value */ - } - - lua_pushstring(L, "left_x"); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { - if (left_set) { - errormsg = "Left side already set"; goto BAD; - } else { - if (!set_left_control(L, mp, p)) { errormsg = "Failed to set left control"; goto BAD; } - } - } else { - lua_pop(L,1); - } - - lua_pushstring(L, "right_curl"); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { - if (!set_right_curl (L, mp, p)) { errormsg = "failed to set right curl"; goto BAD; } - right_set = 1; - } else { - lua_pop(L,1); /* a nil value */ - } - - lua_pushstring(L, "right_tension"); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { - if (right_set) { - errormsg = "Right side already set"; goto BAD; - } else { - if (!set_right_tension(L, mp, p)) { errormsg = "Failed to set right tension"; goto BAD; } - right_set = 1; - } - } else { - lua_pop(L,1); - } - - lua_pushstring(L, "right_x"); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { - if (right_set) { - errormsg = "Right side already set"; goto BAD; - } else { - if (!set_right_control(L, mp, p)) { errormsg = "Failed to set right control"; goto BAD; } - } - } else { - lua_pop(L,1); - } - - lua_pushstring(L, "direction_x"); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { - if (!set_direction (L, mp, p)) { errormsg = "failed to set direction"; goto BAD; } - } else { - lua_pop(L,1); /* a nil value */ - } - - lua_pop(L,1); /* done with this item */ - } - if (cyclic) { - mp_close_path_cycle (mp, p, first); - } else { - mp_close_path (mp, p, first); - } -#if 0 - mp_dump_path(mp,first); -#endif - /* finished reading arguments */ - if (!mp_solve_path(mp,first)) { errormsg = "Failed to solve the path"; goto BAD; } - - /* squeeze the new values back into the table */ - p = first; - for (i=1;i<=numpoints;i++) { - - lua_rawgeti(L,-1, i); - mplib_push_S(left_x); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_left_x(mp, p))); lua_rawset(L,-3); - mplib_push_S(left_y); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_left_y(mp, p))); lua_rawset(L,-3); - mplib_push_S(right_x); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_right_x(mp, p))); lua_rawset(L,-3); - mplib_push_S(right_y); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_right_y(mp, p))); lua_rawset(L,-3); - mplib_push_S(left_tension); lua_pushnil(L); lua_rawset(L,-3); - mplib_push_S(right_tension); lua_pushnil(L); lua_rawset(L,-3); - mplib_push_S(left_curl); lua_pushnil(L); lua_rawset(L,-3); - mplib_push_S(right_curl); lua_pushnil(L); lua_rawset(L,-3); - mplib_push_S(direction_x); lua_pushnil(L); lua_rawset(L,-3); - mplib_push_S(direction_y); lua_pushnil(L); lua_rawset(L,-3); - mplib_push_S(left_type); lua_pushstring(L, knot_type_enum[mp_knot_left_type(mp, p)]); lua_rawset(L, -3); - mplib_push_S(right_type); lua_pushstring(L, knot_type_enum[mp_knot_right_type(mp, p)]); lua_rawset(L, -3); - lua_pop(L,1); - p = mp_knot_next(mp,p); - } - - lua_pushboolean(L, 1); - return 1; -BAD: - if (p != NULL) { - mp_close_path (mp, p, first); - mp_free_path (mp, p); - } - lua_pushboolean(L, 0); - lua_pushstring(L, errormsg); - return 2; -} - -/* figure methods */ - -static int mplib_fig_collect(lua_State * L) -{ - struct mp_edge_object **hh = is_fig(L, 1); - if (*hh != NULL) { - mp_gr_toss_objects(*hh); - *hh = NULL; - } - return 0; -} - -static int mplib_fig_body(lua_State * L) -{ - int i = 1; - struct mp_graphic_object **v; - struct mp_graphic_object *p; - struct mp_edge_object **hh = is_fig(L, 1); - lua_newtable(L); - p = (*hh)->body; - while (p != NULL) { - v = lua_newuserdata(L, sizeof(struct mp_graphic_object *)); - *v = p; - luaL_getmetatable(L, MPLIB_GR_METATABLE); - lua_setmetatable(L, -2); - lua_rawseti(L, -2, i); - i++; - p = p->next; - } - (*hh)->body = NULL; /* prevent double free */ - return 1; -} - -static int mplib_fig_copy_body(lua_State * L) -{ - int i = 1; - struct mp_graphic_object **v; - struct mp_graphic_object *p; - struct mp_edge_object **hh = is_fig(L, 1); - lua_newtable(L); - p = (*hh)->body; - while (p != NULL) { - v = lua_newuserdata(L, sizeof(struct mp_graphic_object *)); - *v = mp_gr_copy_object((*hh)->parent, p); - luaL_getmetatable(L, MPLIB_GR_METATABLE); - lua_setmetatable(L, -2); - lua_rawseti(L, -2, i); - i++; - p = p->next; - } - return 1; -} - - -static int mplib_fig_tostring(lua_State * L) -{ - struct mp_edge_object **hh = is_fig(L, 1); - (void)lua_pushfstring(L, "
", *hh); - return 1; -} - -static int mplib_fig_postscript(lua_State * L) -{ - mp_run_data *res; - struct mp_edge_object **hh = is_fig(L, 1); - int prologues = (int)luaL_optnumber(L, 2, (lua_Number)-1); - int procset = (int)luaL_optnumber(L, 3, (lua_Number)-1); - if (mp_ps_ship_out(*hh, prologues, procset) - && (res = mp_rundata((*hh)->parent)) - && (res->ship_out.size != 0)) { - lua_pushstring(L, res->ship_out.data); - } else { - lua_pushnil(L); - } - return 1; -} - -static int mplib_fig_svg(lua_State * L) -{ - mp_run_data *res; - struct mp_edge_object **hh = is_fig(L, 1); - int prologues = (int)luaL_optnumber(L, 2, (lua_Number)-1); - if (mp_svg_ship_out(*hh, prologues) - && (res = mp_rundata((*hh)->parent)) - && (res->ship_out.size != 0)) { - lua_pushstring(L, res->ship_out.data); - } else { - lua_pushnil(L); - } - return 1; -} - - -static int mplib_fig_png(lua_State * L) -{ - mp_run_data *res; - struct mp_edge_object **hh = is_fig(L, 1); - const char *string = luaL_optstring(L, 2, NULL); - if (mp_png_ship_out(*hh, string) - && (res = mp_rundata((*hh)->parent)) - && (res->ship_out.size != 0)) { - lua_pushlstring(L, res->ship_out.data, res->ship_out.size); - } else { - lua_pushnil(L); - } - return 1; -} - -static int mplib_fig_filename(lua_State * L) -{ - struct mp_edge_object **hh = is_fig(L, 1); - if (*hh != NULL) { - char *s = (*hh)->filename; - lua_pushstring(L, s); - } else { - lua_pushnil(L); - } - return 1; -} - -static int mplib_fig_width(lua_State * L) -{ - struct mp_edge_object **hh = is_fig(L, 1); - if (*hh != NULL) { - lua_pushnumber(L, (double) (*hh)->width); - } else { - lua_pushnil(L); - } - return 1; -} - -static int mplib_fig_height(lua_State * L) -{ - struct mp_edge_object **hh = is_fig(L, 1); - if (*hh != NULL) { - lua_pushnumber(L, (double) (*hh)->height); - } else { - lua_pushnil(L); - } - return 1; -} - -static int mplib_fig_depth(lua_State * L) -{ - struct mp_edge_object **hh = is_fig(L, 1); - if (*hh != NULL) { - lua_pushnumber(L, (double) (*hh)->depth); - } else { - lua_pushnil(L); - } - return 1; -} - -static int mplib_fig_italcorr(lua_State * L) -{ - struct mp_edge_object **hh = is_fig(L, 1); - if (*hh != NULL) { - lua_pushnumber(L, (double) (*hh)->ital_corr); - } else { - lua_pushnil(L); - } - return 1; -} - -static int mplib_fig_charcode(lua_State * L) -{ - struct mp_edge_object **hh = is_fig(L, 1); - if (*hh != NULL) { - lua_pushnumber(L, (lua_Number)(*hh)->charcode); - } else { - lua_pushnil(L); - } - return 1; -} - - - -static int mplib_fig_bb(lua_State * L) -{ - struct mp_edge_object **hh = is_fig(L, 1); - lua_newtable(L); - lua_pushnumber(L, (double) (*hh)->minx); - lua_rawseti(L, -2, 1); - lua_pushnumber(L, (double) (*hh)->miny); - lua_rawseti(L, -2, 2); - lua_pushnumber(L, (double) (*hh)->maxx); - lua_rawseti(L, -2, 3); - lua_pushnumber(L, (double) (*hh)->maxy); - lua_rawseti(L, -2, 4); - return 1; -} - -/* object methods */ - -static int mplib_gr_collect(lua_State * L) -{ - struct mp_graphic_object **hh = is_gr_object(L, 1); - if (*hh != NULL) { - mp_gr_toss_object(*hh); - *hh = NULL; - } - return 0; -} - -static int mplib_gr_tostring(lua_State * L) -{ - struct mp_graphic_object **hh = is_gr_object(L, 1); - (void)lua_pushfstring(L, "", *hh); - return 1; -} - -#define pyth(a,b) (sqrt((a)*(a) + (b)*(b))) - -#define aspect_bound (10.0/65536.0) -#define aspect_default 1.0 - -static double eps = 0.0001; - -static double coord_range_x (mp_gr_knot h, double dz) { - double z; - double zlo = 0.0, zhi = 0.0; - mp_gr_knot f = h; - while (h != NULL) { - z = h->x_coord; - if (z < zlo) zlo = z; else if (z > zhi) zhi = z; - z = h->right_x; - if (z < zlo) zlo = z; else if (z > zhi) zhi = z; - z = h->left_x; - if (z < zlo) zlo = z; else if (z > zhi) zhi = z; - h = h->next; - if (h==f) - break; - } - return (zhi - zlo <= dz ? aspect_bound : aspect_default); -} - -static double coord_range_y (mp_gr_knot h, double dz) { - double z; - double zlo = 0.0, zhi = 0.0; - mp_gr_knot f = h; - while (h != NULL) { - z = h->y_coord; - if (z < zlo) zlo = z; else if (z > zhi) zhi = z; - z = h->right_y; - if (z < zlo) zlo = z; else if (z > zhi) zhi = z; - z = h->left_y; - if (z < zlo) zlo = z; else if (z > zhi) zhi = z; - h = h->next; - if (h==f) - break; - } - return (zhi - zlo <= dz ? aspect_bound : aspect_default); -} - - -static int mplib_gr_peninfo(lua_State * L) { - double x_coord, y_coord, left_x, left_y, right_x, right_y; - double wx, wy; - double rx = 1.0, sx = 0.0, sy = 0.0, ry = 1.0, tx = 0.0, ty = 0.0; - double width = 1.0; - mp_gr_knot p = NULL, path = NULL; - struct mp_graphic_object **hh = is_gr_object(L, -1); - if (!*hh) { - lua_pushnil(L); - return 1; - } - if ((*hh)->type == mp_fill_code) { - p = ((mp_fill_object *)(*hh))->pen_p; - path = ((mp_fill_object *)(*hh))->path_p; - } else if ((*hh)->type == mp_stroked_code) { - p = ((mp_stroked_object *)(*hh))->pen_p; - path = ((mp_stroked_object *)(*hh))->path_p; - } - if (p==NULL || path == NULL) { - lua_pushnil(L); - return 1; - } - x_coord = p->x_coord; - y_coord = p->y_coord; - left_x = p->left_x; - left_y = p->left_y; - right_x = p->right_x; - right_y = p->right_y; - if ((right_x == x_coord) && (left_y == y_coord)) { - wx = fabs(left_x - x_coord); - wy = fabs(right_y - y_coord); - } else { - wx = pyth(left_x - x_coord, right_x - x_coord); - wy = pyth(left_y - y_coord, right_y - y_coord); - } - if ((wy/coord_range_x(path, wx)) >= (wx/coord_range_y(path, wy))) - width = wy; - else - width = wx; - tx = x_coord; - ty = y_coord; - sx = left_x - tx; - rx = left_y - ty; - ry = right_x - tx; - sy = right_y - ty; - if (width !=1.0) { - if (width == 0.0) { - sx = 1.0; sy = 1.0; - } else { - rx/=width; ry/=width; sx/=width; sy/=width; - } - } - if (fabs(sx) < eps) sx = eps; - if (fabs(sy) < eps) sy = eps; - lua_newtable(L); - lua_pushnumber(L,width); lua_setfield(L,-2,"width"); - lua_pushnumber(L,rx); lua_setfield(L,-2,"rx"); - lua_pushnumber(L,sx); lua_setfield(L,-2,"sx"); - lua_pushnumber(L,sy); lua_setfield(L,-2,"sy"); - lua_pushnumber(L,ry); lua_setfield(L,-2,"ry"); - lua_pushnumber(L,tx); lua_setfield(L,-2,"tx"); - lua_pushnumber(L,ty); lua_setfield(L,-2,"ty"); - return 1; -} - - -static int mplib_gr_fields(lua_State * L) -{ - const char **fields; - int i; - struct mp_graphic_object **hh = is_gr_object(L, 1); - if (*hh) { - switch ((*hh)->type) { - case mp_fill_code: - fields = fill_fields; - break; - case mp_stroked_code: - fields = stroked_fields; - break; - case mp_text_code: - fields = text_fields; - break; - case mp_special_code: - fields = special_fields; - break; - case mp_start_clip_code: - fields = start_clip_fields; - break; - case mp_start_bounds_code: - fields = start_bounds_fields; - break; - case mp_stop_clip_code: - fields = stop_clip_fields; - break; - case mp_stop_bounds_code: - fields = stop_bounds_fields; - break; - default: - fields = no_fields; - } - lua_newtable(L); - for (i = 0; fields[i] != NULL; i++) { - lua_pushstring(L, fields[i]); - lua_rawseti(L, -2, (i + 1)); - } - } else { - lua_pushnil(L); - } - return 1; -} - - -#define mplib_push_number(L,x) lua_pushnumber(L,(lua_Number)(x)) - -#define MPLIB_PATH 0 -#define MPLIB_PEN 1 - -static void mplib_push_path(lua_State * L, mp_gr_knot h, int is_pen) -{ - mp_gr_knot p; /* for scanning the path */ - int i = 1; - p = h; - if (p != NULL) { - lua_newtable(L); - do { - lua_createtable(L, 0, 6); - if (!is_pen) { - if (p->data.types.left_type != mp_explicit) { - mplib_push_S(left_type); - lua_pushstring(L, knot_type_enum[p->data.types.left_type]); - lua_rawset(L, -3); - } - if (p->data.types.right_type != mp_explicit) { - mplib_push_S(right_type); - lua_pushstring(L, knot_type_enum[p->data.types.right_type]); - lua_rawset(L, -3); - } - } - mplib_push_S(x_coord); - mplib_push_number(L, p->x_coord); - lua_rawset(L, -3); - mplib_push_S(y_coord); - mplib_push_number(L, p->y_coord); - lua_rawset(L, -3); - mplib_push_S(left_x); - mplib_push_number(L, p->left_x); - lua_rawset(L, -3); - mplib_push_S(left_y); - mplib_push_number(L, p->left_y); - lua_rawset(L, -3); - mplib_push_S(right_x); - mplib_push_number(L, p->right_x); - lua_rawset(L, -3); - mplib_push_S(right_y); - mplib_push_number(L, p->right_y); - lua_rawset(L, -3); - lua_rawseti(L, -2, i); - i++; - if (p->data.types.right_type == mp_endpoint) { - return; - } - p = p->next; - } while (p != h); - } else { - lua_pushnil(L); - } -} - -/* this assumes that the top of the stack is a table - or nil already in the case - */ -static void mplib_push_pentype(lua_State * L, mp_gr_knot h) -{ - mp_gr_knot p; /* for scanning the path */ - p = h; - if (p == NULL) { - /* do nothing */ - } else if (p == p->next) { - mplib_push_S(type); - lua_pushstring(L, "elliptical"); - lua_rawset(L, -3); - } else { - } -} - -#define set_color_objects(pq) \ - object_color_model = pq->color_model; \ - object_color_a = pq->color.a_val; \ - object_color_b = pq->color.b_val; \ - object_color_c = pq->color.c_val; \ - object_color_d = pq->color.d_val; - - -static void mplib_push_color(lua_State * L, struct mp_graphic_object *p) -{ - int object_color_model; - double object_color_a, object_color_b, object_color_c, object_color_d; - if (p != NULL) { - if (p->type == mp_fill_code) { - mp_fill_object *h = (mp_fill_object *) p; - set_color_objects(h); - } else if (p->type == mp_stroked_code) { - mp_stroked_object *h = (mp_stroked_object *) p; - set_color_objects(h); - } else { - mp_text_object *h = (mp_text_object *) p; - set_color_objects(h); - } - lua_newtable(L); - if (object_color_model >= mp_grey_model) { - mplib_push_number(L, object_color_a); - lua_rawseti(L, -2, 1); - if (object_color_model >= mp_rgb_model) { - mplib_push_number(L, object_color_b); - lua_rawseti(L, -2, 2); - mplib_push_number(L, object_color_c); - lua_rawseti(L, -2, 3); - if (object_color_model == mp_cmyk_model) { - mplib_push_number(L, object_color_d); - lua_rawseti(L, -2, 4); - } - } - } - } else { - lua_pushnil(L); - } -} - -/* the dash scale is not exported, the field has no external value */ -static void mplib_push_dash(lua_State * L, struct mp_stroked_object *h) -{ - mp_dash_object *d; - double ds; - if (h != NULL && h->dash_p != NULL) { - d = h->dash_p; - lua_newtable(L); - mplib_push_number(L, d->offset); - lua_setfield(L, -2, "offset"); - if (d->array != NULL) { - int i = 0; - lua_newtable(L); - while (*(d->array + i) != -1) { - ds = *(d->array + i); - lua_pushnumber(L, ds); - i++; - lua_rawseti(L, -2, i); - } - lua_setfield(L, -2, "dashes"); - } - } else { - lua_pushnil(L); - } -} - -static void mplib_push_transform(lua_State * L, struct mp_text_object *h) -{ - int i = 1; - if (h != NULL) { - lua_createtable(L, 6, 0); - mplib_push_number(L, h->tx); - lua_rawseti(L, -2, i); - i++; - mplib_push_number(L, h->ty); - lua_rawseti(L, -2, i); - i++; - mplib_push_number(L, h->txx); - lua_rawseti(L, -2, i); - i++; - mplib_push_number(L, h->tyx); - lua_rawseti(L, -2, i); - i++; - mplib_push_number(L, h->txy); - lua_rawseti(L, -2, i); - i++; - mplib_push_number(L, h->tyy); - lua_rawseti(L, -2, i); - i++; - } else { - lua_pushnil(L); - } -} - -#define FIELD(A) (mplib_is_S(A,2)) - -static void mplib_fill(lua_State * L, struct mp_fill_object *h) -{ - if (FIELD(path)) { - mplib_push_path(L, h->path_p, MPLIB_PATH); - } else if (FIELD(htap)) { - mplib_push_path(L, h->htap_p, MPLIB_PATH); - } else if (FIELD(pen)) { - mplib_push_path(L, h->pen_p, MPLIB_PEN); - mplib_push_pentype(L, h->pen_p); - } else if (FIELD(color)) { - mplib_push_color(L, (mp_graphic_object *) h); - } else if (FIELD(linejoin)) { - lua_pushnumber(L, (lua_Number)h->ljoin); - } else if (FIELD(miterlimit)) { - mplib_push_number(L, h->miterlim); - } else if (FIELD(prescript)) { - lua_pushstring(L, h->pre_script); - } else if (FIELD(postscript)) { - lua_pushstring(L, h->post_script); - } else { - lua_pushnil(L); - } -} - -static void mplib_stroked(lua_State * L, struct mp_stroked_object *h) -{ - if (FIELD(path)) { - mplib_push_path(L, h->path_p, MPLIB_PATH); - } else if (FIELD(pen)) { - mplib_push_path(L, h->pen_p, MPLIB_PEN); - mplib_push_pentype(L, h->pen_p); - } else if (FIELD(color)) { - mplib_push_color(L, (mp_graphic_object *) h); - } else if (FIELD(dash)) { - mplib_push_dash(L, h); - } else if (FIELD(linecap)) { - lua_pushnumber(L, (lua_Number)h->lcap); - } else if (FIELD(linejoin)) { - lua_pushnumber(L, (lua_Number)h->ljoin); - } else if (FIELD(miterlimit)) { - mplib_push_number(L, h->miterlim); - } else if (FIELD(prescript)) { - lua_pushstring(L, h->pre_script); - } else if (FIELD(postscript)) { - lua_pushstring(L, h->post_script); - } else { - lua_pushnil(L); - } -} - -static void mplib_text(lua_State * L, struct mp_text_object *h) -{ - if (FIELD(text)) { - lua_pushstring(L, h->text_p); - } else if (FIELD(dsize)) { - mplib_push_number(L, (h->font_dsize / 16)); - } else if (FIELD(font)) { - lua_pushstring(L, h->font_name); - } else if (FIELD(color)) { - mplib_push_color(L, (mp_graphic_object *) h); - } else if (FIELD(width)) { - mplib_push_number(L, h->width); - } else if (FIELD(height)) { - mplib_push_number(L, h->height); - } else if (FIELD(depth)) { - mplib_push_number(L, h->depth); - } else if (FIELD(transform)) { - mplib_push_transform(L, h); - } else if (FIELD(prescript)) { - lua_pushstring(L, h->pre_script); - } else if (FIELD(postscript)) { - lua_pushstring(L, h->post_script); - } else { - lua_pushnil(L); - } -} - -static void mplib_special(lua_State * L, struct mp_special_object *h) -{ - if (FIELD(prescript)) { - lua_pushstring(L, h->pre_script); - } else { - lua_pushnil(L); - } -} - -static void mplib_start_bounds(lua_State * L, struct mp_bounds_object *h) -{ - if (FIELD(path)) { - mplib_push_path(L, h->path_p, MPLIB_PATH); - } else { - lua_pushnil(L); - } -} - -static void mplib_start_clip(lua_State * L, struct mp_clip_object *h) -{ - if (FIELD(path)) { - mplib_push_path(L, h->path_p, MPLIB_PATH); - } else { - lua_pushnil(L); - } -} - -static int mplib_gr_index(lua_State * L) -{ - struct mp_graphic_object **hh = is_gr_object(L, 1); - if (*hh) { - struct mp_graphic_object *h = *hh; - - if (mplib_is_S(type, 2)) { - lua_rawgeti(L, LUA_REGISTRYINDEX, mplib_type_Ses[h->type]); - } else { - switch (h->type) { - case mp_fill_code: - mplib_fill(L, (mp_fill_object *) h); - break; - case mp_stroked_code: - mplib_stroked(L, (mp_stroked_object *) h); - break; - case mp_text_code: - mplib_text(L, (mp_text_object *) h); - break; - case mp_special_code: - mplib_special(L, (mp_special_object *) h); - break; - case mp_start_clip_code: - mplib_start_clip(L, (mp_clip_object *) h); - break; - case mp_start_bounds_code: - mplib_start_bounds(L, (mp_bounds_object *) h); - break; - case mp_stop_clip_code: - case mp_stop_bounds_code: - default: - lua_pushnil(L); - } - } - } else { - lua_pushnil(L); - } - return 1; -} - - -static const struct luaL_reg mplib_meta[] = { - {"__gc", mplib_collect}, - {"__tostring", mplib_tostring}, - {NULL, NULL} /* sentinel */ -}; - -static const struct luaL_reg mplib_fig_meta[] = { - {"__gc", mplib_fig_collect}, - {"__tostring", mplib_fig_tostring}, - {"objects", mplib_fig_body}, - {"copy_objects", mplib_fig_copy_body}, - {"filename", mplib_fig_filename}, - {"postscript", mplib_fig_postscript}, - {"png", mplib_fig_png}, - {"svg", mplib_fig_svg}, - {"boundingbox", mplib_fig_bb}, - {"width", mplib_fig_width}, - {"height", mplib_fig_height}, - {"depth", mplib_fig_depth}, - {"italcorr", mplib_fig_italcorr}, - {"charcode", mplib_fig_charcode}, - {NULL, NULL} /* sentinel */ -}; - -static const struct luaL_reg mplib_gr_meta[] = { - {"__gc", mplib_gr_collect}, - {"__tostring", mplib_gr_tostring}, - {"__index", mplib_gr_index}, - {NULL, NULL} /* sentinel */ -}; - -static const struct luaL_reg mplib_d[] = { - {"execute", mplib_execute}, - {"finish", mplib_finish}, - {"char_width", mplib_charwidth}, - {"char_height", mplib_charheight}, - {"char_depth", mplib_chardepth}, - {"statistics", mplib_statistics}, - {"solve_path", mplib_solve_path}, - {NULL, NULL} /* sentinel */ -}; - - -static const struct luaL_reg mplib_m[] = { - {"new", mplib_new}, - {"version", mplib_version}, - {"fields", mplib_gr_fields}, - {"pen_info", mplib_gr_peninfo}, - {NULL, NULL} /* sentinel */ -}; - - -int luaopen_mplib(lua_State * L) -{ - mplib_init_Ses(L); - - luaL_newmetatable(L, MPLIB_GR_METATABLE); - lua_pushvalue(L, -1); /* push metatable */ - lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_register(L, NULL, mplib_gr_meta); /* object meta methods */ - lua_pop(L, 1); - - luaL_newmetatable(L, MPLIB_FIG_METATABLE); - lua_pushvalue(L, -1); /* push metatable */ - lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_register(L, NULL, mplib_fig_meta); /* figure meta methods */ - lua_pop(L, 1); - - luaL_newmetatable(L, MPLIB_METATABLE); - lua_pushvalue(L, -1); /* push metatable */ - lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_register(L, NULL, mplib_meta); /* meta methods */ - luaL_register(L, NULL, mplib_d); /* dict methods */ - luaL_register(L, "mplib", mplib_m); /* module functions */ - return 1; -} +/* lmplib.c + + Copyright 2012 Taco Hoekwater + + This file is part of the MetaPost tarball, but belongs to LuaTeX. + + LuaTeX is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + LuaTeX is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with LuaTeX; if not, see . */ + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include /* temporary */ + +#ifndef pdfTeX +# include +# include +# include +#else +# include "lua.h" +# include "lauxlib.h" +# include "lualib.h" +#define luaL_reg luaL_Reg +#define lua_objlen lua_rawlen +#endif + +#include "mplib.h" +#include "mplibps.h" +#include "mplibsvg.h" +#include "mplibpng.h" + + /*@unused@*/ static const char _svn_version[] = + "$Id: lmplib.c 1962 2014-03-11 13:18:08Z taco $"; + +int luaopen_mplib(lua_State * L); /* forward */ + +/* metatable identifiers and tests */ + +#define MPLIB_METATABLE "MPlib.meta" +#define MPLIB_FIG_METATABLE "MPlib.fig" +#define MPLIB_GR_METATABLE "MPlib.gr" + +#define is_mp(L,b) (MP *)luaL_checkudata(L,b,MPLIB_METATABLE) +#define is_fig(L,b) (struct mp_edge_object **)luaL_checkudata(L,b,MPLIB_FIG_METATABLE) +#define is_gr_object(L,b) (struct mp_graphic_object **)luaL_checkudata(L,b,MPLIB_GR_METATABLE) + +/* Lua string pre-hashing */ + +#define mplib_init_S(a) do { \ + lua_pushliteral(L,#a); \ + mplib_##a##_ptr = lua_tostring(L,-1); \ + mplib_##a##_index = luaL_ref (L,LUA_REGISTRYINDEX); \ + } while (0) + +#define mplib_push_S(a) do { \ + lua_rawgeti(L,LUA_REGISTRYINDEX,mplib_##a##_index); \ + } while (0) + +#define mplib_is_S(a,i) (mplib_##a##_ptr==lua_tostring(L,i)) + +#define mplib_make_S(a) \ + static int mplib_##a##_index = 0; \ + static const char *mplib_##a##_ptr = NULL + +static int mplib_type_Ses[mp_special_code + 1] = { 0 }; /* [0] is not used */ + +mplib_make_S(fill); +mplib_make_S(outline); +mplib_make_S(text); +mplib_make_S(special); +mplib_make_S(start_bounds); +mplib_make_S(stop_bounds); +mplib_make_S(start_clip); +mplib_make_S(stop_clip); + +mplib_make_S(left_type); +mplib_make_S(right_type); +mplib_make_S(x_coord); +mplib_make_S(y_coord); +mplib_make_S(left_x); +mplib_make_S(left_y); +mplib_make_S(right_x); +mplib_make_S(right_y); +mplib_make_S(left_tension); +mplib_make_S(right_tension); +mplib_make_S(left_curl); +mplib_make_S(right_curl); +mplib_make_S(direction_x); +mplib_make_S(direction_y); + +mplib_make_S(color); +mplib_make_S(dash); +mplib_make_S(depth); +mplib_make_S(dsize); +mplib_make_S(font); +mplib_make_S(height); +mplib_make_S(htap); +mplib_make_S(linecap); +mplib_make_S(linejoin); +mplib_make_S(miterlimit); +mplib_make_S(path); +mplib_make_S(pen); +mplib_make_S(postscript); +mplib_make_S(prescript); +mplib_make_S(transform); +mplib_make_S(type); +mplib_make_S(width); + +static void mplib_init_Ses(lua_State * L) +{ + mplib_init_S(fill); + mplib_init_S(outline); + mplib_init_S(text); + mplib_init_S(start_bounds); + mplib_init_S(stop_bounds); + mplib_init_S(start_clip); + mplib_init_S(stop_clip); + mplib_init_S(special); + + mplib_type_Ses[mp_fill_code] = mplib_fill_index; + mplib_type_Ses[mp_stroked_code] = mplib_outline_index; + mplib_type_Ses[mp_text_code] = mplib_text_index; + mplib_type_Ses[mp_start_bounds_code] = mplib_start_bounds_index; + mplib_type_Ses[mp_stop_bounds_code] = mplib_stop_bounds_index; + mplib_type_Ses[mp_start_clip_code] = mplib_start_clip_index; + mplib_type_Ses[mp_stop_clip_code] = mplib_stop_clip_index; + mplib_type_Ses[mp_special_code] = mplib_special_index; + + mplib_init_S(left_type); + mplib_init_S(right_type); + mplib_init_S(x_coord); + mplib_init_S(y_coord); + mplib_init_S(left_x); + mplib_init_S(left_y); + mplib_init_S(right_x); + mplib_init_S(right_y); + mplib_init_S(left_tension); + mplib_init_S(right_tension); + mplib_init_S(left_curl); + mplib_init_S(right_curl); + mplib_init_S(direction_x); + mplib_init_S(direction_y); + + mplib_init_S(color); + mplib_init_S(dash); + mplib_init_S(depth); + mplib_init_S(dsize); + mplib_init_S(font); + mplib_init_S(height); + mplib_init_S(htap); + mplib_init_S(linecap); + mplib_init_S(linejoin); + mplib_init_S(miterlimit); + mplib_init_S(path); + mplib_init_S(pen); + mplib_init_S(postscript); + mplib_init_S(prescript); + mplib_init_S(transform); + mplib_init_S(type); + mplib_init_S(width); +} + + +/* Enumeration arrays to map MPlib enums to Lua strings */ + +static const char *math_options[] = + { "scaled", "double", "binary", "decimal", NULL }; + +static const char *interaction_options[] = + { "unknown", "batch", "nonstop", "scroll", "errorstop", NULL }; + +static const char *mplib_filetype_names[] = + { "term", "error", "mp", "log", "ps", "png", "mem", "tfm", "map", "pfb", "enc", NULL }; + +static const char *knot_type_enum[] = + { "endpoint", "explicit", "given", "curl", "open", "end_cycle" }; + +static const char *fill_fields[] = + { "type", "path", "htap", "pen", "color", "linejoin", "miterlimit", + "prescript", "postscript", NULL }; + +static const char *stroked_fields[] = + { "type", "path", "pen", "color", "linejoin", "miterlimit", "linecap", + "dash", "prescript", "postscript", NULL }; + +static const char *text_fields[] = + { "type", "text", "dsize", "font", "color", "width", "height", "depth", + "transform", "prescript", "postscript", NULL }; + +static const char *special_fields[] = + { "type", "prescript", NULL }; + +static const char *start_bounds_fields[] = + { "type", "path", NULL }; + +static const char *start_clip_fields[] = + { "type", "path", NULL }; + +static const char *stop_bounds_fields[] = + { "type", NULL }; + +static const char *stop_clip_fields[] = + { "type", NULL }; + +static const char *no_fields[] = + { NULL }; + + +/* The list of supported MPlib options (not all make sense) */ + +typedef enum { + P_ERROR_LINE, P_MAX_LINE, P_RANDOM_SEED, P_MATH_MODE, + P_INTERACTION, P_INI_VERSION, P_MEM_NAME, P_JOB_NAME, P_FIND_FILE, + P_RUN_SCRIPT, P_SCRIPT_ERROR, + P__SENTINEL } mplib_parm_idx; + +typedef struct { + const char *name; /* parameter name */ + mplib_parm_idx idx; /* parameter index */ +} mplib_parm_struct; + +static mplib_parm_struct mplib_parms[] = { + {"error_line", P_ERROR_LINE }, + {"print_line", P_MAX_LINE }, + {"random_seed", P_RANDOM_SEED }, + {"interaction", P_INTERACTION }, + {"job_name", P_JOB_NAME }, + {"find_file", P_FIND_FILE }, + {"run_script", P_RUN_SCRIPT }, + {"script_error", P_SCRIPT_ERROR }, + {"math_mode", P_MATH_MODE }, + {NULL, P__SENTINEL } +}; + +/* Start by defining the needed callback routines for the library */ + +/* todo: make subtable in registry, beware, for all mp instances */ + +static char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ftype) +{ + lua_State *L = (lua_State *)mp_userdata(mp); + lua_checkstack(L, 4); + lua_getfield(L, LUA_REGISTRYINDEX, "mplib.file_finder"); + if (lua_isfunction(L, -1)) { + char *s = NULL; + const char *x = NULL; + lua_pushstring(L, fname); + lua_pushstring(L, fmode); + if (ftype >= mp_filetype_text) { + lua_pushnumber(L, (lua_Number)(ftype - mp_filetype_text)); + } else { + lua_pushstring(L, mplib_filetype_names[ftype]); + } + if (lua_pcall(L, 3, 1, 0) != 0) { + fprintf(stdout, "Error in mp.find_file: %s\n", lua_tostring(L, -1)); + return NULL; + } + x = lua_tostring(L, -1); + if (x != NULL) + s = strdup(x); + lua_pop(L, 1); /* pop the string */ + return s; + } else { + lua_pop(L, 1); + } + if (fmode[0] != 'r' || (!access(fname, R_OK)) || ftype) { + return strdup(fname); + } + return NULL; +} + +static int mplib_find_file_function(lua_State * L) +{ + if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) { + return 1; /* error */ + } + lua_pushstring(L, "mplib.file_finder"); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + return 0; +} + +static void mplib_script_error(MP mp, const char *str) +{ + lua_State *L = (lua_State *)mp_userdata(mp); + lua_checkstack(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, "mplib.script_error"); + if (lua_isfunction(L, -1)) { + lua_pushstring(L, str); + lua_pcall(L, 1, 0, 0); /* assume the function is ok */ + } else { + fprintf(stdout,"Error in script: %s\n",str); + lua_pop(L, 1); + } +} + +static int mplib_script_error_function(lua_State * L) +{ + if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) { + return 1; /* error */ + } + lua_pushstring(L, "mplib.script_error"); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + return 0; +} + +static char *mplib_run_script(MP mp, const char *str) +{ + lua_State *L = (lua_State *)mp_userdata(mp); + lua_checkstack(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, "mplib.run_script"); + if (lua_isfunction(L, -1)) { + char *s = NULL; + const char *x = NULL; + lua_pushstring(L, str); + if (lua_pcall(L, 1, 1, 0) != 0) { + mplib_script_error(mp, lua_tostring(L, -1)); + return NULL; + } + x = lua_tostring(L, -1); + if (x != NULL) + s = strdup(x); + lua_pop(L, 1); /* pop the string */ + return s; + } else { + lua_pop(L, 1); + } + return NULL; +} + +static int mplib_run_script_function(lua_State * L) +{ + if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) { + return 1; /* error */ + } + lua_pushstring(L, "mplib.run_script"); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + return 0; +} + +static int mplib_get_numeric(lua_State * L) +{ + MP *mp = is_mp(L, 1); + if (*mp != NULL) { + size_t l; + const char *s = lua_tolstring(L, 2, &l); + if (s != NULL) { + lua_pushnumber(L, mp_get_numeric_value(*mp,s,l)); + return 1; + } + } + lua_pushnumber(L,0); + return 1; +} + +static int mplib_get_boolean(lua_State * L) +{ + MP *mp = is_mp(L, 1); + if (*mp != NULL) { + size_t l; + const char *s = lua_tolstring(L, 2, &l); + if (s != NULL) { + lua_pushboolean(L, mp_get_boolean_value(*mp,s,l)); + return 1; + } + } + lua_pushboolean(L,0); + return 1; +} + +static int mplib_get_string(lua_State * L) +{ + MP *mp = is_mp(L, 1); + if (*mp != NULL) { + size_t l; + const char *s = lua_tolstring(L, 2, &l); + if (s != NULL) { + char *r = mp_get_string_value(*mp,s,l) ; + if (r != NULL) { + lua_pushstring(L, r); + return 1; + } + } + } + lua_pushstring(L,""); + return 1; +} + +#define xfree(A) if ((A)!=NULL) { free((A)); A = NULL; } + +static int mplib_new(lua_State * L) +{ + MP *mp_ptr; + mp_ptr = lua_newuserdata(L, sizeof(MP *)); + if (mp_ptr) { + int i; + struct MP_options *options = mp_options(); + options->userdata = (void *) L; + options->noninteractive = 1; /* required ! */ + options->find_file = mplib_find_file; + options->run_script = mplib_run_script; + // options->script_error = mplib_script_error; + options->print_found_names = 1; + options->ini_version = 1; + if (lua_type(L, 1) == LUA_TTABLE) { + for (i = 0; mplib_parms[i].name != NULL; i++) { + lua_getfield(L, 1, mplib_parms[i].name); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + continue; /* skip unset */ + } + switch (mplib_parms[i].idx) { + case P_ERROR_LINE: + options->error_line = (int)lua_tointeger(L, -1); + if (options->error_line<60) options->error_line =60; + if (options->error_line>250) options->error_line = 250; + options->half_error_line = (options->error_line/2)+10; + break; + case P_MAX_LINE: + options->max_print_line = (int)lua_tointeger(L, -1); + if (options->max_print_line<60) options->max_print_line = 60; + break; + case P_RANDOM_SEED: + options->random_seed = (int)lua_tointeger(L, -1); + break; + case P_INTERACTION: + options->interaction = + luaL_checkoption(L, -1, "errorstopmode", + interaction_options); + break; + case P_MATH_MODE: + options->math_mode = + luaL_checkoption(L, -1, "scaled", + math_options); + break; + case P_JOB_NAME: + options->job_name = strdup(lua_tostring(L, -1)); + break; + case P_FIND_FILE: + if (mplib_find_file_function(L)) { /* error here */ + fprintf(stdout,"Invalid arguments to mp.new { find_file = ... }\n"); + } + break; + case P_RUN_SCRIPT: + if (mplib_run_script_function(L)) { /* error here */ + fprintf(stdout,"Invalid arguments to mp.new { run_script = ... }\n"); + } + break; + case P_SCRIPT_ERROR: + if (mplib_script_error_function(L)) { /* error here */ + fprintf(stdout,"Invalid arguments to mp.new { script_error = ... }\n"); + } + break; + default: + break; + } + lua_pop(L, 1); + } + } + *mp_ptr = mp_initialize(options); + xfree(options->command_line); + xfree(options->mem_name); + free(options); + if (*mp_ptr) { + luaL_getmetatable(L, MPLIB_METATABLE); + lua_setmetatable(L, -2); + return 1; + } + } + lua_pushnil(L); + return 1; +} + +static int mplib_collect(lua_State * L) +{ + MP *mp_ptr = is_mp(L, 1); + if (*mp_ptr != NULL) { + (void)mp_finish(*mp_ptr); + *mp_ptr = NULL; + } + return 0; +} + +static int mplib_tostring(lua_State * L) +{ + MP *mp_ptr = is_mp(L, 1); + if (*mp_ptr != NULL) { + (void)lua_pushfstring(L, "", *mp_ptr); + return 1; + } + return 0; +} + +static int mplib_wrapresults(lua_State * L, mp_run_data *res, int status) +{ + lua_checkstack(L, 5); + lua_newtable(L); + if (res->term_out.used != 0) { + lua_pushlstring(L, res->term_out.data, res->term_out.used); + lua_setfield(L, -2, "term"); + } + if (res->error_out.used != 0) { + lua_pushlstring(L, res->error_out.data, res->error_out.used); + lua_setfield(L, -2, "error"); + } + if (res->log_out.used != 0) { + lua_pushlstring(L, res->log_out.data, res->log_out.used); + lua_setfield(L, -2, "log"); + } + if (res->edges != NULL) { + struct mp_edge_object **v; + struct mp_edge_object *p = res->edges; + int i = 1; + lua_newtable(L); + while (p != NULL) { + v = lua_newuserdata(L, sizeof(struct mp_edge_object *)); + *v = p; + luaL_getmetatable(L, MPLIB_FIG_METATABLE); + lua_setmetatable(L, -2); + lua_rawseti(L, -2, i); + i++; + p = p->next; + } + lua_setfield(L, -2, "fig"); + res->edges = NULL; + } + lua_pushnumber(L, (lua_Number)status); + lua_setfield(L, -2, "status"); + return 1; +} + +static int mplib_execute(lua_State * L) +{ + MP *mp_ptr; + if (lua_gettop(L)!=2) { + lua_pushnil(L); + return 1; + } + mp_ptr = is_mp(L, 1); + if (*mp_ptr != NULL && lua_isstring(L, 2)) { + size_t l; + char *s = xstrdup(lua_tolstring(L, 2, &l)); + int h = mp_execute(*mp_ptr, s, l); + mp_run_data *res = mp_rundata(*mp_ptr); + free(s); + return mplib_wrapresults(L, res, h); + } else { + lua_pushnil(L); + } + return 1; +} + +static int mplib_finish(lua_State * L) +{ + MP *mp_ptr = is_mp(L, 1); + if (*mp_ptr != NULL) { + int i; + int h = mp_execute(*mp_ptr,NULL,0); + mp_run_data *res = mp_rundata(*mp_ptr); + i = mplib_wrapresults(L, res, h); + (void)mp_finish(*mp_ptr); + *mp_ptr = NULL; + return i; + } else { + lua_pushnil(L); + } + return 1; +} + +static int mplib_char_dimension(lua_State * L, int t) +{ + MP *mp_ptr = is_mp(L, 1); + if (*mp_ptr != NULL) { + char *fname = xstrdup(luaL_checkstring(L,2)); + int charnum = (int)luaL_checkinteger(L,3); + if (charnum<0 || charnum>255) { + lua_pushnumber(L, (lua_Number)0); + } else { + lua_pushnumber(L,(lua_Number)mp_get_char_dimension(*mp_ptr,fname,charnum,t)); + } + free(fname); + } else { + lua_pushnumber(L, (lua_Number)0); + } + return 1; +} + +static int mplib_charwidth(lua_State * L) +{ + return mplib_char_dimension(L, 'w'); +} + +static int mplib_chardepth(lua_State * L) +{ + return mplib_char_dimension(L, 'd'); +} + +static int mplib_charheight(lua_State * L) +{ + return mplib_char_dimension(L, 'h'); +} + +static int mplib_version(lua_State * L) +{ + char *s = mp_metapost_version(); + lua_pushstring(L, s); + free(s); + return 1; +} + +static int mplib_statistics(lua_State * L) +{ + MP *mp_ptr = is_mp(L, 1); + if (*mp_ptr != NULL) { + lua_newtable(L); + lua_pushnumber(L, (lua_Number)mp_memory_usage(*mp_ptr)); + lua_setfield(L, -2, "memory"); + lua_pushnumber(L, (lua_Number)mp_hash_usage(*mp_ptr)); + lua_setfield(L, -2, "hash"); + lua_pushnumber(L, (lua_Number)mp_param_usage(*mp_ptr)); + lua_setfield(L, -2, "params"); + lua_pushnumber(L, (lua_Number)mp_open_usage(*mp_ptr)); + lua_setfield(L, -2, "open"); + } else { + lua_pushnil(L); + } + return 1; +} + + +static int set_direction (lua_State * L, MP mp, mp_knot p) { + double direction_x = 0, direction_y = 0; + direction_x = (double)lua_tonumber(L,-1); + lua_pop(L,1); + lua_pushstring(L, "direction_y"); + lua_rawget(L,-2); + if (!lua_isnumber(L,-1)) { + return 0; + } + direction_y = (double)lua_tonumber(L,-1); + lua_pop(L,1); + if (!mp_set_knot_direction(mp, p, direction_x, direction_y)) { + return 0; + } + return 1; +} + +static int set_left_curl (lua_State * L, MP mp, mp_knot p) { + double curl = (double)lua_tonumber(L,-1); + lua_pop(L,1); + if (!mp_set_knot_left_curl(mp, p, curl)) { + return 0; + } + return 1; +} + +static int set_left_tension (lua_State * L, MP mp, mp_knot p) { + double tension = (double)lua_tonumber(L,-1); + lua_pop(L,1); + if (!mp_set_knot_left_tension(mp, p, tension)) { + return 0; + } + return 1; +} + +static int set_left_control (lua_State * L, MP mp, mp_knot p) { + double x, y; + x = (double)lua_tonumber(L,-1); + lua_pop(L,1); + lua_pushstring(L, "left_y"); + lua_rawget(L,-2); + if (!lua_isnumber(L,-1)) { + return 0; + } + y = (double)lua_tonumber(L,-1); + lua_pop(L,1); + if (!mp_set_knot_left_control(mp, p, x, y)) { + return 0; + } + return 1; +} + +static int set_right_curl (lua_State * L, MP mp, mp_knot p) { + double curl = (double)lua_tonumber(L,-1); + lua_pop(L,1); + if (!mp_set_knot_right_curl(mp, p, curl)) { + return 0; + } + return 1; +} + +static int set_right_tension (lua_State * L, MP mp, mp_knot p) { + double tension = (double)lua_tonumber(L,-1); + lua_pop(L,1); + if (!mp_set_knot_right_tension(mp, p, tension)) { + return 0; + } + return 1; +} + +static int set_right_control (lua_State * L, MP mp, mp_knot p) { + double x, y; + x = (double)lua_tonumber(L,-1); + lua_pop(L,1); + lua_pushstring(L, "right_y"); + lua_rawget(L,-2); + if (!lua_isnumber(L,-1)) { + return 0; + } + y = (double)lua_tonumber(L,-1); + lua_pop(L,1); + if (!mp_set_knot_right_control(mp, p, x, y)) { + return 0; + } + return 1; +} + + +#if 0 +#define ROUNDED_ZERO(v) (fabs((v))<0.00001 ? 0 : (v)) +#define PI 3.1415926535897932384626433832795028841971 +#define RADIANS(a) (mp_number_as_double(mp,(a)) / 16.0) * PI/180.0 + +void mp_dump_path (MP mp, mp_knot h) { + mp_knot p, q; + if (h == NULL) return; + p = h; + do { + q=mp_knot_next(mp,p); + if ( (p==NULL)||(q==NULL) ) { + printf("\n???"); + return; /* this won't happen */ + } + printf ("(%g,%g)", mp_number_as_double(mp,mp_knot_x_coord(mp,p)), + mp_number_as_double(mp,mp_knot_y_coord(mp,p))); + switch (mp_knot_right_type(mp,p)) { + case mp_endpoint: + if ( mp_knot_left_type(mp,p)==mp_open ) printf("{open?}"); + if ( (mp_knot_left_type(mp,q)!=mp_endpoint)||(q!=h) ) + q=NULL; /* force an error */ + goto DONE; + break; + case mp_explicit: + printf ("..controls (%g,%g)", + mp_number_as_double(mp,mp_knot_right_x(mp,p)), + mp_number_as_double(mp,mp_knot_right_y(mp,p))); + printf(" and "); + if ( mp_knot_left_type(mp,q)!=mp_explicit ) { + printf("??"); + } else { + printf ("(%g,%g)",mp_number_as_double(mp,mp_knot_left_x(mp,q)), + mp_number_as_double(mp,mp_knot_left_y(mp,q))); + } + goto DONE; + break; + case mp_open: + if ( (mp_knot_left_type(mp,p)!=mp_explicit) + && + (mp_knot_left_type(mp,p)!=mp_open) ) { + printf("{open?}"); + } + break; + case mp_curl: + case mp_given: + if ( mp_knot_left_type(mp,p)==mp_open ) + printf("??"); + if ( mp_knot_right_type(mp,p)==mp_curl ) { + printf("{curl %g}", mp_number_as_double(mp,mp_knot_right_curl(mp,p))); + } else { + double rad = RADIANS(mp_knot_right_curl(mp,p)); + double n_cos = ROUNDED_ZERO(cos(rad)*4096); + double n_sin = ROUNDED_ZERO(sin(rad)*4096); + printf("{%g,%g}", n_cos, n_sin); + } + break; + } + if ( mp_knot_left_type(mp,q)<=mp_explicit ) { + printf("..control?"); /* can't happen */ + } else if ((mp_number_as_double(mp,mp_knot_right_tension(mp,p))!=(1.0))|| + (mp_number_as_double(mp,mp_knot_left_tension(mp,q)) !=(1.0))) { + printf("..tension "); + if ( mp_number_as_double(mp,mp_knot_right_tension(mp,p))<0.0 ) + printf("atleast "); + printf("%g", fabs(mp_number_as_double(mp,mp_knot_right_tension(mp,p)))); + if (mp_number_as_double(mp,mp_knot_right_tension(mp,p)) != + mp_number_as_double(mp,mp_knot_left_tension(mp,q))) { + printf(" and "); + if (mp_number_as_double(mp,mp_knot_left_tension(mp,q))< 0.0) + printf("atleast "); + printf("%g", fabs(mp_number_as_double(mp,mp_knot_left_tension(mp,q)))); + } + } + DONE: + p=q; + if ( p!=h || mp_knot_left_type(mp,h)!=mp_endpoint) { + printf ("\n .."); + if ( mp_knot_left_type(mp,p) == mp_given ) { + double rad = RADIANS(mp_knot_left_curl(mp,p)); + double n_cos = ROUNDED_ZERO(cos(rad)*4096); + double n_sin = ROUNDED_ZERO(sin(rad)*4096); + printf("{%g,%g}", n_cos, n_sin); + } else if ( mp_knot_left_type(mp,p) ==mp_curl ){ + printf("{curl %g}", mp_number_as_double(mp,mp_knot_left_curl(mp,p))); + } + } + } while (p!=h); + if ( mp_knot_left_type(mp,h)!=mp_endpoint ) + printf("cycle"); + printf (";\n"); +} +#endif + +static int mplib_solve_path(lua_State * L) +{ + MP *mp_ptr; + MP mp = NULL; + int cyclic; + const char *errormsg = NULL; + mp_knot p, q, first; + int numpoints, i; + p = q = first = NULL; + if (lua_gettop(L) != 3) { + errormsg = "Wrong number of arguments"; + goto BAD; + } + mp_ptr = is_mp(L, 1); + if (*mp_ptr == NULL || (!lua_istable(L,2)) || lua_objlen(L,2)<=0 || (!lua_isboolean(L,3))) { + errormsg = "Wrong argument types"; + goto BAD; + } + mp = *mp_ptr; + cyclic = lua_toboolean(L,3); + lua_pop(L,1); + + /* build up the path */ + numpoints = lua_objlen(L,2); + + first = p = NULL; + for (i=1;i<=numpoints;i++) { + int left_set = 0, right_set = 0; + double x_coord, y_coord; + lua_rawgeti(L,-1,i); + if (!lua_istable(L,-1)) { errormsg = "Wrong argument types"; goto BAD; } + + lua_pushstring(L, "x_coord"); + lua_rawget(L,-2); + if (!lua_isnumber(L,-1)) { errormsg = "Missing X coordinate"; goto BAD; } + x_coord = (double)lua_tonumber(L,-1); + lua_pop(L,1); + + lua_pushstring(L, "y_coord"); + lua_rawget(L,-2); + if (!lua_isnumber(L,-1)) { errormsg = "Missing y coordinate"; goto BAD; } + y_coord = (double)lua_tonumber(L,-1); + lua_pop(L,1); + + q = p; + if (q!=NULL) { + /* we have to save the right_tension because |mp_append_knot| trashes + it, believing that it is as yet uninitialized */ + double saved_tension = mp_number_as_double(mp, mp_knot_right_tension(mp,p)); + p = mp_append_knot(mp, p, x_coord, y_coord); + if ( ! p ) { errormsg = "knot creation failure"; goto BAD; } + (void)mp_set_knot_right_tension(mp, q, saved_tension); + } else { + p = mp_append_knot(mp, p, x_coord, y_coord); + if ( ! p ) { errormsg = "knot creation failure"; goto BAD; } + } + + if (first == NULL) first = p; + + lua_pushstring(L, "left_curl"); + lua_rawget(L,-2); + if (lua_isnumber(L,-1)) { + if (!set_left_curl (L, mp, p)) { errormsg = "failed to set left curl"; goto BAD; } + left_set = 1; + } else { + lua_pop(L,1); /* a nil value */ + } + + lua_pushstring(L, "left_tension"); + lua_rawget(L,-2); + if (lua_isnumber(L,-1)) { + if (left_set) { + errormsg = "Left side already set"; goto BAD; + } else { + if (!set_left_tension(L, mp, p)) { errormsg = "Failed to set left tension"; goto BAD; } + left_set = 1; + } + } else { + lua_pop(L,1); /* a nil value */ + } + + lua_pushstring(L, "left_x"); + lua_rawget(L,-2); + if (lua_isnumber(L,-1)) { + if (left_set) { + errormsg = "Left side already set"; goto BAD; + } else { + if (!set_left_control(L, mp, p)) { errormsg = "Failed to set left control"; goto BAD; } + } + } else { + lua_pop(L,1); + } + + lua_pushstring(L, "right_curl"); + lua_rawget(L,-2); + if (lua_isnumber(L,-1)) { + if (!set_right_curl (L, mp, p)) { errormsg = "failed to set right curl"; goto BAD; } + right_set = 1; + } else { + lua_pop(L,1); /* a nil value */ + } + + lua_pushstring(L, "right_tension"); + lua_rawget(L,-2); + if (lua_isnumber(L,-1)) { + if (right_set) { + errormsg = "Right side already set"; goto BAD; + } else { + if (!set_right_tension(L, mp, p)) { errormsg = "Failed to set right tension"; goto BAD; } + right_set = 1; + } + } else { + lua_pop(L,1); + } + + lua_pushstring(L, "right_x"); + lua_rawget(L,-2); + if (lua_isnumber(L,-1)) { + if (right_set) { + errormsg = "Right side already set"; goto BAD; + } else { + if (!set_right_control(L, mp, p)) { errormsg = "Failed to set right control"; goto BAD; } + } + } else { + lua_pop(L,1); + } + + lua_pushstring(L, "direction_x"); + lua_rawget(L,-2); + if (lua_isnumber(L,-1)) { + if (!set_direction (L, mp, p)) { errormsg = "failed to set direction"; goto BAD; } + } else { + lua_pop(L,1); /* a nil value */ + } + + lua_pop(L,1); /* done with this item */ + } + if (cyclic) { + mp_close_path_cycle (mp, p, first); + } else { + mp_close_path (mp, p, first); + } +#if 0 + mp_dump_path(mp,first); +#endif + /* finished reading arguments */ + if (!mp_solve_path(mp,first)) { errormsg = "Failed to solve the path"; goto BAD; } + + /* squeeze the new values back into the table */ + p = first; + for (i=1;i<=numpoints;i++) { + + lua_rawgeti(L,-1, i); + mplib_push_S(left_x); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_left_x(mp, p))); lua_rawset(L,-3); + mplib_push_S(left_y); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_left_y(mp, p))); lua_rawset(L,-3); + mplib_push_S(right_x); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_right_x(mp, p))); lua_rawset(L,-3); + mplib_push_S(right_y); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_right_y(mp, p))); lua_rawset(L,-3); + mplib_push_S(left_tension); lua_pushnil(L); lua_rawset(L,-3); + mplib_push_S(right_tension); lua_pushnil(L); lua_rawset(L,-3); + mplib_push_S(left_curl); lua_pushnil(L); lua_rawset(L,-3); + mplib_push_S(right_curl); lua_pushnil(L); lua_rawset(L,-3); + mplib_push_S(direction_x); lua_pushnil(L); lua_rawset(L,-3); + mplib_push_S(direction_y); lua_pushnil(L); lua_rawset(L,-3); + mplib_push_S(left_type); lua_pushstring(L, knot_type_enum[mp_knot_left_type(mp, p)]); lua_rawset(L, -3); + mplib_push_S(right_type); lua_pushstring(L, knot_type_enum[mp_knot_right_type(mp, p)]); lua_rawset(L, -3); + lua_pop(L,1); + p = mp_knot_next(mp,p); + } + + lua_pushboolean(L, 1); + return 1; +BAD: + if (p != NULL) { + mp_close_path (mp, p, first); + mp_free_path (mp, p); + } + lua_pushboolean(L, 0); + lua_pushstring(L, errormsg); + return 2; +} + +/* figure methods */ + +static int mplib_fig_collect(lua_State * L) +{ + struct mp_edge_object **hh = is_fig(L, 1); + if (*hh != NULL) { + mp_gr_toss_objects(*hh); + *hh = NULL; + } + return 0; +} + +static int mplib_fig_body(lua_State * L) +{ + int i = 1; + struct mp_graphic_object **v; + struct mp_graphic_object *p; + struct mp_edge_object **hh = is_fig(L, 1); + lua_newtable(L); + p = (*hh)->body; + while (p != NULL) { + v = lua_newuserdata(L, sizeof(struct mp_graphic_object *)); + *v = p; + luaL_getmetatable(L, MPLIB_GR_METATABLE); + lua_setmetatable(L, -2); + lua_rawseti(L, -2, i); + i++; + p = p->next; + } + (*hh)->body = NULL; /* prevent double free */ + return 1; +} + +static int mplib_fig_copy_body(lua_State * L) +{ + int i = 1; + struct mp_graphic_object **v; + struct mp_graphic_object *p; + struct mp_edge_object **hh = is_fig(L, 1); + lua_newtable(L); + p = (*hh)->body; + while (p != NULL) { + v = lua_newuserdata(L, sizeof(struct mp_graphic_object *)); + *v = mp_gr_copy_object((*hh)->parent, p); + luaL_getmetatable(L, MPLIB_GR_METATABLE); + lua_setmetatable(L, -2); + lua_rawseti(L, -2, i); + i++; + p = p->next; + } + return 1; +} + + +static int mplib_fig_tostring(lua_State * L) +{ + struct mp_edge_object **hh = is_fig(L, 1); + (void)lua_pushfstring(L, "
", *hh); + return 1; +} + +static int mplib_fig_postscript(lua_State * L) +{ + mp_run_data *res; + struct mp_edge_object **hh = is_fig(L, 1); + int prologues = (int)luaL_optnumber(L, 2, (lua_Number)-1); + int procset = (int)luaL_optnumber(L, 3, (lua_Number)-1); + if (mp_ps_ship_out(*hh, prologues, procset) + && (res = mp_rundata((*hh)->parent)) + && (res->ship_out.size != 0)) { + lua_pushstring(L, res->ship_out.data); + } else { + lua_pushnil(L); + } + return 1; +} + +static int mplib_fig_svg(lua_State * L) +{ + mp_run_data *res; + struct mp_edge_object **hh = is_fig(L, 1); + int prologues = (int)luaL_optnumber(L, 2, (lua_Number)-1); + if (mp_svg_ship_out(*hh, prologues) + && (res = mp_rundata((*hh)->parent)) + && (res->ship_out.size != 0)) { + lua_pushstring(L, res->ship_out.data); + } else { + lua_pushnil(L); + } + return 1; +} + + +static int mplib_fig_png(lua_State * L) +{ + mp_run_data *res; + struct mp_edge_object **hh = is_fig(L, 1); + const char *string = luaL_optstring(L, 2, NULL); + if (mp_png_ship_out(*hh, string) + && (res = mp_rundata((*hh)->parent)) + && (res->ship_out.size != 0)) { + lua_pushlstring(L, res->ship_out.data, res->ship_out.size); + } else { + lua_pushnil(L); + } + return 1; +} + +static int mplib_fig_filename(lua_State * L) +{ + struct mp_edge_object **hh = is_fig(L, 1); + if (*hh != NULL) { + char *s = (*hh)->filename; + lua_pushstring(L, s); + } else { + lua_pushnil(L); + } + return 1; +} + +static int mplib_fig_width(lua_State * L) +{ + struct mp_edge_object **hh = is_fig(L, 1); + if (*hh != NULL) { + lua_pushnumber(L, (double) (*hh)->width); + } else { + lua_pushnil(L); + } + return 1; +} + +static int mplib_fig_height(lua_State * L) +{ + struct mp_edge_object **hh = is_fig(L, 1); + if (*hh != NULL) { + lua_pushnumber(L, (double) (*hh)->height); + } else { + lua_pushnil(L); + } + return 1; +} + +static int mplib_fig_depth(lua_State * L) +{ + struct mp_edge_object **hh = is_fig(L, 1); + if (*hh != NULL) { + lua_pushnumber(L, (double) (*hh)->depth); + } else { + lua_pushnil(L); + } + return 1; +} + +static int mplib_fig_italcorr(lua_State * L) +{ + struct mp_edge_object **hh = is_fig(L, 1); + if (*hh != NULL) { + lua_pushnumber(L, (double) (*hh)->ital_corr); + } else { + lua_pushnil(L); + } + return 1; +} + +static int mplib_fig_charcode(lua_State * L) +{ + struct mp_edge_object **hh = is_fig(L, 1); + if (*hh != NULL) { + lua_pushnumber(L, (lua_Number)(*hh)->charcode); + } else { + lua_pushnil(L); + } + return 1; +} + + + +static int mplib_fig_bb(lua_State * L) +{ + struct mp_edge_object **hh = is_fig(L, 1); + lua_newtable(L); + lua_pushnumber(L, (double) (*hh)->minx); + lua_rawseti(L, -2, 1); + lua_pushnumber(L, (double) (*hh)->miny); + lua_rawseti(L, -2, 2); + lua_pushnumber(L, (double) (*hh)->maxx); + lua_rawseti(L, -2, 3); + lua_pushnumber(L, (double) (*hh)->maxy); + lua_rawseti(L, -2, 4); + return 1; +} + +/* object methods */ + +static int mplib_gr_collect(lua_State * L) +{ + struct mp_graphic_object **hh = is_gr_object(L, 1); + if (*hh != NULL) { + mp_gr_toss_object(*hh); + *hh = NULL; + } + return 0; +} + +static int mplib_gr_tostring(lua_State * L) +{ + struct mp_graphic_object **hh = is_gr_object(L, 1); + (void)lua_pushfstring(L, "", *hh); + return 1; +} + +#define pyth(a,b) (sqrt((a)*(a) + (b)*(b))) + +#define aspect_bound (10.0/65536.0) +#define aspect_default 1.0 + +static double eps = 0.0001; + +static double coord_range_x (mp_gr_knot h, double dz) { + double z; + double zlo = 0.0, zhi = 0.0; + mp_gr_knot f = h; + while (h != NULL) { + z = h->x_coord; + if (z < zlo) zlo = z; else if (z > zhi) zhi = z; + z = h->right_x; + if (z < zlo) zlo = z; else if (z > zhi) zhi = z; + z = h->left_x; + if (z < zlo) zlo = z; else if (z > zhi) zhi = z; + h = h->next; + if (h==f) + break; + } + return (zhi - zlo <= dz ? aspect_bound : aspect_default); +} + +static double coord_range_y (mp_gr_knot h, double dz) { + double z; + double zlo = 0.0, zhi = 0.0; + mp_gr_knot f = h; + while (h != NULL) { + z = h->y_coord; + if (z < zlo) zlo = z; else if (z > zhi) zhi = z; + z = h->right_y; + if (z < zlo) zlo = z; else if (z > zhi) zhi = z; + z = h->left_y; + if (z < zlo) zlo = z; else if (z > zhi) zhi = z; + h = h->next; + if (h==f) + break; + } + return (zhi - zlo <= dz ? aspect_bound : aspect_default); +} + + +static int mplib_gr_peninfo(lua_State * L) { + double x_coord, y_coord, left_x, left_y, right_x, right_y; + double wx, wy; + double rx = 1.0, sx = 0.0, sy = 0.0, ry = 1.0, tx = 0.0, ty = 0.0; + double width = 1.0; + mp_gr_knot p = NULL, path = NULL; + struct mp_graphic_object **hh = is_gr_object(L, -1); + if (!*hh) { + lua_pushnil(L); + return 1; + } + if ((*hh)->type == mp_fill_code) { + p = ((mp_fill_object *)(*hh))->pen_p; + path = ((mp_fill_object *)(*hh))->path_p; + } else if ((*hh)->type == mp_stroked_code) { + p = ((mp_stroked_object *)(*hh))->pen_p; + path = ((mp_stroked_object *)(*hh))->path_p; + } + if (p==NULL || path == NULL) { + lua_pushnil(L); + return 1; + } + x_coord = p->x_coord; + y_coord = p->y_coord; + left_x = p->left_x; + left_y = p->left_y; + right_x = p->right_x; + right_y = p->right_y; + if ((right_x == x_coord) && (left_y == y_coord)) { + wx = fabs(left_x - x_coord); + wy = fabs(right_y - y_coord); + } else { + wx = pyth(left_x - x_coord, right_x - x_coord); + wy = pyth(left_y - y_coord, right_y - y_coord); + } + if ((wy/coord_range_x(path, wx)) >= (wx/coord_range_y(path, wy))) + width = wy; + else + width = wx; + tx = x_coord; + ty = y_coord; + sx = left_x - tx; + rx = left_y - ty; + ry = right_x - tx; + sy = right_y - ty; + if (width !=1.0) { + if (width == 0.0) { + sx = 1.0; sy = 1.0; + } else { + rx/=width; ry/=width; sx/=width; sy/=width; + } + } + if (fabs(sx) < eps) sx = eps; + if (fabs(sy) < eps) sy = eps; + lua_newtable(L); + lua_pushnumber(L,width); lua_setfield(L,-2,"width"); + lua_pushnumber(L,rx); lua_setfield(L,-2,"rx"); + lua_pushnumber(L,sx); lua_setfield(L,-2,"sx"); + lua_pushnumber(L,sy); lua_setfield(L,-2,"sy"); + lua_pushnumber(L,ry); lua_setfield(L,-2,"ry"); + lua_pushnumber(L,tx); lua_setfield(L,-2,"tx"); + lua_pushnumber(L,ty); lua_setfield(L,-2,"ty"); + return 1; +} + + +static int mplib_gr_fields(lua_State * L) +{ + const char **fields; + int i; + struct mp_graphic_object **hh = is_gr_object(L, 1); + if (*hh) { + switch ((*hh)->type) { + case mp_fill_code: + fields = fill_fields; + break; + case mp_stroked_code: + fields = stroked_fields; + break; + case mp_text_code: + fields = text_fields; + break; + case mp_special_code: + fields = special_fields; + break; + case mp_start_clip_code: + fields = start_clip_fields; + break; + case mp_start_bounds_code: + fields = start_bounds_fields; + break; + case mp_stop_clip_code: + fields = stop_clip_fields; + break; + case mp_stop_bounds_code: + fields = stop_bounds_fields; + break; + default: + fields = no_fields; + } + lua_newtable(L); + for (i = 0; fields[i] != NULL; i++) { + lua_pushstring(L, fields[i]); + lua_rawseti(L, -2, (i + 1)); + } + } else { + lua_pushnil(L); + } + return 1; +} + + +#define mplib_push_number(L,x) lua_pushnumber(L,(lua_Number)(x)) + +#define MPLIB_PATH 0 +#define MPLIB_PEN 1 + +static void mplib_push_path(lua_State * L, mp_gr_knot h, int is_pen) +{ + mp_gr_knot p; /* for scanning the path */ + int i = 1; + p = h; + if (p != NULL) { + lua_newtable(L); + do { + lua_createtable(L, 0, 6); + if (!is_pen) { + if (p->data.types.left_type != mp_explicit) { + mplib_push_S(left_type); + lua_pushstring(L, knot_type_enum[p->data.types.left_type]); + lua_rawset(L, -3); + } + if (p->data.types.right_type != mp_explicit) { + mplib_push_S(right_type); + lua_pushstring(L, knot_type_enum[p->data.types.right_type]); + lua_rawset(L, -3); + } + } + mplib_push_S(x_coord); + mplib_push_number(L, p->x_coord); + lua_rawset(L, -3); + mplib_push_S(y_coord); + mplib_push_number(L, p->y_coord); + lua_rawset(L, -3); + mplib_push_S(left_x); + mplib_push_number(L, p->left_x); + lua_rawset(L, -3); + mplib_push_S(left_y); + mplib_push_number(L, p->left_y); + lua_rawset(L, -3); + mplib_push_S(right_x); + mplib_push_number(L, p->right_x); + lua_rawset(L, -3); + mplib_push_S(right_y); + mplib_push_number(L, p->right_y); + lua_rawset(L, -3); + lua_rawseti(L, -2, i); + i++; + if (p->data.types.right_type == mp_endpoint) { + return; + } + p = p->next; + } while (p != h); + } else { + lua_pushnil(L); + } +} + +/* this assumes that the top of the stack is a table + or nil already in the case + */ +static void mplib_push_pentype(lua_State * L, mp_gr_knot h) +{ + mp_gr_knot p; /* for scanning the path */ + p = h; + if (p == NULL) { + /* do nothing */ + } else if (p == p->next) { + mplib_push_S(type); + lua_pushstring(L, "elliptical"); + lua_rawset(L, -3); + } else { + } +} + +#define set_color_objects(pq) \ + object_color_model = pq->color_model; \ + object_color_a = pq->color.a_val; \ + object_color_b = pq->color.b_val; \ + object_color_c = pq->color.c_val; \ + object_color_d = pq->color.d_val; + + +static void mplib_push_color(lua_State * L, struct mp_graphic_object *p) +{ + int object_color_model; + double object_color_a, object_color_b, object_color_c, object_color_d; + if (p != NULL) { + if (p->type == mp_fill_code) { + mp_fill_object *h = (mp_fill_object *) p; + set_color_objects(h); + } else if (p->type == mp_stroked_code) { + mp_stroked_object *h = (mp_stroked_object *) p; + set_color_objects(h); + } else { + mp_text_object *h = (mp_text_object *) p; + set_color_objects(h); + } + lua_newtable(L); + if (object_color_model >= mp_grey_model) { + mplib_push_number(L, object_color_a); + lua_rawseti(L, -2, 1); + if (object_color_model >= mp_rgb_model) { + mplib_push_number(L, object_color_b); + lua_rawseti(L, -2, 2); + mplib_push_number(L, object_color_c); + lua_rawseti(L, -2, 3); + if (object_color_model == mp_cmyk_model) { + mplib_push_number(L, object_color_d); + lua_rawseti(L, -2, 4); + } + } + } + } else { + lua_pushnil(L); + } +} + +/* the dash scale is not exported, the field has no external value */ +static void mplib_push_dash(lua_State * L, struct mp_stroked_object *h) +{ + mp_dash_object *d; + double ds; + if (h != NULL && h->dash_p != NULL) { + d = h->dash_p; + lua_newtable(L); + mplib_push_number(L, d->offset); + lua_setfield(L, -2, "offset"); + if (d->array != NULL) { + int i = 0; + lua_newtable(L); + while (*(d->array + i) != -1) { + ds = *(d->array + i); + lua_pushnumber(L, ds); + i++; + lua_rawseti(L, -2, i); + } + lua_setfield(L, -2, "dashes"); + } + } else { + lua_pushnil(L); + } +} + +static void mplib_push_transform(lua_State * L, struct mp_text_object *h) +{ + int i = 1; + if (h != NULL) { + lua_createtable(L, 6, 0); + mplib_push_number(L, h->tx); + lua_rawseti(L, -2, i); + i++; + mplib_push_number(L, h->ty); + lua_rawseti(L, -2, i); + i++; + mplib_push_number(L, h->txx); + lua_rawseti(L, -2, i); + i++; + mplib_push_number(L, h->tyx); + lua_rawseti(L, -2, i); + i++; + mplib_push_number(L, h->txy); + lua_rawseti(L, -2, i); + i++; + mplib_push_number(L, h->tyy); + lua_rawseti(L, -2, i); + i++; + } else { + lua_pushnil(L); + } +} + +#define FIELD(A) (mplib_is_S(A,2)) + +static void mplib_fill(lua_State * L, struct mp_fill_object *h) +{ + if (FIELD(path)) { + mplib_push_path(L, h->path_p, MPLIB_PATH); + } else if (FIELD(htap)) { + mplib_push_path(L, h->htap_p, MPLIB_PATH); + } else if (FIELD(pen)) { + mplib_push_path(L, h->pen_p, MPLIB_PEN); + mplib_push_pentype(L, h->pen_p); + } else if (FIELD(color)) { + mplib_push_color(L, (mp_graphic_object *) h); + } else if (FIELD(linejoin)) { + lua_pushnumber(L, (lua_Number)h->ljoin); + } else if (FIELD(miterlimit)) { + mplib_push_number(L, h->miterlim); + } else if (FIELD(prescript)) { + lua_pushstring(L, h->pre_script); + } else if (FIELD(postscript)) { + lua_pushstring(L, h->post_script); + } else { + lua_pushnil(L); + } +} + +static void mplib_stroked(lua_State * L, struct mp_stroked_object *h) +{ + if (FIELD(path)) { + mplib_push_path(L, h->path_p, MPLIB_PATH); + } else if (FIELD(pen)) { + mplib_push_path(L, h->pen_p, MPLIB_PEN); + mplib_push_pentype(L, h->pen_p); + } else if (FIELD(color)) { + mplib_push_color(L, (mp_graphic_object *) h); + } else if (FIELD(dash)) { + mplib_push_dash(L, h); + } else if (FIELD(linecap)) { + lua_pushnumber(L, (lua_Number)h->lcap); + } else if (FIELD(linejoin)) { + lua_pushnumber(L, (lua_Number)h->ljoin); + } else if (FIELD(miterlimit)) { + mplib_push_number(L, h->miterlim); + } else if (FIELD(prescript)) { + lua_pushstring(L, h->pre_script); + } else if (FIELD(postscript)) { + lua_pushstring(L, h->post_script); + } else { + lua_pushnil(L); + } +} + +static void mplib_text(lua_State * L, struct mp_text_object *h) +{ + if (FIELD(text)) { + lua_pushstring(L, h->text_p); + } else if (FIELD(dsize)) { + mplib_push_number(L, (h->font_dsize / 16)); + } else if (FIELD(font)) { + lua_pushstring(L, h->font_name); + } else if (FIELD(color)) { + mplib_push_color(L, (mp_graphic_object *) h); + } else if (FIELD(width)) { + mplib_push_number(L, h->width); + } else if (FIELD(height)) { + mplib_push_number(L, h->height); + } else if (FIELD(depth)) { + mplib_push_number(L, h->depth); + } else if (FIELD(transform)) { + mplib_push_transform(L, h); + } else if (FIELD(prescript)) { + lua_pushstring(L, h->pre_script); + } else if (FIELD(postscript)) { + lua_pushstring(L, h->post_script); + } else { + lua_pushnil(L); + } +} + +static void mplib_special(lua_State * L, struct mp_special_object *h) +{ + if (FIELD(prescript)) { + lua_pushstring(L, h->pre_script); + } else { + lua_pushnil(L); + } +} + +static void mplib_start_bounds(lua_State * L, struct mp_bounds_object *h) +{ + if (FIELD(path)) { + mplib_push_path(L, h->path_p, MPLIB_PATH); + } else { + lua_pushnil(L); + } +} + +static void mplib_start_clip(lua_State * L, struct mp_clip_object *h) +{ + if (FIELD(path)) { + mplib_push_path(L, h->path_p, MPLIB_PATH); + } else { + lua_pushnil(L); + } +} + +static int mplib_gr_index(lua_State * L) +{ + struct mp_graphic_object **hh = is_gr_object(L, 1); + if (*hh) { + struct mp_graphic_object *h = *hh; + + if (mplib_is_S(type, 2)) { + lua_rawgeti(L, LUA_REGISTRYINDEX, mplib_type_Ses[h->type]); + } else { + switch (h->type) { + case mp_fill_code: + mplib_fill(L, (mp_fill_object *) h); + break; + case mp_stroked_code: + mplib_stroked(L, (mp_stroked_object *) h); + break; + case mp_text_code: + mplib_text(L, (mp_text_object *) h); + break; + case mp_special_code: + mplib_special(L, (mp_special_object *) h); + break; + case mp_start_clip_code: + mplib_start_clip(L, (mp_clip_object *) h); + break; + case mp_start_bounds_code: + mplib_start_bounds(L, (mp_bounds_object *) h); + break; + case mp_stop_clip_code: + case mp_stop_bounds_code: + default: + lua_pushnil(L); + } + } + } else { + lua_pushnil(L); + } + return 1; +} + + +static const struct luaL_reg mplib_meta[] = { + {"__gc", mplib_collect}, + {"__tostring", mplib_tostring}, + {NULL, NULL} /* sentinel */ +}; + +static const struct luaL_reg mplib_fig_meta[] = { + {"__gc", mplib_fig_collect}, + {"__tostring", mplib_fig_tostring}, + {"objects", mplib_fig_body}, + {"copy_objects", mplib_fig_copy_body}, + {"filename", mplib_fig_filename}, + {"postscript", mplib_fig_postscript}, + {"png", mplib_fig_png}, + {"svg", mplib_fig_svg}, + {"boundingbox", mplib_fig_bb}, + {"width", mplib_fig_width}, + {"height", mplib_fig_height}, + {"depth", mplib_fig_depth}, + {"italcorr", mplib_fig_italcorr}, + {"charcode", mplib_fig_charcode}, + {NULL, NULL} /* sentinel */ +}; + +static const struct luaL_reg mplib_gr_meta[] = { + {"__gc", mplib_gr_collect}, + {"__tostring", mplib_gr_tostring}, + {"__index", mplib_gr_index}, + {NULL, NULL} /* sentinel */ +}; + +static const struct luaL_reg mplib_d[] = { + {"execute", mplib_execute}, + {"finish", mplib_finish}, + {"char_width", mplib_charwidth}, + {"char_height", mplib_charheight}, + {"char_depth", mplib_chardepth}, + {"statistics", mplib_statistics}, + {"solve_path", mplib_solve_path}, + {"get_numeric", mplib_get_numeric}, + {"get_number", mplib_get_numeric}, + {"get_boolean", mplib_get_boolean}, + {"get_string", mplib_get_string}, + {NULL, NULL} /* sentinel */ +}; + + +static const struct luaL_reg mplib_m[] = { + {"new", mplib_new}, + {"version", mplib_version}, + {"fields", mplib_gr_fields}, + {"pen_info", mplib_gr_peninfo}, + {"get_numeric", mplib_get_numeric}, + {"get_number", mplib_get_numeric}, + {"get_boolean", mplib_get_boolean}, + {"get_string", mplib_get_string}, + {NULL, NULL} /* sentinel */ +}; + + +int luaopen_mplib(lua_State * L) +{ + mplib_init_Ses(L); + + luaL_newmetatable(L, MPLIB_GR_METATABLE); + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_register(L, NULL, mplib_gr_meta); /* object meta methods */ + lua_pop(L, 1); + + luaL_newmetatable(L, MPLIB_FIG_METATABLE); + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_register(L, NULL, mplib_fig_meta); /* figure meta methods */ + lua_pop(L, 1); + + luaL_newmetatable(L, MPLIB_METATABLE); + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_register(L, NULL, mplib_meta); /* meta methods */ + luaL_register(L, NULL, mplib_d); /* dict methods */ + luaL_register(L, "mplib", mplib_m); /* module functions */ + return 1; +} diff --git a/source/texk/web2c/mplibdir/mp.w b/source/texk/web2c/mplibdir/mp.w index 956d8b747..bff157140 100644 --- a/source/texk/web2c/mplibdir/mp.w +++ b/source/texk/web2c/mplibdir/mp.w @@ -1,34523 +1,34629 @@ -% $Id: mp.w 1962 2014-03-11 13:18:08Z taco $ -% -% This file is part of MetaPost; -% the MetaPost program is in the public domain. -% See the code in mpost.w for more info. - -% Here is TeX material that gets inserted after \input webmac -\def\hang{\hangindent 3em\noindent\ignorespaces} -\def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces} -\def\ps{PostScript} -\def\psqrt#1{\sqrt{\mathstrut#1}} -\def\k{_{k+1}} -\def\pct!{{\char`\%}} % percent sign in ordinary text -\font\tenlogo=logo10 % font used for the METAFONT logo -\font\logos=logosl10 -\def\MF{{\tenlogo META}\-{\tenlogo FONT}} -\def\MP{{\tenlogo META}\-{\tenlogo POST}} -\def\<#1>{$\langle#1\rangle$} -\def\section{\mathhexbox278} -\let\swap=\leftrightarrow -\def\round{\mathop{\rm round}\nolimits} -\mathchardef\vbv="026A % synonym for `\|' -\def\vb{\relax\ifmmode\vbv\else$\vbv$\fi} - -\def\(#1){} % this is used to make section names sort themselves better -\def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@> -\def\title{MetaPost} -\pdfoutput=1 -\pageno=3 - -@* Introduction. - -This is \MP\ by John Hobby, a graphics-language processor based on D. E. Knuth's \MF. - -Much of the original Pascal version of this program was copied with -permission from MF.web Version 1.9. It interprets a language very -similar to D.E. Knuth's METAFONT, but with changes designed to make it -more suitable for PostScript output. - -The main purpose of the following program is to explain the algorithms of \MP\ -as clearly as possible. However, the program has been written so that it -can be tuned to run efficiently in a wide variety of operating environments -by making comparatively few changes. Such flexibility is possible because -the documentation that follows is written in the \.{WEB} language, which is -at a higher level than C. - -A large piece of software like \MP\ has inherent complexity that cannot -be reduced below a certain level of difficulty, although each individual -part is fairly simple by itself. The \.{WEB} language is intended to make -the algorithms as readable as possible, by reflecting the way the -individual program pieces fit together and by providing the -cross-references that connect different parts. Detailed comments about -what is going on, and about why things were done in certain ways, have -been liberally sprinkled throughout the program. These comments explain -features of the implementation, but they rarely attempt to explain the -\MP\ language itself, since the reader is supposed to be familiar with -{\sl The {\logos METAFONT\/}book} as well as the manual -@.WEB@> -@:METAFONTbook}{\sl The {\logos METAFONT\/}book@> -{\sl A User's Manual for MetaPost}, Computing Science Technical Report 162, -AT\AM T Bell Laboratories. - -@ The present implementation is a preliminary version, but the possibilities -for new features are limited by the desire to remain as nearly compatible -with \MF\ as possible. - -On the other hand, the \.{WEB} description can be extended without changing -the core of the program, and it has been designed so that such -extensions are not extremely difficult to make. -The |banner| string defined here should be changed whenever \MP\ -undergoes any modifications, so that it will be clear which version of -\MP\ might be the guilty party when a problem arises. -@^extensions to \MP@> -@^system dependencies@> - -@d default_banner "This is MetaPost, Version 1.900" /* printed when \MP\ starts */ -@d true 1 -@d false 0 - -@= -#define metapost_version "1.900" - -@ The external library header for \MP\ is |mplib.h|. It contains a -few typedefs and the header defintions for the externally used -fuctions. - -The most important of the typedefs is the definition of the structure -|MP_options|, that acts as a small, configurable front-end to the fairly -large |MP_instance| structure. - -@(mplib.h@>= -#ifndef MPLIB_H -#define MPLIB_H 1 -#include -#ifndef HAVE_BOOLEAN -typedef int boolean; -#endif -@ -typedef struct MP_instance *MP; -@ -typedef struct MP_options { - @