[med-svn] [cnrun] 15/25: WIP

andrei zavada hmmr-guest at moszumanska.debian.org
Thu Nov 6 22:08:31 UTC 2014


This is an automated email from the git hooks/post-receive script.

hmmr-guest pushed a commit to branch WIP
in repository cnrun.

commit e8aa0a3f9beffed7cf0bba168c8790e29a0252c6
Author: andrei zavada <johnhommer at gmail.com>
Date:   Sat Sep 20 10:30:55 2014 +0400

    WIP
---
 upstream/src/cnrun/Makefile.am            |    2 +-
 upstream/src/cnrun/interpreter.cc         | 1667 +++++++++++++++--------------
 upstream/src/cnrun/main.cc                |   14 -
 upstream/src/cnrun/runner.hh              |   48 +-
 upstream/src/libcn/base-unit.cc           |   44 +-
 upstream/src/libcn/hosted-neurons.cc      |    8 -
 upstream/src/libcn/hosted-synapses.cc     |   20 +-
 upstream/src/libcn/model-cycle.cc         |   35 +-
 upstream/src/libcn/model-nmlio.cc         |   37 +-
 upstream/src/libcn/model-struct.cc        |  103 +-
 upstream/src/libcn/model.hh               |  111 +-
 upstream/src/libcn/standalone-neurons.cc  |   35 +-
 upstream/src/libcn/standalone-synapses.cc |   31 +-
 upstream/src/libstilton/Makefile.am       |    6 +-
 upstream/src/libstilton/alg.hh            |    6 +-
 upstream/src/libstilton/libcommon.cc      |   27 +
 upstream/src/libstilton/misc.hh           |   43 +
 upstream/src/libstilton/string.hh         |    2 +-
 18 files changed, 1115 insertions(+), 1124 deletions(-)

diff --git a/upstream/src/cnrun/Makefile.am b/upstream/src/cnrun/Makefile.am
index 148bf1a..36a717d 100644
--- a/upstream/src/cnrun/Makefile.am
+++ b/upstream/src/cnrun/Makefile.am
@@ -10,7 +10,7 @@ endif
 bin_PROGRAMS = \
 	cnrun
 cnrun_SOURCES = \
-	main.cc interpreter.cc completions.cc cnrun.hh
+	interpreter.cc completions.cc cnrun.hh main.cc
 cnrun_LDADD = \
 	$(top_srcdir)/src/libicing.a \
 	$(top_srcdir)/src/libcn/libcn.la \
diff --git a/upstream/src/cnrun/interpreter.cc b/upstream/src/cnrun/interpreter.cc
index 9aaa464..323c59e 100644
--- a/upstream/src/cnrun/interpreter.cc
+++ b/upstream/src/cnrun/interpreter.cc
@@ -15,7 +15,6 @@
 #include <cassert>
 #include <regex.h>
 #include <list>
-#include <initializer_list>
 
 #if HAVE_CONFIG_H && !defined(VERSION)
 #  include "config.h"
@@ -34,58 +33,59 @@
 #endif
 
 #include "libstilton/string.hh"
-#include "runner.hh"
 #include "libstilton/exprparser.hh"
 #include "libcn/integrate-rk65.hh"
 #include "libcn/base-unit.hh"
+#include "runner.hh"
 
 using namespace std;
 using namespace cnrun;
 
 const char* const cnrun::cnrun_cmd[] = {
-	"new_model",
-	"load_nml",
-	"merge_nml",
-	"add_neuron",
-	"add_synapse",
-	"reset",
-	"reset_revert_params",
-	"reset_state_units",
-	"advance_until",
-	"advance",
-	"putout",
-	"decimate",
-	"start_listen",
-	"stop_listen",
-	"listen_dt",
-	"listen_mode",
-	"integration_dt_min",
-	"integration_dt_max",
-	"integration_dt_cap",
-	"start_log_spikes",
-	"stop_log_spikes",
-	"sxf_params",
-	"new_source",
-	"show_sources",
-	"connect_source",
-	"disconnect_source",
-	"set_parm_neuron",
-	"set_parm_synapse",
-	"cull_deaf_synapses",
-	"describe_model",
-	"show_units",
-	"exec",
-	"verbosity",
-	"show_vars",
-	"clear_vars",
-	"pause",
-	"quit",
-	nullptr
+        "new_model",
+        "load_nml",
+        "merge_nml",
+        "add_neuron",
+        "add_synapse",
+        "reset",
+        "reset_revert_params",
+        "reset_state_units",
+        "advance_until",
+        "advance",
+        "putout",
+        "decimate",
+        "start_listen",
+        "stop_listen",
+        "listen_dt",
+        "listen_mode",
+        "integration_dt_min",
+        "integration_dt_max",
+        "integration_dt_cap",
+        "start_log_spikes",
+        "stop_log_spikes",
+        "sxf_params",
+        "new_source",
+        "show_sources",
+        "connect_source",
+        "disconnect_source",
+        "set_parm_neuron",
+        "set_parm_synapse",
+        "cull_deaf_synapses",
+        "describe_model",
+        "show_units",
+        "exec",
+        "verbosity",
+        "show_vars",
+        "clear_vars",
+        "pause",
+        "quit",
+        nullptr
 };
 
 
 
-list<SVariable> *cnrun::current_shell_variables;
+list<cnrun::stilton::SVariable>
+       *cnrun::CInterpreter::current_env;
 
 
 
@@ -94,26 +94,27 @@ namespace {
 void
 report_script_issue( const char *fname, int lineno, int vrb, const char* fmt, ...)
 {
-	va_list ap;
-	va_start (ap, fmt);
-	string body = str::svasprintf( fmt, ap);
-	va_end (ap);
-
-	string pre = ( lineno > 0 )
-		? str::sasprintf( "%s:%d: %s", fname, lineno, body.c_str())
-		: str::sasprintf( "%s: %s", fname, body.c_str());
+        using namespace stilton::str;
+        va_list ap;
+        va_start (ap, fmt);
+        string body = svasprintf( fmt, ap);
+        va_end (ap);
+
+        string pre = ( lineno > 0 )
+                ? sasprintf( "%s:%d: %s", fname, lineno, body.c_str())
+                : sasprintf( "%s: %s", fname, body.c_str());
 }
 
 int do_single_cmd( const char*,
-		   list<SVariable> &varlist,
-		   int level = 0, const char *fname = "",
-		   unsigned lineno = -1);
+                   list<stilton::SVariable> &varlist,
+                   int level = 0, const char *fname = "",
+                   unsigned lineno = -1);
 
 
-#define CN_INTERP_EXIT		 1
-#define CN_INTERP_WARN		-1
-#define CN_INTERP_PARSEERROR	-2
-#define CN_INTERP_SYSFAIL	-3
+#define CN_INTERP_EXIT                 1
+#define CN_INTERP_WARN                -1
+#define CN_INTERP_PARSEERROR        -2
+#define CN_INTERP_SYSFAIL        -3
 
 #define CNRUN_HISTORY ".cnrun-history"
 
