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

Generated on Tue Sep 25 01:17:14 2018 for NAMD by  doxygen 1.4.7