NEURON
units.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 #include <algorithm>
4 #include <string>
5 #include <string_view>
6 #include <fstream>
7 
8 /* /local/src/master/nrn/src/modlunit/units.c,v 1.5 1997/11/24 16:19:13 hines Exp */
9 /* Mostly from Berkeley */
10 #include "model.h"
11 #include "nrnassrt.h"
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <signal.h>
15 #include <string.h>
16 #include "units.h"
17 #include <assert.h>
18 
19 #include <cstring>
20 
21 #ifdef MINGW
22 #include "../mswin/extra/d2upath.h"
23 #endif
24 
25 #if defined(WIN32)
26 #include <windows.h>
27 #endif
28 
29 #ifndef _WIN32
30 #include <unistd.h>
31 #include <fcntl.h>
32 #endif
33 
34 int unitonflag = 1;
35 static int UnitsOn = 0;
36 extern "C" {
37 extern double fabs(double);
38 } // extern "C"
39 extern void diag(const char*, const char*);
40 #define IFUNITS \
41  { \
42  if (!UnitsOn) \
43  return; \
44  }
45 #define OUTTOLERANCE(arg1, arg2) (fabs(arg2 / arg1 - 1.) > 1.e-5)
46 
47 #define NTAB 601
48 
49 /* if MODLUNIT environment variable not set then look in the following places*/
50 #if defined(NEURON_DATA_DIR)
51 static char const* const dfile = NEURON_DATA_DIR "/lib/nrnunits.lib";
52 #else
53 static char const* const dfile = "/usr/lib/units";
54 #endif
55 static char const* const dfilealt = "../../share/lib/nrnunits.lib";
56 static char* unames[NDIM];
57 double getflt();
58 void fperr(int);
59 int lookup(char* name, unit* up, int den, int c);
60 struct table* hash_table(const char*);
61 
62 void chkfperror();
63 void units(unit*);
64 int pu(int, int, int);
65 int convr(unit*);
66 void units_cpp_init();
67 int get();
68 
69 extern void Unit_push(const char*);
70 
71 static struct table {
72  double factor;
73 #if - 1 == '\377'
74  char dim[NDIM];
75 #else
76  signed char dim[NDIM];
77 #endif
78  char* name;
79 } * table;
80 
81 static char* names;
82 
83 static struct prefix {
84  double factor;
85  const char* pname;
86 } prefix[] = {{1e-18, "atto"},
87  {1e-15, "femto"},
88  {1e-12, "pico"},
89  {1e-9, "nano"},
90  {1e-6, "micro"},
91  {1e-3, "milli"},
92  {1e-2, "centi"},
93  {1e-1, "deci"},
94  {1e1, "deka"},
95  {1e2, "hecta"},
96  {1e2, "hecto"},
97  {1e3, "kilo"},
98  {1e6, "mega"},
99  {1e6, "meg"},
100  {1e9, "giga"},
101  {1e12, "tera"},
102  {0.0, nullptr}};
103 static FILE* inpfile;
104 static int fperrc;
105 static int peekc;
106 static int dumpflg;
107 
108 static const char* pc;
109 
110 static constexpr std::string_view embedded_nrnunits =
111 #include "embedded_nrnunits.lib"
112  ;
113 
114 // cross-platform workaround for:
115 // https://github.com/neuronsimulator/nrn/issues/3470
116 // the API requires a FILE handle instead of a std::string or similar
117 // so we write a temporary file
118 // Note: with posix we experience
119 // warning: 'tmpnam' is deprecated: This function is provided for
120 // compatibility reasons only. Due to security concerns inherent in the
121 // design of tmpnam(3), it is highly recommended that you use mkstemp(3) instead
122 // [-Wdeprecated-declarations]
124 #ifdef _WIN32
125  // Windows: Use GetTempPath and CreateFile for a secure temp file
126  char temp_path[MAX_PATH];
127  GetTempPath(MAX_PATH, temp_path);
128  char temp_file[MAX_PATH];
129  GetTempFileName(temp_path, "nrn", 0, temp_file);
130 
131  // Write embedded_nrnunits to the temp file
132  std::ofstream out(temp_file, std::ios::out | std::ios::binary);
133  out.write(embedded_nrnunits.data(), embedded_nrnunits.size());
134  out.close();
135 
136  // Open the temp file for reading
137  return fopen(temp_file, "r");
138 #else
139  // POSIX: Use mkstemp for a secure temp file
140  char temp_file[] = "/tmp/nrnunitsXXXXXX";
141  int fd = mkstemp(temp_file);
142  if (fd == -1) {
143  return nullptr; // Handle error appropriately
144  }
145 
146  // Write embedded_nrnunits to the temp file
147  std::ofstream out(temp_file, std::ios::out | std::ios::binary);
148  out.write(embedded_nrnunits.data(), embedded_nrnunits.size());
149  out.close();
150 
151  // Open the temp file for reading
152  FILE* file = fdopen(fd, "r");
153  if (!file) {
154  close(fd);
155  unlink(temp_file); // Clean up
156  }
157  return file;
158 #endif
159 }
160 
161 static int Getc(FILE* inp) {
162  if (inp != stdin) {
163  return getc(inp);
164  } else if (pc && *pc) {
165  return (int) (*pc++);
166  } else {
167  return (int) ('\n');
168  }
169 }
170 
171 #define UNIT_STK_SIZE 20
172 static struct unit unit_stack[UNIT_STK_SIZE], *usp{nullptr};
173 
174 static std::string neuronhome() {
175 #if defined(MINGW)
176  std::string buf(256, '\0');
177  GetModuleFileName(nullptr, buf.data(), 256);
178  // Remove neuron.exe
179  auto pos = buf.find_last_of('\\');
180  buf.resize(pos);
181  // Remove bin
182  pos = buf.find_last_of('\\');
183  buf.resize(pos);
184  std::replace(buf.begin(), buf.end(), '\\', '/');
185  return buf;
186 #else
187  char* buf = std::getenv("NEURONHOME");
188  return (buf != nullptr) ? std::string(buf) : std::string();
189 #endif
190 }
191 
192 
193 static char* ucp;
194 const char* Unit_str(unit* up) {
195  struct unit* p;
196  int f, i;
197  static char buf[256];
198 
199  p = up;
200  Sprintf(buf, "%g ", p->factor);
201  {
202  int seee = 0;
203  for (ucp = buf; *ucp; ucp++) {
204  if (*ucp == 'e')
205  seee = 1;
206  if (seee)
207  *ucp = ucp[1];
208  }
209  if (seee)
210  ucp--;
211  }
212  f = 0;
213  for (i = 0; i < NDIM; i++)
214  f |= pu(p->dim[i], i, f);
215  if (f & 1) {
216  *ucp++ = '/';
217  f = 0;
218  for (i = 0; i < NDIM; i++)
219  f |= pu(-p->dim[i], i, f);
220  }
221  *ucp = '\0';
222  return buf;
223 }
224 
225 void unit_pop() {
226  IFUNITS
227  assert(usp >= unit_stack);
228  if (usp == unit_stack) {
229  usp = nullptr;
230  } else {
231  --usp;
232  }
233 }
234 
235 void unit_swap() { /*exchange top two elements of stack*/
236  struct unit* up;
237  int i, j;
238  double d;
239 
240  IFUNITS
241  assert(usp > unit_stack);
242  up = usp - 1;
243 
244  d = usp->factor;
245  usp->factor = up->factor;
246  up->factor = d;
247 
248  for (i = 0; i < NDIM; i++) {
249  j = usp->dim[i];
250  usp->dim[i] = up->dim[i];
251  up->dim[i] = j;
252  }
253 }
254 
255 double unit_mag() { /* return unit magnitude that is on stack */
256  return usp->factor;
257 }
258 
259 void unit_mag_mul(double d) {
260  usp->factor *= d;
261 }
262 
263 void punit() {
264  struct unit* i;
265  for (i = usp; i != unit_stack - 1; --i) {
266  printf("%s\n", Unit_str(i));
267  }
268 }
269 
270 void ucopypop(unit* up) {
271  int i;
272  for (i = 0; i < NDIM; i++) {
273  up->dim[i] = usp->dim[i];
274  }
275  up->factor = usp->factor;
276  up->isnum = usp->isnum;
277  unit_pop();
278 }
279 
280 void ucopypush(unit* up) {
281  int i;
282  Unit_push("");
283  for (i = 0; i < NDIM; i++) {
284  usp->dim[i] = up->dim[i];
285  }
286  usp->factor = up->factor;
287  usp->isnum = up->isnum;
288 }
289 
290 void Unit_push(const char* str) {
291  IFUNITS
292  assert(usp < unit_stack + (UNIT_STK_SIZE - 1));
293  if (usp) {
294  ++usp;
295  } else {
296  usp = unit_stack;
297  }
298  pc = str;
299  if (str) {
300  usp->isnum = 0;
301  } else {
302  pc = "";
303  usp->isnum = 1;
304  }
305  convr(usp);
306  /*printf("unit_push %s\n", str); units(usp);*/
307 }
308 
309 void unit_push_num(double d) {
310  Unit_push("");
311  usp->factor = d;
312 }
313 
314 void unitcheck(char* s) {
315  Unit_push(s);
316  unit_pop();
317 }
318 
319 const char* unit_str() {
320  /* return top of stack as units string */
321  if (!UnitsOn)
322  return "";
323  return Unit_str(usp);
324 }
325 
326 static void install_units_help(char* s1, char* s2) /* define s1 as s2 */
327 {
328  struct table* tp;
329  int i;
330 
331  IFUNITS
332  Unit_push(s2);
333  tp = hash_table(s1);
334  if (tp->name) {
335  printf("Redefinition of units (%s) to:", s1);
336  units(usp);
337  printf(" is ignored.\nThey remain:");
338  Unit_push(s1);
339  units(usp);
340  diag("Units redefinition", (char*) 0);
341  }
342  tp->name = s1;
343  tp->factor = usp->factor;
344  for (i = 0; i < NDIM; i++) {
345  tp->dim[i] = usp->dim[i];
346  }
347  unit_pop();
348 }
349 
350 void install_units(char* s1, char* s2) {
351  install_units_help(s1, s2);
352 }
353 
354 void check_num() {
355  struct unit* up = usp - 1;
356  /*EMPTY*/
357  if (up->isnum && usp->isnum) {
358  ;
359  } else {
360  up->isnum = 0;
361  }
362 }
363 
364 void unit_mul() {
365  /* multiply next element by top of stack and leave on stack */
366  struct unit* up;
367  int i;
368 
369  IFUNITS
370  assert(usp > unit_stack);
371  check_num();
372  up = usp - 1;
373  for (i = 0; i < NDIM; i++) {
374  up->dim[i] += usp->dim[i];
375  }
376  up->factor *= usp->factor;
377  unit_pop();
378 }
379 
380 void unit_div() {
381  /* divide next element by top of stack and leave on stack */
382  struct unit* up;
383  int i;
384 
385  IFUNITS
386  assert(usp > unit_stack);
387  check_num();
388  up = usp - 1;
389  for (i = 0; i < NDIM; i++) {
390  up->dim[i] -= usp->dim[i];
391  }
392  up->factor /= usp->factor;
393  unit_pop();
394 }
395 
396 void Unit_exponent(int val) {
397  /* multiply top of stack by val and leave on stack */
398  int i;
399  double d;
400 
401  IFUNITS
402  assert(usp >= unit_stack);
403  for (i = 0; i < NDIM; i++) {
404  usp->dim[i] *= val;
405  }
406  d = usp->factor;
407  for (i = 1; i < val; i++) {
408  usp->factor *= d;
409  }
410 }
411 
412 int unit_cmp_exact() { /* returns 1 if top two units on stack are same */
413  struct unit* up;
414  int i;
415 
416  {
417  if (!UnitsOn)
418  return 0;
419  }
420  up = usp - 1;
421  if (unitonflag) {
422  if (up->dim[0] == 9 || usp->dim[0] == 9) {
423  return 1;
424  }
425  for (i = 0; i < NDIM; i++) {
426  if (up->dim[i] != usp->dim[i]) {
427  chkfperror();
428  return 0;
429  }
430  }
431  if (OUTTOLERANCE(up->factor, usp->factor)) {
432  chkfperror();
433  return 0;
434  }
435  }
436  return 1;
437 }
438 
439 void Unit_cmp() {
440  /*compares top two units on stack. If not conformable then
441  gives error. If not same factor then gives error.
442  */
443  struct unit* up;
444  int i;
445 
446  IFUNITS
447  assert(usp > unit_stack);
448  up = usp - 1;
449  if (usp->isnum) {
450  unit_pop();
451  return;
452  }
453  if (up->isnum) {
454  for (i = 0; i < NDIM; i++) {
455  up->dim[i] = usp->dim[i];
456  }
457  up->factor = usp->factor;
458  up->isnum = 0;
459  }
460  if (unitonflag && up->dim[0] != 9 && usp->dim[0] != 9) {
461  for (i = 0; i < NDIM; i++) {
462  if (up->dim[i] != usp->dim[i]) {
463  chkfperror();
464  fprintf(stderr, "\nunits:");
465  units(usp);
466  fprintf(stderr, "\nunits:");
467  units(up);
468  diag("The units of the previous two expressions are not conformable", (char*) "\n");
469  }
470  }
471  if (OUTTOLERANCE(up->factor, usp->factor)) {
472  chkfperror();
473  fprintf(stderr,
474  "The previous primary expression with units: %s\n\
475 is missing a conversion factor and should read:\n (%g)*(",
476  Unit_str(usp),
477  usp->factor / up->factor);
478  diag(")\n", (char*) 0);
479  }
480  }
481  unit_pop();
482  return;
483 }
484 
485 int unit_diff() {
486  /*compares top two units on stack. If not conformable then
487  return 1, if not same factor return 2 if same return 0
488  */
489  struct unit* up;
490  int i;
491 
492  if (!UnitsOn)
493  return 0;
494  assert(usp > unit_stack);
495  up = usp - 1;
496  if (up->dim[0] == 9 || usp->dim[0] == 9) {
497  unit_pop();
498  return 0;
499  }
500  if (usp->isnum) {
501  unit_pop();
502  return 0;
503  }
504  if (up->isnum) {
505  for (i = 0; i < NDIM; i++) {
506  up->dim[i] = usp->dim[i];
507  }
508  up->factor = usp->factor;
509  up->isnum = 0;
510  }
511  for (i = 0; i < NDIM; i++) {
512  if (up->dim[i] != usp->dim[i]) {
513  return 1;
514  }
515  }
516  if (OUTTOLERANCE(up->factor, usp->factor)) {
517  return 2;
518  }
519  unit_pop();
520  return 0;
521 }
522 
523 void chkfperror() {
524  if (fperrc) {
525  diag("underflow or overflow in units calculation", (char*) 0);
526  }
527 }
528 
530  /* ensures top element is dimensionless */
531  int i;
532 
533  IFUNITS
534  assert(usp >= unit_stack);
535  if (usp->dim[0] == 9) {
536  return;
537  }
538  for (i = 0; i < NDIM; i++) {
539  if (usp->dim[i] != 0) {
540  units(usp);
541  diag("The previous expression is not dimensionless", (char*) 0);
542  }
543  }
544 }
545 
546 void unit_less() {
547  /* ensures top element is dimensionless with factor 1*/
548  IFUNITS
549  if (unitonflag) {
550  dimensionless();
551  if (usp->dim[0] != 9 && OUTTOLERANCE(usp->factor, 1.0)) {
552  fprintf(stderr,
553  "The previous expression needs the conversion factor (%g)\n",
554  1. / (usp->factor));
555  diag("", (char*) 0);
556  }
557  }
558  unit_pop();
559 }
560 
562  IFUNITS
563  usp = nullptr;
564 }
565 
566 // allow the outside world to call either modl_units() or unit_init().
567 static void units_alloc() {
568  static int units_alloc_called = 0;
569  if (!units_alloc_called) {
570  units_alloc_called = 1;
571  table = (struct table*) calloc(NTAB, sizeof(struct table));
572  assert(table);
573  names = (char*) calloc(NTAB * 10, sizeof(char));
574  assert(names);
575  }
576 }
577 
578 extern void unit_init();
579 
580 void modl_units() {
581  static int first = 1;
582  unitonflag = 1;
583  if (first) {
584  units_alloc();
585  unit_init();
586  first = 0;
587  }
588 }
589 
590 void unit_init() {
591  char* s;
592  char buf[1024];
593  inpfile = (FILE*) 0;
594  units_alloc();
595  UnitsOn = 1;
596  s = getenv("MODLUNIT");
597  if (s) {
598  /* note that on mingw, even if MODLUNIT set to /cygdrive/c/...
599  * it ends up here as c:/... and that is good*/
600  /* printf("MODLUNIT=|%s|\n", s); */
601  Sprintf(buf, "%s", s);
602  if ((inpfile = fopen(buf, "r")) == (FILE*) 0) {
603  diag("Bad MODLUNIT environment variable. Cant open:", buf);
604  }
605  }
606 #if defined(__MINGW32__)
607  if (!inpfile) {
608  auto s = neuronhome();
609  if (!s.empty()) {
610  std::string filename = s + "/lib/nrnunits.lib";
611  inpfile = fopen(filename.c_str(), "r");
612  }
613  }
614 #else
615  if (!inpfile && (inpfile = fopen(dfile, "r")) == nullptr) {
616  if ((inpfile = fopen(dfilealt, "r")) == nullptr) {
617  auto s = neuronhome();
618  if (!s.empty()) {
619  std::string filename = s + "/lib/nrnunits.lib";
620  inpfile = fopen(filename.c_str(), "r");
621  }
622  }
623  }
624 #endif
625 
626  // try to load the embedded one as a last resort
627  if (!inpfile) {
629  }
630 
631  if (!inpfile) {
632  fprintf(stderr, "Set a MODLUNIT environment variable path to the units table file\n");
633  fprintf(stderr, "Cant open units table in either of:\n%s\n", buf);
634  diag(dfile, dfilealt);
635  }
636  signal(8, fperr);
637  units_cpp_init();
638  unit_stk_clean();
639 }
640 
641 void units(unit* up) {
642  printf("\t%s\n", Unit_str(up));
643 }
644 
645 int pu(int u, int i, int f) {
646  if (u > 0) {
647  if (f & 2)
648  *ucp++ = '-';
649  if (unames[i]) {
650  std::strcpy(ucp, unames[i]);
651  ucp += strlen(ucp);
652  } else {
653  *ucp++ = '*';
654  *ucp++ = 'a' + i;
655  *ucp++ = '*';
656  }
657  if (u > 1)
658  *ucp++ = (u + '0');
659  return 2;
660  }
661  if (u < 0)
662  return 1;
663  return 0;
664 }
665 
666 int convr(unit* up) {
667  struct unit* p;
668  int c;
669  char* cp;
670  char name[20];
671  int den, err;
672 
673  p = up;
674  for (c = 0; c < NDIM; c++)
675  p->dim[c] = 0;
676  p->factor = getflt();
677  if (p->factor == 0.) {
678  p->factor = 1.0;
679  }
680  err = 0;
681  den = 0;
682  cp = name;
683 
684 loop:
685  switch (c = get()) {
686  case '1':
687  case '2':
688  case '3':
689  case '4':
690  case '5':
691  case '6':
692  case '7':
693  case '8':
694  case '9':
695  case '-':
696  case '/':
697  case ' ':
698  case '\t':
699  case '\n':
700  if (cp != name) {
701  *cp++ = 0;
702  cp = name;
703  err |= lookup(cp, p, den, c);
704  }
705  if (c == '/')
706  den++;
707  if (c == '\n')
708  return err;
709  goto loop;
710  }
711  *cp++ = c;
712  goto loop;
713 }
714 
715 int lookup(char* name, unit* up, int den, int c) {
716  struct unit* p;
717  struct table* q;
718  int i;
719  char* cp2;
720  double e;
721 
722  p = up;
723  e = 1.0;
724 loop:
725  q = hash_table(name);
726  if (q->name) {
727  l1:
728  if (den) {
729  p->factor /= q->factor * e;
730  for (i = 0; i < NDIM; i++)
731  p->dim[i] -= q->dim[i];
732  } else {
733  p->factor *= q->factor * e;
734  for (i = 0; i < NDIM; i++)
735  p->dim[i] += q->dim[i];
736  }
737  if (c >= '2' && c <= '9') {
738  c--;
739  goto l1;
740  }
741  return 0;
742  }
743  {
744  const char* cp1{};
745  for (i = 0; (cp1 = prefix[i].pname) != 0; i++) {
746  cp2 = name;
747  while (*cp1 == *cp2++)
748  if (*cp1++ == 0) {
749  cp1--;
750  break;
751  }
752  if (*cp1 == 0) {
753  e *= prefix[i].factor;
754  name = cp2 - 1;
755  goto loop;
756  }
757  }
758  }
759  /*EMPTY*/
760  char* cp1;
761  for (cp1 = name; *cp1; cp1++)
762  ;
763  if (cp1 > name + 1 && *--cp1 == 's') {
764  *cp1 = 0;
765  goto loop;
766  }
767  fprintf(stderr,
768  "Need declaration in UNITS block of the form:\n\
769  (%s) (units)\n",
770  name);
771  diag("Cannot recognize the units: ", name);
772  /* printf("cannot recognize %s\n", name);*/
773  return 1;
774 }
775 
776 static int equal(const char* c1, const char* c2) {
777  while (*c1++ == *c2)
778  if (*c2++ == 0)
779  return 1;
780  return 0;
781 }
782 
784  char* cp;
785  struct table *tp, *lp;
786  int c, i, f, t;
787  char* np;
788 
789  cp = names;
790  for (i = 0; i < NDIM; i++) {
791  np = cp;
792  *cp++ = '*';
793  *cp++ = i + 'a';
794  *cp++ = '*';
795  *cp++ = 0;
796  lp = hash_table(np);
797  lp->name = np;
798  lp->factor = 1.0;
799  lp->dim[i] = 1;
800  }
801  lp = hash_table("");
802  lp->name = cp - 1;
803  lp->factor = 1.0;
804 
805 l0:
806  c = get();
807  if (c == 0) {
808  if (dumpflg)
809  for (tp = table; tp < table + NTAB; tp++) {
810  if (tp->name == 0)
811  continue;
812  printf("%s", tp->name);
813  units((struct unit*) tp);
814  }
815 
816  fclose(inpfile);
817  inpfile = stdin;
818  return;
819  }
820  if (c == '/') {
821  while (c != '\n' && c != 0)
822  c = get();
823  goto l0;
824  }
825 
826  if (c == '\n')
827  goto l0;
828 
829  np = cp;
830  while (c != ' ' && c != '\t') {
831  *cp++ = c;
832  c = get();
833  if (c == 0)
834  goto l0;
835  if (c == '\n') {
836  *cp++ = 0;
837  tp = hash_table(np);
838  if (tp->name)
839  goto redef;
840  tp->name = np;
841  tp->factor = lp->factor;
842  for (c = 0; c < NDIM; c++)
843  tp->dim[c] = lp->dim[c];
844  i++;
845  goto l0;
846  }
847  }
848  *cp++ = 0;
849  lp = hash_table(np);
850  if (lp->name)
851  goto redef;
852  convr((struct unit*) lp);
853  lp->name = np;
854  f = 0;
855  i++;
856  if (lp->factor != 1.0)
857  goto l0;
858  for (c = 0; c < NDIM; c++) {
859  t = lp->dim[c];
860  if (t > 1 || (f > 0 && t != 0))
861  goto l0;
862  if (f == 0 && t == 1) {
863  if (unames[c])
864  goto l0;
865  f = c + 1;
866  }
867  }
868  if (f > 0)
869  unames[f - 1] = np;
870  goto l0;
871 
872 redef:
873  printf("redefinition %s\n", np);
874  goto l0;
875 }
876 
877 double getflt() {
878  int c;
879  char str[100];
880  char* cp;
881  double d_modern;
882 
883  cp = str;
884  do
885  c = get();
886  while (c == ' ' || c == '\t');
887 
888 l1:
889  if (c >= '0' && c <= '9') {
890  *cp++ = c;
891  c = get();
892  goto l1;
893  }
894  if (c == '.') {
895  *cp++ = c;
896  c = get();
897  goto l1;
898  }
899  if (c == '+' || c == '-') {
900  *cp++ = 'e';
901  *cp++ = c;
902  c = get();
903  while (c >= '0' && c <= '9') {
904  *cp++ = c;
905  c = get();
906  }
907  }
908  *cp = '\0';
909  d_modern = atof(str);
910  if (c == '|') {
911  d_modern /= getflt();
912  return d_modern;
913  }
914  peekc = c;
915  return d_modern;
916 }
917 
918 int get() {
919  int c;
920 
921  /*SUPPRESS 560*/
922  if ((c = peekc) != 0) {
923  peekc = 0;
924  return c;
925  }
926  c = Getc(inpfile);
927  if (c == '\r') {
928  c = Getc(inpfile);
929  }
930  if (c == EOF) {
931  if (inpfile == stdin) {
932  printf("\n");
933  exit(0);
934  }
935  return 0;
936  }
937  return c;
938 }
939 
940 struct table* hash_table(const char* name) {
941  struct table* tp;
942  const char* np;
943  unsigned h;
944 
945  h = 0;
946  np = name;
947  while (*np)
948  h = h * 57 + *np++ - '0';
949  if (((int) h) < 0)
950  h = -(int) h;
951  h %= NTAB;
952  tp = &table[h];
953 l0:
954  if (tp->name == 0)
955  return tp;
956  if (equal(name, tp->name))
957  return tp;
958  tp++;
959  if (tp >= table + NTAB)
960  tp = table;
961  goto l0;
962 }
963 
964 void fperr(int sig) {
965  signal(8, fperr);
966  fperrc++;
967 }
968 
969 void nrnunit_str(char (&buf)[NRN_BUFSIZE], const char* name, const char* u1, const char* u2) {
970  Unit_push(u1);
971  Unit_push(u2);
972  unit_div();
973  Sprintf(buf, "static double %s = %a;\n", name, unit_mag());
974  unit_pop();
975 }
#define i
Definition: md1redef.h:19
char buf[512]
Definition: init.cpp:13
static int c
Definition: hoc.cpp:169
#define assert(ex)
Definition: hocassrt.h:24
#define NRN_BUFSIZE
Definition: model.h:6
printf
Definition: extdef.h:5
const char * name
Definition: init.cpp:16
static int np
Definition: mpispike.cpp:25
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
size_t q
size_t p
size_t j
s
Definition: multisend.cpp:521
void unit_mag_mul(double d)
Definition: units.cpp:259
static int peekc
Definition: units.cpp:105
static char const *const dfile
Definition: units.cpp:53
#define NTAB
Definition: units.cpp:47
double fabs(double)
double unit_mag()
Definition: units.cpp:255
static void units_alloc()
Definition: units.cpp:567
void nrnunit_str(char(&buf)[NRN_BUFSIZE], const char *name, const char *u1, const char *u2)
Definition: units.cpp:969
static char const *const dfilealt
Definition: units.cpp:55
static FILE * open_embedded_nrnunits_as_file()
Definition: units.cpp:123
static std::string neuronhome()
Definition: units.cpp:174
static void install_units_help(char *s1, char *s2)
Definition: units.cpp:326
void unit_init()
Definition: units.cpp:590
void units(unit *)
Definition: units.cpp:641
void unit_push_num(double d)
Definition: units.cpp:309
static int UnitsOn
Definition: units.cpp:35
static char * names
Definition: units.cpp:81
static char * unames[NDIM]
Definition: units.cpp:56
static int equal(const char *c1, const char *c2)
Definition: units.cpp:776
const char * Unit_str(unit *up)
Definition: units.cpp:194
int unitonflag
Definition: units.cpp:34
void Unit_cmp()
Definition: units.cpp:439
static FILE * inpfile
Definition: units.cpp:103
struct table * hash_table(const char *)
Definition: units.cpp:940
void unitcheck(char *s)
Definition: units.cpp:314
int lookup(char *name, unit *up, int den, int c)
Definition: units.cpp:715
const char * unit_str()
Definition: units.cpp:319
void ucopypush(unit *up)
Definition: units.cpp:280
int convr(unit *)
Definition: units.cpp:666
static int dumpflg
Definition: units.cpp:106
void install_units(char *s1, char *s2)
Definition: units.cpp:350
void ucopypop(unit *up)
Definition: units.cpp:270
static int Getc(FILE *inp)
Definition: units.cpp:161
int get()
Definition: units.cpp:918
void unit_pop()
Definition: units.cpp:225
static const char * pc
Definition: units.cpp:108
#define UNIT_STK_SIZE
Definition: units.cpp:171
void Unit_push(const char *)
Definition: units.cpp:290
void unit_mul()
Definition: units.cpp:364
#define OUTTOLERANCE(arg1, arg2)
Definition: units.cpp:45
static struct table * table
void unit_less()
Definition: units.cpp:546
int unit_cmp_exact()
Definition: units.cpp:412
void unit_swap()
Definition: units.cpp:235
void diag(const char *, const char *)
Definition: io.cpp:112
void Unit_exponent(int val)
Definition: units.cpp:396
static int fperrc
Definition: units.cpp:104
#define IFUNITS
Definition: units.cpp:40
static char * ucp
Definition: units.cpp:193
static struct unit unit_stack[UNIT_STK_SIZE]
Definition: units.cpp:172
void modl_units()
Definition: units.cpp:580
int unit_diff()
Definition: units.cpp:485
double getflt()
Definition: units.cpp:877
void chkfperror()
Definition: units.cpp:523
void fperr(int)
Definition: units.cpp:964
void dimensionless()
Definition: units.cpp:529
void unit_stk_clean()
Definition: units.cpp:561
void unit_div()
Definition: units.cpp:380
void punit()
Definition: units.cpp:263
void check_num()
Definition: units.cpp:354
int pu(int, int, int)
Definition: units.cpp:645
static struct unit * usp
Definition: units.cpp:172
void units_cpp_init()
Definition: units.cpp:783
static constexpr std::string_view embedded_nrnunits
Definition: units.cpp:110
Definition: units.cpp:83
double factor
Definition: units.cpp:84
const char * pname
Definition: units.cpp:85
Definition: units.cpp:71
double factor
Definition: units.cpp:72
char * name
Definition: units.cpp:78
signed char dim[NDIM]
Definition: units.cpp:76
Definition: units.h:2
signed char dim[NDIM]
Definition: units.h:7
int isnum
Definition: units.h:9
double factor
Definition: units.h:3
#define NDIM
Definition: units.h:1