@@ -121,34 +122,33 @@ int do_single_cmd( const char*,
 
 
 int
-new_model( const char *model_name, const char *fname, unsigned lineno)
+cnrun::CInterpreter::
+new_model( const string& model_name, const string& fname, size_t lineno)
 {
-	if ( !(Model = new CModel( model_name,
-				   new CIntegrateRK65( Options.integration_dt_min,
-						       Options.integration_dt_max,
-						       Options.integration_dt_max_cap),
-				   0 |
-				   (Options.log_dt ? CN_MDL_LOGDT : 0) |
-				   (Options.log_spikers ? CN_MDL_LOGSPIKERS : 0) |
-				   (Options.sort_units ? CN_MDL_SORTUNITS : 0) |
-				   (Options.log_spikers_use_serial_id ? CN_MDL_LOGUSINGID : 0) |
-				   (Options.display_progress_percent ? CN_MDL_DISPLAY_PROGRESS_PERCENT : 0) |
-				   (Options.display_progress_time ? CN_MDL_DISPLAY_PROGRESS_TIME : 0) |
-				   (Options.dont_coalesce ? CN_MDL_DONT_COALESCE : 0))) ) {
-		report_script_issue( fname, lineno, -1, "Failed to create model");
-		return CN_INTERP_SYSFAIL;
-	}
-
-	Model->verbosely = Options.verbosely;
-	Model->listen_dt = Options.listen_dt;
-	Model->spike_threshold = Options.spike_threshold /*,  Model->spike_lapse = Options.spike_lapse */;
-	lprintf( 3,
-		 "generator type: %s\n"
-		 "         seed = %lu\n"
-		 "  first value = %lu\n",
-		 gsl_rng_name (Model->_rng), gsl_rng_default_seed, gsl_rng_get (Model->_rng));
-
-	return 0;
+        if ( model )
+                delete model;
+
+        model = new CModel(
+                model_name,
+                new CIntegrateRK65(
+                        Options.integration_dt_min,
+                        Options.integration_dt_max,
+                        Options.integration_dt_max_cap),
+                Options);
+        if ( !model ) {
+                report_script_issue( fname, lineno, -1, "Failed to create model");
+                return CN_INTERP_SYSFAIL;
+        }
+
+        model->vp( 3,
+                   "generator type: %s\n"
+                   "         seed = %lu\n"
+                   "  first value = %lu\n",
+                   gsl_rng_name (model->_rng),
+                   gsl_rng_default_seed,
+                   gsl_rng_get (model->_rng));
+
+        return 0;
 }
 
 
@@ -158,643 +158,643 @@ new_model( const char *model_name, const char *fname, unsigned lineno)
 
 int
 do_single_cmd( const char* raw,
-	       list<SVariable> &varlist,
-	       int level, const char *fname, unsigned lineno)
+               list<SVariable> &varlist,
+               int level, const char *fname, unsigned lineno)
 {
-	string	raw_s( raw);
-	char	*cmd = strtok( &raw_s[0], " \t"),
-		*operand = strtok( nullptr, "\n");
+        string  raw_s( raw);
+        char   *cmd = strtok( &raw_s[0], " \t"),
+               *operand = strtok( nullptr, "\n");
 
-	CExpression expr;
-	double result;
+        CExpression expr;
+        double result;
 
 #define CHECK_MODEL \
-	if ( !Model ) {							\
-		report_script_issue( fname, lineno, -1, "No model loaded");		\
-		return CN_INTERP_WARN;					\
-	}
-
-
-	if ( strcmp( cmd, cnrun_cmd[CNCMD_new_model]) == 0 ) {
-		if ( !operand ) {
-			report_script_issue( fname, lineno, -1, "Missing a name for the new model");
-			return CN_INTERP_PARSEERROR;
-		}
-		delete Model;
-
-		regenerate_unit_labels = true;
-		return new_model( operand, fname, lineno);
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_load_nml]) == 0 ) {
-		struct stat s;
-		if ( stat( operand, &s) ) {
-			report_script_issue( fname, lineno, -1, "No such file: \"%s\"", operand);
-			return CN_INTERP_SYSFAIL;
-		}
-
-		int retval = new_model( operand, fname, lineno);
-		if ( retval )
-			return retval;
-
-		if ( Model->import_NetworkML( operand, false) < 0 ) {
-			report_script_issue( fname, lineno, -1, "Failed to create model topology from \"%s\"", operand);
-			delete Model;
-			Model = nullptr;
-			return CN_INTERP_SYSFAIL;
-		}
-
-		Model -> cull_blind_synapses();
-		regenerate_unit_labels = true;
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_merge_nml]) == 0 ) {
-		CHECK_MODEL;
-		struct stat s;
-		if ( stat( operand, &s) ) {
-			report_script_issue( fname, lineno, -1, "No such file: \"%s\"", operand);
-			return CN_INTERP_SYSFAIL;
-		}
-		if ( Model->import_NetworkML( operand, true) < 0 ) {
-			report_script_issue( fname, lineno, -1, "Failed to import topology from \"%s\"", operand);
-			return CN_INTERP_SYSFAIL;
-		}
-
-		regenerate_unit_labels = true;
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_add_neuron]) == 0 ) {
-		CHECK_MODEL;
-		char *type_s, *label_s;
-		if ( !operand ||
-		     !(type_s = (strtok( operand, " \t"))) ||
-		     !(label_s = strtok( nullptr, "\n")) ) {
-			report_script_issue( fname, lineno, -1, "Missing neuron type and/or label in `add_neuron'");
-			return CN_INTERP_PARSEERROR;
-		}
-		if ( !Model->add_neuron_species( type_s, label_s, true) ) {
-			report_script_issue( fname, lineno, -1, "`add_neuron' failed");
-			return CN_INTERP_PARSEERROR;
-		}
-		regenerate_unit_labels = true;
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_add_synapse]) == 0 ) {
-		CHECK_MODEL;
-		char *type_s, *src_s, *tgt_s, *g_s;
-		if ( !operand ||
-		     !(type_s = (strtok( operand, " \t"))) ||
-		     !(src_s = strtok( nullptr, " \t")) ||
-		     !(tgt_s = strtok( nullptr, " \t")) ||
-		     !(g_s = strtok( nullptr, "\n")) ) {
-			report_script_issue( fname, lineno, -1, "Missing synapse type, source or target label, and/or gsyn in `add_synapse'");
-			return CN_INTERP_PARSEERROR;
-		}
-		double g;
-		if ( expr( g_s, g, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "Bad value for gsyn in `add_synapse'");
-			return CN_INTERP_PARSEERROR;
-		}
-
-		if ( !Model->add_synapse_species( type_s, src_s, tgt_s, g, true, true) ) {
-			report_script_issue( fname, lineno, -1, "`add_synapse' failed (reason given above)", operand);
-			return CN_INTERP_SYSFAIL;
-		}
-		regenerate_unit_labels = true;
-
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_reset]) == 0 ) {
-		CHECK_MODEL;
-		Model->reset();
-		lprintf( 0, "Reset model and state of all units");
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_reset_revert_params]) == 0 ) {
-		CHECK_MODEL;
-		Model->reset( true);
-		lprintf( 0, "Reset model and reverted all units' state and parameters");
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_reset_state_units]) == 0 ) {
-		CHECK_MODEL;
-		if ( !operand )
-			operand = const_cast<char*>(".*");
-		regex_t RE;
-		if ( 0 != regcomp( &RE, operand, REG_EXTENDED | REG_NOSUB) ) {
-			report_script_issue( fname, lineno, -1, "Invalid regexp for `reset_state_units' arg");
-			return CN_INTERP_PARSEERROR;
-		}
-		size_t cnt = 0;
-		for_model_units (Model,U)
-			if ( regexec( &RE, (*U)->label(), 0, 0, 0) == 0 ) {
-				(*U) -> reset_state();
-				++cnt;
-			}
-		if ( cnt )
-			lprintf( 0, "Reset %zd unit(s)", cnt);
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_advance_until]) == 0 ) {
-		CHECK_MODEL;
-		expr.silent = true;
-		if ( !operand || expr( operand, result, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "No or bad time value for `advance_until'");
-			return CN_INTERP_PARSEERROR;
-		}
-		if ( Model->model_time() > result ) {
-			report_script_issue( fname, lineno, 0, "Cannot go back in time (now is %g)", Model->model_time());
-			return CN_INTERP_WARN;
-		}
-
-		Model -> advance( result - Model->model_time());
-		for_model_spikelogging_neurons (Model,N)
-			(*N)->sync_spikelogging_history();
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_advance]) == 0 ) {
-		CHECK_MODEL;
-		if ( !operand || expr( operand, result, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "No or bad time value for `advance'");
-			return CN_INTERP_PARSEERROR;
-		}
-
-		Model -> advance( result);
-		for_model_spikelogging_neurons (Model,N)
-			(*N)->sync_spikelogging_history();
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_putout]) == 0 ) {
-		CHECK_MODEL;
-		char *label_s;
-		if ( !operand ||
-		     !(label_s = (strtok( operand, " \t"))) ) {
-			report_script_issue( fname, lineno, -1, "Missing label in `putout'");
-			return CN_INTERP_PARSEERROR;
-		}
-
-		list<CModel::STagGroup> tags;
-		tags.push_back( CModel::STagGroup (label_s));
-		Model->process_putout_tags( tags);
-
-		regenerate_unit_labels = true;
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_decimate]) == 0 ) {
-		CHECK_MODEL;
-		char *label_s, *frac_s;
-		if ( !operand ||
-		     !(label_s = (strtok( operand, " \t"))) ||
-		     !(frac_s = (strtok( nullptr, "\n"))) ) {
-			report_script_issue( fname, lineno, -1, "Missing fraction or label in `decimate'");
-			return CN_INTERP_PARSEERROR;
-		}
-		if ( expr( frac_s, result, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "Unparsable expression for decimation fraction: \"%s\"", operand);
-			return CN_INTERP_PARSEERROR;
-		}
-		if ( result < 0. || result > 1. ) {
-			report_script_issue( fname, lineno, -1, "Decimation fraction outside [0..1]");
-			return CN_INTERP_PARSEERROR;
-		}
-
-		list<CModel::STagGroupDecimate> tags;
-		tags.push_back( CModel::STagGroupDecimate( label_s, result));
-		Model -> process_decimate_tags( tags);
-
-		regenerate_unit_labels = true;
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_start_listen]) == 0 ) {
-		CHECK_MODEL;
-		if ( !operand ||
-		     !(operand = (strtok( operand, " \t")) ) ) {
-			report_script_issue( fname, lineno, -1, "Missing label in `start_listen'");
-			return CN_INTERP_PARSEERROR;
-		}
-		list<CModel::STagGroupListener> tags;
-		tags.push_back( CModel::STagGroupListener (operand, true, 0
-					      | (Options.listen_1varonly ? CN_ULISTENING_1VARONLY : 0)
-					      | (Options.listen_deferwrite ? CN_ULISTENING_DEFERWRITE : 0)
-					      | (Options.listen_binary ? CN_ULISTENING_BINARY : CN_ULISTENING_DISK)));
-		Model->process_listener_tags( tags);
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_stop_listen]) == 0 ) {
-		CHECK_MODEL;
-		if ( !operand ||
-		     !(operand = (strtok( operand, " \t"))) ) {
-			report_script_issue( fname, lineno, -1, "Missing label in `stop_listen'");
-			return CN_INTERP_PARSEERROR;
-		}
-		list<CModel::STagGroupListener> tags;
-		tags.push_back( CModel::STagGroupListener (operand, false));
-		Model->process_listener_tags( tags);
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_listen_dt]) == 0 ) {
-		if ( !operand ) {
-			lprintf( 0, "listen_dt is %g", Options.listen_dt);
-			return 0;
-		}
-		if ( expr( operand, result, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "Unparsable expression for value in `listen_dt'");
-			return CN_INTERP_PARSEERROR;
-		}
-		if ( Model )
-			Model->listen_dt = Options.listen_dt = result;
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_listen_mode]) == 0 ) {
-		if ( !operand )
-			lprintf( 0, "listen mode is 1%sd%sb%s (%s%s%s)",
-				  Options.listen_1varonly ? "+" : "",
-				  Options.listen_deferwrite ? "+" : "",
-				  Options.listen_binary ? "+" : "",
-				  Options.listen_1varonly ? "one var-only, " : "all vars, ",
-				  Options.listen_deferwrite ? "deferred write, " : "continuous write, ",
-				  Options.listen_binary ? "binary" : "ascii");
-		else {
-			char *c;
-			if ( (c = strchr( operand, '1')) ) Options.listen_1varonly   = (*(c+1) != '-');
-			if ( (c = strchr( operand, 'd')) ) Options.listen_deferwrite = (*(c+1) != '-');
-			if ( (c = strchr( operand, 'b')) ) Options.listen_binary     = (*(c+1) != '-');
-		}
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_integration_dt_min]) == 0 ) {
-		if ( !operand ) {
-			lprintf( 0, "integration_dt_min is %g", Options.integration_dt_min);
-			return 0;
-		}
-		if ( expr( operand, result, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "Unparsable expression for value in `integration_dt_min'");
-			return CN_INTERP_PARSEERROR;
-		}
-		Options.integration_dt_min = result;
-		if ( Model )
-			Model->dt_min() = result;
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_integration_dt_max]) == 0 ) {
-		if ( !operand ) {
-			lprintf( 0, "integration_dt_max is %g", Options.integration_dt_max);
-			return 0;
-		}
-		if ( expr( operand, result, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "Unparsable expression for value in `integration_dt_max'");
-			return CN_INTERP_PARSEERROR;
-		}
-		Options.integration_dt_max = result;
-		if ( Model )
-			Model->dt_max() = result;
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_integration_dt_cap]) == 0 ) {
-		if ( !operand ) {
-			lprintf( 0, "integration_dt_cap is %g", Options.integration_dt_max_cap);
-			return 0;
-		}
-		if ( expr( operand, result, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "Unparsable expression for value in `integration_dt_cap'");
-			return CN_INTERP_PARSEERROR;
-		}
-		Options.integration_dt_max_cap = result;
-		if ( Model )
-			(static_cast<CIntegrateRK65*>(Model->_integrator)) -> _dt_max_cap = result;
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_set_sxf_params]) == 0 ) {
-		if ( !operand ) {
-			lprintf( 0, "sxf_start_delay:sxf_period:sdf_sigma is %g:%g:%g",
-				  Options.sxf_start_delay, Options.sxf_sample, Options.sdf_sigma);
-			return 0;
-		}
-		if ( sscanf( operand, "%g:%g:%g",
-			     &Options.sxf_start_delay, &Options.sxf_sample, &Options.sdf_sigma) < 3 ) {
-			report_script_issue( fname, lineno, -1, "Expecting <double>:<double>:<double> with set_sxf_params");
-			return CN_INTERP_PARSEERROR;
-		}
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_start_log_spikes]) == 0 ) {
-		CHECK_MODEL;
-		char *label_s;
-		if ( !operand ||
-		     !(label_s = (strtok( operand, " \t"))) ) {
-			report_script_issue( fname, lineno, -1, "Missing label in `start_log_spikes'");
-			return CN_INTERP_PARSEERROR;
-		}
-		if ( Options.sxf_sample <= 0. || Options.sdf_sigma <= 0. ) {
-			report_script_issue( fname, lineno, 1, "SDF parameters not set up, will only log spike times");
-		}
-		list<CModel::STagGroupSpikelogger> specs;
-		specs.push_back( CModel::STagGroupSpikelogger (label_s, true,
-							       Options.sxf_sample, Options.sdf_sigma, Options.sxf_start_delay));
-		Model->process_spikelogger_tags( specs);
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_stop_log_spikes]) == 0 ) {
-		CHECK_MODEL;
-		char *label_s;
-		if ( !operand ||
-		     !(label_s = (strtok( operand, " \t"))) ) {
-			report_script_issue( fname, lineno, -1, "Missing label in `stop_log_spikes'");
-			return CN_INTERP_PARSEERROR;
-		}
-		list<CModel::STagGroupSpikelogger> specs;
-		specs.push_back( CModel::STagGroupSpikelogger (label_s, false));
-		Model->process_spikelogger_tags( specs);
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_set_parm_neuron]) == 0 ) {
-		CHECK_MODEL;
-		char *label_s, *parm_s, *value_s;
-		if ( !operand ||
-		     !(label_s = (strtok( operand, " \t"))) ||
-		     !(parm_s = strtok( nullptr, " \t")) ||
-		     !(value_s = strtok( nullptr, "\n")) ) {
-			report_script_issue( fname, lineno, -1, "Missing label, parameter or value in `set_parm_neuron'");
-			return CN_INTERP_PARSEERROR;
-		}
-		if ( expr( value_s, result, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "Unparsable expression for value in `set_parm_neuron'");
-			return CN_INTERP_PARSEERROR;
-		}
-		list<CModel::STagGroupNeuronParmSet> specs = { CModel::STagGroupNeuronParmSet (label_s, true, parm_s, result) };
-		Model->process_paramset_static_tags( specs);
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_set_parm_synapse]) == 0 ) {
-		CHECK_MODEL;
-		char *src_s, *tgt_s, *parm_s, *value_s;
-		if ( !operand ||
-		     !(src_s = (strtok( operand, " \t"))) ||
-		     !(tgt_s = (strtok( nullptr, " \t"))) ||
-		     !(parm_s = strtok( nullptr, " \t")) ||
-		     !(value_s = strtok( nullptr, "\n")) ) {
-			report_script_issue( fname, lineno, -1, "Missing source or target label, parameter and/or value in `set_parm_synapse'");
-			return CN_INTERP_PARSEERROR;
-		}
-		if ( expr( value_s, result, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "Unparsable value in `set_parm_synapse'");
-			return CN_INTERP_PARSEERROR;
-		}
-		list<CModel::STagGroupSynapseParmSet> specs = { CModel::STagGroupSynapseParmSet (src_s, tgt_s, true, parm_s, result) };
-		Model->process_paramset_static_tags( specs);
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_new_source]) == 0 ) {
-		CHECK_MODEL;
-		char *type_s, *name_s;
-		if ( !operand ||
-		     !(type_s = (strtok( operand, " \t"))) ||
-		     !(name_s = (strtok( nullptr, " \t"))) ) {
-			report_script_issue( fname, lineno, -1, "Missing source type or name in `new_source'");
-			return CN_INTERP_PARSEERROR;
-		}
-
-		if ( Model->source_by_id( name_s) ) {
-			report_script_issue( fname, lineno, -1, "A source named \"%s\" already exists", name_s);
-			return CN_INTERP_PARSEERROR;
-		}
-
-		char *arg1, *arg2;
-		if ( strcmp( type_s, __SourceTypes[SRC_TAPE]) == 0 ) {
-			if ( !(arg1 = strtok( nullptr, "\n")) ) {
-				report_script_issue( fname, lineno, -1, "Missing filename for a Tape source in `new_source'");
-				return CN_INTERP_PARSEERROR;
-			} else {
-				CSourceTape *source = new CSourceTape( name_s, arg1);
-				if ( source && source->name.size() )
-					if ( count( Model->Sources.begin(), Model->Sources.end(), source) == 0 )
-						Model->Sources.push_back( source);
-					else {
-						report_script_issue( fname, lineno, -1, "Duplicate name (\"%s\") for a source", arg1);
-						return CN_INTERP_SYSFAIL;
-					}
-				else {
-					delete source;
-					report_script_issue( fname, lineno, -1, "Failed to set up a Tape source from \"%s\"", arg1);
-					return CN_INTERP_SYSFAIL;
-				}
-			}
-		} else if ( strcmp( type_s, __SourceTypes[SRC_PERIODIC]) == 0 ) {
-			if ( !(arg1 = strtok( nullptr, "\n")) ) {
-				report_script_issue( fname, lineno, -1, "Missing filename for a Periodic source in `new_source'");
-				return CN_INTERP_PARSEERROR;
-			} else {
-				CSourcePeriodic *source = new CSourcePeriodic( name_s, arg1);
-				if ( source && source->name.size() )
-					if ( count( Model->Sources.begin(), Model->Sources.end(), source) == 0 )
-						Model->Sources.push_back( source);
-					else {
-						report_script_issue( fname, lineno, -1, "Duplicate name (\"%s\") for a source", arg1);
-						return CN_INTERP_SYSFAIL;
-					}
-				else {
-					delete source;
-					report_script_issue( fname, lineno, -1, "Failed to set up a Periodic source from \"%s\"", arg1);
-					return CN_INTERP_SYSFAIL;
-				}
-			}
-		} else if ( strcmp( type_s, __SourceTypes[SRC_NOISE]) == 0 ) {
-			if ( !(arg1 = strtok( nullptr, ":")) ||
-			     !(arg2 = strtok( nullptr, "\n")) ) {
-				report_script_issue( fname, lineno, -1, "Incomplete min:max set for a Noise source in `new_source'");
-				return CN_INTERP_PARSEERROR;
-			} else {
-				double _min, _max;
-				if ( expr( arg1, _min, &varlist) ||
-				     expr( arg2, _max, &varlist) ) {
-					report_script_issue( fname, lineno, -1, "Bad min:max values for a Noise source");
-					return CN_INTERP_PARSEERROR;
-				}
-				CSourceNoise *source = new CSourceNoise( name_s, _min, _max);
-				if ( source && source->name.size() ) {
-					Model->Sources.push_back( source);
-				} else {
-					delete source;
-					report_script_issue( fname, lineno, -1, "Failed to set up a Noise source");
-					return CN_INTERP_SYSFAIL;
-				}
-			}
-		} else if ( strcmp( type_s, __SourceTypes[SRC_FUNCTION]) == 0 ) {
-			report_script_issue( fname, lineno, -1, "Go code, Chris!");
-			return CN_INTERP_SYSFAIL;
-		} else {
-			report_script_issue( fname, lineno, -1, "Unrecognised source type in `new_source'");
-			return CN_INTERP_PARSEERROR;
-		}
-
-		regenerate_source_ids = true;
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_show_sources]) == 0 ) {
-		CHECK_MODEL;
-		for ( list<C_BaseSource*>::iterator S = Model->Sources.begin(); S != Model->Sources.end(); S++ )
-			(*S)->dump();
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_connect_source]) == 0 ) {
-		CHECK_MODEL;
-		char *label_s, *parm_s, *source_s;
-		if ( !operand ||
-		     !(source_s = strtok( operand, " \t")) ||
-		     !(label_s = strtok( nullptr, " \t")) ||
-		     !(parm_s = strtok( nullptr, "\n")) ) {
-			report_script_issue( fname, lineno, -1, "Missing source id, unit label and/or parameter in `connect_source'");
-			return CN_INTERP_PARSEERROR;
-		}
-		C_BaseSource *source = Model->source_by_id( source_s);
-		if ( !source ) {
-			report_script_issue( fname, lineno, -1, "Unknown source \"%s\"", source_s);
-			return CN_INTERP_PARSEERROR;
-		}
-
-		list<CModel::STagGroupSource> tags;
-		tags.push_back( CModel::STagGroupSource (label_s, true, parm_s, source));
-		Model->process_paramset_source_tags( tags);
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_disconnect_source]) == 0 ) {
-		CHECK_MODEL;
-		char *label_s, *parm_s, *source_s;
-		if ( !operand ||
-		     !(label_s = (strtok( operand, " \t"))) ||
-		     !(parm_s = strtok( nullptr, " \t")) ||
-		     !(source_s = strtok( nullptr, "\n")) ) {
-			report_script_issue( fname, lineno, -1, "Missing label, parameter or source in `disconnect_source'");
-			return CN_INTERP_PARSEERROR;
-		}
-		C_BaseSource *source = Model->source_by_id( source_s);
-		if ( !source ) {
-			report_script_issue( fname, lineno, -1, "Unknown source \"%s\"", source_s);
-			return CN_INTERP_PARSEERROR;
-		}
-
-		list<CModel::STagGroupSource> specs;
-		specs.push_back( CModel::STagGroupSource (label_s, false, parm_s, source));
-		Model->process_paramset_source_tags( specs);
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_cull_deaf_synapses]) == 0 ) {
-	 	CHECK_MODEL;
-	 	Model->cull_deaf_synapses();
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_describe_model]) == 0 ) {
-		CHECK_MODEL;
-		Model->dump_metrics();
-		Model->dump_units();
-		Model->dump_state();
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_show_units]) == 0 ) {
-		CHECK_MODEL;
-		if ( !operand )
-			operand = const_cast<char*>(".*");
-
-		regex_t RE;
-		if ( 0 != regcomp( &RE, operand, REG_EXTENDED | REG_NOSUB) ) {
-			report_script_issue( fname, lineno, -1, "Invalid regexp for `show_units' arg");
-			return CN_INTERP_PARSEERROR;
-		}
-		size_t cnt = 0;
-		for_model_units (Model,U)
-			if ( regexec( &RE, (*U)->label(), 0, 0, 0) == 0 ) {
-				(*U) -> dump( true);
-				cnt++;
-			}
-		if ( cnt )
-			lprintf( 0, "------------\n%zd units total\n", cnt);
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_exec]) == 0 ) {
-		return interpreter_run( operand, level+1, Options.interp_howstrict,
-					true, true, varlist);
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_verbosity]) == 0 ) {
-		if ( !operand )
-			lprintf( 0, "verbosity level is %d", Options.verbosely);
-		else if ( sscanf( operand, "%d", &Options.verbosely) < 1 ) {
-			report_script_issue( fname, lineno, -1, "Bad value for `verbosity'");
-			return CN_INTERP_PARSEERROR;
-		}
-		if ( Model )
-			Model->verbosely = Options.verbosely;
-		__cn_verbosely = Options.verbosely;
-
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_exit]) == 0 ) {
-		delete Model;
-		Model = nullptr;
-		return CN_INTERP_EXIT;
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_show_vars]) == 0 ) {
-		if ( !operand )
-			operand = const_cast<char*>(".*");
-		regex_t RE;
-		if ( 0 != regcomp( &RE, operand, REG_EXTENDED | REG_NOSUB) ) {
-			report_script_issue( fname, lineno, -1, "Invalid regexp for `show_vars' arg");
-			return CN_INTERP_PARSEERROR;
-		}
-		size_t	cnt = 0;
-		size_t	longest_id = 0;
-		for ( auto& V : varlist )
-			if ( regexec( &RE, V.name, 0, 0, 0) == 0 )
-				if ( longest_id < strlen( V.name) )
-					longest_id = strlen( V.name);
-		for ( auto& V : varlist )
-			if ( regexec( &RE, V.name, 0, 0, 0) == 0 ) {
-				lprintf( 0, "  %*s = %g", (int)longest_id, V.name, V.value);
-				++cnt;
-			}
-		if ( cnt > 1 )
-			lprintf( 0, "---------- %zu variables\n", cnt);
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_clear_vars]) == 0 ) {
-		if ( !operand )
-			varlist.clear();
-		else {
-			regex_t RE;
-			if ( 0 != regcomp( &RE, operand, REG_EXTENDED | REG_NOSUB) ) {
-				report_script_issue( fname, lineno, -1, "Invalid regexp for `clear_vars' arg");
-				return CN_INTERP_PARSEERROR;
-			}
-			for ( list<SVariable>::iterator V = varlist.begin(); V != varlist.end(); V++ )
-				if ( regexec( &RE, V->name, 0, 0, 0) == 0 ) {
-					varlist.erase( V);
-					break;
-				}
-		}
-
-		regenerate_var_names = true;
-
-
-	} else if ( strcmp( cmd, cnrun_cmd[CNCMD_pause]) == 0 ) {
-		if ( operand ) {
-			double s;
-			if ( expr( operand, s, &varlist) )
-				return CN_INTERP_PARSEERROR;
-			if ( s < 0 ) {
-				lprintf( 0, "Can't sleep backwards in time");
-				return CN_INTERP_WARN;
-			}
-			printf( "(Paused for %u sec)", (unsigned int)s); fflush(stdin);
-			sleep( rintf( s));
-			printf( "\n");
-		} else {
-			printf( "Paused: press Enter ...");
-			getchar();
-		}
-
-	} else {  // feed it to exprparser
-		if ( expr( raw, result, &varlist) ) {
-			report_script_issue( fname, lineno, -1, "%s", expr.status_s());
-			return CN_INTERP_PARSEERROR;
-		}
-		if ( expr.toplevel_op != '=' )
-			lprintf( 0, "%g", result);
-
-		regenerate_var_names = true;
-	}
-
-	return 0;
+        if ( !Model ) {                                                        \
+                report_script_issue( fname, lineno, -1, "No model loaded");                \
+                return CN_INTERP_WARN;                                        \
+        }
+
+
+        if ( strcmp( cmd, cnrun_cmd[CNCMD_new_model]) == 0 ) {
+                if ( !operand ) {
+                        report_script_issue( fname, lineno, -1, "Missing a name for the new model");
+                        return CN_INTERP_PARSEERROR;
+                }
+                delete Model;
+
+                regenerate_unit_labels = true;
+                return new_model( operand, fname, lineno);
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_load_nml]) == 0 ) {
+                struct stat s;
+                if ( stat( operand, &s) ) {
+                        report_script_issue( fname, lineno, -1, "No such file: \"%s\"", operand);
+                        return CN_INTERP_SYSFAIL;
+                }
+
+                int retval = new_model( operand, fname, lineno);
+                if ( retval )
+                        return retval;
+
+                if ( Model->import_NetworkML( operand, false) < 0 ) {
+                        report_script_issue( fname, lineno, -1, "Failed to create model topology from \"%s\"", operand);
+                        delete Model;
+                        Model = nullptr;
+                        return CN_INTERP_SYSFAIL;
+                }
+
+                Model -> cull_blind_synapses();
+                regenerate_unit_labels = true;
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_merge_nml]) == 0 ) {
+                CHECK_MODEL;
+                struct stat s;
+                if ( stat( operand, &s) ) {
+                        report_script_issue( fname, lineno, -1, "No such file: \"%s\"", operand);
+                        return CN_INTERP_SYSFAIL;
+                }
+                if ( Model->import_NetworkML( operand, true) < 0 ) {
+                        report_script_issue( fname, lineno, -1, "Failed to import topology from \"%s\"", operand);
+                        return CN_INTERP_SYSFAIL;
+                }
+
+                regenerate_unit_labels = true;
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_add_neuron]) == 0 ) {
+                CHECK_MODEL;
+                char *type_s, *label_s;
+                if ( !operand ||
+                     !(type_s = (strtok( operand, " \t"))) ||
+                     !(label_s = strtok( nullptr, "\n")) ) {
+                        report_script_issue( fname, lineno, -1, "Missing neuron type and/or label in `add_neuron'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                if ( !Model->add_neuron_species( type_s, label_s, true) ) {
+                        report_script_issue( fname, lineno, -1, "`add_neuron' failed");
+                        return CN_INTERP_PARSEERROR;
+                }
+                regenerate_unit_labels = true;
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_add_synapse]) == 0 ) {
+                CHECK_MODEL;
+                char *type_s, *src_s, *tgt_s, *g_s;
+                if ( !operand ||
+                     !(type_s = (strtok( operand, " \t"))) ||
+                     !(src_s = strtok( nullptr, " \t")) ||
+                     !(tgt_s = strtok( nullptr, " \t")) ||
+                     !(g_s = strtok( nullptr, "\n")) ) {
+                        report_script_issue( fname, lineno, -1, "Missing synapse type, source or target label, and/or gsyn in `add_synapse'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                double g;
+                if ( expr( g_s, g, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "Bad value for gsyn in `add_synapse'");
+                        return CN_INTERP_PARSEERROR;
+                }
+
+                if ( !Model->add_synapse_species( type_s, src_s, tgt_s, g, true, true) ) {
+                        report_script_issue( fname, lineno, -1, "`add_synapse' failed (reason given above)", operand);
+                        return CN_INTERP_SYSFAIL;
+                }
+                regenerate_unit_labels = true;
+
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_reset]) == 0 ) {
+                CHECK_MODEL;
+                Model->reset();
+                lprintf( 0, "Reset model and state of all units");
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_reset_revert_params]) == 0 ) {
+                CHECK_MODEL;
+                Model->reset( true);
+                lprintf( 0, "Reset model and reverted all units' state and parameters");
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_reset_state_units]) == 0 ) {
+                CHECK_MODEL;
+                if ( !operand )
+                        operand = const_cast<char*>(".*");
+                regex_t RE;
+                if ( 0 != regcomp( &RE, operand, REG_EXTENDED | REG_NOSUB) ) {
+                        report_script_issue( fname, lineno, -1, "Invalid regexp for `reset_state_units' arg");
+                        return CN_INTERP_PARSEERROR;
+                }
+                size_t cnt = 0;
+                for_model_units (Model,U)
+                        if ( regexec( &RE, (*U)->label(), 0, 0, 0) == 0 ) {
+                                (*U) -> reset_state();
+                                ++cnt;
+                        }
+                if ( cnt )
+                        lprintf( 0, "Reset %zd unit(s)", cnt);
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_advance_until]) == 0 ) {
+                CHECK_MODEL;
+                expr.silent = true;
+                if ( !operand || expr( operand, result, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "No or bad time value for `advance_until'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                if ( Model->model_time() > result ) {
+                        report_script_issue( fname, lineno, 0, "Cannot go back in time (now is %g)", Model->model_time());
+                        return CN_INTERP_WARN;
+                }
+
+                Model -> advance( result - Model->model_time());
+                for_model_spikelogging_neurons (Model,N)
+                        (*N)->sync_spikelogging_history();
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_advance]) == 0 ) {
+                CHECK_MODEL;
+                if ( !operand || expr( operand, result, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "No or bad time value for `advance'");
+                        return CN_INTERP_PARSEERROR;
+                }
+
+                Model -> advance( result);
+                for_model_spikelogging_neurons (Model,N)
+                        (*N)->sync_spikelogging_history();
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_putout]) == 0 ) {
+                CHECK_MODEL;
+                char *label_s;
+                if ( !operand ||
+                     !(label_s = (strtok( operand, " \t"))) ) {
+                        report_script_issue( fname, lineno, -1, "Missing label in `putout'");
+                        return CN_INTERP_PARSEERROR;
+                }
+
+                list<CModel::STagGroup> tags;
+                tags.push_back( CModel::STagGroup (label_s));
+                Model->process_putout_tags( tags);
+
+                regenerate_unit_labels = true;
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_decimate]) == 0 ) {
+                CHECK_MODEL;
+                char *label_s, *frac_s;
+                if ( !operand ||
+                     !(label_s = (strtok( operand, " \t"))) ||
+                     !(frac_s = (strtok( nullptr, "\n"))) ) {
+                        report_script_issue( fname, lineno, -1, "Missing fraction or label in `decimate'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                if ( expr( frac_s, result, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "Unparsable expression for decimation fraction: \"%s\"", operand);
+                        return CN_INTERP_PARSEERROR;
+                }
+                if ( result < 0. || result > 1. ) {
+                        report_script_issue( fname, lineno, -1, "Decimation fraction outside [0..1]");
+                        return CN_INTERP_PARSEERROR;
+                }
+
+                list<CModel::STagGroupDecimate> tags;
+                tags.push_back( CModel::STagGroupDecimate( label_s, result));
+                Model -> process_decimate_tags( tags);
+
+                regenerate_unit_labels = true;
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_start_listen]) == 0 ) {
+                CHECK_MODEL;
+                if ( !operand ||
+                     !(operand = (strtok( operand, " \t")) ) ) {
+                        report_script_issue( fname, lineno, -1, "Missing label in `start_listen'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                list<CModel::STagGroupListener> tags;
+                tags.push_back( CModel::STagGroupListener (operand, true, 0
+                                              | (Options.listen_1varonly ? CN_ULISTENING_1VARONLY : 0)
+                                              | (Options.listen_deferwrite ? CN_ULISTENING_DEFERWRITE : 0)
+                                              | (Options.listen_binary ? CN_ULISTENING_BINARY : CN_ULISTENING_DISK)));
+                Model->process_listener_tags( tags);
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_stop_listen]) == 0 ) {
+                CHECK_MODEL;
+                if ( !operand ||
+                     !(operand = (strtok( operand, " \t"))) ) {
+                        report_script_issue( fname, lineno, -1, "Missing label in `stop_listen'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                list<CModel::STagGroupListener> tags;
+                tags.push_back( CModel::STagGroupListener (operand, false));
+                Model->process_listener_tags( tags);
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_listen_dt]) == 0 ) {
+                if ( !operand ) {
+                        lprintf( 0, "listen_dt is %g", Options.listen_dt);
+                        return 0;
+                }
+                if ( expr( operand, result, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "Unparsable expression for value in `listen_dt'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                if ( Model )
+                        Model->listen_dt = Options.listen_dt = result;
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_listen_mode]) == 0 ) {
+                if ( !operand )
+                        lprintf( 0, "listen mode is 1%sd%sb%s (%s%s%s)",
+                                  Options.listen_1varonly ? "+" : "",
+                                  Options.listen_deferwrite ? "+" : "",
+                                  Options.listen_binary ? "+" : "",
+                                  Options.listen_1varonly ? "one var-only, " : "all vars, ",
+                                  Options.listen_deferwrite ? "deferred write, " : "continuous write, ",
+                                  Options.listen_binary ? "binary" : "ascii");
+                else {
+                        char *c;
+                        if ( (c = strchr( operand, '1')) ) Options.listen_1varonly   = (*(c+1) != '-');
+                        if ( (c = strchr( operand, 'd')) ) Options.listen_deferwrite = (*(c+1) != '-');
+                        if ( (c = strchr( operand, 'b')) ) Options.listen_binary     = (*(c+1) != '-');
+                }
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_integration_dt_min]) == 0 ) {
+                if ( !operand ) {
+                        lprintf( 0, "integration_dt_min is %g", Options.integration_dt_min);
+                        return 0;
+                }
+                if ( expr( operand, result, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "Unparsable expression for value in `integration_dt_min'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                Options.integration_dt_min = result;
+                if ( Model )
+                        Model->dt_min() = result;
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_integration_dt_max]) == 0 ) {
+                if ( !operand ) {
+                        lprintf( 0, "integration_dt_max is %g", Options.integration_dt_max);
+                        return 0;
+                }
+                if ( expr( operand, result, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "Unparsable expression for value in `integration_dt_max'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                Options.integration_dt_max = result;
+                if ( Model )
+                        Model->dt_max() = result;
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_integration_dt_cap]) == 0 ) {
+                if ( !operand ) {
+                        lprintf( 0, "integration_dt_cap is %g", Options.integration_dt_max_cap);
+                        return 0;
+                }
+                if ( expr( operand, result, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "Unparsable expression for value in `integration_dt_cap'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                Options.integration_dt_max_cap = result;
+                if ( Model )
+                        (static_cast<CIntegrateRK65*>(Model->_integrator)) -> _dt_max_cap = result;
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_set_sxf_params]) == 0 ) {
+                if ( !operand ) {
+                        lprintf( 0, "sxf_start_delay:sxf_period:sdf_sigma is %g:%g:%g",
+                                  Options.sxf_start_delay, Options.sxf_sample, Options.sdf_sigma);
+                        return 0;
+                }
+                if ( sscanf( operand, "%g:%g:%g",
+                             &Options.sxf_start_delay, &Options.sxf_sample, &Options.sdf_sigma) < 3 ) {
+                        report_script_issue( fname, lineno, -1, "Expecting <double>:<double>:<double> with set_sxf_params");
+                        return CN_INTERP_PARSEERROR;
+                }
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_start_log_spikes]) == 0 ) {
+                CHECK_MODEL;
+                char *label_s;
+                if ( !operand ||
+                     !(label_s = (strtok( operand, " \t"))) ) {
+                        report_script_issue( fname, lineno, -1, "Missing label in `start_log_spikes'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                if ( Options.sxf_sample <= 0. || Options.sdf_sigma <= 0. ) {
+                        report_script_issue( fname, lineno, 1, "SDF parameters not set up, will only log spike times");
+                }
+                list<CModel::STagGroupSpikelogger> specs;
+                specs.push_back( CModel::STagGroupSpikelogger (label_s, true,
+                                                               Options.sxf_sample, Options.sdf_sigma, Options.sxf_start_delay));
+                Model->process_spikelogger_tags( specs);
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_stop_log_spikes]) == 0 ) {
+                CHECK_MODEL;
+                char *label_s;
+                if ( !operand ||
+                     !(label_s = (strtok( operand, " \t"))) ) {
+                        report_script_issue( fname, lineno, -1, "Missing label in `stop_log_spikes'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                list<CModel::STagGroupSpikelogger> specs;
+                specs.push_back( CModel::STagGroupSpikelogger (label_s, false));
+                Model->process_spikelogger_tags( specs);
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_set_parm_neuron]) == 0 ) {
+                CHECK_MODEL;
+                char *label_s, *parm_s, *value_s;
+                if ( !operand ||
+                     !(label_s = (strtok( operand, " \t"))) ||
+                     !(parm_s = strtok( nullptr, " \t")) ||
+                     !(value_s = strtok( nullptr, "\n")) ) {
+                        report_script_issue( fname, lineno, -1, "Missing label, parameter or value in `set_parm_neuron'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                if ( expr( value_s, result, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "Unparsable expression for value in `set_parm_neuron'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                list<CModel::STagGroupNeuronParmSet> specs = { CModel::STagGroupNeuronParmSet (label_s, true, parm_s, result) };
+                Model->process_paramset_static_tags( specs);
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_set_parm_synapse]) == 0 ) {
+                CHECK_MODEL;
+                char *src_s, *tgt_s, *parm_s, *value_s;
+                if ( !operand ||
+                     !(src_s = (strtok( operand, " \t"))) ||
+                     !(tgt_s = (strtok( nullptr, " \t"))) ||
+                     !(parm_s = strtok( nullptr, " \t")) ||
+                     !(value_s = strtok( nullptr, "\n")) ) {
+                        report_script_issue( fname, lineno, -1, "Missing source or target label, parameter and/or value in `set_parm_synapse'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                if ( expr( value_s, result, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "Unparsable value in `set_parm_synapse'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                list<CModel::STagGroupSynapseParmSet> specs = { CModel::STagGroupSynapseParmSet (src_s, tgt_s, true, parm_s, result) };
+                Model->process_paramset_static_tags( specs);
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_new_source]) == 0 ) {
+                CHECK_MODEL;
+                char *type_s, *name_s;
+                if ( !operand ||
+                     !(type_s = (strtok( operand, " \t"))) ||
+                     !(name_s = (strtok( nullptr, " \t"))) ) {
+                        report_script_issue( fname, lineno, -1, "Missing source type or name in `new_source'");
+                        return CN_INTERP_PARSEERROR;
+                }
+
+                if ( Model->source_by_id( name_s) ) {
+                        report_script_issue( fname, lineno, -1, "A source named \"%s\" already exists", name_s);
+                        return CN_INTERP_PARSEERROR;
+                }
+
+                char *arg1, *arg2;
+                if ( strcmp( type_s, __SourceTypes[SRC_TAPE]) == 0 ) {
+                        if ( !(arg1 = strtok( nullptr, "\n")) ) {
+                                report_script_issue( fname, lineno, -1, "Missing filename for a Tape source in `new_source'");
+                                return CN_INTERP_PARSEERROR;
+                        } else {
+                                CSourceTape *source = new CSourceTape( name_s, arg1);
+                                if ( source && source->name.size() )
+                                        if ( count( Model->Sources.begin(), Model->Sources.end(), source) == 0 )
+                                                Model->Sources.push_back( source);
+                                        else {
+                                                report_script_issue( fname, lineno, -1, "Duplicate name (\"%s\") for a source", arg1);
+                                                return CN_INTERP_SYSFAIL;
+                                        }
+                                else {
+                                        delete source;
+                                        report_script_issue( fname, lineno, -1, "Failed to set up a Tape source from \"%s\"", arg1);
+                                        return CN_INTERP_SYSFAIL;
+                                }
+                        }
+                } else if ( strcmp( type_s, __SourceTypes[SRC_PERIODIC]) == 0 ) {
+                        if ( !(arg1 = strtok( nullptr, "\n")) ) {
+                                report_script_issue( fname, lineno, -1, "Missing filename for a Periodic source in `new_source'");
+                                return CN_INTERP_PARSEERROR;
+                        } else {
+                                CSourcePeriodic *source = new CSourcePeriodic( name_s, arg1);
+                                if ( source && source->name.size() )
+                                        if ( count( Model->Sources.begin(), Model->Sources.end(), source) == 0 )
+                                                Model->Sources.push_back( source);
+                                        else {
+                                                report_script_issue( fname, lineno, -1, "Duplicate name (\"%s\") for a source", arg1);
+                                                return CN_INTERP_SYSFAIL;
+                                        }
+                                else {
+                                        delete source;
+                                        report_script_issue( fname, lineno, -1, "Failed to set up a Periodic source from \"%s\"", arg1);
+                                        return CN_INTERP_SYSFAIL;
+                                }
+                        }
+                } else if ( strcmp( type_s, __SourceTypes[SRC_NOISE]) == 0 ) {
+                        if ( !(arg1 = strtok( nullptr, ":")) ||
+                             !(arg2 = strtok( nullptr, "\n")) ) {
+                                report_script_issue( fname, lineno, -1, "Incomplete min:max set for a Noise source in `new_source'");
+                                return CN_INTERP_PARSEERROR;
+                        } else {
+                                double _min, _max;
+                                if ( expr( arg1, _min, &varlist) ||
+                                     expr( arg2, _max, &varlist) ) {
+                                        report_script_issue( fname, lineno, -1, "Bad min:max values for a Noise source");
+                                        return CN_INTERP_PARSEERROR;
+                                }
+                                CSourceNoise *source = new CSourceNoise( name_s, _min, _max);
+                                if ( source && source->name.size() ) {
+                                        Model->Sources.push_back( source);
+                                } else {
+                                        delete source;
+                                        report_script_issue( fname, lineno, -1, "Failed to set up a Noise source");
+                                        return CN_INTERP_SYSFAIL;
+                                }
+                        }
+                } else if ( strcmp( type_s, __SourceTypes[SRC_FUNCTION]) == 0 ) {
+                        report_script_issue( fname, lineno, -1, "Go code, Chris!");
+                        return CN_INTERP_SYSFAIL;
+                } else {
+                        report_script_issue( fname, lineno, -1, "Unrecognised source type in `new_source'");
+                        return CN_INTERP_PARSEERROR;
+                }
+
+                regenerate_source_ids = true;
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_show_sources]) == 0 ) {
+                CHECK_MODEL;
+                for ( list<C_BaseSource*>::iterator S = Model->Sources.begin(); S != Model->Sources.end(); S++ )
+                        (*S)->dump();
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_connect_source]) == 0 ) {
+                CHECK_MODEL;
+                char *label_s, *parm_s, *source_s;
+                if ( !operand ||
+                     !(source_s = strtok( operand, " \t")) ||
+                     !(label_s = strtok( nullptr, " \t")) ||
+                     !(parm_s = strtok( nullptr, "\n")) ) {
+                        report_script_issue( fname, lineno, -1, "Missing source id, unit label and/or parameter in `connect_source'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                C_BaseSource *source = Model->source_by_id( source_s);
+                if ( !source ) {
+                        report_script_issue( fname, lineno, -1, "Unknown source \"%s\"", source_s);
+                        return CN_INTERP_PARSEERROR;
+                }
+
+                list<CModel::STagGroupSource> tags;
+                tags.push_back( CModel::STagGroupSource (label_s, true, parm_s, source));
+                Model->process_paramset_source_tags( tags);
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_disconnect_source]) == 0 ) {
+                CHECK_MODEL;
+                char *label_s, *parm_s, *source_s;
+                if ( !operand ||
+                     !(label_s = (strtok( operand, " \t"))) ||
+                     !(parm_s = strtok( nullptr, " \t")) ||
+                     !(source_s = strtok( nullptr, "\n")) ) {
+                        report_script_issue( fname, lineno, -1, "Missing label, parameter or source in `disconnect_source'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                C_BaseSource *source = Model->source_by_id( source_s);
+                if ( !source ) {
+                        report_script_issue( fname, lineno, -1, "Unknown source \"%s\"", source_s);
+                        return CN_INTERP_PARSEERROR;
+                }
+
+                list<CModel::STagGroupSource> specs;
+                specs.push_back( CModel::STagGroupSource (label_s, false, parm_s, source));
+                Model->process_paramset_source_tags( specs);
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_cull_deaf_synapses]) == 0 ) {
+                 CHECK_MODEL;
+                 Model->cull_deaf_synapses();
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_describe_model]) == 0 ) {
+                CHECK_MODEL;
+                Model->dump_metrics();
+                Model->dump_units();
+                Model->dump_state();
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_show_units]) == 0 ) {
+                CHECK_MODEL;
+                if ( !operand )
+                        operand = const_cast<char*>(".*");
+
+                regex_t RE;
+                if ( 0 != regcomp( &RE, operand, REG_EXTENDED | REG_NOSUB) ) {
+                        report_script_issue( fname, lineno, -1, "Invalid regexp for `show_units' arg");
+                        return CN_INTERP_PARSEERROR;
+                }
+                size_t cnt = 0;
+                for_model_units (Model,U)
+                        if ( regexec( &RE, (*U)->label(), 0, 0, 0) == 0 ) {
+                                (*U) -> dump( true);
+                                cnt++;
+                        }
+                if ( cnt )
+                        lprintf( 0, "------------\n%zd units total\n", cnt);
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_exec]) == 0 ) {
+                return interpreter_run( operand, level+1, Options.interp_howstrict,
+                                        true, true, varlist);
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_verbosity]) == 0 ) {
+                if ( !operand )
+                        lprintf( 0, "verbosity level is %d", Options.verbosely);
+                else if ( sscanf( operand, "%d", &Options.verbosely) < 1 ) {
+                        report_script_issue( fname, lineno, -1, "Bad value for `verbosity'");
+                        return CN_INTERP_PARSEERROR;
+                }
+                if ( Model )
+                        Model->verbosely = Options.verbosely;
+                __cn_verbosely = Options.verbosely;
+
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_exit]) == 0 ) {
+                delete Model;
+                Model = nullptr;
+                return CN_INTERP_EXIT;
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_show_vars]) == 0 ) {
+                if ( !operand )
+                        operand = const_cast<char*>(".*");
+                regex_t RE;
+                if ( 0 != regcomp( &RE, operand, REG_EXTENDED | REG_NOSUB) ) {
+                        report_script_issue( fname, lineno, -1, "Invalid regexp for `show_vars' arg");
+                        return CN_INTERP_PARSEERROR;
+                }
+                size_t        cnt = 0;
+                size_t        longest_id = 0;
+                for ( auto& V : varlist )
+                        if ( regexec( &RE, V.name, 0, 0, 0) == 0 )
+                                if ( longest_id < strlen( V.name) )
+                                        longest_id = strlen( V.name);
+                for ( auto& V : varlist )
+                        if ( regexec( &RE, V.name, 0, 0, 0) == 0 ) {
+                                lprintf( 0, "  %*s = %g", (int)longest_id, V.name, V.value);
+                                ++cnt;
+                        }
+                if ( cnt > 1 )
+                        lprintf( 0, "---------- %zu variables\n", cnt);
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_clear_vars]) == 0 ) {
+                if ( !operand )
+                        varlist.clear();
+                else {
+                        regex_t RE;
+                        if ( 0 != regcomp( &RE, operand, REG_EXTENDED | REG_NOSUB) ) {
+                                report_script_issue( fname, lineno, -1, "Invalid regexp for `clear_vars' arg");
+                                return CN_INTERP_PARSEERROR;
+                        }
+                        for ( list<SVariable>::iterator V = varlist.begin(); V != varlist.end(); V++ )
+                                if ( regexec( &RE, V->name, 0, 0, 0) == 0 ) {
+                                        varlist.erase( V);
+                                        break;
+                                }
+                }
+
+                regenerate_var_names = true;
+
+
+        } else if ( strcmp( cmd, cnrun_cmd[CNCMD_pause]) == 0 ) {
+                if ( operand ) {
+                        double s;
+                        if ( expr( operand, s, &varlist) )
+                                return CN_INTERP_PARSEERROR;
+                        if ( s < 0 ) {
+                                lprintf( 0, "Can't sleep backwards in time");
+                                return CN_INTERP_WARN;
+                        }
+                        printf( "(Paused for %u sec)", (unsigned int)s); fflush(stdin);
+                        sleep( rintf( s));
+                        printf( "\n");
+                } else {
+                        printf( "Paused: press Enter ...");
+                        getchar();
+                }
+
+        } else {  // feed it to exprparser
+                if ( expr( raw, result, &varlist) ) {
+                        report_script_issue( fname, lineno, -1, "%s", expr.status_s());
+                        return CN_INTERP_PARSEERROR;
+                }
+                if ( expr.toplevel_op != '=' )
+                        lprintf( 0, "%g", result);
+
+                regenerate_var_names = true;
+        }
+
+        return 0;
 }
 
 
