<commit_before>/*
 * SchemeEval.c
 *
 * Simple scheme evaluator
 * Copyright (c) 2008 Linas Vepstas <linas@linas.org>
 */

#ifdef HAVE_GUILE

#include "SchemeEval.h"

#include <libguile.h>
#include <libguile/backtrace.h>
#include <libguile/debug.h>
#include <libguile/lang.h>
#include <pthread.h>

#include <opencog/util/platform.h>
#include "SchemeSmob.h"

using namespace opencog;

void SchemeEval::init(void)
{
	SchemeSmob::init();

	outport = scm_open_output_string();
	outport = scm_permanent_object(outport);
	scm_set_current_output_port(outport);

	pending_input = false;
	caught_error = false;
	input_line = "";
	error_string_port = SCM_EOL;
	captured_stack = SCM_BOOL_F;
	pexpr = NULL;
}

void * SchemeEval::c_wrap_init(void *p)
{
	SchemeEval *self = (SchemeEval *) p;
	self->init();
	return self;
}

static pthread_once_t eval_init_once = PTHREAD_ONCE_INIT;
static pthread_key_t tid_key = NULL;

#define WORK_AROUND_GUILE_185_BUG
#ifdef WORK_AROUND_GUILE_185_BUG
/* There's a bug in guile-1.8.5, where the second and subsequent
 * threads run in guile mode with a bogus/broken current-module.
 * This cannot be worked around by anything as simple as saying
 * "(set-current-module the-root-module)" because dynwind undoes
 * any module-setting that we do.
 *
 * So we work around it here, by explicitly setting the module
 * outside of a dynwind context.
 */
static SCM guile_user_module;

static void * do_bogus_scm(void *p)
{
	scm_c_eval_string ("(+ 2 2)\n");
	return p;
}
#endif /* WORK_AROUND_GUILE_185_BUG */

static void first_time_only(void)
{
   pthread_key_create(&tid_key, NULL);
	pthread_setspecific(tid_key, (const void *) 0x42);
#ifdef WORK_AROUND_GUILE_185_BUG
	scm_with_guile(do_bogus_scm, NULL);
	guile_user_module = scm_current_module();
#endif /* WORK_AROUND_GUILE_185_BUG */
}

SchemeEval::SchemeEval(void)
{
	pthread_once(&eval_init_once, first_time_only);
	scm_with_guile(c_wrap_init, this);
}

/* This should be called once for every new thread. */
void SchemeEval::per_thread_init(void)
{
	/* Avoid more than one call per thread. */
	if (((void *) 0x2) == pthread_getspecific(tid_key)) return;
	pthread_setspecific(tid_key, (const void *) 0x2);

#ifdef WORK_AROUND_GUILE_185_BUG
	scm_set_current_module(guile_user_module);
#endif /* WORK_AROUND_GUILE_185_BUG */

	// Guile implements the current port as a fluid on each thread.
	// So, for every new thread, we need to set this.
	scm_set_current_output_port(outport);
}

SchemeEval::~SchemeEval()
{
}

/* ============================================================== */

std::string SchemeEval::prt(SCM node)
{
	if (SCM_SMOB_PREDICATE(SchemeSmob::cog_handle_tag, node))
	{
		return SchemeSmob::handle_to_string(node);
	}

	else if (SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, node))
	{
		return SchemeSmob::misc_to_string(node);
	}

	else if (scm_is_eq(node, SCM_UNSPECIFIED))
	{
		return "";
	}
#if CUSTOM_PRINTING_WHY_DO_WE_HAVE_THIS_DELETE_ME
	else if (scm_is_pair(node))
	{
		std::string str = "(";
      SCM node_list = node;
		const char * sp = "";
      do
      {
			str += sp;
			sp = " ";
         node = SCM_CAR (node_list);
         str += prt (node);
         node_list = SCM_CDR (node_list);
      }
      while (scm_is_pair(node_list));

		// Print the rest -- the CDR part
		if (!scm_is_null(node_list))
		{
			str += " . ";
			str += prt (node_list);
		}
		str += ")";
		return str;
   }
	else if (scm_is_true(scm_symbol_p(node)))
	{
		node = scm_symbol_to_string(node);
		char * str = scm_to_locale_string(node);
		// std::string rv = "'";  // print the symbol escape
		std::string rv = "";      // err .. don't print it
		rv += str;
		free(str);
		return rv;
	}
	else if (scm_is_true(scm_string_p(node)))
	{
		char * str = scm_to_locale_string(node);
		std::string rv = "\"";
		rv += str;
		rv += "\"";
		free(str);
		return rv;
	}
	else if (scm_is_number(node))
	{
		#define NUMBUFSZ 60
		char buff[NUMBUFSZ];
		if (scm_is_signed_integer(node, INT_MIN, INT_MAX))
		{
			snprintf (buff, NUMBUFSZ, "%ld", (long) scm_to_long(node));
		}
		else if (scm_is_unsigned_integer(node, 0, UINT_MAX))
		{
			snprintf (buff, NUMBUFSZ, "%lu", (unsigned long) scm_to_ulong(node));
		}
		else if (scm_is_real(node))
		{
			snprintf (buff, NUMBUFSZ, "%g", scm_to_double(node));
		}
		else if (scm_is_complex(node))
		{
			snprintf (buff, NUMBUFSZ, "%g +i %g",
				scm_c_real_part(node),
				scm_c_imag_part(node));
		}
		else if (scm_is_rational(node))
		{
			std::string rv;
			rv = prt(scm_numerator(node));
			rv += "/";
			rv += prt(scm_denominator(node));
			return rv;
		}
		return buff;
	}
	else if (scm_is_true(scm_char_p(node)))
	{
		std::string rv;
		rv = (char) scm_to_char(node);
		return rv;
	}
	else if (scm_is_true(scm_boolean_p(node)))
	{
		if (scm_to_bool(node)) return "#t";
		return "#f";
	}
	else if (SCM_NULL_OR_NIL_P(node))
	{
		// scm_is_null(x) is true when x is SCM_EOL
		// SCM_NILP(x) is true when x is SCM_ELISP_NIL
		return "()";
	}
	else if (scm_is_eq(node, SCM_UNDEFINED))
	{
		return "undefined";
	}
	else if (scm_is_eq(node, SCM_EOF_VAL))
	{
		return "eof";
	}
#endif
	else
	{
		// Let SCM display do the rest of the work.
		SCM port = scm_open_output_string();
		scm_display (node, port);
		SCM rc = scm_get_output_string(port);
		char * str = scm_to_locale_string(rc);
		std::string rv = str;
		free(str);
		scm_close_port(port);
		return rv;
	}

	return "";
}

/* ============================================================== */

SCM SchemeEval::preunwind_handler_wrapper (void *data, SCM tag, SCM throw_args)
{
	SchemeEval *ss = (SchemeEval *)data;
	return ss->preunwind_handler(tag, throw_args);
	return SCM_EOL;
}

SCM SchemeEval::catch_handler_wrapper (void *data, SCM tag, SCM throw_args)
{
	SchemeEval *ss = (SchemeEval *)data;
	return ss->catch_handler(tag, throw_args);
}

SCM SchemeEval::preunwind_handler (SCM tag, SCM throw_args)
{
	// We can only record the stack before it is unwound.
	// The normal catch handler body runs only *after* the stack
	// has been unwound.
	captured_stack = scm_make_stack (SCM_BOOL_T, SCM_EOL);
	return SCM_EOL;
}

SCM SchemeEval::catch_handler (SCM tag, SCM throw_args)
{
	// Check for read error. If a read error, then wait for user to correct it.
	SCM re = scm_symbol_to_string(tag);
	char * restr = scm_to_locale_string(re);
	pending_input = false;
	if (0 == strcmp(restr, "read-error"))
	{
		pending_input = true;
		free(restr);
		return SCM_EOL;
	}

	// If its not a read error, then its a regular error; report it.
	caught_error = true;

	/* get string port into which we write the error message and stack. */
	error_string_port = scm_open_output_string();
	SCM port = error_string_port;

	if (scm_is_true(scm_list_p(throw_args)) && (scm_ilength(throw_args) >= 1))
	{
		long nargs = scm_ilength(throw_args);
		SCM subr    = SCM_CAR (throw_args);
		SCM message = SCM_EOL;
		if (nargs >= 2)
			message = SCM_CADR (throw_args);
		SCM parts   = SCM_EOL;
		if (nargs >= 3)
			parts   = SCM_CADDR (throw_args);
		SCM rest    = SCM_EOL;
		if (nargs >= 4)
			rest    = SCM_CADDDR (throw_args);

		if (scm_is_true (captured_stack))
		{
			SCM highlights;

			if (scm_is_eq (tag, scm_arg_type_key) ||
			    scm_is_eq (tag, scm_out_of_range_key))
				highlights = rest;
			else
				highlights = SCM_EOL;

			scm_puts ("Backtrace:\n", port);
			scm_display_backtrace_with_highlights (captured_stack, port,
			      SCM_BOOL_F, SCM_BOOL_F, highlights);
			scm_newline (port);
		}
		scm_display_error (captured_stack, port, subr, message, parts, rest);
	}
	else
	{
		scm_puts ("ERROR: thow args are unexpectedly short!\n", port);
	}
	scm_puts("ABORT: ", port);
	scm_puts(restr, port);
	free(restr);

	return SCM_BOOL_F;
}

/* ============================================================== */

/**
 * Evaluate the expression
 */
std::string SchemeEval::eval(const std::string &expr)
{
	pexpr = &expr;
	scm_with_guile(c_wrap_eval, this);
	return answer;
}

void * SchemeEval::c_wrap_eval(void * p)
{
	SchemeEval *self = (SchemeEval *) p;
	self->answer = self->do_eval(*(self->pexpr));
	return self;
}

