00001
00007
00008
00009
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"
00019
00020
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
00038 const char *ustring(Units u)
00039 {
00040 return unit_string_array[u];
00041 }
00042
00043
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
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
00077
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
00084
00085 BigReal convert(Units to, Units from)
00086 {
00087
00088
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
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
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
00170 dataelement_cons_macro(char, STRING, sptr);
00171
00172
00173
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
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
00194
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
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
00216 void ParseOptions::add_element(DataElement *el) {
00217 if (array_size == array_max_size) {
00218 array_max_size += 30;
00219 DataElement **tmp = new DataElement*[array_max_size];
00220 memcpy(tmp, data_array, array_size * sizeof(DataElement *));
00221 delete [] data_array;
00222 data_array = tmp;
00223 }
00224 el->index = array_size;
00225 data_array[array_size++] = el;
00226 }
00227
00228
00229
00230 int ParseOptions::make_dependencies(DataElement *el) {
00231 int i;
00232
00233 if (!strcasecmp(el->name, el->parent)) {
00234 return FALSE;
00235 }
00236
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
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
00253
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);
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
00366
00367
00368 int ParseOptions::check_children(int idx, int *flgs)
00369 {
00370 if (flgs[idx]) {
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
00385
00386
00387 Bool ParseOptions::check_consistency(void) {
00388 int i;
00389
00390 {
00391 int has_error = FALSE;
00392 for(i=1; i<array_size; i++) {
00393 if (!data_array[i]->parent_ptr) {
00394
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
00406 int *arr = new int[array_size];
00407 for (i=0; i<array_size; i++) {
00408 arr[i] = 0;
00409 }
00410 if (!check_children(0, arr)) {
00411
00412 iout << iERROR << "Loop found in ParseOptions data" << "\n" << endi;
00413 delete [] arr;
00414 return 0;
00415 }
00416
00417
00418 {
00419 int has_error = FALSE;
00420 for (i=1; i<array_size; i++) {
00421 if (arr[i] == 0) {
00422
00423 if (has_error == FALSE) {
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
00441 delete [] arr;
00442 return 1;
00443 }
00444
00445
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
00460
00461
00462
00463
00464
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
00475
00476 Bool ParseOptions::scan_float(DataElement *data, const char *s)
00477 {
00478 double input_value;
00479 BigReal fval;
00480 char units_str[80];
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) {
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) {
00495 data->fdata = fval;
00496 return TRUE;
00497 }
00498 if (count == 2) {
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
00514 data->fdata = fval * scale;
00515 return TRUE;
00516 }
00517 if (count <=0) {
00518 iout << iERROR << "Expecting value and optional units for option '"
00519 << data->name << "'" << "\n" << endi;
00520 }
00521 if (count > 2) {
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
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
00544
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
00561
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);
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;
00593
00594 return TRUE;
00595 }
00596
00597
00598
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
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
00630
00631 void ParseOptions::set_string(DataElement *el)
00632 {
00633 if (el->sptr) strcpy(el->sptr, el->sldata->data);
00634 }
00635
00636
00637
00638 Bool ParseOptions::set(const ConfigList& clist)
00639 {
00640
00641 int cont = TRUE, i;
00642 StringList *slptr;
00643 DataElement *data;
00644 int has_error = FALSE;
00645 int *checked = new int[array_size];
00646 configList = &clist;
00647
00648
00649
00650
00651 for (i=0; i<array_size; i++)
00652 {
00653 checked[i] = FALSE;
00654 }
00655
00656
00657 data_array[0]->is_defined = TRUE;
00658 checked[0] = TRUE;
00659
00660
00661 while (cont)
00662 {
00663 cont = FALSE;
00664 for (i=1; i<array_size; i++)
00665 {
00666 data = data_array[i];
00667
00668
00669
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;
00676
00677
00678 slptr = clist.find(data->name);
00679
00680 if (slptr != NULL)
00681 {
00682
00683
00684
00685
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
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 {
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
00766
00767
00768 if (!data->is_defined)
00769 {
00770 if (!data->is_optional)
00771 {
00772 has_error = TRUE;
00773 iout << iERROR << "'" << data->name << "' is a required configuration option" << "\n" << endi;
00774
00775
00776 if (data->parent_ptr != data_array[0])
00777 {
00778 iout << iERROR << " when '" << data->parent_ptr -> name << "' is set" << "\n" << endi;
00779 }
00780
00781 iout << iERROR << data->name << " defines: " << data->error_message << "\n" << endi;
00782
00783 }
00784 }
00785 else
00786 {
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
00813
00814
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
00829 }
00830 }
00831 }
00832 }
00833 }
00834
00835
00836
00837
00838
00839
00840 {
00841 int flg = 0;
00842
00843 for (int i=1; i<array_size; i++)
00844 {
00845 if (!checked[i]) {
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
00865
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
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
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
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
00922
00923
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);
01048 if (el == NULL || !el->is_defined) {
01049 return FALSE;
01050 }
01051
01052
01053 if (!configList) { return FALSE; }
01054 *val = configList->find(name);
01055 if (!*val) { return FALSE; }
01056 return TRUE;
01057 }
01058
01059
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) {
01067 tmp=tmp->next;
01068 i--;
01069 }
01070 if (tmp) {
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
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
01125 Bool ParseOptions::units(const char *name, Units units)
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)
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