@@ -804,120 +804,127 @@ do_single_cmd( const char* raw,
 
 
 int
-cnrun::
-interpreter_run( const char *script_fname, int level, int howstrict,
-		 bool env_import, bool env_export, list<SVariable> &varlist)
+cnrun::CInterpreter::
+run( const string& script_fname, int level, int howstrict,
+     TEnvImportOption env_import_option, TEnvExportOption env_export_option,
+     list<SVariable> &varlist)
 {
-	int retval = 0;
-
-	list<SVariable> our_variables;
-	current_shell_variables = &our_variables;
-
-	if ( env_import ) {
-		our_variables.splice( our_variables.begin(), varlist);
-//		printf( "imported %zu vars\n", our_variables.size());
-	}
-
-	if ( script_fname && strlen(script_fname) > 0 ) {
-		ifstream script_stream( script_fname);
-		if ( !script_stream.good() ) {
-			lprintf( -1, "Failed to open script file \"%s\"", script_fname);
-			return -1;
-		}
-		lprintf( 1, "execing %s\n", script_fname);
-
-		unsigned lineno = 0;
-		string buf;
-		while ( getline( script_stream, buf) || script_stream.gcount() ) {
-			lineno++;
-			if ( buf.size() ) {
-
-				char	*pp = strchr( (char*)buf.c_str(), '#');
-				if ( pp )
-					buf.resize( pp - buf.c_str());
-				size_t	buflen = buf.size();
-				while ( strlen(buf.c_str()) && isspace(buf[buflen-1]) )
-					buf[--buflen] = '\0';
-
-				char	*_stmt = &buf[0],
-					*stmt;
-				while ( _stmt - &buf[0] < (int)buflen && (stmt = strtok( _stmt, ";\n")) ) {
-					_stmt = _stmt + strlen(_stmt)+1;
-
-					retval = do_single_cmd( stmt, our_variables, level, script_fname, lineno);
-					if ( retval == CN_INTERP_EXIT ||
-					     (retval < CN_INTERP_WARN && howstrict == CN_INTRP_STRICT) )
-						break;
-				}
-			}
-		}
-	} else {
-		if ( level == 0 ) {
-			using_history();
-			read_history( CNRUN_HISTORY);
-			rl_attempted_completion_function = cnrun_completion;
-			rl_bind_key( '\t', rl_complete);
-		}
-		HISTORY_STATE *the_history_state = history_get_history_state();
-		if ( the_history_state && the_history_state->length == 0 )
-			printf( "Hit TAB for context completions\n");
-
-		char *buf, prompt[256];
-		while ( snprintf( prompt, 255, "%s @%g%.*s ",
-				  Model ? Model->name.c_str() : "-",
-				  Model ? Model->model_time() : 0,
-				  level+1, "]]]]]]]"),
-			(buf = readline( prompt)) ) {
-
-			the_history_state = history_get_history_state();
-			if ( the_history_state &&
-			     (the_history_state->length < 2 ||
-			      (the_history_state->length > 1 &&
-			       *buf &&
-			       strcmp( history_get( the_history_state->length)->line, buf) != 0) ) ) {
-				add_history( buf);
-			}
-
-			char	*pp = strchr( buf, '#');
-			if ( pp )
-				*pp = '\0';
-			size_t	buflen = strlen( buf);
-			while ( buflen && strchr( " \t", buf[buflen-1]) )
-				buf[--buflen] = '\0';
-			if ( !buflen )
-				continue;
-
-			char	*_stmt = buf,  // will hold the pointer to the next statement
-				*stmt;
-			while ( _stmt - buf < (int)buflen  &&  (stmt = strtok( _stmt, ";\n")) ) {
-				_stmt += (strlen(_stmt) + 1);
-
-				retval = do_single_cmd( stmt, our_variables, level, nullptr, -1);
-				if ( retval == CN_INTERP_EXIT ) {
-					free( buf);
-					goto out;
-				}
-			}
-			free( buf);
-			if ( level == 0 ) {
-//				rl_attempted_completion_function = cnrun_completion;
-				rl_bind_key( '\t', rl_complete);
-			}
-		}
-	out:
-		if ( level == 0 )
-			write_history( CNRUN_HISTORY);
-		printf( "\n");
-	}
-
-	if ( env_export ) {
-	      // update varlist
-		varlist.merge( our_variables);
-		varlist.sort();
-		varlist.unique();
-	}
-	current_shell_variables = &varlist;
-
-	return retval;
+        int retval = 0;
+
+        list<SVariable> our_variables;
+        current_shell_variables = &our_variables;
+
+        if ( env_import ) {
+                our_variables.splice( our_variables.begin(), varlist);
+//                printf( "imported %zu vars\n", our_variables.size());
+        }
+
+        if ( script_fname && strlen(script_fname) > 0 ) {
+                ifstream script_stream( script_fname);
+                if ( !script_stream.good() ) {
+                        lprintf( -1, "Failed to open script file \"%s\"", script_fname);
+                        return -1;
+                }
+                lprintf( 1, "execing %s\n", script_fname);
+
+                size_t lineno = 0;
+                string buf;
+                while ( getline( script_stream, buf) || script_stream.gcount() ) {
+                        lineno++;
+                        if ( buf.size() ) {
+
+                                char    *pp = strchr( (char*)buf.c_str(), '#');
+                                if ( pp )
+                                        buf.resize( pp - buf.c_str());
+                                size_t  buflen = buf.size();
+                                while ( strlen(buf.c_str()) && isspace(buf[buflen-1]) )
+                                        buf[--buflen] = '\0';
+
+                                char    *_stmt = &buf[0],
+                                        *stmt;
+                                while ( _stmt - &buf[0] < (int)buflen && (stmt = strtok( _stmt, ";\n")) ) {
+                                        _stmt = _stmt + strlen(_stmt)+1;
+
+                                        retval = do_single_cmd( stmt, our_variables, level, script_fname, lineno);
+                                        if ( retval == CN_INTERP_EXIT ||
+                                             (retval < CN_INTERP_WARN && howstrict == CN_INTRP_STRICT) )
+                                                break;
+                                }
+                        }
+                }
+        } else {
+                if ( level == 0 ) {
+                        using_history();
+                        read_history( CNRUN_HISTORY);
+                        rl_attempted_completion_function = cnrun_completion;
+                        rl_bind_key( '\t', rl_complete);
+                }
+                HISTORY_STATE *the_history_state = history_get_history_state();
+                if ( the_history_state && the_history_state->length == 0 )
+                        printf( "Hit TAB for context completions\n");
+
+                char *buf, prompt[256];
+                while ( snprintf( prompt, 255, "%s @%g%.*s ",
+                                  Model ? Model->name.c_str() : "-",
+                                  Model ? Model->model_time() : 0,
+                                  level+1, "]]]]]]]"),
+                        (buf = readline( prompt)) ) {
+
+                        the_history_state = history_get_history_state();
+                        if ( the_history_state &&
+                             (the_history_state->length < 2 ||
+                              (the_history_state->length > 1 &&
+                               *buf &&
+                               strcmp( history_get( the_history_state->length)->line, buf) != 0) ) ) {
+                                add_history( buf);
+                        }
+
+                        char        *pp = strchr( buf, '#');
+                        if ( pp )
+                                *pp = '\0';
+                        size_t        buflen = strlen( buf);
+                        while ( buflen && strchr( " \t", buf[buflen-1]) )
+                                buf[--buflen] = '\0';
+                        if ( !buflen )
+                                continue;
+
+                        char        *_stmt = buf,  // will hold the pointer to the next statement
+                                *stmt;
+                        while ( _stmt - buf < (int)buflen  &&  (stmt = strtok( _stmt, ";\n")) ) {
+                                _stmt += (strlen(_stmt) + 1);
+
+                                retval = do_single_cmd( stmt, our_variables, level, nullptr, -1);
+                                if ( retval == CN_INTERP_EXIT ) {
+                                        free( buf);
+                                        goto out;
+                                }
+                        }
+                        free( buf);
+                        if ( level == 0 ) {
+//                                rl_attempted_completion_function = cnrun_completion;
+                                rl_bind_key( '\t', rl_complete);
+                        }
+                }
+        out:
+                if ( level == 0 )
+                        write_history( CNRUN_HISTORY);
+                printf( "\n");
+        }
+
+        if ( env_export ) {
+              // update varlist
+                varlist.merge( our_variables);
+                varlist.sort();
+                varlist.unique();
+        }
+        current_shell_variables = &varlist;
+
+        return retval;
 }
 
+// Local Variables:
+// Mode: c++
+// indent-tabs-mode: nil
+// tab-width: 8
+// c-basic-offset: 8
+// End:
diff --git a/upstream/src/cnrun/main.cc b/upstream/src/cnrun/main.cc
index 52486dd..79218b2 100644
--- a/upstream/src/cnrun/main.cc
+++ b/upstream/src/cnrun/main.cc
@@ -234,20 +234,6 @@ parse_opt( int key, const char *arg, struct argp_state *state)
 }
 
 
