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

Generated on Sat Aug 30 04:07:40 2008 for NAMD by  doxygen 1.3.9.1