1
0
mirror of https://github.com/simh/simh.git synced 2026-01-11 23:52:58 +00:00

SCP: Default to dynamically loading LIBEDIT, LIBPCRE and LIBPNG

This commit is contained in:
Mark Pizzolato 2023-07-23 11:31:24 -10:00
parent 9932fd1610
commit 63028863e4
7 changed files with 317 additions and 112 deletions

View File

@ -96,6 +96,7 @@ Simulator binaries for x86 Linus, x86 macOS, and Windows for all recent changes
- Various failing bugs in tape detach logic are fixed.
- Clean building on Android Termux.
- Proper line editing behavior on all Unix platforms.
- Simulators with video displays have a working SCREENSHOT command.
#### Changes to the PDP-11 and VAX simulators also not in the Open SIMH repo

View File

@ -718,11 +718,13 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin)
# Find PCRE RegEx library.
ifneq (,$(call find_include,pcre))
ifneq (,$(call find_lib,pcre))
OS_CCDEFS += -DHAVE_PCRE_H
OS_LDFLAGS += -lpcre
$(info using libpcre: $(call find_lib,pcre) $(call find_include,pcre))
ifeq ($(LD_SEARCH_NEEDED),$(call need_search,pcre))
OS_LDFLAGS += -L$(dir $(call find_lib,pcre))
ifneq (,$(ALL_DEPENDENCIES))
OS_CCDEFS += -DHAVE_PCRE_H
OS_LDFLAGS += -lpcre
ifeq ($(LD_SEARCH_NEEDED),$(call need_search,pcre))
OS_LDFLAGS += -L$(dir $(call find_lib,pcre))
endif
endif
else
NEEDED_PKGS += DPKG_PCRE
@ -733,14 +735,16 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin)
# Find libedit BSD licensed library for readline support.
ifneq (,$(call find_lib,edit))
ifneq (,$(call find_include,editline/readline))
OS_CCDEFS += -DHAVE_LIBEDIT
OS_LDFLAGS += -ledit
$(info using libedit: $(call find_lib,edit) $(call find_include,editline/readline))
ifneq (,$(call find_lib,termcap))
OS_LDFLAGS += -ltermcap
endif
ifeq ($(LD_SEARCH_NEEDED),$(call need_search,edit))
OS_LDFLAGS += -L$(dir $(call find_lib,edit))
ifneq (,$(ALL_DEPENDENCIES))
OS_CCDEFS += -DHAVE_LIBEDIT
OS_LDFLAGS += -ledit
ifneq (,$(call find_lib,termcap))
OS_LDFLAGS += -ltermcap
endif
ifeq ($(LD_SEARCH_NEEDED),$(call need_search,edit))
OS_LDFLAGS += -L$(dir $(call find_lib,edit))
endif
endif
else
NEEDED_PKGS += DPKG_EDITLINE
@ -802,14 +806,18 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin)
endif
ifneq (,$(call find_include,png))
ifneq (,$(call find_lib,png))
OS_CCDEFS += -DHAVE_LIBPNG
OS_LDFLAGS += -lpng
$(info using libpng: $(call find_lib,png) $(call find_include,png))
OS_CCDEFS += -DHAVE_LIBPNG
ifneq (,$(ALL_DEPENDENCIES))
OS_LDFLAGS += -lpng
endif
ifneq (,$(call find_include,zlib))
ifneq (,$(call find_lib,z))
OS_CCDEFS += -DHAVE_ZLIB
OS_LDFLAGS += -lz
$(info using zlib: $(call find_lib,z) $(call find_include,zlib))
OS_CCDEFS += -DHAVE_ZLIB
ifneq (,$(ALL_DEPENDENCIES))
OS_LDFLAGS += -lz
endif
else
NEEDED_PKGS += DPKG_ZLIB
endif

97
scp.c
View File