-void
-cnrun::
-lprintf( int level, int verbosely, const char* fmt, ...)
-{
-        if ( level > verbosely ) {
-                va_list ap;
-                va_start (ap, fmt);
-                vprintf( fmt, ap);
-                va_end (ap);
-        }
-}
-
-
-
 
 
 // #include "print-version.hh"
diff --git a/upstream/src/cnrun/runner.hh b/upstream/src/cnrun/runner.hh
index c9f7419..3b11e72 100644
--- a/upstream/src/cnrun/runner.hh
+++ b/upstream/src/cnrun/runner.hh
@@ -18,7 +18,6 @@
 #include "libstilton/exprparser.hh"
 
 #include "libcn/model.hh"
-#include "libcn/sources.hh"
 
 #if HAVE_CONFIG_H && !defined(VERSION)
 #  include "config.h"
@@ -26,7 +25,7 @@
 
 namespace cnrun {
 
-struct SInitOptions
+struct SInterpOptions
   : public cnrun::SModelOptions {
         bool    dump_params:1,
                 list_units:1;
@@ -35,35 +34,46 @@ struct SInitOptions
         list<string>
                 scripts;
 
-        SInitOptions ()
-              : dump_params(false), list_units (false)
+        SInterpOptions ()
+              : dump_params (false),
+                list_units (false),
                 working_dir (".")
                 {}
 };
 
 
-enum class TInterpStrictness {
-        strict,
-        loose
-};
-
-class CInterpreter : public SOptions {
-        CModel* model;
+class CInterpreter {
 
     public:
-        CState ()
-              : CModel (nullptr)
+        enum class TStrictness { strict, loose };
+        CInterpreter ()
+              : model (nullptr)
                 {}
-       ~CState ()
+       ~CInterpreter ()
                 {
                         if ( model )
                                 delete model;
                 }
 
+        SInterpOptions
+                options;
+
+        enum class TEnvImportOption { yes, no };
+        enum class TEnvExportOption { yes, no };
+        int run( const string& script_fname, const SInterpOptions&,
+                 TEnvImportOption, TEnvExportOption);
+        int new_model( const string& model_name, const string& fname, size_t lineno);
+
     private:
+        cnrun::CModel
+               *model;
+
         bool    regenerate_unit_labels,
                 regenerate_var_names,
                 regenerate_source_ids;
+
+        static list<cnrun::stilton::SVariable>
+               *current_env;
 };
 
 
@@ -71,9 +81,6 @@ class CInterpreter : public SOptions {
 
 extern const char* const cnrun_cmd[];
 
-int interpreter_run( const char *script_fname, const SOptions&,
-                     bool env_import, bool env_export);
-
 
 enum class TInterpCommand {
         noop,
@@ -120,13 +127,6 @@ enum class TInterpCommand {
 
 char** cnrun_completion( const char *text, int start, int end);
 
-
-extern list<cnrun::SVariable> *current_shell_variables;
-
-
-void lprintf( int level, const char* fmt, ...) __attribute__ ((format (printf, 2, 3)));
-
-
 }  // namespace cnrun
 
 #endif
diff --git a/upstream/src/libcn/base-unit.cc b/upstream/src/libcn/base-unit.cc
index 4929cf5..5922abd 100644
--- a/upstream/src/libcn/base-unit.cc
+++ b/upstream/src/libcn/base-unit.cc
@@ -58,8 +58,8 @@ void
 cnrun::C_BaseUnit::
 reset_state()
 {
-        if ( M && M->options.verbosely > 3 )
-                fprintf( stderr, "Resetting \"%s\"\n", _label);
+        if ( M )
+                M->vp( 3, stderr, "Resetting \"%s\"\n", _label);
         reset_vars();
         if ( is_listening() )
                 restart_listening();
@@ -106,8 +106,7 @@ start_listening( int mask)
                      != mask ) {
                         stop_listening();  // this will nullptrify _listener_{mem,disk}, avoiding recursion
                         start_listening( mask);
-                        if ( M->options.verbosely > 4 )
-                                fprintf( stderr, "Unit \"%s\" was already listening\n", _label);
+                        M->vp( 4, stderr, "Unit \"%s\" was already listening\n", _label);
                         return;
                 }
         }
@@ -133,8 +132,7 @@ start_listening( int mask)
                                 for ( size_t v = 0; v < v_no(); ++v )
                                         *_listener_disk << "\t<" << var_sym(v) << ">";
                         *_listener_disk << endl;
-                        if ( M->options.verbosely > 4 )
-                                fprintf( stderr, "Unit \"%s\" now listening\n", _label);
+                        M->vp( 4, stderr, "Unit \"%s\" now listening\n", _label);
                 }
         }
 
@@ -190,10 +188,10 @@ stop_listening()
 
         _status &= ~(CN_ULISTENING_MEM | CN_ULISTENING_DISK | CN_ULISTENING_BINARY);
 
-        if ( M )
+        if ( M ) {
                 M->unregister_listener( this);
-        if ( M->options.verbosely > 4 )
-                fprintf( stderr, "Unit \"%s\" not listening now\n", _label);
+                M->vp( 4, stderr, "Unit \"%s\" not listening now\n", _label);
+        }
 
 }
 