std::string SchemeEval::do_eval(const std::string &expr)
{
	per_thread_init();

	// XXX This is a defacto string buffer copy, could probably be avoided
	// in most cases. FIXME.  i.e. no copy needed when no peding input.
	input_line += expr;

	caught_error = false;
	pending_input = false;
#if 0
	SCM rc = scm_internal_catch (SCM_BOOL_T,
	            (scm_t_catch_body) scm_c_eval_string, (void *) input_line.c_str(),
	            SchemeEval::catch_handler_wrapper, this);
#endif
	captured_stack = SCM_BOOL_F;
	SCM rc = scm_c_catch (SCM_BOOL_T,
	            (scm_t_catch_body) scm_c_eval_string, (void *) input_line.c_str(),
	            SchemeEval::catch_handler_wrapper, this,
	            SchemeEval::preunwind_handler_wrapper, this);

	if (pending_input)
	{
		return "";
	}
	pending_input = false;
	input_line = "";

	if (caught_error)
	{
		std::string rv;
		rc = scm_get_output_string(error_string_port);
		char * str = scm_to_locale_string(rc);
		rv = str;
		free(str);
		scm_close_port(error_string_port);
		error_string_port = SCM_EOL;
		captured_stack = SCM_BOOL_F;

		scm_truncate_file(outport, scm_from_uint16(0));

		rv += "\n";
		return rv;
	}
	else
	{
		std::string rv;
		// First, we get the contents of the output port,
		// and pass that on.
		SCM out = scm_get_output_string(outport);
		char * str = scm_to_locale_string(out);
		rv = str;
		free(str);
		scm_truncate_file(outport, scm_from_uint16(0));

		// Next, we append the "interpreter" output
		rv += prt(rc);
		rv += "\n";

		return rv;
	}
	return "#<Error: Unreachable statement reached>";
}

/* ============================================================== */

/**
 * Return true if the expression was incomplete, and more is expected
 * (for example, more closing parens are expected)
 */
bool SchemeEval::input_pending(void)
{
	return pending_input;
}

/**
 * Return true if an error occured during the evaluation of the expression
 */
bool SchemeEval::eval_error(void)
{
	return caught_error;
}

/**
 * Clear the error state, the input buffers, etc.
 */
void SchemeEval::clear_pending(void)
{
	input_line = "";
	pending_input = false;
	caught_error = false;
}

#endif
/* ===================== END OF FILE ============================ */
<commit_msg>work around a guile multi-threading bug, by serializing guile access.<commit_after>/*
 * SchemeEval.c
 *
 * Simple scheme evaluator
 * Copyright (c) 2008 Linas Vepstas <linas@linas.org>
 */

#ifdef HAVE_GUILE

#include "SchemeEval.h"

#include <libguile.h>
#include <libguile/backtrace.h>
#include <libguile/debug.h>
#include <libguile/lang.h>
#include <pthread.h>

#include <opencog/util/platform.h>
#include "SchemeSmob.h"

using namespace opencog;

void SchemeEval::init(void)
{
	SchemeSmob::init();

	outport = scm_open_output_string();
	outport = scm_permanent_object(outport);
	scm_set_current_output_port(outport);

	pending_input = false;
	caught_error = false;
	input_line = "";
	error_string_port = SCM_EOL;
	captured_stack = SCM_BOOL_F;
	pexpr = NULL;
}

void * SchemeEval::c_wrap_init(void *p)
{
	SchemeEval *self = (SchemeEval *) p;
	self->init();
	return self;
}

static pthread_once_t eval_init_once = PTHREAD_ONCE_INIT;
static pthread_key_t tid_key = NULL;

#define WORK_AROUND_GUILE_185_BUG
#ifdef WORK_AROUND_GUILE_185_BUG
/* There's a bug in guile-1.8.5, where the second and subsequent
 * threads run in guile mode with a bogus/broken current-module.
 * This cannot be worked around by anything as simple as saying
 * "(set-current-module the-root-module)" because dynwind undoes
 * any module-setting that we do.
 *
 * So we work around it here, by explicitly setting the module
 * outside of a dynwind context.
 */
static SCM guile_user_module;

static void * do_bogus_scm(void *p)
{
	scm_c_eval_string ("(+ 2 2)\n");
	return p;
}
#endif /* WORK_AROUND_GUILE_185_BUG */

#define WORK_AROUND_GUILE_THREADING_BUG
#ifdef WORK_AROUND_GUILE_THREADING_BUG
/* There are bugs in guile-1.8.6 and earlier that prevent proper
 * multi-threaded operation. Currently, the most serious of these is
 * a prallel-define bug, documented in
 * https://savannah.gnu.org/bugs/index.php?24867
 * Until that bug is fixed and released, this work-around is needed.
 * The work-around serializes all guile-mode thread execution, by
 * means of a mutex lock.
 */
static pthread_mutex_t serialize_lock;
#endif /* WORK_AROUND_GUILE_THREADING_BUG */

static void first_time_only(void)
{
   pthread_key_create(&tid_key, NULL);
	pthread_setspecific(tid_key, (const void *) 0x42);
#ifdef WORK_AROUND_GUILE_THREADING_BUG
	pthread_mutex_init(&serialize_lock, NULL);
#endif /* WORK_AROUND_GUILE_THREADING_BUG */
#ifdef WORK_AROUND_GUILE_185_BUG
	scm_with_guile(do_bogus_scm, NULL);
	guile_user_module = scm_current_module();
#endif /* WORK_AROUND_GUILE_185_BUG */
}

SchemeEval::SchemeEval(void)
{
	pthread_once(&eval_init_once, first_time_only);

#ifdef WORK_AROUND_GUILE_THREADING_BUG
	pthread_mutex_lock(&serialize_lock);
#endif /* WORK_AROUND_GUILE_THREADING_BUG */

	scm_with_guile(c_wrap_init, this);

#ifdef WORK_AROUND_GUILE_THREADING_BUG
	pthread_mutex_unlock(&serialize_lock);
#endif /* WORK_AROUND_GUILE_THREADING_BUG */

}

/* This should be called once for every new thread. */
void SchemeEval::per_thread_init(void)
{
	/* Avoid more than one call per thread. */
	if (((void *) 0x2) == pthread_getspecific(tid_key)) return;
	pthread_setspecific(tid_key, (const void *) 0x2);

#ifdef WORK_AROUND_GUILE_185_BUG
	scm_set_current_module(guile_user_module);
#endif /* WORK_AROUND_GUILE_185_BUG */

	// Guile implements the current port as a fluid on each thread.
	// So, for every new thread, we need to set this.
	scm_set_current_output_port(outport);
}

SchemeEval::~SchemeEval()
{
}

/* ============================================================== */

std::string SchemeEval::prt(SCM node)
{
	if (SCM_SMOB_PREDICATE(SchemeSmob::cog_handle_tag, node))
	{
		return SchemeSmob::handle_to_string(node);
	}

	else if (SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, node))
	{
		return SchemeSmob::misc_to_string(node);
	}

	else if (scm_is_eq(node, SCM_UNSPECIFIED))
	{
		return "";
	}
#if CUSTOM_PRINTING_WHY_DO_WE_HAVE_THIS_DELETE_ME
	else if (scm_is_pair(node))
	{
		std::string str = "(";
      SCM node_list = node;
		const char * sp = "";
      do
      {
			str += sp;
			sp = " ";
         node = SCM_CAR (node_list);
         str += prt (node);
         node_list = SCM_CDR (node_list);
      }
      while (scm_is_pair(node_list));

		// Print the rest -- the CDR part
		if (!scm_is_null(node_list))
		{
			str += " . ";
			str += prt (node_list);
		}
		str += ")";
		return str;
   }
	else if (scm_is_true(scm_symbol_p(node)))
	{
		node = scm_symbol_to_string(node);
		char * str = scm_to_locale_string(node);
		// std::string rv = "'";  // print the symbol escape
		std::string rv = "";      // err .. don't print it
		rv += str;
		free(str);
		return rv;
	}
	else if (scm_is_true(scm_string_p(node)))
	{
		char * str = scm_to_locale_string(node);
		std::string rv = "\"";
		rv += str;
		rv += "\"";
		free(str);
		return rv;
	}
	else if (scm_is_number(node))
	{
		#define NUMBUFSZ 60
		char buff[NUMBUFSZ];
		if (scm_is_signed_integer(node, INT_MIN, INT_MAX))
		{
			snprintf (buff, NUMBUFSZ, "%ld", (long) scm_to_long(node));
		}
		else if (scm_is_unsigned_integer(node, 0, UINT_MAX))
		{
			snprintf (buff, NUMBUFSZ, "%lu", (unsigned long) scm_to_ulong(node));
		}
		else if (scm_is_real(node))
		{
			snprintf (buff, NUMBUFSZ, "%g", scm_to_double(node));
		}
		else if (scm_is_complex(node))
		{
			snprintf (buff, NUMBUFSZ, "%g +i %g",
				scm_c_real_part(node),
				scm_c_imag_part(node));
		}
		else if (scm_is_rational(node))
		{
			std::string rv;
			rv = prt(scm_numerator(node));
			rv += "/";
			rv += prt(scm_denominator(node));
			return rv;
		}
		return buff;
	}
	else if (scm_is_true(scm_char_p(node)))
	{
		std::string rv;
		rv = (char) scm_to_char(node);
		return rv;
	}
	else if (scm_is_true(scm_boolean_p(node)))
	{
		if (scm_to_bool(node)) return "#t";
		return "#f";
	}
	else if (SCM_NULL_OR_NIL_P(node))
	{
		// scm_is_null(x) is true when x is SCM_EOL
		// SCM_NILP(x) is true when x is SCM_ELISP_NIL
		return "()";
	}
	else if (scm_is_eq(node, SCM_UNDEFINED))
	{
		return "undefined";
	}
	else if (scm_is_eq(node, SCM_EOF_VAL))
	{
		return "eof";
	}
#endif
	else
	{
		// Let SCM display do the rest of the work.
		SCM port = scm_open_output_string();
		scm_display (node, port);
		SCM rc = scm_get_output_string(port);
		char * str = scm_to_locale_string(rc);
		std::string rv = str;
		free(str);
		scm_close_port(port);
		return rv;
	}

	return "";
}

/* ============================================================== */

