summaryrefslogtreecommitdiff
path: root/source/luametatex/source/luaoptional/lmtghostscript.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/luametatex/source/luaoptional/lmtghostscript.c')
-rw-r--r--source/luametatex/source/luaoptional/lmtghostscript.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/source/luametatex/source/luaoptional/lmtghostscript.c b/source/luametatex/source/luaoptional/lmtghostscript.c
new file mode 100644
index 000000000..b16c3767c
--- /dev/null
+++ b/source/luametatex/source/luaoptional/lmtghostscript.c
@@ -0,0 +1,175 @@
+/*
+ See license.txt in the root of this project.
+*/
+
+# include "luametatex.h"
+# include "lmtoptional.h"
+
+# define GS_ARG_ENCODING_UTF8 1
+
+typedef struct gslib_state_info {
+
+ int initialized;
+ int padding;
+ luaL_Buffer outbuffer;
+ luaL_Buffer errbuffer;
+
+ int (*gsapi_new_instance) (
+ void **pinstance,
+ void *caller_handle
+ );
+
+ void (*gsapi_delete_instance) (
+ void * instance
+ );
+
+ int (*gsapi_set_arg_encoding) (
+ void *instance,
+ int encoding
+ );
+
+ int (*gsapi_init_with_args) (
+ void *instance,
+ int argc,
+ const char **argv
+ );
+
+ int (*gsapi_set_stdio) (
+ void *instance,
+ int (*stdin_fn )(void *caller_handle, char *buf, int len),
+ int (*stdout_fn)(void *caller_handle, const char *str, int len),
+ int (*stderr_fn)(void *caller_handle, const char *str, int len)
+ );
+
+ /*
+ int (*gsapi_run_string_begin) (void *instance, int user_errors, int *pexit_code);
+ int (*gsapi_run_string_continue) (void *instance, const char *str, unsigned int length, int user_errors, int *pexit_code);
+ int (*gsapi_run_string_end) (void *instance, int user_errors, int *pexit_code);
+ int (*gsapi_run_string_with_length) (void *instance, const char *str, unsigned int length, int user_errors, int *pexit_code);
+ int (*gsapi_run_string) (void *instance, const char *str, int user_errors, int *pexit_code);
+ int (*gsapi_run_file) (void *instance, const char *file_name, int user_errors, int *pexit_code);
+ int (*gsapi_exit) (void *instance);
+ */
+
+} gslib_state_info;
+
+static gslib_state_info gslib_state = {
+
+ .initialized = 0,
+ .padding = 0,
+ /* .outbuffer = NULL, */
+ /* .errbuffer = NULL, */
+
+ .gsapi_new_instance = NULL,
+ .gsapi_delete_instance = NULL,
+ .gsapi_set_arg_encoding = NULL,
+ .gsapi_init_with_args = NULL,
+ .gsapi_set_stdio = NULL,
+
+};
+
+static int gslib_initialize(lua_State * L)
+{
+ if (! gslib_state.initialized) {
+ const char *filename = lua_tostring(L, 1);
+ if (filename) {
+
+ lmt_library lib = lmt_library_load(filename);
+
+ gslib_state.gsapi_new_instance = lmt_library_find(lib, "gsapi_new_instance");
+ gslib_state.gsapi_delete_instance = lmt_library_find(lib, "gsapi_delete_instance");
+ gslib_state.gsapi_set_arg_encoding = lmt_library_find(lib, "gsapi_set_arg_encoding");
+ gslib_state.gsapi_init_with_args = lmt_library_find(lib, "gsapi_init_with_args");
+ gslib_state.gsapi_set_stdio = lmt_library_find(lib, "gsapi_set_stdio");
+
+ gslib_state.initialized = lmt_library_okay(lib);
+ }
+ }
+ lua_pushboolean(L, gslib_state.initialized);
+ return 1;
+}
+
+/* We could have a callback for stdout and error. */
+
+static int gslib_stdout(void * caller_handle, const char *str, int len)
+{
+ (void)caller_handle;
+ luaL_addlstring(&gslib_state.outbuffer, str, len);
+ return len;
+}
+
+static int gslib_stderr(void * caller_handle, const char *str, int len)
+{
+ (void)caller_handle;
+ luaL_addlstring(&gslib_state.errbuffer, str, len);
+ return len;
+}
+
+static int gslib_execute(lua_State * L)
+{
+ if (gslib_state.initialized) {
+ if (lua_type(L, 1) == LUA_TTABLE) {
+ size_t n = (int) lua_rawlen(L, 1);
+ if (n > 0) {
+ void *instance = NULL;
+ int result = gslib_state.gsapi_new_instance(&instance, NULL);
+ if (result >= 0) {
+ /*tex
+ Strings are not yet garbage colected. We add some slack. Here MSVC wants
+ |char**| and gcc wants |const char**| i.e.\ doesn't like a castso we just
+ accept the less annoying MSVC warning.
+ */
+ const char** arguments = malloc((n + 2) * sizeof(char*));
+ if (arguments) {
+ int m = 1;
+ /*tex This is a kind of dummy. */
+ arguments[0] = "ghostscript";
+ luaL_buffinit(L, &gslib_state.outbuffer);
+ luaL_buffinit(L, &gslib_state.errbuffer);
+ gslib_state.gsapi_set_stdio(instance, NULL, &gslib_stdout, &gslib_stderr);
+ for (size_t i = 1; i <= n; i++) {
+ lua_rawgeti(L, 1, i);
+ switch (lua_type(L, -1)) {
+ case LUA_TSTRING:
+ case LUA_TNUMBER:
+ {
+ size_t l = 0;
+ const char *s = lua_tolstring(L, -1, &l);
+ if (l > 0) {
+ arguments[m] = s;
+ m += 1;
+ }
+ }
+ break;
+ }
+ lua_pop(L, 1);
+ }
+ arguments[m] = NULL;
+ result = gslib_state.gsapi_set_arg_encoding(instance, GS_ARG_ENCODING_UTF8);
+ result = gslib_state.gsapi_init_with_args(instance, m, arguments);
+ gslib_state.gsapi_delete_instance(instance);
+ /* Nothing done with the array cells! No gc done yet anyway. */
+ free((void *) arguments);
+ lua_pushboolean(L, result >= 0);
+ luaL_pushresult(&gslib_state.outbuffer);
+ luaL_pushresult(&gslib_state.errbuffer);
+ return 3;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static struct luaL_Reg gslib_function_list[] = {
+ { "initialize", gslib_initialize },
+ { "execute", gslib_execute },
+ { NULL, NULL },
+};
+
+int luaopen_ghostscript(lua_State * L)
+{
+ lmt_library_register(L, "ghostscript", gslib_function_list);
+ return 0;
+}