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