@ -239,10 +239,6 @@
#include <fcntl.h>
#endif
#if defined(SIM_HAVE_DLOPEN) /* Dynamic Readline support */
#include <dlfcn.h>
#endif
#ifndef MAX
#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
#endif
@ -693,6 +689,16 @@ static int sim_external_env_count = 0;
static char *sim_tmpnam;
static FILE *sim_tmpfile = NULL;
static int sim_editline_version = 0;
static t_bool sim_pcre_regex_available = FALSE;
/* Dynamically loaded pcre support */
#if !defined(HAVE_PCRE_H)
pcre *(*pcre_compile) (const char *, int, const char **, int *, const unsigned char *);
const char *(*pcre_version) (void);
void (*pcre_free) (void *);
int (*pcre_fullinfo) (const pcre *, const pcre_extra *, int, void *);
int (*pcre_exec) (const pcre *, const pcre_extra *, const char *, int, int, int, int *, int);
#endif
static void sim_exp_initialize (void);
t_stat sim_last_cmd_stat; /* Command Status */
struct timespec cmd_time; /* */
@ -3036,8 +3042,10 @@ AIO_INIT; /* init Asynch I/O */
sim_finit (); /* init fio package */
sim_disk_init (); /* init disk package */
sim_tape_init (); /* init tape package */
sim_exp_initialize (); /* init expect package regex support */
if ((argc > 2) &&
(sim_strcasecmp (argv[1], "CheckSourceCode") == 0)) {
if (sim_pcre_regex_available)
return sim_check_source (argc - 1, argv + 1);
sim_messagef (SCPE_NOFNC, "Missing PCRE support.\n");
sim_messagef (SCPE_NOFNC, "Install the Perl Compatible Regular Expression (PCRE) package for\n");
@ -3187,9 +3195,6 @@ if (!sim_quiet) {
sim_timer_precalibrate_execution_rate ();
sim_reset_time ();
show_version (stdnul, NULL, NULL, 1, NULL); /* Quietly set SIM_OSTYPE */
#if defined (HAVE_PCRE_H)
setenv ("SIM_REGEX_TYPE", "PCRE", 1); /* Publish regex type */
#endif
sim_argv = argv;
if (sim_switches & SWMASK ('T')) /* Command Line -T switch */
@ -7047,18 +7052,18 @@ if (flag) {
fprintf (st, "\n Memory Pointer Size: %d bits", (int)sizeof(dptr)*8);
fprintf (st, "\n %s", sim_toffset_64 ? "Large File (>2GB) support" : "No Large File support");
fprintf (st, "\n SDL Video support: %s", vid_version());
#if defined (HAVE_PCRE_H)
fprintf (st, "\n PCRE RegEx (Version %s) support for EXPECT commands", pcre_version());
#else
fprintf (st, "\n No RegEx support for EXPECT commands");
#endif
if (sim_pcre_regex_available)
fprintf (st, "\n PCRE RegEx (Version %s) support for EXPECT commands", pcre_version());
else
fprintf (st, "\n No RegEx support for EXPECT commands");
fprintf (st, "\n OS clock resolution: %dms", os_tick_size);
fprintf (st, "\n Time taken by msleep(1): %dms", os_ms_sleep_1);
if (sim_editline_version != 0)
if (sim_editline_version != 0) {
if (sim_editline_version > 0xFFFF)
fprintf (st, "\n WinEditLine Version: %d.%d%02X", sim_editline_version >> 16, (sim_editline_version >> 8) & 0xFF, sim_editline_version & 0xFF);
else
fprintf (st, "\n EditLine Version: %d.%d", (sim_editline_version >> 8) & 0xFF, sim_editline_version & 0xFF);
}
if (eth_version ())
fprintf (st, "\n Ethernet packet info: %s", eth_version());
#if defined(__VMS)
@ -10769,22 +10774,9 @@ return read_line_p (NULL, cptr, size, stream);
#include <editline/readline.h>
#endif
#if defined(_WIN32)
#define dlopen(X,Y) LoadLibraryA((X))
#define dlsym(X,Y) GetProcAddress((HINSTANCE)(X),(Y))
#define dlclose(X) FreeLibrary((X))
#ifndef RTLD_NOW
#define RTLD_NOW 0
#endif
#ifndef RTLD_LOCAL
#define RTLD_LOCAL 0
#endif
#define EDIT_DEFAULT_LIB "edit."
#define SIM_DLOPEN_EXTENSION DLL
#else /* !defined(_WIN32) */
#define EDIT_DEFAULT_LIB "libedit."
#if defined(SIM_HAVE_DLOPEN)
#define SIM_DLOPEN_EXTENSION SIM_HAVE_DLOPEN
#endif
#endif /* defined(_WIN32) */
char *read_line_p (const char *prompt, char *cptr, int32 size, FILE *stream)
@ -13458,6 +13450,7 @@ return msg;
The package contains the following public routines:
sim_exp_initialize initialize the expect facility regex sypport
sim_set_expect expect command parser and intializer
sim_set_noexpect noexpect command parser
sim_exp_init initialize an expect context
@ -13469,6 +13462,40 @@ return msg;
sim_exp_check test for rule match
*/
/* Optionally dynamically locate and load pcre support */
void sim_exp_initialize (void)
{
#if defined (SIM_HAVE_DLOPEN) && !defined (HAVE_PCRE_H)
static void *hPCRELib = 0; /* handle to Library */
/* generic function pointer used when loading shared object */
typedef int (*_func)();
hPCRELib = dlopen("libpcre." __STR(SIM_DLOPEN_EXTENSION), RTLD_NOW|RTLD_GLOBAL);
if (!hPCRELib)
hPCRELib = dlopen("libpcre." __STR(SIM_DLOPEN_EXTENSION) ".2", RTLD_NOW|RTLD_GLOBAL);
if (!hPCRELib)
hPCRELib = dlopen("libpcre." __STR(SIM_DLOPEN_EXTENSION) ".3", RTLD_NOW|RTLD_GLOBAL);
#define _load_function(function) *((_func **)&function) = (_func *)((size_t)dlsym(hPCRELib, __STR(function)))
_load_function(pcre_compile);
_load_function(pcre_version);
_load_function(pcre_free);
_load_function(pcre_fullinfo);
_load_function(pcre_exec);
sim_pcre_regex_available = (pcre_compile != NULL);
if (sim_pcre_regex_available)
*((_func *)&pcre_free) = *((_func *)pcre_free); /* Fixup initially indirect pointer */
#else
#if defined (HAVE_PCRE_H)
sim_pcre_regex_available = TRUE;
#endif
#endif /* defined (SIM_HAVE_DLOPEN) && !defined (HAVE_PCRE_H) */
if (sim_pcre_regex_available)
setenv ("SIM_REGEX_TYPE", "PCRE", 1); /* Publish regex type */
}
/* Initialize an expect context. */
t_stat sim_exp_init (EXPECT *exp)
@ -13565,10 +13592,8 @@ if (!ep) /* not there? ok */
free (ep->match); /* deallocate match string */
free (ep->match_pattern); /* deallocate the display format match string */
free (ep->act); /* deallocate action */
#if defined(USE_REGEX)
if (ep->switches & EXP_TYP_REGEX)
pcre_free (ep->regex); /* release compiled regex */
#endif
exp->size -= 1; /* decrement count */
for (i=ep-exp->rules; i<exp->size; i++) /* shuffle up remaining rules */
exp->rules[i] = exp->rules[i+1];
@ -13600,10 +13625,8 @@ for (i=0; i<exp->size; i++) {
free (exp->rules[i].match); /* deallocate match string */
free (exp->rules[i].match_pattern); /* deallocate display format match string */
free (exp->rules[i].act); /* deallocate action */
#if defined(USE_REGEX)
if (exp->rules[i].switches & EXP_TYP_REGEX)
pcre_free (exp->rules[i].regex); /* release compiled regex */
#endif
}
free (exp->rules);
exp->rules = NULL;
@ -13628,8 +13651,7 @@ int i;
match_buf = (uint8 *)calloc (strlen (match) + 1, 1);
if (!match_buf)
return SCPE_MEM;
if (switches & EXP_TYP_REGEX) {
#if !defined (USE_REGEX)
if ((switches & EXP_TYP_REGEX) && !sim_pcre_regex_available) {
free (match_buf);
sim_messagef (SCPE_ARG, "RegEx support is not available\n");
sim_messagef (SCPE_ARG, "The necessary components for expect command regular expression\n");
@ -13637,7 +13659,7 @@ if (switches & EXP_TYP_REGEX) {
sim_messagef (SCPE_ARG, "Install the Perl Compatible Regular Expression (PCRE) package for\n");
return sim_messagef (SCPE_ARG, "your system and try again.\n");
}
#else /* USE_REGEX */
if (switches & EXP_TYP_REGEX) {
pcre *re;
const char *errmsg;
int erroffset, re_nsub;
@ -13650,11 +13672,10 @@ if (switches & EXP_TYP_REGEX) {
free (match_buf);
return SCPE_ARG|SCPE_NOMESSAGE;
}
(void)pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &re_nsub);
(void)pcre_fullinfo (re, NULL, PCRE_INFO_CAPTURECOUNT, &re_nsub);
sim_debug (exp->dbit, exp->dptr, "Expect Regular Expression: \"%s\" has %d sub expressions\n", match_buf, re_nsub);
pcre_free (re);
}
#endif
else {
if (switches & EXP_TYP_REGEX_I) {
free (match_buf);
@ -13691,15 +13712,13 @@ if ((match_buf == NULL) || (ep->match_pattern == NULL)) {
return SCPE_MEM;
}
if (switches & EXP_TYP_REGEX) {
#if defined(USE_REGEX)
const char *errmsg;
int erroffset;
memcpy (match_buf, match+1, strlen(match)-2); /* extract string without surrounding quotes */
match_buf[strlen(match)-2] = '\0';
ep->regex = pcre_compile ((char *)match_buf, (switches & EXP_TYP_REGEX_I) ? PCRE_CASELESS : 0, &errmsg, &erroffset, NULL);
(void)pcre_fullinfo(ep->regex, NULL, PCRE_INFO_CAPTURECOUNT, &ep->re_nsub);
#endif
(void)pcre_fullinfo (ep->regex, NULL, PCRE_INFO_CAPTURECOUNT, &ep->re_nsub);
free (match_buf);
match_buf = NULL;
}
@ -13830,7 +13849,6 @@ if (exp->buf_data < exp->buf_size)
for (i=0; i < exp->size; i++) {
ep = &exp->rules[i];
if (ep->switches & EXP_TYP_REGEX) {
#if defined (USE_REGEX)
int *ovector = NULL;
int rc;
char *cbuf = (char *)exp->buf;
@ -13885,7 +13903,6 @@ for (i=0; i < exp->size; i++) {
break;
}
free (ovector);
#endif
}
else {
if (exp->buf_data < ep->size) /* Too little data to match yet? */

View File

@ -6341,15 +6341,13 @@ else
_rand_uuid_gen (uuidaddr);
}
#elif defined (SIM_HAVE_DLOPEN)
#include <dlfcn.h>
static void
uuid_gen (void *uuidaddr)
{
void (*uuid_generate_c) (void *) = NULL;
void *handle;
handle = dlopen("libuuid." __STR(SIM_HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL);
handle = dlopen("libuuid." __STR(SIM_DLOPEN_EXTENSION), RTLD_NOW|RTLD_GLOBAL);
if (handle)
uuid_generate_c = (void (*)(void *))((size_t)dlsym(handle, "uuid_generate"));
if (uuid_generate_c)

View File

@ -373,6 +373,9 @@
#include "sim_ether.h"
#include "sim_sock.h"
#include "sim_timer.h"
#include "sim_scp_private.h"
#if defined(_WIN32)
#include <direct.h>
#else
@ -1245,10 +1248,6 @@ extern "C" {
#include <winreg.h>
#endif
#ifdef SIM_HAVE_DLOPEN
#include <dlfcn.h>
#endif
#if defined(USE_SHARED) && (defined(_WIN32) || defined(SIM_HAVE_DLOPEN))
/* Dynamic DLL loading technique and modified source comes from
Etherial/WireShark capture_pcap.c */
@ -1267,7 +1266,7 @@ static const char* lib_name =
#elif defined(__APPLE__)
"/usr/lib/libpcap.A.dylib";
#else
"libpcap." __STR(SIM_HAVE_DLOPEN);
"libpcap." __STR(SIM_DLOPEN_EXTENSION);
#endif
static char no_pcap[PCAP_ERRBUF_SIZE] =
@ -1276,7 +1275,7 @@ static char no_pcap[PCAP_ERRBUF_SIZE] =
#elif defined(__APPLE__)
"/usr/lib/libpcap.A.dylib failed to load, install libpcap to use pcap networking";
#else
"libpcap." __STR(SIM_HAVE_DLOPEN) " failed to load, install libpcap to use pcap networking";
"libpcap." __STR(SIM_DLOPEN_EXTENSION) " failed to load, install libpcap to use pcap networking";
#endif
/* define pointers to pcap functions needed */

View File

@ -37,14 +37,144 @@ extern "C" {
#include "sim_sock.h"
#ifdef USE_REGEX
#undef USE_REGEX
#if defined(_WIN32)
#define dlopen(X,Y) LoadLibraryA((X))
#define dlsym(X,Y) GetProcAddress((HINSTANCE)(X),(Y))
#define dlclose(X) FreeLibrary((X))
#define SIM_DLOPEN_EXTENSION DLL
#else /* !defined(_WIN32) */
#if defined(SIM_HAVE_DLOPEN)
#include <dlfcn.h>
#define SIM_DLOPEN_EXTENSION SIM_HAVE_DLOPEN
#endif
#endif /* defined(_WIN32) */
#if defined(HAVE_PCRE_H)
#include <pcre.h>
#define USE_REGEX 1
#else /* !defined(HAVE_PCRE_H) */
/* Dynamically loaded PCRE support */
#if !defined(PCRE_DYNAMIC_SETUP)
#define PCRE_DYNAMIC_SETUP
typedef void pcre;
typedef void pcre_extra;
#ifndef PCRE_INFO_CAPTURECOUNT
#define PCRE_INFO_CAPTURECOUNT 2
#define PCRE_ERROR_NOMATCH (-1)
#endif
#ifndef PCRE_NOTBOL
#define PCRE_NOTBOL 0x00000080 /* E D J */
#endif
#ifndef PCRE_CASELESS
#define PCRE_CASELESS 0x00000001 /* C1 */
#endif
/* Pointers to useful PCRE functions */
extern pcre *(*pcre_compile) (const char *, int, const char **, int *, const unsigned char *);
extern const char *(*pcre_version) (void);
extern void (*pcre_free) (void *);
extern int (*pcre_fullinfo) (const pcre *, const pcre_extra *, int, void *);
extern int (*pcre_exec) (const pcre *, const pcre_extra *, const char *, int, int, int, int *, int);
#endif /* PCRE_DYNAMIC_SETUP */
#endif /* HAVE_PCRE_H */
/* Dynamically loaded PNG support */
#if defined(PNG_H) /* This symbol has been defined by png.h since png 1.0.7 in 2000 */
#if !defined(PNG_ROUTINE)
#if PNG_LIBPNG_VER < 10600
#define png_const_structrp png_structp
#define png_structrp png_structp
#define png_const_inforp png_infop
#define png_inforp png_infop
#define png_const_colorp png_colorp
#define png_const_bytep png_bytep
#undef PNG_SETJMP_SUPPORTED
#endif
/* Pointers to useful PNG functions */
#if defined(_WIN32) || defined(ALL_DEPENDENCIES) /* This would be appropriate anytime libpng is specifically listed at link time */
#define PNG_ROUTINE(_type, _name, _args) _type (*p_##_name) _args = &_name;
#else
#define PNG_ROUTINE(_type, _name, _args) _type (*p_##_name) _args;
#endif
#else /* !defined(PNG_ROUTINE) */
#undef PNG_ROUTINE
static struct PNG_Entry {
const char *entry_name;
void **entry_pointer;
} libpng_entries[] = {
#define DEFINING_PNG_ARRAY 1
#define PNG_ROUTINE(_type, _name, _args) {#_name, (void **)&p_##_name},
#endif
/* Return the user pointer associated with the I/O functions */
PNG_ROUTINE(png_voidp, png_get_io_ptr, (png_const_structrp png_ptr))
/* Allocate and initialize png_ptr struct for reading, and any other memory. */
PNG_ROUTINE(png_structp, png_create_read_struct,
(png_const_charp user_png_ver, png_voidp error_ptr,
png_error_ptr error_fn, png_error_ptr warn_fn))
/* Allocate and initialize png_ptr struct for writing, and any other memory */
PNG_ROUTINE(png_structp, png_create_write_struct,
(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn))
/* Allocate and initialize the info structure */
PNG_ROUTINE(png_infop, png_create_info_struct, (png_const_structrp png_ptr))
/* Free any memory associated with the png_struct and the png_info_structs */
PNG_ROUTINE(void, png_destroy_read_struct, (png_structpp png_ptr_ptr,
png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr))
/* Free any memory associated with the png_struct and the png_info_structs */
PNG_ROUTINE(void, png_destroy_write_struct, (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr))
/* Replace the default data output functions with a user supplied one(s).
* If buffered output is not used, then output_flush_fn can be set to NULL.
* If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time
* output_flush_fn will be ignored (and thus can be NULL).
* It is probably a mistake to use NULL for output_flush_fn if
* write_data_fn is not also NULL unless you have built libpng with
* PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's
* default flush function, which uses the standard *FILE structure, will
* be used.
*/
PNG_ROUTINE(void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr,
png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn))
PNG_ROUTINE(void, png_set_PLTE, (png_structrp png_ptr,
png_inforp info_ptr, png_const_colorp palette, int num_palette))
PNG_ROUTINE(void, png_set_IHDR, (png_const_structrp png_ptr,
png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,
int color_type, int interlace_method, int compression_method,
int filter_method))
/* Use blue, green, red order for pixels. */
PNG_ROUTINE(void, png_set_bgr, (png_structrp png_ptr))
PNG_ROUTINE(void, png_write_info,
(png_structrp png_ptr, png_const_inforp info_ptr))
/* Write a row of image data */
PNG_ROUTINE(void, png_write_row, (png_structrp png_ptr,
png_const_bytep row))
/* Write the image data */
PNG_ROUTINE(void, png_write_image, (png_structrp png_ptr, png_bytepp image))
/* Write the end of the PNG file. */
PNG_ROUTINE(void, png_write_end, (png_structrp png_ptr,
png_inforp info_ptr))
#if defined(PNG_SETJMP_SUPPORTED)
/* This function returns the jmp_buf built in to *png_ptr. It must be
* supplied with an appropriate 'longjmp' function to use on that jmp_buf
* unless the default error function is overridden in which case NULL is
* acceptable. The size of the jmp_buf is checked against the actual size
* allocated by the library - the call will return NULL on a mismatch
* indicating an ABI mismatch.
*/
PNG_ROUTINE(jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr,
png_longjmp_ptr longjmp_fn, size_t jmp_buf_size))
#endif /* PNG_SETJMP_SUPPORTED */
PNG_ROUTINE(png_const_charp, png_get_libpng_ver,
(png_const_structrp png_ptr))
#if defined(ZLIB_VERSION)
PNG_ROUTINE(png_const_charp, zlibVersion,
(void))
#endif
#if defined(DEFINING_PNG_ARRAY)
{0},
};
#undef DEFINING_PNG_ARRAY
#else /* !defined(DEFINING_PNG_ARRAY) */
#undef SIM_SCP_PRIVATE_H_
#include "sim_scp_private.h" /* recurse to generate libpng_entries array */
#endif /* !defined(DEFINING_PNG_ARRAY) */
#endif /* PNG_H */
/* Asynch/Threaded I/O support */
@ -234,6 +364,8 @@ extern int32 sim_asynch_inst_latency;
/* Private SCP only structures */
#if !defined(SIM_SCP_PRIVATE_DONT_REPEAT)
#define SIM_SCP_PRIVATE_DONT_REPEAT
/* Expect rule */
struct EXPTAB {
@ -248,10 +380,8 @@ struct EXPTAB {
#define EXP_TYP_REGEX (SWMASK ('R')) /* rule pattern is a regular expression */
#define EXP_TYP_REGEX_I (SWMASK ('I')) /* regular expression pattern matching should be case independent */
#define EXP_TYP_TIME (SWMASK ('T')) /* halt delay is in microseconds instead of instructions */
#if defined(USE_REGEX)
pcre *regex; /* compiled regular expression */
int re_nsub; /* regular expression sub expression count */
#endif
char *act; /* action string */
};
@ -282,6 +412,7 @@ struct SEND {
int32 insoff; /* insert offset */
int32 extoff; /* extra offset */
};
#endif /* defined(SIM_SCP_PRIVATE_DONT_REPEAT) */
#ifdef __cplusplus
}

View File

@ -28,8 +28,17 @@
*/
#if defined(HAVE_LIBPNG) && defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL)
/*
png.h is included here (before sim_video.h) since some older
versions of png.h report errors when included after setjmp.h
which is included in sim_defs.h.
*/
#include <png.h>
#if defined(HAVE_ZLIB)
#include <zlib.h>
#endif
#endif
#include "sim_video.h"
#include "scp.h"
@ -45,6 +54,7 @@ static VID_QUIT_CALLBACK vid_quit_callback = NULL;
static VID_GAMEPAD_CALLBACK motion_callback[10];
static VID_GAMEPAD_CALLBACK button_callback[10];
static int vid_gamepad_inited = 0;
static t_bool sim_libpng_available = FALSE;
t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback)
{
@ -155,9 +165,10 @@ static char tmp_key_name[40];
*
* This code is free software, available under zlib/libpng license.
* http://www.libpng.org/pub/png/src/libpng-LICENSE.txt
* This code has been slightly modified to leverage indirect pointers
* to the various png routines.
*/
#include <SDL.h>
#include <zlib.h>
#define SUCCESS 0
#define ERROR -1
@ -183,7 +194,7 @@ static void png_error_SDL(png_structp ctx, png_const_charp str)
}
static void png_write_SDL(png_structp png_ptr, png_bytep data, png_size_t length)
{
SDL_RWops *rw = (SDL_RWops*)png_get_io_ptr(png_ptr);
SDL_RWops *rw = (SDL_RWops*)p_png_get_io_ptr(png_ptr);
SDL_RWwrite(rw, data, sizeof(png_byte), length);
}
@ -230,30 +241,31 @@ static int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
if (freedst) SDL_RWclose(dst);
return (ERROR);
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_SDL, NULL); /* err_ptr, err_fn, warn_fn */
png_ptr = p_png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_SDL, NULL); /* err_ptr, err_fn, warn_fn */
if (!png_ptr)
{
SDL_SetError("Unable to png_create_write_struct on %s\n", PNG_LIBPNG_VER_STRING);
if (freedst) SDL_RWclose(dst);
return (ERROR);
}
info_ptr = png_create_info_struct(png_ptr);
info_ptr = p_png_create_info_struct(png_ptr);
if (!info_ptr)
{
SDL_SetError("Unable to png_create_info_struct\n");
png_destroy_write_struct(&png_ptr, NULL);
p_png_destroy_write_struct(&png_ptr, NULL);
if (freedst) SDL_RWclose(dst);
return (ERROR);
}
if (setjmp(png_jmpbuf(png_ptr))) /* All other errors, see also "png_error_SDL" */
#if defined(PNG_SETJMP_SUPPORTED)
if (setjmp(*p_png_set_longjmp_fn(png_ptr, longjmp, sizeof (jmp_buf)))) /* All other errors, see also "png_error_SDL" */
{
png_destroy_write_struct(&png_ptr, &info_ptr);
p_png_destroy_write_struct(&png_ptr, &info_ptr);
if (freedst) SDL_RWclose(dst);
return (ERROR);
}
#endif
/* Setup our RWops writer */
png_set_write_fn(png_ptr, dst, png_write_SDL, NULL); /* w_ptr, write_fn, flush_fn */
p_png_set_write_fn(png_ptr, dst, png_write_SDL, NULL); /* w_ptr, write_fn, flush_fn */
/* Prepare chunks */
colortype = PNG_COLOR_MASK_COLOR;
@ -268,13 +280,13 @@ static int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
pal_ptr[i].green = pal->colors[i].g;
pal_ptr[i].blue = pal->colors[i].b;
}
png_set_PLTE(png_ptr, info_ptr, pal_ptr, pal->ncolors);
p_png_set_PLTE(png_ptr, info_ptr, pal_ptr, pal->ncolors);
free(pal_ptr);
}
else if (surface->format->BytesPerPixel > 3 || surface->format->Amask)
colortype |= PNG_COLOR_MASK_ALPHA;
png_set_IHDR(png_ptr, info_ptr, surface->w, surface->h, 8, colortype,
p_png_set_IHDR(png_ptr, info_ptr, surface->w, surface->h, 8, colortype,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
// png_set_packing(png_ptr);
@ -283,24 +295,24 @@ static int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
if (surface->format->Rmask == bmask
&& surface->format->Gmask == gmask
&& surface->format->Bmask == rmask)
png_set_bgr(png_ptr);
p_png_set_bgr(png_ptr);
/* Write everything */
png_write_info(png_ptr, info_ptr);
p_png_write_info(png_ptr, info_ptr);
#ifdef USE_ROW_POINTERS
row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*surface->h);
for (i = 0; i < surface->h; i++)
row_pointers[i] = (png_bytep)(Uint8*)surface->pixels + i * surface->pitch;
png_write_image(png_ptr, row_pointers);
p_png_write_image(png_ptr, row_pointers);
free(row_pointers);
#else
for (i = 0; i < surface->h; i++)
png_write_row(png_ptr, (png_bytep)(Uint8*)surface->pixels + i * surface->pitch);
p_png_write_row(png_ptr, (png_bytep)(Uint8*)surface->pixels + i * surface->pitch);
#endif
png_write_end(png_ptr, info_ptr);
p_png_write_end(png_ptr, info_ptr);
/* Done */
png_destroy_write_struct(&png_ptr, &info_ptr);
p_png_destroy_write_struct(&png_ptr, &info_ptr);
if (freedst) SDL_RWclose(dst);
return (SUCCESS);
}
@ -467,6 +479,8 @@ switch (ev->type) {
break;
case SDL_USEREVENT:
uev = (SDL_UserEvent *)ev;
if (uev->code == EVENT_SCREENSHOT)
return &vid_first; /* Currently only support screenshot of the first windown */
sim_messagef (SCPE_OK, "Unrecognized user event.\n");
sim_messagef (SCPE_OK, " type = %u\n", uev->type);
sim_messagef (SCPE_OK, " timestamp = %u\n", uev->timestamp);
@ -480,10 +494,12 @@ switch (ev->type) {
break;
}
sim_messagef (SCPE_OK,
"\nSIMH has encountered a bug in SDL2. An upgrade to SDL2\n"
"version 2.0.14 should fix this problem.\n");
sim_messagef (SCPE_IERR,
"\nSIMH has encountered a bug in SDL2 (or in SIMH's use of SDL2).\n");
sim_messagef (SCPE_IERR,
"Create an issue at https://github.com/simh/simh/issues and report\n");
sim_messagef (SCPE_IERR,
"your simulator setup and the above details\n");
return NULL;
}
@ -590,7 +606,7 @@ user_event.user.data1 = vptr;
user_event.user.data2 = NULL;
SDL_PushEvent (&user_event);
while ((!vptr->vid_ready) && (++wait_count < 20))
while ((!vptr->vid_ready) && (++wait_count < 100)) /* Wait up to 10 seconds for video startup */
sim_os_ms_sleep (100);
if (!vptr->vid_ready) {
vid_close ();
@ -619,7 +635,7 @@ if (vid_thread_handle == NULL) {
vid_close ();
return SCPE_OPENERR;
}
while ((!vptr->vid_ready) && (++wait_count < 20))
while ((!vptr->vid_ready) && (++wait_count < 100)) /* Wait up to 10 seconds for video startup */
sim_os_ms_sleep (100);
if (!vptr->vid_ready) {
vid_close ();
@ -2249,11 +2265,40 @@ SDL_Quit ();
return 0;
}
/* Optionally dynamically locate and load png support */
#if defined(SIM_HAVE_DLOPEN)
#include <dlfcn.h>
#endif
const char *vid_version(void)
{
static char SDLVersion[160];
static char SDLVersion[200];
SDL_version compiled = { 0}, running = { 0};
if (SDLVersion[0] != '\0') /* If we already did this, */
return (const char *)SDLVersion; /* the result will be the same */
#if defined(SIM_DLOPEN_EXTENSION) && defined(HAVE_LIBPNG)
if (1) {
struct PNG_Entry *p;
void *hPNGLib = 0; /* handle to Library */
#if defined(SIM_DLOPEN_EXTENSION)
hPNGLib = dlopen("libpng." __STR(SIM_DLOPEN_EXTENSION), RTLD_NOW|RTLD_GLOBAL);
if (!hPNGLib)
hPNGLib = dlopen("libpng." __STR(SIM_DLOPEN_EXTENSION) ".2", RTLD_NOW|RTLD_GLOBAL);
if (!hPNGLib)
hPNGLib = dlopen("libpng." __STR(SIM_DLOPEN_EXTENSION) ".3", RTLD_NOW|RTLD_GLOBAL);
#endif
for (p = libpng_entries; p->entry_name != NULL; p++) {
if (*p->entry_pointer == NULL)
*p->entry_pointer = dlsym(hPNGLib, p->entry_name);
}
}
#endif /* defined(SIM_DLOPEN_EXTENSION) && defined(HAVE_LIBPNG) */
sim_libpng_available = (*libpng_entries->entry_pointer != NULL);
SDL_GetVersion(&running);
SDL_VERSION(&compiled);
@ -2269,26 +2314,31 @@ else
compiled.major, compiled.minor, compiled.patch,
running.major, running.minor, running.patch);
#if defined (HAVE_LIBPNG)
if (1) {
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (sim_libpng_available) {
png_structp png = p_png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (strcmp (PNG_LIBPNG_VER_STRING, png_get_libpng_ver (png)))
if (strcmp (PNG_LIBPNG_VER_STRING, p_png_get_libpng_ver (png))) {
snprintf(&SDLVersion[strlen (SDLVersion)], sizeof (SDLVersion) - (strlen (SDLVersion) + 1),
", PNG Version (Compiled: %s, Runtime: %s)",
PNG_LIBPNG_VER_STRING, png_get_libpng_ver (png));
", PNG Version (Compiled: %s, Runtime: %s - png screenshots disabled)",
PNG_LIBPNG_VER_STRING, p_png_get_libpng_ver (png));
sim_libpng_available = FALSE;
}
else
snprintf(&SDLVersion[strlen (SDLVersion)], sizeof (SDLVersion) - (strlen (SDLVersion) + 1),
", PNG Version %s", PNG_LIBPNG_VER_STRING);
png_destroy_read_struct(&png, NULL, NULL);
p_png_destroy_read_struct(&png, NULL, NULL);
#if defined (ZLIB_VERSION)
if (strcmp (ZLIB_VERSION, zlibVersion ()))
if (strcmp (ZLIB_VERSION, p_zlibVersion ()))
snprintf(&SDLVersion[strlen (SDLVersion)], sizeof (SDLVersion) - (strlen (SDLVersion) + 1),
", zlib: (Compiled: %s, Runtime: %s)", ZLIB_VERSION, zlibVersion ());
", zlib: (Compiled: %s, Runtime: %s)", ZLIB_VERSION, p_zlibVersion ());
else
snprintf(&SDLVersion[strlen (SDLVersion)], sizeof (SDLVersion) - (strlen (SDLVersion) + 1),
", zlib: %s", ZLIB_VERSION);
#endif
}
else
snprintf(&SDLVersion[strlen (SDLVersion)], sizeof (SDLVersion) - (strlen (SDLVersion) + 1),
", PNG Not currently available");
#endif
return (const char *)SDLVersion;
}
@ -2594,19 +2644,20 @@ if (1) {
SDL_Surface *sshot = sim_end ? SDL_CreateRGBSurface(0, vptr->vid_width, vptr->vid_height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000) :
SDL_CreateRGBSurface(0, vptr->vid_width, vptr->vid_height, 32, 0x0000ff00, 0x000ff000, 0xff000000, 0x000000ff) ;
SDL_RenderReadPixels(vptr->vid_renderer, NULL, SDL_PIXELFORMAT_ARGB8888, sshot->pixels, sshot->pitch);
#if defined(HAVE_LIBPNG)
if (!match_ext (filename, "bmp")) {
sprintf (fullname, "%s%s", filename, match_ext (filename, "png") ? "" : ".png");
stat = SDL_SavePNG(sshot, fullname);
if (sim_libpng_available) {
if (!match_ext (filename, "bmp")) {
sprintf (fullname, "%s%s", filename, match_ext (filename, "png") ? "" : ".png");
stat = SDL_SavePNG(sshot, fullname);
}
else {
sprintf (fullname, "%s", filename);
stat = SDL_SaveBMP(sshot, fullname);
}
}
else {
sprintf (fullname, "%s", filename);
sprintf (fullname, "%s%s", filename, match_ext (filename, "bmp") ? "" : ".bmp");
stat = SDL_SaveBMP(sshot, fullname);
}
#else
sprintf (fullname, "%s%s", filename, match_ext (filename, "bmp") ? "" : ".bmp");
stat = SDL_SaveBMP(sshot, fullname);
#endif /* defined(HAVE_LIBPNG) */
SDL_FreeSurface(sshot);
}
if (stat) {
@ -2828,8 +2879,8 @@ return;
const char *vid_version (void)
{
#if defined(HAVE_LIBSDL)
static char SDLVersion[160];
SDL_version compiled, running;
static char SDLVersion[200] = "";
SDL_version compiled = { 0}, running = { 0};
SDL_GetVersion(&running);