SCM SchemeEval::preunwind_handler_wrapper (void *data, SCM tag, SCM throw_args)
{
	SchemeEval *ss = (SchemeEval *)data;
	return ss->preunwind_handler(tag, throw_args);
	return SCM_EOL;
}

SCM SchemeEval::catch_handler_wrapper (void *data, SCM tag, SCM throw_args)
{
	SchemeEval *ss = (SchemeEval *)data;
	return ss->catch_handler(tag, throw_args);
}

SCM SchemeEval::preunwind_handler (SCM tag, SCM throw_args)
{
	// We can only record the stack before it is unwound.
	// The normal catch handler body runs only *after* the stack
	// has been unwound.
	captured_stack = scm_make_stack (SCM_BOOL_T, SCM_EOL);
	return SCM_EOL;
}

SCM SchemeEval::catch_handler (SCM tag, SCM throw_args)
{
	// Check for read error. If a read error, then wait for user to correct it.
	SCM re = scm_symbol_to_string(tag);
	char * restr = scm_to_locale_string(re);
	pending_input = false;
	if (0 == strcmp(restr, "read-error"))
	{
		pending_input = true;
		free(restr);
		return SCM_EOL;
	}

	// If its not a read error, then its a regular error; report it.
	caught_error = true;

	/* get string port into which we write the error message and stack. */
	error_string_port = scm_open_output_string();
	SCM port = error_string_port;

	if (scm_is_true(scm_list_p(throw_args)) && (scm_ilength(throw_args) >= 1))
	{
		long nargs = scm_ilength(throw_args);
		SCM subr    = SCM_CAR (throw_args);
		SCM message = SCM_EOL;
		if (nargs >= 2)
			message = SCM_CADR (throw_args);
		SCM parts   = SCM_EOL;
		if (nargs >= 3)
			parts   = SCM_CADDR (throw_args);
		SCM rest    = SCM_EOL;
		if (nargs >= 4)
			rest    = SCM_CADDDR (throw_args);

		if (scm_is_true (captured_stack))
		{
			SCM highlights;

			if (scm_is_eq (tag, scm_arg_type_key) ||
			    scm_is_eq (tag, scm_out_of_range_key))
				highlights = rest;
			else
				highlights = SCM_EOL;

			scm_puts ("Backtrace:\n", port);
			scm_display_backtrace_with_highlights (captured_stack, port,
			      SCM_BOOL_F, SCM_BOOL_F, highlights);
			scm_newline (port);
		}
		scm_display_error (captured_stack, port, subr, message, parts, rest);
	}
	else
	{
		scm_puts ("ERROR: thow args are unexpectedly short!\n", port);
	}
	scm_puts("ABORT: ", port);
	scm_puts(restr, port);
	free(restr);

	return SCM_BOOL_F;
}

/* ============================================================== */

/**
 * Evaluate the expression
 */
std::string SchemeEval::eval(const std::string &expr)
{
	pexpr = &expr;

#ifdef WORK_AROUND_GUILE_THREADING_BUG
	pthread_mutex_lock(&serialize_lock);
#endif /* WORK_AROUND_GUILE_THREADING_BUG */

	scm_with_guile(c_wrap_eval, this);

#ifdef WORK_AROUND_GUILE_THREADING_BUG
	pthread_mutex_unlock(&serialize_lock);
#endif /* WORK_AROUND_GUILE_THREADING_BUG */

	return answer;
}

void * SchemeEval::c_wrap_eval(void * p)
{
	SchemeEval *self = (SchemeEval *) p;
	self->answer = self->do_eval(*(self->pexpr));
	return self;
}

std::string SchemeEval::do_eval(const std::string &expr)
{
	per_thread_init();

	// XXX This is a defacto string buffer copy, could probably be avoided
	// in most cases. FIXME.  i.e. no copy needed when no pending input.
	input_line += expr;

	caught_error = false;
	pending_input = false;
#if 0
	SCM rc = scm_internal_catch (SCM_BOOL_T,
	            (scm_t_catch_body) scm_c_eval_string, (void *) input_line.c_str(),
	            SchemeEval::catch_handler_wrapper, this);
#endif
	captured_stack = SCM_BOOL_F;
	SCM rc = scm_c_catch (SCM_BOOL_T,
	            (scm_t_catch_body) scm_c_eval_string, (void *) input_line.c_str(),
	            SchemeEval::catch_handler_wrapper, this,
	            SchemeEval::preunwind_handler_wrapper, this);

	if (pending_input)
	{
		return "";
	}
	pending_input = false;
	input_line = "";

	if (caught_error)
	{
		std::string rv;
		rc = scm_get_output_string(error_string_port);
		char * str = scm_to_locale_string(rc);
		rv = str;
		free(str);
		scm_close_port(error_string_port);
		error_string_port = SCM_EOL;
		captured_stack = SCM_BOOL_F;

		scm_truncate_file(outport, scm_from_uint16(0));

		rv += "\n";
		return rv;
	}
	else
	{
		std::string rv;
		// First, we get the contents of the output port,
		// and pass that on.
		SCM out = scm_get_output_string(outport);
		char * str = scm_to_locale_string(out);
		rv = str;
		free(str);
		scm_truncate_file(outport, scm_from_uint16(0));

		// Next, we append the "interpreter" output
		rv += prt(rc);
		rv += "\n";

		return rv;
	}
	return "#<Error: Unreachable statement reached>";
}

/* ============================================================== */

/**
 * Return true if the expression was incomplete, and more is expected
 * (for example, more closing parens are expected)
 */
bool SchemeEval::input_pending(void)
{
	return pending_input;
}

/**
 * Return true if an error occured during the evaluation of the expression
 */
bool SchemeEval::eval_error(void)
{
	return caught_error;
}

/**
 * Clear the error state, the input buffers, etc.
 */
void SchemeEval::clear_pending(void)
{
	input_line = "";
	pending_input = false;
	caught_error = false;
}

#endif
/* ===================== END OF FILE ============================ */
<|endoftext|>


<commit_before>/*
 * Recognizer.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef _OPENCOG_RECOGNIZER_H
#define _OPENCOG_RECOGNIZER_H

#include <set>

#include <opencog/query/DefaultPatternMatchCB.h>
#include <opencog/atoms/pattern/PatternLink.h>
#include <opencog/atoms/core/ScopeLink.h>
#include <opencog/atomutils/FindUtils.h>

#include "BindLinkAPI.h"

namespace opencog {

/**
 * Very rough, crude, experimental prototype for the idea that
 * pattern recognition is the dual of pattern matching.
 * That is, rather than using one query pattern to search a large
 * collection of data, this does the opposite: given a single piece of
 * data, it searches for all rules/queries which apply to it.
 *
 * The file /examples/aiml/recog.scm provides a very simple example.
 * The implementation here is very minimalistic, and does many things
 * wrong:
 * -- it fails to perform any type-checking to make sure the variable
 *    constraints are satisfied.
 * -- AIML wants a left-to-right traversal, this does an omni-
 *    directional exploration. (which is OK, but is not how AIML is
 *    defined...)
 * -- This hasn't been thought through thoroughly. There are almost
 *    surely some weird gotcha's.
 */
class Recognizer :
   public virtual DefaultPatternMatchCB
{
	private:
		std::vector<Variables> _soln_vars;
		void get_glob_decl(const Handle&);

	protected:
		const Pattern* _pattern;

		Handle _root;
		Handle _starter_term;
		size_t _cnt;
		bool do_search(PatternMatchEngine*, const Handle&);
		bool loose_match(const Handle&, const Handle&);

	public:
		OrderedHandleSet _rules;

		Recognizer(AtomSpace* as) :
			DefaultPatternMatchCB(as) {}

		virtual void set_pattern(const Variables& vars,
		                         const Pattern& pat)
		{
			_pattern = &pat;
			DefaultPatternMatchCB::set_pattern(vars, pat);
		}

		virtual bool initiate_search(PatternMatchEngine*);
		virtual bool node_match(const Handle&, const Handle&);
		virtual bool link_match(const PatternTermPtr&, const Handle&);
		virtual bool fuzzy_match(const Handle&, const Handle&);
		virtual bool grounding(const HandleMap &var_soln,
		                       const HandleMap &term_soln);
};

} // namespace opencog

#endif // _OPENCOG_RECOGNIZER_H

using namespace opencog;

// Uncomment below to enable debug print
#define DEBUG 1
#ifdef DEBUG
#define dbgprt(f, varargs...) logger().fine(f, ##varargs)
#else
#define dbgprt(f, varargs...)
#endif

/* ======================================================== */

void Recognizer::get_glob_decl(const Handle& h)
{
	IncomingSet scop = h->getIncomingSetByType(SCOPE_LINK, true);

	if (0 < scop.size())
	{
		for (const LinkPtr& lp : scop)
		{
			Handle s(lp);
			ScopeLinkPtr sl(ScopeLinkCast(s));
			if (NULL == sl)
				sl = createScopeLink(*LinkCast(s));
			_soln_vars.push_back(sl->get_variables());
		}
	}
	else
	{
		IncomingSet iset = h->getIncomingSet();
		if (iset.size() == 0) return;
		for (const LinkPtr& lp : iset)
			get_glob_decl(lp->getHandle());
	}
}

bool Recognizer::do_search(PatternMatchEngine* pme, const Handle& top)
{
	if (top->isLink())
	{
		// Recursively drill down and explore every possible node as
		// a search starting point. This is needed, as the patterns we
		// compare against might not be connected.
		for (const Handle& h : top->getOutgoingSet())
		{
			_starter_term = top;
			bool found = do_search(pme, h);
			if (found) return true;
		}
		return false;
	}

	IncomingSet iset = get_incoming_set(top);
	size_t sz = iset.size();
	for (size_t i = 0; i < sz; i++)
	{
		Handle h(iset[i]);
		dbgprt("rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr\n");
		dbgprt("Loop candidate (%lu - %s):\n%s\n", _cnt++,
		       top->toShortString().c_str(),
		       h->toShortString().c_str());
		bool found = pme->explore_neighborhood(_root, _starter_term, h);

		// Terminate search if satisfied.
		if (found) return true;
   }

	return false;
}

