NAMD
ParseOptions.C
Go to the documentation of this file.
1 
7 /*
8  Defines a set of dependencies, units, ranges, defaults, and info
9  messages which simplify the parsing of a ConfigList
10 */
11 
12 #include <stdlib.h>
13 #include <string.h>
14 #include "ParseOptions.h"
15 #include "ConfigList.h"
16 #include "InfoStream.h"
17 
18 #include "strlib.h" // For strcasecmp and strncasecmp
19 
20 #ifdef NAMD_TCL
21 #include <tcl.h>
22 #endif
23 
24 // given the range, return the string
25 const char *rstring(Range r)
26 {
27  switch (r) {
28  case FREE_RANGE: return "unconstrained";
29  case POSITIVE: return "positive";
30  case NOT_NEGATIVE: return "non-negative";
31  case NEGATIVE: return "negative";
32  case NOT_POSITIVE: return "non-positive";
33  default: return "error in rstring(Range )";
34  }
35 }
36 
37 static const char *unit_string_array[N_UNITS_UNDEFINED+1] = {
38  "", "fs", "ns", "sec", "min", "hr", "A", "nm", "m",
39  "kcal", "kJ", "eV", "K", "undefined units"
40 };
41 // given the units, return the string
42 const char *ustring(Units u)
43 {
44  return unit_string_array[u];
45 }
46 // little function so I can do for loops nicely
47 // static, so it never leaves the .C
48 Units static next(Units u) {
49  switch (u) {
50  case N_UNIT: return N_FSEC;
51  case N_FSEC: return N_NSEC;
52  case N_NSEC: return N_SEC;
53  case N_SEC: return N_MIN;
54  case N_MIN: return N_HOUR;
55  case N_HOUR: return N_ANGSTROM;
56  case N_ANGSTROM: return N_NANOMETER;
57  case N_NANOMETER: return N_METER;
58  case N_METER: return N_KCAL;
59  case N_KCAL: return N_KJOULE;
60  case N_KJOULE: return N_EV;
61  case N_EV: return N_KELVIN;
62  case N_KELVIN: return N_UNITS_UNDEFINED;
63  default: return N_UNITS_UNDEFINED;
64  }
65 }
66 
67 // convert from a string to Units
68 Units ParseOptions::atoUnits(const char *s) {
69  Units u;
70  for (u=N_UNIT; u!=N_UNITS_UNDEFINED; u = ::next(u)) {
71  if (!strcasecmp(unit_string_array[u], s)) return u;
72  }
73  if (!strcasecmp(s, "Angstrom")) return N_ANGSTROM;
74  if (!strcasecmp(s, "kcal/mol")) return N_KCAL;
75  if (!strcasecmp(s, "kJ/mol")) return N_KJOULE;
76  return N_UNITS_UNDEFINED;
77 }
78 
79 
80 // returns the scaling factor "sf" such that from*sf == to
81 // returns 0 if there is no conversion (like from METER to SEC)
83  1, 1, 1000, 1E15, 60E15, 3600E15, 1, 10, 1E10, 1, 1/4.1855, 1/23.052,
84  1, 0
85 };
86 
87 // find the convertion factor "cf" such that to = cf * from
88 // or return 0 of there is an error
90 {
91 // cout << "Converting from " << string(from) << " to " << string(to) << std::endl;
92 // cout << scaling_factors[from] << " <--> " << scaling_factors[to] << std::endl;
93  if (from == N_UNIT && to == N_UNIT) { return 1.0; }
94  if ((from == N_NSEC || from == N_FSEC || from == N_SEC || from == N_MIN ||
95  from == N_HOUR) &&
96  (to == N_NSEC || to == N_FSEC || to == N_SEC || to == N_MIN ||
97  to == N_HOUR)) {
98  return scaling_factors[from]/scaling_factors[to];
99  }
100  if ((from == N_METER || from == N_NANOMETER || from == N_ANGSTROM) &&
101  (to == N_METER || to == N_NANOMETER || to == N_ANGSTROM)) {
102  return scaling_factors[from]/scaling_factors[to];
103  }
104  if ((from == N_KCAL || from == N_KJOULE || from == N_EV) &&
105  (to == N_KCAL || to == N_KJOULE || to == N_EV)) {
106  return scaling_factors[from]/scaling_factors[to];
107  }
108  if (from == N_KELVIN && to == N_KELVIN) {
109  return scaling_factors[from]/scaling_factors[to];
110  }
111  return 0.0;
112 }
113 
114 static char *Strdup(const char *newname)
115 {
116  char *tmp = new char[strlen(newname)+1];
117  strcpy(tmp, newname);
118  return tmp;
119 }
120 
121 // Initialize a DataElement; this is called by all the constructors
122 void ParseOptions::DataElement::init(const char *newname,
123  const char *newparent, int optional, const char *err) {
124  name = Strdup(newname);
125  index = -1;
127  is_defined = FALSE;
128  parent = Strdup(newparent);
129  parent_ptr = NULL;
130  error_message = Strdup(err);
131  type = UNDEF;
132  has_default = FALSE;
134  idef = 0;
135  iptr = NULL;
136  range = FREE_RANGE;
137  units = N_UNIT;
138 }
139 
140 #define dataelement_cons_macro_default(Mtype, MType, Mptr, Mdef) \
141 ParseOptions::DataElement::DataElement(const char *newname, \
142  const char *newparent, int optional, const char *err, \
143  Mtype *ptr, Mtype defalt) \
144 { \
145  init(newname, newparent, optional, err); \
146  type = MType; \
147  Mptr = ptr; \
148  Mdef = defalt; \
149  has_default = TRUE; \
150  if ( ptr ) *ptr = defalt; \
151 }
152 
153 #define dataelement_cons_macro(Mtype, MType, Mptr) \
154 ParseOptions::DataElement::DataElement(const char *newname, \
155  const char *newparent, int optional, const char *err, \
156  Mtype *ptr) \
157 { \
158  init(newname, newparent, optional, err); \
159  type = MType; \
160  Mptr = ptr; \
161 }
162 
163 dataelement_cons_macro_default(BigReal, FLOAT, fptr, fdef);
164 dataelement_cons_macro_default(int, INT, iptr, idef);
165 dataelement_cons_macro_default(unsigned int, UINT, uiptr, uidef);
167 
168 //dataelement_cons_macro_default(int, BOOL, iptr, idef);
169 dataelement_cons_macro(BigReal, FLOAT, fptr);
171 dataelement_cons_macro(int, INT, iptr);
172 dataelement_cons_macro(unsigned int, UINT, uiptr);
173 //dataelement_cons_macro(int, BOOL, iptr);
174 dataelement_cons_macro(char, STRING, sptr);
175 
176 
177 // This is a "STRINGLIST", which has NO default element
179  const char *newparent, int optional, const char *err, StringList **ptr,
180  int many)
181 {
182  init(newname, newparent, optional, err);
184  slptr = ptr;
185  has_default = FALSE;
186  many_allowed = many;
187 }
188 
189 // free up what needs to be freed
191  if (name) delete[] name;
192  if (parent) delete[] parent;
193  if (error_message) delete[] error_message;
194 }
196 
197 // Initialize the data array to 20 element, and
198 // start it off with the "main" DataElement
200  configList = NULL;
201  array_size = 0;
202  array_max_size = 20;
203  data_array = new DataElement*[array_max_size];
204  DataElement *tmp = new DataElement("main", "main", TRUE,
205  "Error in ParseOptions",
206  (int *) NULL, 0);
207  tmp->type = DataElement::UNDEF;
208  add_element(tmp);
209 }
210 
211 // delete the data array
213  for (int i=0; i<array_size; i++) {
214  delete data_array[i];
215  }
216  delete [] data_array;
217 }
218 
219 // add the new element to the array,
220 void ParseOptions::add_element(DataElement *el) {
221  if (array_size == array_max_size) { // grow the array, if need be
222  array_max_size += 30;
223  DataElement **tmp = new DataElement*[array_max_size];
224  memcpy(tmp, data_array, array_size * sizeof(DataElement *)); // copy
225  delete [] data_array;
226  data_array = tmp;
227  }
228  el->index = array_size; // append the new element to the array
229  data_array[array_size++] = el;
230 }
231 
232 // update so that the elements are properly dependent
233 // returns 1 if everything set okay, 0 if no
234 int ParseOptions::make_dependencies(DataElement *el) {
235  int i;
236  // check if it is dependent on itself
237  if (!strcasecmp(el->name, el->parent)) {
238  return FALSE;
239  }
240  // check that there is no element with this name
241  for (i=0; i<array_size; i++) {
242  if (!strcasecmp(data_array[i]->name, el->name) &&
243  el != data_array[i]) {
244  return FALSE;
245  }
246  }
247 
248  // check if el's parent has already been inserted
249  for (i=0; i<array_size; i++) {
250  if (!strcasecmp(data_array[i]->name, el->parent)) {
251  el->parent_ptr = data_array[i];
252  break;
253  }
254  }
255 
256  // check if el is the parent of any already inserted
257  // element
258  for (i=0; i<array_size; i++) {
259  if (!data_array[i]->parent_ptr) {
260  if (!strcasecmp(data_array[i]->parent,
261  el->name)) {
262  data_array[i]->parent_ptr = el;
263  }
264  }
265  }
266  return TRUE;
267 }
268 
269 
271 #define parse_input_macro_default(fctnname, type, optional) \
272 int ParseOptions::fctnname(const char *parent, const char *newname, \
273  const char *msg, type *ptr, type defalt) \
274 { \
275  DataElement *tmp = new DataElement(newname, parent, optional, msg, \
276  ptr, defalt); \
277  if (!make_dependencies(tmp)) { \
278  iout << iERROR << "ParseOption '" << newname << "' already exists" << "\n" << endi; \
279  return FALSE; \
280  } \
281  add_element(tmp); \
282  return TRUE; \
283 }
284 #define parse_input_macro(fctnname, type, optional) \
285 int ParseOptions::fctnname(const char *parent, const char *newname, \
286  const char *msg, type *ptr) \
287 { \
288  DataElement *tmp = new DataElement(newname, parent, optional, msg, \
289  ptr); \
290  if (!make_dependencies(tmp)) { \
291  iout << iERROR << "ParseOption '" << newname << "' already exists" << "\n" << endi; \
292  return FALSE; \
293  } \
294  add_element(tmp); \
295  return TRUE; \
296 }
297 #define parse_input_macro_default_b(fctnname, type, optional, extra) \
298 int ParseOptions::fctnname(const char *parent, const char *newname, \
299  const char *msg, type *ptr, type defalt) \
300 { \
301  DataElement *tmp = new DataElement(newname, parent, optional, msg, \
302  ptr, defalt); \
303  if (!make_dependencies(tmp)) { \
304  iout << iERROR << "ParseOption '" << newname << "' already exists" << "\n" << endi; \
305  return FALSE; \
306  } \
307  add_element(tmp); \
308  extra; \
309  return TRUE; \
310 }
311 #define parse_input_macro_b(fctnname, type, optional, extra) \
312 int ParseOptions::fctnname(const char *parent, const char *newname, \
313  const char *msg, type *ptr) \
314 { \
315  DataElement *tmp = new DataElement(newname, parent, optional, msg, \
316  ptr); \
317  if (!make_dependencies(tmp)) { \
318  iout << iERROR << "ParseOption '" << newname << "' already exists" << "\n" << endi; \
319  return FALSE; \
320  } \
321  add_element(tmp); \
322  extra; \
323  return TRUE; \
324 }
325 
326 parse_input_macro(require, BigReal, FALSE); // the ; is there to look pretty
329 parse_input_macro(require, unsigned int, FALSE);
332 
336 parse_input_macro(optional, unsigned int, TRUE);
339 
343 parse_input_macro_default(require, unsigned int, FALSE);
345 
349 parse_input_macro_default(optional, unsigned int, TRUE);
351 
352 #define parse_stringlist_macro(fctn, xxx) \
353 int ParseOptions::fctn(const char *parent, const char *newname, \
354  const char *msg, StringList **ptr, int many_allowed)\
355 { \
356  DataElement *tmp = new DataElement(newname, parent, xxx, msg, \
357  ptr, many_allowed); \
358  if (!make_dependencies(tmp)) { \
359  iout << iERROR << "ParseOption '" << newname << "' already exists" << "\n" << endi;\
360  return FALSE; \
361  } \
362  add_element(tmp); \
363  return TRUE; \
364 }
367 
368 
369 // find all the children of the given element; returns 0
370 // if a loop was detected. Children are marked with a 1 in the
371 // appropriate location in the flag array
372 int ParseOptions::check_children(int idx, int *flgs)
373 {
374  if (flgs[idx]) { // oops, been here before
375  return 0;
376  }
377  flgs[idx] = 1;
378  for (int i=0; i<array_size; i++) {
379  if (data_array[i]->parent_ptr == data_array[idx]) {
380  if (!check_children(i, flgs)) {
381  return 0;
382  }
383  }
384  }
385  return 1;
386 }
387 
388 // see if there are elements which have no parent (except main)
389 // or elements inaccessible via main
390 // returns a 0 if there was an error
392  int i;
393  // check for lack of parent
394  {
395  int has_error = FALSE;
396  for(i=1; i<array_size; i++) {
397  if (!data_array[i]->parent_ptr) {
398  // missing a parent
399  iout << iERROR << "Configuration element '" << data_array[i]->name
400  << "' defined, but the parent element" << "\n" << endi;
401  iout << iERROR << " '" << data_array[i]->parent << "' is nowhere "
402  << "to be found" << "\n" << endi;
403  has_error = TRUE;
404  }
405  }
406  if (has_error) return 0;
407  }
408 
409  // check for loop constructs in the "main" heirarchy
410  int *arr = new int[array_size];
411  for (i=0; i<array_size; i++) { // initialize it
412  arr[i] = 0;
413  }
414  if (!check_children(0, arr)) {
415  // a loop was found
416  iout << iERROR << "Loop found in ParseOptions data" << "\n" << endi;
417  delete [] arr;
418  return 0;
419  }
420 
421  // check for elements inaccessible to "main"
422  {
423  int has_error = FALSE;
424  for (i=1; i<array_size; i++) {
425  if (arr[i] == 0) {
426  // found an inaccesible element
427  if (has_error == FALSE) { // first time, so print message
428  iout << iERROR
429  << "Found data in ParseOptions which are inaccessible "
430  << "to" << "\n" << endi;
431  iout << iERROR
432  << "the main data hierarchy. Errors in:" << "\n" << endi;
433  has_error = TRUE;
434  }
435  iout << iERROR << " '" << data_array[i]->name << "' depends on '"
436  << data_array[i]->parent << "'" << "\n" << endi;
437  }
438  }
439  if (has_error) {
440  delete [] arr;
441  return 0;
442  }
443  }
444  // looks like everything went well
445  delete [] arr;
446  return 1;
447 }
448 
449 // convert from a string to Bool; returns 1(TRUE) 0(FALSE) or -1(if unknown)
450 int ParseOptions::atoBool(const char *s)
451 {
452  if (!strcasecmp(s, "on")) return 1;
453  if (!strcasecmp(s, "off")) return 0;
454  if (!strcasecmp(s, "true")) return 1;
455  if (!strcasecmp(s, "false")) return 0;
456  if (!strcasecmp(s, "yes")) return 1;
457  if (!strcasecmp(s, "no")) return 0;
458  if (!strcasecmp(s, "1")) return 1;
459  if (!strcasecmp(s, "0")) return 0;
460  return -1;
461 }
462 
463 // A "Boolean" can indicate 1 of 2 things, either a simple
464 // yes/ no flag for a piece of data, or a on/ off for a
465 // set of parameters. The distinction is if the option
466 // has children. In "set", if the option is defined and
467 // is false and has children, then it is made undefined,
468 // so that other elements won't be parsed
469 Bool ParseOptions::is_parent_node(DataElement *el) {
470  for (int i=1; i<array_size; i++) {
471  if (data_array[i]->parent_ptr == el) {
472  return 1;
473  }
474  }
475  return 0;
476 }
477 
478 // given a string, read in the float and (perhaps) units,
479 // do the needed conversions, check for errors, etc...
480 Bool ParseOptions::scan_float(DataElement *data, const char *s)
481 {
482  double input_value; // I do this since I don't know if "BigReal" is
483  BigReal fval; // float or double, and I need to know for the
484  char units_str[80]; // sscanf
485  char tmp_str[80];
486  int count = sscanf(s, "%lf%s%s", &input_value, units_str, tmp_str);
487  if (count > 1 && units_str[0] == '.' &&
488  input_value == (double)(long int)input_value) { // for final . on Mac
489  long int input_long;
490  count = sscanf(s, "%ld.%s%s", &input_long, units_str, tmp_str);
491  if ( count < 1 || input_value != (double)input_long ) {
492  iout << iERROR << "Could not parse option '"
493  << data->name << " = " << s << "'\n" << endi;
494  return FALSE;
495  }
496  }
497  fval = input_value;
498  if (count == 1) { // no units given, so simply apply the number
499  data->fdata = fval;
500  return TRUE;
501  }
502  if (count == 2) { // number and units
503  Units u = atoUnits(units_str);
504  if (u == N_UNITS_UNDEFINED) {
505  iout << iERROR << "Could not understand units '" << units_str
506  << "' in option '" << data->name << " = " << s
507  << "\n" << endi;
508  return FALSE;
509  }
510  BigReal scale = convert(data->units, u);
511  if (scale == 0) {
512  iout << iERROR << "Could not translate from units '" << ustring(u)
513  << "' to '" << ustring(data->units) << "' for option '"
514  << data->name << "'" << "\n" << endi;
515  return FALSE;
516  }
517 // cout << "fval == " << fval << " scale == " << scale << std::endl;
518  data->fdata = fval * scale;
519  return TRUE;
520  }
521  if (count <=0) { // not enough
522  iout << iERROR << "Expecting value and optional units for option '"
523  << data->name << "'" << "\n" << endi;
524  }
525  if (count > 2) { // too many
526  iout << iERROR << "Too much information given to '" << data -> name
527  << " = " << s << "'" << "\n" << endi;
528  iout << iERROR << " - expecting a value and optional units" << "\n" << endi;
529  }
530  return FALSE;
531 }
532 
533 // no units are allowed (yet?) for a vector
534 Bool ParseOptions::scan_vector(DataElement *data, const char *s)
535 {
536  Vector v;
537  if (!v.set(s)) {
538  iout << iERROR << "Could not translate the value '" << s << "'" << "\n" << endi;
539  iout << iERROR << " into a Vector for the option '" << data->name << "'"
540  << "\n" << endi;
541  return FALSE;
542  }
543  data->vdata = v;
544  return TRUE;
545 }
546 
547 // read an int from string. No units are supported for ints,
548 // though they could be. (eg, 1 KB, ...)
549 Bool ParseOptions::scan_int(DataElement *data, const char *s)
550 {
551  int ival;
552  char units_str[80];
553  char tmp_str[80];
554  int count = sscanf(s, "%d%s%s", &ival, units_str, tmp_str);
555  if (count == 1) {
556  data->idata = ival;
557  return TRUE;
558  }
559  iout << iERROR << "Expecting only a number for '" << data->name
560  << "' input, got: " << s << "\n" << endi;
561  return FALSE;
562 }
563 
564 // read an unsigned int from string. No units are supported for ints,
565 // though they could be. (eg, 1 KB, ...)
566 Bool ParseOptions::scan_uint(DataElement *data, const char *s)
567 {
568  unsigned int ival;
569  char units_str[80];
570  char tmp_str[80];
571  int count = sscanf(s, "%u%s%s", &ival, units_str, tmp_str);
572  if (count == 1) {
573  data->idata = ival;
574  return TRUE;
575  }
576  iout << iERROR << "Expecting only a number for '" << data->name
577  << "' input, got: " << s << "\n" << endi;
578  return FALSE;
579 }
580 
581 Bool ParseOptions::scan_bool(DataElement *data, const char *s)
582 {
583  int tmp = atoBool(s); // convert the boolean
584 
585  if (tmp == -1)
586  {
587  iout << iERROR << "ParseOptions can't understand '" << s << "' for the "
588  << "\n" << endi;
589  iout << iERROR << " Boolean variable '" << data->name << "'" << "\n" << endi;
590 
591  data->idata = FALSE;
592 
593  return FALSE;
594  }
595 
596  data->idata = tmp; // set the value, if understood
597 
598  return TRUE;
599 }
600 
601 // check the range and, if valid, set the variable and return 1
602 // if bad range, print error message and return 0
603 #define set_macro(type, field, fieldptr) \
604 int ParseOptions::set_##type(DataElement *el) \
605 { \
606  if (el->range == FREE_RANGE || \
607  (el->range == POSITIVE && el->field > 0) || \
608  (el->range == NOT_NEGATIVE && el->field >= 0) || \
609  (el->range == NEGATIVE && el->field < 0) || \
610  (el->range == NOT_POSITIVE && el->field <= 0)) { \
611  if (el->fieldptr) *(el->fieldptr) = el->field; \
612  return 1; \
613  } \
614  iout << iERROR << "'" << el->name << "' was set to " << el->field << " but it " \
615  << "should be " << rstring(el->range) \
616  << "\n" << endi; \
617  return 0; \
618 }
619 set_macro(float, fdata, fptr);
620 set_macro(int, idata, iptr);
621 set_macro(uint, uidata, uiptr);
622 
623 // for elements without ranges
624 #define simple_set_macro(type, field, fieldptr) \
625 void ParseOptions::set_##type(DataElement *el) \
626 { \
627  if (el->fieldptr) *(el->fieldptr) = el->field; \
628 }
629 
630 simple_set_macro(bool, idata, iptr);
631 simple_set_macro(vector, vdata, vptr);
632 simple_set_macro(stringlist, sldata, slptr);
633 // simple_set_macro(string, sldata->data, sptr);
634 
635 void ParseOptions::set_string(DataElement *el)
636 {
637  if (el->sptr) strcpy(el->sptr, el->sldata->data);
638 }
639 
640 // set the variables, given the contents of the ConfigList
641 // return FALSE if there was an error
643 {
644  // the algorithm is easy, though it looks scary
645  int cont = TRUE, i; // do some initialization
646  StringList *slptr;
647  DataElement *data;
648  int has_error = FALSE;
649  int *checked = new int[array_size];
650  configList = &clist;
651 
652  // I make here a list of element I have already checked, starting
653  // at the head. I check only children of those that have already
654  // been defined and add it to the checked list
655  for (i=0; i<array_size; i++)
656  {
657  checked[i] = FALSE;
658  }
659 
660  // make "main" 'defined' (at this point, nothing else should be defined)
661  data_array[0]->is_defined = TRUE;
662  checked[0] = TRUE; // and make "main" checked
663 
664  // while there is still data which hasn't been defined
665  while (cont)
666  {
667  cont = FALSE;
668  for (i=1; i<array_size; i++)
669  { // check each element
670  data = data_array[i];
671 
672  // find unchecked data which has a parent which was checked
673  // and defined
674  if (!checked[data->index] &&
675  checked[data-> parent_ptr -> index] &&
676  data -> parent_ptr -> is_defined)
677  {
678  cont = TRUE;
679  checked[data->index] = TRUE; // so I don't check again
680 
681  // check to see if data is available in the StringList
682  slptr = clist.find(data->name);
683 
684  if (slptr != NULL)
685  { // it is
686 
687  // most data types allow only 1 item, so check if that is
688  // a problem. (some StringLists, like 'parameters', allow
689  // multiple strings)
690  if (!data->many_allowed && slptr->next != NULL)
691  {
692  iout << iERROR << "Multiple definitions of '" << data->name << "'" << "\n" << endi;
693  iout << iERROR << " in the configuration file are not allowed" << "\n" << endi;
694  has_error = TRUE;
695  }
696 
697  data->is_defined = TRUE;
698 
699  // set the appropriate data field
700  if (data->type == DataElement::FLOAT)
701  {
702  if (!scan_float(data, slptr->data))
703  has_error = TRUE;
704  }
705  else if (data->type == DataElement::VECTOR)
706  {
707  if (!scan_vector(data, slptr->data))
708  has_error = TRUE;
709  }
710  else if (data->type == DataElement::INT)
711  {
712  if (!scan_int(data, slptr->data))
713  has_error = TRUE;
714  }
715  else if (data->type == DataElement::UINT)
716  {
717  if (!scan_uint(data, slptr->data))
718  has_error = TRUE;
719  }
720  else if (data->type == DataElement::BOOL)
721  {
722  if (!scan_bool(data, slptr->data))
723  has_error = TRUE;
724  }
725  else if (data->type == DataElement::STRINGLIST ||
726  data->type == DataElement::STRING )
727  {
728  data->sldata = slptr;
729  }
730  else
731  {
732  iout << iERROR << "Unknown ParseOption data type " << (int)(data->type) << " for "
733  << "variable " << data->name << "\n" << endi;
734  has_error = TRUE;
735  }
736  }
737  else
738  { // no definition; is there a default?
739  if (data->has_default)
740  {
741  data->is_defined = TRUE;
742 
743  if (data->type == DataElement::FLOAT)
744  {
745  data->fdata = data->fdef;
746  }
747  else if (data->type == DataElement::VECTOR)
748  {
749  data->vdata = data->vdef;
750  }
751  else if (data->type == DataElement::UINT)
752  {
753  data->uidata = data->uidef;
754  }
755  else if (data->type == DataElement::INT ||
756  data->type == DataElement::BOOL)
757  {
758  data->idata = data->idef;
759  }
760  else
761  {
762  iout << iERROR << "Unknown ParseOption data type " << (int)(data->type) << " for "
763  << "variable " << data->name << "\n" << endi;
764  has_error = TRUE;
765  }
766  }
767  }
768 
769  // at this point we should have gotten data from the file or the defaults,
770  // or it hasn't yet been defined. If it still isn't defined, check
771  // to see if it is optional
772  if (!data->is_defined)
773  { // if still not defined,
774  if (!data->is_optional)
775  { // it is it required
776  has_error = TRUE;
777  iout << iERROR << "'" << data->name << "' is a required configuration option" << "\n" << endi;
778 
779  // print some helpful information if this isn't a "main" option
780  if (data->parent_ptr != data_array[0])
781  {
782  iout << iERROR << " when '" << data->parent_ptr -> name << "' is set" << "\n" << endi;
783  } // printed parent info
784 
785  iout << iERROR << data->name << " defines: " << data->error_message << "\n" << endi;
786 
787  } // printed error message
788  }
789  else
790  { // there was a definition, so assign to the variable
791  if (data->type == DataElement::FLOAT)
792  {
793  if (!set_float(data))
794  has_error = TRUE;
795  }
796  else if ( data -> type == DataElement::VECTOR)
797  {
798  set_vector(data);
799  }
800  else if ( data -> type == DataElement::INT)
801  {
802  if (!set_int(data))
803  has_error = TRUE;
804  }
805  else if ( data -> type == DataElement::UINT)
806  {
807  if (!set_uint(data))
808  has_error = TRUE;
809  }
810  else if ( data -> type == DataElement::BOOL)
811  {
812  set_bool(data);
813 
814  if (is_parent_node(data))
815  {
816  // this makes the boolean variable undefined if it is 'off'
817  // _and_ it is a parent; this makes it agree with namd's
818  // configuration option semantics
819  data->is_defined = data->idata;
820  }
821  }
822  else if ( data -> type == DataElement::STRINGLIST)
823  {
824  set_stringlist(data);
825  }
826  else if ( data -> type == DataElement::STRING)
827  {
828  set_string(data);
829  }
830  else
831  {
832  // already printed the error message
833  }
834  }
835  } // end of checking the available variables
836  } // end of pass through the list
837  } // end of finding data in the ConfigList
838 
839 
840  // and now print the warning messages
841 
842  // first, find elements which are in the configuration file and are
843  // valid, but which were not needed (ie, the checked array wasn''t set)
844  {
845  int flg = 0;
846 
847  for (int i=1; i<array_size; i++)
848  {
849  if (!checked[i]) { // wasn't needed
850  data = data_array[i];
851  if (clist.find(data->name)) {
852  if (flg == 0) {
853  flg = 1;
854  iout << iWARN
855  << "The following variables were set in the\n";
856  iout << iWARN
857  << "configuration file but will be ignored:\n" << endi;
858  }
859  iout << iWARN << " " << data->name;
860  if (data->parent_ptr != data_array[0]) {
861  iout << " (" << data->parent_ptr->name << ")";
862  }
863  iout << "\n" << endi;
864  }
865  }
866  }
867  }
868  // and now look for names which are in the config list but which
869  // are not in the parseoptions list
870  {
871  int flg = 0;
872  ConfigList::ConfigListNode const *ptr;
873  for (ptr = clist.head(); ptr != NULL; ptr = ptr -> next) {
874  if (!exists(ptr -> name)) {
875  if (flg == 0) {
876  flg = 1;
877  has_error = TRUE;
878  iout << iERROR
879  << "The following variables were set in the\n";
880  iout << iERROR
881  << "configuration file but are NOT VALID\n" << endi;
882  }
883  iout << iERROR << " " << ptr -> name << "\n" << endi;
884  }
885  }
886  }
887 
888  delete [] checked;
889  return !has_error;
890 }
891 
892 // simple search though the list; return NULL if not found
893 ParseOptions::DataElement *ParseOptions::internal_find(const char* name)
894 {
895  for (int i=1; i<array_size; i++) {
896  if (!strcasecmp(name, data_array[i]->name)) {
897  return data_array[i];
898  }
899  }
900  return NULL;
901 }
902 
903 // returns 1 if the given name exists; 0 if no
904 Bool ParseOptions::exists(const char *name)
905 {
906  if (!name) return 0;
907  if (internal_find(name)) {
908  return 1;
909  }
910  return 0;
911 }
912 // returns 1 if the element name exists and is defined
913 Bool ParseOptions::defined(const char *name)
914 {
915  if (!name) return FALSE;
916  DataElement *tmp = internal_find(name);
917  if (!tmp) return FALSE;
918  if (tmp->is_defined) {
919  return TRUE;
920  }
921  return FALSE;
922 }
923 
924 #ifdef NAMD_TCL
925 #define PRINT_DOUBLE(BUF,VAL) Tcl_PrintDouble(0,VAL,BUF)
926 
927 static void PRINT_VECTOR(char *buf, Vector val) {
928  PRINT_DOUBLE(buf, val.x);
929  buf += strlen(buf); buf[0] = ' '; ++buf;
930  PRINT_DOUBLE(buf, val.y);
931  buf += strlen(buf); buf[0] = ' '; ++buf;
932  PRINT_DOUBLE(buf, val.z);
933  buf += strlen(buf); buf[0] = ' '; buf[1] = 0;
934 }
935 #endif
936 
938 char* ParseOptions::getfromptr(const char* name, char *outbuf) {
939 #ifdef NAMD_TCL
940  if ( ! name ) NAMD_bug("ParseOptions::getfromptr called with null name");
941  if ( ! outbuf ) NAMD_bug("ParseOptions::getfromptr called with null outbuf");
942  DataElement *el = internal_find(name);
943  if ( el == NULL ) return 0;
944  switch (el->type) {
945  case DataElement::FLOAT :
946  if ( el->fptr ) PRINT_DOUBLE(outbuf, *(el->fptr));
947  else PRINT_DOUBLE(outbuf, el->fdata);
948  return outbuf;
949  case DataElement::INT:
950  case DataElement::BOOL:
951  if ( el->iptr ) sprintf(outbuf,"%d", *(el->iptr));
952  else sprintf(outbuf,"%d", el->idata);
953  return outbuf;
955  if ( el->slptr ) return (*(el->slptr))->data;
956  else if ( el->sldata ) return el->sldata->data;
957  else return 0;
958  case DataElement::STRING :
959  if ( el->sptr ) return el->sptr;
960  else if ( el->sldata ) return el->sldata->data;
961  else return 0;
962  case DataElement::VECTOR :
963  if ( el->vptr ) PRINT_VECTOR(outbuf, *(el->vptr));
964  else PRINT_VECTOR(outbuf, el->vdata);
965  return outbuf;
966  default:
967  iout << iERROR
968  << "Unknown data type " << (int)(el->type) << " for '" << name << "'"
969  << "\n" << endi;
970  }
971 #endif
972  return 0;
973 }
974 
976 int ParseOptions::istruefromptr(const char* name) {
977  if ( ! name ) NAMD_bug("ParseOptions::getfromptr called with null name");
978  DataElement *el = internal_find(name);
979  if ( el == NULL ) return -1;
980  if ( el->type != DataElement::BOOL ) return -2;
981  if ( el->iptr ) return ((*(el->iptr)) ? 1 : 0);
982  if ( ! el->is_defined ) return -3; // ignores defaults
983  return (el->idata ? 1 : 0);
984 }
985 
987 int ParseOptions::issetfromptr(const char* name) {
988  if ( ! name ) NAMD_bug("ParseOptions::getfromptr called with null name");
989  DataElement *el = internal_find(name);
990  if ( el == NULL ) return -1;
991  return (el->is_defined ? 1 : 0);
992 }
993 
995 // get the value associated with the given name
996 // if there was a type conversion, print a warning message
997 // if the element wasn't found, return a FALSE, else return a TRUE
998 Bool ParseOptions::get(const char* name, int *val) {
999  if (!val) return FALSE;
1000  DataElement *el = internal_find(name);
1001  if (el == NULL || !el->is_defined) {
1002  return FALSE;
1003  }
1004  switch (el->type) {
1005  case DataElement::FLOAT :
1006  iout << iWARN
1007  << "ParseOptions doing a conversion from float to int for '"
1008  << name << "'" << "\n" << endi;
1009  *val = (int) el->fdata;
1010  return TRUE;
1011  case DataElement::INT:
1012  case DataElement::BOOL:
1013  *val = el->idata;
1014  return TRUE;
1016  case DataElement::STRING :
1017  iout << iWARN
1018  << "ParseOptions doing a conversion from StringList[0] to int "
1019  << "for '" << name << "'" << "\n" << endi;
1020  *val = atoi(el->sldata->data);
1021  return TRUE;
1022  case DataElement::VECTOR :
1023  iout << iERROR
1024  << "ParseOptions cannot convert from Vector to int for '"
1025  << name << "'" << "\n" << endi;
1026  return FALSE;
1027  default:
1028  iout << iERROR
1029  << "Unknown data type " << (int)(el->type) << " for '" << name << "'"
1030  << "\n" << endi;
1031  }
1032  return FALSE;
1033 }
1034 
1035 Bool ParseOptions::get(const char* name, BigReal *val) {
1036  if (!val) return FALSE;
1037  DataElement *el = internal_find(name);
1038  if (el == NULL || !el->is_defined) {
1039  return FALSE;
1040  }
1041  switch (el -> type) {
1042  case DataElement::FLOAT:
1043  *val = el->fdata;
1044  return TRUE;
1045  case DataElement::INT:
1046  iout << iWARN
1047  << "ParseOptions doing a conversion from int to float '"
1048  << name << "'" << "\n" << endi;
1049  *val = (BigReal) el->idata;
1050  return TRUE;
1051  case DataElement::BOOL:
1052  iout << iWARN
1053  << "ParseOptions doing a conversion from boolean to float for '"
1054  << name << "'" << "\n" << endi;
1055  *val = (BigReal) el->idata;
1056  return TRUE;
1057  case DataElement::STRING:
1059  iout << iWARN
1060  << "ParseOptions doing a conversion from StringList[0] to float "
1061  << "for '" << name << "'" << "\n" << endi;
1062  *val = atof(el->sldata->data);
1063  return TRUE;
1064  case DataElement::VECTOR :
1065  iout << iERROR
1066  << "ParseOptions cannot convert from Vector to float for '"
1067  << name << "'" << "\n" << endi;
1068  return FALSE;
1069  default:
1070  iout << iERROR
1071  << "Unknown data type " << (int)(el->type) << " for '" << name << "'"
1072  << "\n" << endi;
1073  }
1074  return FALSE;
1075 }
1076 Bool ParseOptions::get(const char *name, Vector *val) {
1077  if (!val) return FALSE;
1078  DataElement *el = internal_find(name);
1079  if (el == NULL || !el->is_defined) {
1080  return FALSE;
1081  }
1082  switch (el -> type) {
1083  case DataElement::FLOAT:
1084  iout << iERROR
1085  << "ParseOptions cannot convert from float to Vector for '"
1086  << name << "'" << "\n" << endi;
1087  return FALSE;
1088  case DataElement::INT:
1089  iout << iERROR
1090  << "ParseOptions cannot convert from int to Vector for '"
1091  << name << "'" << "\n" << endi;
1092  return FALSE;
1093  case DataElement::STRING:
1095  iout << iWARN
1096  << "ParseOptions doing a conversion from StringList[0] to "
1097  << "Vector for '" << name << "'" << "\n" << endi;
1098  Vector v;
1099  if (!v.set(el->sldata->data)) {
1100  iout << iERROR
1101  << "Could not convert '" << el->sldata->data
1102  << "' to a Vector";
1103  return FALSE;
1104  }
1105  *val = v;
1106  return TRUE;
1107  }
1108  case DataElement::VECTOR :
1109  *val = el->vdata;
1110  return TRUE;
1111  default:
1112  iout << iERROR
1113  << "Unknown data type " << (int)(el->type) << " for '" << name << "'"
1114  << "\n" << endi;
1115 
1116  }
1117  return FALSE;
1118 }
1119 Bool ParseOptions::get(const char *name, StringList **val) {
1120  if (!val) return FALSE;
1121  DataElement *el = internal_find(name); // first check it is internally valid
1122  if (el == NULL || !el->is_defined) {
1123  return FALSE;
1124  }
1125  // then simply ask the configList itself for the answer
1126  // (while I do keep the information internally, in sldata, why bother?
1127  if (!configList) { return FALSE; }
1128  *val = configList->find(name);
1129  if (!*val) { return FALSE; } // paranoia, I know...
1130  return TRUE;
1131 }
1132 
1133 // get the nth element of the StringList
1134 Bool ParseOptions::get(const char *name, char *val, int n)
1135 {
1136  if (!val || n<0) {return FALSE;}
1137  StringList *tmp;
1138  if (!get(name, &tmp)) {val[0]=STRINGNULL; return FALSE; }
1139  int i=n;
1140  while (i>0 && tmp) { // search for the nth element
1141  tmp=tmp->next;
1142  i--;
1143  }
1144  if (tmp) { // if it was long enough, return it
1145  strcpy(val, tmp->data);
1146  return TRUE;
1147  }
1148  val[0] = STRINGNULL;
1149  return FALSE;
1150 }
1151 
1152 
1153 int ParseOptions::num(const char *name)
1154 {
1155  DataElement *el = internal_find(name);
1156  if (!el || !el ->is_defined) {
1157  return 0;
1158  }
1159  if (!el->many_allowed) {
1160  return 1;
1161  }
1162  StringList *tmp;
1163  if (!get(name, &tmp)) { return 0; }
1164  int i=0;
1165  while (tmp) {
1166  i++;
1167  tmp=tmp->next;
1168  }
1169  return i;
1170 }
1171 
1172 
1173 // get or set the range for the given variable
1174 void ParseOptions::range(const char *name, Range newrange)
1175 {
1176  DataElement *el = internal_find(name);
1177  if (!el) {
1178  iout << iERROR
1179  << "Trying to set the range of undefined variable '"
1180  << name << "'" << "\n" << endi;
1181  return;
1182  }
1183  el->range = newrange;
1184 
1185 }
1186 Range ParseOptions::range(const char *name)
1187 {
1188  DataElement *el = internal_find(name);
1189  if (!el) {
1190  iout << iERROR
1191  << "Trying to get the range of undefined variable '"
1192  << name << "'" << "\n" << endi;
1193  return FREE_RANGE;
1194  }
1195  return el->range;
1196 }
1197 
1198 // get / set the units value
1199 Bool ParseOptions::units(const char *name, Units units) // get
1200 {
1201  DataElement *tmp = internal_find(name);
1202  if (!tmp) {
1203  iout << iERROR
1204  << name << " not found so units not set" << "\n" << endi;
1205  return FALSE;
1206  }
1207  if ((tmp -> type == DataElement::INT && units != N_UNIT) ||
1208  (tmp -> type != DataElement::INT &&
1209  tmp -> type != DataElement::FLOAT)) {
1210  iout << iERROR
1211  << "Cannot set units '" << ustring(units) << "' for option '"
1212  << name << "'; wrong data type" << "\n" << endi;
1213  return FALSE;
1214  }
1215  tmp -> units = units;
1216  return TRUE;
1217 }
1218 
1219 Bool ParseOptions::units(const char *name, Units *units) // set
1220 {
1221  DataElement *tmp = internal_find(name);
1222  *units = N_UNIT;
1223  if (!tmp) {
1224  iout << iERROR
1225  << "'" << name << "' doesn't exist so cannot get its units"
1226  << "\n" << endi;
1227  return FALSE;
1228  }
1229  if (tmp -> type != DataElement::INT &&
1230  tmp -> type != DataElement::FLOAT) {
1231  iout << iERROR
1232  << "Can only get units for FLOAT and INT variables, and '"
1233  << name << "' isn't one of those" << "\n" << endi;
1234  return FALSE;
1235  }
1236  *units = tmp->units;
1237  return TRUE;
1238 }
1239 
static char * Strdup(const char *newname)
Definition: ParseOptions.C:114
BigReal convert(Units to, Units from)
Definition: ParseOptions.C:89
#define simple_set_macro(type, field, fieldptr)
Definition: ParseOptions.C:624
DataElement(const char *newname, const char *newparent, int optional, const char *err, BigReal *ptr, BigReal defalt)
#define parse_input_macro_default_b(fctnname, type, optional, extra)
Definition: ParseOptions.C:297
#define set_macro(type, field, fieldptr)
Definition: ParseOptions.C:603
const char * ustring(Units u)
Definition: ParseOptions.C:42
Bool defined(const char *name)
Definition: ParseOptions.C:913
Bool units(const char *name, Units units)
Definition: Vector.h:64
#define parse_input_macro_default(fctnname, type, optional)
routines to add dependencies to the array
Definition: ParseOptions.C:271
static void PRINT_VECTOR(char *buf, Vector val)
Definition: ParseOptions.C:927
#define dataelement_cons_macro_default(Mtype, MType, Mptr, Mdef)
Definition: ParseOptions.C:140
std::ostream & endi(std::ostream &s)
Definition: InfoStream.C:54
BigReal z
Definition: Vector.h:66
#define FALSE
Definition: common.h:118
std::ostream & iWARN(std::ostream &s)
Definition: InfoStream.C:82
#define iout
Definition: InfoStream.h:51
int optionalB(const char *newname, const char *parent, const char *msg, int *ptr, int defalt)
char * getfromptr(const char *name, char *outbuf)
Definition: ParseOptions.C:938
Units
Definition: ParseOptions.h:28
int require(const char *newname, const char *parent, const char *msg, BigReal *ptr, BigReal defalt)
const char * rstring(Range r)
Definition: ParseOptions.C:25
ParseOptions(void)
Definition: ParseOptions.C:199
ConfigListNode * head(void) const
Definition: ConfigList.h:126
#define INT(X)
int num(const char *name)
static Units next(Units u)
Definition: ParseOptions.C:48
#define parse_stringlist_macro(fctn, xxx)
Definition: ParseOptions.C:352
Bool set(const ConfigList &configlist)
Definition: ParseOptions.C:642
#define parse_input_macro_b(fctnname, type, optional, extra)
Definition: ParseOptions.C:311
void NAMD_bug(const char *err_msg)
Definition: common.C:129
#define STRINGNULL
Definition: common.h:128
int Bool
Definition: common.h:133
DataElement * parent_ptr
Definition: ParseOptions.h:53
Range
Definition: ParseOptions.h:26
BigReal x
Definition: Vector.h:66
#define PRINT_DOUBLE(BUF, VAL)
Definition: ParseOptions.C:925
Bool set(const char *s)
Definition: Vector.h:228
int istruefromptr(const char *name)
Definition: ParseOptions.C:976
static const char * unit_string_array[N_UNITS_UNDEFINED+1]
Definition: ParseOptions.C:37
static BigReal scaling_factors[N_UNITS_UNDEFINED+1]
Definition: ParseOptions.C:82
#define parse_input_macro(fctnname, type, optional)
Definition: ParseOptions.C:284
StringList * next
Definition: ConfigList.h:49
~ParseOptions(void)
Definition: ParseOptions.C:212
char * data
Definition: ConfigList.h:48
int optional(const char *newname, const char *parent, const char *msg, BigReal *ptr, BigReal defalt)
BigReal y
Definition: Vector.h:66
Bool get(const char *name, int *val)
Definition: ParseOptions.C:998
StringList * find(const char *name) const
Definition: ConfigList.C:341
Range range(const char *name)
#define dataelement_cons_macro(Mtype, MType, Mptr)
Definition: ParseOptions.C:153
std::ostream & iERROR(std::ostream &s)
Definition: InfoStream.C:83
Bool check_consistency(void)
Definition: ParseOptions.C:391
int issetfromptr(const char *name)
Definition: ParseOptions.C:987
int requireB(const char *newname, const char *parent, const char *msg, int *ptr, int defalt)
#define TRUE
Definition: common.h:119
double BigReal
Definition: common.h:114
Bool exists(const char *name)
Definition: ParseOptions.C:904