NEURON
units.cpp
Go to the documentation of this file.
1 #include <../../nmodlconf.h>
2 /* /local/src/master/nrn/src/modlunit/units.c,v 1.5 1997/11/24 16:19:13 hines Exp */
3 /* Mostly from Berkeley */
4 #include "nrnassrt.h"
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <signal.h>
8 #include <string.h>
9 #include "units.h"
10 #include <assert.h>
11 
12 /**
13  The strategy for dynamic units selection between Legacy and modern units
14  is to maintain two complete tables respectively. Legacy and modern in the
15  nrnunits.lib.in file are distinquished by, e.g.,
16  @LegacyY@faraday 9.6485309+4 coul
17  @LegacyN@faraday 96485.3321233100184 coul
18  The reason for two complete tables, as opposed to a main table and several
19  short legacy and modern tables, is that units are often defined in terms
20  of modified units. eg, "R = (k-mole) (joule/degC)"
21 
22  Nmodl, via the parser, uses only unit_pop, unit_mag, Unit_push,
23  install_units, unit_div, and modl_units.
24 
25  The issue of unit magnitude arises only when declaring a unit factor as in
26  the gasconstant (R) above or with the equivalent "name = (unit) -> (unit)"
27  syntax. If the magnitude difers between legacy and modern, then instead of
28  emitting code like "static double FARADAY = 96485.3;\n" we can emit
29  #define FARADAY _nrnunit_FARADAY_[_nrnunit_use_legacy_]
30  static double _nrnunit_FARADAY_[2] = {96485.3321233100184, 96485.3};
31 **/
32 
33 /* modlunit can do its thing in the old way */
34 #if !defined(NRN_DYNAMIC_UNITS)
35 #define NRN_DYNAMIC_UNITS 0
36 #endif
37 
38 #ifdef MINGW
39 #include "../mswin/extra/d2upath.cpp"
40 #endif
41 #if defined(WIN32)
42 #include <windows.h>
43 #endif
44 
45 int unitonflag = 1;
46 static int UnitsOn = 0;
47 extern "C" {
48 extern double fabs(double);
49 } // extern "C"
50 extern void diag(char*, char*);
51 #define IFUNITS \
52  { \
53  if (!UnitsOn) \
54  return; \
55  }
56 #define OUTTOLERANCE(arg1, arg2) (fabs(arg2 / arg1 - 1.) > 1.e-5)
57 
58 #define NTAB 601
59 
60 #if NRN_DYNAMIC_UNITS
61 #define SUFFIX ".in"
62 #else
63 #define SUFFIX ""
64 #endif
65 
66 /* if MODLUNIT environment variable not set then look in the following places*/
67 #if MAC
68 static char* dfile = ":lib:nrnunits.lib" SUFFIX;
69 #else
70 #if defined(NEURON_DATA_DIR)
71 static char* dfile = NEURON_DATA_DIR "/lib/nrnunits.lib" SUFFIX;
72 #else
73 static char* dfile = "/usr/lib/units";
74 #endif
75 #endif
76 #if defined(__TURBOC__) || defined(__GO32__)
77 static char* dfilealt = "/nrn/lib/nrnunits.lib" SUFFIX;
78 #else
79 #if MAC
80 static char* dfilealt = "::lib:nrnunits.lib" SUFFIX;
81 #else
82 static char* dfilealt = "../../share/lib/nrnunits.lib" SUFFIX;
83 #endif
84 #endif
85 static char* unames[NDIM];
86 double getflt();
87 void fperr(int);
88 int lookup(char* name, unit* up, int den, int c);
89 struct table* hash_table(char*);
90 
91 void chkfperror();
92 void units(unit*);
93 int pu(int, int, int);
94 int convr(unit*);
95 void units_cpp_init();
96 int get();
97 
98 extern void Unit_push(char*);
99 
100 static struct table {
101  double factor;
102 #if - 1 == '\377'
103  char dim[NDIM];
104 #else
105  signed char dim[NDIM];
106 #endif
107  char* name;
108 } * table;
109 
110 static char* names;
111 
112 #if NRN_DYNAMIC_UNITS
113 static struct dynam {
114  struct table* table; /* size NTAB */
115  char* names; /* size NTAB*10 */
116 } dynam[2];
117 #endif
118 
119 static struct prefix {
120  double factor;
121  char* pname;
122 } prefix[] = {1e-18, "atto", 1e-15, "femto", 1e-12, "pico", 1e-9, "nano", 1e-6,
123  "micro", 1e-3, "milli", 1e-2, "centi", 1e-1, "deci", 1e1, "deka",
124  1e2, "hecta", 1e2, "hecto", 1e3, "kilo", 1e6, "mega", 1e6,
125  "meg", 1e9, "giga", 1e12, "tera", 0.0, 0};
126 static FILE* inpfile;
127 static int fperrc;
128 static int peekc;
129 static int dumpflg;
130 
131 static char* pc;
132 
133 static int Getc(FILE* inp) {
134  if (inp != stdin) {
135 #if MAC
136  int c = getc(inp);
137  if (c == '\r') {
138  c = '\n';
139  }
140  return c;
141 #else
142  return getc(inp);
143 #endif
144  } else if (pc && *pc) {
145  return (int) (*pc++);
146  } else {
147  return (int) ('\n');
148  }
149 }
150 
151 #define UNIT_STK_SIZE 20
152 static struct unit unit_stack[UNIT_STK_SIZE], *usp{nullptr};
153 
154 static char* neuronhome() {
155 #if defined(WIN32)
156  int i;
157  static char buf[256];
158  GetModuleFileName(NULL, buf, 256);
159  for (i = strlen(buf); i >= 0 && buf[i] != '\\'; --i) {
160  ;
161  }
162  buf[i] = '\0'; // /neuron.exe gone
163  // printf("setneuronhome |%s|\n", buf);
164  for (i = strlen(buf); i >= 0 && buf[i] != '\\'; --i) {
165  ;
166  }
167  buf[i] = '\0'; // /bin gone
168  {
169  char* u = hoc_dos2unixpath(buf);
170  strcpy(buf, hoc_dos2unixpath(u));
171  free(u);
172  }
173  return buf;
174 #else
175  return getenv("NEURONHOME");
176 #endif
177 }
178 
179 
180 static char* ucp;
181 char* Unit_str(unit* up) {
182  struct unit* p;
183  int f, i;
184  static char buf[256];
185 
186  p = up;
187  sprintf(buf, "%g ", p->factor);
188  {
189  int seee = 0;
190  for (ucp = buf; *ucp; ucp++) {
191  if (*ucp == 'e')
192  seee = 1;
193  if (seee)
194  *ucp = ucp[1];
195  }
196  if (seee)
197  ucp--;
198  }
199  f = 0;
200  for (i = 0; i < NDIM; i++)
201  f |= pu(p->dim[i], i, f);
202  if (f & 1) {
203  *ucp++ = '/';
204  f = 0;
205  for (i = 0; i < NDIM; i++)
206  f |= pu(-p->dim[i], i, f);
207  }
208  *ucp = '\0';
209  return buf;
210 }
211 
212 void unit_pop() {
213  IFUNITS
214  assert(usp >= unit_stack);
215  if (usp == unit_stack) {
216  usp = nullptr;
217  } else {
218  --usp;
219  }
220 }
221 
222 void unit_swap() { /*exchange top two elements of stack*/
223  struct unit* up;
224  int i, j;
225  double d;
226 
227  IFUNITS
228  assert(usp > unit_stack);
229  up = usp - 1;
230 
231  d = usp->factor;
232  usp->factor = up->factor;
233  up->factor = d;
234 
235  for (i = 0; i < NDIM; i++) {
236  j = usp->dim[i];
237  usp->dim[i] = up->dim[i];
238  up->dim[i] = j;
239  }
240 }
241 
242 double unit_mag() { /* return unit magnitude that is on stack */
243  return usp->factor;
244 }
245 
246 void unit_mag_mul(double d) {
247  usp->factor *= d;
248 }
249 
250 void punit() {
251  struct unit* i;
252  for (i = usp; i != unit_stack - 1; --i) {
253  printf("%s\n", Unit_str(i));
254  }
255 }
256 
257 void ucopypop(unit* up) {
258  int i;
259  for (i = 0; i < NDIM; i++) {
260  up->dim[i] = usp->dim[i];
261  }
262  up->factor = usp->factor;
263  up->isnum = usp->isnum;
264  unit_pop();
265 }
266 
267 void ucopypush(unit* up) {
268  int i;
269  Unit_push("");
270  for (i = 0; i < NDIM; i++) {
271  usp->dim[i] = up->dim[i];
272  }
273  usp->factor = up->factor;
274  usp->isnum = up->isnum;
275 }
276 
277 void Unit_push(char* str) {
278  IFUNITS
279  assert(usp < unit_stack + (UNIT_STK_SIZE - 1));
280  if (usp) {
281  ++usp;
282  } else {
283  usp = unit_stack;
284  }
285  pc = str;
286  if (str) {
287  usp->isnum = 0;
288  } else {
289  pc = "";
290  usp->isnum = 1;
291  }
292  convr(usp);
293  /*printf("unit_push %s\n", str); units(usp);*/
294 }
295 
296 void unit_push_num(double d) {
297  Unit_push("");
298  usp->factor = d;
299 }
300 
301 void unitcheck(char* s) {
302  Unit_push(s);
303  unit_pop();
304 }
305 
306 char* unit_str() {
307  /* return top of stack as units string */
308  char* s;
309  if (!UnitsOn)
310  return "";
311  s = Unit_str(usp);
312  return s;
313 }
314 
315 static void install_units_help(char* s1, char* s2) /* define s1 as s2 */
316 {
317  struct table* tp;
318  int i;
319 
320  IFUNITS
321  Unit_push(s2);
322  tp = hash_table(s1);
323  if (tp->name) {
324  printf("Redefinition of units (%s) to:", s1);
325  units(usp);
326  printf(" is ignored.\nThey remain:");
327  Unit_push(s1);
328  units(usp);
329  diag("Units redefinition", (char*) 0);
330  }
331  tp->name = s1;
332  tp->factor = usp->factor;
333  for (i = 0; i < NDIM; i++) {
334  tp->dim[i] = usp->dim[i];
335  }
336  unit_pop();
337 }
338 
339 static void switch_units(int legacy) {
340 #if NRN_DYNAMIC_UNITS
341  table = dynam[legacy].table;
342  names = dynam[legacy].names;
343 #endif
344 }
345 
346 void install_units(char* s1, char* s2) {
347 #if NRN_DYNAMIC_UNITS
348  int i;
349  for (i = 0; i < 2; ++i) {
350  switch_units(i);
351  install_units_help(s1, s2);
352  }
353 #else
354  install_units_help(s1, s2);
355 #endif
356 }
357 
358 void check_num() {
359  struct unit* up = usp - 1;
360  /*EMPTY*/
361  if (up->isnum && usp->isnum) {
362  ;
363  } else {
364  up->isnum = 0;
365  }
366 }
367 
368 void unit_mul() {
369  /* multiply next element by top of stack and leave on stack */
370  struct unit* up;
371  int i;
372 
373  IFUNITS
374  assert(usp > unit_stack);
375  check_num();
376  up = usp - 1;
377  for (i = 0; i < NDIM; i++) {
378  up->dim[i] += usp->dim[i];
379  }
380  up->factor *= usp->factor;
381  unit_pop();
382 }
383 
384 void unit_div() {
385  /* divide next element by top of stack and leave on stack */
386  struct unit* up;
387  int i;
388 
389  IFUNITS
390  assert(usp > unit_stack);
391  check_num();
392  up = usp - 1;
393  for (i = 0; i < NDIM; i++) {
394  up->dim[i] -= usp->dim[i];
395  }
396  up->factor /= usp->factor;
397  unit_pop();
398 }
399 
400 void Unit_exponent(int val) {
401  /* multiply top of stack by val and leave on stack */
402  int i;
403  double d;
404 
405  IFUNITS
406  assert(usp >= unit_stack);
407  for (i = 0; i < NDIM; i++) {
408  usp->dim[i] *= val;
409  }
410  d = usp->factor;
411  for (i = 1; i < val; i++) {
412  usp->factor *= d;
413  }
414 }
415 
416 int unit_cmp_exact() { /* returns 1 if top two units on stack are same */
417  struct unit* up;
418  int i;
419 
420  {
421  if (!UnitsOn)
422  return 0;
423  }
424  up = usp - 1;
425  if (unitonflag) {
426  if (up->dim[0] == 9 || usp->dim[0] == 9) {
427  return 1;
428  }
429  for (i = 0; i < NDIM; i++) {
430  if (up->dim[i] != usp->dim[i]) {
431  chkfperror();
432  return 0;
433  }
434  }
435  if (OUTTOLERANCE(up->factor, usp->factor)) {
436  chkfperror();
437  return 0;
438  }
439  }
440  return 1;
441 }
442 
443 /* ARGSUSED */
444 static void print_unit_expr(int i) {}
445 
446 void Unit_cmp() {
447  /*compares top two units on stack. If not conformable then
448  gives error. If not same factor then gives error.
449  */
450  struct unit* up;
451  int i;
452 
453  IFUNITS
454  assert(usp > unit_stack);
455  up = usp - 1;
456  if (usp->isnum) {
457  unit_pop();
458  return;
459  }
460  if (up->isnum) {
461  for (i = 0; i < NDIM; i++) {
462  up->dim[i] = usp->dim[i];
463  }
464  up->factor = usp->factor;
465  up->isnum = 0;
466  }
467  if (unitonflag && up->dim[0] != 9 && usp->dim[0] != 9) {
468  for (i = 0; i < NDIM; i++) {
469  if (up->dim[i] != usp->dim[i]) {
470  chkfperror();
471  print_unit_expr(2);
472  fprintf(stderr, "\nunits:");
473  units(usp);
474  print_unit_expr(1);
475  fprintf(stderr, "\nunits:");
476  units(up);
477  diag("The units of the previous two expressions are not conformable", (char*) "\n");
478  }
479  }
480  if (OUTTOLERANCE(up->factor, usp->factor)) {
481  chkfperror();
482  fprintf(stderr,
483  "The previous primary expression with units: %s\n\
484 is missing a conversion factor and should read:\n (%g)*(",
485  Unit_str(usp),
486  usp->factor / up->factor);
487  print_unit_expr(2);
488  diag(")\n", (char*) 0);
489  }
490  }
491  unit_pop();
492  return;
493 }
494 
495 int unit_diff() {
496  /*compares top two units on stack. If not conformable then
497  return 1, if not same factor return 2 if same return 0
498  */
499  struct unit* up;
500  int i;
501 
502  if (!UnitsOn)
503  return 0;
504  assert(usp > unit_stack);
505  up = usp - 1;
506  if (up->dim[0] == 9 || usp->dim[0] == 9) {
507  unit_pop();
508  return 0;
509  }
510  if (usp->isnum) {
511  unit_pop();
512  return 0;
513  }
514  if (up->isnum) {
515  for (i = 0; i < NDIM; i++) {
516  up->dim[i] = usp->dim[i];
517  }
518  up->factor = usp->factor;
519  up->isnum = 0;
520  }
521  for (i = 0; i < NDIM; i++) {
522  if (up->dim[i] != usp->dim[i]) {
523  return 1;
524  }
525  }
526  if (OUTTOLERANCE(up->factor, usp->factor)) {
527  return 2;
528  }
529  unit_pop();
530  return 0;
531 }
532 
533 void chkfperror() {
534  if (fperrc) {
535  diag("underflow or overflow in units calculation", (char*) 0);
536  }
537 }
538 
540  /* ensures top element is dimensionless */
541  int i;
542 
543  IFUNITS
544  assert(usp >= unit_stack);
545  if (usp->dim[0] == 9) {
546  return;
547  }
548  for (i = 0; i < NDIM; i++) {
549  if (usp->dim[i] != 0) {
550  units(usp);
551  diag("The previous expression is not dimensionless", (char*) 0);
552  }
553  }
554 }
555 
556 void unit_less() {
557  /* ensures top element is dimensionless with factor 1*/
558  IFUNITS
559  if (unitonflag) {
560  dimensionless();
561  if (usp->dim[0] != 9 && OUTTOLERANCE(usp->factor, 1.0)) {
562  fprintf(stderr,
563  "The previous expression needs the conversion factor (%g)\n",
564  1. / (usp->factor));
565  diag("", (char*) 0);
566  }
567  }
568  unit_pop();
569 }
570 
572  IFUNITS
573  usp = nullptr;
574 }
575 
576 // allow the outside world to call either modl_units() or unit_init().
577 static void units_alloc() {
578  int i;
579  static int units_alloc_called = 0;
580  if (!units_alloc_called) {
581  units_alloc_called = 1;
582 #if NRN_DYNAMIC_UNITS
583  for (i = 0; i < 2; ++i) {
584  dynam[i].table = (struct table*) calloc(NTAB, sizeof(struct table));
585  assert(dynam[i].table);
586  dynam[i].names = (char*) calloc(NTAB * 10, sizeof(char));
587  assert(dynam[i].names);
588  switch_units(i);
589  }
590 #else
591  table = (struct table*) calloc(NTAB, sizeof(struct table));
592  assert(table);
593  names = (char*) calloc(NTAB * 10, sizeof(char));
594  assert(names);
595 #endif
596  }
597 }
598 
599 #if MODL || NMODL || HMODL || SIMSYS
600 extern void unit_init();
601 
602 void modl_units() {
603  int i;
604  static int first = 1;
605  unitonflag = 1;
606  if (first) {
607  units_alloc();
608 #if NRN_DYNAMIC_UNITS
609  for (i = 0; i < 2; ++i) {
610  switch_units(i);
611  unit_init();
612  }
613 #else
614  unit_init();
615 #endif
616  first = 0;
617  }
618 }
619 
620 #endif
621 
622 void unit_init() {
623  char* s;
624  char buf[1024];
625  inpfile = (FILE*) 0;
626  units_alloc();
627  UnitsOn = 1;
628  s = getenv("MODLUNIT");
629  if (s) {
630  /* note that on mingw, even if MODLUNIT set to /cygdrive/c/...
631  * it ends up here as c:/... and that is good*/
632  /* printf("MODLUNIT=|%s|\n", s); */
633  sprintf(buf, "%s%s", s, SUFFIX);
634  if ((inpfile = fopen(buf, "r")) == (FILE*) 0) {
635  diag("Bad MODLUNIT environment variable. Cant open:", buf);
636  }
637  }
638 #if defined(__MINGW32__)
639  if (!inpfile) {
640  s = strdup(neuronhome());
641  if (s) {
642  if (strncmp(s, "/cygdrive/", 10) == 0) {
643  /* /cygdrive/x/... to c:/... */
644  sprintf(buf, "%c:%s/lib/nrnunits.lib" SUFFIX, s[10], s + 11);
645  } else {
646  sprintf(buf, "%s/lib/nrnunits.lib" SUFFIX, s);
647  }
648  inpfile = fopen(buf, "r");
649  free(s);
650  }
651  }
652 #else
653  if (!inpfile && (inpfile = fopen(dfile, "r")) == (FILE*) 0) {
654  if ((inpfile = fopen(dfilealt, "r")) == (FILE*) 0) {
655  s = neuronhome();
656  if (s) {
657  sprintf(buf, "%s/lib/nrnunits.lib" SUFFIX, s);
658  inpfile = fopen(buf, "r");
659  }
660  }
661  }
662 #endif
663 
664  if (!inpfile) {
665  fprintf(stderr, "Set a MODLUNIT environment variable path to the units table file\n");
666  fprintf(stderr, "Cant open units table in either of:\n%s\n", buf);
667  diag(dfile, dfilealt);
668  }
669  signal(8, fperr);
670  units_cpp_init();
671  unit_stk_clean();
672 }
673 
674 #if 0
675 void main(argc, argv)
676 char *argv[];
677 {
678  register i;
679  register char *file;
680  struct unit u1, u2;
681  double f;
682 
683  if(argc>1 && *argv[1]=='-') {
684  argc--;
685  argv++;
686  dumpflg++;
687  }
688  file = dfile;
689  if(argc > 1)
690  file = argv[1];
691  if ((inpfile = fopen(file, "r")) == NULL) {
692  printf("no table\n");
693  exit(1);
694  }
695  signal(8, fperr);
696  units_cpp_init();
697 
698 loop:
699  fperrc = 0;
700  printf("you have: ");
701  if(convr(&u1))
702  goto loop;
703  if(fperrc)
704  goto fp;
705 loop1:
706  printf("you want: ");
707  if(convr(&u2))
708  goto loop1;
709  for(i=0; i<NDIM; i++)
710  if(u1.dim[i] != u2.dim[i])
711  goto conform;
712  f = u1.factor/u2.factor;
713  if(fperrc)
714  goto fp;
715  printf("\t* %e\n", f);
716  printf("\t/ %e\n", 1./f);
717  goto loop;
718 
719 conform:
720  if(fperrc)
721  goto fp;
722  printf("conformability\n");
723  units(&u1);
724  units(&u2);
725  goto loop;
726 
727 fp:
728  printf("underflow or overflow\n");
729  goto loop;
730 }
731 #endif
732 
733 void units(unit* up) {
734  printf("\t%s\n", Unit_str(up));
735 }
736 
737 int pu(int u, int i, int f) {
738  if (u > 0) {
739  if (f & 2)
740  *ucp++ = '-';
741  if (unames[i]) {
742  sprintf(ucp, "%s", unames[i]);
743  ucp += strlen(ucp);
744  } else {
745  sprintf(ucp, "*%c*", i + 'a');
746  ucp += strlen(ucp);
747  }
748  if (u > 1)
749  *ucp++ = (u + '0');
750  return (2);
751  }
752  if (u < 0)
753  return (1);
754  return (0);
755 }
756 
757 int convr(unit* up) {
758  struct unit* p;
759  int c;
760  char* cp;
761  char name[20];
762  int den, err;
763 
764  p = up;
765  for (c = 0; c < NDIM; c++)
766  p->dim[c] = 0;
767  p->factor = getflt();
768  if (p->factor == 0.) {
769  p->factor = 1.0;
770  }
771  err = 0;
772  den = 0;
773  cp = name;
774 
775 loop:
776  switch (c = get()) {
777  case '1':
778  case '2':
779  case '3':
780  case '4':
781  case '5':
782  case '6':
783  case '7':
784  case '8':
785  case '9':
786  case '-':
787  case '/':
788  case ' ':
789  case '\t':
790  case '\n':
791  if (cp != name) {
792  *cp++ = 0;
793  cp = name;
794  err |= lookup(cp, p, den, c);
795  }
796  if (c == '/')
797  den++;
798  if (c == '\n')
799  return (err);
800  goto loop;
801  }
802  *cp++ = c;
803  goto loop;
804 }
805 
806 int lookup(char* name, unit* up, int den, int c) {
807  struct unit* p;
808  struct table* q;
809  int i;
810  char *cp1, *cp2;
811  double e;
812 
813  p = up;
814  e = 1.0;
815 loop:
816  q = hash_table(name);
817  if (q->name) {
818  l1:
819  if (den) {
820  p->factor /= q->factor * e;
821  for (i = 0; i < NDIM; i++)
822  p->dim[i] -= q->dim[i];
823  } else {
824  p->factor *= q->factor * e;
825  for (i = 0; i < NDIM; i++)
826  p->dim[i] += q->dim[i];
827  }
828  if (c >= '2' && c <= '9') {
829  c--;
830  goto l1;
831  }
832  return (0);
833  }
834  for (i = 0; (cp1 = prefix[i].pname) != 0; i++) {
835  cp2 = name;
836  while (*cp1 == *cp2++)
837  if (*cp1++ == 0) {
838  cp1--;
839  break;
840  }
841  if (*cp1 == 0) {
842  e *= prefix[i].factor;
843  name = cp2 - 1;
844  goto loop;
845  }
846  }
847  /*EMPTY*/
848  for (cp1 = name; *cp1; cp1++)
849  ;
850  if (cp1 > name + 1 && *--cp1 == 's') {
851  *cp1 = 0;
852  goto loop;
853  }
854  fprintf(stderr,
855  "Need declaration in UNITS block of the form:\n\
856  (%s) (units)\n",
857  name);
858  diag("Cannot recognize the units: ", name);
859  /* printf("cannot recognize %s\n", name);*/
860  return (1);
861 }
862 
863 static int equal(char* s1, char* s2) {
864  char *c1, *c2;
865 
866  c1 = s1;
867  c2 = s2;
868  while (*c1++ == *c2)
869  if (*c2++ == 0)
870  return (1);
871  return (0);
872 }
873 
875  char* cp;
876  struct table *tp, *lp;
877  int c, i, f, t;
878  char* np;
879 
880  cp = names;
881  for (i = 0; i < NDIM; i++) {
882  np = cp;
883  *cp++ = '*';
884  *cp++ = i + 'a';
885  *cp++ = '*';
886  *cp++ = 0;
887  lp = hash_table(np);
888  lp->name = np;
889  lp->factor = 1.0;
890  lp->dim[i] = 1;
891  }
892  lp = hash_table("");
893  lp->name = cp - 1;
894  lp->factor = 1.0;
895 
896 l0:
897  c = get();
898  if (c == 0) {
899 #if 0
900  printf("%d units; %ld bytes\n\n", i, cp-names);
901 #endif
902  if (dumpflg)
903  for (tp = table; tp < table + NTAB; tp++) {
904  if (tp->name == 0)
905  continue;
906  printf("%s", tp->name);
907  units((struct unit*) tp);
908  }
909 
910  fclose(inpfile);
911  inpfile = stdin;
912  return;
913  }
914  if (c == '/') {
915  while (c != '\n' && c != 0)
916  c = get();
917  goto l0;
918  }
919 
920 #if NRN_DYNAMIC_UNITS
921  if (c == '@') {
922  /**
923  Dynamic unit line beginning with @LegacyY@ or @LegacyN@.
924  If the Y or N does not match the modern or legacy table, skip the
925  entire line. For a match, just leave file at char after the final '@'.
926  **/
927  int i;
928  int legacy;
929  char legstr[7];
930  char y_or_n;
931  for (i = 0; i < 6; ++i) {
932  legstr[i] = get();
933  }
934  legstr[6] = '\0';
935  assert(strcmp(legstr, "Legacy") == 0);
936  y_or_n = get();
937  assert(y_or_n == 'Y' || y_or_n == 'N');
938  legacy = (y_or_n == 'Y') ? 1 : 0;
939  nrn_assert(get() == '@');
940  if (dynam[legacy].table != table) { /* skip the line */
941  while (c != '\n' && c != 0) {
942  c = get();
943  }
944  goto l0;
945  }
946  c = get();
947  }
948 #endif
949 
950  if (c == '\n')
951  goto l0;
952 
953  np = cp;
954  while (c != ' ' && c != '\t') {
955  *cp++ = c;
956  c = get();
957  if (c == 0)
958  goto l0;
959  if (c == '\n') {
960  *cp++ = 0;
961  tp = hash_table(np);
962  if (tp->name)
963  goto redef;
964  tp->name = np;
965  tp->factor = lp->factor;
966  for (c = 0; c < NDIM; c++)
967  tp->dim[c] = lp->dim[c];
968  i++;
969  goto l0;
970  }
971  }
972  *cp++ = 0;
973  lp = hash_table(np);
974  if (lp->name)
975  goto redef;
976  convr((struct unit*) lp);
977  lp->name = np;
978  f = 0;
979  i++;
980  if (lp->factor != 1.0)
981  goto l0;
982  for (c = 0; c < NDIM; c++) {
983  t = lp->dim[c];
984  if (t > 1 || (f > 0 && t != 0))
985  goto l0;
986  if (f == 0 && t == 1) {
987  if (unames[c])
988  goto l0;
989  f = c + 1;
990  }
991  }
992  if (f > 0)
993  unames[f - 1] = np;
994  goto l0;
995 
996 redef:
997  printf("redefinition %s\n", np);
998  goto l0;
999 }
1000 
1001 #if NRN_DYNAMIC_UNITS
1002 /* Translate string to double using a2f for modern units
1003  to allow consistency with BlueBrain/nmodl
1004 */
1005 double modern_getflt() {
1006  int c;
1007  char str[100];
1008  char* cp;
1009  double d_modern;
1010 
1011  assert(table == dynam[0].table);
1012 
1013  cp = str;
1014  do
1015  c = get();
1016  while (c == ' ' || c == '\t');
1017 
1018 l1:
1019  if (c >= '0' && c <= '9') {
1020  *cp++ = c;
1021  c = get();
1022  goto l1;
1023  }
1024  if (c == '.') {
1025  *cp++ = c;
1026  c = get();
1027  goto l1;
1028  }
1029  if (c == '+' || c == '-') {
1030  *cp++ = 'e';
1031  *cp++ = c;
1032  c = get();
1033  while (c >= '0' && c <= '9') {
1034  *cp++ = c;
1035  c = get();
1036  }
1037  }
1038  *cp = '\0';
1039  d_modern = atof(str);
1040  if (c == '|') {
1041  d_modern /= modern_getflt();
1042  return d_modern;
1043  }
1044  peekc = c;
1045  return (d_modern);
1046 }
1047 #endif /* NRN_DYNAMIC_UNITS */
1048 
1049 double getflt() {
1050  int c, i, dp;
1051  double d, e;
1052  int f;
1053 
1054 #if NRN_DYNAMIC_UNITS
1055  if (table == dynam[0].table) {
1056  return modern_getflt();
1057  }
1058 #endif /* NRN_DYNAMIC_UNITS */
1059  d = 0.;
1060  dp = 0;
1061  do
1062  c = get();
1063  while (c == ' ' || c == '\t');
1064 
1065 l1:
1066  if (c >= '0' && c <= '9') {
1067  d = d * 10. + c - '0';
1068  if (dp)
1069  dp++;
1070  c = get();
1071  goto l1;
1072  }
1073  if (c == '.') {
1074  dp++;
1075  c = get();
1076  goto l1;
1077  }
1078  if (dp)
1079  dp--;
1080  if (c == '+' || c == '-') {
1081  f = 0;
1082  if (c == '-')
1083  f++;
1084  i = 0;
1085  c = get();
1086  while (c >= '0' && c <= '9') {
1087  i = i * 10 + c - '0';
1088  c = get();
1089  }
1090  if (f)
1091  i = -i;
1092  dp -= i;
1093  }
1094  e = 1.;
1095  i = dp;
1096  if (i < 0)
1097  i = -i;
1098  while (i--)
1099  e *= 10.;
1100  if (dp < 0)
1101  d *= e;
1102  else
1103  d /= e;
1104  if (c == '|')
1105  return (d / getflt());
1106  peekc = c;
1107  return (d);
1108 }
1109 
1110 int get() {
1111  int c;
1112 
1113  /*SUPPRESS 560*/
1114  if ((c = peekc) != 0) {
1115  peekc = 0;
1116  return (c);
1117  }
1118  c = Getc(inpfile);
1119  if (c == '\r') {
1120  c = Getc(inpfile);
1121  }
1122  if (c == EOF) {
1123  if (inpfile == stdin) {
1124  printf("\n");
1125  exit(0);
1126  }
1127  return (0);
1128  }
1129  return (c);
1130 }
1131 
1132 struct table* hash_table(char* name) {
1133  struct table* tp;
1134  char* np;
1135  unsigned h;
1136 
1137  h = 0;
1138  np = name;
1139  while (*np)
1140  h = h * 57 + *np++ - '0';
1141  if (((int) h) < 0)
1142  h = -(int) h;
1143  h %= NTAB;
1144  tp = &table[h];
1145 l0:
1146  if (tp->name == 0)
1147  return (tp);
1148  if (equal(name, tp->name))
1149  return (tp);
1150  tp++;
1151  if (tp >= table + NTAB)
1152  tp = table;
1153  goto l0;
1154 }
1155 
1156 void fperr(int sig) {
1157  signal(8, fperr);
1158  fperrc++;
1159 }
1160 
1161 static double dynam_unit_mag(int legacy, char* u1, char* u2) {
1162  double result;
1163  switch_units(legacy);
1164  Unit_push(u1);
1165  Unit_push(u2);
1166  unit_div();
1167  result = unit_mag();
1168  unit_pop();
1169  return result;
1170 }
1171 
1172 void nrnunit_dynamic_str(char* buf, const char* name, char* u1, char* u2) {
1173 #if NRN_DYNAMIC_UNITS
1174 
1175  double legacy = dynam_unit_mag(1, u1, u2);
1176  double modern = dynam_unit_mag(0, u1, u2);
1177  sprintf(buf,
1178  "\n"
1179  "#define %s _nrnunit_%s[_nrnunit_use_legacy_]\n"
1180  /*since c++17/c99, %a instead of %.18g for exact hex representation of double*/
1181  "static double _nrnunit_%s[2] = {%a, %g}; /* %.18g */\n",
1182  name,
1183  name,
1184  name,
1185  modern,
1186  legacy,
1187  modern);
1188 
1189 #else
1190 
1191  Unit_push(u1);
1192  Unit_push(u2);
1193  unit_div();
1194 #if (defined(LegacyFR) && LegacyFR == 1)
1195  sprintf(buf, "static double %s = %g;\n", name, unit_mag());
1196 #else
1197  sprintf(buf, "static double %s = %.12g;\n", name, unit_mag());
1198 #endif
1199  unit_pop();
1200 
1201 #endif
1202 }
static Frame * fp
Definition: code.cpp:161
double t
Definition: cvodeobj.cpp:59
char * hoc_dos2unixpath(const char *d)
Definition: d2upath.cpp:47
sprintf(buf, " if (secondorder) {\n" " int _i;\n" " for (_i = 0; _i < %d; ++_i) {\n" " _p[_slist%d[_i]] += dt*_p[_dlist%d[_i]];\n" " }}\n", numeqn, listnum, listnum)
#define c
static int first
Definition: fmenu.cpp:190
char buf[512]
Definition: init.cpp:13
#define assert(ex)
Definition: hocassrt.h:32
static int argc
Definition: inithoc.cpp:53
static char ** argv
Definition: inithoc.cpp:54
int main()
Definition: macmain.cpp:5
char * getenv(const char *s)
Definition: macprt.cpp:67
#define y_or_n(s)
Definition: matrix.h:372
#define i
Definition: md1redef.h:12
char * name
Definition: init.cpp:16
static double dynam_unit_mag(int legacy, char *u1, char *u2)
Definition: units.cpp:1161
void unit_mag_mul(double d)
Definition: units.cpp:246
static int peekc
Definition: units.cpp:128
#define NTAB
Definition: units.cpp:58
char * unit_str()
Definition: units.cpp:306
double fabs(double)
double unit_mag()
Definition: units.cpp:242
static void units_alloc()
Definition: units.cpp:577
static void install_units_help(char *s1, char *s2)
Definition: units.cpp:315
void unit_init()
Definition: units.cpp:622
void units(unit *)
Definition: units.cpp:733
void unit_push_num(double d)
Definition: units.cpp:296
static int UnitsOn
Definition: units.cpp:46
static char * names
Definition: units.cpp:110
static char * unames[NDIM]
Definition: units.cpp:85
int unitonflag
Definition: units.cpp:45
void Unit_cmp()
Definition: units.cpp:446
static FILE * inpfile
Definition: units.cpp:126
#define SUFFIX
Definition: units.cpp:63
void unitcheck(char *s)
Definition: units.cpp:301
int lookup(char *name, unit *up, int den, int c)
Definition: units.cpp:806
static char * dfile
Definition: units.cpp:73
static char * neuronhome()
Definition: units.cpp:154
static void switch_units(int legacy)
Definition: units.cpp:339
void ucopypush(unit *up)
Definition: units.cpp:267
int convr(unit *)
Definition: units.cpp:757
static int dumpflg
Definition: units.cpp:129
void nrnunit_dynamic_str(char *buf, const char *name, char *u1, char *u2)
Definition: units.cpp:1172
void install_units(char *s1, char *s2)
Definition: units.cpp:346
void ucopypop(unit *up)
Definition: units.cpp:257
void diag(char *, char *)
Definition: io.cpp:114
static int Getc(FILE *inp)
Definition: units.cpp:133
int get()
Definition: units.cpp:1110
void unit_pop()
Definition: units.cpp:212
#define UNIT_STK_SIZE
Definition: units.cpp:151
void unit_mul()
Definition: units.cpp:368
#define OUTTOLERANCE(arg1, arg2)
Definition: units.cpp:56
static struct table * table
void Unit_push(char *)
Definition: units.cpp:277
void unit_less()
Definition: units.cpp:556
int unit_cmp_exact()
Definition: units.cpp:416
static char * pc
Definition: units.cpp:131
static int equal(char *s1, char *s2)
Definition: units.cpp:863
void unit_swap()
Definition: units.cpp:222
void Unit_exponent(int val)
Definition: units.cpp:400
static int fperrc
Definition: units.cpp:127
#define IFUNITS
Definition: units.cpp:51
static char * ucp
Definition: units.cpp:180
static struct unit unit_stack[UNIT_STK_SIZE]
Definition: units.cpp:152
char * Unit_str(unit *up)
Definition: units.cpp:181
static char * dfilealt
Definition: units.cpp:82
struct table * hash_table(char *)
Definition: units.cpp:1132
int unit_diff()
Definition: units.cpp:495
double getflt()
Definition: units.cpp:1049
void chkfperror()
Definition: units.cpp:533
void fperr(int)
Definition: units.cpp:1156
void dimensionless()
Definition: units.cpp:539
void unit_stk_clean()
Definition: units.cpp:571
void unit_div()
Definition: units.cpp:384
void punit()
Definition: units.cpp:250
static void print_unit_expr(int i)
Definition: units.cpp:444
void check_num()
Definition: units.cpp:358
int pu(int, int, int)
Definition: units.cpp:737
static struct unit * usp
Definition: units.cpp:152
void units_cpp_init()
Definition: units.cpp:874
void modl_units()
#define printf
Definition: mwprefix.h:26
#define fprintf
Definition: mwprefix.h:30
#define nrn_assert(ex)
Definition: nrnassrt.h:53
size_t q
size_t p
size_t j
#define e
Definition: passive0.cpp:22
FILE * fopen()
#define NULL
Definition: sptree.h:16
double factor
Definition: units.cpp:120
char * pname
Definition: units.cpp:121
Definition: units.cpp:100
double factor
Definition: units.cpp:101
char * name
Definition: units.cpp:107
signed char dim[NDIM]
Definition: units.cpp:105
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