bool Recognizer::initiate_search(PatternMatchEngine* pme)
{
	const HandleSeq& clauses = _pattern->cnf_clauses;

	_cnt = 0;
	for (const Handle& h: clauses)
	{
		_root = h;
		bool found = do_search(pme, h);
		if (found) return true;
	}
	return false;
}

bool Recognizer::node_match(const Handle& npat_h, const Handle& nsoln_h)
{
	if (npat_h == nsoln_h) return true;
	Type tso = nsoln_h->getType();
	if (VARIABLE_NODE == tso) return true;
	if (GLOB_NODE == tso)
	{
		if (0 < _soln_vars.size())
		{
			// Check if it satisfies the type restrictions, if any
			if (std::all_of(_soln_vars.begin(), _soln_vars.end(),
				[&](const Variables& v) {
					return (not v.is_type(nsoln_h, npat_h)); }))
				return false;

			// Check if it satisfies the interval restrictions, if any
			if (std::all_of(_soln_vars.begin(), _soln_vars.end(),
				[&](const Variables& v) {
					return (not v.is_interval(nsoln_h, 1)); }))
				return false;
		}
		// No reason to reject
		return true;
	}
	return false;
}

bool Recognizer::link_match(const PatternTermPtr& ptm, const Handle& lsoln)
{
	_soln_vars.clear();
	const Handle& lpat = ptm->getHandle();

	// Self-compares always proceed.
	if (lpat == lsoln) return true;

	// mis-matched types are a dead-end.
	if (lpat->getType() != lsoln->getType()) return false;

	// Find the type and interval restrictions under a ScopeLink, if any
	if (contains_atomtype(lsoln, GLOB_NODE))
		get_glob_decl(lsoln);

	return true;
}

bool Recognizer::loose_match(const Handle& npat_h, const Handle& nsoln_h)
{
	Type gtype = nsoln_h->getType();
	// Variable matches anything; move to next.
	if (VARIABLE_NODE == gtype) return true;

	// Strict match for link types.
	if (npat_h->getType() != gtype) return false;
	if (not npat_h->isNode()) return true;

	// If we are here, we know we have nodes. Ask for a strict match.
	if (npat_h != nsoln_h) return false;
	return true;
}

bool Recognizer::fuzzy_match(const Handle& npat_h, const Handle& nsoln_h)
{
	// If we are here, then there are probably glob nodes in the soln.
	// Try to match them, fairly rigorously. Exactly what constitutes
	// an OK match is still a bit up in the air.

	if (not npat_h->isLink() or not nsoln_h->isLink()) return false;

	const HandleSeq &osg = nsoln_h->getOutgoingSet();
	size_t osg_size = osg.size();

	// Lets not waste time, if there's no glob there.
	bool have_glob = false;
	for (size_t j=0; j<osg_size; j++)
	{
		if (osg[j]->getType() == GLOB_NODE)
		{
			have_glob = true;
			break;
		}
	}
	if (not have_glob) return false;

	const HandleSeq &osp = npat_h->getOutgoingSet();
	size_t osp_size = osp.size();
	size_t max_size = std::max(osg_size, osp_size);

	// Do a side-by-side compare. This is not as rigorous as
	// PatternMatchEngine::tree_compare() nor does it handle the bells
	// and whistles (ChoiceLink, QuoteLink, etc).
	size_t ip=0, jg=0;
	for (; ip<osp_size and jg<osg_size; ip++, jg++)
	{
		if (GLOB_NODE != osg[jg]->getType())
		{
			if (loose_match(osp[ip], osg[jg])) continue;
			return false;
		}

		// If we are here, we have a glob in the soln. If the glob is at
		// the end, it eats everything, so its a match. Else, resume
		// matching at the end of the glob.
		if ((jg+1) == osg_size) return true;

		const Handle& post(osg[jg+1]);
		ip++;
		while (ip < max_size and not loose_match(osp[ip], post))
		{
			ip++;
		}
		// If ip ran past the end, then the post was not found. This is
		// a mismatch.
		if (not (ip < max_size)) return false;

		// Go around again, look for more GlobNodes. Back up by one, so
		// that the for-loop increment gets us back on track.
		ip--;
	}

	// If we are here, then we should have matched up all the atoms;
	// if we exited the loop because pattern or grounding was short,
	// then its a mis-match.
	if (ip != osp_size or jg != osg_size) return false;
	return true;
}

bool Recognizer::grounding(const HandleMap& var_soln,
                           const HandleMap& term_soln)
{
	Handle rule = term_soln.at(_root);

	if (rule != _root) {
		_rules.insert(rule);
	}

	// Look for more groundings.
	return false;
}

Handle opencog::recognize(AtomSpace* as, const Handle& hlink)
{
	PatternLinkPtr bl(PatternLinkCast(hlink));
	if (NULL == bl)
		bl = createPatternLink(*LinkCast(hlink));

	Recognizer reco(as);
	bl->satisfy(reco);

	HandleSeq hs;
	for (const Handle& h : reco._rules) hs.push_back(h);

	return as->add_link(SET_LINK, hs);
}
<commit_msg>Check the restrictions in fuzzy_match<commit_after>/*
 * Recognizer.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef _OPENCOG_RECOGNIZER_H
#define _OPENCOG_RECOGNIZER_H

#include <set>

#include <opencog/query/DefaultPatternMatchCB.h>
#include <opencog/atoms/pattern/PatternLink.h>
#include <opencog/atoms/core/ScopeLink.h>
#include <opencog/atomutils/FindUtils.h>

#include "BindLinkAPI.h"

namespace opencog {

/**
 * Very rough, crude, experimental prototype for the idea that
 * pattern recognition is the dual of pattern matching.
 * That is, rather than using one query pattern to search a large
 * collection of data, this does the opposite: given a single piece of
 * data, it searches for all rules/queries which apply to it.
 *
 * The file /examples/aiml/recog.scm provides a very simple example.
 * The implementation here is very minimalistic, and does many things
 * wrong:
 * -- it fails to perform any type-checking to make sure the variable
 *    constraints are satisfied.
 * -- AIML wants a left-to-right traversal, this does an omni-
 *    directional exploration. (which is OK, but is not how AIML is
 *    defined...)
 * -- This hasn't been thought through thoroughly. There are almost
 *    surely some weird gotcha's.
 */
class Recognizer :
   public virtual DefaultPatternMatchCB
{
	private:
		std::vector<Variables> _soln_vars;
		void get_glob_decl(const Handle&);

	protected:
		const Pattern* _pattern;

		Handle _root;
		Handle _starter_term;
		size_t _cnt;
		bool do_search(PatternMatchEngine*, const Handle&);
		bool loose_match(const Handle&, const Handle&);

	public:
		OrderedHandleSet _rules;

		Recognizer(AtomSpace* as) :
			DefaultPatternMatchCB(as) {}

		virtual void set_pattern(const Variables& vars,
		                         const Pattern& pat)
		{
			_pattern = &pat;
			DefaultPatternMatchCB::set_pattern(vars, pat);
		}

		virtual bool initiate_search(PatternMatchEngine*);
		virtual bool node_match(const Handle&, const Handle&);
		virtual bool link_match(const PatternTermPtr&, const Handle&);
		virtual bool fuzzy_match(const Handle&, const Handle&);
		virtual bool grounding(const HandleMap &var_soln,
		                       const HandleMap &term_soln);
};

} // namespace opencog

#endif // _OPENCOG_RECOGNIZER_H

using namespace opencog;

// Uncomment below to enable debug print
#define DEBUG 1
#ifdef DEBUG
#define dbgprt(f, varargs...) logger().fine(f, ##varargs)
#else
#define dbgprt(f, varargs...)
#endif

/* ======================================================== */

void Recognizer::get_glob_decl(const Handle& h)
{
	IncomingSet scop = h->getIncomingSetByType(SCOPE_LINK, true);

	if (0 < scop.size())
	{
		for (const LinkPtr& lp : scop)
		{
			Handle s(lp);
			ScopeLinkPtr sl(ScopeLinkCast(s));
			if (NULL == sl)
				sl = createScopeLink(*LinkCast(s));
			_soln_vars.push_back(sl->get_variables());
		}
	}
	else
	{
		IncomingSet iset = h->getIncomingSet();
		if (iset.size() == 0) return;
		for (const LinkPtr& lp : iset)
			get_glob_decl(lp->getHandle());
	}
}

bool Recognizer::do_search(PatternMatchEngine* pme, const Handle& top)
{
	if (top->isLink())
	{
		// Recursively drill down and explore every possible node as
		// a search starting point. This is needed, as the patterns we
		// compare against might not be connected.
		for (const Handle& h : top->getOutgoingSet())
		{
			_starter_term = top;
			bool found = do_search(pme, h);
			if (found) return true;
		}
		return false;
	}

	IncomingSet iset = get_incoming_set(top);
	size_t sz = iset.size();
	for (size_t i = 0; i < sz; i++)
	{
		Handle h(iset[i]);
		dbgprt("rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr\n");
		dbgprt("Loop candidate (%lu - %s):\n%s\n", _cnt++,
		       top->toShortString().c_str(),
		       h->toShortString().c_str());
		bool found = pme->explore_neighborhood(_root, _starter_term, h);

		// Terminate search if satisfied.
		if (found) return true;
   }

	return false;
}

bool Recognizer::initiate_search(PatternMatchEngine* pme)
{
	const HandleSeq& clauses = _pattern->cnf_clauses;

	_cnt = 0;
	for (const Handle& h: clauses)
	{
		_root = h;
		bool found = do_search(pme, h);
		if (found) return true;
	}
	return false;
}

