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 1391b7e0a..effb2d07e 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, * @@ -23,6 +23,7 @@ #include #include #include "../86box.h" +#include "../lang/language.h" #include "../lpt.h" #include "../timer.h" #include "../pit.h" @@ -38,7 +39,10 @@ #include -#define PATH_GHOSTSCRIPT_DLL "gsdll32.dll" +#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); @@ -58,7 +62,6 @@ static dllimp_t ghostscript_imports[] = { }; static void *ghostscript_handle = NULL; -static bool ghostscript_initialized = false; typedef struct { @@ -82,14 +85,16 @@ typedef struct wchar_t filename[260]; - char buffer[65536]; + char buffer[POSTSCRIPT_BUFFER_LENGTH]; uint16_t buffer_pos; } ps_t; static void reset_ps(ps_t *dev) { - if (dev == NULL) return; + if (dev == NULL) { + return; + } dev->ack = false; @@ -139,25 +144,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 || code == gs_error_Quit) + if (code == 0) { plat_remove(input_fn); - else + } else { plat_remove(output_fn); + } return code; } @@ -165,20 +174,24 @@ 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->filename[0] == 0) - { + if (dev->buffer[0] == 0) { + return; + } + + if (dev->filename[0] == 0) { plat_tempfile(dev->filename, NULL, L".ps"); } @@ -187,14 +200,18 @@ write_buffer(ps_t *dev) 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", dev->buffer); + fprintf(fp, "%.*s%s", POSTSCRIPT_BUFFER_LENGTH, dev->buffer, newline ? "\n" : ""); fclose(fp); + + dev->buffer[0] = 0; + dev->buffer_pos = 0; } static void @@ -202,9 +219,7 @@ timeout_timer(void *priv) { ps_t *dev = (ps_t *) priv; - if (dev == NULL) return; - - write_buffer(dev); + write_buffer(dev, false); finish_document(dev); timer_disable(&dev->timeout_timer); @@ -215,58 +230,84 @@ 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 '\v': + case '\f': + 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': + 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; - 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) - { - case '\b': - dev->buffer[dev->buffer_pos--] = 0; - break; - case '\r': - dev->buffer_pos = 0; - if(!dev->autofeed) - break; - case '\n': - write_buffer(dev); - dev->buffer[0] = 0; - dev->buffer_pos = 0; - 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; @@ -285,40 +326,18 @@ ps_read_status(void *p) ret |= 0x80; - if(!dev->ack) + if (!dev->ack) { ret |= 0x40; + } 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, L"Couldn't initialize Ghostscript!"); - 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)); @@ -327,14 +346,25 @@ 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 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); @@ -348,14 +378,20 @@ 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); + if (dev->buffer[0] != 0) { + write_buffer(dev, false); finish_document(dev); } + if (ghostscript_handle != NULL) { + dynld_close(ghostscript_handle); + ghostscript_handle = NULL; + } + free(dev); } 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