Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

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

Generated on Fri May 25 04:07:16 2012 for NAMD by  doxygen 1.3.9.1