bool Recognizer::node_match(const Handle& npat_h, const Handle& nsoln_h)
{
	if (npat_h == nsoln_h) return true;
	Type tso = nsoln_h->getType();
	if (VARIABLE_NODE == tso) return true;
	if (GLOB_NODE == tso)
	{
		if (0 < _soln_vars.size())
		{
			// Check if it satisfies the type restrictions, if any
			if (std::all_of(_soln_vars.begin(), _soln_vars.end(),
				[&](const Variables& v) {
					return (not v.is_type(nsoln_h, npat_h)); }))
				return false;

			// Check if it satisfies the interval restrictions, if any
			// This is just to make sure that the upper bound is not zero
			if (std::all_of(_soln_vars.begin(), _soln_vars.end(),
				[&](const Variables& v) {
					return (not v.is_interval(nsoln_h, 1)); }))
				return false;
		}
		// No reason to reject
		return true;
	}
	return false;
}

bool Recognizer::link_match(const PatternTermPtr& ptm, const Handle& lsoln)
{
	_soln_vars.clear();
	const Handle& lpat = ptm->getHandle();

	// Self-compares always proceed.
	if (lpat == lsoln) return true;

	// mis-matched types are a dead-end.
	if (lpat->getType() != lsoln->getType()) return false;

	// Find the type and interval restrictions under a ScopeLink, if any
	if (contains_atomtype(lsoln, GLOB_NODE))
		get_glob_decl(lsoln);

	return true;
}

bool Recognizer::loose_match(const Handle& npat_h, const Handle& nsoln_h)
{
	Type gtype = nsoln_h->getType();
	// Variable matches anything; move to next.
	if (VARIABLE_NODE == gtype) return true;

	// Strict match for link types.
	if (npat_h->getType() != gtype) return false;
	if (not npat_h->isNode()) return true;

	// If we are here, we know we have nodes. Ask for a strict match.
	if (npat_h != nsoln_h) return false;
	return true;
}

bool Recognizer::fuzzy_match(const Handle& npat_h, const Handle& nsoln_h)
{
	// If we are here, then there are probably glob nodes in the soln.
	// Try to match them, fairly rigorously. Exactly what constitutes
	// an OK match is still a bit up in the air.

	if (not npat_h->isLink() or not nsoln_h->isLink()) return false;

	const HandleSeq &osg = nsoln_h->getOutgoingSet();
	size_t osg_size = osg.size();

	// Lets not waste time, if there's no glob there.
	bool have_glob = false;
	for (size_t j=0; j<osg_size; j++)
	{
		if (osg[j]->getType() == GLOB_NODE)
		{
			have_glob = true;
			break;
		}
	}
	if (not have_glob) return false;

	const HandleSeq &osp = npat_h->getOutgoingSet();
	size_t osp_size = osp.size();
	size_t max_size = std::max(osg_size, osp_size);

	size_t ks = 0;
	Variables svar = _soln_vars[ks];

	// Do a side-by-side compare. This is not as rigorous as
	// PatternMatchEngine::tree_compare() nor does it handle the bells
	// and whistles (ChoiceLink, QuoteLink, etc).
	size_t ip=0, jg=0;
	for (; ip<osp_size and jg<osg_size; ip++, jg++)
	{
		if (GLOB_NODE != osg[jg]->getType())
		{
			if (loose_match(osp[ip], osg[jg])) continue;
			return false;
		}

		// If we are here, we have a glob in the soln.
		const Handle& glob = osg[jg];
		size_t match_cnt = 0;

		// If the glob is at the end, see if it can eat everything.
		if (jg+1 == osg_size)
		{
			while (ip < osp_size)
			{
				// Make sure it satisfies both type and interval restrictions.
				if (svar.is_type(glob, osp[ip]) and
				    svar.is_interval(glob, match_cnt+1))
				{
					match_cnt++;
					ip++;
				}
				else break;
			}

			// Return true if it managed to eat everything.
			if (ip == osp_size) return true;
			else
			{
				// If we have gone through all the scopes,
				// it's not a match and we are done.
				if (ks+1 == _soln_vars.size())
					return false;
				// Otherwise reset everything and try again
				// with the next scope.
				else
				{
					// The for-loop increment will turn them back to zero.
					ip = -1;
					jg = -1;
					ks++;
					svar = _soln_vars[ks];
					continue;
				}
			}
		}

		const Handle& post(osg[jg+1]);
		while (ip < max_size and not loose_match(osp[ip], post) and
		       svar.is_type(glob, osp[ip]) and
		       svar.is_interval(glob, match_cnt+1))
		{
			match_cnt++;
			ip++;
		}
		// If ip ran past the end, then the post was not found. This is
		// a mismatch.
		if (not (ip < max_size))
		{
			// If we have gone through all the scopes,
			// it's not a match and we are done.
			if (ks+1 == _soln_vars.size())
				return false;
			// Otherwise reset everything and try again
			// with the next scope.
			else
			{
				// The for-loop increment will turn them back to zero.
				ip = -1;
				jg = -1;
				ks++;
				svar = _soln_vars[ks];
				continue;
			}
		}

		// Go around again, look for more GlobNodes. Back up by one, so
		// that the for-loop increment gets us back on track.
		ip--;
	}

	// If we are here, then we should have matched up all the atoms;
	// if we exited the loop because pattern or grounding was short,
	// then its a mis-match.
	if (ip != osp_size or jg != osg_size) return false;
	return true;
}

bool Recognizer::grounding(const HandleMap& var_soln,
                           const HandleMap& term_soln)
{
	Handle rule = term_soln.at(_root);

	if (rule != _root) {
		_rules.insert(rule);
	}

	// Look for more groundings.
	return false;
}

Handle opencog::recognize(AtomSpace* as, const Handle& hlink)
{
	PatternLinkPtr bl(PatternLinkCast(hlink));
	if (NULL == bl)
		bl = createPatternLink(*LinkCast(hlink));

	Recognizer reco(as);
	bl->satisfy(reco);

	HandleSeq hs;
	for (const Handle& h : reco._rules) hs.push_back(h);

	return as->add_link(SET_LINK, hs);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2011 Rony Shapiro <ronys@users.sourceforge.net>.
 * All rights reserved. Use of the code is allowed under the
 * Artistic License 2.0 terms, as specified in the LICENSE file
 * distributed with this code, or available from
 * http://www.opensource.org/licenses/artistic-license-2.0.php
 */

/** \file DbSelectionPanel.cpp
*
*/
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "./DbSelectionPanel.h"
#include "./OpenFilePickerValidator.h"
#include "./SafeCombinationCtrl.h"
#include "./wxutils.h"
#include "../../core/PWScore.h"

#include <wx/filename.h>

DbSelectionPanel::DbSelectionPanel(wxWindow* parent,
                                    const wxString& filePrompt,
                                    const wxString& filePickerCtrlTitle,
                                    bool autoValidate,
                                    PWScore* core,
                                    unsigned rowsep) : wxPanel(parent), m_filepicker(0),
                                                                        m_sc(0),
                                                                        m_bAutoValidate(autoValidate),
                                                                        m_core(core)
{
  wxSizerFlags borderFlags = wxSizerFlags().Border(wxLEFT|wxRIGHT, SideMargin);

  /* This doesn't work since the second Border() call overwrites all the
   * previous border values.  So now we have to insert separators by hand
   */
  //wxSizerFlags rowFlags = borderFlags.Border(wxBOTTOM, RowSeparation);

  wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL);
  panelSizer->AddSpacer(TopMargin);

  panelSizer->Add(new wxStaticText(this, wxID_ANY, filePrompt), borderFlags);
  panelSizer->AddSpacer(RowSeparation);
  COpenFilePickerValidator validator(m_filepath);
  m_filepicker = new wxFilePickerCtrl(this, wxID_ANY, wxEmptyString,
                                          filePickerCtrlTitle,
                                          _("Password Safe Databases (*.psafe3; *.dat)|*.psafe3;*.dat|Password Safe Backups (*.bak)|*.bak|Password Safe Intermediate Backups (*.ibak)|*.ibak|All files (*.*; *)|*.*;*"),
                                          wxDefaultPosition, wxDefaultSize,
                                          wxFLP_DEFAULT_STYLE | wxFLP_USE_TEXTCTRL,
                                          validator);
  panelSizer->Add(m_filepicker, borderFlags.Expand());
  panelSizer->AddSpacer(RowSeparation*rowsep);

  panelSizer->Add(new wxStaticText(this, wxID_ANY, _("Safe Combination:")), borderFlags);
  panelSizer->AddSpacer(RowSeparation);

  m_sc = new CSafeCombinationCtrl(this);
  m_sc->textCtrl->SetValidator(wxTextValidator(wxFILTER_NONE, &m_combination));
  panelSizer->Add(m_sc, borderFlags.Expand());

  SetSizerAndFit(panelSizer);

  //The parent window must call our TransferDataToWindow and TransferDataFromWindow
  m_parent->SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
}

DbSelectionPanel::~DbSelectionPanel()
{
}

void DbSelectionPanel::SelectCombinationText()
{
  m_sc->textCtrl->SetFocus();
  m_sc->textCtrl->SetSelection(-1,-1);
}

bool DbSelectionPanel::DoValidation()
{
  //the data has not been transferred from the window to our members yet, so get them from the controls
  if (wxWindow::Validate()) {

    wxFileName wxfn(m_filepicker->GetPath());

    //Did the user enter a valid file path
    if (!wxfn.FileExists()) {
      wxMessageBox( _("File or path not found."), _("Error"), wxOK | wxICON_EXCLAMATION, this);
      return false;
    }

    //Did he enter the same file that's currently open?
    if (wxfn.SameAs(wxFileName(towxstring(m_core->GetCurFile())))) {
      // It is the same damn file
      wxMessageBox(_("That file is already open."), _("Synchronize error"), wxOK | wxICON_WARNING, this);
      return false;
    }

    wxString combination = m_sc->textCtrl->GetValue();
    //Did he enter a combination?
    if (combination.empty()) {
      wxMessageBox(_("The combination cannot be blank."), _("Error"), wxOK | wxICON_EXCLAMATION, this);
      return false;
    }

    //Does the combination match?
    if (m_core->CheckPasskey(tostringx(wxfn.GetFullPath()), tostringx(combination)) != PWScore::SUCCESS) {
      wxString errmess(_("Incorrect passkey, not a PasswordSafe database, or a corrupt database. (Backup database has same name as original, ending with '~')"));
      wxMessageBox(errmess, _("Error"), wxOK | wxICON_ERROR, this);
      SelectCombinationText();
      return false;
    }

    return true;

  }
  else {
    return false;
  }
}
<commit_msg>Shift keyboard focus to the combination field if nothing was entered. Also fixed a typo<commit_after>/*
 * Copyright (c) 2003-2011 Rony Shapiro <ronys@users.sourceforge.net>.
 * All rights reserved. Use of the code is allowed under the
 * Artistic License 2.0 terms, as specified in the LICENSE file
 * distributed with this code, or available from
 * http://www.opensource.org/licenses/artistic-license-2.0.php
 */