@@ -314,8 +312,8 @@ apprise_from_sources()
 cnrun::C_BaseUnit::
 ~C_BaseUnit()
 {
-        if ( M && M->options.verbosely > 5 )
-                fprintf( stderr, "   deleting base unit \"%s\"\n", _label);
+        if ( M )
+                M->vp( 5, stderr, "   deleting base unit \"%s\"\n", _label);
 
         if ( is_listening() ) {
                 stop_listening();
@@ -377,8 +375,8 @@ dump( bool with_params, FILE *strm) const
 cnrun::C_BaseNeuron::
 ~C_BaseNeuron()
 {
-        if ( M && M->options.verbosely > 4 )
-                fprintf( stderr, "  deleting base neuron \"%s\"\n", _label);
+        if ( M )
+                M->vp( 4, stderr, "  deleting base neuron \"%s\"\n", _label);
 
       // kill all efferents
         for ( auto Y = _axonal_harbour.rbegin(); Y != _axonal_harbour.rend(); ++Y ) {
@@ -546,8 +544,8 @@ C_BaseSynapse( TUnitType intype,
         _source (insource),
         t_last_release_started (-INFINITY)
 {
-        if ( M && M->options.verbosely > 5 )
-                printf( "Creating a \"%s\" base synapse\n", species());
+        if ( M )
+                M->vp( 5, "Creating a \"%s\" base synapse\n", species());
         _targets.push_back( intarget);
         intarget->_dendrites[this] = ing;
         _source->_axonal_harbour.push_back( this);
@@ -589,9 +587,9 @@ make_clone_independent( C_BaseNeuron *tgt)
         if ( !isfinite(g) || !M )
                 return nullptr;
 
-        if ( M && M->options.verbosely > 4 )
-                printf( "promoting a clone of %s synapse from \"%s\" to \"%s\"\n",
-                        species(), _label, tgt->_label);
+        if ( M )
+                M->vp( 4, "promoting a clone of %s synapse from \"%s\" to \"%s\"\n",
+                       species(), _label, tgt->_label);
         if ( member( tgt, _targets ) )
                 fprintf( stderr, "ебать!\n");
         _targets.remove( tgt);
@@ -640,8 +638,8 @@ dump( bool with_params, FILE *strm) const
 cnrun::C_BaseSynapse::
 ~C_BaseSynapse()
 {
-        if ( M && M->options.verbosely > 4 )
-                fprintf( stderr, "  deleting base synapse \"%s\"\n", _label);
+        if ( M )
+                M->vp( 4, "  deleting base synapse \"%s\"\n", _label);
 
         for ( auto &T : _targets )
                 if ( T )
@@ -649,9 +647,9 @@ cnrun::C_BaseSynapse::
 
         if ( _source ) {
                 _source->_axonal_harbour.remove( this);
-                if ( M && M->options.verbosely > 5 )
-                        printf( "    removing ourselves from \"%s\" axonals (%zu still there)\n",
-                                _source->_label, _source->_axonal_harbour.size());
+                if ( M )
+                        M->vp( 5, "    removing ourselves from \"%s\" axonals (%zu still there)\n",
+                               _source->_label, _source->_axonal_harbour.size());
         }
 }
 
diff --git a/upstream/src/libcn/hosted-neurons.cc b/upstream/src/libcn/hosted-neurons.cc
index 5a9c6eb..d26ab35 100644
--- a/upstream/src/libcn/hosted-neurons.cc
+++ b/upstream/src/libcn/hosted-neurons.cc
@@ -39,14 +39,6 @@ C_HostedNeuron (TUnitType intype, const string& inlabel,
 }
 
 
-// C_HostedNeuron::~C_HostedNeuron()
-// {
-//         if ( __cn_verbosely > 5 )
-//                 cout << " deleting hosted neuron " << label << endl;
-// }
-
-
-
 
 
 
diff --git a/upstream/src/libcn/hosted-synapses.cc b/upstream/src/libcn/hosted-synapses.cc
index 7d340e1..121ec6b 100644
--- a/upstream/src/libcn/hosted-synapses.cc
+++ b/upstream/src/libcn/hosted-synapses.cc
@@ -41,16 +41,6 @@ C_HostedSynapse( TUnitType intype,
 
 
 
-cnrun::C_HostedSynapse::
-~C_HostedSynapse()
-{
-        if ( cn_verbosely > 5 )
-                fprintf( stderr, " deleting hosted synapse \"%s\"\n", _label);
-}
-
-
-
-
 
 
 // -- parameters
@@ -284,11 +274,11 @@ derivative( vector<double>& x, vector<double>& dx)
                 while ( effective_q  &&  M->model_time(x) - _kq[q()-effective_q] > P[_rtime_] )
                         --effective_q;
 #ifdef __CN_MORECODE__
-                if ( effective_q < q() && M->verbosely > 6 )
-                        printf( "YMxAB %s smacks %zu spike(s) of %zu at %g(+%g)\n", label,
-                                (size_t)q() - effective_q, (size_t)q(),
-                                M->model_time(),
-                                M->model_time(x) - M->model_time());
+                if ( effective_q < q() )
+                        M->vp( 6, "YMxAB %s smacks %zu spike(s) of %zu at %g(+%g)\n", label,
+                               (size_t)q() - effective_q, (size_t)q(),
+                               M->model_time(),
+                               M->model_time(x) - M->model_time());
 #endif
                 dS(dx) = P[_alpha_] * effective_q - P[_beta_] * S(x);
         } else
diff --git a/upstream/src/libcn/model-cycle.cc b/upstream/src/libcn/model-cycle.cc
index 741c322..dc76682 100644
--- a/upstream/src/libcn/model-cycle.cc
+++ b/upstream/src/libcn/model-cycle.cc
@@ -10,6 +10,7 @@
  */
 
 
+#include <csignal>
 #include <iostream>
 #include <ctime>
 #include <cstdlib>
@@ -69,15 +70,16 @@ void
 cnrun::CIntegrateRK65::
 prepare()
 {
-        for ( unsigned short i = 0; i < 9; ++i )
-                Y[i].resize( model->_var_cnt), F[i].resize( model->_var_cnt);
+        for ( unsigned short i = 0; i < 9; ++i ) {
+                Y[i].resize( model->_var_cnt);
+                F[i].resize( model->_var_cnt);
+        }
         y5.resize( model->_var_cnt);
 
         if ( model->n_standalone_units() > 0 )
                 if ( _dt_max > model->_discrete_dt ) {
                         _dt_max = model->_discrete_dt;
-                        if ( model->options.verbosely > 1 )
-                                cout << "CIntegrateRK65: Set dt_max to model->discrete_dt: " << _dt_max << endl;
+                        model->vp( 1, "CIntegrateRK65: Set dt_max to model->discrete_dt: %g\n", _dt_max);
                 }
 }
 
@@ -91,7 +93,7 @@ cycle()
       // (thread creation)
         unsigned int i, j, k;
 
-        double        aF;
+        double  aF;
 
       // calculate iterative terms rk65_Y[__i] and rk65_F[__i] (to sixth order)
         for ( i = 0; i < 9; ++i ) {
@@ -222,13 +224,10 @@ _setup_schedulers()
                 regular_periods_last_checked.resize( regular_periods.size());
         }
 
-        if ( options.verbosely > 2 && regular_periods.size() > 0 ) {
-                printf( "%zd timepoint(s) in scheduler_update_periods: ", regular_periods.size());
-                auto I = regular_periods.begin();
-                for ( size_t i = 0; i < regular_periods.size()-1; ++i, ++I )
-                        printf( "%g, ", *I);
-                printf( "%g\n\n", regular_periods.back());
-        }
+        if ( regular_periods.size() > 0 )
+                vp( 2, "%zd timepoint(s) in scheduler_update_periods: %s\n\n",
+                    regular_periods.size(),
+                    stilton::str::join( regular_periods).c_str());
 
       // ensure all schedulers are effective at the beginning, too
         for ( auto& U : units_with_periodic_sources )
@@ -252,8 +251,7 @@ prepare_advance()
 
         is_ready = true;
 
-        if ( options.verbosely > 5 )
-                fprintf( stderr, "Model prepared\n");
+        vp( 5, stderr, "Model prepared\n");
 }
 
 
@@ -345,11 +343,10 @@ prepare_advance()
                 fprintf( stderr, "\r\033[K");                                \
                 fflush( stderr);                                        \
         }                                                                \
-        if ( options.verbosely > 0 )                                                \
-                printf( "@%.1fmsec (+%.1f in %lu cycles in %.2f sec CPU time:" \
-                        " avg %.3g \302\265s/cyc, ratio to CPU time %.2g)\n\n", \
-                        model_time(), dist, steps, cpu_time_taken_seconds, \
-                        model_time()/_cycle * 1e3, model_time() / cpu_time_taken_seconds / 1e3);
+        vp( 0, "@%.1fmsec (+%.1f in %lu cycles in %.2f sec CPU time:"   \
+            " avg %.3g \302\265s/cyc, ratio to CPU time %.2g)\n\n",     \
+            model_time(), dist, steps, cpu_time_taken_seconds,          \
+            model_time()/_cycle * 1e3, model_time() / cpu_time_taken_seconds / 1e3);
 
 
 
diff --git a/upstream/src/libcn/model-nmlio.cc b/upstream/src/libcn/model-nmlio.cc
index 7e2cc22..2868194 100644
--- a/upstream/src/libcn/model-nmlio.cc
+++ b/upstream/src/libcn/model-nmlio.cc
@@ -96,8 +96,7 @@ import_NetworkML( xmlDoc *doc, const string& fname,
         if ( import_option == TNMLImportOption::reset ) {
                 reset();
                 if ( !(n = find_named_root_child_elem( root_node, "notes")) ) {
-                        if ( options.verbosely > 1 )
-                                fprintf( stderr, "<notes> element not found; model will be unnamed\n");
+                        vp( 1, stderr, "<notes> element not found; model will be unnamed\n");
                         // this is not critical, so just keep the user
                         // informed and proceed
                 } else
@@ -115,10 +114,10 @@ import_NetworkML( xmlDoc *doc, const string& fname,
                                 name = "(unnamed)";
         }
 
-        if ( options.verbosely > 0 )
-                printf( "Model \"%s\": %s topology from %s\n",
-                        name.c_str(), (import_option == TNMLImportOption::merge) ?"Merging" :"Importing",
-                        fname.c_str());
+        vp( 0, "Model \"%s\": %s topology from %s\n",
+            name.c_str(),
+            (import_option == TNMLImportOption::merge) ?"Merging" :"Importing",
+            fname.c_str());
 
         // In the following calls to _process_{populations,instances}
         // functions, the actual order of appearance of these nodes in
@@ -203,17 +202,15 @@ _process_populations( xmlNode *n)
                                                 if ( subretval < 0 )
                                                         throw subretval;
 
-                                                if ( options.verbosely > 2 )
-                                                        printf( " %5d instance(s) of type \"%s\" in population \"%s\"\n",
-                                                                subretval, cell_type_s,  group_id_s);
-                                                        ++pop_cnt;
+                                                vp( 2, " %5d instance(s) of type \"%s\" in population \"%s\"\n",
+                                                    subretval, cell_type_s,  group_id_s);
+                                                ++pop_cnt;
                                         }
 
                         xmlFree( cell_type_s), xmlFree( group_id_s);
                 }
 
-                if ( options.verbosely > 1 )
-                        printf( "\tTotal %d population(s)\n", pop_cnt);
+                vp( 1, "\tTotal %d population(s)\n", pop_cnt);
 
         } catch (int ex) {
                 xmlFree( cell_type_s), xmlFree( group_id_s);
@@ -286,16 +283,14 @@ _process_projections( xmlNode *n)
                                         if ( subretval < 0 )
                                                 throw subretval;
 
-                                        if ( options.verbosely > 2 )
-                                                printf( " %5d connection(s) of type \"%s\" in projection \"%s\"\n",
-                                                        subretval, synapse_type_s,  prj_name_s);
+                                        vp( 2, " %5d connection(s) of type \"%s\" in projection \"%s\"\n",
+                                            subretval, synapse_type_s,  prj_name_s);
                                         ++pop_cnt;
                                 }
                         xmlFree( prj_name_s), xmlFree( prj_src_s), xmlFree( prj_tgt_s);
                 }
 
-                if ( options.verbosely > 1 )
-                        printf( "\tTotal %zd projection(s)\n", pop_cnt);
+                vp( 1, "\tTotal %zd projection(s)\n", pop_cnt);
 
         } catch (int ex) {
                 xmlFree( prj_name_s), xmlFree( prj_src_s), xmlFree( prj_tgt_s);
@@ -369,8 +364,7 @@ _process_population_instances(
                                         *z_s = xmlGetProp( nin, BAD_CAST "z");
                               // here we do actually insert neurons into the model
                                 if ( !(x_s && y_s && z_s) )
-                                        if ( options.verbosely > 1 )
-                                                fprintf( stderr, "<location> element missing full set of coordinates near line %d\n", nin->line);
+                                        vp( 1, stderr, "<location> element missing full set of coordinates near line %d\n", nin->line);
                                         // not an error
                                 x = strtod( (char*)x_s, nullptr), y = strtod( (char*)y_s, nullptr), z = strtod( (char*)z_s, nullptr);
                                 xmlFree( x_s), xmlFree( y_s), xmlFree( z_s);
@@ -443,9 +437,8 @@ _process_projection_connections(
                         snprintf( tgt_s, C_BaseUnit::max_label_size-1, "%s.%s", tgt_grp_prefix, tgt_cell_id_s);
 
                         if ( !weight_s ) {
-                                if ( options.verbosely > 1 )
-                                        fprintf( stderr, "Assuming 0 for a synapse of \"%s.%s\" to \"%s%s\" without a \"weight\" attribute near line %u\n",
-                                                 src_grp_prefix, src_cell_id_s, tgt_grp_prefix, tgt_cell_id_s, n->line);
+                                vp( 1, stderr, "Assuming 0 for a synapse of \"%s.%s\" to \"%s%s\" without a \"weight\" attribute near line %u\n",
+                                    src_grp_prefix, src_cell_id_s, tgt_grp_prefix, tgt_cell_id_s, n->line);
                                 weight = 0.;
                         }
                         /* xmlFree( synapse_id_s), */ xmlFree( src_cell_id_s), xmlFree( tgt_cell_id_s),
diff --git a/upstream/src/libcn/model-struct.cc b/upstream/src/libcn/model-struct.cc
index 1bffa66..14ee703 100644
--- a/upstream/src/libcn/model-struct.cc
+++ b/upstream/src/libcn/model-struct.cc
@@ -10,6 +10,7 @@
  */
 
 #include <sys/time.h>
+#include <csignal>
 #include <iostream>
 #include <set>
 #include <algorithm>
@@ -71,8 +72,7 @@ CModel( const string& inname, CIntegrate_base *inintegrator, const SModelOptions
 cnrun::CModel::
 ~CModel()
 {
-        if ( options.verbosely > 4 )
-                fprintf( stdout, "Deleting all units...\n");
+        vp( 4, "Deleting all units...\n");
 
         while (units.size())
                 if ( units.back() -> is_owned() )
@@ -179,8 +179,7 @@ _include_base_unit( C_BaseUnit* u)
         else
                 units.push_back( u);
 
-        if ( options.verbosely > 5 )
-                fprintf( stdout, "  registered base unit %s\n", u->_label);
+        vp( 5, "  registered base unit %s\n", u->_label);
 
         if ( u->has_sources() )
                 register_unit_with_sources( u);
@@ -297,8 +296,7 @@ cnrun::C_BaseUnit*
 cnrun::CModel::
 exclude_unit( C_BaseUnit *u, const TExcludeOption option)
 {
-        if ( options.verbosely > 5 )
-                fprintf( stderr, "-excluding unit \"%s\"", u->_label);
+        vp( 5, stderr, "-excluding unit \"%s\"", u->_label);
 
         if ( u->has_sources() )
                 unregister_unit_with_sources( u);
@@ -325,8 +323,7 @@ exclude_unit( C_BaseUnit *u, const TExcludeOption option)
                 }
 
               // shrink V
-                if ( options.verbosely > 5 )
-                        fprintf( stderr, " (shrink V by %d)", u->v_no());
+                vp( 5, stderr, " (shrink V by %d)", u->v_no());
                 for ( auto& N : hosted_neurons )
                         if ( N->idx > our_idx )
                                 N->idx -= u->v_no();
@@ -360,8 +357,7 @@ exclude_unit( C_BaseUnit *u, const TExcludeOption option)
         } else
                 u->M = nullptr;
 
-        if ( options.verbosely > 5 )
-                fprintf( stderr, ".\n");
+        vp( 5, stderr, ".\n");
         return u;
 }
 
@@ -646,9 +642,8 @@ add_synapse_species( TUnitType ytype,
                      double g,
                      TSynapseCloningOption cloning_option, TIncludeOption include_option)
 {
-        if ( options.verbosely > 5 )
-                printf( "add_synapse_species( \"%s\", \"%s\", \"%s\", %g, %d, %d)\n",
-                        __CNUDT[ytype].species, src->_label, tgt->_label, g, cloning_option, include_option);
+        vp( 5, "add_synapse_species( \"%s\", \"%s\", \"%s\", %g, %d, %d)\n",
+            __CNUDT[ytype].species, src->_label, tgt->_label, g, cloning_option, include_option);
 
         C_BaseSynapse *y = nullptr;
 
@@ -772,8 +767,7 @@ add_synapse_species( TUnitType ytype,
                 return nullptr;
         }
 
-        if ( options.verbosely > 5 )
-                printf( "new synapse \"%s->%s\"\n", y->_label, tgt->label());
+        vp( 5, "new synapse \"%s->%s\"\n", y->_label, tgt->label());
         y->set_g_on_target( *tgt, g);
 
         return y;
@@ -824,9 +818,8 @@ cull_deaf_synapses()
                 while ( Ti != Y._targets.end() ) {
                         auto& T = **Ti;
                         if ( Y.g_on_target( T) == 0  ) {
-                                if ( options.verbosely > 3 )
-                                        fprintf( stderr, " (deleting dendrite to \"%s\" of a synapse \"%s\" with gsyn == 0)\n",
-                                                 T._label, Y._label);
+                                vp( 3, stderr, " (deleting dendrite to \"%s\" of a synapse \"%s\" with gsyn == 0)\n",
+                                    T._label, Y._label);
                                 T._dendrites.erase( &Y);
                                 ++Ti;
                                 Y._targets.erase( prev(Ti));
@@ -847,19 +840,17 @@ cull_deaf_synapses()
                 if ( ((*Y)->param_schedulers && device_list_concerns_parm( (*Y)->param_schedulers, gsyn_pidx)) ||
                      ((*Y)->param_readers    && device_list_concerns_parm( (*Y)->param_readers,    gsyn_pidx)) ||
                      ((*Y)->param_ranges     && device_list_concerns_parm( (*Y)->param_ranges,     gsyn_pidx)) ) {
-                        if ( verbosely > 2 )
-                                printf( " (preserving doped synapse with zero gsyn: \"%s\")\n", (*Y)->_label);
+                        vp( 2, " (preserving doped synapse with zero gsyn: \"%s\")\n", (*Y)->_label);
                         continue;
                 }
                 if ( gsyn_pidx > -1 && (*Y)->param_value( gsyn_pidx) == 0. ) {
-                        if ( verbosely > 2 )
-                                printf( " (deleting synapse with zero gsyn: \"%s\")\n", (*Y)->_label);
+                        vp( 2, " (deleting synapse with zero gsyn: \"%s\")\n", (*Y)->_label);
                         delete (*Y);
                         ++cnt;
                 }
         }
-        if ( verbosely > 0 && cnt )
-                printf( "Deleted %zd deaf synapses\n", cnt);
+        if ( cnt )
+                vp( 0, "Deleted %zd deaf synapses\n", cnt);
 */
 }
 
@@ -876,8 +867,7 @@ cull_blind_synapses()
         while ( Yi != hosted_synapses.rend() ) {
                 auto& Y = **Yi;
                 if ( !Y._source && !Y.has_sources() ) {
-                        if ( options.verbosely > 3 )
-                                printf( " (deleting synapse with NULL source: \"%s\")\n", Y._label);
+                        vp( 3, " (deleting synapse with NULL source: \"%s\")\n", Y._label);
                         delete &Y;
                 }
         }
@@ -885,8 +875,7 @@ cull_blind_synapses()
         while ( Zi != standalone_synapses.rend() ) {
                 auto& Y = **Zi;
                 if ( !Y._source && !Y.has_sources() ) {
-                        if ( options.verbosely > 3 )
-                                printf( " (deleting synapse with NULL source: \"%s\")\n", Y._label);
+                        vp( 3, " (deleting synapse with NULL source: \"%s\")\n", Y._label);
                         delete &Y;
                 }
         }
@@ -920,13 +909,11 @@ process_listener_tags( const list<STagGroupListener> &Listeners)
                         if ( regexec( &RE, U._label, 0, 0, 0) == 0 ) {
                                 if ( P.enable ) {
                                         U.start_listening( P.bits);
-                                        if ( options.verbosely > 3 )
-                                                printf( " (unit \"%s\" listening%s)\n",
-                                                        U._label, P.bits & CN_ULISTENING_1VARONLY ? ", to one var only" :"");
+                                        vp( 3, " (unit \"%s\" listening%s)\n",
+                                            U._label, P.bits & CN_ULISTENING_1VARONLY ? ", to one var only" :"");
                                 } else {
                                         U.stop_listening();
-                                        if ( options.verbosely > 3 )
-                                                printf( " (unit \"%s\" not listening)\n", U._label);
+                                        vp( 3, " (unit \"%s\" not listening)\n", U._label);
                                 }
                         }
                 }
@@ -962,9 +949,8 @@ process_spikelogger_tags( const list<STagGroupSpikelogger> &Spikeloggers)
                                 } else
                                         N.disable_spikelogging_service();
 
-                                if ( options.verbosely > 3 )
-                                        printf( " (%sabling spike logging for standalone neuron \"%s\")\n",
-                                                P.enable ? "en" : "dis", N._label);
+                                vp( 3, " (%sabling spike logging for standalone neuron \"%s\")\n",
+                                    P.enable ? "en" : "dis", N._label);
                         }
                 }
                 for ( auto& Ni : hosted_neurons ) {
@@ -982,9 +968,8 @@ process_spikelogger_tags( const list<STagGroupSpikelogger> &Spikeloggers)
                                 } else
                                         N.disable_spikelogging_service();
 
-                                if ( options.verbosely > 3 )
-                                        printf( " (%sabling spike logging for hosted neuron \"%s\")\n",
-                                                P.enable ? "en" : "dis", N._label);
+                                vp( 3, " (%sabling spike logging for hosted neuron \"%s\")\n",
+                                    P.enable ? "en" : "dis", N._label);
                         }
                 }
         }
