NEURON
hoc.cpp
Go to the documentation of this file.
1 #ifndef __INTEL_LLVM_COMPILER
2 #ifdef __clang__
3 #pragma float_control(precise, on)
4 #endif
5 #pragma STDC FENV_ACCESS ON
6 #endif
7 
8 #include <../../nrnconf.h>
9 #include "hocstr.h"
10 #include "equation.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <math.h>
17 #include <errno.h>
18 #include "parse.hpp"
19 #include "hocparse.h"
20 #include "oc_ansi.h"
21 #include "ocjump.h"
22 #include "ocfunc.h"
23 #include "ocmisc.h"
24 #include "nrnmpi.h"
25 #include "nrnpy.h"
26 #include "nrnfilewrap.h"
27 #include "../nrniv/backtrace_utils.h"
28 
29 #include "../utils/profile/profiler_interface.h"
30 
31 #include <cfenv>
32 #include <condition_variable>
33 #include <filesystem>
34 #include <iostream>
35 #include <mutex>
36 #include <thread>
37 #include <utility>
38 
39 #include "utils/logger.hpp"
40 
41 /* for eliminating "ignoreing return value" warnings. */
43 
44 /* only set in ivoc */
47 
48 #if defined(USE_PYTHON)
49 int use_python_interpreter = 0;
50 void (*p_nrnpython_finalize)();
51 #endif
53 int (*p_nrnpy_pyrun)(const char* fname);
54 
55 #if 0 /* defined by cmake if rl_event_hook is not available */
56 #define use_rl_getc_function
57 #endif
58 
59 #if defined(MINGW)
60 extern int stdin_event_ready();
61 #endif
62 
63 #define FEEXCEPT (FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW)
64 static void matherr1(void) {
65  const int e = std::fetestexcept(FEEXCEPT);
66  /* above gives the signal but for some reason fegetexcept returns 0 */
67  switch (e) {
68  case FE_DIVBYZERO:
69  fprintf(stderr, "Floating exception: Divide by zero\n");
70  break;
71  case FE_INVALID:
72  fprintf(stderr, "Floating exception: Invalid (no well defined result\n");
73  break;
74  case FE_OVERFLOW:
75  fprintf(stderr, "Floating exception: Overflow\n");
76  break;
77  }
78 }
79 
81 
82 int nrn_feenableexcept_ = 0; // 1 if feenableexcept(FEEXCEPT) is successful
83 
85  int result = -2; // feenableexcept does not exist.
87 #if NRN_FLOAT_EXCEPTION
88  if (ifarg(1) && chkarg(1, 0., 1.) == 0.) {
89  result = fedisableexcept(FEEXCEPT);
90  } else {
91  result = feenableexcept(FEEXCEPT);
92  nrn_feenableexcept_ = (result == -1) ? 0 : 1;
93  }
94 #endif
95  hoc_ret();
96  hoc_pushx((double) result);
97 }
98 
99 void start_profile(int i) {}
100 void add_profile(int i) {}
101 void pr_profile(void) {}
102 
103 #if OCSMALL
104 #define READLINE 0
105 #endif
106 
107 #ifndef READLINE
108 #define READLINE 1
109 #endif
110 
111 #if READLINE
112 extern "C" {
113 extern char* readline(const char* prompt);
114 extern void rl_deprep_terminal(void);
115 extern void add_history(const char*);
116 }
117 #endif
118 
122 #if 1
123 /* no longer necessary to distinguish signed from unsigned since EOF
124  never stored in a buffer.
125  */
126 #define CHAR char
127 #else
128 #if - 1 == '\377'
129 #define CHAR char
130 #else
131 #define CHAR signed char
132 #endif
133 #endif
134 /* buffers will grow automatically if an input line exceeds the following*/
135 #define TMPBUFSIZE 512
136 #define CBUFSIZE 512
139 const char* hoc_promptstr;
140 static CHAR* hoc_cbuf;
143 
144 extern char* neuron_home;
145 extern int hoc_print_first_instance;
146 
147 #define EPS hoc_epsilon
148 /*
149 used to be a FILE* but had fopen problems when 128K cores on BG/P
150 tried to fopen the same file for reading at once.
151 */
152 NrnFILEWrap* hoc_fin; /* input file pointer */
153 
154 #include <ctype.h>
155 const char* progname; /* for error messages */
157 
158 #if HAVE_EXECINFO_H
159 #include <execinfo.h>
160 #endif
161 #include <signal.h>
162 int hoc_intset; /* safer interrupt handling */
164 const char* infile; /* input file name */
165 extern size_t hoc_xopen_file_size_;
166 extern char* hoc_xopen_file_;
167 const char** gargv; /* global argument list */
168 int gargc;
169 static int c = '\n'; /* global for use by warning() */
170 
171 #if defined(WIN32)
172 void set_intset() {
173  hoc_intset++;
174 }
175 extern void ivoc_win32_cleanup();
176 #endif
177 
178 static int follow(int expect, int ifyes, int ifno); /* look ahead for >=, etc. */
179 static int Getc(NrnFILEWrap* fp);
180 static void unGetc(int c, NrnFILEWrap* fp);
181 static int backslash(int c);
182 
183 [[noreturn]] void nrn_exit(int i) {
184 #if defined(WIN32)
185  printf("NEURON exiting abnormally, press return to quit\n");
186  fgetc(stdin);
187 #endif
188  exit(i);
189 }
190 
191 #if defined(WIN32)
192 #define HAS_SIGPIPE 0
193 #else
194 #define HAS_SIGPIPE 1
195 #endif
196 #if HAS_SIGPIPE
197 /*ARGSUSED*/
198 static void sigpipe_handler(int sig) {
199  fprintf(stderr, "writing to a broken pipe\n");
200  signal(SIGPIPE, sigpipe_handler);
201 }
202 #endif
203 
204 int getnb(void) /* get next non-white character */
205 {
206  int c;
207 
208  /*EMPTY*/
209  while ((c = Getc(hoc_fin)) == ' ' || c == '\t') {
210  ;
211  }
212  return c;
213 }
214 
215 /* yylex modified to return -3 when at end of hoc_cbuf. The parser can
216  return and take up where it left off later. Supported by modification
217  of bison.simple to allow event driven programming.
218 */
219 #define YYNEEDMORE -3
220 /* for now we say comments or strings that span lines on stdin are in error */
221 #if 0
222 #define INCOMMENT 1;
223 #define INSTRING 2;
224 static int lexstate = 0;
225 #endif
226 /* sometimes is... doesn't work with -3. Hence Getc returns null and look
227  at eos to see if true.*/
228 static int eos;
229 
230 static char* optarray(char* buf) {
231  int c;
232  if ((c = Getc(hoc_fin)) == '[') {
233  char* s = buf + strlen(buf);
234  *s++ = c;
235  while (isdigit(c = Getc(hoc_fin)) && (s - buf) < 200) {
236  *s++ = c;
237  }
238  if (c == ']') {
239  *s++ = c;
240  *s = '\0';
241  } else {
242  *s = '\0';
243  hoc_acterror(buf, " not literal name[int]");
244  }
245  } else {
246  unGetc(c, hoc_fin);
247  }
248  return buf;
249 }
250 
251 int yylex(void) /* hoc6 */
252 {
253 restart: /* when no token in between comments */
254  eos = 0;
255 #if 0 /* do we really want to have several states? */
256  switch (lexstate) {
257 
258  case INCOMMENT:
259  goto incomment;
260  case INSTRING:
261  goto instring;
262  }
263 #endif
264 
265  if ((c = getnb()) == EOF) {
266  return 0;
267  }
268  if (c == '/' && follow('*', 1, 0)) /* comment */
269  {
270  while ((c = Getc(hoc_fin)) != '*' || follow('/', 0, 1)) {
271  if (c == EOF)
272  return (0);
273  /* if (c == YYNEEDMORE) {*/
274  if (eos) {
275  hoc_acterror("comment not complete", " in hoc_cbuf");
276  }
277  }
278  goto restart;
279  }
280  if (c == '.' || isdigit(c)) /* number */
281  {
282  char* npt;
283  double d;
284  IGNORE(unGetc(c, hoc_fin));
285  npt = (char*) hoc_ctp;
286  /*EMPTY*/
287  while (isdigit(c = Getc(hoc_fin))) {
288  ;
289  }
290  if (c == '.') {
291  /*EMPTY*/
292  while (isdigit(c = Getc(hoc_fin))) {
293  ;
294  }
295  }
296  if (*npt == '.' && !isdigit(npt[1])) {
297  IGNORE(unGetc(c, hoc_fin));
298  return (int) (*npt);
299  }
300  if (c == 'E' || c == 'e') {
301  if (isdigit(c = Getc(hoc_fin)) || c == '+' || c == '-') {
302  /*EMPTY*/
303  while (isdigit(c = Getc(hoc_fin))) {
304  ;
305  }
306  }
307  }
308  IGNORE(unGetc(c, hoc_fin));
309  IGNORE(sscanf(npt, "%lf", &d));
310  if (d == 0.)
311  return NUMZERO;
312  yylval.sym = hoc_install("", NUMBER, d, &hoc_p_symlist);
313  return NUMBER;
314  }
315  if (isalpha(c) || c == '_') {
316  Symbol* s;
317  char sbuf[256], *p = sbuf;
318  do {
319  if (p >= (sbuf + 255)) {
320  sbuf[255] = '\0';
321  hoc_execerror("Name too long:", sbuf);
322  }
323  *p++ = c;
324  } while ((c = Getc(hoc_fin)) != EOF && (isalnum(c) || c == '_'));
325  IGNORE(unGetc(c, hoc_fin));
326  *p = '\0';
327  if (strncmp(sbuf, "__nrnsec_0x", 11) == 0) {
328  yylval.ptr = hoc_sec_internal_name2ptr(sbuf, 1);
329  return INTERNALSECTIONNAME;
330  }
331  /* _pysec.name[int] or _pysec.name[int].name[int] where
332  [int] is optional must resolve to Section at parse time.
333  void* nrn_parsing_pysec_ is 1 to signal the beginning
334  of parsing and as a sub-dictionary pointer in case the
335  first level __psec.name[int] is the name of a cell.
336  On error or success in parse.ypp, nrn_parsing_pysec_ is
337  set back to NULL.
338  */
339  if (strcmp(sbuf, "_pysec") == 0) {
340  if (c != '.') {
341  hoc_acterror(
342  "Must be of form _pysec.secname where secname is the literal result of "
343  "nrn.Section.name() .",
344  NULL);
345  }
346  yylval.ptr = NULL;
347  nrn_parsing_pysec_ = (void*) 1;
348  return PYSEC;
349  }
350  if (nrn_parsing_pysec_) {
351  yylval.ptr = hoc_pysec_name2ptr(optarray(sbuf), 1);
352  if (nrn_parsing_pysec_ > (void*) 1) { /* there will be a second part */
353  c = Getc(hoc_fin);
354  unGetc(c, hoc_fin);
355  if (c != '.') { /* so there must be a . */
357  hoc_acterror(
358  "Must be of form _pysec.cellname.secname where cellname.secname is the "
359  "literal result of nrn.Section.name() .",
360  NULL);
361  }
362  }
363  if (yylval.ptr == NULL) {
364  return PYSECOBJ;
365  } else {
367  return PYSECNAME;
368  }
369  }
370  if ((s = hoc_lookup(sbuf)) == 0)
371  s = hoc_install(sbuf, UNDEF, 0.0, &hoc_symlist);
372  yylval.sym = s;
373  return s->type == UNDEF ? VAR : s->type;
374  }
375  if (c == '$') { /* argument? */
376  int ith;
377  int n = 0;
378  int retval = follow('o', OBJECTARG, ARG);
379  if (retval == ARG)
380  retval = follow('s', STRINGARG, ARG);
381  if (retval == ARG)
382  retval = follow('&', ARGREF, ARG);
383  ith = follow('i', 1, 0);
384  if (ith) {
385  yylval.narg = 0;
386  return retval;
387  }
388  while (isdigit(c = Getc(hoc_fin)))
389  n = 10 * n + c - '0';
390  IGNORE(unGetc(c, hoc_fin));
391  if (n == 0)
392  hoc_acterror("strange $...", (char*) 0);
393  yylval.narg = n;
394  return retval;
395  }
396  if (c == '"') /* quoted string */
397  {
398  static HocStr* sbuf;
399  char* p;
400  int n;
401  if (!sbuf) {
402  sbuf = hocstr_create(256);
403  }
404  for (p = sbuf->buf; (c = Getc(hoc_fin)) != '"'; p++) {
405  if (c == '\n' || c == EOF || c == YYNEEDMORE)
406  hoc_acterror("missing quote", "");
407  n = p - sbuf->buf;
408  if (n >= sbuf->size - 1) {
409  hocstr_resize(sbuf, n + 200);
410  p = sbuf->buf + n;
411  }
412  *p = backslash(c);
413  }
414  *p = 0;
415  yylval.sym = hoc_install("", CSTRING, 0.0, &hoc_p_symlist);
416 
417  (yylval.sym)->u.cstr = (char*) emalloc((unsigned) (strlen(sbuf->buf) + 1));
418  Strcpy((yylval.sym)->u.cstr, sbuf->buf);
419  return CSTRING;
420  }
421  switch (c) {
422  case 0: {
423  if (eos)
424  return YYNEEDMORE;
425  else
426  return 0;
427  }
428  case '>':
429  return follow('=', GE, GT);
430  case '<':
431  return follow('=', LE, LT);
432  case '!':
433  return follow('=', NE, NOT);
434 
435  case '+':
436  case '-':
437  case '*': {
438  if (follow('=', 1, 0)) {
439  yylval.narg = c;
440  return ROP;
441  } else {
442  return c;
443  }
444  }
445  case '=': {
446  if (follow('=', EQ, '=') == EQ) {
447  return EQ;
448  }
449  if (hoc_do_equation) {
450  return EQNEQ;
451  }
452  yylval.narg = 0;
453  return ROP;
454  }
455  case '|':
456  return follow('|', OR, '|');
457  case '&':
458  return follow('&', AND, '&');
459  case '\\': {
460  int i; /* continuation line if last char in line is \ */
461  i = follow('\n', 1000, '\\');
462  if (i == 1000) {
463  return yylex();
464  }
465  return i;
466  }
467  case '\r':
468  return follow('\n', '\n', '\n');
469  case '\n':
470  return '\n';
471  case '/':
472  if (follow('/', 1, 0)) {
473  while (*hoc_ctp) {
474  ++hoc_ctp;
475  }
476  return '\n';
477  } else if (follow('=', 1, 0)) {
478  yylval.narg = c;
479  return ROP;
480  } else {
481  return '/';
482  }
483  default:
484  return c;
485  }
486 }
487 
488 static int backslash(int c) { /* get next char with \'s interpreted */
489  static char transtab[] = "b\bf\fn\nr\rt\t";
490  if (c != '\\')
491  return c;
492  c = Getc(hoc_fin);
493  if (islower(c) && strchr(transtab, c))
494  return strchr(transtab, c)[1];
495  return c;
496 }
497 
498 static int follow(int expect, int ifyes, int ifno) /* look ahead for >=, etc. */
499 {
500  int c = Getc(hoc_fin);
501 
502  if (c == expect)
503  return ifyes;
504  IGNORE(unGetc(c, hoc_fin));
505  return ifno;
506 }
507 
508 void hoc_arayinstal(void) /* allocate storage for arrays */
509 {
510  int i, nsub;
511  Symbol* sp;
512 
513  nsub = (hoc_pc++)->i;
514  sp = hoc_spop();
515 
516  hoc_freearay(sp);
517  sp->type = VAR;
518  sp->s_varn = 0;
519  i = hoc_arayinfo_install(sp, nsub);
520  if ((OPVAL(sp) = (double*) hoc_Ecalloc((unsigned) i, sizeof(double))) == (double*) 0) {
521  hoc_freearay(sp);
522  Fprintf(stderr, "Not enough space for array %s\n", sp->name);
523  hoc_malchk();
524  hoc_execerror("", (char*) 0);
525  }
526 }
527 
528 int hoc_arayinfo_install(Symbol* sp, int nsub) {
529  double total, subscpt;
530  int i;
532  sp->arayinfo = (Arrayinfo*) emalloc((unsigned) (sizeof(Arrayinfo) + nsub * sizeof(int)));
533  /*printf("emalloc arrayinfo at %lx\n", sp->arayinfo);*/
534  sp->arayinfo->a_varn = (unsigned*) 0;
535  sp->arayinfo->nsub = nsub;
536  sp->arayinfo->refcount = 1;
537  total = 1.;
538  while (nsub) {
539  subscpt = floor(hoc_xpop() + EPS);
540  if (subscpt <= 0.)
541  hoc_execerror("subscript < 1", sp->name);
542  total = total * subscpt;
543  sp->arayinfo->sub[--nsub] = (int) subscpt;
544  }
545  if (total > 2e9) {
546  /*
547  following gives purify uninitialized memory read and cannot work
548  around it with anything involving i. Must be a bug in purify because
549  the i=(int)total gives the UMR when it is just above this if statement.
550  but no UMR if in present location just above return.
551  if ( (double)(i = (int)total) != total) {
552  */
553  free((char*) sp->arayinfo);
554  sp->arayinfo = (Arrayinfo*) 0;
555  hoc_execerror(sp->name, ":total subscript too large");
556  }
557  if (OPARINFO(sp)) {
558  /* probably never get here */
560  }
561  OPARINFO(sp) = sp->arayinfo;
562  ++sp->arayinfo->refcount;
563  i = (int) total;
564  return i;
565 }
566 
567 void hoc_freearay(Symbol* sp) {
568  Arrayinfo** pa = &(OPARINFO(sp));
569  if (sp->type == VAR) {
571  sp->type = UNDEF;
572  }
573  hoc_free_arrayinfo(*pa);
575  sp->arayinfo = (Arrayinfo*) 0;
576  *pa = (Arrayinfo*) 0;
577 }
578 
580  if (a != (Arrayinfo*) 0) {
581  if ((--a->refcount) <= 0) {
582  if (a->a_varn != (unsigned*) 0)
583  free((char*) (a->a_varn));
584  free((char*) a);
585  /* printf("free arrayinfo at %lx\n", a);*/
586  }
587  }
588 }
589 
590 void hoc_defnonly(const char* s) { /* warn if illegal definition */
591  if (!hoc_indef)
592  hoc_acterror(s, "used outside definition");
593 }
594 
595 /* messages can turned off but the user had better check the return
596 value of oc_run()
597 */
598 static int debug_message_;
600  double x;
601  x = chkarg(1, 0., 1.);
602  debug_message_ = (int) x;
603  hoc_ret();
604  hoc_pushx(x);
605 }
606 
610 
611 void hoc_execerror_mes(const char* s, const char* t, int prnt) { /* recover from run-time error */
612  hoc_in_yyparse = 0;
613  yystart = 1;
614  hoc_errno_check();
615  if (debug_message_ || prnt) {
616  hoc_warning(s, t);
617  frame_debug();
618  nrn_err_dialog(s);
619  }
620  // In case hoc_warning not called
621  hoc_ctp = hoc_cbuf;
622  *hoc_ctp = '\0';
623  // There used to be some logic here to abort here if we are inside an OcJump call.
624 #if NRNMPI
626  nrnmpi_abort(-1);
627  }
628 #endif
630  if (hoc_fin && hoc_pipeflag == 0 && (!nrn_fw_eq(hoc_fin, stdin) || !nrn_istty_)) {
631  IGNORE(nrn_fw_fseek(hoc_fin, 0L, 2)); /* flush rest of file */
632  }
633 
634  // If the exception is due to a multiple ^C interrupt, then onintr
635  // will not exit normally (because of the throw below) and the signal
636  // would remain in a SIG_BLOCK state.
637  // It is not clear to me if this would be better done in every catch.
638 #if HAVE_SIGPROCMASK
639  if (hoc_intset > 1) {
640  sigset_t set;
641  sigemptyset(&set);
642  sigaddset(&set, SIGINT);
643  sigprocmask(SIG_UNBLOCK, &set, NULL);
644  }
645 #endif // HAVE_SIGPROCMASK
646 
647  hoc_intset = 0;
649  std::string message{"hoc_execerror: "};
650  message.append(s);
651  if (t) {
652  message.append(1, ' ');
653  message.append(t);
654  }
655  throw neuron::oc::runtime_error(std::move(message));
656 }
657 
658 void hoc_execerror(const char* s, const char* t) /* recover from run-time error */
659 {
661 }
662 
663 void onintr(int /* sig */) /* catch interrupt */
664 {
665  /*ARGSUSED*/
666  stoprun = 1;
667  if (hoc_intset++)
668  hoc_execerror("interrupted", (char*) 0);
669  IGNORE(signal(SIGINT, onintr));
670 }
671 
672 static int coredump;
673 
675  coredump = 1;
676  hoc_ret();
677  hoc_pushx(1.);
678 }
679 
680 void print_bt() {
681 #ifdef USE_BACKWARD
683 #else
684 #if HAVE_EXECINFO_H
685  const size_t nframes = 12;
686  void* frames[nframes];
687  size_t size;
688  char** bt_strings = NULL;
689  // parsed elements from stacktrace line:
690  size_t funcname_size = 256;
691  // symbol stores the symbol at which the signal was invoked
692  char* symbol = static_cast<char*>(malloc(sizeof(char) * funcname_size));
693  // the function name where the signal was invoked
694  char* funcname = static_cast<char*>(malloc(sizeof(char) * funcname_size));
695  // offset stores the relative address from the function where the signal was invoked
696  char* offset = static_cast<char*>(malloc(sizeof(char) * 10));
697  // the memory address of the function
698  void* addr = NULL;
699  // get void*'s for maximum last 16 entries on the stack
700  size = backtrace(frames, nframes);
701 
702  // print out all the frames to stderr
703  Fprintf(stderr, "Backtrace:\n");
704  // get the stacktrace as an array of strings
705  bt_strings = backtrace_symbols(frames, size);
706  if (bt_strings) {
707  size_t i;
708  // start printing at third frame to skip the signal handler and printer function
709  for (i = 2; i < size; ++i) {
710  // parse the stack frame line
711  int status = parse_bt_symbol(bt_strings[i], &addr, symbol, offset);
712  if (status) {
713  status = cxx_demangle(symbol, &funcname, &funcname_size);
714  if (status == 0) { // demangling worked
715  Fprintf(stderr, "\t%s : %s+%s\n", bt_strings[i], funcname, offset);
716  } else { // demangling failed, fallback
717  Fprintf(stderr, "\t%s : %s()+%s\n", bt_strings[i], symbol, offset);
718  }
719  } else { // could not parse, simply print the stackframe as is
720  Fprintf(stderr, "\t%s\n", bt_strings[i]);
721  }
722  }
723  free(bt_strings);
724  }
725  free(funcname);
726  free(offset);
727  free(symbol);
728 #else
729  Fprintf(stderr, "No backtrace info available.\n");
730 #endif
731 #endif
732 }
733 
734 void fpecatch(int /* sig */) /* catch floating point exceptions */
735 {
736  /*ARGSUSED*/
737 #if NRN_FLOAT_EXCEPTION
738  matherr1();
739 #endif
740  Fprintf(stderr, "Floating point exception\n");
741  print_bt();
742  if (coredump) {
743  abort();
744  }
745  signal(SIGFPE, fpecatch);
746  hoc_execerror("Floating point exception.", (char*) 0);
747 }
748 
749 __attribute__((noreturn)) void sigsegvcatch(int /* sig */) /* segmentation violation probably due to
750  arg type error */
751 {
752  Fprintf(stderr, "Segmentation violation\n");
753  print_bt();
754  /*ARGSUSED*/
755  if (coredump) {
756  abort();
757  }
758  hoc_execerror("Aborting.", (char*) 0);
759 }
760 
761 #if HAVE_SIGBUS
762 __attribute__((noreturn)) void sigbuscatch(int /* sig */) {
763  Fprintf(stderr, "Bus error\n");
764  print_bt();
765  /*ARGSUSED*/
766  if (coredump) {
767  abort();
768  }
769  hoc_execerror("Aborting. ", "See $NEURONHOME/lib/help/oc.help");
770 }
771 #endif
772 
773 int hoc_pid(void) {
774  return (int) getpid();
775 } /* useful for making unique temporary file names */
776 
777 /* readline should be avoided if stdin is not a terminal */
779 
781 
782 /* has got to be called first. oc can only be event driven after this returns */
783 void hoc_main1_init(const char* pname, const char** envp) {
784  extern NrnFILEWrap* hoc_frin;
785  extern FILE* hoc_fout;
786 
787  if (!hoc_xopen_file_) {
788  hoc_xopen_file_size_ = 200;
789  hoc_xopen_file_ = static_cast<char*>(emalloc(hoc_xopen_file_size_));
790  }
791  hoc_xopen_file_[0] = '\0';
792 
793  hoc_promptstr = "oc>";
794  yystart = 1;
795  hoc_lineno = 0;
796  if (hoc_main1_inited_) {
797  return;
798  }
799 
800  /* could have been forced with the -isatty option */
801  if (nrn_istty_ == 0) { /* if not set then */
802 #ifdef HAVE_ISATTY
803  nrn_istty_ = isatty(0);
804 #else
805  /* if we do not know, then assume so */
806  nrn_istty_ = 1;
807 #endif
808  }
809  if (nrn_istty_ == -1) {
810  nrn_istty_ = 0;
811  }
815  hoc_ctp = hoc_cbuf;
817  hoc_fout = stdout;
818  if (!nrn_is_cable()) {
819  Fprintf(stderr,
820  "Copyright 1992 - Michael Hines, Neurobiology Dept., DUMC, Durham, NC. 27710\n");
821  }
822  progname = pname;
823  hoc_init();
824  initplot();
825  hoc_main1_inited_ = 1;
826 }
827 
828 HocStr* hocstr_create(size_t size) {
829  HocStr* hs;
830  hs = (HocStr*) emalloc(sizeof(HocStr));
831  hs->size = size;
832  hs->buf = static_cast<char*>(emalloc(size + 1));
833  return hs;
834 }
835 
836 static CHAR* fgets_unlimited_nltrans(HocStr* s, NrnFILEWrap* f, int nltrans);
837 
839  return fgets_unlimited_nltrans(s, f, 0);
840 }
841 
843  free(hs->buf);
844  free(hs);
845 }
846 
847 void hocstr_resize(HocStr* hs, size_t n) {
848  if (hs->size < n) {
849  /*printf("hocstr_resize to %d\n", n);*/
850  hs->buf = static_cast<char*>(erealloc(hs->buf, n + 1));
851  hs->size = n;
852  }
853 }
854 
855 void hocstr_copy(HocStr* hs, const char* buf) {
856  hocstr_resize(hs, strlen(buf) + 1);
857  strcpy(hs->buf, buf);
858 }
859 
860 #ifdef MINGW
861 static int cygonce; /* does not need the '-' after a list of hoc files */
862 #endif
863 
864 static int hoc_run1();
865 
866 // hoc6
867 int hoc_main1(int argc, const char** argv, const char** envp) {
868  int exit_status = EXIT_SUCCESS;
869 #ifdef WIN32
870  extern void hoc_set_unhandled_exception_filter();
871  hoc_set_unhandled_exception_filter();
872 #endif
873 #if 0
874  int controlled;
875 #endif
876 #if PVM
877  init_parallel(&argc, argv);
878 #endif
879 
881  hoc_main1_init(argv[0], envp);
882  try {
883 #if HAS_SIGPIPE
884  signal(SIGPIPE, sigpipe_handler);
885 #endif
886  gargv = argv;
887  gargc = argc;
888  if (argc > 2 && strcmp(argv[1], "-bbs_nhost") == 0) {
889  /* if IV not running this may still be here */
890  gargv += 2;
891  gargc -= 2;
892  }
893 
894  if (gargc == 1) /* fake an argument list */
895  {
896  static const char* stdinonly[] = {"-"};
897 
898 #ifdef MINGW
899  cygonce = 1;
900 #endif
901  gargv = stdinonly;
902  gargc = 1;
903  } else {
904  ++gargv;
905  --gargc;
906  }
907  // If we pass multiple HOC files to special then this loop runs once for each one of them
908  while (hoc_moreinput()) {
909  exit_status = hoc_run1();
910  if (exit_status) {
911  // Abort if one of the HOC files we're processing gives an error
912  break;
913  }
914  }
915  return exit_status;
916  } catch (std::exception const& e) {
917  Fprintf(stderr, fmt::format("hoc_main1 caught exception: {}\n", e.what()).c_str());
918  nrn_exit(1);
919  }
920 }
921 
922 #ifdef MINGW
923 namespace {
924 std::mutex inputMutex_;
925 std::condition_variable inputCond_;
926 // This is intentionally leaked because it is never joined, and the destructor
927 // would call terminate.
928 std::thread* inputReady_;
929 int inputReadyFlag_;
930 int inputReadyVal_;
931 } // namespace
932 extern "C" int getch();
933 
934 void inputReadyThread() {
935  for (;;) {
936  // The pthread version had pthread_testcancel() here, but the thread was
937  // never cancelled.
938  int i = getch();
939  std::unique_lock<std::mutex> lock{inputMutex_};
940  inputReadyFlag_ = 1;
941  inputReadyVal_ = i;
943  inputCond_.wait(lock);
944  }
945  printf("inputReadyThread done\n");
946 }
947 #endif
948 
949 void hoc_final_exit(void) {
950 #if defined(USE_PYTHON)
951  if (neuron::python::methods.interpreter_start) {
953  }
954 #endif
955  bbs_done();
957 
958  /* Don't close the plots for the sub-processes when they finish,
959  by default they are then closed when the master process ends */
960  hoc_close_plot();
961 #if READLINE && !defined(MINGW)
963 #endif
964  ivoc_cleanup();
965 #if defined(WIN32) && HAVE_IV
966  ivoc_win32_cleanup();
967 #endif
968  auto tmp_dir = std::getenv("TEMP");
969  auto path = std::filesystem::path(tmp_dir ? std::string(tmp_dir) : "/tmp") /
970  fmt::format("oc{}.hl", hoc_pid());
971  std::error_code ec;
972  std::filesystem::remove(path, ec);
973 }
974 
975 void hoc_quit(void) {
976  hoc_final_exit();
977  ivoc_final_exit();
978 #if defined(USE_PYTHON)
979  /* if python was launched and neuron is an extension */
980  if (p_nrnpython_finalize) {
981  extern int bbs_poll_;
982  // don't want an MPI_Iprobe after MPI_Finalize if python gui
983  // thread calls doNotify().
984  bbs_poll_ = -1;
985  (*p_nrnpython_finalize)();
986  }
987 #endif
988  int exit_code = ifarg(1) ? int(*getarg(1)) : 0;
990  exit(exit_code);
991 }
992 
993 #ifdef MINGW
994 static const char* double_at2space(const char* infile) {
995  char* buf;
996  const char* cp1;
997  char* cp2;
998  int replace = 0;
999  for (cp1 = infile; *cp1; ++cp1) {
1000  if (*cp1 == '@' && cp1[1] == '@') {
1001  replace = 1;
1002  break;
1003  }
1004  }
1005  if (!replace) {
1006  return infile;
1007  }
1008  buf = static_cast<char*>(emalloc(strlen(infile) + 1));
1009  for (cp1 = infile, cp2 = buf; *cp1; ++cp1, ++cp2) {
1010  if (*cp1 == '@' && cp1[1] == '@') {
1011  *cp2 = ' ';
1012  ++cp1;
1013  } else {
1014  *cp2 = *cp1;
1015  }
1016  }
1017  *cp2 = '\0';
1018  return buf;
1019 }
1020 #endif /*MINGW*/
1021 
1023  if (hoc_pipeflag) {
1024  hoc_pipeflag = 0;
1025  return 1;
1026  }
1027 #if defined(WIN32)
1028  /* like mswin, do not need a '-' after hoc files, but ^D works */
1029  if (gargc == 0 && cygonce == 0) {
1030  cygonce = 1;
1032  infile = 0;
1033  hoc_xopen_file_[0] = 0;
1034 #if defined(USE_PYTHON)
1035  return use_python_interpreter ? 0 : 1;
1036 #else
1037  return 1;
1038 #endif
1039  }
1040 #endif // WIN32
1041  if (hoc_fin && !nrn_fw_eq(hoc_fin, stdin)) {
1043  }
1045  infile = 0;
1046  hoc_xopen_file_[0] = 0;
1047  if (gargc-- <= 0) {
1048  return 0;
1049  }
1050  infile = *gargv++;
1051 #if defined(WIN32)
1052  if (infile[0] == '"') {
1053  char* cp = strdup(infile + 1);
1054  for (++cp; *cp; ++cp) {
1055  if (*cp == '"') {
1056  *cp = '\0';
1057  break;
1058  }
1059  }
1060  infile = cp;
1061  }
1062 #endif // WIN32
1063 #ifdef MINGW
1064  /* have difficulty passing spaces within arguments from neuron.exe
1065  through the neuron.sh shell script to nrniv.exe. Therefore
1066  neuron.exe converts the ' ' to "@@" and here we need to convert
1067  it back */
1068  infile = double_at2space(infile);
1069 #endif
1070  hoc_lineno = 0;
1071 #if defined(USE_PYTHON)
1072  if (use_python_interpreter) {
1073  /* deal only with .hoc files. The hoc files are intended
1074  only for legacy code and there is no notion of stdin interaction
1075  with the hoc interpreter.
1076  */
1077  if (strlen(infile) < 4 || strcmp(infile + strlen(infile) - 4, ".hoc") != 0) {
1078  return hoc_moreinput();
1079  }
1080  }
1081 #endif
1082  if (strcmp(infile, "-") == 0) {
1084  infile = 0;
1085  hoc_xopen_file_[0] = 0;
1086  } else if (strcmp(infile, "-parallel") == 0) {
1087  /* ignore "val" as next argument */
1088  infile = *gargv++;
1089  gargc--;
1090  return hoc_moreinput();
1091  } else if (strcmp(infile, "-c") == 0) {
1092  int hpfi, err;
1093  HocStr* hs;
1094  infile = *gargv++;
1095  gargc--;
1096 #ifdef MINGW
1097  infile = double_at2space(infile);
1098 #endif
1099  hs = hocstr_create(strlen(infile) + 2);
1100  std::snprintf(hs->buf, hs->size + 1, "%s\n", infile);
1101  /* now infile is a hoc statement */
1102  hpfi = hoc_print_first_instance;
1103  hoc_fin = (NrnFILEWrap*) 0;
1105  // This is processing HOC code via -c on the commandline. That HOC code could include
1106  // nrnpython(...), so the Python interpreter needs to be configured appropriately for
1107  // that (i.e. sys.path[0] = '').
1108  if (neuron::python::methods.interpreter_set_path) {
1110  }
1111  err = hoc_oc(hs->buf);
1112  hoc_print_first_instance = hpfi;
1113  hocstr_delete(hs);
1114  if (err) {
1115  hoc_execerror("arg not valid statement:", infile);
1116  }
1117  return hoc_moreinput();
1118  } else if (strlen(infile) > 3 && strcmp(infile + strlen(infile) - 3, ".py") == 0) {
1119  if (!p_nrnpy_pyrun) {
1120  hoc_execerror("Python not available to interpret", infile);
1121  }
1122  if (!p_nrnpy_pyrun(infile)) {
1123  hoc_execerror("Python error", infile);
1124  }
1125  return hoc_moreinput();
1126  } else if ((hoc_fin = nrn_fw_fopen(infile, "r")) == (NrnFILEWrap*) 0) {
1127  Fprintf(stderr, "%d %s: can't open %s\n", nrnmpi_myid_world, progname, infile);
1128 #if NRNMPI
1129  if (nrnmpi_numprocs_world > 1) {
1130  nrnmpi_abort(-1);
1131  }
1132 #endif
1133  return hoc_moreinput();
1134  }
1135  if (infile) {
1136  if (strlen(infile) >= hoc_xopen_file_size_) {
1137  hoc_xopen_file_size_ = strlen(infile) + 100;
1139  }
1140  strcpy(hoc_xopen_file_, infile);
1141  // This is, unfortunately rather implicitly, how we trigger execution of HOC files on a
1142  // commandline like `nrniv a.hoc b.hoc`. To make HOC treatment similar to Python treatment
1143  // we would pass hoc_xopen_file_ here, which would imply that nrnpython("...") inside
1144  // test.hoc sees sys.path[0] == "/dir/" when we run `nrniv /dir/test.hoc`, however it seems
1145  // that legacy models (183300) assume that sys.path[0] == '' in this context, so we stick
1146  // with that. There is no particular reason to follow Python conventions when launching HOC
1147  // scripts, in contrast to Python scripts where we strive to make `nrniv foo.py` and
1148  // `python foo.py` behave in the same way.
1149  if (neuron::python::methods.interpreter_set_path) {
1151  }
1152  }
1153  return 1;
1154 }
1155 
1156 using SignalType = void(int);
1157 static SignalType* signals[4];
1158 
1159 static void set_signals(void) {
1160  signals[0] = signal(SIGINT, onintr);
1161  signals[1] = signal(SIGFPE, fpecatch);
1162  signals[2] = signal(SIGSEGV, sigsegvcatch);
1163 #if HAVE_SIGBUS
1164  signals[3] = signal(SIGBUS, sigbuscatch);
1165 #endif
1166 }
1167 
1168 static void restore_signals(void) {
1169  signals[0] = signal(SIGINT, signals[0]);
1170  signals[1] = signal(SIGFPE, signals[1]);
1171  signals[2] = signal(SIGSEGV, signals[2]);
1172 #if HAVE_SIGBUS
1173  signals[3] = signal(SIGBUS, signals[3]);
1174 #endif
1175 }
1176 
1179  set_signals();
1180  }
1182  restore_signals();
1183  }
1184 };
1185 
1186 // Helper to temporarily set a global to something and then restore the original
1187 // value when the helper goes out of scope
1188 template <typename T>
1190  temporarily_change(T& global, T new_value)
1191  : m_global_value{global}
1192  , m_saved_value{std::exchange(global, new_value)} {}
1195  }
1196 
1197  private:
1200 };
1201 
1202 // execute until EOF
1203 // called from a try { ... } block in hoc_main1
1204 static int hoc_run1() {
1205  auto* const sav_fin = hoc_fin;
1206  hoc_pipeflag = 0;
1208  auto const loop_body = []() {
1209  hoc_initcode();
1210  if (!hoc_yyparse()) {
1211  if (hoc_intset) {
1212  hoc_execerror("interrupted", nullptr);
1213  }
1214  return false;
1215  }
1217  return true;
1218  };
1220  // This is not the most shallowly nested call to hoc_run1(), allow the
1221  // most shallowly nested call to handle exceptions.
1222  while (loop_body())
1223  ;
1224  } else {
1225  // This is the most shallowly nested call to hoc_run1(), handle exceptions.
1226  signal_handler_guard _{}; // install signal handlers
1227  try_catch_depth_increment tell_children_we_will_catch{};
1228  hoc_intset = 0;
1229  for (;;) {
1230  try {
1231  if (!loop_body()) {
1232  break;
1233  }
1234  } catch (std::exception const& e) {
1235  hoc_fin = sav_fin;
1236  Fprintf(stderr, "hoc_run1: caught exception");
1237  std::string_view what{e.what()};
1238  if (!what.empty()) {
1239  Fprintf(stderr, fmt::format(": {}", what).c_str());
1240  }
1241  Fprintf(stderr, "\n");
1242  // Exit if we're not in interactive mode
1243  if (!nrn_fw_eq(hoc_fin, stdin)) {
1244  return EXIT_FAILURE;
1245  }
1246  }
1247  }
1248  }
1249  return EXIT_SUCCESS;
1250 }
1251 
1252 /* event driven interface to oc. This routine always returns after processing
1253  its argument. The normal case is where the argument consists of a complete
1254  statement which can be parsed and executed. However this routine can
1255  be called with single tokens as well and the parsing will proceed
1256  incrementally until the last token that completes a statement is seen
1257  at which time the statement is executed.
1258  The routine can also be called with a string containing multiple statements
1259  separated by '\n's.
1260  During execution a ^C will halt
1261  processing and this routine will return to the calling statement. (if it
1262  is the controlling call for the jmp_buf; see below).
1263  Parse errors and execution errors will also result in a normal return to the
1264  calling statement.
1265 
1266  To avoid blocking other input events, this routine should not be called
1267  with statements which take too much time to execute or block
1268  waiting for input. With regard to long executing statements, at least in
1269  xview it is possible to run the event loop from the execute loop at
1270  intervals in code.cpp or else to run the event loop once via a hoc command.
1271 
1272  Where do we go in case of an hoc_execerror. We have to go to the beginning
1273  of hoc. But just maybe that is here. However hoc_oc may be called
1274  recursively. Or it may be called from the original hoc_run. Or it may be
1275  There is therefore a notion of the controlling routine for the jmp_buf begin.
1276  We only do a setjmp and set the signals when there is no other controlling
1277  routine. Note that setjmp is no longer used, but for now the same notion of a
1278  controlling routine is maintained.
1279 */
1280 
1281 /* allow hoc_oc(buf) to handle any number of multiline statements */
1282 static const char* nrn_inputbufptr;
1283 static void nrn_inputbuf_getline(void) {
1284  CHAR* cp;
1285  cp = hoc_ctp = hoc_cbuf = hoc_cbufstr->buf;
1286  while (*nrn_inputbufptr) {
1287  *cp++ = *nrn_inputbufptr++;
1288  if (cp[-1] == '\n') {
1289  break;
1290  }
1291  }
1292  if (cp != hoc_ctp) {
1293  if (cp[-1] != '\n') {
1294  *cp++ = '\n';
1295  }
1296  }
1297  *cp = '\0';
1298 }
1299 
1300 // used by ocjump.cpp
1301 void oc_save_input_info(const char** i1, int* i2, int* i3, NrnFILEWrap** i4) {
1302  *i1 = nrn_inputbufptr;
1303  *i2 = hoc_pipeflag;
1304  *i3 = hoc_lineno;
1305  *i4 = hoc_fin;
1306 }
1307 void oc_restore_input_info(const char* i1, int i2, int i3, NrnFILEWrap* i4) {
1308  nrn_inputbufptr = i1;
1309  hoc_pipeflag = i2;
1310  hoc_lineno = i3;
1311  hoc_fin = i4;
1312 }
1313 
1314 int hoc_oc(const char* buf) {
1315  return hoc_oc(buf, std::cerr);
1316 }
1317 
1318 int hoc_oc(const char* buf, std::ostream& os) {
1319  // the substantive code to execute, everything else is to do with handling
1320  // errors here or elsewhere
1321  auto const kernel = [buf]() {
1322  hoc_intset = 0;
1323  hocstr_resize(hoc_cbufstr, strlen(buf) + 10);
1325  while (*hoc_ctp || *nrn_inputbufptr) {
1327  if (hoc_intset) {
1328  hoc_execerror("interrupted", nullptr);
1329  }
1330  }
1331  };
1332  auto const lineno_manager = temporarily_change{hoc_lineno, 1};
1333  auto const pipeflag_manager = temporarily_change{hoc_pipeflag, 3};
1334  auto const inputbufptr_manager = temporarily_change{nrn_inputbufptr, buf};
1336  // Someone else is responsible for catching errors
1337  kernel();
1338  } else {
1339  // This is the highest level try/catch
1340  try_catch_depth_increment tell_children_we_will_catch{};
1341  try {
1343  kernel();
1344  } catch (std::exception const& e) {
1345  os << "hoc_oc caught exception: " << e.what() << std::endl;
1346  hoc_initcode();
1347  hoc_intset = 0;
1348  return 1;
1349  }
1350  }
1352  return 0;
1353 }
1354 
1355 void hoc_warning(const char* s, const char* t) /* print warning message */
1356 {
1357  CHAR* cp;
1358  char id[10];
1359  int n;
1360  if (nrnmpi_numprocs_world > 1) {
1361  Sprintf(id, "%d ", nrnmpi_myid_world);
1362  } else {
1363  id[0] = '\0';
1364  }
1365  if (t) {
1366  Fprintf(stderr, "%s%s: %s %s\n", id, progname, s, t);
1367  } else {
1368  Fprintf(stderr, "%s%s: %s\n", id, progname, s);
1369  }
1370  if (hoc_xopen_file_ && hoc_xopen_file_[0]) {
1371  Fprintf(stderr, "%s in %s near line %d\n", id, hoc_xopen_file_, hoc_lineno);
1372  } else {
1373  Fprintf(stderr, "%s near line %d\n", id, hoc_lineno);
1374  }
1375  n = strlen(hoc_cbuf);
1376  for (cp = hoc_cbuf; cp < (hoc_cbuf + n); ++cp) {
1377  if (!isprint((int) (*cp)) && !isspace((int) (*cp))) {
1378  Fprintf(stderr,
1379  "%scharacter \\%03o at position %ld is not printable\n",
1380  id,
1381  ((int) (*cp) & 0xff),
1382  cp - hoc_cbuf);
1383  break;
1384  }
1385  }
1386  Fprintf(stderr, "%s %s", id, hoc_cbuf);
1387  if (nrnmpi_numprocs_world > 0) {
1388  for (cp = hoc_cbuf; cp != hoc_ctp; cp++) {
1389  Fprintf(stderr, " ");
1390  }
1391  Fprintf(stderr, "^\n");
1392  }
1393  hoc_ctp = hoc_cbuf;
1394  *hoc_ctp = '\0';
1395 }
1396 
1397 
1398 static int Getc(NrnFILEWrap* fp) {
1399  /*ARGSUSED*/
1400  if (*hoc_ctp) {
1401  ++hoc_ictp;
1402  return *hoc_ctp++;
1403  }
1404 
1405 #if 0
1406 /* don't allow parser to block. Actually partial statements were never
1407 allowed anyway */
1408  if (!hoc_pipeflag && nrn_fw_eq(fp,stdin)) {
1409  eos = 1;
1410  return 0;
1411  }
1412 #endif
1413 
1414  if (hoc_get_line() == EOF) {
1415  return EOF;
1416  }
1417  return *hoc_ctp++;
1418 }
1419 
1420 static void unGetc(int c, NrnFILEWrap* fp) {
1421  /*ARGSUSED*/
1422  if (c != EOF && c && hoc_ctp != hoc_cbuf) {
1423  *(--hoc_ctp) = c;
1424  }
1425 }
1426 
1428 
1429 int hoc_yyparse(void) {
1430  /* read line before calling yyparse() and set flag that we
1431  are inside yyparse() since re-entry is not allowed.
1432  This allows xview menus to work since most of the time
1433  we are reading a line from this point instead of in
1434  Getc which was called from yyparse().
1435  */
1436  /*
1437  the above may be obsolete.
1438  I switched to a modified bison generator from yacc which is generated
1439  a parser exactly like it used to be but may return YYNEEDMORE=-3
1440  instead of blocking in yylex. If so another call to yyparse will
1441  take up exactly where it left off. This makes it easier to
1442  support event driven processing.
1443  Maybe it's time to redo the get_line process which fills hoc_cbuf with
1444  the next line to read. A real event driven program would fill hoc_cbuf
1445  and then call yyparse() directly. yyparse() returns
1446  0 : end of file
1447  '\n' : ready to execute a command
1448  -3: need more input, not at a point where it accepts or rejects the
1449  input.
1450  */
1451 
1452  int i;
1453 
1454  if (hoc_in_yyparse) {
1455  hoc_execerror("Cannot re-enter parser", (char*) 0);
1456  }
1457  do {
1458  if (hoc_get_line() == EOF) {
1459  return 0;
1460  }
1461  hoc_in_yyparse = 1;
1462  i = yyparse();
1463  hoc_in_yyparse = 0;
1464  if (i == -3) { // need more input
1465  hoc_in_yyparse = 1;
1466  i = '\n';
1467  }
1468  } while (i == '\n');
1469  return i;
1470 }
1471 
1472 #ifdef WIN32
1473 #define INTERVIEWS 1
1474 #endif
1475 
1477 #if INTERVIEWS
1478 extern int run_til_stdin(); /* runs the interviews event loop. Returns 1
1479  if there is input to be read. Returns 0
1480  if somebody said quit but there is no input
1481  */
1482 
1483 extern void hoc_notify_value(void);
1484 
1485 #if READLINE
1486 #ifdef MINGW
1487 extern "C" int (*rl_getc_function)(void);
1488 extern "C" int rl_getc(void);
1489 static int getc_hook(void) {
1490  if (!inputReady_) {
1491  stdin_event_ready(); /* store main thread id */
1492  inputReady_ = new std::thread{inputReadyThread};
1493  } else {
1494  inputMutex_.unlock();
1495  }
1496  // printf("run til stdin\n");
1497  while (!inputReadyFlag_) {
1498  run_til_stdin();
1499  usleep(10000);
1500  }
1501  inputReadyFlag_ = 0;
1502  int i = inputReadyVal_;
1503  inputMutex_.lock();
1504  inputCond_.notify_one();
1505  return i;
1506 }
1507 #else /* not MINGW */
1508 
1509 #if defined(use_rl_getc_function)
1510 /* e.g. mac libedit.3.dylib missing rl_event_hook */
1511 
1512 extern int iv_dialog_is_running;
1513 extern "C" int (*rl_getc_function)(void);
1514 static int getc_hook(void) {
1515  while (1) {
1516  int r;
1517  unsigned char c;
1518  if (hoc_interviews && !hoc_in_yyparse && run_til_stdin() == 0) {
1519  // nothing in stdin (happens when windows are dismissed)
1520  continue;
1521  }
1522  if ((r = read(0, &c, sizeof(c))) == sizeof(c)) {
1523  return (int) c;
1524  } else {
1525  /* this seems consistent with the internal readline and the
1526  current master version 8.0. That is, rl_getc in the
1527  internal readline gets the return value of read and only
1528  cares about r == 1, loops if errno == EINTR, and returns
1529  EOF otherwise. (Note: internal readline does not have
1530  rl_getc_function.). Version 8.0 rl_getc is complex but in
1531  terms of read, it returns c if r == 1, returns EOF if
1532  r == 0, loops if errno == EINTR, and generally returns EOF
1533  if some other error occurred.
1534  */
1535  if (errno != EINTR) {
1536  return EOF;
1537  }
1538  }
1539  }
1540 }
1541 
1542 #else /* not use_rl_getc_function */
1543 
1544 extern int (*rl_event_hook)(void);
1545 static int event_hook(void) {
1546  int i;
1547  i = run_til_stdin();
1548  return i;
1549 }
1550 
1551 #endif /* not use_rl_getc_function */
1552 
1553 #endif /* not MINGW */
1554 #endif /* READLINE */
1555 #endif /* INTERVIEWS */
1556 
1557 /*
1558  On Mac combinations of /n /r /r/n require binary mode
1559  (otherwise /r/n is /n/n)
1560  but then /r does not end a line in fgets (keeps reading til /n)
1561  so we make our own fgets. May need to use it for data as well.
1562 */
1563 /*
1564  for unix and mac this allows files created on any machine to be
1565  read on any machine
1566 */
1568  return fgets_unlimited_nltrans(bufstr, f, 1);
1569 }
1570 
1571 static CHAR* fgets_unlimited_nltrans(HocStr* bufstr, NrnFILEWrap* f, int nltrans) {
1572  int c, i;
1573  int nl1, nl2;
1574  if (!f) {
1575  hoc_execerr_ext("No file (or stdin) for input");
1576  }
1577  if (nltrans) {
1578  nl1 = 26;
1579  nl2 = 4;
1580  } else {
1581  nl1 = nl2 = EOF;
1582  }
1583  for (i = 0;; ++i) {
1584  c = nrn_fw_getc(f);
1585  if (c == EOF || c == nl1 || c == nl2) { /* ^Z and ^D are end of file */
1586  /* some editors don't put a newline at last line */
1587  if (i > 0) {
1588  nrn_fw_ungetc(c, f);
1589  c = '\n';
1590  } else {
1591  break;
1592  }
1593  }
1594  if (c == '\r') {
1595  int c2 = nrn_fw_getc(f);
1596  if (c2 != '\n') {
1597  nrn_fw_ungetc(c2, f);
1598  }
1599  c = '\n';
1600  }
1601  if (bufstr->size <= i) {
1602  hocstr_resize(bufstr, bufstr->size * 2);
1603  }
1604  bufstr->buf[i] = c;
1605  if (c == '\n') {
1606  bufstr->buf[i + 1] = '\0';
1607  return bufstr->buf;
1608  }
1609  }
1610  return (CHAR*) 0;
1611 }
1612 
1613 int hoc_get_line(void) { /* supports re-entry. fill hoc_cbuf with next line */
1614  if (*hoc_ctp) {
1615  hoc_execerror("Internal error:", "Not finished with previous input line");
1616  }
1618  *hoc_ctp = '\0';
1619  if (hoc_pipeflag == 3) {
1621  if (*hoc_ctp == '\0') {
1622  return EOF;
1623  }
1624  } else if (hoc_pipeflag) {
1625  if (hoc_strgets_need() > hoc_cbufstr->size) {
1627  }
1628  if (hoc_strgets(hoc_cbuf, CBUFSIZE - 1) == (char*) 0) {
1629  return EOF;
1630  }
1631  } else {
1632 #if READLINE
1633  if (nrn_fw_eq(hoc_fin, stdin) && nrn_istty_) {
1634  char* line;
1635  int n;
1636 #if INTERVIEWS
1637 #ifdef MINGW
1638  if (hoc_usegui) {
1639  if (hoc_interviews && !hoc_in_yyparse) {
1640  rl_getc_function = getc_hook;
1641  hoc_notify_value();
1642  } else {
1643  rl_getc_function = rl_getc;
1644  }
1645  }
1646 #else /* not MINGW */
1647 #if defined(use_rl_getc_function)
1648  if (hoc_interviews && !hoc_in_yyparse) {
1649  rl_getc_function = getc_hook;
1650  hoc_notify_value();
1651  } else {
1652  rl_getc_function = getc_hook;
1653  }
1654 #else /* not use_rl_getc_function */
1655  if (hoc_interviews && !hoc_in_yyparse) {
1656  rl_event_hook = event_hook;
1657  hoc_notify_value();
1658  } else {
1659  rl_event_hook = NULL;
1660  }
1661 #endif /* not use_rl_getc_function */
1662 #endif /* not MINGW */
1663 #endif /* INTERVIEWS */
1664  if ((line = readline(hoc_promptstr)) == (char*) 0) {
1665  extern int hoc_notify_stop;
1666  return EOF;
1667  }
1668  n = strlen(line);
1669  for (int i = 0; i < n; ++i) {
1670  if (!isascii(line[i])) {
1671  hoc_execerr_ext("Non-ASCII character value 0x%hhx at input position %d\n",
1672  (unsigned) line[i],
1673  i);
1674  }
1675  }
1676  if (n >= hoc_cbufstr->size - 3) {
1677  hocstr_resize(hoc_cbufstr, n + 100);
1679  }
1680  strcpy(hoc_cbuf, line);
1681  hoc_cbuf[n] = '\n';
1682  hoc_cbuf[n + 1] = '\0';
1683  if (line && *line) {
1684  add_history(line);
1685  }
1686  free(line);
1688  } else {
1689  fflush(stdout);
1690  if (hoc_fgets_unlimited(hoc_cbufstr, hoc_fin) == (CHAR*) 0) {
1691  return EOF;
1692  }
1693  }
1694 #else // READLINE
1695 #if INTERVIEWS
1696  if (nrn_fw_eq(hoc_fin, stdin) && hoc_interviews && !hoc_in_yyparse) {
1697  run_til_stdin());
1698  }
1699 #endif // INTERVIEWS
1700 #if defined(WIN32)
1701  if (nrn_fw_eq(hoc_fin, stdin)) {
1702  if (gets(hoc_cbuf) == (char*) 0) {
1703  /*DebugMessage("gets returned NULL\n");*/
1704  return EOF;
1705  }
1706  strcat(hoc_cbuf, "\n");
1707  } else
1708 #endif // WIN32
1709  {
1710  if (hoc_fgets_unlimited(hoc_cbufstr, hoc_fin) == (char*) 0) {
1711  return EOF;
1712  }
1713  }
1714 #endif // READLINE
1715  }
1716  errno = 0;
1717  hoc_lineno++;
1719  hoc_ictp = 0;
1720  return 1;
1721 }
1722 
1723 void hoc_help(void) {
1724 #if INTERVIEWS
1725  if (hoc_interviews) {
1727  } else
1728 #endif
1729  {
1730  if (hoc_usegui) {
1731  hoc_warning("Help only available from version with ivoc library", 0);
1732  }
1733  }
1734  hoc_ctp = hoc_cbuf + strlen(hoc_cbuf) - 1;
1735 }
int cxx_demangle(const char *symbol, char **funcname, size_t *funcname_sz)
void backward_wrapper()
int parse_bt_symbol(char *backtrace_line, void **addr, char *symbol, char *offset)
int bbs_poll_
Definition: code.cpp:32
char * hoc_strgets(char *cbuf, int nc)
Definition: code.cpp:576
static Frame * fp
Definition: code.cpp:96
int hoc_strgets_need(void)
Definition: code.cpp:572
Inst * hoc_progbase
Definition: code.cpp:79
#define i
Definition: md1redef.h:19
#define yyparse
Definition: difeqdef.h:4
#define yylval
Definition: difeqdef.h:7
int hoc_do_equation
Definition: nonlin.cpp:11
double chkarg(int, double low, double high)
Definition: code2.cpp:626
NrnFILEWrap * hoc_frin
Definition: fileio.cpp:26
FILE * hoc_fout
Definition: fileio.cpp:27
char buf[512]
Definition: init.cpp:13
void initplot()
Definition: plot.cpp:132
double hoc_xpop()
Definition: code.cpp:903
void hoc_audit_command(const char *buf)
Definition: audit.cpp:122
void frame_debug()
Definition: code.cpp:1330
void hoc_execerr_ext(const char *fmt,...)
printf style specification of hoc_execerror message.
Definition: fileio.cpp:828
void hoc_close_plot()
Definition: plot.cpp:177
void hoc_execerror(const char *s, const char *t)
Definition: hoc.cpp:658
void hoc_ret()
int hoc_arayinfo_install(Symbol *sp, int nsub)
Definition: hoc.cpp:528
void hoc_final_exit(void)
Definition: hoc.cpp:949
int nrn_inpython_
Definition: hoc.cpp:52
int hoc_errno_check(void)
Definition: math.cpp:257
int hoc_pid(void)
Definition: hoc.cpp:773
void hoc_init(void)
Definition: hoc_init.cpp:232
int hoc_ParseExec(int yystart)
Definition: code.cpp:603
void hoc_freearay(Symbol *sp)
Definition: hoc.cpp:567
void * hoc_sec_internal_name2ptr(const char *s, int eflag)
Definition: cabcode.cpp:764
void * nrn_parsing_pysec_
Symbol * hoc_install(const char *, int, double, Symlist **)
Definition: symbol.cpp:77
int hoc_get_line(void)
Definition: hoc.cpp:1613
void hoc_oop_initaftererror(void)
Definition: hoc_oop.cpp:412
void nrn_exit(int i)
Definition: hoc.cpp:183
void hoc_audit_from_final_exit(void)
Definition: audit.cpp:138
int hoc_oc(const char *buf)
Definition: hoc.cpp:1314
void hoc_warning(const char *s, const char *t)
Definition: hoc.cpp:1355
void ivoc_help(const char *)
Definition: ocnoiv1.cpp:14
void ivoc_final_exit()
Definition: ivocmain.cpp:740
void * hoc_pysec_name2ptr(const char *s, int)
Definition: cabcode.cpp:806
int hoc_main1(int argc, const char **argv, const char **envp)
Definition: hoc.cpp:867
void hoc_free_val_array(double *, std::size_t)
void hoc_initcode()
Definition: code.cpp:473
void hoc_audit_from_hoc_main1(int argc, const char **argv, const char **envp)
Definition: audit.cpp:56
Symbol * hoc_spop()
Definition: code.cpp:928
int nrnignore
Definition: hoc.cpp:42
void hoc_execerror_mes(const char *s, const char *t, int prnt)
Definition: hoc.cpp:611
size_t hoc_total_array(Symbol *s)
Definition: hoc_oop.cpp:83
Symbol * hoc_lookup(const char *)
Definition: symbol.cpp:59
void hoc_free_arrayinfo(Arrayinfo *a)
Definition: hoc.cpp:579
void bbs_done(void)
Definition: ocbbs.cpp:76
int nrn_is_cable(void)
Definition: init.cpp:226
int nrn_mpiabort_on_error_
Definition: hoc.cpp:80
static void unGetc(int c, NrnFILEWrap *fp)
Definition: hoc.cpp:1420
static void set_signals(void)
Definition: hoc.cpp:1159
static CHAR * hoc_cbuf
Definition: hoc.cpp:140
#define CBUFSIZE
Definition: hoc.cpp:136
int nrn_try_catch_nest_depth
How many NEURON try { ...
Definition: hoc.cpp:608
int gargc
Definition: hoc.cpp:168
char * fgets_unlimited(HocStr *s, NrnFILEWrap *f)
Definition: hoc.cpp:838
static int debug_message_
Definition: hoc.cpp:598
static int coredump
Definition: hoc.cpp:672
void hoc_main1_init(const char *pname, const char **envp)
Definition: hoc.cpp:783
char * hoc_xopen_file_
Definition: fileio.cpp:159
HocStr * hoc_tmpbuf
Definition: hoc.cpp:137
void hoc_defnonly(const char *s)
Definition: hoc.cpp:590
int hoc_execerror_messages
Definition: hoc.cpp:607
void add_history(const char *)
static void matherr1(void)
Definition: hoc.cpp:64
int hoc_ictp
Definition: hoc.cpp:142
static CHAR * fgets_unlimited_nltrans(HocStr *s, NrnFILEWrap *f, int nltrans)
Definition: hoc.cpp:1571
#define CHAR
Definition: hoc.cpp:126
static int eos
Definition: hoc.cpp:228
int hoc_intset
Definition: hoc.cpp:162
NrnFILEWrap * hoc_fin
Definition: hoc.cpp:152
static int hoc_run1()
Definition: hoc.cpp:1204
const char * infile
Definition: hoc.cpp:164
void pr_profile(void)
Definition: hoc.cpp:101
#define TMPBUFSIZE
Definition: hoc.cpp:135
HocStr * hocstr_create(size_t size)
Definition: hoc.cpp:828
int nrn_global_argc
Definition: hoc.cpp:45
static int c
Definition: hoc.cpp:169
int nrn_istty_
Definition: hoc.cpp:778
HocStr * hoc_cbufstr
Definition: hoc.cpp:138
int nrn_nobanner_
Definition: hoc.cpp:119
int hoc_print_first_instance
Definition: hoc_oop.cpp:39
void nrn_feenableexcept()
Definition: hoc.cpp:84
static SignalType * signals[4]
Definition: hoc.cpp:1157
static int Getc(NrnFILEWrap *fp)
Definition: hoc.cpp:1398
int hoc_yyparse(void)
Definition: hoc.cpp:1429
#define EPS
Definition: hoc.cpp:147
void print_bt()
Definition: hoc.cpp:680
int hoc_indef
Definition: hoc.cpp:163
void oc_restore_input_info(const char *i1, int i2, int i3, NrnFILEWrap *i4)
Definition: hoc.cpp:1307
int hoc_interviews
Definition: hoc.cpp:1476
size_t hoc_xopen_file_size_
Definition: fileio.cpp:158
void hocstr_copy(HocStr *hs, const char *buf)
Definition: hoc.cpp:855
static void restore_signals(void)
Definition: hoc.cpp:1168
int hoc_in_yyparse
Definition: hoc.cpp:1427
CHAR * hoc_fgets_unlimited(HocStr *bufstr, NrnFILEWrap *f)
Definition: hoc.cpp:1567
CHAR * hoc_ctp
Definition: hoc.cpp:141
int nrn_feenableexcept_
Definition: hoc.cpp:82
void hoc_arayinstal(void)
Definition: hoc.cpp:508
const char * hoc_promptstr
Definition: hoc.cpp:139
int hoc_lineno
Definition: hoc.cpp:156
#define YYNEEDMORE
Definition: hoc.cpp:219
void oc_save_input_info(const char **i1, int *i2, int *i3, NrnFILEWrap **i4)
Definition: hoc.cpp:1301
__attribute__((noreturn)) void sigsegvcatch(int)
Definition: hoc.cpp:749
static int backslash(int c)
Definition: hoc.cpp:488
int hoc_main1_inited_
Definition: hoc.cpp:780
const char ** gargv
Definition: hoc.cpp:167
int yylex(void)
Definition: hoc.cpp:251
int getnb(void)
Definition: hoc.cpp:204
char ** nrn_global_argv
Definition: hoc.cpp:46
static void nrn_inputbuf_getline(void)
Definition: hoc.cpp:1283
void fpecatch(int)
Definition: hoc.cpp:734
void add_profile(int i)
Definition: hoc.cpp:100
int yystart
Definition: hoc.cpp:609
void hocstr_resize(HocStr *hs, size_t n)
Definition: hoc.cpp:847
void onintr(int)
Definition: hoc.cpp:663
void hoc_coredump_on_error(void)
Definition: hoc.cpp:674
void hoc_quit(void)
Definition: hoc.cpp:975
static char * optarray(char *buf)
Definition: hoc.cpp:230
#define FEEXCEPT
Definition: hoc.cpp:63
const char * progname
Definition: hoc.cpp:155
char * neuron_home
Definition: hoc_init.cpp:227
void hoc_help(void)
Definition: hoc.cpp:1723
char * readline(const char *prompt)
static const char * nrn_inputbufptr
Definition: hoc.cpp:1282
int hoc_usegui
Definition: hoc.cpp:121
int hoc_pipeflag
Definition: hoc.cpp:120
void hocstr_delete(HocStr *hs)
Definition: hoc.cpp:842
void(int) SignalType
Definition: hoc.cpp:1156
void hoc_show_errmess_always(void)
Definition: hoc.cpp:599
static void sigpipe_handler(int sig)
Definition: hoc.cpp:198
static int follow(int expect, int ifyes, int ifno)
Definition: hoc.cpp:498
void rl_deprep_terminal(void)
int hoc_moreinput()
Definition: hoc.cpp:1022
int(* p_nrnpy_pyrun)(const char *fname)
Definition: hoc.cpp:53
void start_profile(int i)
Definition: hoc.cpp:99
#define getarg
Definition: hocdec.h:17
#define OPARINFO(sym)
Definition: hocdec.h:239
#define OPVAL(sym)
Definition: hocdec.h:234
void hoc_acterror(const char *, const char *)
Symlist * hoc_p_symlist
Definition: symbol.cpp:35
void(* p_nrnpython_finalize)()
static int argc
Definition: inithoc.cpp:45
static char ** argv
Definition: inithoc.cpp:46
void nrn_err_dialog(const char *mes)
Definition: ivoc.cpp:182
void ivoc_cleanup()
Definition: ocnoiv1.cpp:15
void hoc_notify_value()
Definition: ivocmain.cpp:764
void hoc_pushx(double)
Definition: code.cpp:779
int run_til_stdin()
Definition: ivocmain.cpp:761
int stdin_event_ready()
Definition: ivocwin.cpp:288
#define IGNORE(arg)
Definition: model.h:224
#define Strcpy
Definition: model.h:215
floor
Definition: extdef.h:4
printf
Definition: extdef.h:5
void move(Item *q1, Item *q2, Item *q3)
Definition: list.cpp:200
void hoc_malchk(void)
Definition: nrnoc_aux.cpp:83
bool stoprun
Definition: nrnoc_aux.cpp:19
void * erealloc(void *ptr, size_t size)
Definition: nrnoc_aux.cpp:94
static void * emalloc(size_t size)
Definition: mpispike.cpp:30
impl_ptrs methods
Collection of pointers to functions with python-version-specific implementations.
Definition: nrnpy.cpp:21
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
Definition: wrap_sprintf.h:14
@ read
variable is ready only
static void prnt(const TQItem *b, int level)
Definition: tqueue.cpp:46
#define nrn_fw_eq(fw, ff)
Definition: nrnfilewrap.h:11
#define nrn_fw_fclose
Definition: nrnfilewrap.h:12
#define nrn_fw_set_stdin()
Definition: nrnfilewrap.h:13
#define nrn_fw_getc(fw)
Definition: nrnfilewrap.h:16
#define nrn_fw_fseek
Definition: nrnfilewrap.h:15
FILE NrnFILEWrap
Definition: nrnfilewrap.h:8
#define nrn_fw_fopen
Definition: nrnfilewrap.h:14
#define nrn_fw_ungetc(c, fw)
Definition: nrnfilewrap.h:17
int const size_t const size_t n
Definition: nrngsl.h:10
return status
size_t p
s
Definition: multisend.cpp:521
int ifarg(int)
Definition: code.cpp:1607
void nrnmpi_abort(int errcode)
Definition: nrnmpi.cpp:209
Inst * hoc_pc
Definition: code.cpp:78
#define lock
static realtype retval
Symlist * hoc_symlist
Definition: symbol.cpp:34
void * hoc_Ecalloc(std::size_t n, std::size_t size)
Definition: memory.cpp:30
int nrnmpi_numprocs_world
int nrnmpi_myid_world
HOC interpreter function declarations (included by hocdec.h)
static double remove(void *v)
Definition: ocdeck.cpp:205
void hoc_execute(Inst *)
Definition: code.cpp:2531
static const char ** pname(void *v)
Definition: ocpointer.cpp:64
#define NULL
Definition: spdefs.h:105
#define OR
Definition: spdefs.h:101
#define AND
Definition: spdefs.h:100
#define NOT
Definition: spdefs.h:99
unsigned * a_varn
Definition: hocdec.h:60
int nsub
Definition: hocdec.h:61
int refcount
Definition: hocdec.h:62
int sub[1]
Definition: hocdec.h:63
Definition: hocstr.h:6
size_t size
Definition: hocstr.h:8
char * buf
Definition: hocstr.h:7
Definition: model.h:47
short type
Definition: model.h:48
unsigned s_varn
Definition: hocdec.h:129
char * name
Definition: model.h:61
Arrayinfo * arayinfo
Definition: hocdec.h:130
void(* interpreter_set_path)(std::string_view)
Definition: nrnpy.h:42
int(* interpreter_start)(int)
Definition: nrnpy.h:43
temporarily_change(T &global, T new_value)
Definition: hoc.cpp:1190
Helper type for incrementing/decrementing nrn_try_catch_nest_depth.
Definition: ocjump.h:20
int Fprintf(FILE *stream, const char *fmt, Args... args)
Definition: logger.hpp:8