text: 
  #include <../../nrnconf.h>
  
  #include <stdio.h>
  #include <string.h>
  #include <OS/string.h>
  #include <ivstream.h>
  
  #if HAVE_IV
  #include "secbrows.h"
  #include "ivoc.h"
  #endif
  #include "nrnoc2iv.h"
  #include "nrnmenu.h"
  #include "classreg.h"
  
  typedef void (*ReceiveFunc)(Point_process*, double*, double);
  extern "C" int hoc_return_type_code;
  extern "C" {
  // from nrnoc
  #include "membfunc.h"
  #include "parse.h"
  extern Symlist *hoc_built_in_symlist;
  extern Symbol **pointsym;
  extern double* point_process_pointer(Point_process*, Symbol*, int);
  extern Point_process* ob2pntproc(Object*);
  extern ReceiveFunc* pnt_receive;
  extern int nrn_has_net_event_cnt_;
  extern int* nrn_has_net_event_;
  extern short* nrn_is_artificial_;
  extern int node_index(Section*, double);
  extern char* pnt_map;
  extern void nrn_parent_info(Section*);
  
  // to nrnoc
  void nrnallsectionmenu();
  void nrnallpointmenu();
  void nrnsecmenu();
  void nrnglobalmechmenu();
  void nrnmechmenu();
  void nrnpointmenu();
  
  Object* (*nrnpy_callable_with_args)(Object*, int narg);
  int (*nrnpy_ob_is_seg)(Object*);
  
  }
  
  #if HAVE_IV
  static void pnodemenu(Prop* p1, double, int type, const char* path, MechSelector* = NULL);
  static void mech_menu(Prop* p1, double, int type, const char* path, MechSelector* = NULL);
  static void point_menu(Object*, int);
  #endif
  
  void nrnallsectionmenu() {
  #if HAVE_IV
  IFGUI
  	SectionBrowser::make_section_browser();
  ENDGUI
  #endif
  
  	hoc_retpushx(1.);
  }
  
  void nrnsecmenu() {
  #if HAVE_IV
  IFGUI
  	double x;
  	Section* sec = NULL;
  	if (hoc_is_object_arg(1)) { // x = -1 not allowed
  		nrn_seg_or_x_arg(1, &sec, &x);
  		nrn_pushsec(sec);
  	}else{
  		x = chkarg(1,-1.,1.);
  	}
  	section_menu(x, (int)chkarg(2,1.,3.));
  	if (sec) { nrn_popsec(); }
  ENDGUI
  #endif
  	hoc_retpushx(1.);
  }
  
  #ifdef ultrix
  extern "C" { char *strstr(const char *, const char *); }
  #endif
  
  static bool has_globals(const char* name) {
  	Symbol* sp;
  	char suffix[100];
  	sprintf(suffix, "_%s", name);
  	for (sp = hoc_built_in_symlist->first; sp; sp = sp->next) {
  		if (sp->type == VAR && sp->subtype == USERDOUBLE
  		    && strstr(sp->name, suffix) ) {
  	    		return true;
  		}
  	}
  	return false;
  }
  
  void nrnglobalmechmenu() {
  #if HAVE_IV
  IFGUI
  	Symbol *sp;
  	char* s;
  	char buf[200];
  	char suffix[100];
     if (!ifarg(1)) {
  	hoc_ivmenu("Mechanisms (Globals)");
  	for (sp = hoc_built_in_symlist->first; sp; sp = sp->next) {
  		if (sp->type == MECHANISM && sp->subtype != MORPHOLOGY
  		  && has_globals(sp->name)) {
  			sprintf(buf, "nrnglobalmechmenu(\"%s\")", sp->name);
  			hoc_ivbutton(sp->name, buf);
  		}
  	}
  	hoc_ivmenu(0);
  	hoc_retpushx(1.);
  	return;
     }
  	char* name = gargstr(1);
  	sprintf(suffix, "_%s", name);
  	if (ifarg(2) && *getarg(2) == 0.) {
  		int cnt = 0;
  		for (sp = hoc_built_in_symlist->first; sp; sp = sp->next) {
  			if (sp->type == VAR && sp->subtype == USERDOUBLE
  			    && (s = strstr(sp->name, suffix)) != 0
  			    && s[strlen(suffix)] == '\0'){
  		    		++cnt;
  			}
  		}
  		hoc_retpushx(double(cnt));
  		return;
  	}
  	sprintf(buf, "%s (Globals)", name);
  	hoc_ivpanel(buf);
  	for (sp = hoc_built_in_symlist->first; sp; sp = sp->next) {
  		if (sp->type == VAR && sp->subtype == USERDOUBLE
  		    && (s = strstr(sp->name, suffix)) != 0
  		    && s[strlen(suffix)] == '\0'){
     if (ISARRAY(sp)) {
  	char n[50];
  	int i;
  	Arrayinfo* a = sp->arayinfo;
  	for (i=0; i < a->sub[0]; i++) {
  		if (i > 5) break;
  		sprintf(buf, "%s[%d]", sp->name, i);
  		sprintf(n, "%s[%d]", sp->name, i);
  		hoc_ivpvalue(n, hoc_val_pointer(buf), false, sp->extra);
  	}
     }else{
  			hoc_ivvalue(sp->name, sp->name, 1);
  		}
  	}
     }
  	hoc_ivpanelmap();
  ENDGUI
  #endif
  	hoc_retpushx(1.);
  }
  
  void nrnmechmenu() {
  	hoc_retpushx(1.);
  }
  
  #if HAVE_IV
  void section_menu(double x1, int type, MechSelector* ms)
  {
  	char buf[200];
  	const char* name;
  	Section *sec;
  	Prop *p;
  	Node* node;
  	double x;
  	String btype;
  	CopyString sname;
  	
  	switch (type) {
  	case nrnocCONST:
  		btype = "(Parameters)";
  		break;
  	case STATE:
  		btype = "(States)";
  		break;
  	case 2:
  		btype = "(Assigned)";
  		break;
  	}
  	
  	sec = chk_access();
  	name = secname(sec);
  
  	if (x1 >= 0) {
  		node = node_exact(sec, x1);
  		x = nrn_arc_position(sec, node);
  		sprintf(buf, "%s(%g) %s", name, x, btype.string());
  	}else{
  		sprintf(buf, "%s(0 - 1) %s", name, btype.string());
  		node = sec->pnode[0];
  		x = nrn_arc_position(sec, node);
  		sname = hoc_section_pathname(sec);
  //printf("returned %s\n", sname.string());
  	}		
  	hoc_ivpanel(buf);
  	hoc_ivlabel(buf);
  	if (type == nrnocCONST) {
  		if (x1 < 0) {
  			sprintf(buf,"nseg = %d", sec->nnode-1); hoc_ivlabel(buf);
  			sprintf(buf, "%s.L", sname.string());
  			if (sec->npt3d) {
  				hoc_ivvaluerun("L", buf, "define_shape()", 1);
  			}else{
  				hoc_ivvalue("L", buf, 1);
  			}
  			sprintf(buf, "%s.Ra += 0", sname.string());
  			hoc_ivpvaluerun("Ra",&sec->prop->dparam[7].val, buf, 1, 0, hoc_var_extra("Ra"));
  			p = sec->prop;
  			if (p->dparam[4].val != 1) {
  				hoc_ivpvaluerun("Rall",&sec->prop->dparam[4].val, "diam_changed = 1", 1, 0, hoc_var_extra("rallbranch"));
  			}
  		}
  	}else{
  		if (x1 < 0) {
  			sprintf(buf,"%s.%s", sname.string(), "v");
  			hoc_ivvalue("v",buf);
  		}else{
  sprintf(buf,"v(%g)", x); hoc_ivpvalue("v",hoc_val_pointer(buf), false, hoc_lookup("v")->extra);
  		}
  	}
  	
  	p = node->prop;
  	if (x1 < 0) {
  		pnodemenu(p, x, type, sname.string(), ms);
  	}else{
  		pnodemenu(p, x, type, 0, ms);
  	}
  	hoc_ivpanelmap();
  }
  
  static void pnodemenu(Prop* p1, double x, int type, const char* path, MechSelector* ms)
  {
  	if (!p1) {
  		return;
  	}
  	pnodemenu(p1->next, x, type, path, ms);	/*print in insert order*/
  	if (memb_func[p1->type].is_point) {
  		return;
  	}else{
  		mech_menu(p1, x, type, path, ms);
  	}
  }
  #endif
  
  #if HAVE_IV
  static bool nrn_is_const(const char* path, const char* name) {
  	char buf[256];
  	sprintf(buf,
  "%s for (hoc_ac_) if (hoc_ac_ > 0 && hoc_ac_ < 1) if (%s(hoc_ac_) != %s(.5)) {hoc_ac_ = 0  break}\n",
  	path, name, name);
  	Oc oc;
  	oc.run(buf);
  	return (hoc_ac_ != 0.);
  }
  #endif
  
  #if HAVE_IV
  static void mech_menu(Prop* p1, double x, int type, const char* path, MechSelector* ms) {
  	Symbol *sym, *vsym;
  	int i, j;
  	char buf[200];
  	bool deflt;
  
  	if (ms && !ms->is_selected(p1->type)) {
  		return;
  	}
  	if (type == nrnocCONST) {
  		deflt = true;
  	}else{
  		deflt = false;
  	}
  	sym = memb_func[p1->type].sym;
  	if (sym->s_varn) {
  		for (j=0; j < sym->s_varn; j++ ) {
  			vsym = sym->u.ppsym[j];
  			if (nrn_vartype(vsym) == type) {
  				if (vsym->type == RANGEVAR) {
  if (ISARRAY(vsym)) {
  	char n[50];
  	Arrayinfo* a = vsym->arayinfo;
  	for (i=0; i < a->sub[0]; i++) {
  		if (i > 5) break;
  		sprintf(n, "%s[%d]", vsym->name, i);
  		if (path) {
  			if (nrn_is_const(path, n)) {
  				sprintf(buf, "%s.%s", path, n);
  				hoc_ivvalue(n, buf, deflt);
  			}else{
  				sprintf(buf, "%s is not constant", n);
  				hoc_ivlabel(buf);
  			}
  		}else{
  			sprintf(buf, "%s[%d](%g)",vsym->name, i, x);
  			hoc_ivpvalue(n, hoc_val_pointer(buf), false, vsym->extra);
  		}
  	}
  }else{
  					if (path) {
  					 if (nrn_is_const(path, vsym->name)) {
  					   sprintf(buf, "%s.%s", path, vsym->name);
  					   hoc_ivvalue(vsym->name, buf, deflt);
  					 }else{
  					   sprintf(buf, "%s is not constant", vsym->name);
  					   hoc_ivlabel(buf);
  					 }
  					}else{
  					 sprintf(buf, "%s(%g)", vsym->name, x);
  					 if (p1->type == MORPHOLOGY) {
  					   Section* sec = chk_access();
  					   char buf2[200];
  					   sprintf(buf2, "%s.Ra += 0", secname(sec));
  hoc_ivpvaluerun(vsym->name, hoc_val_pointer(buf), buf2, 1, 0, vsym->extra);
  					 }else{
  hoc_ivpvalue(vsym->name, hoc_val_pointer(buf), deflt, vsym->extra);
  					 }
  					}
  }
  				}
  			}
  		}
  	}
  }
  #endif
  
  void nrnallpointmenu() {
  #if HAVE_IV
  IFGUI
  	int i;
  	double x = n_memb_func - 1;
  	Symbol *sp, *psym;
  	char buf[200];
  	hoc_Item* q;
  
     if (!ifarg(1)) {
  	hoc_ivmenu("Point Processes");
  	for (i=1; (sp = pointsym[i]) != (Symbol *)0; i++) {
  		sprintf(buf, "nrnallpointmenu(%d)", i);
  		hoc_ivbutton(sp->name, buf);
  	}
  	hoc_ivmenu(0);
  	hoc_retpushx(1.);
  	return;
     }
  
  	i = (int)chkarg(1, 0., x);
     if ((psym = pointsym[i]) != (Symbol *)0) {
  	hoc_ivpanel(psym->name);
  	sp = hoc_table_lookup(psym->name,hoc_built_in_symlist);
  	assert (sp && sp->type == TEMPLATE);
  	
  	bool locmenu = false;
  	ITERATE(q, sp->u.ctemplate->olist) { // are there any
  		hoc_ivmenu("locations");
  		locmenu = true;
  		break;
  	}
  
  	bool are_globals = false;
  	char suffix[100];
  	sprintf(suffix, "_%s", sp->name);
  	for (Symbol *stmp = hoc_built_in_symlist->first; stmp; stmp = stmp->next) {
  		if (stmp->type == VAR && stmp->subtype == USERDOUBLE
  		     && strstr(stmp->name, suffix) ) {
  		     	are_globals = true;
  		     	break;
  		}
  	}
  
  	ITERATE(q, sp->u.ctemplate->olist) {
  		Object* ob = OBJ(q);
  			Point_process* pp = ob2pntproc(ob);
  			if (pp->sec) {
  sprintf(buf, "nrnpointmenu(%p)", ob);
  hoc_ivbutton(sec_and_position(pp->sec,pp->node), buf);
  			}
  	}
  	if (locmenu) {
  		hoc_ivmenu(0);
  	}
  	if (are_globals) {
  		sprintf(buf, "nrnglobalmechmenu(\"%s\")", psym->name);
  		hoc_ivbutton("Globals", buf);
  	}
  	hoc_ivpanelmap();
     }
  ENDGUI
  #endif
  	hoc_retpushx(1.);
  }
  
  void nrnpointmenu()
  {
  #if HAVE_IV
  IFGUI
  	Object* ob;
  	if (hoc_is_object_arg(1)) {
  		ob = *hoc_objgetarg(1);
  	}else{
  		ob = (Object*)((size_t)(*getarg(1)));
  	}
  	Symbol* sym = hoc_table_lookup(ob->ctemplate->sym->name,
  			ob->ctemplate->symtable);
  	if (!sym || sym->type != MECHANISM || !memb_func[sym->subtype].is_point) {
  		hoc_execerror(ob->ctemplate->sym->name, "not a point process");
  	}
  	int make_label = 1;
  	if (ifarg(2)) {
  	        make_label = int(chkarg(2, -1., 1.));
  	}
  	point_menu(ob, make_label);
  ENDGUI
  #endif
  	hoc_retpushx(1.);
  }
  
  #if HAVE_IV
  static void point_menu(Object* ob, int make_label) {
  	Point_process* pp = ob2pntproc(ob);
  	int  k, m;
  	Symbol *psym, *vsym;
  	char buf[200];
  	bool deflt;
  
  	if (pp->sec) {
  		sprintf(buf, "%s at ", hoc_object_name(ob));
  		strcat(buf, sec_and_position(pp->sec, pp->node));	
  	}else{
  		sprintf(buf, "%s", hoc_object_name(ob));
  	}
  	hoc_ivpanel(buf);
  
  
          if (make_label== 1){
  		hoc_ivlabel(buf);
  	}else if (make_label== 0){
  		hoc_ivlabel(hoc_object_name(ob));
  	}else if (make_label==-1){ //i.e. do neither
  		k=0;
  	}
  	psym = pointsym[pnt_map[pp->prop->type]];
  
  #if 0
          switch (type) {
          case nrnocCONST:
                  sprintf(buf, "%s[%d] (Parameters)", psym->name, j);
                  break;
          case STATE:
                  sprintf(buf, "%s[%d] (States)", psym->name, j);
                  break; 
          case 2: 
                  sprintf(buf, "%s[%d] (Assigned)", psym->name, j);
                  break; 
          } 
  #endif
  
  	if (psym->s_varn) {
  		for (k=0; k < psym->s_varn; k++ ) {
  			vsym = psym->u.ppsym[k];
  			if (nrn_vartype(vsym) == nrnocCONST) {
  				deflt = true;
  
  #if defined(MikeNeubig)
  				deflt = false;
  #endif // end of hack
  			}else{
  				deflt = false;
  			}
  			if (ISARRAY(vsym)) {
  				Arrayinfo* a = vsym->arayinfo;
  	for (m=0; m < vsym->arayinfo->sub[0]; m++) {
  		double* pd;
  		if (m > 5) break;
  		sprintf(buf, "%s[%d]", vsym->name, m);
  		pd = point_process_pointer(pp, vsym, m);
  		if (pd) {
  			hoc_ivpvalue(buf, pd,deflt, vsym->extra);
  		}
  	}
  			}else{
  	hoc_ivpvalue(vsym->name, point_process_pointer(pp, vsym,0),deflt, vsym->extra);
  			}
  		}
  	}
  
  	hoc_ivpanelmap();
  }
  #endif
  
  //-----------------------
  // MechanismStandard
  static double ms_panel(void* v) {
  #if HAVE_IV
  IFGUI
  	char* label = NULL;
  	if (ifarg(1)) {
  		label = gargstr(1);
  	}
  	((MechanismStandard*)v)->panel(label);
  ENDGUI
  #endif
  	return 0.;
  }
  static double ms_action(void* v) {
  	char* a = 0;
  	Object* pyact = NULL;
  	if(ifarg(1)) {
  		if (hoc_is_str_arg(1)) {
  			a = gargstr(1);
  		}else{
  			pyact = *hoc_objgetarg(1);
  		}
  	}
  	((MechanismStandard*)v)->action(a, pyact);
  	return 0.;
  }
  
  static double ms_out(void* v) {
  	MechanismStandard* m = (MechanismStandard*)v;
  	if (ifarg(1)) {
  	    if (hoc_is_double_arg(1)) {
  		double x = chkarg(1, 0, 1);
  		m->out(chk_access(), x);
  	    }else{
  		Object* o = *hoc_objgetarg(1);
  		if (is_obj_type(o, "MechanismStandard")) {
  			m->out((MechanismStandard*)o->u.this_pointer);
  		}else if (is_point_process(o)) {
  			m->out(ob2pntproc(o));
  		}else if (nrnpy_ob_is_seg && (*nrnpy_ob_is_seg)(o)) {
  			double x;
  			Section* sec;
  			nrn_seg_or_x_arg(1, &sec, &x);
  			m->out(sec, x);
  		}else{
  hoc_execerror("Object arg must be MechanismStandard or a Point Process, not",
  			hoc_object_name(o));
  		}
  	    }
  	}else{
  		m->out(chk_access());
  	}
  	return 0.;
  }
  
  static double ms_in(void* v) {
  	MechanismStandard* m = (MechanismStandard*)v;
  	if (ifarg(1)) {
  	    if (hoc_is_double_arg(1)) {
  		double x = chkarg(1, 0, 1);
  		m->in(chk_access(), x);
  	    }else{
  		Object* o = *hoc_objgetarg(1);
  		if (is_obj_type(o, "MechanismStandard")) {
  			m->in((MechanismStandard*)o->u.this_pointer);
  		}else if (is_point_process(o)) {
  			m->in(ob2pntproc(o));
  		}else if (nrnpy_ob_is_seg && (*nrnpy_ob_is_seg)(o)) {
  			double x;
  			Section* sec;
  			nrn_seg_or_x_arg(1, &sec, &x);
  			m->in(sec, x);
  		}else{
  hoc_execerror("Object arg must be MechanismStandard or a Point Process or a nrn.Segment, not",
  			hoc_object_name(o));
  		}
  	    }
  	}else{
  		m->in(chk_access());
  	}
  	return 0.;
  }
  
  static double ms_set(void* v) {
  	int i=0;
  	if (ifarg(3)) { // array index
  		i = int(*getarg(3));
  	}
  	((MechanismStandard*)v)->set(gargstr(1), *getarg(2), i);
  	return 0.;
  }
  static double ms_get(void* v) {
  	int i=0;
  	if (ifarg(2)) { // array index
  		i = int(*getarg(2));
  	}
  	return ((MechanismStandard*)v)->get(gargstr(1), i);
  }
  static double ms_count(void* v) {
  	hoc_return_type_code = 1;
  	return ((MechanismStandard*)v)->count();
  }
  static double ms_name(void* v) {
  	const char* n;
     int rval = 0;
     MechanismStandard* ms = (MechanismStandard*)v;
     if (ifarg(2)) {
  		n = ms->name((int)chkarg(2, 0, ms->count() - 1), rval);
     }else{
     	n = ms->name();
     }
     hoc_assign_str(hoc_pgargstr(1), n);
     hoc_return_type_code = 1;
     return double(rval);
  }
  
  static double ms_save(void* v) {
  #if HAVE_IV
  	ostream* o = Oc::save_stream;
  	if (o) {
  		((MechanismStandard*)v)->save(gargstr(1), o);
  	}
  #endif
  	return 0.;
  }
  
  static void* ms_cons(Object* ob) {
  	int vartype = nrnocCONST;
  	if (ifarg(2)) {
  		// 0 means all
  		vartype = int(chkarg(2, -1, STATE));
  	}
  	MechanismStandard* m = new MechanismStandard(gargstr(1), vartype);
  	m->ref();
  	m->msobj_ = ob;
  	return (void*)m;
  }
  
  static void ms_destruct(void* v) {
  	Resource::unref((MechanismStandard*)v);
  }
  
  static Member_func ms_members[] = {
  	"panel", ms_panel,
  	"action", ms_action,
  	"in", ms_in,
  	"_in", ms_in,
  	"out", ms_out,
  	"set", ms_set,
  	"get", ms_get,
  	"count", ms_count,
  	"name", ms_name,
  	"save", ms_save,
  	0, 0
  };
  
  void MechanismStandard_reg() {
  	class2oc("MechanismStandard", ms_cons, ms_destruct, ms_members, NULL, NULL, NULL);
  }
  
  MechanismStandard::MechanismStandard(const char* name, int vartype) {
  	msobj_ = NULL;
  	glosym_ = NULL;
  	np_ = new NrnProperty(name);
  	name_cnt_ = 0;
  	vartype_ = vartype; // vartype=0 means all but not globals, -1 means globals
  	offset_ = 0;
      if (vartype_ == -1) {
  	char suffix[100];
  	char* s;
  	sprintf(suffix, "_%s", name);
  	Symbol * sp;
  	for (sp = hoc_built_in_symlist->first; sp; sp = sp->next) {
  		if (sp->type == VAR && sp->subtype == USERDOUBLE
  		    && (s = strstr(sp->name, suffix)) != 0 
  		    && s[strlen(suffix)] == '\0'){
  			++name_cnt_;
  		}
  	}
  	glosym_ = new Symbol*[name_cnt_];
  	int i=0;
  	for (sp = hoc_built_in_symlist->first; sp; sp = sp->next) {
  		if (sp->type == VAR && sp->subtype == USERDOUBLE
  		    && (s = strstr(sp->name, suffix)) != 0 
  		    && s[strlen(suffix)] == '\0'){
  			glosym_[i] = sp;
  			++i;
  		}
  	}
      }else{
  	for (Symbol* sym = np_->first_var(); np_->more_var(); sym = np_->next_var()) {
  		int type = np_->var_type(sym);
  		if (type < vartype) {
  			++offset_;
  		}else if (vartype == 0 || type == vartype) {
  			++name_cnt_;
  		}
  	}
      }
  	action_ = "";
  	pyact_ = NULL;
  }
  MechanismStandard::~MechanismStandard() {
  	if (pyact_) {
  		hoc_obj_unref(pyact_);
  	}
  	if (glosym_) {
  		delete [] glosym_;
  	}
  	delete np_;
  }
  int MechanismStandard::count() {
  	return name_cnt_;
  }
  const char* MechanismStandard::name() {
  	return np_->name();
  }
  const char* MechanismStandard::name(int i, int& size) {
  	Symbol* s;
  	if (vartype_ == -1) {
  		s = glosym_[i];
  	}else{
  		s = np_->var(i+offset_);
  	}
  	size = hoc_total_array_data(s, 0);
  	return s->name;
  }
  
  void MechanismStandard::panel(const char* label) {
  #if HAVE_IV
  	mschk("panel");
  	char buf[256];
  	int i;
  	Symbol* sym;
  	hoc_ivpanel("MechanismStandard");
  	if (label) {
  		hoc_ivlabel(label);
  	}else{
  		hoc_ivlabel(np_->name());
  	}
  	for (sym = np_->first_var(), i=0; np_->more_var(); sym = np_->next_var(), ++i) {
  		if (vartype_ == 0 || np_->var_type(sym) == vartype_) {
  			Object* pyactval = NULL;
  			int size = hoc_total_array_data(sym, 0);
  			if (pyact_) {
  				assert(nrnpy_callable_with_args);
  				hoc_push_object(msobj_);
  				hoc_pushx(double(i));
  				hoc_pushx(0.0);
  				pyactval = (*nrnpy_callable_with_args)(pyact_, 3);
  			}else{
  				sprintf(buf, "hoc_ac_ = %d  %s", i, action_.string());
  			}
  			hoc_ivvaluerun_ex(sym->name,
  				NULL, np_->prop_pval(sym), NULL,
  				pyact_ ? NULL : buf, pyactval,
  				true, false, true, sym->extra);
  			if (pyactval) {
  				hoc_obj_unref(pyactval);
  			}
  			int j;
  			for (j=1; j < size; ++j) {
  				++i;
  				if (pyact_) {
  					assert(nrnpy_callable_with_args);
  					hoc_push_object(msobj_);
  					hoc_pushx(double(i));
  					hoc_pushx(double(j));
  					pyactval = (*nrnpy_callable_with_args)(pyact_, 3);
  				}else{
  					sprintf(buf, "hoc_ac_ = %d %s", i, action_.string());
  				}
  				char buf2[200];
  				sprintf(buf2, "%s[%d]", sym->name, j);
  				hoc_ivvaluerun_ex(buf2,
  					NULL, np_->prop_pval(sym, j), NULL,
  					pyact_ ? NULL : buf, pyact_,
  					true, false, true, sym->extra);
  				if (pyactval) { hoc_obj_unref(pyactval); }
  			}
  		}
  	}
  	hoc_ivpanelmap();
  #endif
  }
  void MechanismStandard::action(const char* action, Object* pyact){
  	mschk("action");
  	action_ = action ? action : "";
  	if (pyact) {
  		pyact_ = pyact;
  		hoc_obj_ref(pyact);
  	}
  }
  void MechanismStandard::set(const char* name, double val, int index){
  	mschk("set");
  	Symbol* s =  np_->find(name);
  	if (s) {
  		*np_->prop_pval(s, index) = val;
  	}else{
  		hoc_execerror(name, "not in this property");
  	}
  }
  double MechanismStandard::get(const char* name, int index){
  	mschk("get");
  	Symbol* s =  np_->find(name);
  	if (!s) {
  		hoc_execerror(name, "not in this property");
  	}
  	double* pval = np_->prop_pval(s, index);
  	if (!pval) {
  		return -1e300;
  	}
  	return *pval;
  }
  
  void MechanismStandard::in(Section* sec, double x){
  	mschk("in");
  	int i = 0;
  	if (x >= 0) {
  		i = node_index(sec, x);
  	}
  	Prop* p = nrn_mechanism(np_->type(), sec->pnode[i]);
  	NrnProperty::assign(p, np_->prop(), vartype_);
  }
  void MechanismStandard::in(Point_process* pp){
  	mschk("in");
  	NrnProperty::assign(pp->prop, np_->prop(), vartype_);
  }
  void MechanismStandard::in(MechanismStandard* ms){
  	mschk("in");
  	NrnProperty::assign(ms->np_->prop(), np_->prop(), vartype_);
  }
  
  void MechanismStandard::out(Section* sec, double x){
  	mschk("out");
  	if (x < 0) {
  		for (int i = 0; i < sec->nnode; ++i) {
  			Prop* p = nrn_mechanism(np_->type(), sec->pnode[i]);
  			NrnProperty::assign(np_->prop(), p, vartype_);
  		}
  	}else{
  		int i = node_index(sec, x);
  		Prop* p = nrn_mechanism(np_->type(), sec->pnode[i]);
  		NrnProperty::assign(np_->prop(), p, vartype_);
  	}
  }
  void MechanismStandard::out(Point_process* pp){
  	mschk("out");
  	NrnProperty::assign(np_->prop(), pp->prop, vartype_);
  }
  void MechanismStandard::out(MechanismStandard* ms){
  	mschk("out");
  	NrnProperty::assign(np_->prop(), ms->np_->prop(), vartype_);
  }
  
  void MechanismStandard::save(const char* obref, ostream* po) {
  	mschk("save");
  	ostream& o = *po;
  	char buf[256];
  	sprintf(buf, "%s = new MechanismStandard(\"%s\")", obref, np_->name());
  	o << buf << endl;
  	for (Symbol* sym = np_->first_var(); np_->more_var(); sym = np_->next_var()) {
  		if (vartype_ == 0 || np_->var_type(sym) == vartype_) {
  			int i, cnt = hoc_total_array_data(sym, 0);
  			for (i=0; i < cnt; ++i) {
  				sprintf(buf, "%s.set(\"%s\", %g, %d)", obref, sym->name,
  					*np_->prop_pval(sym, i), i);
  				o << buf << endl;
  			}
  		}
  	}
  }
  
  void MechanismStandard::mschk(const char* s) {
  	if (vartype_ == -1) {
  		hoc_execerror(s, " MechanismStandard method not implemented for GLOBAL type");
  	}
  }
  
  /*
  help MembraneType
  listin nrniv
  Provides a way of iterating over all membrane mechanisms or point
  processes and allows selection via a menu or under hoc control.
  
  mt = new MembraneType(0)
  The object can be considered a list of all the available continuous
  membrane mechanisms. eg "hh", "pas", "extracellular". that can
  be inserted into a section.
  
  mt = new MembraneType(1)
  The object can be considered a list of all available Point Processes.
  eg. PulseStim, AlphaSynapse, VClamp.
  
  To print the names of all mechanisms in this object list try:
  strdef mname
  for i=0,mt.count() {
  	mt.select(i)
    mt.selected(mname)
  	print mname
  }
  
  help select
  mt.select("name")
  mt.select(i)
  selects either the named mechanism or the i'th mechanism in the list.
  
  help selected
  i = mt.selected([strdef])
  returns the index of the current selection.  If present, strarg is assigned
  to the name of the current selection.
  
  help make
  mt.make()
  For continuous mechanisms. Inserts selected mechanism into currently
  accessed section.
  
  help remove
  mt.remove()
  For continuous mechanisms. Deletes selected mechanism from currently
  accessed section. A nop if the mechanism is not in the section.
  
  help make
  mt.make(objectvar)
  For point processes.  The arg becomes a reference to a new point process
  of type given by the selection.
  Note that the newly created point process is not located in any section.
  Note that if objectvar was the only reference to another object then
  that object is destroyed.
  
  help count
  i = mt.count()
  The number of  different mechanisms in the list.
  
  help menu
  mt.menu()
  Inserts a special menu into the currently open xpanel. The menu
  label always reflects the current selection. Submenu items are indexed
  according to position with the first item being item 0.  When the mouse
  button is released on a submenu item that item becomes the selection
  and the action (if any) is executed.
  
  help action
  mt.action("command")
  The action to be executed when a submenu item is selected.
  */
  
  static double mt_select(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	if (hoc_is_double_arg(1)) {
  		mt->select(int(chkarg(1,  -1,  mt->count() - 1)));
  	}else if (hoc_is_str_arg(1)) {
  		mt->select(gargstr(1));
  	}
  	return 0.;
  }
  static double mt_selected(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	int i = mt->selected_item();
  	if (ifarg(1)) {
  		hoc_assign_str(hoc_pgargstr(1), mt->selected());
  	}
  	hoc_return_type_code = 1;
  	return double(i);
  }
  static double mt_internal_type(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	return double(mt->internal_type());
  }
  static double mt_make(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	if (mt->is_point()) {
  		mt->point_process(hoc_objgetarg(1));
  	}else{
  		mt->insert(chk_access());
  	}
  	return 0.;
  }
  static double mt_remove(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	mt->remove(chk_access());
  	return 0.;
  }
  static double mt_count(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	hoc_return_type_code = 1;
  	return double(mt->count());
  }
  static double mt_menu(void* v) {
  #if HAVE_IV
  IFGUI
  	MechanismType* mt = (MechanismType*)v;
  	mt->menu();
  ENDGUI
  #endif
  	return 0.;
  }
  static double mt_action(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	if (hoc_is_str_arg(1)) {
  		mt->action(gargstr(1), NULL);
  	}else{
  		mt->action(NULL, *hoc_objgetarg(1));
  	}
  	return 0.;
  }
  static double mt_is_target(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	hoc_return_type_code = 2;
  	return double(mt->is_netcon_target(int(chkarg(1, 0, mt->count()))));
  }
  static double mt_has_net_event(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	hoc_return_type_code = 2;
  	return double(mt->has_net_event(int(chkarg(1, 0, mt->count()))));
  }
  static double mt_is_artificial(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	hoc_return_type_code = 2;
  	return double(mt->is_artificial(int(chkarg(1, 0, mt->count()))));
  }
  static Object** mt_pp_begin(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	Point_process* pp = mt->pp_begin();
  	Object* obj = NULL;
  	if (pp) {
  		obj = pp->ob;
  	}
  	return hoc_temp_objptr(obj);
  }
  
  static Object** mt_pp_next(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	Point_process* pp = mt->pp_next();
  	Object* obj = NULL;
  	if (pp) {
  		obj = pp->ob;
  	}
  	return hoc_temp_objptr(obj);
  }
  
  extern const char** nrn_nmodl_text_;
  static const char** mt_code(void* v) {
    static const char* nullstr = "";
    MechanismType* mt = (MechanismType*)v;
    int type = mt->internal_type();
    const char** p = nrn_nmodl_text_ + type;
    if (*p) {
      return p;
    }
    return &nullstr;
  }
  
  extern const char** nrn_nmodl_filename_;
  static const char** mt_file(void* v) {
    static const char* nullstr = "";
    MechanismType* mt = (MechanismType*)v;
    int type = mt->internal_type();
    const char** p = nrn_nmodl_filename_ + type;
    if (*p) {
      return p;
    }
    return &nullstr;
  }
  
  static void* mt_cons(Object* obj) {
  	MechanismType* mt = new MechanismType(int(chkarg(1, 0, 1)));
  	mt->ref();
  	mt->mtobj_ = obj;
  	return (void*)mt;
  }
  static void mt_destruct(void* v) {
  	MechanismType* mt = (MechanismType*)v;
  	mt->unref();
  }
  static Member_func mt_members[] = {
  	"select", mt_select,
  	"selected", mt_selected,
  	"make", mt_make,
  	"remove", mt_remove,
  	"count", mt_count,
  	"menu", mt_menu,
  	"action", mt_action,
  	"is_netcon_target", mt_is_target,
  	"has_net_event", mt_has_net_event,
  	"is_artificial", mt_is_artificial,
  	"internal_type", mt_internal_type,
  	0,0
  };
  static Member_ret_obj_func mt_retobj_members[] = {
  	"pp_begin", mt_pp_begin,
  	"pp_next", mt_pp_next,
  	0,0
  };
  static Member_ret_str_func mt_retstr_func[] = {
  	"code", mt_code,
  	"file", mt_file,
  	0,0
  };
  void MechanismType_reg() {
  	class2oc("MechanismType", mt_cons, mt_destruct, mt_members,
  		NULL, mt_retobj_members, mt_retstr_func);
  }
  
  /* static */ class MechTypeImpl {
  private:
  	friend class MechanismType;
  	bool is_point_;
  	int* type_;
  	int count_;
  	int select_;
  	CopyString action_;
  	Object* pyact_;
  	Section* sec_iter_;
  	int inode_iter_;
  	Prop* p_iter_;
  };
  
  typedef Symbol* PSym;
  
  MechanismType::MechanismType(bool point_process){
  	mti_ = new MechTypeImpl;
  	mti_->is_point_ = point_process;
  	mti_->count_ = 0;
  	int i;
  	for (i=2; i < n_memb_func; ++i) {
  		if (point_process == memb_func[i].is_point) {
  			++mti_->count_;
  		}
  	}
  	mti_->type_ = new int[mti_->count_];
  	int j=0;
  	for (i=2; i < n_memb_func; ++i) {
  		if (point_process == memb_func[i].is_point) {
  			mti_->type_[j] = i;
  			++j;
  		}
  	}
  	mti_->pyact_ = NULL;
  	action("", NULL);
  	select(0);
  }
  MechanismType::~MechanismType(){
  	if (mti_->pyact_) {
  		hoc_obj_unref(mti_->pyact_);
  	}
  	delete [] mti_->type_;
  	delete mti_;
  }
  bool MechanismType::is_point() {
  	return mti_->is_point_;
  }
  
  Point_process* MechanismType::pp_begin() {
  	if (!mti_->is_point_) {
  		hoc_execerror("Not a MechanismType(1)", 0);
  	}
  	mti_->sec_iter_ = chk_access();
  	nrn_parent_info(mti_->sec_iter_);
  	mti_->p_iter_ = 0;
  	if (mti_->sec_iter_->parentnode) {
  		mti_->inode_iter_ = -1;
  		mti_->p_iter_ = mti_->sec_iter_->parentnode->prop;
  	}
  	if (!mti_->p_iter_) {
  		mti_->inode_iter_ = 0;
  		mti_->p_iter_ = mti_->sec_iter_->pnode[0]->prop;
  	}
  	Point_process* pp = pp_next(); // note that p_iter is the one looked at and then incremented
  	return pp;
  }
  
  Point_process* MechanismType::pp_next() {
  	Point_process* pp = NULL;
  	bool done = mti_->p_iter_ == 0;
  	while (!done) {
  		if (mti_->p_iter_->type == mti_->type_[mti_->select_]) {
  			pp = (Point_process*)mti_->p_iter_->dparam[1]._pvoid;
  			done = true;
  			// but if it does not belong to this section
  			if (pp->sec != mti_->sec_iter_) {
  				pp = NULL;
  				done = false;
  			}
  		}
  		mti_->p_iter_ = mti_->p_iter_->next;
  		while (!mti_->p_iter_) {
  			++mti_->inode_iter_;
  			if (mti_->inode_iter_ >= mti_->sec_iter_->nnode) {
  				done = true;
  				break; // really at the end
  			}else{
  				mti_->p_iter_ = mti_->sec_iter_->pnode[mti_->inode_iter_]->prop;
  			}
  		}
  	}
  	return pp;
  }
  
  bool MechanismType::is_netcon_target(int i) {
  	int j = mti_->type_[i];
  	return pnt_receive[j] ? true : false;
  }
  
  bool MechanismType::has_net_event(int i) {
  	int j = mti_->type_[i];
  	int k;
  	for (k=0; k < nrn_has_net_event_cnt_; ++k) {
  		if (nrn_has_net_event_[k] == j) {
  			return true;
  		}
  	}
  	return false;
  }
  
  bool MechanismType::is_artificial(int i) {
  	int j = mti_->type_[i];
  	return (nrn_is_artificial_[j] ? true:false);
  }
  
  void MechanismType::select(const char* name){
  	for (int i=0; i < mti_->count_; ++i) {
  		if (strcmp(name, memb_func[mti_->type_[i]].sym->name) == 0) {
  			select(i);
  			break;
  		}
  	}
  }
  const char* MechanismType::selected(){
  	Symbol* sym = memb_func[mti_->type_[selected_item()]].sym;
  	return sym->name;
  }
  int MechanismType::internal_type() {
  	return mti_->type_[selected_item()];
  }
  extern "C" {
  extern void mech_insert1(Section*, int);
  extern void mech_uninsert1(Section*, Symbol*);
  }
  void MechanismType::insert(Section* sec){
  	if (!mti_->is_point_) {
  		mech_insert1(sec, memb_func[mti_->type_[selected_item()]].sym->subtype);
  	}
  }
  void MechanismType::remove(Section* sec){
  	if (!mti_->is_point_) {
  		mech_uninsert1(sec, memb_func[mti_->type_[selected_item()]].sym);
  	}
  }
  
  extern "C" {extern Object* nrn_new_pointprocess(Symbol*);}
  
  void MechanismType::point_process(Object** o){
  	Symbol* sym = memb_func[mti_->type_[selected_item()]].sym;
  	hoc_dec_refcount(o);
  	*o = nrn_new_pointprocess(sym);
  	(*o)->refcount = 1;
  }
  
  void MechanismType::action(const char* action, Object* pyact){
  	mti_->action_ = action ? action : "";
  	if (pyact) {
  		hoc_obj_ref(pyact);
  	}
  	if (mti_->pyact_) {
  		hoc_obj_unref(mti_->pyact_);
  		mti_->pyact_ = NULL;
  	}
  	mti_->pyact_ = pyact;
  }
  void MechanismType::menu(){
  #if HAVE_IV
  	char buf[200];
  	Oc oc;
  	oc.run("{xmenu(\"MechType\")}\n");
  	for (int i=0; i < mti_->count_; ++i) {
  	    Symbol* s = memb_func[mti_->type_[i]].sym;
  	    if (s->subtype != MORPHOLOGY) {
  		if (mti_->pyact_) {
  			assert(nrnpy_callable_with_args);
  			hoc_push_object(mtobj_);
  			hoc_pushx(double(i));
  			Object* pyactval = (*nrnpy_callable_with_args)(mti_->pyact_, 2);
  			hoc_ivbutton(s->name, NULL, pyactval);
  			hoc_obj_unref(pyactval);
  		}else {
  			sprintf(buf, "xbutton(\"%s\", \"hoc_ac_=%d %s\")\n",
  				s->name, i, mti_->action_.string()
  			);
  			oc.run(buf);
  		}
  	    }
  	}
  	oc.run("{xmenu()}\n");
  #endif
  }
  
  int MechanismType::count(){
  	return mti_->count_;
  }
  int MechanismType::selected_item(){
  	return mti_->select_;
  }
  void MechanismType::select(int index){
  	if (index < 0) {
  		mti_->select_ = index;
  	}else if (index >= count()) {
  		mti_->select_ = count() - 1;
  	}else{
  		mti_->select_ = index;
  	}
  }
  