@@ -1009,9 +994,7 @@ process_putout_tags( const list<STagGroup> &ToRemove)
                         ++Ui;
                         auto& U = **prev(Ui);
                         if ( regexec( &RE, U._label, 0, 0, 0) == 0 ) {
-                                if ( options.verbosely > 2 )
-                                        printf( " (put out unit \"%s\")\n",
-                                                U._label);
+                                vp( 2, " (put out unit \"%s\")\n", U._label);
                                 delete &U;
                         }
                 }
@@ -1047,9 +1030,8 @@ process_decimate_tags( const list<STagGroupDecimate> &ToDecimate)
                 while ( n-- )
                         delete dcmgroup[n];
 
-                if ( options.verbosely > 3 )
-                        printf( " (decimated %4.1f%% (%zu units) of %s)\n",
-                                P.fraction*100, to_execute, P.pattern.c_str());
+                vp( 3, " (decimated %4.1f%% (%zu units) of %s)\n",
+                    P.fraction*100, to_execute, P.pattern.c_str());
 
         }
 
@@ -1115,10 +1097,9 @@ process_paramset_static_tags( const list<STagGroupNeuronParmSet> &tags)
                         continue;
                 }
 
-                if ( options.verbosely > 3 )
-                        printf( " set [%s]{%s} = %g\n",
-                                join(current_tag_assigned_labels, ", ").c_str(),
-                                P.parm.c_str(), P.value);
+                vp( 3, " set [%s]{%s} = %g\n",
+                    join(current_tag_assigned_labels, ", ").c_str(),
+                    P.parm.c_str(), P.value);
         }
         return 0;
 }
