ParseOptions.C

Go to the documentation of this file.
00001 
00007 /*
00008    Defines a set of dependencies, units, ranges, defaults, and info
00009    messages which simplify the parsing of a ConfigList
00010 */
00011 
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include "ParseOptions.h"
00015 #include "ConfigList.h"
00016 #include "InfoStream.h"
00017 
00018 #include "strlib.h"             //  For strcasecmp and strncasecmp
00019 
00020 #ifdef NAMD_TCL
00021 #define USE_COMPAT_CONST
00022 #include <tcl.h>
00023 #endif
00024 
00025 // given the range, return the string
00026 const char *rstring(Range r)
00027 {
00028    switch (r) {
00029     case FREE_RANGE: return "unconstrained";
00030     case POSITIVE: return "positive";
00031     case NOT_NEGATIVE: return "non-negative";
00032     case NEGATIVE: return "negative";
00033     case NOT_POSITIVE: return "non-positive";
00034     default: return "error in rstring(Range )";
00035    }
00036 }
00037    
00038 static const char *unit_string_array[N_UNITS_UNDEFINED+1] =  {
00039   "", "fs", "ns", "sec", "min", "hr", "A", "nm", "m", 
00040   "kcal", "kJ", "eV", "K", "undefined units"
00041 };
00042 // given the units, return the string
00043 const char *ustring(Units u) 
00044 {
00045    return unit_string_array[u];
00046 }
00047 // little function so I can do for loops nicely
00048 // static, so it never leaves the .C
00049 Units static next(Units u) {
00050   switch (u) {
00051    case N_UNIT: return N_FSEC;
00052    case N_FSEC: return N_NSEC;
00053    case N_NSEC: return N_SEC;
00054    case N_SEC: return N_MIN;
00055    case N_MIN: return N_HOUR;
00056    case N_HOUR:  return N_ANGSTROM;
00057    case N_ANGSTROM: return N_NANOMETER;
00058    case N_NANOMETER: return N_METER;
00059    case N_METER: return N_KCAL;
00060    case N_KCAL: return N_KJOULE;
00061    case N_KJOULE: return N_EV;
00062    case N_EV: return N_KELVIN;
00063    case N_KELVIN: return N_UNITS_UNDEFINED;
00064    default: return N_UNITS_UNDEFINED;
00065   }
00066 }
00067 
00068 // convert from a string to Units
00069 Units ParseOptions::atoUnits(const char *s) {
00070    Units u;
00071    for (u=N_UNIT; u!=N_UNITS_UNDEFINED; u = ::next(u)) {
00072       if (!strcasecmp(unit_string_array[u], s)) return u;
00073    }
00074    if (!strcasecmp(s, "Angstrom")) return N_ANGSTROM;
00075    if (!strcasecmp(s, "kcal/mol")) return N_KCAL;
00076    if (!strcasecmp(s, "kJ/mol")) return N_KJOULE;
00077    return N_UNITS_UNDEFINED;
00078 }
00079 
00080 
00081 // returns the scaling factor "sf" such that from*sf == to
00082 // returns 0 if there is no conversion (like from METER to SEC)
00083 static BigReal scaling_factors[N_UNITS_UNDEFINED+1] = {
00084    1, 1, 1000, 1E15, 60E15, 3600E15, 1, 10, 1E10, 1, 1/4.1855, 1/23.052,
00085    1, 0
00086 };
00087 
00088 // find the convertion factor "cf" such that to = cf * from
00089 // or return 0 of there is an error
00090 BigReal convert(Units to, Units from)
00091 {
00092 // cout << "Converting from " << string(from) << " to " << string(to) << std::endl;
00093 // cout << scaling_factors[from] << " <--> " << scaling_factors[to] << std::endl;
00094    if (from == N_UNIT && to == N_UNIT) { return 1.0; }
00095    if ((from == N_NSEC || from == N_FSEC || from == N_SEC || from == N_MIN || 
00096         from == N_HOUR) &&
00097        (to   == N_NSEC || to   == N_FSEC || to   == N_SEC || to   == N_MIN || 
00098         to   == N_HOUR)) {
00099       return scaling_factors[from]/scaling_factors[to];
00100    }
00101    if ((from == N_METER || from == N_NANOMETER || from == N_ANGSTROM) &&
00102        (to   == N_METER || to   == N_NANOMETER || to   == N_ANGSTROM)) {
00103       return scaling_factors[from]/scaling_factors[to];
00104    }
00105    if ((from == N_KCAL || from == N_KJOULE || from == N_EV) &&
00106        (to   == N_KCAL || to   == N_KJOULE || to   == N_EV)) {
00107       return scaling_factors[from]/scaling_factors[to];
00108    }
00109    if (from == N_KELVIN && to == N_KELVIN) {
00110       return scaling_factors[from]/scaling_factors[to];
00111    }
00112    return 0.0;
00113 }
00114 
00115 static char *Strdup(const char *newname)
00116 {
00117   char *tmp = new char[strlen(newname)+1];
00118   strcpy(tmp, newname);
00119   return tmp;
00120 }
00121 
00122 // Initialize a DataElement; this is called by all the constructors
00123 void ParseOptions::DataElement::init(const char *newname,
00124      const char *newparent, int optional, const char *err) {
00125    name = Strdup(newname);
00126    index = -1;
00127    is_optional = optional;
00128    is_defined = FALSE;
00129    parent = Strdup(newparent);
00130    parent_ptr = NULL;
00131    error_message = Strdup(err);
00132    type = UNDEF;
00133    has_default = FALSE;
00134    many_allowed = FALSE;
00135    idef = 0;
00136    iptr = NULL;
00137    range = FREE_RANGE;
00138    units = N_UNIT;
00139 }
00140 
00141 #define dataelement_cons_macro_default(Mtype, MType, Mptr, Mdef) \
00142 ParseOptions::DataElement::DataElement(const char *newname,      \
00143      const char *newparent, int optional, const char *err,       \
00144      Mtype *ptr, Mtype defalt)                                   \
00145 {                                                                \
00146    init(newname, newparent, optional, err);                      \
00147    type = MType;                                                 \
00148    Mptr = ptr;                                                   \
00149    Mdef = defalt;                                                \
00150    has_default = TRUE;                                           \
00151    if ( ptr ) *ptr = defalt;                                     \
00152 }
00153 
00154 #define dataelement_cons_macro(Mtype, MType, Mptr) \
00155 ParseOptions::DataElement::DataElement(const char *newname,      \
00156      const char *newparent, int optional, const char *err,       \
00157      Mtype *ptr)                                                 \
00158 {                                                                \
00159    init(newname, newparent, optional, err);                      \
00160    type = MType;                                                 \
00161    Mptr = ptr;                                                   \
00162 }
00163 
00164 dataelement_cons_macro_default(BigReal, FLOAT, fptr, fdef);
00165 dataelement_cons_macro_default(int, INT, iptr, idef);
00166 dataelement_cons_macro_default(unsigned int, UINT, uiptr, uidef);
00167 dataelement_cons_macro_default(Vector, VECTOR, vptr, vdef);
00168 
00169 //dataelement_cons_macro_default(int, BOOL, iptr, idef);
00170 dataelement_cons_macro(BigReal, FLOAT, fptr);
00171 dataelement_cons_macro(Vector, VECTOR, vptr);
00172 dataelement_cons_macro(int, INT, iptr);
00173 dataelement_cons_macro(unsigned int, UINT, uiptr);
00174 //dataelement_cons_macro(int, BOOL, iptr);
00175 dataelement_cons_macro(char, STRING, sptr);
00176 
00177 
00178 // This is a "STRINGLIST", which has NO default element
00179 ParseOptions::DataElement::DataElement(const char *newname,
00180       const char *newparent, int optional, const char *err, StringList **ptr,
00181       int many)
00182 {
00183    init(newname, newparent, optional, err);
00184    type = DataElement::STRINGLIST;
00185    slptr = ptr;
00186    has_default = FALSE;
00187    many_allowed = many;
00188 }
00189 
00190 // free up what needs to be freed
00191 ParseOptions::DataElement::~DataElement(void) {
00192    if (name) delete[] name;
00193    if (parent) delete[] parent;
00194    if (error_message) delete[] error_message;
00195 }
00197 
00198 // Initialize the data array to 20 element, and
00199 // start it off with the "main" DataElement
00200 ParseOptions::ParseOptions(void) {
00201    configList = NULL;
00202    array_size = 0;
00203    array_max_size = 20;
00204    data_array = new DataElement*[array_max_size];
00205    DataElement *tmp = new DataElement("main", "main", TRUE,
00206                                       "Error in ParseOptions",
00207                                       (int *) NULL,  0);
00208    tmp->type = DataElement::UNDEF;
00209    add_element(tmp);
00210 }
00211 
00212 // delete the data array
00213 ParseOptions::~ParseOptions(void) {
00214    for (int i=0; i<array_size; i++) {
00215       delete data_array[i];
00216    }
00217    delete [] data_array;
00218 }
00219    
00220 // add the new element to the array,
00221 void ParseOptions::add_element(DataElement *el) {
00222    if (array_size == array_max_size) {   // grow the array, if need be
00223       array_max_size += 30;
00224       DataElement **tmp = new DataElement*[array_max_size]; 
00225       memcpy(tmp, data_array, array_size * sizeof(DataElement *)); // copy
00226       delete [] data_array;
00227       data_array = tmp;
00228    }
00229    el->index = array_size;       // append the new element to the array
00230    data_array[array_size++] = el;
00231 }
00232 
00233 // update so that the elements are properly dependent
00234 // returns 1 if everything set okay, 0 if no
00235 int ParseOptions::make_dependencies(DataElement *el) {
00236    int i;
00237    // check if it is dependent on itself
00238    if (!strcasecmp(el->name, el->parent)) {
00239       return FALSE;
00240    }
00241    // check that there is no element with this name
00242    for (i=0; i<array_size; i++) {
00243       if (!strcasecmp(data_array[i]->name, el->name) &&
00244           el != data_array[i]) {
00245          return FALSE;
00246       }
00247    }
00248 
00249    // check if el's parent has already been inserted
00250    for (i=0; i<array_size; i++) {
00251       if (!strcasecmp(data_array[i]->name, el->parent)) {
00252          el->parent_ptr = data_array[i];
00253          break;
00254       }
00255    }
00256    
00257    // check if el is the parent of any already inserted
00258    // element
00259    for (i=0; i<array_size; i++) {
00260       if (!data_array[i]->parent_ptr) {
00261          if (!strcasecmp(data_array[i]->parent,
00262                          el->name)) {
00263             data_array[i]->parent_ptr = el;
00264          }
00265       }
00266    }
00267    return TRUE;
00268 }
00269    
00270 
00272 #define parse_input_macro_default(fctnname, type, optional)           \
00273 int ParseOptions::fctnname(const char *parent, const char *newname,   \
00274                           const char *msg, type *ptr, type defalt)    \
00275 {                                                                     \
00276    DataElement *tmp = new DataElement(newname, parent, optional, msg, \
00277                                       ptr, defalt);                   \
00278    if (!make_dependencies(tmp)) {                                     \
00279       iout << iERROR << "ParseOption '" << newname << "' already exists" << "\n" << endi; \
00280       return FALSE;                                                   \
00281    }                                                                  \
00282    add_element(tmp);                                                  \
00283    return TRUE;                                                       \
00284 }
00285 #define parse_input_macro(fctnname, type, optional)                   \
00286 int ParseOptions::fctnname(const char *parent, const char *newname,   \
00287                           const char *msg, type *ptr)                 \
00288 {                                                                     \
00289    DataElement *tmp = new DataElement(newname, parent, optional, msg, \
00290                                       ptr);                           \
00291    if (!make_dependencies(tmp)) {                                     \
00292       iout << iERROR << "ParseOption '" << newname << "' already exists" << "\n" << endi; \
00293       return FALSE;                                                   \
00294    }                                                                  \
00295    add_element(tmp);                                                  \
00296    return TRUE;                                                       \
00297 }
00298 #define parse_input_macro_default_b(fctnname, type, optional, extra)  \
00299 int ParseOptions::fctnname(const char *parent, const char *newname,   \
00300                           const char *msg, type *ptr, type defalt)    \
00301 {                                                                     \
00302    DataElement *tmp = new DataElement(newname, parent, optional, msg, \
00303                                       ptr, defalt);                   \
00304    if (!make_dependencies(tmp)) {                                     \
00305       iout << iERROR << "ParseOption '" << newname << "' already exists" << "\n" << endi; \
00306       return FALSE;                                                   \
00307    }                                                                  \
00308    add_element(tmp);                                                  \
00309    extra;                                                             \
00310    return TRUE;                                                       \
00311 }
00312 #define parse_input_macro_b(fctnname, type, optional, extra)                 \
00313 int ParseOptions::fctnname(const char *parent, const char *newname,   \
00314                           const char *msg, type *ptr)                 \
00315 {                                                                     \
00316    DataElement *tmp = new DataElement(newname, parent, optional, msg, \
00317                                       ptr);                           \
00318    if (!make_dependencies(tmp)) {                                     \
00319       iout << iERROR << "ParseOption '" << newname << "' already exists" << "\n" << endi; \
00320       return FALSE;                                                   \
00321    }                                                                  \
00322    add_element(tmp);                                                  \
00323    extra;                                                             \
00324    return TRUE;                                                       \
00325 }
00326 
00327 parse_input_macro(require, BigReal, FALSE);  // the ; is there to look pretty
00328 parse_input_macro(require, Vector, FALSE);
00329 parse_input_macro(require, int, FALSE);
00330 parse_input_macro(require, unsigned int, FALSE);
00331 parse_input_macro_b(requireB, int, FALSE, tmp->type = DataElement::BOOL);
00332 parse_input_macro(require, char, FALSE);
00333 
00334 parse_input_macro(optional, BigReal, TRUE);
00335 parse_input_macro(optional, Vector, TRUE);
00336 parse_input_macro(optional, int, TRUE);
00337 parse_input_macro(optional, unsigned int, TRUE);
00338 parse_input_macro_b(optionalB, int, TRUE, tmp->type = DataElement::BOOL);
00339 parse_input_macro(optional, char, TRUE);
00340 
00341 parse_input_macro_default(require, BigReal, FALSE);
00342 parse_input_macro_default(require, Vector, FALSE);
00343 parse_input_macro_default(require, int, FALSE);
00344 parse_input_macro_default(require, unsigned int, FALSE);
00345 parse_input_macro_default_b(requireB, int, FALSE, tmp->type=DataElement::BOOL);
00346 
00347 parse_input_macro_default(optional, BigReal, TRUE);
00348 parse_input_macro_default(optional, Vector, TRUE);
00349 parse_input_macro_default(optional, int, TRUE);
00350 parse_input_macro_default(optional, unsigned int, TRUE);
00351 parse_input_macro_default_b(optionalB, int, TRUE, tmp->type=DataElement::BOOL);
00352 
00353 #define parse_stringlist_macro(fctn, xxx) \
00354 int ParseOptions::fctn(const char *parent, const char *newname, \
00355                           const char *msg, StringList **ptr, int many_allowed)\
00356 {                                                                            \
00357    DataElement *tmp = new DataElement(newname, parent, xxx, msg,             \
00358                                       ptr, many_allowed);                    \
00359    if (!make_dependencies(tmp)) {                                            \
00360       iout << iERROR << "ParseOption '" << newname << "' already exists" << "\n" << endi;\
00361       return FALSE;                                                          \
00362    }                                                                         \
00363    add_element(tmp);                                                         \
00364    return TRUE;                                                              \
00365 }
00366 parse_stringlist_macro(require, FALSE);
00367 parse_stringlist_macro(optional, TRUE);
00368 
00369 
00370 // find all the children of the given element; returns 0
00371 // if a loop was detected.  Children are marked with a 1 in the
00372 // appropriate location in the flag array
00373 int ParseOptions::check_children(int idx, int *flgs)
00374 {
00375    if (flgs[idx]) { // oops, been here before
00376       return 0;
00377    }
00378    flgs[idx] = 1;
00379    for (int i=0; i<array_size; i++) {
00380       if (data_array[i]->parent_ptr == data_array[idx]) {
00381          if (!check_children(i, flgs)) {
00382             return 0;
00383          }
00384       }
00385    }
00386    return 1;
00387 }
00388          
00389 // see if there are elements which have no parent (except main)
00390 // or elements inaccessible via main
00391 // returns a 0 if there was an error
00392 Bool ParseOptions::check_consistency(void) {
00393    int i;
00394    // check for lack of parent
00395    {
00396       int has_error = FALSE;
00397       for(i=1; i<array_size; i++) {
00398          if (!data_array[i]->parent_ptr) {
00399             // missing a parent
00400             iout << iERROR << "Configuration element '" << data_array[i]->name
00401                     << "' defined, but the parent element" << "\n" << endi;
00402             iout << iERROR << "  '" << data_array[i]->parent << "' is nowhere "
00403                     << "to be found" << "\n" << endi;
00404             has_error = TRUE;
00405          }
00406       }
00407       if (has_error) return 0;
00408    }
00409 
00410    // check for loop constructs in the "main" heirarchy
00411    int *arr = new int[array_size];
00412    for (i=0; i<array_size; i++) {  // initialize it
00413       arr[i] = 0;
00414    }
00415    if (!check_children(0, arr)) {
00416       // a loop was found
00417       iout << iERROR << "Loop found in ParseOptions data" << "\n" << endi;
00418       delete [] arr;
00419       return 0;
00420    }
00421 
00422    // check for elements inaccessible to "main"
00423    {
00424       int has_error = FALSE;
00425       for (i=1; i<array_size; i++) {
00426          if (arr[i] == 0) {
00427             // found an inaccesible element
00428             if (has_error == FALSE) { // first time, so print message
00429                iout << iERROR 
00430                    << "Found data in ParseOptions which are inaccessible "
00431                    << "to" << "\n" << endi;
00432                iout << iERROR 
00433                   << "the main data hierarchy.  Errors in:" << "\n" << endi;
00434                has_error = TRUE;
00435             }
00436             iout << iERROR << "   '" << data_array[i]->name << "' depends on '"
00437                     << data_array[i]->parent << "'" << "\n" << endi;
00438          }
00439       }
00440       if (has_error) {
00441          delete [] arr;
00442          return 0;
00443       }
00444    }
00445    // looks like everything went well
00446    delete [] arr;
00447    return 1;
00448 }
00449 
00450 // convert from a string to Bool; returns 1(TRUE) 0(FALSE) or -1(if unknown)
00451 int ParseOptions::atoBool(const char *s)
00452 {
00453    if (!strcasecmp(s, "on")) return 1;
00454    if (!strcasecmp(s, "off")) return 0;
00455    if (!strcasecmp(s, "true")) return 1;
00456    if (!strcasecmp(s, "false")) return 0;
00457    if (!strcasecmp(s, "yes")) return 1;
00458    if (!strcasecmp(s, "no")) return 0;
00459    if (!strcasecmp(s, "1")) return 1;
00460    if (!strcasecmp(s, "0")) return 0;
00461    return -1;
00462 }
00463 
00464 // A "Boolean" can indicate 1 of 2 things, either a simple
00465 // yes/ no flag for a piece of data, or a on/ off for a
00466 // set of parameters.  The distinction is if the option
00467 // has children.  In "set", if the option is defined and
00468 // is false and has children, then it is made undefined,
00469 // so that other elements won't be parsed
00470 Bool ParseOptions::is_parent_node(DataElement *el) {
00471    for (int i=1; i<array_size; i++) {
00472       if (data_array[i]->parent_ptr == el) {
00473          return 1;
00474       }
00475    }
00476    return 0;
00477 }
00478 
00479 // given a string, read in the float and (perhaps) units,
00480 // do the needed conversions, check for errors, etc...
00481 Bool ParseOptions::scan_float(DataElement *data, const char *s)
00482 {
00483    double input_value;  // I do this since I don't know if "BigReal" is
00484    BigReal fval;        // float or double, and I need to know for the
00485    char units_str[80];  // sscanf
00486    char tmp_str[80];
00487    int count = sscanf(s, "%lf%s%s", &input_value, units_str, tmp_str);
00488    if (count > 1 && units_str[0] == '.' &&
00489        input_value == (double)(long int)input_value) {  // for final . on Mac
00490      long int input_long;
00491      count = sscanf(s, "%ld.%s%s", &input_long, units_str, tmp_str);
00492      if ( count < 1 || input_value != (double)input_long ) {
00493          iout << iERROR << "Could not parse option '"
00494                  << data->name << " = " << s << "'\n" << endi;
00495          return FALSE;
00496      }
00497    }
00498    fval = input_value;
00499    if (count == 1) {     // no units given, so simply apply the number
00500       data->fdata = fval;
00501       return TRUE;
00502    }
00503    if (count == 2) {     // number and units
00504       Units u = atoUnits(units_str);
00505       if (u == N_UNITS_UNDEFINED) {
00506          iout << iERROR << "Could not understand units '" << units_str
00507                  << "' in option '" << data->name << " = " << s
00508                  << "\n" << endi;
00509          return FALSE;
00510       }
00511       BigReal scale = convert(data->units, u);
00512       if (scale == 0) {
00513          iout << iERROR << "Could not translate from units '" << ustring(u) 
00514                  << "' to '" << ustring(data->units) << "' for option '"
00515                  << data->name << "'" << "\n" << endi;
00516          return FALSE;
00517       }
00518 //      cout << "fval == " << fval << "  scale == " << scale << std::endl;
00519       data->fdata = fval * scale;
00520       return TRUE;
00521    }
00522    if (count <=0) {  // not enough
00523       iout << iERROR << "Expecting value and optional units for option '"
00524               << data->name << "'" << "\n" << endi;
00525    }
00526    if (count > 2) {  // too many
00527       iout << iERROR << "Too much information given to '" << data -> name 
00528       << " = " <<  s << "'" << "\n" << endi;
00529       iout << iERROR << "  - expecting a value and optional units" << "\n" << endi;
00530    }
00531    return FALSE;
00532 }
00533 
00534 // no units are allowed (yet?) for a vector
00535 Bool ParseOptions::scan_vector(DataElement *data, const char *s)
00536 {
00537    Vector v;
00538    if (!v.set(s)) {
00539       iout << iERROR << "Could not translate the value '" << s << "'" << "\n" << endi;
00540       iout << iERROR << "  into a Vector for the option '" << data->name << "'"
00541               << "\n" << endi;
00542       return FALSE;
00543    }
00544    data->vdata = v;
00545    return TRUE;
00546 }
00547 
00548 // read an int from string.  No units are supported for ints,
00549 // though they could be.  (eg, 1 KB, ...)
00550 Bool ParseOptions::scan_int(DataElement *data, const char *s)
00551 {
00552    int ival;
00553    char units_str[80];
00554    char tmp_str[80];
00555    int count = sscanf(s, "%d%s%s", &ival, units_str, tmp_str);
00556    if (count == 1) {
00557       data->idata = ival;
00558       return TRUE;
00559    }
00560    iout << iERROR << "Expecting only a number for '" << data->name
00561            << "' input, got: " << s << "\n" << endi;
00562    return FALSE;
00563 }
00564 
00565 // read an unsigned int from string.  No units are supported for ints,
00566 // though they could be.  (eg, 1 KB, ...)
00567 Bool ParseOptions::scan_uint(DataElement *data, const char *s)
00568 {
00569    unsigned int ival;
00570    char units_str[80];
00571    char tmp_str[80];
00572    int count = sscanf(s, "%u%s%s", &ival, units_str, tmp_str);
00573    if (count == 1) {
00574       data->idata = ival;
00575       return TRUE;
00576    }
00577    iout << iERROR << "Expecting only a number for '" << data->name
00578            << "' input, got: " << s << "\n" << endi;
00579    return FALSE;
00580 }
00581    
00582 Bool ParseOptions::scan_bool(DataElement *data, const char *s)
00583 {
00584    int tmp = atoBool(s);  // convert the boolean
00585 
00586    if (tmp == -1) 
00587    {
00588         iout << iERROR << "ParseOptions can't understand '" << s << "' for the "
00589                 << "\n" << endi;
00590         iout << iERROR << " Boolean variable '" << data->name << "'"  << "\n" << endi;
00591 
00592         data->idata = FALSE;
00593 
00594         return FALSE;
00595    }
00596 
00597    data->idata = tmp;  // set the value, if understood
00598 
00599    return TRUE;
00600 }
00601 
00602 // check the range and, if valid, set the variable and return 1
00603 // if bad range, print error message and return 0
00604 #define set_macro(type, field, fieldptr)                 \
00605 int ParseOptions::set_##type(DataElement *el)            \
00606 {                                                        \
00607    if (el->range == FREE_RANGE ||                        \
00608        (el->range == POSITIVE && el->field > 0) ||       \
00609        (el->range == NOT_NEGATIVE && el->field >= 0) ||  \
00610        (el->range == NEGATIVE && el->field < 0) ||       \
00611        (el->range == NOT_POSITIVE && el->field <= 0)) {  \
00612       if (el->fieldptr) *(el->fieldptr) = el->field;     \
00613       return 1;                                          \
00614    }                                                     \
00615    iout << iERROR << "'" << el->name << "' was set to " << el->field << " but it " \
00616            << "should be " << rstring(el->range)          \
00617            << "\n" << endi;      \
00618    return 0;                \
00619 }
00620 set_macro(float, fdata, fptr);
00621 set_macro(int, idata, iptr);
00622 set_macro(uint, uidata, uiptr);
00623 
00624 // for elements without ranges
00625 #define simple_set_macro(type, field, fieldptr)   \
00626 void ParseOptions::set_##type(DataElement *el)     \
00627 {                                                   \
00628    if (el->fieldptr) *(el->fieldptr) = el->field;    \
00629 }
00630 
00631 simple_set_macro(bool, idata, iptr); 
00632 simple_set_macro(vector, vdata, vptr);
00633 simple_set_macro(stringlist, sldata, slptr);
00634 // simple_set_macro(string, sldata->data, sptr);
00635 
00636 void ParseOptions::set_string(DataElement *el)   
00637 {                                                  
00638    if (el->sptr) strcpy(el->sptr, el->sldata->data);  
00639 }
00640 
00641 // set the variables, given the contents of the ConfigList
00642 // return FALSE if there was an error
00643 Bool ParseOptions::set(const ConfigList& clist)
00644 {
00645    // the algorithm is easy, though it looks scary
00646    int cont = TRUE, i;  // do some initialization
00647    StringList *slptr;
00648    DataElement *data;
00649    int has_error = FALSE;
00650    int *checked = new int[array_size];
00651    configList = &clist;
00652 
00653    // I make here a list of element I have already checked, starting
00654    // at the head.  I check only children of those that have already
00655    // been defined and add it to the checked list
00656    for (i=0; i<array_size; i++) 
00657    {
00658       checked[i] = FALSE;
00659    }
00660 
00661    //   make "main" 'defined' (at this point, nothing else should be defined)
00662    data_array[0]->is_defined = TRUE;
00663    checked[0] = TRUE;  // and make "main" checked
00664    
00665    // while there is still data which hasn't been defined
00666    while (cont) 
00667    {
00668       cont = FALSE;
00669       for (i=1; i<array_size; i++) 
00670       {  // check each element
00671          data = data_array[i];
00672 
00673          // find unchecked data which has a parent which was checked
00674          // and defined
00675          if (!checked[data->index] &&
00676              checked[data-> parent_ptr -> index] &&
00677              data -> parent_ptr -> is_defined) 
00678          {
00679             cont = TRUE;
00680             checked[data->index] = TRUE;  // so I don't check again
00681 
00682             // check to see if data is available in the StringList
00683             slptr = clist.find(data->name);
00684 
00685             if (slptr != NULL) 
00686             {  // it is 
00687 
00688                // most data types allow only 1 item, so check if that is
00689                // a problem.  (some StringLists, like 'parameters', allow
00690                // multiple strings)
00691                if (!data->many_allowed && slptr->next != NULL) 
00692                {
00693                   iout << iERROR << "Multiple definitions of '" << data->name << "'" << "\n" << endi;
00694                   iout << iERROR << "  in the configuration file are not allowed" << "\n" << endi;
00695                   has_error = TRUE;
00696                }
00697 
00698                data->is_defined = TRUE;
00699 
00700                // set the appropriate data field
00701                if (data->type == DataElement::FLOAT) 
00702                {
00703                   if (!scan_float(data, slptr->data)) 
00704                         has_error = TRUE;
00705                } 
00706                else if (data->type == DataElement::VECTOR) 
00707                {
00708                   if (!scan_vector(data, slptr->data)) 
00709                         has_error = TRUE;
00710                } 
00711                else if (data->type == DataElement::INT) 
00712                {
00713                   if (!scan_int(data, slptr->data)) 
00714                         has_error = TRUE;
00715                } 
00716                else if (data->type == DataElement::UINT) 
00717                {
00718                   if (!scan_uint(data, slptr->data)) 
00719                         has_error = TRUE;
00720                } 
00721                else if (data->type == DataElement::BOOL) 
00722                {
00723                   if (!scan_bool(data, slptr->data)) 
00724                         has_error = TRUE;
00725                } 
00726                else if (data->type == DataElement::STRINGLIST ||
00727                           data->type == DataElement::STRING ) 
00728                {
00729                   data->sldata = slptr;
00730                } 
00731                else 
00732                {
00733                   iout << iERROR << "Unknown ParseOption data type " << (int)(data->type) << " for "
00734                           << "variable " << data->name << "\n" << endi;
00735                   has_error = TRUE;
00736                }
00737             } 
00738             else 
00739             {  // no definition; is there a default?
00740                if (data->has_default) 
00741                {
00742                   data->is_defined = TRUE;
00743 
00744                   if (data->type == DataElement::FLOAT) 
00745                   {
00746                      data->fdata = data->fdef;
00747                   } 
00748                   else if (data->type == DataElement::VECTOR) 
00749                   {
00750                      data->vdata = data->vdef;
00751                   } 
00752                   else if (data->type == DataElement::UINT) 
00753                   {
00754                      data->uidata = data->uidef;
00755                   } 
00756                   else if (data->type == DataElement::INT ||
00757                              data->type == DataElement::BOOL) 
00758                   {
00759                      data->idata = data->idef;
00760                   } 
00761                   else 
00762                   {
00763                         iout << iERROR << "Unknown ParseOption data type " << (int)(data->type) << " for "
00764                                 << "variable " << data->name << "\n" << endi;
00765                     has_error = TRUE;
00766                   }
00767                }
00768             }
00769 
00770             // at this point we should have gotten data from the file or the defaults,
00771             // or it hasn't yet been defined.  If it still isn't defined, check
00772             // to see if it is optional
00773             if (!data->is_defined) 
00774             { // if still not defined,
00775                if (!data->is_optional) 
00776                { // it is it required
00777                   has_error = TRUE;
00778                   iout << iERROR << "'" << data->name << "' is a required configuration option" << "\n" << endi;
00779 
00780                   // print some helpful information if this isn't a "main" option
00781                   if (data->parent_ptr != data_array[0]) 
00782                   {
00783                         iout << iERROR << "  when '" << data->parent_ptr -> name << "' is set" << "\n" << endi;
00784                   }  // printed parent info
00785 
00786                   iout << iERROR << data->name << " defines:   " << data->error_message << "\n" << endi;
00787 
00788                }  // printed error message
00789             }  
00790             else 
00791             { // there was a definition, so assign to the variable
00792                if (data->type ==  DataElement::FLOAT) 
00793                {
00794                   if (!set_float(data)) 
00795                         has_error = TRUE;
00796                } 
00797                else if ( data -> type == DataElement::VECTOR) 
00798                {
00799                   set_vector(data);
00800                } 
00801                else if ( data -> type == DataElement::INT) 
00802                {
00803                   if (!set_int(data)) 
00804                         has_error = TRUE;
00805                } 
00806                else if ( data -> type == DataElement::UINT) 
00807                {
00808                   if (!set_uint(data)) 
00809                         has_error = TRUE;
00810                } 
00811                else if ( data -> type == DataElement::BOOL) 
00812                {
00813                   set_bool(data);
00814 
00815                   if (is_parent_node(data)) 
00816                   {
00817                         // this makes the boolean variable undefined if it is 'off'
00818                         // _and_ it is a parent; this makes it agree with namd's
00819                         // configuration option semantics
00820                         data->is_defined = data->idata;
00821                   }
00822                } 
00823                else if ( data -> type == DataElement::STRINGLIST) 
00824                {
00825                   set_stringlist(data);
00826                } 
00827                else if ( data -> type == DataElement::STRING) 
00828                {
00829                   set_string(data);
00830                } 
00831                else 
00832                {
00833                   // already printed the error message
00834                }
00835             }
00836          }  // end of checking the available variables
00837       } // end of pass through the list
00838    } // end of finding data in the ConfigList
00839 
00840 
00841    // and now print the warning messages
00842 
00843    // first, find elements which are in the configuration file and are
00844    // valid, but which were not needed (ie, the checked array wasn''t set)
00845    {
00846       int flg = 0;
00847 
00848       for (int i=1; i<array_size; i++) 
00849       {
00850          if (!checked[i]) { // wasn't needed
00851             data = data_array[i];
00852             if (clist.find(data->name)) {
00853                if (flg == 0) {
00854                   flg = 1;
00855                   iout << iWARN 
00856                     << "The following variables were set in the\n";
00857                   iout << iWARN 
00858                     << "configuration file but will be ignored:\n" << endi;
00859                }
00860                iout << iWARN << "   " << data->name;
00861                if (data->parent_ptr != data_array[0]) {
00862                  iout << " (" << data->parent_ptr->name << ")";
00863                }
00864                iout << "\n" << endi;
00865             }
00866          }
00867       }
00868    }
00869    // and now look for names which are in the config list but which
00870    // are not in the parseoptions list
00871    {
00872       int flg = 0;
00873       ConfigList::ConfigListNode const *ptr;
00874       for (ptr = clist.head(); ptr != NULL; ptr = ptr -> next) {
00875          if (!exists(ptr -> name)) {
00876             if (flg == 0) {
00877                flg = 1;
00878                has_error = TRUE;
00879                iout << iERROR
00880                   << "The following variables were set in the\n";
00881                iout << iERROR
00882                   << "configuration file but are NOT VALID\n" << endi;
00883             }
00884             iout << iERROR << "   " << ptr -> name << "\n" << endi;
00885          }
00886       }
00887    }
00888       
00889    delete [] checked;
00890    return !has_error;
00891 }
00892 
00893 // simple search though the list; return NULL if not found
00894 ParseOptions::DataElement *ParseOptions::internal_find(const char* name)
00895 {
00896    for (int i=1; i<array_size; i++) {
00897       if (!strcasecmp(name, data_array[i]->name)) {
00898          return data_array[i];
00899       }
00900    }
00901    return NULL;
00902 }
00903 
00904 // returns 1 if the given name exists; 0 if no
00905 Bool ParseOptions::exists(const char *name)
00906 {
00907    if (!name) return 0;
00908    if (internal_find(name)) {
00909       return 1;
00910    }
00911    return 0;
00912 }
00913 // returns 1 if the element name exists and is defined
00914 Bool ParseOptions::defined(const char *name)
00915 {
00916    if (!name) return FALSE;
00917    DataElement *tmp = internal_find(name);
00918    if (!tmp) return FALSE;
00919    if (tmp->is_defined) {
00920       return TRUE;
00921    }
00922    return FALSE;
00923 }
00924 
00925 #ifdef NAMD_TCL
00926 #define PRINT_DOUBLE(BUF,VAL) Tcl_PrintDouble(0,VAL,BUF)
00927 
00928 static void PRINT_VECTOR(char *buf, Vector val) {
00929   PRINT_DOUBLE(buf, val.x);
00930   buf += strlen(buf); buf[0] = ' '; ++buf;
00931   PRINT_DOUBLE(buf, val.y);
00932   buf += strlen(buf); buf[0] = ' '; ++buf;
00933   PRINT_DOUBLE(buf, val.z);
00934   buf += strlen(buf); buf[0] = ' '; buf[1] = 0;
00935 }
00936 #endif
00937 
00939 char* ParseOptions::getfromptr(const char* name, char *outbuf) {
00940 #ifdef NAMD_TCL
00941    if ( ! name ) NAMD_bug("ParseOptions::getfromptr called with null name");
00942    if ( ! outbuf ) NAMD_bug("ParseOptions::getfromptr called with null outbuf");
00943    DataElement *el = internal_find(name);
00944    if ( el == NULL ) return 0;
00945    switch (el->type) {
00946     case DataElement::FLOAT :
00947       if ( el->fptr ) PRINT_DOUBLE(outbuf, *(el->fptr));
00948       else PRINT_DOUBLE(outbuf, el->fdata);
00949       return outbuf;
00950     case DataElement::INT:
00951     case DataElement::BOOL:
00952       if ( el->iptr ) sprintf(outbuf,"%d", *(el->iptr));
00953       else sprintf(outbuf,"%d", el->idata);
00954       return outbuf;
00955     case DataElement::STRINGLIST :
00956       if ( el->slptr ) return (*(el->slptr))->data;
00957       else if ( el->sldata ) return el->sldata->data;
00958       else return 0;
00959     case DataElement::STRING :
00960       if ( el->sptr ) return el->sptr;
00961       else if ( el->sldata ) return el->sldata->data;
00962       else return 0;
00963     case DataElement::VECTOR :
00964       if ( el->vptr ) PRINT_VECTOR(outbuf, *(el->vptr));
00965       else PRINT_VECTOR(outbuf, el->vdata);
00966       return outbuf;
00967     default:
00968       iout << iERROR 
00969          << "Unknown data type " << (int)(el->type) << " for '" << name << "'"
00970          << "\n" << endi;
00971    }
00972 #endif
00973    return 0;
00974 }
00975 
00977 int ParseOptions::istruefromptr(const char* name) {
00978    if ( ! name ) NAMD_bug("ParseOptions::getfromptr called with null name");
00979    DataElement *el = internal_find(name);
00980    if ( el == NULL ) return -1;
00981    if ( el->type != DataElement::BOOL ) return -2;
00982    if ( el->iptr ) return ((*(el->iptr)) ? 1 : 0);
00983    if ( ! el->is_defined ) return -3;  // ignores defaults
00984    return (el->idata ? 1 : 0);
00985 }
00986 
00988 int ParseOptions::issetfromptr(const char* name) {
00989    if ( ! name ) NAMD_bug("ParseOptions::getfromptr called with null name");
00990    DataElement *el = internal_find(name);
00991    if ( el == NULL ) return -1;
00992    return (el->is_defined ? 1 : 0);
00993 }
00994 
00996 // get the value associated with the given name
00997 // if there was a type conversion, print a warning message
00998 // if the element wasn't found, return a FALSE, else return a TRUE
00999 Bool ParseOptions::get(const char* name, int *val) {
01000    if (!val) return FALSE;
01001    DataElement *el = internal_find(name);
01002    if (el == NULL || !el->is_defined) {
01003       return FALSE;
01004    }
01005    switch (el->type) {
01006     case DataElement::FLOAT :
01007       iout << iWARN 
01008          << "ParseOptions doing a conversion from float to int for '"
01009          << name << "'" << "\n" << endi;
01010       *val = (int) el->fdata;
01011       return TRUE;
01012     case DataElement::INT:
01013     case DataElement::BOOL:
01014       *val = el->idata;
01015       return TRUE;
01016     case DataElement::STRINGLIST :
01017     case DataElement::STRING :
01018       iout << iWARN 
01019          << "ParseOptions doing a conversion from StringList[0] to int "
01020          << "for '" << name << "'" << "\n" << endi;
01021       *val = atoi(el->sldata->data);
01022       return TRUE;
01023     case DataElement::VECTOR :
01024        iout << iERROR 
01025           << "ParseOptions cannot convert from Vector to int for '"
01026           << name << "'" << "\n" << endi;
01027        return FALSE;
01028     default:
01029       iout << iERROR 
01030          << "Unknown data type " << (int)(el->type) << " for '" << name << "'"
01031          << "\n" << endi;
01032    }
01033    return FALSE;
01034 }
01035 
01036 Bool ParseOptions::get(const char* name, BigReal *val) {
01037    if (!val) return FALSE;
01038    DataElement *el = internal_find(name);
01039    if (el == NULL || !el->is_defined) {
01040       return FALSE;
01041    }
01042    switch (el -> type) {
01043     case DataElement::FLOAT: 
01044       *val =  el->fdata;
01045       return TRUE;
01046     case DataElement::INT:
01047       iout << iWARN 
01048          << "ParseOptions doing a conversion from int to float '"
01049          << name << "'" << "\n" << endi;
01050       *val = (BigReal) el->idata;
01051       return TRUE;
01052     case DataElement::BOOL:
01053       iout << iWARN 
01054          << "ParseOptions doing a conversion from boolean to float for '"
01055          << name << "'" << "\n" << endi;
01056       *val = (BigReal) el->idata;
01057       return TRUE;
01058     case DataElement::STRING:
01059     case DataElement::STRINGLIST:
01060      iout << iWARN 
01061         << "ParseOptions doing a conversion from StringList[0] to float "
01062         << "for '" << name << "'" << "\n" << endi;
01063       *val = atof(el->sldata->data);
01064       return TRUE;
01065     case DataElement::VECTOR :
01066        iout << iERROR 
01067           << "ParseOptions cannot convert from Vector to float for '"
01068           << name << "'" << "\n" << endi;
01069        return FALSE;
01070     default:
01071       iout << iERROR 
01072          << "Unknown data type " << (int)(el->type) << " for '" << name << "'"
01073          << "\n" << endi;
01074    }
01075    return FALSE;
01076 }
01077 Bool ParseOptions::get(const char *name, Vector *val) {
01078    if (!val) return FALSE;
01079    DataElement *el = internal_find(name);
01080    if (el == NULL || !el->is_defined) {
01081       return FALSE;
01082    }
01083    switch (el -> type) {
01084     case DataElement::FLOAT:
01085       iout << iERROR 
01086          << "ParseOptions cannot convert from float to Vector for '"
01087          << name << "'" << "\n" << endi;
01088       return FALSE;
01089     case DataElement::INT:
01090       iout << iERROR 
01091          << "ParseOptions cannot convert from int to Vector for '"
01092          << name << "'" << "\n" << endi;
01093       return FALSE;
01094     case DataElement::STRING:
01095     case DataElement::STRINGLIST:{
01096       iout << iWARN 
01097          << "ParseOptions doing a conversion from StringList[0] to "
01098          << "Vector for '" << name << "'" << "\n" << endi;
01099       Vector v;
01100       if (!v.set(el->sldata->data)) {
01101          iout << iERROR 
01102             << "Could not convert '" << el->sldata->data
01103             << "' to a Vector";
01104          return FALSE;
01105       }
01106       *val = v;
01107       return TRUE;
01108      }
01109      case DataElement::VECTOR : 
01110       *val = el->vdata;
01111       return TRUE;
01112     default:
01113       iout << iERROR 
01114          << "Unknown data type " << (int)(el->type) << " for '" << name << "'"
01115          << "\n" << endi;
01116 
01117    }
01118    return FALSE;
01119 }
01120 Bool ParseOptions::get(const char *name, StringList **val) {
01121    if (!val) return FALSE;
01122    DataElement *el = internal_find(name); // first check it is internally valid
01123    if (el == NULL || !el->is_defined) {
01124       return FALSE;
01125    }
01126    // then simply ask the configList itself for the answer
01127    // (while I do keep the information internally, in sldata, why bother?
01128    if (!configList) { return FALSE; }
01129    *val = configList->find(name);
01130    if (!*val) { return FALSE; }  // paranoia, I know...
01131    return TRUE;
01132 }
01133 
01134 // get the nth element of the StringList
01135 Bool ParseOptions::get(const char *name, char *val, int n)
01136 {
01137    if (!val || n<0) {return FALSE;}
01138    StringList *tmp;
01139    if (!get(name, &tmp)) {val[0]=STRINGNULL; return FALSE; }
01140    int i=n;
01141    while (i>0 && tmp) { // search for the nth element
01142       tmp=tmp->next;
01143       i--;
01144    }
01145    if (tmp) {  // if it was long enough, return it
01146       strcpy(val, tmp->data);
01147       return TRUE;
01148    }
01149    val[0] = STRINGNULL;
01150    return FALSE;
01151 }
01152 
01153 
01154 int ParseOptions::num(const char *name)
01155 {
01156    DataElement *el = internal_find(name);
01157    if (!el || !el ->is_defined) {
01158       return 0;
01159    }
01160    if (!el->many_allowed) {
01161       return 1;
01162    }
01163    StringList *tmp;
01164    if (!get(name, &tmp)) { return 0; }
01165    int i=0;
01166    while (tmp) {
01167       i++;
01168       tmp=tmp->next;
01169    }
01170    return i;
01171 }
01172    
01173 
01174 // get or set the range for the given variable
01175 void ParseOptions::range(const char *name, Range newrange)
01176 {
01177    DataElement *el = internal_find(name);
01178    if (!el) {
01179       iout << iERROR 
01180          << "Trying to set the range of undefined variable '"
01181          << name << "'" << "\n" << endi;
01182       return;
01183    }
01184    el->range = newrange;
01185    
01186 }
01187 Range ParseOptions::range(const char *name)
01188 {
01189    DataElement *el = internal_find(name);
01190    if (!el) {
01191       iout << iERROR 
01192          << "Trying to get the range of undefined variable '"
01193          << name << "'" << "\n" << endi;
01194       return FREE_RANGE;
01195    }
01196    return el->range;
01197 }
01198 
01199 // get / set the units value
01200 Bool ParseOptions::units(const char *name, Units units)  // get
01201 {
01202   DataElement *tmp = internal_find(name);
01203   if (!tmp) {
01204      iout << iERROR 
01205         << name << " not found so units not set" << "\n" << endi;
01206      return FALSE;
01207   }
01208   if ((tmp -> type == DataElement::INT && units != N_UNIT) ||
01209       (tmp -> type != DataElement::INT && 
01210        tmp -> type != DataElement::FLOAT)) {
01211      iout << iERROR 
01212         << "Cannot set units '" << ustring(units) << "' for option '"
01213         << name << "'; wrong data type" << "\n" << endi;
01214      return FALSE;
01215   }
01216   tmp -> units = units;
01217   return TRUE;
01218 }
01219 
01220 Bool ParseOptions::units(const char *name, Units *units) // set
01221 {
01222    DataElement *tmp = internal_find(name);
01223    *units = N_UNIT;
01224    if (!tmp) {
01225       iout << iERROR 
01226          << "'" << name << "' doesn't exist so cannot get its units"
01227          << "\n" << endi;
01228       return FALSE;
01229    }
01230    if (tmp -> type != DataElement::INT && 
01231        tmp -> type != DataElement::FLOAT) {
01232       iout << iERROR 
01233          << "Can only get units for FLOAT and INT variables, and '"
01234          << name << "' isn't one of those" << "\n" << endi;
01235       return FALSE;
01236    }
01237    *units = tmp->units;
01238    return TRUE;
01239 }
01240 

Generated on Fri Sep 22 01:17:14 2017 for NAMD by  doxygen 1.4.7