option.cpp

00001 /* -*- mode:C++; c-basic-offset:4 -*-
00002      Shore-MT -- Multi-threaded port of the SHORE storage manager
00003    
00004                        Copyright (c) 2007-2009
00005       Data Intensive Applications and Systems Labaratory (DIAS)
00006                Ecole Polytechnique Federale de Lausanne
00007    
00008                          All Rights Reserved.
00009    
00010    Permission to use, copy, modify and distribute this software and
00011    its documentation is hereby granted, provided that both the
00012    copyright notice and this permission notice appear in all copies of
00013    the software, derivative works or modified versions, and any
00014    portions thereof, and that both notices appear in supporting
00015    documentation.
00016    
00017    This code is distributed in the hope that it will be useful, but
00018    WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
00020    DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
00021    RESULTING FROM THE USE OF THIS SOFTWARE.
00022 */
00023 
00024 /*<std-header orig-src='shore'>
00025 
00026  $Id: option.cpp,v 1.57 2010/08/03 14:24:41 nhall Exp $
00027 
00028 SHORE -- Scalable Heterogeneous Object REpository
00029 
00030 Copyright (c) 1994-99 Computer Sciences Department, University of
00031                       Wisconsin -- Madison
00032 All Rights Reserved.
00033 
00034 Permission to use, copy, modify and distribute this software and its
00035 documentation is hereby granted, provided that both the copyright
00036 notice and this permission notice appear in all copies of the
00037 software, derivative works or modified versions, and any portions
00038 thereof, and that both notices appear in supporting documentation.
00039 
00040 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00041 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00042 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00043 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00044 
00045 This software was developed with support by the Advanced Research
00046 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00047 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00048 Further funding for this work was provided by DARPA through
00049 Rome Research Laboratory Contract No. F30602-97-2-0247.
00050 
00051 */
00052 
00053 #include "w_defines.h"
00054 
00055 /*  -- do not edit anything above this line --   </std-header>*/
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 /*__GNUG__*/
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; // since at end of string
00132             } else {
00133                 DBG(<<"fails because at " << i << 
00134                     " matchName is " << matchName[i] <<
00135                     " _name is " << _name[i]
00136                 );
00137                 equal = false;         // since _name[i] == '\0' 
00138                                 // matchName must be longer
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             /* option not set */
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; /* option was set successfully */
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; /* option was set successfully */
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; /* option was set successfully */
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             //break;
00223         case 'f': case 'F': case 'n': case 'N':
00224             badStr = false;
00225             return false;
00226             //break;
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/*any base*/);
00255     if(((l == LONG_MAX) || (l == LONG_MIN)) && errno == ERANGE) {
00256         /* out of range */
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         // not integer could be formed
00266         if (err_stream) *err_stream << "no valid integer could be formed from " << value;
00267         return RC(OPT_BadValue);
00268    }
00269     // value is good
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         /* XXX breaks on 64 bit machines? */
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     // Keep compiler from complaining about
00294     // unused l: 
00295     // w_base_t::int8_t l =
00296     (void) w_base_t::strtoi8(value, &lastValid);
00297     if (errno == ERANGE) {
00298         /* out of range */
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         // not integer could be formed
00308         if (err_stream) *err_stream 
00309             << "no valid integer could be formed from " << value;
00310         return RC(OPT_BadValue);
00311     }
00312     // value is good
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 * //err_stream_unused
00331         )
00332 {
00333     W_DO(opt->copyValue(value));
00334     return RCOK;
00335 }
00336 
00337 ///////////////////////////////////////////////////////////////////
00338 //            option_group_t functions                                 //
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); // use malloc so we can realloc
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     // This list mod is ok
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/*for . and \0*/);
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     // rebuild the class level string
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 /*OLD_CODE*/
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;        // duplicate
00478                 rc = RC(OPT_Duplicate);
00479             } else {
00480                 // match found;
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     // regular expr is placed here, at most
00511     // it can be twice as long as optClassName
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     // process the option name and classification suffix
00518     // Make a regular expression for the option classification
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                         // no semicolons allowed (really internal error)
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     //        See if class name is missing
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             // see if option name matches
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()) { // only print option which have a value 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      * FUNCTION DESCRIPTION:
00726      *
00727      * This function examines command line arguments for configuration
00728      * options.  It returns argv with any sm configuration options
00729      * removed.  Argc is adjusted as well.
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                 // found the option
00742                 if (i+1 == argc) {
00743 
00744                     if (err_stream) *err_stream << "missing argument for " << argv[i];
00745                     // remove this option argument
00746                     argc--;
00747                     rc = RC(OPT_BadValue);
00748                 } else {
00749                         // VCPP Wierdness if (rc = ...)
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                     // remove these option and value arguments
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                 // no real error, just not found
00763                 i++;  // advance to next argument
00764             } else {
00765                 // fall out of loop due to error
00766             }
00767         } else {
00768             i++;  // advance to next argument
00769         }
00770     }
00771     return(rc);
00772 }
00773 
00774 ///////////////////////////////////////////////////////////////////
00775 //            option_file_scan_t functions                                 //
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                 // behavior in case of memory failure is fail safe
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             //        Find the classOption field
00852             //
00853             optBegin = -1;
00854             optEnd = -1;
00855             for (i = 0; _line[i] != '\0'; i++) {
00856             if (optBegin < 0) {
00857                     /* if whitespace */
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; /* out of for loop */
00871             } 
00872             backSlash = false;
00873             }
00874 
00875             // check for a comment or blank line and skip it
00876             if (optBegin < 0 || _line[optBegin] == '#' || _line[optBegin] == '!') {
00877             continue;        
00878             }
00879 
00880             // check syntax
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             //option name was not found
00893             rc = RC(OPT_NoOptionMatch);
00894         }
00895 
00896             switch (rc.err_num()) {
00897             case 0:
00898                     break;
00899             case OPT_NoClassMatch:
00900                 // no error message needed since this is ok
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                 // this is ok, we just skip the line
00927                 rc = RCOK;
00928             }
00929             if (mismatch_ok && rc.err_num() == OPT_NoOptionMatch) {
00930                 // this is ok, we just skip the line
00931                 rc = RCOK;
00932             }
00933             continue;
00934             }
00935 
00936             // 
00937             //        Find the option value field
00938             //
00939             valBegin = -1;
00940             valEnd = -1;
00941             for (i = optEnd+1; _line[i] != '\0'; i++) {
00942             /* if whitespace */
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             // remove any quote marks
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             // if option was found to set 
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 

Generated on Mon Nov 8 11:12:36 2010 for Shore Storage Manager by  doxygen 1.4.7