/** \file DbSelectionPanel.cpp
*
*/
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "./DbSelectionPanel.h"
#include "./OpenFilePickerValidator.h"
#include "./SafeCombinationCtrl.h"
#include "./wxutils.h"
#include "../../core/PWScore.h"

#include <wx/filename.h>

DbSelectionPanel::DbSelectionPanel(wxWindow* parent,
                                    const wxString& filePrompt,
                                    const wxString& filePickerCtrlTitle,
                                    bool autoValidate,
                                    PWScore* core,
                                    unsigned rowsep) : wxPanel(parent), m_filepicker(0),
                                                                        m_sc(0),
                                                                        m_bAutoValidate(autoValidate),
                                                                        m_core(core)
{
  wxSizerFlags borderFlags = wxSizerFlags().Border(wxLEFT|wxRIGHT, SideMargin);

  /* This doesn't work since the second Border() call overwrites all the
   * previous border values.  So now we have to insert separators by hand
   */
  //wxSizerFlags rowFlags = borderFlags.Border(wxBOTTOM, RowSeparation);

  wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL);
  panelSizer->AddSpacer(TopMargin);

  panelSizer->Add(new wxStaticText(this, wxID_ANY, filePrompt), borderFlags);
  panelSizer->AddSpacer(RowSeparation);
  COpenFilePickerValidator validator(m_filepath);
  m_filepicker = new wxFilePickerCtrl(this, wxID_ANY, wxEmptyString,
                                          filePickerCtrlTitle,
                                          _("Password Safe Databases (*.psafe3; *.dat)|*.psafe3;*.dat|Password Safe Backups (*.bak)|*.bak|Password Safe Intermediate Backups (*.ibak)|*.ibak|All files (*.*; *)|*.*;*"),
                                          wxDefaultPosition, wxDefaultSize,
                                          wxFLP_DEFAULT_STYLE | wxFLP_USE_TEXTCTRL,
                                          validator);
  panelSizer->Add(m_filepicker, borderFlags.Expand());
  panelSizer->AddSpacer(RowSeparation*rowsep);

  panelSizer->Add(new wxStaticText(this, wxID_ANY, _("Safe Combination:")), borderFlags);
  panelSizer->AddSpacer(RowSeparation);

  m_sc = new CSafeCombinationCtrl(this);
  m_sc->textCtrl->SetValidator(wxTextValidator(wxFILTER_NONE, &m_combination));
  panelSizer->Add(m_sc, borderFlags.Expand());

  SetSizerAndFit(panelSizer);

  //The parent window must call our TransferDataToWindow and TransferDataFromWindow
  m_parent->SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
}

DbSelectionPanel::~DbSelectionPanel()
{
}

void DbSelectionPanel::SelectCombinationText()
{
  m_sc->textCtrl->SetFocus();
  m_sc->textCtrl->SetSelection(-1,-1);
}

bool DbSelectionPanel::DoValidation()
{
  //the data has not been transferred from the window to our members yet, so get them from the controls
  if (wxWindow::Validate()) {

    wxFileName wxfn(m_filepicker->GetPath());

    //Did the user enter a valid file path
    if (!wxfn.FileExists()) {
      wxMessageBox( _("File or path not found."), _("Error"), wxOK | wxICON_EXCLAMATION, this);
      return false;
    }

    //Did he enter the same file that's currently open?
    if (wxfn.SameAs(wxFileName(towxstring(m_core->GetCurFile())))) {
      // It is the same damn file
      wxMessageBox(_("That file is already open."), _("Error"), wxOK | wxICON_WARNING, this);
      return false;
    }

    wxString combination = m_sc->textCtrl->GetValue();
    //Did he enter a combination?
    if (combination.empty()) {
      m_sc->textCtrl->SetFocus();
      wxMessageBox(_("The combination cannot be blank."), _("Error"), wxOK | wxICON_EXCLAMATION, this);
      return false;
    }

    //Does the combination match?
    if (m_core->CheckPasskey(tostringx(wxfn.GetFullPath()), tostringx(combination)) != PWScore::SUCCESS) {
      wxString errmess(_("Incorrect passkey, not a PasswordSafe database, or a corrupt database. (Backup database has same name as original, ending with '~')"));
      wxMessageBox(errmess, _("Error"), wxOK | wxICON_ERROR, this);
      SelectCombinationText();
      return false;
    }

    return true;

  }
  else {
    return false;
  }
}
<|endoftext|>


<commit_before>// Copyright 2015-2018 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_AUDIO_AUDIODEVICE_HPP
#define OUZEL_AUDIO_AUDIODEVICE_HPP

#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <vector>
#include "audio/Driver.hpp"
#include "audio/Node.hpp"
#include "audio/SampleFormat.hpp"
#include "math/Quaternion.hpp"
#include "math/Vector3.hpp"

namespace ouzel
{
    namespace audio
    {
        class Audio;
        class ListenerNode;
        class MixerNode;

        class AudioDevice
        {
            friend Audio;
        public:
            struct Command
            {
                enum class Type
                {
                    INIT_NODE,
                    DESTROY_NODE,
                    UPDATE_NODE,
                    SET_INPUT,
                    SET_OUTPUT,
                };

                Type type;
                uintptr_t resourceId;
                std::function<std::unique_ptr<Node>(void)> createFunction;
                std::function<void(Node*)> updateFunction;
            };

            explicit AudioDevice(Driver initDriver);
            virtual ~AudioDevice();

            AudioDevice(const AudioDevice&) = delete;
            AudioDevice& operator=(const AudioDevice&) = delete;

            AudioDevice(AudioDevice&&) = delete;
            AudioDevice& operator=(AudioDevice&&) = delete;

            virtual void process();

            inline uint16_t getAPIMajorVersion() const { return apiMajorVersion; }
            inline uint16_t getAPIMinorVersion() const { return apiMinorVersion; }

            struct RenderCommand
            {
                std::function<void(Vector3& listenerPosition,
                                   Quaternion& listenerRotation,
                                   float& pitch,
                                   float& gain,
                                   float& rolloffFactor)> attributeCallback;

                std::function<void(uint32_t frames,
                                   uint16_t channels,
                                   uint32_t sampleRate,
                                   const Vector3& listenerPosition,
                                   const Quaternion& listenerRotation,
                                   float pitch,
                                   float gain,
                                   float rolloffFactor,
                                   std::vector<float>& result)> renderCallback;
                std::vector<RenderCommand> renderCommands;
            };

            void setRenderCommands(const std::vector<RenderCommand>& newRenderCommands);

            void addCommand(const Command& command);

            uintptr_t getNodeId()
            {
                if (deletedNodeIds.empty())
                    return ++lastNodeId; // zero is reserved for null node
                else
                {
                    uintptr_t nodeId = deletedNodeIds.front();
                    deletedNodeIds.pop();
                    return nodeId;
                }
            }

            void deleteNodeId(uintptr_t nodeId)
            {
                deletedNodeIds.push(nodeId);
            }

        protected:
            void getData(uint32_t frames, std::vector<uint8_t>& result);
            void processRenderCommands(uint32_t frames,
                                       std::vector<float>& result);
            void processRenderCommand(const RenderCommand& renderCommand,
                                      uint32_t frames,
                                      Vector3 listenerPosition,
                                      Quaternion listenerRotation,
                                      float pitch,
                                      float gain,
                                      float rolloffFactor,
                                      std::vector<float>& result);

            Driver driver;

            uint16_t apiMajorVersion = 0;
            uint16_t apiMinorVersion = 0;

            SampleFormat sampleFormat = SampleFormat::SINT16;
            const uint32_t bufferSize = 2 * 4096;
            const uint32_t sampleRate = 44100;
            const uint16_t channels = 2;

            std::vector<std::vector<float>> buffers;
            uint32_t currentBuffer = 0;

            std::vector<RenderCommand> renderQueue;
            std::mutex renderQueueMutex;

            uintptr_t lastNodeId = 0;
            std::queue<uintptr_t> deletedNodeIds;

            std::vector<std::unique_ptr<Node>> nodes;

        private:
            std::mutex commandMutex;
            std::condition_variable commandConditionVariable;
            std::queue<Command> commandQueue;
        };
    } // namespace audio
} // namespace ouzel

#endif // OUZEL_AUDIO_AUDIODEVICE_HPP
<commit_msg>Add missing condition_variable include<commit_after>// Copyright 2015-2018 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_AUDIO_AUDIODEVICE_HPP
#define OUZEL_AUDIO_AUDIODEVICE_HPP

#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <vector>
#include "audio/Driver.hpp"
#include "audio/Node.hpp"
#include "audio/SampleFormat.hpp"
#include "math/Quaternion.hpp"
#include "math/Vector3.hpp"

namespace ouzel
{
    namespace audio
    {
        class Audio;
        class ListenerNode;
        class MixerNode;

        class AudioDevice
        {
            friend Audio;
        public:
            struct Command
            {
                enum class Type
                {
                    INIT_NODE,
                    DESTROY_NODE,
                    UPDATE_NODE,
                    SET_INPUT,
                    SET_OUTPUT,
                };

                Type type;
                uintptr_t resourceId;
                std::function<std::unique_ptr<Node>(void)> createFunction;
                std::function<void(Node*)> updateFunction;
            };

            explicit AudioDevice(Driver initDriver);
            virtual ~AudioDevice();

            AudioDevice(const AudioDevice&) = delete;
            AudioDevice& operator=(const AudioDevice&) = delete;

