From dd0e8532d0e4fb9260d25190de930543be630be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Wed, 4 Dec 2019 19:52:49 +0100 Subject: [PATCH 1/7] prt_ps: add ctrl+d support --- src/printer/prt_ps.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index 1391b7e0a..ac8319ef8 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -39,6 +39,7 @@ #define PATH_GHOSTSCRIPT_DLL "gsdll32.dll" +#define PATH_GHOSTSCRIPT_SO "libgs.so" static GSDLLAPI int (*ghostscript_revision)(gsapi_revision_t *pr, int len); static GSDLLAPI int (*ghostscript_new_instance)(void **pinstance, void *caller_handle); @@ -192,9 +193,12 @@ write_buffer(ps_t *dev) fseek(fp, 0, SEEK_END); - fprintf(fp, "%s\n", dev->buffer); + fprintf(fp, "%s65536\n", dev->buffer); fclose(fp); + + dev->buffer[0] = 0; + dev->buffer_pos = 0; } static void @@ -255,10 +259,13 @@ ps_write_ctrl(uint8_t val, void *p) dev->buffer_pos = 0; if(!dev->autofeed) break; + // fallthrough case '\n': write_buffer(dev); - dev->buffer[0] = 0; - dev->buffer_pos = 0; + break; + case 0x04: // Ctrl+D + write_buffer(dev); + finish_document(dev); break; } } From 0c9902575658bcc8f36b6dd4527db3d215bc0345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Thu, 5 Dec 2019 00:44:11 +0100 Subject: [PATCH 2/7] prt_ps: added a more verbose message when gsdll32 is not found --- src/lang/language.h | 3 ++- src/printer/prt_ps.c | 3 ++- src/win/86Box.rc | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lang/language.h b/src/lang/language.h index bbbffdb2c..7150fbe2d 100644 --- a/src/lang/language.h +++ b/src/lang/language.h @@ -96,6 +96,7 @@ #define IDS_2120 2120 // "Unable to initialize SDL..." #define IDS_2121 2121 // "Are you sure you want to..." #define IDS_2122 2122 // "Are you sure you want to..." +#define IDS_2123 2123 // "Unable to initialize Ghostscript..." #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -174,7 +175,7 @@ #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 75 +#define STR_NUM_2048 76 #define STR_NUM_3072 11 #define STR_NUM_4096 18 #define STR_NUM_4352 7 diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index ac8319ef8..2ea717de4 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -23,6 +23,7 @@ #include #include #include "../86box.h" +#include "../lang/language.h" #include "../lpt.h" #include "../timer.h" #include "../pit.h" @@ -308,7 +309,7 @@ ghostscript_init() /* Try loading the DLL. */ ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL, ghostscript_imports); if (ghostscript_handle == NULL) { - ui_msgbox(MBX_ERROR, L"Couldn't initialize Ghostscript!"); + ui_msgbox(MBX_ERROR, (wchar_t *) IDS_2123); return; } diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 2c7c0ee61..d9f73af4b 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -903,6 +903,7 @@ BEGIN IDS_2120 "Unable to initialize SDL, SDL2.dll is required" IDS_2121 "Are you sure you want to hard reset the emulated machine?" IDS_2122 "Are you sure you want to quit 86Box?" + IDS_2123 "Unable to initialize Ghostscript, gsdll32.dll is required for automatic convertion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript files (.ps)." END STRINGTABLE DISCARDABLE From 5fc4280479ccf062e37ce1874d54135464480b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Thu, 5 Dec 2019 23:35:53 +0100 Subject: [PATCH 3/7] prt_ps: style, minor bugfixes --- src/printer/prt_ps.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index 2ea717de4..138b62e0c 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -39,8 +39,10 @@ #include -#define PATH_GHOSTSCRIPT_DLL "gsdll32.dll" -#define PATH_GHOSTSCRIPT_SO "libgs.so" +#define PATH_GHOSTSCRIPT_DLL "gsdll32.dll" +#define PATH_GHOSTSCRIPT_SO "libgs.so" + +#define POSTSCRIPT_BUFFER_LENGTH 65536 static GSDLLAPI int (*ghostscript_revision)(gsapi_revision_t *pr, int len); static GSDLLAPI int (*ghostscript_new_instance)(void **pinstance, void *caller_handle); @@ -84,7 +86,7 @@ typedef struct wchar_t filename[260]; - char buffer[65536]; + char buffer[POSTSCRIPT_BUFFER_LENGTH]; uint16_t buffer_pos; } ps_t; @@ -156,7 +158,7 @@ convert_to_pdf(ps_t *dev) ghostscript_delete_instance(instance); - if (code == 0 || code == gs_error_Quit) + if (code == 0) plat_remove(input_fn); else plat_remove(output_fn); @@ -179,10 +181,11 @@ write_buffer(ps_t *dev) wchar_t path[1024]; FILE *fp; + if (dev->buffer[0] == 0) + return; + if (dev->filename[0] == 0) - { plat_tempfile(dev->filename, NULL, L".ps"); - } path[0] = 0; wcscat(path, dev->printer_path); @@ -194,7 +197,7 @@ write_buffer(ps_t *dev) fseek(fp, 0, SEEK_END); - fprintf(fp, "%s65536\n", dev->buffer); + fprintf(fp, "%.*s\n", POSTSCRIPT_BUFFER_LENGTH, dev->buffer); fclose(fp); @@ -207,8 +210,6 @@ timeout_timer(void *priv) { ps_t *dev = (ps_t *) priv; - if (dev == NULL) return; - write_buffer(dev); finish_document(dev); @@ -234,25 +235,20 @@ ps_write_ctrl(uint8_t val, void *p) dev->autofeed = val & 0x02 ? true : false; - if (val & 0x08) - { + if (val & 0x08) { dev->select = true; } - if((val & 0x04) && !(dev->ctrl & 0x04)) - { + if((val & 0x04) && !(dev->ctrl & 0x04)) { // reset printer dev->select = false; reset_ps(dev); } - if(!(val & 0x01) && (dev->ctrl & 0x01)) - { - if (dev->data < 0x20 && dev->data != '\t') - { - switch (dev->data) - { + if(!(val & 0x01) && (dev->ctrl & 0x01)) { + if (dev->data < 0x20 && dev->data != '\t') { + switch (dev->data) { case '\b': dev->buffer[dev->buffer_pos--] = 0; break; @@ -313,12 +309,9 @@ ghostscript_init() return; } - if (ghostscript_revision(&rev, sizeof(rev)) == 0) - { + if (ghostscript_revision(&rev, sizeof(rev)) == 0) { pclog("Loaded %s, rev %ld (%ld)\n", rev.product, rev.revision, rev.revisiondate); - } - else - { + } else { ghostscript_handle = NULL; } } @@ -358,8 +351,7 @@ ps_close(void *p) if (dev == NULL) return; - if (dev->buffer[0] != 0) - { + if (dev->buffer[0] != 0) { write_buffer(dev); finish_document(dev); } From bd8cc556154a38e3aefabcb13726a94300f63438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Sat, 7 Dec 2019 14:49:05 +0100 Subject: [PATCH 4/7] pr_ps: bound checking + code style --- src/printer/prt_ps.c | 136 ++++++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 47 deletions(-) diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index 138b62e0c..b0183d1f3 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -93,7 +93,9 @@ typedef struct static void reset_ps(ps_t *dev) { - if (dev == NULL) return; + if (dev == NULL) { + return; + } dev->ack = false; @@ -143,25 +145,29 @@ convert_to_pdf(ps_t *dev) gsargv[8] = input_fn; code = ghostscript_new_instance(&instance, dev); - if(code < 0) + if (code < 0) { return code; + } code = ghostscript_set_arg_encoding(instance, GS_ARG_ENCODING_UTF16LE); - if (code == 0) + if (code == 0) { code = ghostscript_init_with_args(instance, 9, (char **) gsargv); + } - if (code == 0 || code == gs_error_Quit) + if (code == 0 || code == gs_error_Quit) { code = ghostscript_exit(instance); - else + } else { ghostscript_exit(instance); + } ghostscript_delete_instance(instance); - if (code == 0) + if (code == 0) { plat_remove(input_fn); - else + } else { plat_remove(output_fn); + } return code; } @@ -169,35 +175,39 @@ convert_to_pdf(ps_t *dev) static void finish_document(ps_t *dev) { - if (ghostscript_handle != NULL) + if (ghostscript_handle != NULL) { convert_to_pdf(dev); + } dev->filename[0] = 0; } static void -write_buffer(ps_t *dev) +write_buffer(ps_t *dev, bool newline) { wchar_t path[1024]; FILE *fp; - if (dev->buffer[0] == 0) + if (dev->buffer[0] == 0) { return; + } - if (dev->filename[0] == 0) + if (dev->filename[0] == 0) { plat_tempfile(dev->filename, NULL, L".ps"); + } path[0] = 0; wcscat(path, dev->printer_path); wcscat(path, dev->filename); fp = plat_fopen(path, L"a"); - if (fp == NULL) + if (fp == NULL) { return; + } fseek(fp, 0, SEEK_END); - fprintf(fp, "%.*s\n", POSTSCRIPT_BUFFER_LENGTH, dev->buffer); + fprintf(fp, "%.*s%s", POSTSCRIPT_BUFFER_LENGTH, dev->buffer, newline ? "\n" : ""); fclose(fp); @@ -210,7 +220,7 @@ timeout_timer(void *priv) { ps_t *dev = (ps_t *) priv; - write_buffer(dev); + write_buffer(dev, false); finish_document(dev); timer_disable(&dev->timeout_timer); @@ -221,17 +231,67 @@ ps_write_data(uint8_t val, void *p) { ps_t *dev = (ps_t *) p; - if (dev == NULL) return; + if (dev == NULL) { + return; + } dev->data = (char) val; } +static bool +process_nonprintable(ps_t *dev) +{ + switch (dev->data) { + case '\b': + dev->buffer_pos--; + break; + case '\r': + dev->buffer_pos = 0; + if (dev->autofeed) + write_buffer(dev, true); + break; + case '\n': + write_buffer(dev, true); + break; + case 0x04: // Ctrl+D + write_buffer(dev, false); + finish_document(dev); + break; + + /* Characters that should be written to the buffer as-is */ + case '\t': + case '\v': + return false; + } + + return true; +} + +static void +process_data(ps_t *dev) +{ + if (dev->data < 0x20 || dev->data == 0x7F) { + if (process_nonprintable(dev)) { + return; + } + } + + if (dev->buffer_pos == POSTSCRIPT_BUFFER_LENGTH) { + write_buffer(dev, false); + } + + dev->buffer[dev->buffer_pos++] = dev->data; + dev->buffer[dev->buffer_pos] = 0; +} + static void ps_write_ctrl(uint8_t val, void *p) { ps_t *dev = (ps_t *) p; - if (dev == NULL) return; + if (dev == NULL) { + return; + } dev->autofeed = val & 0x02 ? true : false; @@ -239,38 +299,15 @@ ps_write_ctrl(uint8_t val, void *p) dev->select = true; } - if((val & 0x04) && !(dev->ctrl & 0x04)) { + if ((val & 0x04) && !(dev->ctrl & 0x04)) { // reset printer dev->select = false; reset_ps(dev); } - if(!(val & 0x01) && (dev->ctrl & 0x01)) { - if (dev->data < 0x20 && dev->data != '\t') { - switch (dev->data) { - case '\b': - dev->buffer[dev->buffer_pos--] = 0; - break; - case '\r': - dev->buffer_pos = 0; - if(!dev->autofeed) - break; - // fallthrough - case '\n': - write_buffer(dev); - break; - case 0x04: // Ctrl+D - write_buffer(dev); - finish_document(dev); - break; - } - } - else - { - dev->buffer[dev->buffer_pos++] = dev->data; - dev->buffer[dev->buffer_pos] = 0; - } + if (!(val & 0x01) && (dev->ctrl & 0x01)) { + process_data(dev); dev->ack = true; @@ -289,8 +326,9 @@ ps_read_status(void *p) ret |= 0x80; - if(!dev->ack) + if (!dev->ack) { ret |= 0x40; + } return(ret); } @@ -328,14 +366,16 @@ ps_init(void *lpt) reset_ps(dev); - if(! ghostscript_initialized) + if (!ghostscript_initialized) { ghostscript_init(); + } // Cache print folder path memset(dev->printer_path, 0x00, sizeof(dev->printer_path)); plat_append_filename(dev->printer_path, usr_path, L"printer"); - if (! plat_dir_check(dev->printer_path)) + if (!plat_dir_check(dev->printer_path)) { plat_dir_create(dev->printer_path); + } plat_path_slash(dev->printer_path); timer_add(&dev->pulse_timer, pulse_timer, dev, 0); @@ -349,10 +389,12 @@ ps_close(void *p) { ps_t *dev = (ps_t *) p; - if (dev == NULL) return; + if (dev == NULL) { + return; + } if (dev->buffer[0] != 0) { - write_buffer(dev); + write_buffer(dev, false); finish_document(dev); } From a0f444a76059636b8d5b4e0d08f4c5acbd9bc5ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Sat, 7 Dec 2019 19:47:32 +0100 Subject: [PATCH 5/7] prt_ps: line breaks --- src/printer/prt_ps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index b0183d1f3..18a1e10c6 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -250,6 +250,8 @@ process_nonprintable(ps_t *dev) if (dev->autofeed) write_buffer(dev, true); break; + case '\v': + case '\f': case '\n': write_buffer(dev, true); break; @@ -260,7 +262,6 @@ process_nonprintable(ps_t *dev) /* Characters that should be written to the buffer as-is */ case '\t': - case '\v': return false; } From 5a2d13a92974c87188fe5bdb628420d069dadb2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Sat, 7 Dec 2019 20:29:51 +0100 Subject: [PATCH 6/7] prt_ps: update copyright header --- src/printer/prt_ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index 18a1e10c6..f2392d06f 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -8,7 +8,7 @@ * * Implementation of a generic PostScript printer. * - * Version: @(#)prt_ps.c 1.0.1 2019/12/06 + * Version: @(#)prt_ps.c 1.0.2 2019/12/08 * * Authors: David Hrdlička, * From 111dee6eb0c371248eba9ba6803403c79ee03161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Tue, 10 Dec 2019 17:29:53 +0100 Subject: [PATCH 7/7] prt_ps: proper unloading of ghostscript --- src/printer/prt_ps.c | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index f2392d06f..effb2d07e 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -62,7 +62,6 @@ static dllimp_t ghostscript_imports[] = { }; static void *ghostscript_handle = NULL; -static bool ghostscript_initialized = false; typedef struct { @@ -334,31 +333,11 @@ ps_read_status(void *p) return(ret); } -static void -ghostscript_init() -{ - gsapi_revision_t rev; - - ghostscript_initialized = true; - - /* Try loading the DLL. */ - ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL, ghostscript_imports); - if (ghostscript_handle == NULL) { - ui_msgbox(MBX_ERROR, (wchar_t *) IDS_2123); - return; - } - - if (ghostscript_revision(&rev, sizeof(rev)) == 0) { - pclog("Loaded %s, rev %ld (%ld)\n", rev.product, rev.revision, rev.revisiondate); - } else { - ghostscript_handle = NULL; - } -} - static void * ps_init(void *lpt) { ps_t *dev; + gsapi_revision_t rev; dev = (ps_t *) malloc(sizeof(ps_t)); memset(dev, 0x00, sizeof(ps_t)); @@ -367,8 +346,17 @@ ps_init(void *lpt) reset_ps(dev); - if (!ghostscript_initialized) { - ghostscript_init(); + /* Try loading the DLL. */ + ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL, ghostscript_imports); + if (ghostscript_handle == NULL) { + ui_msgbox(MBX_ERROR, (wchar_t *) IDS_2123); + } else { + if (ghostscript_revision(&rev, sizeof(rev)) == 0) { + pclog("Loaded %s, rev %ld (%ld)\n", rev.product, rev.revision, rev.revisiondate); + } else { + dynld_close(ghostscript_handle); + ghostscript_handle = NULL; + } } // Cache print folder path @@ -399,6 +387,11 @@ ps_close(void *p) finish_document(dev); } + if (ghostscript_handle != NULL) { + dynld_close(ghostscript_handle); + ghostscript_handle = NULL; + } + free(dev); }