00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include "w_defines.h"
00054
00055
00056
00057 #define OPTION_C
00058 #ifdef __GNUC__
00059 # pragma implementation
00060 #endif
00061
00062 #include "w.h"
00063 #include <cstring>
00064 #include <cctype>
00065 #include "w_autodel.h"
00066 #include "option.h"
00067 #include "w_debug.h"
00068
00069 #include "regex_posix.h"
00070
00071 #ifdef EXPLICIT_TEMPLATE
00072 template class w_list_i<option_t,unsafe_list_dummy_lock_t>;
00073 template class w_list_t<option_t,unsafe_list_dummy_lock_t>;
00074 #endif
00075
00076
00077 option_t::option_t() : _name(NULL), _value(NULL), _setFunc(NULL)
00078 {
00079 }
00080
00081 option_t::~option_t()
00082 {
00083 _link.detach();
00084 if (_value) free(_value);
00085 _value = NULL;
00086 _name = NULL;
00087 }
00088
00089 w_rc_t option_t::init(const char* name, const char* newPoss,
00090 const char* defaultVal, const char* descr,
00091 bool req, OptionSetFunc setFunc,
00092 ostream *err_stream)
00093 {
00094 _name = name;
00095 _possible_values = newPoss;
00096 _default_value = defaultVal;
00097 _required = req;
00098 _description = descr;
00099 _setFunc = setFunc;
00100 _set = false;
00101 if (!_required) {
00102 if (_default_value) {
00103 w_rc_t rc = set_value(_default_value, false, err_stream);
00104 _set = false;
00105 return rc;
00106 }
00107 }
00108 return RCOK;
00109 }
00110
00111 bool option_t::match(const char* matchName, bool exact)
00112 {
00113 int i;
00114 bool equal;
00115
00116 i = 0;
00117 equal = true;
00118
00119 DBG(<<"name to match is " << matchName);
00120 while(equal) {
00121 if ( (matchName[i] != '\0') && (_name[i] != '\0') ) {
00122 if (matchName[i] != _name[i]) {
00123 DBG(<<"fails because at " << i <<
00124 " matchName is " << matchName[i] <<
00125 " _name is " << _name[i]
00126 );
00127 equal = false;
00128 }
00129 } else {
00130 if (matchName[i] == '\0') {
00131 break;
00132 } else {
00133 DBG(<<"fails because at " << i <<
00134 " matchName is " << matchName[i] <<
00135 " _name is " << _name[i]
00136 );
00137 equal = false;
00138
00139 }
00140 }
00141 i++;
00142 }
00143
00144 if (i == 0) {
00145 equal = false;
00146 } else {
00147 if (exact && (matchName[i] != '\0' || _name[i] != '\0')) {
00148 equal = false;
00149 }
00150 }
00151 return equal;
00152 }
00153
00154 w_rc_t option_t::set_value(const char* value, bool overRide, ostream* err_stream)
00155 {
00156 DBG(<<"option_t::set_value " << name()
00157 << " value = " << value);
00158 if (_set && !overRide) {
00159
00160 return RCOK;
00161 }
00162
00163 if (value == NULL) {
00164 if (_value) {
00165 free(_value);
00166 _set = false;
00167 }
00168 return RCOK;
00169 } else {
00170 W_DO(_setFunc(this, value, err_stream));
00171 }
00172 return RCOK;
00173 }
00174
00175 w_rc_t option_t::copyValue(const char* value)
00176 {
00177 char* new_value;
00178
00179 if (_value) {
00180 new_value = (char*)realloc(_value, strlen(value)+1);
00181 } else {
00182 new_value = (char*)malloc(strlen(value)+1);
00183 }
00184 if (!new_value) {
00185 return RC(fcOUTOFMEMORY);
00186 }
00187 _value = new_value;
00188 strcpy(_value, value);
00189 _set = true;
00190 return RCOK;
00191 }
00192
00193 w_rc_t option_t::concatValue(const char* value)
00194 {
00195 char* new_value;
00196 const char* separator = "\n";
00197
00198 if (_value) {
00199 new_value = (char*)realloc(_value, strlen(_value) + strlen(separator) + strlen(value)+1);
00200 } else {
00201 new_value = (char*)malloc(strlen(value)+1);
00202 }
00203 if (!new_value) {
00204 return RC(fcOUTOFMEMORY);
00205 }
00206 _value = new_value;
00207 strcat(_value, separator);
00208 strcat(_value, value);
00209 _set = true;
00210 return RCOK;
00211 }
00212
00213 bool option_t::str_to_bool(const char* str, bool& badStr)
00214 {
00215 badStr = true;
00216 if (strlen(str) < 1) return false;
00217
00218 switch (str[0]) {
00219 case 't': case 'T': case 'y': case 'Y':
00220 badStr = false;
00221 return true;
00222
00223 case 'f': case 'F': case 'n': case 'N':
00224 badStr = false;
00225 return false;
00226
00227 default:
00228 return false;
00229 }
00230 }
00231
00232 w_rc_t option_t::set_value_bool(option_t* opt, const char* value, ostream* err_stream)
00233 {
00234 bool badVal;
00235 str_to_bool(value, badVal);
00236 if (badVal) {
00237 if (err_stream) *err_stream << "value must be true,false,yes,no";
00238 return RC(OPT_BadValue);
00239 }
00240 W_DO(opt->copyValue(value));
00241 return RCOK;
00242 }
00243
00244 w_rc_t
00245 option_t::set_value_int4(
00246 option_t* opt,
00247 const char* value,
00248 ostream* err_stream)
00249 {
00250 long l;
00251 char* lastValid;
00252
00253 errno = 0;
00254 l = strtol(value, &lastValid, 0);
00255 if(((l == LONG_MAX) || (l == LONG_MIN)) && errno == ERANGE) {
00256
00257 if (err_stream) {
00258 *err_stream
00259 << "value is out of range for a long integer "
00260 << value;
00261 return RC(OPT_BadValue);
00262 }
00263 }
00264 if (lastValid == value) {
00265
00266 if (err_stream) *err_stream << "no valid integer could be formed from " << value;
00267 return RC(OPT_BadValue);
00268 }
00269
00270 W_DO(opt->copyValue(value));
00271 return RCOK;
00272 }
00273
00274 w_rc_t
00275 option_t::set_value_long(
00276 option_t* opt,
00277 const char* value,
00278 ostream* err_stream)
00279 {
00280
00281 return set_value_int4(opt, value, err_stream);
00282 }
00283
00284 w_rc_t
00285 option_t::set_value_int8(
00286 option_t* opt,
00287 const char* value,
00288 ostream* err_stream)
00289 {
00290 w_base_t::int8_t l;
00291
00292 char* lastValid;
00293 errno = 0;
00294 l = w_base_t::strtoi8(value, &lastValid);
00295 if (errno == ERANGE) {
00296
00297 if (err_stream) {
00298 *err_stream
00299 << "value is out of range for a long integer "
00300 << value;
00301 return RC(OPT_BadValue);
00302 }
00303 }
00304 if (lastValid == value) {
00305
00306 if (err_stream) *err_stream << "no valid integer could be formed from " << value;
00307 return RC(OPT_BadValue);
00308 }
00309
00310
00311 W_DO(opt->copyValue(value));
00312 return RCOK;
00313 }
00314
00315 w_rc_t
00316 option_t::set_value_long_long(
00317 option_t* opt,
00318 const char* value,
00319 ostream* err_stream)
00320 {
00321 return set_value_int8(opt, value, err_stream);
00322 }
00323
00324 w_rc_t option_t::set_value_charstr(
00325 option_t* opt,
00326 const char* value,
00327 ostream *
00328 )
00329 {
00330 W_DO(opt->copyValue(value));
00331 return RCOK;
00332 }
00333
00334
00335
00336
00337
00338 bool option_group_t::_error_codes_added = false;
00339
00340 #include "opt_einfo_gen.h"
00341
00342 option_group_t::option_group_t(int maxNameLevels)
00343 : _options(W_LIST_ARG(option_t, _link), unsafe_nolock),
00344 _class_name(NULL),
00345 _levelLocation(NULL),
00346 _maxLevels(maxNameLevels),
00347 _numLevels(0)
00348 {
00349 if (!_error_codes_added) {
00350 if (!(w_error_t::insert(
00351 "Options Package",
00352 opt_error_info,
00353 OPT_ERRMAX - OPT_ERRMIN + 1)) ) {
00354 abort();
00355 }
00356 _error_codes_added = true;
00357 }
00358
00359
00360 _class_name = (char*)malloc(1);
00361 _levelLocation = new char*[_maxLevels];
00362
00363 if (_class_name == NULL || _levelLocation == NULL) {
00364 W_FATAL(fcOUTOFMEMORY);
00365 }
00366 _class_name[0] = '\0';
00367 }
00368
00369 option_group_t::~option_group_t()
00370 {
00371 w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00372
00373 while (scan.next()) {
00374 delete scan.curr();
00375 }
00376 if (_class_name) free(_class_name);
00377 if (_levelLocation) delete[] _levelLocation;
00378 }
00379
00380 w_rc_t option_group_t::add_option(
00381 const char* name, const char* newPoss,
00382 const char* default_value, const char* description,
00383 bool required, option_t::OptionSetFunc setFunc,
00384 option_t*& newOpt,
00385 ostream *err_stream
00386 )
00387 {
00388 DBG(<<"option_group_t::add_option " << name );
00389 W_DO(lookup(name, true, newOpt));
00390 if (newOpt) return RC(OPT_Duplicate);
00391
00392 newOpt = new option_t();
00393 if (!newOpt) return RC(fcOUTOFMEMORY);
00394 w_rc_t rc = newOpt->init(name, newPoss,
00395 default_value, description, required, setFunc, err_stream);
00396 if (rc.is_error()) {
00397 delete newOpt;
00398 newOpt = NULL;
00399 return rc;
00400 }
00401 _options.append(newOpt);
00402 return RCOK;
00403 }
00404
00405 w_rc_t option_group_t::add_class_level(const char* name)
00406 {
00407 if (_numLevels == _maxLevels) {
00408 return RC(OPT_TooManyClasses);
00409 }
00410
00411 char* new_str = (char*)realloc(_class_name, strlen(_class_name)+strlen(name)+2);
00412 if (!new_str) {
00413 return RC(fcOUTOFMEMORY);
00414 }
00415 _class_name = new_str;
00416 _levelLocation[_numLevels] = &(_class_name[strlen(_class_name)]);
00417 _numLevels++;
00418 strcat(_class_name, name);
00419 strcat(_class_name, ".");
00420
00421 return RCOK;
00422 }
00423
00424 #ifdef OLD_CODE
00425 w_rc_t option_group_t::setClassLevel(const char* name, int level)
00426 {
00427 int len;
00428
00429 if (level > _numLevels) {
00430 return RC(OPT_TooManyClasses);
00431 }
00432
00433 if (level == _numLevels) {
00434 return (add_class_level(name));
00435 }
00436
00437 if (_numLevels == MaxOptClassification) {
00438 return RC(OPT_TooManyClasses);
00439 }
00440
00441 _levelName[level] = name;
00442
00443
00444 _classStringLen = 0;
00445 _class_name[0] = '\0';
00446
00447 for(int i = 0; i < _numLevels; i++) {
00448 len = strlen(_levelName[i]) + 1;
00449
00450 if (len > (MaxOptClassLength-_classStringLen) ) {
00451 return RC(OPT_ClassTooLong);
00452 }
00453 strncat(_class_name, _levelName[i], MaxOptClassLength-_classStringLen);
00454 strcat(_class_name, ".");
00455 _classStringLen += len;
00456 }
00457 return RCOK;
00458 }
00459 #endif
00460
00461 w_rc_t option_group_t::lookup(const char* name, bool exact, option_t*& returnOption)
00462 {
00463 DBG(<<"option_group_t::lookup " << name << " exact=" << exact);
00464 w_rc_t rc;
00465
00466 returnOption = NULL;
00467
00468 w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00469 while (scan.next()) {
00470 DBG(<<"scan.curr()==|" << scan.curr()->name() <<"|");
00471 if (scan.curr()->match(name, exact)) {
00472 DBG(<<"match");
00473 if (returnOption != NULL) {
00474 returnOption = NULL;
00475 rc = RC(OPT_Duplicate);
00476 } else {
00477
00478 returnOption = scan.curr();
00479 }
00480 break;
00481 } else {
00482 DBG(<<"nomatch");
00483 }
00484 }
00485 DBG(<<"option_group_t::lookup " << name << " scan done" );
00486 return rc;
00487 }
00488
00489 w_rc_t
00490 option_group_t::lookup_by_class(
00491 const char* optClassName,
00492 option_t*& returnOption,
00493 bool exact
00494 )
00495 {
00496 const char* c;
00497 const char* lastSpecial;
00498
00499 int lastNewSpecial;
00500 w_rc_t rc;
00501 int newClen;
00502 const char* regex = NULL;
00503 bool backSlash = false;
00504
00505 DBG(<<"option_group_t::lookup_by_class " << optClassName);
00506
00507
00508
00509 int newC_len = strlen(optClassName)*2;
00510 char* newC = new char[newC_len];
00511 if (!newC) return RC(fcOUTOFMEMORY);
00512 w_auto_delete_array_t<char> newC_delete(newC);
00513
00514
00515
00516 lastSpecial = optClassName-1;
00517 lastNewSpecial = 0;
00518 newC[lastNewSpecial] = '^';
00519 for (c = optClassName, newClen = 1; *c != '\0'; c++, newClen++) {
00520 if (!backSlash) {
00521 switch (*c) {
00522 case '*':
00523 newC[newClen] = '.';
00524 newClen++;
00525 newC[newClen] = '*';
00526 lastSpecial = c;
00527 lastNewSpecial = newClen;
00528 break;
00529 case '.':
00530 newC[newClen] = '\\';
00531 newClen++;
00532 newC[newClen] = '.';
00533 lastSpecial = c;
00534 lastNewSpecial = newClen;
00535 break;
00536 case '?':
00537 newC[newClen++] = '[';
00538 newC[newClen++] = '^';
00539 newC[newClen++] = '.';
00540 newC[newClen++] = ']';
00541 newC[newClen] = '*';
00542 lastSpecial = c;
00543 lastNewSpecial = newClen;
00544 break;
00545 case ':':
00546
00547 rc = RC(OPT_Syntax);
00548 break;
00549 case ' ': case '\t':
00550 rc = RC(OPT_IllegalClass);
00551 break;
00552 case '\\':
00553 backSlash = true;
00554 newClen--;
00555 break;
00556 default:
00557 newC[newClen] = *c;
00558 }
00559
00560 } else {
00561 newC[newClen] = *c;
00562 backSlash = false;
00563 }
00564
00565 if (lastNewSpecial == newC_len) {
00566 rc = RC(OPT_ClassTooLong);
00567 }
00568 }
00569
00570 if (rc.is_error()) return rc;
00571
00572 if (*c != '\0') {
00573 return RC(OPT_Syntax);
00574 } else {
00575 newC[newClen] = *c;
00576 }
00577
00578
00579 if (lastSpecial == (optClassName-1)) {
00580 return RC(OPT_IllegalClass);
00581 }
00582
00583 newC[lastNewSpecial+1] = '$';
00584 newC[lastNewSpecial+2] = '\0';
00585
00586 if (newC[1] == '$') {
00587 strcat(newC, ".*");
00588 }
00589
00590 regex = re_comp(newC);
00591 if (regex != NULL) {
00592 cerr << "regular expression error: " << regex << endl;
00593 rc = RC(OPT_IllegalClass);
00594 } else {
00595 if (re_exec(_class_name) == 1) {
00596 DBG(<<"re_exec("<<_class_name<<") returned 1");
00597
00598
00599 const char* option = lastSpecial+1;
00600 return lookup(option, exact, returnOption);
00601 } else {
00602 DBG(<<"re_exec("<<_class_name<<") failed");
00603 rc = RC(OPT_NoClassMatch);
00604 }
00605
00606 }
00607
00608 delete regex;
00609 returnOption = NULL;
00610 return rc;
00611 }
00612
00613 w_rc_t
00614 option_group_t::set_value(
00615 const char* name, bool exact,
00616 const char* value, bool overRide,
00617 ostream* err_stream)
00618 {
00619 DBG(<<"option_group_t::set_value: " << name
00620 << " exact=" << exact);
00621 option_t* opt = 0;
00622 W_DO(lookup(name, exact, opt));
00623 if (!opt) {
00624 DBG(<<"nomatch");
00625 return RC(OPT_NoOptionMatch);
00626 }
00627 DBG(<<"MATCH");
00628 W_DO(opt->set_value(value, overRide, err_stream));
00629 return RCOK;
00630 }
00631
00632
00633 void
00634 option_group_t::print_usage(bool longForm, ostream& err_stream)
00635 {
00636 option_t* current;
00637
00638 w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00639 while (scan.next()) {
00640 current = scan.curr();
00641 if (current->is_required()) {
00642 err_stream << " ";
00643 } else {
00644 err_stream << " [";
00645 }
00646 if (current->possible_values() == NULL) {
00647 err_stream << "-" << current->name();
00648 } else {
00649 err_stream << "-" << current->name()
00650 << " <" << current->possible_values() << ">";
00651 }
00652
00653 if (!current->is_required()) err_stream << "]";
00654
00655 if (longForm) {
00656 err_stream << "\n\t\t" << current->description() << "\n";
00657 if (current->default_value() == NULL) {
00658 err_stream << "\t\tdefault value: <none>\n";
00659 } else {
00660 err_stream << "\t\tdefault value: " << current->default_value() << "\n";
00661 }
00662 }
00663 }
00664 if (!longForm) err_stream << endl;
00665 err_stream << "[brackets means optional]" << endl;
00666
00667 return;
00668 }
00669
00670 void option_group_t::print_values(bool longForm, ostream& err_stream)
00671 {
00672 option_t* current;
00673
00674 err_stream << "Values for options of class " << _class_name << ":";
00675 if (longForm) err_stream << "\n";
00676 w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00677 while (scan.next()) {
00678 current = scan.curr();
00679 if (current->is_set()) {
00680 if (!current->is_required()) {
00681 err_stream << " [-" << current->name() << " ";
00682 } else {
00683 err_stream << " -" << current->name() << " ";
00684 }
00685 if (current->value() == NULL) {
00686 err_stream << "<not-set>";
00687 } else {
00688 err_stream << current->value();
00689 }
00690 if (!current->is_required()) err_stream << "]";
00691
00692 if (longForm) err_stream << "\n";
00693 }
00694 }
00695 if (!longForm) err_stream << endl;
00696
00697 return;
00698 }
00699
00700 w_rc_t option_group_t::check_required(ostream* err_stream)
00701 {
00702 DBG(<<"option_group_t::check_required");
00703 w_rc_t rc;
00704 option_t* curr;
00705 bool at_least_one_not_set = false;
00706
00707 w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00708 while ((curr = scan.next())) {
00709 if (curr->is_required() && !curr->is_set()) {
00710 if (err_stream) *err_stream << "option <" << curr->name() << "> is required but not set\n";
00711 at_least_one_not_set = true;
00712 }
00713 }
00714 if (at_least_one_not_set) rc = RC(OPT_NotSet);
00715 return rc;
00716 }
00717
00718 w_rc_t option_group_t::parse_command_line(const char** argv, int& argc, size_t min_len, ostream* err_stream)
00719 {
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729 w_rc_t rc;
00730 int i;
00731 option_t* opt;
00732
00733 i = 0;
00734 while (i < argc && !rc.is_error()) {
00735 if (argv[i][0] == '-' && strlen(argv[i]) > min_len) {
00736 rc = lookup(argv[i]+1, false, opt);
00737 if (!rc.is_error() && opt) {
00738
00739 if (i+1 == argc) {
00740
00741 if (err_stream) *err_stream << "missing argument for " << argv[i];
00742
00743 argc--;
00744 rc = RC(OPT_BadValue);
00745 } else {
00746
00747 rc = opt->set_value(argv[i+1], true, err_stream);
00748 if (rc.is_error()) {
00749 if (err_stream) *err_stream << "bad value for argument " << argv[i];
00750 }
00751
00752
00753 for (int j = i+2; j < argc; j++) {
00754 argv[j-2] = argv[j];
00755 }
00756 argc -= 2;
00757 }
00758 } else if (!rc.is_error()) {
00759
00760 i++;
00761 } else {
00762
00763 }
00764 } else {
00765 i++;
00766 }
00767 }
00768 return(rc);
00769 }
00770
00771
00772
00773
00774
00775 const char *option_stream_scan_t::default_label = "istream";
00776
00777 option_stream_scan_t::option_stream_scan_t(istream &is, option_group_t *list)
00778 : _input(is),
00779 _optList(list),
00780 _line(0),
00781 _label(default_label),
00782 _lineNum(0)
00783 {
00784 }
00785
00786 option_stream_scan_t::~option_stream_scan_t()
00787 {
00788 if (_line) {
00789 delete [] _line;
00790 _line = 0;
00791 }
00792 if (_label != default_label) {
00793 delete [] _label;
00794 _label = default_label;
00795 }
00796 }
00797
00798
00799 void option_stream_scan_t::setLabel(const char *newLabel)
00800 {
00801 if (_label != default_label) {
00802 delete [] _label;
00803 _label = default_label;
00804 }
00805 if (newLabel) {
00806
00807 char *s = new char[strlen(newLabel) + 1];
00808 if (s) {
00809 strcpy(s, newLabel);
00810 _label = s;
00811 }
00812 }
00813 }
00814
00815 w_rc_t option_stream_scan_t::scan(
00816 bool overRide,
00817 ostream& err_stream,
00818 bool exact,
00819 bool mismatch_ok
00820 )
00821 {
00822 option_t* optInfo;
00823 int optBegin, optEnd, valBegin, valEnd, valLength;
00824 int i;
00825 bool backSlash = false;
00826 const char* optionName = NULL;
00827
00828 if (!_line) {
00829 _line = new char[_maxLineLen+1];
00830 if (!_line)
00831 return RC(fcOUTOFMEMORY);
00832 }
00833
00834 DBG(<<"scanning options stream " << _label);
00835
00836 w_rc_t rc;
00837 while ( !rc.is_error() && (_input.getline(_line, _maxLineLen) != NULL) ) {
00838 _lineNum++;
00839 DBG(<<"scan line " << _lineNum);
00840
00841 if (strlen(_line)+1 >= _maxLineLen) {
00842 err_stream << "line " << _lineNum << " is too long";
00843 rc = RC(OPT_IllegalDescLine);
00844 break;
00845 }
00846
00847
00848
00849
00850 optBegin = -1;
00851 optEnd = -1;
00852 for (i = 0; _line[i] != '\0'; i++) {
00853 if (optBegin < 0) {
00854
00855 if (isspace(_line[i])) {
00856 continue;
00857 } else {
00858 optBegin = i;
00859 }
00860 }
00861 if (_line[i] == '\\') {
00862 backSlash = !backSlash;
00863 if (backSlash) continue;
00864 }
00865 if (_line[i] == ':' && !backSlash) {
00866 optEnd = i;
00867 break;
00868 }
00869 backSlash = false;
00870 }
00871
00872
00873 if (optBegin < 0 || _line[optBegin] == '#' || _line[optBegin] == '!') {
00874 continue;
00875 }
00876
00877
00878 if (optEnd < 0) {
00879 err_stream << "syntax error at " << _label << ":" << _lineNum;
00880 rc = RC(OPT_Syntax);
00881 break;
00882 }
00883 _line[optEnd] = '\0';
00884
00885 optionName = _line+optBegin;
00886
00887 rc = _optList->lookup_by_class(optionName, optInfo, exact);
00888 if (!rc.is_error() && optInfo == NULL) {
00889
00890 rc = RC(OPT_NoOptionMatch);
00891 }
00892
00893 switch (rc.err_num()) {
00894 case 0:
00895 break;
00896 case OPT_NoClassMatch:
00897
00898 break;
00899 case OPT_NoOptionMatch:
00900 if(!mismatch_ok) {
00901 err_stream << "unknown option at " << _label << ":" << _lineNum;
00902 }
00903 break;
00904 case OPT_Duplicate:
00905 err_stream << "option name is not unique at "
00906 << _label << ":" << _lineNum;
00907 break;
00908 case OPT_Syntax:
00909 err_stream << "syntax error at " << _label << ":" << _lineNum;
00910 break;
00911 case OPT_IllegalClass:
00912 err_stream << "illegal/missing option class at "
00913 << _label << ":" << _lineNum;
00914 break;
00915 default:
00916 err_stream << "general error in option at "
00917 << _label << ":" << _lineNum;
00918 break;
00919 }
00920
00921 if (rc.is_error()) {
00922 if (rc.err_num() == OPT_NoClassMatch) {
00923
00924 rc = RCOK;
00925 }
00926 if (mismatch_ok && rc.err_num() == OPT_NoOptionMatch) {
00927
00928 rc = RCOK;
00929 }
00930 continue;
00931 }
00932
00933
00934
00935
00936 valBegin = -1;
00937 valEnd = -1;
00938 for (i = optEnd+1; _line[i] != '\0'; i++) {
00939
00940 if (isspace(_line[i])) {
00941 if (valBegin < 0) {
00942 continue;
00943 }
00944 } else {
00945 if (valBegin < 0) {
00946 valBegin = i;
00947 }
00948 valEnd = i;
00949 }
00950 }
00951
00952 if (valBegin < 0) {
00953 err_stream << "syntax error (missing option value) at "
00954 << _label << ":" << _lineNum;
00955 rc = RC(OPT_Syntax);
00956 break;
00957 }
00958
00959
00960 if (_line[valBegin] == '"') {
00961 valBegin++;
00962 if (_line[valEnd] != '"') {
00963 err_stream << "syntax error (missing \") at "
00964 << _label << ":" << _lineNum;
00965 rc = RC(OPT_Syntax);
00966 break;
00967 }
00968 valEnd--;
00969 }
00970 valLength = valEnd - valBegin + 1;
00971
00972 if (valLength < 0) {
00973 err_stream << "syntax error (bad option value) at "
00974 << _label << ":" << _lineNum;
00975 rc = RC(OPT_Syntax);
00976 break;
00977 }
00978
00979 if (rc.is_error()) {
00980 continue;
00981 }
00982
00983
00984 if (optInfo != NULL) {
00985 _line[valEnd+1] = '\0';
00986 rc = optInfo->set_value(_line+valBegin, overRide, &err_stream);
00987 if (rc.is_error()) {
00988 err_stream << "Option value error at "
00989 << _label << ":" << _lineNum;
00990 break;
00991 }
00992 }
00993
00994 }
00995 DBG(<<"last line scanned: " << _lineNum);
00996
00997 return rc;
00998 }
00999
01000 option_file_scan_t::option_file_scan_t(const char* optFile, option_group_t* list)
01001 : _fileName(optFile),
01002 _optList(list)
01003 {
01004 }
01005
01006 option_file_scan_t::~option_file_scan_t()
01007 {
01008 }
01009
01010 w_rc_t option_file_scan_t::scan(
01011 bool overRide,
01012 ostream& err_stream,
01013 bool exact,
01014 bool mismatch_ok
01015 )
01016 {
01017 w_rc_t e;
01018
01019 DBG(<<"scanning options file " << _fileName);
01020
01021 ifstream f(_fileName);
01022
01023 if (!f) {
01024 e = RC(fcOS);
01025 DBG(<<"scan: open failure file " << _fileName);
01026 err_stream << "Could not open the option file " << _fileName;
01027 return e;
01028 }
01029 DBG(<<"scanning options file " << _fileName);
01030
01031 option_stream_scan_t ss(f, _optList);
01032 ss.setLabel(_fileName);
01033
01034 return ss.scan(overRide, err_stream, exact, mismatch_ok);
01035 }
01036