            AudioDevice(AudioDevice&&) = delete;
            AudioDevice& operator=(AudioDevice&&) = delete;

            virtual void process();

            inline uint16_t getAPIMajorVersion() const { return apiMajorVersion; }
            inline uint16_t getAPIMinorVersion() const { return apiMinorVersion; }

            struct RenderCommand
            {
                std::function<void(Vector3& listenerPosition,
                                   Quaternion& listenerRotation,
                                   float& pitch,
                                   float& gain,
                                   float& rolloffFactor)> attributeCallback;

                std::function<void(uint32_t frames,
                                   uint16_t channels,
                                   uint32_t sampleRate,
                                   const Vector3& listenerPosition,
                                   const Quaternion& listenerRotation,
                                   float pitch,
                                   float gain,
                                   float rolloffFactor,
                                   std::vector<float>& result)> renderCallback;
                std::vector<RenderCommand> renderCommands;
            };

            void setRenderCommands(const std::vector<RenderCommand>& newRenderCommands);

            void addCommand(const Command& command);

            uintptr_t getNodeId()
            {
                if (deletedNodeIds.empty())
                    return ++lastNodeId; // zero is reserved for null node
                else
                {
                    uintptr_t nodeId = deletedNodeIds.front();
                    deletedNodeIds.pop();
                    return nodeId;
                }
            }

            void deleteNodeId(uintptr_t nodeId)
            {
                deletedNodeIds.push(nodeId);
            }

        protected:
            void getData(uint32_t frames, std::vector<uint8_t>& result);
            void processRenderCommands(uint32_t frames,
                                       std::vector<float>& result);
            void processRenderCommand(const RenderCommand& renderCommand,
                                      uint32_t frames,
                                      Vector3 listenerPosition,
                                      Quaternion listenerRotation,
                                      float pitch,
                                      float gain,
                                      float rolloffFactor,
                                      std::vector<float>& result);

            Driver driver;

            uint16_t apiMajorVersion = 0;
            uint16_t apiMinorVersion = 0;

            SampleFormat sampleFormat = SampleFormat::SINT16;
            const uint32_t bufferSize = 2 * 4096;
            const uint32_t sampleRate = 44100;
            const uint16_t channels = 2;

            std::vector<std::vector<float>> buffers;
            uint32_t currentBuffer = 0;

            std::vector<RenderCommand> renderQueue;
            std::mutex renderQueueMutex;

            uintptr_t lastNodeId = 0;
            std::queue<uintptr_t> deletedNodeIds;

            std::vector<std::unique_ptr<Node>> nodes;

        private:
            std::mutex commandMutex;
            std::condition_variable commandConditionVariable;
            std::queue<Command> commandQueue;
        };
    } // namespace audio
} // namespace ouzel

#endif // OUZEL_AUDIO_AUDIODEVICE_HPP
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "OSPCommon.h"
#ifdef OSPRAY_USE_INTERNAL_TASKING
#  include "ospray/common/tasking/TaskSys.h"
#endif
// embree
#include "embree2/rtcore.h"
#include "common/sysinfo.h"

namespace ospray {

  /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */
  extern "C" void *malloc64(size_t size)
  {
    return ospcommon::alignedMalloc(size);
  }

  /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */
  extern "C" void free64(void *ptr)
  {
    return ospcommon::alignedFree(ptr);
  }

  /*! logging level - '0' means 'no logging at all', increasing
      numbers mean increasing verbosity of log messages */
  uint32_t logLevel = 0;
  bool debugMode = false;
  int32_t numThreads = -1; //!< for default (==maximum) number of OSPRay/Embree threads

  WarnOnce::WarnOnce(const std::string &s)
    : s(s)
  {
    std::cout << "Warning: " << s << " (only reporting first occurrence)" << std::endl;
  }

  /*! for debugging. compute a checksum for given area range... */
  void *computeCheckSum(const void *ptr, size_t numBytes)
  {
    long *end = (long *)((char *)ptr + (numBytes - (numBytes%8)));
    long *mem = (long *)ptr;
    long sum = 0;
    long i = 0;

    int nextPing = 1;
    while (mem < end) {
      sum += (i+13) * *mem;
      ++i;
      ++mem;

      // if (i==nextPing) {
      //  std::cout << "checksum after " << (i*8) << " bytes: " << (int*)sum << std::endl;
      //   nextPing += nextPing;
     // }
    }
    return (void *)sum;
  }

  void doAssertion(const char *file, int line, const char *expr, const char *expl) {
    if (expl)
      fprintf(stderr,"%s:%i: Assertion failed: \"%s\":\nAdditional Info: %s\n",
              file, line, expr, expl);
    else
      fprintf(stderr,"%s:%i: Assertion failed: \"%s\".\n", file, line, expr);
    abort();
  }

  void removeArgs(int &ac, char **&av, int where, int howMany)
  {
    for (int i=where+howMany;i<ac;i++)
      av[i-howMany] = av[i];
    ac -= howMany;
  }

  void init(int *_ac, const char ***_av)
  {
#ifndef OSPRAY_TARGET_MIC
    // If we're not on a MIC, check for SSE4.1 as minimum supported ISA. Will be increased to SSE4.2 in future.
    int cpuFeatures = ospcommon::getCPUFeatures();
    if ((cpuFeatures & ospcommon::CPU_FEATURE_SSE41) == 0)
      throw std::runtime_error("Error. OSPRay only runs on CPUs that support at least SSE4.1.");
#endif

    if (_ac && _av) {
      int &ac = *_ac;
      char ** &av = *(char ***)_av;
      for (int i=1;i<ac;) {
        std::string parm = av[i];
        if (parm == "--osp:debug") {
          debugMode = true;
          numThreads = 1;
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:verbose") {
          logLevel = 1;
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:vv") {
          logLevel = 2;
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:loglevel") {
          logLevel = atoi(av[i+1]);
          removeArgs(ac,av,i,2);
        } else if (parm == "--osp:numthreads" || parm == "--osp:num-threads") {
          numThreads = atoi(av[i+1]);
          removeArgs(ac,av,i,2);
        } else {
          ++i;
        }
      }
    }

#ifdef OSPRAY_USE_INTERNAL_TASKING
    ospray::Task::initTaskSystem(debugMode ? 0 : numThreads);
#endif
  }

  void error_handler(const RTCError code, const char *str)
  {
    printf("Embree: ");
    switch (code) {
      case RTC_UNKNOWN_ERROR    : printf("RTC_UNKNOWN_ERROR"); break;
      case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break;
      case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break;
      case RTC_OUT_OF_MEMORY    : printf("RTC_OUT_OF_MEMORY"); break;
      case RTC_UNSUPPORTED_CPU  : printf("RTC_UNSUPPORTED_CPU"); break;
      default                   : printf("invalid error code"); break;
    }
    if (str) {
      printf(" (");
      while (*str) putchar(*str++);
      printf(")\n");
    }
    abort();
  }

  size_t sizeOf(const OSPDataType type) {
    switch (type) {
    case OSP_VOID_PTR:  return sizeof(void *);
    case OSP_OBJECT:    return sizeof(void *);
    case OSP_DATA:      return sizeof(void *);
    case OSP_CHAR:      return sizeof(int8);
    case OSP_UCHAR:     return sizeof(uint8);
    case OSP_UCHAR2:    return sizeof(vec2uc);
    case OSP_UCHAR3:    return sizeof(vec3uc);
    case OSP_UCHAR4:    return sizeof(vec4uc);
    case OSP_INT:       return sizeof(int32);
    case OSP_INT2:      return sizeof(vec2i);
    case OSP_INT3:      return sizeof(vec3i);
    case OSP_INT4:      return sizeof(vec4i);
    case OSP_UINT:      return sizeof(uint32);
    case OSP_UINT2:     return sizeof(vec2ui);
    case OSP_UINT3:     return sizeof(vec3ui);
    case OSP_UINT4:     return sizeof(vec4ui);
    case OSP_LONG:      return sizeof(int64);
    case OSP_LONG2:     return sizeof(vec2l);
    case OSP_LONG3:     return sizeof(vec3l);
    case OSP_LONG4:     return sizeof(vec4l);
    case OSP_ULONG:     return sizeof(uint64);
    case OSP_ULONG2:    return sizeof(vec2ul);
    case OSP_ULONG3:    return sizeof(vec3ul);
    case OSP_ULONG4:    return sizeof(vec4ul);
    case OSP_FLOAT:     return sizeof(float);
    case OSP_FLOAT2:    return sizeof(vec2f);
    case OSP_FLOAT3:    return sizeof(vec3f);
    case OSP_FLOAT4:    return sizeof(vec4f);
    case OSP_FLOAT3A:   return sizeof(vec3fa);
    case OSP_DOUBLE:    return sizeof(double);
    default: break;
    };

    std::stringstream error;
    error << __FILE__ << ":" << __LINE__ << ": unknown OSPDataType " << (int)type;
    throw std::runtime_error(error.str());
  }

  OSPDataType typeForString(const char *string) {
    if (string == NULL)                return(OSP_UNKNOWN);
    if (strcmp(string, "char"  ) == 0) return(OSP_CHAR);
    if (strcmp(string, "double") == 0) return(OSP_DOUBLE);
    if (strcmp(string, "float" ) == 0) return(OSP_FLOAT);
    if (strcmp(string, "float2") == 0) return(OSP_FLOAT2);
    if (strcmp(string, "float3") == 0) return(OSP_FLOAT2);
    if (strcmp(string, "float4") == 0) return(OSP_FLOAT2);
    if (strcmp(string, "int"   ) == 0) return(OSP_INT);
    if (strcmp(string, "int2"  ) == 0) return(OSP_INT2);
    if (strcmp(string, "int3"  ) == 0) return(OSP_INT3);
    if (strcmp(string, "int4"  ) == 0) return(OSP_INT4);
    if (strcmp(string, "uchar" ) == 0) return(OSP_UCHAR);
    if (strcmp(string, "uchar2") == 0) return(OSP_UCHAR2);
    if (strcmp(string, "uchar3") == 0) return(OSP_UCHAR3);
    if (strcmp(string, "uchar4") == 0) return(OSP_UCHAR4);
    if (strcmp(string, "uint"  ) == 0) return(OSP_UINT);
    if (strcmp(string, "uint2" ) == 0) return(OSP_UINT2);
    if (strcmp(string, "uint3" ) == 0) return(OSP_UINT3);
    if (strcmp(string, "uint4" ) == 0) return(OSP_UINT4);
    return(OSP_UNKNOWN);
  }

