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
00291 char* lastValid;
00292 errno = 0;
00293
00294
00295
00296 (void) w_base_t::strtoi8(value, &lastValid);
00297 if (errno == ERANGE) {
00298
00299 if (err_stream) {
00300 *err_stream
00301 << "value is out of range for a long integer "
00302 << value;
00303 return RC(OPT_BadValue);
00304 }
00305 }
00306 if (lastValid == value) {
00307
00308 if (err_stream) *err_stream
00309 << "no valid integer could be formed from " << value;
00310 return RC(OPT_BadValue);
00311 }
00312
00313
00314 W_DO(opt->copyValue(value));
00315 return RCOK;
00316 }
00317
00318 w_rc_t
00319 option_t::set_value_long_long(
00320 option_t* opt,
00321 const char* value,
00322 ostream* err_stream)
00323 {
00324 return set_value_int8(opt, value, err_stream);
00325 }
00326
00327 w_rc_t option_t::set_value_charstr(
00328 option_t* opt,
00329 const char* value,
00330 ostream *
00331 )
00332 {
00333 W_DO(opt->copyValue(value));
00334 return RCOK;
00335 }
00336
00337
00338
00339
00340
00341 bool option_group_t::_error_codes_added = false;
00342
00343 #include "opt_einfo_gen.h"
00344
00345 option_group_t::option_group_t(int maxNameLevels)
00346 : _options(W_LIST_ARG(option_t, _link), unsafe_nolock),
00347 _class_name(NULL),
00348 _levelLocation(NULL),
00349 _maxLevels(maxNameLevels),
00350 _numLevels(0)
00351 {
00352 if (!_error_codes_added) {
00353 if (!(w_error_t::insert(
00354 "Options Package",
00355 opt_error_info,
00356 OPT_ERRMAX - OPT_ERRMIN + 1)) ) {
00357 abort();
00358 }
00359 _error_codes_added = true;
00360 }
00361
00362
00363 _class_name = (char*)malloc(1);
00364 _levelLocation = new char*[_maxLevels];
00365
00366 if (_class_name == NULL || _levelLocation == NULL) {
00367 W_FATAL(fcOUTOFMEMORY);
00368 }
00369 _class_name[0] = '\0';
00370 }
00371
00372 option_group_t::~option_group_t()
00373 {
00374 w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00375
00376 while (scan.next()) {
00377 delete scan.curr();
00378 }
00379 if (_class_name) free(_class_name);
00380 if (_levelLocation) delete[] _levelLocation;
00381 }
00382
00383 w_rc_t option_group_t::add_option(
00384 const char* name, const char* newPoss,
00385 const char* default_value, const char* description,
00386 bool required, option_t::OptionSetFunc setFunc,
00387 option_t*& newOpt,
00388 ostream *err_stream
00389 )
00390 {
00391 DBG(<<"option_group_t::add_option " << name );
00392 W_DO(lookup(name, true, newOpt));
00393 if (newOpt) return RC(OPT_Duplicate);
00394
00395 newOpt = new option_t();
00396 if (!newOpt) return RC(fcOUTOFMEMORY);
00397 w_rc_t rc = newOpt->init(name, newPoss,
00398 default_value, description, required, setFunc, err_stream);
00399 if (rc.is_error()) {
00400 delete newOpt;
00401 newOpt = NULL;
00402 return rc;
00403 }
00404 _options.append(newOpt);
00405 return RCOK;
00406 }
00407
00408 w_rc_t option_group_t::add_class_level(const char* name)
00409 {
00410 if (_numLevels == _maxLevels) {
00411 return RC(OPT_TooManyClasses);
00412 }
00413
00414 char* new_str = (char*)realloc(_class_name, strlen(_class_name)+strlen(name)+2);
00415 if (!new_str) {
00416 return RC(fcOUTOFMEMORY);
00417 }
00418 _class_name = new_str;
00419 _levelLocation[_numLevels] = &(_class_name[strlen(_class_name)]);
00420 _numLevels++;
00421 strcat(_class_name, name);
00422 strcat(_class_name, ".");
00423
00424 return RCOK;
00425 }
00426
00427 #ifdef OLD_CODE
00428 w_rc_t option_group_t::setClassLevel(const char* name, int level)
00429 {
00430 int len;
00431
00432 if (level > _numLevels) {
00433 return RC(OPT_TooManyClasses);
00434 }
00435
00436 if (level == _numLevels) {
00437 return (add_class_level(name));
00438 }
00439
00440 if (_numLevels == MaxOptClassification) {
00441 return RC(OPT_TooManyClasses);
00442 }
00443
00444 _levelName[level] = name;
00445
00446
00447 _classStringLen = 0;
00448 _class_name[0] = '\0';
00449
00450 for(int i = 0; i < _numLevels; i++) {
00451 len = strlen(_levelName[i]) + 1;
00452
00453 if (len > (MaxOptClassLength-_classStringLen) ) {
00454 return RC(OPT_ClassTooLong);
00455 }
00456 strncat(_class_name, _levelName[i], MaxOptClassLength-_classStringLen);
00457 strcat(_class_name, ".");
00458 _classStringLen += len;
00459 }
00460 return RCOK;
00461 }
00462 #endif
00463
00464 w_rc_t option_group_t::lookup(const char* name, bool exact, option_t*& returnOption)
00465 {
00466 DBG(<<"option_group_t::lookup " << name << " exact=" << exact);
00467 w_rc_t rc;
00468
00469 returnOption = NULL;
00470
00471 w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00472 while (scan.next()) {
00473 DBG(<<"scan.curr()==|" << scan.curr()->name() <<"|");
00474 if (scan.curr()->match(name, exact)) {
00475 DBG(<<"match");
00476 if (returnOption != NULL) {
00477 returnOption = NULL;
00478 rc = RC(OPT_Duplicate);
00479 } else {
00480
00481 returnOption = scan.curr();
00482 }
00483 break;
00484 } else {
00485 DBG(<<"nomatch");
00486 }
00487 }
00488 DBG(<<"option_group_t::lookup " << name << " scan done" );
00489 return rc;
00490 }
00491
00492 w_rc_t
00493 option_group_t::lookup_by_class(
00494 const char* optClassName,
00495 option_t*& returnOption,
00496 bool exact
00497 )
00498 {
00499 const char* c;
00500 const char* lastSpecial;
00501
00502 int lastNewSpecial;
00503 w_rc_t rc;
00504 int newClen;
00505 const char* regex = NULL;
00506 bool backSlash = false;
00507
00508 DBG(<<"option_group_t::lookup_by_class " << optClassName);
00509
00510
00511
00512 int newC_len = strlen(optClassName)*2;
00513 char* newC = new char[newC_len];
00514 if (!newC) return RC(fcOUTOFMEMORY);
00515 w_auto_delete_array_t<char> newC_delete(newC);
00516
00517
00518
00519 lastSpecial = optClassName-1;
00520 lastNewSpecial = 0;
00521 newC[lastNewSpecial] = '^';
00522 for (c = optClassName, newClen = 1; *c != '\0'; c++, newClen++) {
00523 if (!backSlash) {
00524 switch (*c) {
00525 case '*':
00526 newC[newClen] = '.';
00527 newClen++;
00528 newC[newClen] = '*';
00529 lastSpecial = c;
00530 lastNewSpecial = newClen;
00531 break;
00532 case '.':
00533 newC[newClen] = '\\';
00534 newClen++;
00535 newC[newClen] = '.';
00536 lastSpecial = c;
00537 lastNewSpecial = newClen;
00538 break;
00539 case '?':
00540 newC[newClen++] = '[';
00541 newC[newClen++] = '^';
00542 newC[newClen++] = '.';
00543 newC[newClen++] = ']';
00544 newC[newClen] = '*';
00545 lastSpecial = c;
00546 lastNewSpecial = newClen;
00547 break;
00548 case ':':
00549
00550 rc = RC(OPT_Syntax);
00551 break;
00552 case ' ': case '\t':
00553 rc = RC(OPT_IllegalClass);
00554 break;
00555 case '\\':
00556 backSlash = true;
00557 newClen--;
00558 break;
00559 default:
00560 newC[newClen] = *c;
00561 }
00562
00563 } else {
00564 newC[newClen] = *c;
00565 backSlash = false;
00566 }
00567
00568 if (lastNewSpecial == newC_len) {
00569 rc = RC(OPT_ClassTooLong);
00570 }
00571 }
00572
00573 if (rc.is_error()) return rc;
00574
00575 if (*c != '\0') {
00576 return RC(OPT_Syntax);
00577 } else {
00578 newC[newClen] = *c;
00579 }
00580
00581
00582 if (lastSpecial == (optClassName-1)) {
00583 return RC(OPT_IllegalClass);
00584 }
00585
00586 newC[lastNewSpecial+1] = '$';
00587 newC[lastNewSpecial+2] = '\0';
00588
00589 if (newC[1] == '$') {
00590 strcat(newC, ".*");
00591 }
00592
00593 regex = re_comp(newC);
00594 if (regex != NULL) {
00595 cerr << "regular expression error: " << regex << endl;
00596 rc = RC(OPT_IllegalClass);
00597 } else {
00598 if (re_exec(_class_name) == 1) {
00599 DBG(<<"re_exec("<<_class_name<<") returned 1");
00600
00601
00602 const char* option = lastSpecial+1;
00603 return lookup(option, exact, returnOption);
00604 } else {
00605 DBG(<<"re_exec("<<_class_name<<") failed");
00606 rc = RC(OPT_NoClassMatch);
00607 }
00608
00609 }
00610
00611 delete regex;
00612 returnOption = NULL;
00613 return rc;
00614 }
00615
00616 w_rc_t
00617 option_group_t::set_value(
00618 const char* name, bool exact,
00619 const char* value, bool overRide,
00620 ostream* err_stream)
00621 {
00622 DBG(<<"option_group_t::set_value: " << name
00623 << " exact=" << exact);
00624 option_t* opt = 0;
00625 W_DO(lookup(name, exact, opt));
00626 if (!opt) {
00627 DBG(<<"nomatch");
00628 return RC(OPT_NoOptionMatch);
00629 }
00630 DBG(<<"MATCH");
00631 W_DO(opt->set_value(value, overRide, err_stream));
00632 return RCOK;
00633 }
00634
00635
00636 void
00637 option_group_t::print_usage(bool longForm, ostream& err_stream)
00638 {
00639 option_t* current;
00640
00641 w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00642 while (scan.next()) {
00643 current = scan.curr();
00644 if (current->is_required()) {
00645 err_stream << " ";
00646 } else {
00647 err_stream << " [";
00648 }
00649 if (current->possible_values() == NULL) {
00650 err_stream << "-" << current->name();
00651 } else {
00652 err_stream << "-" << current->name()
00653 << " <" << current->possible_values() << ">";
00654 }
00655
00656 if (!current->is_required()) err_stream << "]";
00657
00658 if (longForm) {
00659 err_stream << "\n\t\t" << current->description() << "\n";
00660 if (current->default_value() == NULL) {
00661 err_stream << "\t\tdefault value: <none>\n";
00662 } else {
00663 err_stream << "\t\tdefault value: " << current->default_value() << "\n";
00664 }
00665 }
00666 }
00667 if (!longForm) err_stream << endl;
00668 err_stream << "[brackets means optional]" << endl;
00669
00670 return;
00671 }
00672
00673 void option_group_t::print_values(bool longForm, ostream& err_stream)
00674 {
00675 option_t* current;
00676
00677 err_stream << "Values for options of class " << _class_name << ":";
00678 if (longForm) err_stream << "\n";
00679 w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00680 while (scan.next()) {
00681 current = scan.curr();
00682 if (current->is_set()) {
00683 if (!current->is_required()) {
00684 err_stream << " [-" << current->name() << " ";
00685 } else {
00686 err_stream << " -" << current->name() << " ";
00687 }
00688 if (current->value() == NULL) {
00689 err_stream << "<not-set>";
00690 } else {
00691 err_stream << current->value();
00692 }
00693 if (!current->is_required()) err_stream << "]";
00694
00695 if (longForm) err_stream << "\n";
00696 }
00697 }
00698 if (!longForm) err_stream << endl;
00699
00700 return;
00701 }
00702
00703 w_rc_t option_group_t::check_required(ostream* err_stream)
00704 {
00705 DBG(<<"option_group_t::check_required");
00706 w_rc_t rc;
00707 option_t* curr;
00708 bool at_least_one_not_set = false;
00709
00710 w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00711 while ((curr = scan.next())) {
00712 if (curr->is_required() && !curr->is_set()) {
00713 if (err_stream) *err_stream << "option <" << curr->name() << "> is required but not set\n";
00714 at_least_one_not_set = true;
00715 }
00716 }
00717 if (at_least_one_not_set) rc = RC(OPT_NotSet);
00718 return rc;
00719 }
00720
00721 w_rc_t option_group_t::parse_command_line(const char** argv, int& argc, size_t min_len, ostream* err_stream)
00722 {
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732 w_rc_t rc;
00733 int i;
00734 option_t* opt;
00735
00736 i = 0;
00737 while (i < argc && !rc.is_error()) {
00738 if (argv[i][0] == '-' && strlen(argv[i]) > min_len) {
00739 rc = lookup(argv[i]+1, false, opt);
00740 if (!rc.is_error() && opt) {
00741
00742 if (i+1 == argc) {
00743
00744 if (err_stream) *err_stream << "missing argument for " << argv[i];
00745
00746 argc--;
00747 rc = RC(OPT_BadValue);
00748 } else {
00749
00750 rc = opt->set_value(argv[i+1], true, err_stream);
00751 if (rc.is_error()) {
00752 if (err_stream) *err_stream << "bad value for argument " << argv[i];
00753 }
00754
00755
00756 for (int j = i+2; j < argc; j++) {
00757 argv[j-2] = argv[j];
00758 }
00759 argc -= 2;
00760 }
00761 } else if (!rc.is_error()) {
00762
00763 i++;
00764 } else {
00765
00766 }
00767 } else {
00768 i++;
00769 }
00770 }
00771 return(rc);
00772 }
00773
00774
00775
00776
00777
00778 const char *option_stream_scan_t::default_label = "istream";
00779
00780 option_stream_scan_t::option_stream_scan_t(istream &is, option_group_t *list)
00781 : _input(is),
00782 _optList(list),
00783 _line(0),
00784 _label(default_label),
00785 _lineNum(0)
00786 {
00787 }
00788
00789 option_stream_scan_t::~option_stream_scan_t()
00790 {
00791 if (_line) {
00792 delete [] _line;
00793 _line = 0;
00794 }
00795 if (_label != default_label) {
00796 delete [] _label;
00797 _label = default_label;
00798 }
00799 }
00800
00801
00802 void option_stream_scan_t::setLabel(const char *newLabel)
00803 {
00804 if (_label != default_label) {
00805 delete [] _label;
00806 _label = default_label;
00807 }
00808 if (newLabel) {
00809
00810 char *s = new char[strlen(newLabel) + 1];
00811 if (s) {
00812 strcpy(s, newLabel);
00813 _label = s;
00814 }
00815 }
00816 }
00817
00818 w_rc_t option_stream_scan_t::scan(
00819 bool overRide,
00820 ostream& err_stream,
00821 bool exact,
00822 bool mismatch_ok
00823 )
00824 {
00825 option_t* optInfo;
00826 int optBegin, optEnd, valBegin, valEnd, valLength;
00827 int i;
00828 bool backSlash = false;
00829 const char* optionName = NULL;
00830
00831 if (!_line) {
00832 _line = new char[_maxLineLen+1];
00833 if (!_line)
00834 return RC(fcOUTOFMEMORY);
00835 }
00836
00837 DBG(<<"scanning options stream " << _label);
00838
00839 w_rc_t rc;
00840 while ( !rc.is_error() && (_input.getline(_line, _maxLineLen) != NULL) ) {
00841 _lineNum++;
00842 DBG(<<"scan line " << _lineNum);
00843
00844 if (strlen(_line)+1 >= _maxLineLen) {
00845 err_stream << "line " << _lineNum << " is too long";
00846 rc = RC(OPT_IllegalDescLine);
00847 break;
00848 }
00849
00850
00851
00852
00853 optBegin = -1;
00854 optEnd = -1;
00855 for (i = 0; _line[i] != '\0'; i++) {
00856 if (optBegin < 0) {
00857
00858 if (isspace(_line[i])) {
00859 continue;
00860 } else {
00861 optBegin = i;
00862 }
00863 }
00864 if (_line[i] == '\\') {
00865 backSlash = !backSlash;
00866 if (backSlash) continue;
00867 }
00868 if (_line[i] == ':' && !backSlash) {
00869 optEnd = i;
00870 break;
00871 }
00872 backSlash = false;
00873 }
00874
00875
00876 if (optBegin < 0 || _line[optBegin] == '#' || _line[optBegin] == '!') {
00877 continue;
00878 }
00879
00880
00881 if (optEnd < 0) {
00882 err_stream << "syntax error at " << _label << ":" << _lineNum;
00883 rc = RC(OPT_Syntax);
00884 break;
00885 }
00886 _line[optEnd] = '\0';
00887
00888 optionName = _line+optBegin;
00889
00890 rc = _optList->lookup_by_class(optionName, optInfo, exact);
00891 if (!rc.is_error() && optInfo == NULL) {
00892
00893 rc = RC(OPT_NoOptionMatch);
00894 }
00895
00896 switch (rc.err_num()) {
00897 case 0:
00898 break;
00899 case OPT_NoClassMatch:
00900
00901 break;
00902 case OPT_NoOptionMatch:
00903 if(!mismatch_ok) {
00904 err_stream << "unknown option at " << _label << ":" << _lineNum;
00905 }
00906 break;
00907 case OPT_Duplicate:
00908 err_stream << "option name is not unique at "
00909 << _label << ":" << _lineNum;
00910 break;
00911 case OPT_Syntax:
00912 err_stream << "syntax error at " << _label << ":" << _lineNum;
00913 break;
00914 case OPT_IllegalClass:
00915 err_stream << "illegal/missing option class at "
00916 << _label << ":" << _lineNum;
00917 break;
00918 default:
00919 err_stream << "general error in option at "
00920 << _label << ":" << _lineNum;
00921 break;
00922 }
00923
00924 if (rc.is_error()) {
00925 if (rc.err_num() == OPT_NoClassMatch) {
00926
00927 rc = RCOK;
00928 }
00929 if (mismatch_ok && rc.err_num() == OPT_NoOptionMatch) {
00930
00931 rc = RCOK;
00932 }
00933 continue;
00934 }
00935
00936
00937
00938
00939 valBegin = -1;
00940 valEnd = -1;
00941 for (i = optEnd+1; _line[i] != '\0'; i++) {
00942
00943 if (isspace(_line[i])) {
00944 if (valBegin < 0) {
00945 continue;
00946 }
00947 } else {
00948 if (valBegin < 0) {
00949 valBegin = i;
00950 }
00951 valEnd = i;
00952 }
00953 }
00954
00955 if (valBegin < 0) {
00956 err_stream << "syntax error (missing option value) at "
00957 << _label << ":" << _lineNum;
00958 rc = RC(OPT_Syntax);
00959 break;
00960 }
00961
00962
00963 if (_line[valBegin] == '"') {
00964 valBegin++;
00965 if (_line[valEnd] != '"') {
00966 err_stream << "syntax error (missing \") at "
00967 << _label << ":" << _lineNum;
00968 rc = RC(OPT_Syntax);
00969 break;
00970 }
00971 valEnd--;
00972 }
00973 valLength = valEnd - valBegin + 1;
00974
00975 if (valLength < 0) {
00976 err_stream << "syntax error (bad option value) at "
00977 << _label << ":" << _lineNum;
00978 rc = RC(OPT_Syntax);
00979 break;
00980 }
00981
00982 if (rc.is_error()) {
00983 continue;
00984 }
00985
00986
00987 if (optInfo != NULL) {
00988 _line[valEnd+1] = '\0';
00989 rc = optInfo->set_value(_line+valBegin, overRide, &err_stream);
00990 if (rc.is_error()) {
00991 err_stream << "Option value error at "
00992 << _label << ":" << _lineNum;
00993 break;
00994 }
00995 }
00996
00997 }
00998 DBG(<<"last line scanned: " << _lineNum);
00999
01000 return rc;
01001 }
01002
01003 option_file_scan_t::option_file_scan_t(const char* optFile, option_group_t* list)
01004 : _fileName(optFile),
01005 _optList(list)
01006 {
01007 }
01008
01009 option_file_scan_t::~option_file_scan_t()
01010 {
01011 }
01012
01013 w_rc_t option_file_scan_t::scan(
01014 bool overRide,
01015 ostream& err_stream,
01016 bool exact,
01017 bool mismatch_ok
01018 )
01019 {
01020 w_rc_t e;
01021
01022 DBG(<<"scanning options file " << _fileName);
01023
01024 ifstream f(_fileName);
01025
01026 if (!f) {
01027 e = RC(fcOS);
01028 DBG(<<"scan: open failure file " << _fileName);
01029 err_stream << "Could not open the option file " << _fileName;
01030 return e;
01031 }
01032 DBG(<<"scanning options file " << _fileName);
01033
01034 option_stream_scan_t ss(f, _optList);
01035 ss.setLabel(_fileName);
01036
01037 return ss.scan(overRide, err_stream, exact, mismatch_ok);
01038 }
01039