@@ -1137,8 +1118,8 @@ process_paramset_static_tags( const list<STagGroupSynapseParmSet> &tags)
 
                 bool do_gsyn = (P.parm == "gsyn");
 
-                if ( options.verbosely > 5 )
-                        printf( "== setting %s -> %s {%s} = %g...\n", P.pattern.c_str(), P.target.c_str(), P.parm.c_str(), P.value);
+                vp( 5, "== setting %s -> %s {%s} = %g...\n",
+                    P.pattern.c_str(), P.target.c_str(), P.parm.c_str(), P.value);
 
                 for ( auto& Uai : units ) {
                         if ( not Uai->is_neuron() )
@@ -1196,10 +1177,9 @@ process_paramset_static_tags( const list<STagGroupSynapseParmSet> &tags)
                         return;
                 }
 
-                if ( options.verbosely > 3 )
-                        printf( " set [%s]{%s} = %g\n",
-                                join(current_tag_assigned_labels, ", ").c_str(),
-                                P.parm.c_str(), P.value);
+                vp( 3, " set [%s]{%s} = %g\n",
+                    join(current_tag_assigned_labels, ", ").c_str(),
+                    P.parm.c_str(), P.value);
         };
 
         for ( auto& P : tags ) {
@@ -1237,8 +1217,7 @@ startover:
                                 continue;
 
                         if ( U1._source == U2._source && U1.is_identical( U2) ) {
-                                if ( options.verbosely > 5 )
-                                        printf( "coalescing \"%s\" and \"%s\"\n", U1.label(), U2.label());
+                                vp( 5, "coalescing \"%s\" and \"%s\"\n", U1.label(), U2.label());
                                 for ( auto& T : U2._targets ) {
                                         U1._targets.push_back( T);
                                         T->_dendrites[&U1] = T->_dendrites[&U2];
@@ -1285,14 +1264,12 @@ process_paramset_source_tags( const list<STagGroupSource> &tags)
 
                         if ( P.enable ) {
                                 U -> attach_source( P.source, kind, p_d);
-                                if ( options.verbosely > 3 )
-                                        printf( "Connected source \"%s\" to \"%s\"{%s}\n",
-                                                P.source->name.c_str(), U->label(), P.parm.c_str());
+                                vp( 3, "Connected source \"%s\" to \"%s\"{%s}\n",
+                                    P.source->name.c_str(), U->label(), P.parm.c_str());
                         } else {
                                 U -> detach_source( P.source, kind, p_d);
-                                if ( options.verbosely > 3 )
-                                        printf( "Disconnected source \"%s\" from \"%s\"{%s}\n",
-                                                P.source->name.c_str(), U->label(), P.parm.c_str());
+                                vp( 3, "Disconnected source \"%s\" from \"%s\"{%s}\n",
+                                    P.source->name.c_str(), U->label(), P.parm.c_str());
                         }
                 }
         }
diff --git a/upstream/src/libcn/model.hh b/upstream/src/libcn/model.hh
index 08ddab7..d2a29b2 100644
--- a/upstream/src/libcn/model.hh
+++ b/upstream/src/libcn/model.hh
@@ -23,7 +23,6 @@ parameters.
 #ifndef CNRUN_LIBCN_MODEL_H_
 #define CNRUN_LIBCN_MODEL_H_
 
-#include <csignal>
 #include <list>
 #include <vector>
 #include <string>
@@ -34,6 +33,7 @@ parameters.
 #include "gsl/gsl_rng.h"
 
 #include "libstilton/exprparser.hh"
+#include "libstilton/misc.hh"
 #include "forward-decls.hh"
 #include "base-neuron.hh"
 #include "base-synapse.hh"
@@ -98,12 +98,12 @@ struct SModelOptions {
 };
 
 
-class CModel {
+class CModel : public cnrun::stilton::C_verprintf {
 
     public:
       // ctor, dtor
-        CModel( const string& name, CIntegrate_base*, const SModelOptions&);
-       ~CModel();
+        CModel (const string& name, CIntegrate_base*, const SModelOptions&);
+        virtual ~CModel ();
 
         string  name;
 
@@ -443,6 +443,11 @@ class CModel {
                 _longest_label;
 
         gsl_rng *_rng;
+
+        int verbose_threshold() const
+                {
+                        return options.verbosely;
+                }
 };
 
 
@@ -496,24 +501,31 @@ C_BaseUnit::attach_source( T *s, TSinkType t, unsigned short idx)
 
 
 inline SSpikeloggerService*
-C_BaseNeuron::enable_spikelogging_service( int s_mask)
+C_BaseNeuron::
+enable_spikelogging_service( int s_mask)
 {
         if ( !_spikelogger_agent )
-                _spikelogger_agent = new SSpikeloggerService( this, s_mask);
+                _spikelogger_agent =
+                        new SSpikeloggerService( this, s_mask);
         M->register_spikelogger( this);
         return _spikelogger_agent;
 }
 inline SSpikeloggerService*
-C_BaseNeuron::enable_spikelogging_service( double sample_period, double sigma, double from, int s_mask)
+C_BaseNeuron::
+enable_spikelogging_service( double sample_period,
+                             double sigma,
+                             double from, int s_mask)
 {
         if ( !_spikelogger_agent )
-                _spikelogger_agent = new SSpikeloggerService( this, sample_period, sigma, from, s_mask);
+                _spikelogger_agent =
+                        new SSpikeloggerService( this, sample_period, sigma, from, s_mask);
         M->register_spikelogger( this);
         return _spikelogger_agent;
 }
 
 inline void
-C_BaseNeuron::disable_spikelogging_service()
+C_BaseNeuron::
+disable_spikelogging_service()
 {
         if ( _spikelogger_agent && !(_spikelogger_agent->_status & CN_KL_PERSIST)) {
                 _spikelogger_agent->sync_history();
@@ -530,7 +542,8 @@ C_BaseNeuron::disable_spikelogging_service()
 
 
 inline void
-C_HostedNeuron::reset_vars()
+C_HostedNeuron::
+reset_vars()
 {
         if ( M && idx < M->_var_cnt )
                 memcpy( &M->V[idx],
@@ -539,7 +552,8 @@ C_HostedNeuron::reset_vars()
 }
 
 inline double&
-C_HostedNeuron::var_value( size_t v)
+C_HostedNeuron::
+var_value( size_t v)
 {
         return M->V[idx + v];
 }
@@ -552,27 +566,31 @@ C_HostedNeuron::get_var_value( size_t v) const
 
 
 
-inline unsigned
-C_HostedConductanceBasedNeuron::n_spikes_in_last_dt() const
+inline size_t
+C_HostedConductanceBasedNeuron::
+n_spikes_in_last_dt() const
 {
         return E() >= M->options.spike_threshold;
 }
 
-inline unsigned
-C_HostedRateBasedNeuron::n_spikes_in_last_dt() const
+inline size_t
+C_HostedRateBasedNeuron::
+n_spikes_in_last_dt() const
 {
         return round(E() * M->dt() * M->rng_sample());
 }
 
 
-inline unsigned
-C_StandaloneConductanceBasedNeuron::n_spikes_in_last_dt() const
+inline size_t
+C_StandaloneConductanceBasedNeuron::
+n_spikes_in_last_dt() const
 {
         return E() >= M->options.spike_threshold;
 }
 
-inline unsigned
-C_StandaloneRateBasedNeuron::n_spikes_in_last_dt() const
+inline size_t
+C_StandaloneRateBasedNeuron::
+n_spikes_in_last_dt() const
 {
         return round(E() * M->dt() * M->rng_sample());
 }
@@ -582,9 +600,9 @@ C_StandaloneRateBasedNeuron::n_spikes_in_last_dt() const
 
 
 inline void
-C_HostedSynapse::reset_vars()
+C_HostedSynapse::
+reset_vars()
 {
-//        cout << "reset_vars() on " << label << " (idx " << idx << ")\n";
         if ( M && M->_var_cnt > idx )
                 memcpy( &M->V[idx],
                         __CNUDT[_type].stock_var_values,
@@ -594,13 +612,15 @@ C_HostedSynapse::reset_vars()
 
 
 inline double&
-C_HostedSynapse::var_value( size_t v)
+C_HostedSynapse::
+var_value( size_t v)
 {
         return M->V[idx + v];
 }
 
 inline const double&
-C_HostedSynapse::get_var_value( size_t v) const
+C_HostedSynapse::
+get_var_value( size_t v) const
 {
         return M->V[idx + v];
 }
@@ -608,7 +628,8 @@ C_HostedSynapse::get_var_value( size_t v) const
 
 
 inline double
-C_HostedConductanceBasedNeuron::E() const
+C_HostedConductanceBasedNeuron::
+E() const
 {
         return M->V[idx+0];
 }
@@ -617,7 +638,8 @@ C_HostedConductanceBasedNeuron::E() const
 
 
 inline double
-C_HostedSynapse::S() const
+C_HostedSynapse::
+S() const
 {
         return M->V[idx+0];
 }
@@ -625,41 +647,9 @@ C_HostedSynapse::S() const
 
 
 
-
-inline
-CNeuronMap::CNeuronMap( const string& inlabel, double x, double y, double z, CModel *inM, int s_mask)
-      : C_StandaloneConductanceBasedNeuron( NT_MAP, inlabel, x, y, z, inM, s_mask)
-{
-        if ( inM ) {
-                if ( isfinite( inM->_discrete_dt) && inM->_discrete_dt != fixed_dt ) {
-                        printf( "Inappropriate discrete dt\n");
-                        _status |= CN_UERROR;
-                }
-                inM -> _discrete_dt = fixed_dt;
-        }
-}
-
-
-inline
-CSynapseMap::CSynapseMap( C_BaseNeuron *insource, C_BaseNeuron *intarget,
-                          double ing, CModel *inM, int s_mask, TUnitType alt_type)
-      : C_StandaloneSynapse( alt_type, insource, intarget, ing, inM, s_mask),
-        _source_was_spiking (false)
-{
-        if ( !inM )
-                fprintf( stderr, "A MxMap synapse is created unattached to a model: preadvance() will cause a segfault!\n");
-        else {
-                if ( isfinite( inM->_discrete_dt) && inM->_discrete_dt != fixed_dt ) {
-                        printf( "Inappropriate discrete dt\n");
-                        _status |= CN_UERROR;
-                }
-                inM -> _discrete_dt = fixed_dt;
-        }
-}
-
-
 inline void
-CSynapseMap::preadvance()
+CSynapseMap::
+preadvance()
 {
         V_next[0] = S() * exp( -M->discrete_dt() / P[_tau_])
                 + (_source->n_spikes_in_last_dt() ? P[_delta_] : 0);
@@ -668,7 +658,8 @@ CSynapseMap::preadvance()
 
 
 inline void
-CSynapseMxMap::preadvance()
+CSynapseMxMap::
+preadvance()
 {
         V_next[0] = S() * exp( -M->discrete_dt() / P[_tau_]) + q() * P[_delta_];
 }
diff --git a/upstream/src/libcn/standalone-neurons.cc b/upstream/src/libcn/standalone-neurons.cc
index 2be61ee..2e7099c 100644
--- a/upstream/src/libcn/standalone-neurons.cc
+++ b/upstream/src/libcn/standalone-neurons.cc
@@ -35,14 +35,6 @@ C_StandaloneNeuron( TUnitType intype, const string& inlabel,
 }
 
 
-cnrun::C_StandaloneNeuron::
-~C_StandaloneNeuron()
-{
-        if ( M && M->options.verbosely > 5 )
-                fprintf( stderr, " deleting standalone neuron \"%s\"\n", _label);
-}
-
-
 
 
 
@@ -304,9 +296,6 @@ do_detect_spike_or_whatever()
 
 
 
-
-
-
 // Map neurons require descrete time
 
 const double cnrun::__CN_Params_NeuronMap[] = {
@@ -343,6 +332,19 @@ const char* const cnrun::__CN_VarSyms_NeuronMap[] = {
 };
 
 
+cnrun::CNeuronMap::
+CNeuronMap( const string& inlabel, double x, double y, double z, CModel *inM, int s_mask)
+      : C_StandaloneConductanceBasedNeuron( NT_MAP, inlabel, x, y, z, inM, s_mask)
+{
+        if ( inM ) {
+                if ( isfinite( inM->_discrete_dt) && inM->_discrete_dt != fixed_dt )
+                        throw "Inappropriate discrete dt";
+
+                inM -> _discrete_dt = fixed_dt;
+        }
+}
+
+
 
 void
 cnrun::CNeuronMap::
@@ -366,14 +368,6 @@ preadvance()
 
 
 
-
-
-
-
-
-
-
-
 // ----- Pulse
 
 const char* const cnrun::__CN_ParamNames_NeuronDotPulse[] = {
@@ -430,8 +424,7 @@ cnrun::CNeuronDotPulse::
 param_changed_hook()
 {
         if ( P[_f_] < 0 ) {
-                if ( M->options.verbosely > 0 )
-                        fprintf( stderr, "DotPulse oscillator \"%s\" got a negative parameter f: capping at 0\n", _label);
+                M->vp( 0, stderr, "DotPulse oscillator \"%s\" got a negative parameter f: capping at 0\n", _label);
                 P[_f_] = 0.;
         }
 }
diff --git a/upstream/src/libcn/standalone-synapses.cc b/upstream/src/libcn/standalone-synapses.cc
index 95294d6..8b28d7d 100644
--- a/upstream/src/libcn/standalone-synapses.cc
+++ b/upstream/src/libcn/standalone-synapses.cc
@@ -38,23 +38,6 @@ C_StandaloneSynapse( TUnitType intype,
 }
 
 
-cnrun::C_StandaloneSynapse::
-~C_StandaloneSynapse()
-{
-        if ( cn_verbosely > 5 )
-                fprintf( stderr, " deleting standalone synapse \"%s\"\n", _label);
-}
-
-// C_StandaloneSynapse::~C_StandaloneSynapse()
-// {
-//         if ( M->unregister_standalone_synapse( this) )
-//                 cerr << "Synapse " << label << " was forgotten by mother model\n";
-// }
-
-
-
-
-
 
 
 
@@ -79,8 +62,18 @@ const char* const cnrun::__CN_ParamSyms_SynapseMap[] = {
 };
 
 
-
-
+cnrun::CSynapseMap::
+CSynapseMap( C_BaseNeuron *insource, C_BaseNeuron *intarget,
+             double ing, CModel *inM, int s_mask, TUnitType alt_type)
+      : C_StandaloneSynapse( alt_type, insource, intarget, ing, inM, s_mask),
+        _source_was_spiking (false)
+{
+        if ( !inM )
+                throw "A MxMap synapse is created unattached to a model: preadvance() will cause a segfault!";
+        if ( isfinite( inM->_discrete_dt) && inM->_discrete_dt != fixed_dt )
+                throw "Inappropriate discrete dt\n";
+        inM -> _discrete_dt = fixed_dt;
+}
 
 
 
diff --git a/upstream/src/libstilton/Makefile.am b/upstream/src/libstilton/Makefile.am
index 75f6417..b7cf695 100644
--- a/upstream/src/libstilton/Makefile.am
+++ b/upstream/src/libstilton/Makefile.am
@@ -9,7 +9,8 @@ libstilton_la_SOURCES = \
 	lang.hh \
 	exprparser.hh \
 	exprparser.cc \
-	libcommon.cc
+	libcommon.cc \
+	misc.hh
 
 libstilton_la_LDFLAGS = \
 	-avoid-version \
@@ -21,7 +22,8 @@ BUILT_SOURCES = \
 	alg.hh.gch \
 	containers.hh.gch \
 	lang.hh.gch \
-	exprparser.hh.gch
+	exprparser.hh.gch \
+	misc.hh.gch
 
 CLEANFILES = $(BUILT_SOURCES)
 endif
diff --git a/upstream/src/libstilton/alg.hh b/upstream/src/libstilton/alg.hh
index f24cba2..aa97b09 100644
--- a/upstream/src/libstilton/alg.hh
+++ b/upstream/src/libstilton/alg.hh
@@ -9,8 +9,8 @@
  *         License:  GPL
  */
 
-#ifndef _CNRUN_LIBSTILTON_ALG_H
-#define _CNRUN_LIBSTILTON_ALG_H
+#ifndef CNRUN_LIBSTILTON_ALG_H_
+#define CNRUN_LIBSTILTON_ALG_H_
 
 
 #if HAVE_CONFIG_H && !defined(VERSION)
@@ -20,6 +20,7 @@
 using namespace std;
 
 namespace cnrun {
+namespace stilton {
 namespace alg {
 
 /// uncomment on demand
@@ -91,6 +92,7 @@ value_within( const T& v, const T& l, const T& h)
 // for more, check this file in Aghermann
 
 } // namespace alg
+} // namespace stilton
 } // namespace cnrun
 
 #endif
diff --git a/upstream/src/libstilton/libcommon.cc b/upstream/src/libstilton/libcommon.cc
index 3f0d4ff..3a7a64b 100644
--- a/upstream/src/libstilton/libcommon.cc
+++ b/upstream/src/libstilton/libcommon.cc
@@ -21,6 +21,7 @@
 
 #include "string.hh"
 #include "alg.hh"
+#include "misc.hh"
 
 
 #if HAVE_CONFIG_H && !defined(VERSION)
@@ -28,6 +29,32 @@
 #endif
 
 using namespace std;
+using namespace cnrun::stilton;
+
+
+void
+C_verprintf::
+vp( int level, const char* fmt, ...)
+{
+        if ( level > verbose_threshold() ) {
+                va_list ap;
+                va_start (ap, fmt);
+                vprintf( fmt, ap);
+                va_end (ap);
+        }
+}
+
+void
+C_verprintf::
+vp( int level, FILE* f, const char* fmt, ...)
+{
+        if ( level > verbose_threshold() ) {
+                va_list ap;
+                va_start (ap, fmt);
+                vfprintf( f, fmt, ap);
+                va_end (ap);
+        }
+}
 
 
 string
diff --git a/upstream/src/libstilton/misc.hh b/upstream/src/libstilton/misc.hh
new file mode 100644
index 0000000..6e3077e
--- /dev/null
+++ b/upstream/src/libstilton/misc.hh
@@ -0,0 +1,43 @@
+/*
+ *       File name:  libstilton/misc.hh
+ *         Project:  cnrun
+ *          Author:  Andrei Zavada <johnhommer at gmail.com>
+ * Initial version:  2014-09-19
+ *
+ *         Purpose:  misc supporting algorithms
+ *
+ *         License:  GPL
+ */
+
+#ifndef CNRUN_LIBSTILTON_MISC_H_
+#define CNRUN_LIBSTILTON_MISC_H_
+
+#include <unistd.h>
+
+#if HAVE_CONFIG_H && !defined(VERSION)
+#  include "config.h"
+#endif
+
+using namespace std;
+
+namespace cnrun {
+namespace stilton {
+
+struct C_verprintf {
+        virtual int verbose_threshold() const = 0;
+        void vp( int, const char* fmt, ...) __attribute__ ((format (printf, 3, 4)));
+        void vp( int, FILE*, const char* fmt, ...) __attribute__ ((format (printf, 4, 5)));
+};
+
+
+} // namespace stilton
+} // namespace cnrun
+
+#endif
+
+// Local Variables:
+// Mode: c++
+// indent-tabs-mode: nil
+// tab-width: 8
+// c-basic-offset: 8
+// End:
diff --git a/upstream/src/libstilton/string.hh b/upstream/src/libstilton/string.hh
index b4c3688..52eeb8a 100644
--- a/upstream/src/libstilton/string.hh
+++ b/upstream/src/libstilton/string.hh
@@ -40,7 +40,7 @@ string pad( const string& r0, size_t to);
 
 template <typename C>
 string
-join( const C& l, const char* sep)
+join( const C& l, const char* sep = ", ")
 {
         if ( l.empty() )
                 return "";

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/cnrun.git



More information about the debian-med-commit mailing list