  size_t sizeOf(const OSPTextureFormat type) {
    switch (type) {
      case OSP_TEXTURE_RGBA8:
      case OSP_TEXTURE_SRGBA:   return sizeof(uint32);
      case OSP_TEXTURE_RGBA32F: return sizeof(vec4f);
      case OSP_TEXTURE_RGB8:
      case OSP_TEXTURE_SRGB:    return sizeof(vec3uc);
      case OSP_TEXTURE_RGB32F:  return sizeof(vec3f);
      case OSP_TEXTURE_R8:      return sizeof(uint8);
      case OSP_TEXTURE_R32F:    return sizeof(float);
    }

    std::stringstream error;
    error << __FILE__ << ":" << __LINE__ << ": unknown OSPTextureFormat " << (int)type;
    throw std::runtime_error(error.str());
  }

} // ::ospray

<commit_msg>allow tasking system to be initialized twice, output warning when it is<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "OSPCommon.h"
#ifdef OSPRAY_USE_INTERNAL_TASKING
#  include "ospray/common/tasking/TaskSys.h"
#endif
// embree
#include "embree2/rtcore.h"
#include "common/sysinfo.h"

namespace ospray {

  /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */
  extern "C" void *malloc64(size_t size)
  {
    return ospcommon::alignedMalloc(size);
  }

  /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */
  extern "C" void free64(void *ptr)
  {
    return ospcommon::alignedFree(ptr);
  }

  /*! logging level - '0' means 'no logging at all', increasing
      numbers mean increasing verbosity of log messages */
  uint32_t logLevel = 0;
  bool debugMode = false;
  int32_t numThreads = -1; //!< for default (==maximum) number of OSPRay/Embree threads

  WarnOnce::WarnOnce(const std::string &s)
    : s(s)
  {
    std::cout << "Warning: " << s << " (only reporting first occurrence)" << std::endl;
  }

  /*! for debugging. compute a checksum for given area range... */
  void *computeCheckSum(const void *ptr, size_t numBytes)
  {
    long *end = (long *)((char *)ptr + (numBytes - (numBytes%8)));
    long *mem = (long *)ptr;
    long sum = 0;
    long i = 0;

    int nextPing = 1;
    while (mem < end) {
      sum += (i+13) * *mem;
      ++i;
      ++mem;

      // if (i==nextPing) {
      //  std::cout << "checksum after " << (i*8) << " bytes: " << (int*)sum << std::endl;
      //   nextPing += nextPing;
     // }
    }
    return (void *)sum;
  }

  void doAssertion(const char *file, int line, const char *expr, const char *expl) {
    if (expl)
      fprintf(stderr,"%s:%i: Assertion failed: \"%s\":\nAdditional Info: %s\n",
              file, line, expr, expl);
    else
      fprintf(stderr,"%s:%i: Assertion failed: \"%s\".\n", file, line, expr);
    abort();
  }

  void removeArgs(int &ac, char **&av, int where, int howMany)
  {
    for (int i=where+howMany;i<ac;i++)
      av[i-howMany] = av[i];
    ac -= howMany;
  }

  void init(int *_ac, const char ***_av)
  {
#ifndef OSPRAY_TARGET_MIC
    // If we're not on a MIC, check for SSE4.1 as minimum supported ISA. Will be increased to SSE4.2 in future.
    int cpuFeatures = ospcommon::getCPUFeatures();
    if ((cpuFeatures & ospcommon::CPU_FEATURE_SSE41) == 0)
      throw std::runtime_error("Error. OSPRay only runs on CPUs that support at least SSE4.1.");
#endif

    if (_ac && _av) {
      int &ac = *_ac;
      char ** &av = *(char ***)_av;
      for (int i=1;i<ac;) {
        std::string parm = av[i];
        if (parm == "--osp:debug") {
          debugMode = true;
          numThreads = 1;
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:verbose") {
          logLevel = 1;
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:vv") {
          logLevel = 2;
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:loglevel") {
          logLevel = atoi(av[i+1]);
          removeArgs(ac,av,i,2);
        } else if (parm == "--osp:numthreads" || parm == "--osp:num-threads") {
          numThreads = atoi(av[i+1]);
          removeArgs(ac,av,i,2);
        } else {
          ++i;
        }
      }
    }

#ifdef OSPRAY_USE_INTERNAL_TASKING
    try {
      ospray::Task::initTaskSystem(debugMode ? 0 : numThreads);
    } catch (const std::runtime_error &e) {
      std::cerr << "WARNING: " << e.what() << std::endl;
    }
#endif
  }

  void error_handler(const RTCError code, const char *str)
  {
    printf("Embree: ");
    switch (code) {
      case RTC_UNKNOWN_ERROR    : printf("RTC_UNKNOWN_ERROR"); break;
      case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break;
      case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break;
      case RTC_OUT_OF_MEMORY    : printf("RTC_OUT_OF_MEMORY"); break;
      case RTC_UNSUPPORTED_CPU  : printf("RTC_UNSUPPORTED_CPU"); break;
      default                   : printf("invalid error code"); break;
    }
    if (str) {
      printf(" (");
      while (*str) putchar(*str++);
      printf(")\n");
    }
    abort();
  }

  size_t sizeOf(const OSPDataType type) {
    switch (type) {
    case OSP_VOID_PTR:  return sizeof(void *);
    case OSP_OBJECT:    return sizeof(void *);
    case OSP_DATA:      return sizeof(void *);
    case OSP_CHAR:      return sizeof(int8);
    case OSP_UCHAR:     return sizeof(uint8);
    case OSP_UCHAR2:    return sizeof(vec2uc);
    case OSP_UCHAR3:    return sizeof(vec3uc);
    case OSP_UCHAR4:    return sizeof(vec4uc);
    case OSP_INT:       return sizeof(int32);
    case OSP_INT2:      return sizeof(vec2i);
    case OSP_INT3:      return sizeof(vec3i);
    case OSP_INT4:      return sizeof(vec4i);
    case OSP_UINT:      return sizeof(uint32);
    case OSP_UINT2:     return sizeof(vec2ui);
    case OSP_UINT3:     return sizeof(vec3ui);
    case OSP_UINT4:     return sizeof(vec4ui);
    case OSP_LONG:      return sizeof(int64);
    case OSP_LONG2:     return sizeof(vec2l);
    case OSP_LONG3:     return sizeof(vec3l);
    case OSP_LONG4:     return sizeof(vec4l);
    case OSP_ULONG:     return sizeof(uint64);
    case OSP_ULONG2:    return sizeof(vec2ul);
    case OSP_ULONG3:    return sizeof(vec3ul);
    case OSP_ULONG4:    return sizeof(vec4ul);
    case OSP_FLOAT:     return sizeof(float);
    case OSP_FLOAT2:    return sizeof(vec2f);
    case OSP_FLOAT3:    return sizeof(vec3f);
    case OSP_FLOAT4:    return sizeof(vec4f);
    case OSP_FLOAT3A:   return sizeof(vec3fa);
    case OSP_DOUBLE:    return sizeof(double);
    default: break;
    };

    std::stringstream error;
    error << __FILE__ << ":" << __LINE__ << ": unknown OSPDataType " << (int)type;
    throw std::runtime_error(error.str());
  }

  OSPDataType typeForString(const char *string) {
    if (string == NULL)                return(OSP_UNKNOWN);
    if (strcmp(string, "char"  ) == 0) return(OSP_CHAR);
    if (strcmp(string, "double") == 0) return(OSP_DOUBLE);
    if (strcmp(string, "float" ) == 0) return(OSP_FLOAT);
    if (strcmp(string, "float2") == 0) return(OSP_FLOAT2);
    if (strcmp(string, "float3") == 0) return(OSP_FLOAT2);
    if (strcmp(string, "float4") == 0) return(OSP_FLOAT2);
    if (strcmp(string, "int"   ) == 0) return(OSP_INT);
    if (strcmp(string, "int2"  ) == 0) return(OSP_INT2);
    if (strcmp(string, "int3"  ) == 0) return(OSP_INT3);
    if (strcmp(string, "int4"  ) == 0) return(OSP_INT4);
    if (strcmp(string, "uchar" ) == 0) return(OSP_UCHAR);
    if (strcmp(string, "uchar2") == 0) return(OSP_UCHAR2);
    if (strcmp(string, "uchar3") == 0) return(OSP_UCHAR3);
    if (strcmp(string, "uchar4") == 0) return(OSP_UCHAR4);
    if (strcmp(string, "uint"  ) == 0) return(OSP_UINT);
    if (strcmp(string, "uint2" ) == 0) return(OSP_UINT2);
    if (strcmp(string, "uint3" ) == 0) return(OSP_UINT3);
    if (strcmp(string, "uint4" ) == 0) return(OSP_UINT4);
    return(OSP_UNKNOWN);
  }

  size_t sizeOf(const OSPTextureFormat type) {
    switch (type) {
      case OSP_TEXTURE_RGBA8:
      case OSP_TEXTURE_SRGBA:   return sizeof(uint32);
      case OSP_TEXTURE_RGBA32F: return sizeof(vec4f);
      case OSP_TEXTURE_RGB8:
      case OSP_TEXTURE_SRGB:    return sizeof(vec3uc);
      case OSP_TEXTURE_RGB32F:  return sizeof(vec3f);
      case OSP_TEXTURE_R8:      return sizeof(uint8);
      case OSP_TEXTURE_R32F:    return sizeof(float);
    }

    std::stringstream error;
    error << __FILE__ << ":" << __LINE__ << ": unknown OSPTextureFormat " << (int)type;
    throw std::runtime_error(error.str());
  }

} // ::ospray

<|endoftext|>