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.58 2010/12/08 17:37:34 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 w_rc_t option_group_t::lookup(const char* name, bool exact, option_t*& returnOption)
00428 {
00429     DBG(<<"option_group_t::lookup " << name << " exact=" << exact);
00430     w_rc_t rc;
00431 
00432     returnOption = NULL;
00433 
00434     w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00435     while (scan.next()) {
00436          DBG(<<"scan.curr()==|" << scan.curr()->name() <<"|");
00437          if (scan.curr()->match(name, exact)) {
00438             DBG(<<"match");
00439             if (returnOption != NULL) {
00440                 returnOption = NULL;        // duplicate
00441                 rc = RC(OPT_Duplicate);
00442             } else {
00443                 // match found;
00444                 returnOption = scan.curr();
00445             }
00446             break;
00447         } else {
00448             DBG(<<"nomatch");
00449         }
00450     }
00451     DBG(<<"option_group_t::lookup " << name << " scan done" );
00452     return rc;
00453 }
00454 
00455 w_rc_t
00456 option_group_t::lookup_by_class(
00457     const char* optClassName, 
00458     option_t*& returnOption,
00459     bool exact
00460 )
00461 {
00462     const char*                c;
00463     const char*                lastSpecial;
00464 
00465     int                        lastNewSpecial;
00466     w_rc_t                     rc;
00467     int                        newClen;
00468     const char*                regex = NULL;
00469     bool                       backSlash = false;
00470 
00471     DBG(<<"option_group_t::lookup_by_class " << optClassName);
00472 
00473     // regular expr is placed here, at most
00474     // it can be twice as long as optClassName
00475     int                        newC_len = strlen(optClassName)*2;
00476     char*                newC = new char[newC_len];
00477     if (!newC) return RC(fcOUTOFMEMORY);
00478     w_auto_delete_array_t<char>        newC_delete(newC);
00479 
00480     // process the option name and classification suffix
00481     // Make a regular expression for the option classification
00482     lastSpecial = optClassName-1;
00483     lastNewSpecial = 0;
00484     newC[lastNewSpecial] = '^';
00485     for (c = optClassName, newClen = 1; *c != '\0'; c++, newClen++) {
00486             if (!backSlash) {
00487                     switch (*c) {
00488                     case '*':
00489                             newC[newClen] = '.';
00490                             newClen++;
00491                             newC[newClen] = '*';
00492                             lastSpecial = c;
00493                             lastNewSpecial = newClen;
00494                             break;
00495                     case '.':
00496                             newC[newClen] = '\\';
00497                             newClen++;
00498                             newC[newClen] = '.';
00499                             lastSpecial = c;
00500                             lastNewSpecial = newClen;
00501                             break;
00502                     case '?':
00503                             newC[newClen++] = '[';
00504                             newC[newClen++] = '^';
00505                             newC[newClen++] = '.';
00506                             newC[newClen++] = ']';
00507                             newC[newClen] = '*';
00508                             lastSpecial = c;
00509                             lastNewSpecial = newClen;
00510                             break;
00511                     case ':':
00512                         // no semicolons allowed (really internal error)
00513                         rc = RC(OPT_Syntax);
00514                             break;
00515                     case ' ': case '\t':        
00516                             rc = RC(OPT_IllegalClass);
00517                             break;
00518                     case '\\':
00519                             backSlash = true;
00520                             newClen--;
00521                             break;
00522                     default:
00523                             newC[newClen] = *c;
00524                     }
00525 
00526             } else {
00527                     newC[newClen] = *c;
00528                     backSlash = false;
00529             }
00530 
00531             if (lastNewSpecial == newC_len) {
00532             rc = RC(OPT_ClassTooLong);
00533             }
00534     }
00535 
00536     if (rc.is_error()) return rc;
00537 
00538     if (*c != '\0') {
00539             return RC(OPT_Syntax);
00540     } else {
00541             newC[newClen] = *c;
00542     }
00543 
00544     //        See if class name is missing
00545     if (lastSpecial == (optClassName-1)) {
00546             return RC(OPT_IllegalClass);
00547     }
00548 
00549     newC[lastNewSpecial+1] = '$';
00550     newC[lastNewSpecial+2] = '\0';
00551 
00552     if (newC[1] == '$') {
00553             strcat(newC, ".*");
00554     }
00555 
00556     regex = re_comp(newC);
00557     if (regex != NULL) {
00558         cerr << "regular expression error: " << regex << endl;
00559         rc = RC(OPT_IllegalClass);
00560     } else {
00561             if (re_exec(_class_name) == 1) {
00562             DBG(<<"re_exec("<<_class_name<<") returned 1");
00563 
00564             // see if option name matches
00565             const char* option = lastSpecial+1;
00566             return lookup(option, exact, returnOption);
00567             } else {
00568             DBG(<<"re_exec("<<_class_name<<") failed");
00569             rc = RC(OPT_NoClassMatch);
00570         }
00571 
00572     }
00573 
00574     delete regex;
00575     returnOption = NULL;        
00576     return rc; 
00577 }
00578 
00579 w_rc_t
00580 option_group_t::set_value(
00581     const char* name, bool exact,
00582     const char* value, bool overRide,
00583     ostream* err_stream)
00584 {
00585     DBG(<<"option_group_t::set_value: " << name
00586         << " exact=" << exact);
00587     option_t* opt = 0;
00588     W_DO(lookup(name, exact, opt));
00589     if (!opt) {
00590         DBG(<<"nomatch");
00591         return RC(OPT_NoOptionMatch);
00592     }
00593     DBG(<<"MATCH");
00594     W_DO(opt->set_value(value, overRide, err_stream));
00595     return RCOK;
00596 }
00597 
00598 
00599 void
00600 option_group_t::print_usage(bool longForm, ostream& err_stream)
00601 {
00602     option_t*        current;
00603 
00604     w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00605     while (scan.next()) {
00606         current = scan.curr();
00607         if (current->is_required()) {
00608             err_stream << " ";
00609         } else {
00610             err_stream << " [";
00611         }
00612         if (current->possible_values() == NULL) {
00613             err_stream << "-" << current->name();
00614         } else {
00615             err_stream << "-" << current->name() 
00616                 << " <" << current->possible_values() << ">";
00617         }
00618 
00619         if (!current->is_required()) err_stream << "]";
00620 
00621         if (longForm) {
00622             err_stream << "\n\t\t" << current->description() << "\n";
00623             if (current->default_value() == NULL) {
00624                 err_stream << "\t\tdefault value: <none>\n";
00625             } else {
00626                 err_stream << "\t\tdefault value: " << current->default_value() << "\n";
00627             }
00628         }
00629     }
00630     if (!longForm) err_stream << endl;
00631     err_stream << "[brackets means optional]" << endl;
00632 
00633     return;
00634 }
00635 
00636 void option_group_t::print_values(bool longForm, ostream& err_stream)
00637 {
00638     option_t*        current;
00639 
00640     err_stream << "Values for options of class " << _class_name << ":";
00641     if (longForm) err_stream << "\n";
00642     w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00643     while (scan.next()) {
00644         current = scan.curr();
00645             if (current->is_set()) { // only print option which have a value set
00646             if (!current->is_required()) {
00647                 err_stream << " [-" << current->name() << " ";
00648             } else {
00649                 err_stream << " -" << current->name() << " ";
00650             }
00651             if (current->value() == NULL) {
00652                 err_stream << "<not-set>";
00653             } else {
00654                 err_stream << current->value();
00655             }
00656             if (!current->is_required()) err_stream << "]";
00657 
00658             if (longForm) err_stream << "\n";
00659             }
00660     }
00661     if (!longForm) err_stream << endl;
00662 
00663     return;
00664 }
00665 
00666 w_rc_t option_group_t::check_required(ostream* err_stream)
00667 {
00668     DBG(<<"option_group_t::check_required");
00669     w_rc_t rc;
00670     option_t* curr;
00671     bool at_least_one_not_set = false;
00672 
00673     w_list_i<option_t,unsafe_list_dummy_lock_t> scan(_options);
00674     while ((curr = scan.next())) {
00675         if (curr->is_required() && !curr->is_set()) {
00676             if (err_stream) *err_stream << "option <" << curr->name() << "> is required but not set\n"; 
00677             at_least_one_not_set = true;
00678         }
00679     }
00680     if (at_least_one_not_set) rc = RC(OPT_NotSet);
00681     return rc;
00682 }
00683 
00684 w_rc_t option_group_t::parse_command_line(const char** argv, int& argc, size_t min_len, ostream* err_stream)
00685 {
00686 
00687     /*
00688      * FUNCTION DESCRIPTION:
00689      *
00690      * This function examines command line arguments for configuration
00691      * options.  It returns argv with any sm configuration options
00692      * removed.  Argc is adjusted as well.
00693      */
00694 
00695     w_rc_t        rc;
00696     int                i;
00697     option_t*         opt;
00698 
00699     i = 0;
00700     while (i < argc && !rc.is_error()) {
00701         if (argv[i][0] == '-' && strlen(argv[i]) > min_len) {
00702             rc = lookup(argv[i]+1, false, opt);
00703             if (!rc.is_error() && opt) {
00704                 // found the option
00705                 if (i+1 == argc) {
00706 
00707                     if (err_stream) *err_stream << "missing argument for " << argv[i];
00708                     // remove this option argument
00709                     argc--;
00710                     rc = RC(OPT_BadValue);
00711                 } else {
00712                         // VCPP Wierdness if (rc = ...)
00713                     rc = opt->set_value(argv[i+1], true, err_stream);
00714                         if (rc.is_error()) {
00715                         if (err_stream) *err_stream << "bad value for argument " << argv[i];
00716                     }
00717 
00718                     // remove these option and value arguments
00719                     for (int j = i+2; j < argc; j++) {
00720                         argv[j-2] = argv[j];
00721                     }
00722                     argc -= 2;
00723                 }
00724             } else if (!rc.is_error()) {
00725                 // no real error, just not found
00726                 i++;  // advance to next argument
00727             } else {
00728                 // fall out of loop due to error
00729             }
00730         } else {
00731             i++;  // advance to next argument
00732         }
00733     }
00734     return(rc);
00735 }
00736 
00737 ///////////////////////////////////////////////////////////////////
00738 //            option_file_scan_t functions                                 //
00739 ///////////////////////////////////////////////////////////////////
00740 
00741 const char *option_stream_scan_t::default_label = "istream";
00742 
00743 option_stream_scan_t::option_stream_scan_t(istream &is, option_group_t *list)
00744 : _input(is),
00745   _optList(list),
00746   _line(0),
00747   _label(default_label),
00748   _lineNum(0)
00749 {
00750 }
00751 
00752 option_stream_scan_t::~option_stream_scan_t()
00753 {
00754         if (_line) {
00755                 delete [] _line;
00756                 _line = 0;
00757         }
00758         if (_label != default_label) {
00759                 delete [] _label;
00760                 _label = default_label;
00761         }
00762 }
00763 
00764 
00765 void option_stream_scan_t::setLabel(const char *newLabel)
00766 {
00767         if (_label != default_label) {
00768                 delete [] _label;
00769                 _label = default_label;
00770         }
00771         if (newLabel) {
00772                 // behavior in case of memory failure is fail safe
00773                 char *s = new char[strlen(newLabel) + 1];
00774                 if (s) {
00775                         strcpy(s, newLabel);
00776                         _label = s;
00777                 }
00778         }
00779 }
00780 
00781 w_rc_t option_stream_scan_t::scan(
00782         bool overRide, 
00783         ostream& err_stream, 
00784         bool exact,
00785         bool mismatch_ok
00786 )
00787 {
00788     option_t*        optInfo;
00789     int                optBegin, optEnd, valBegin, valEnd, valLength;
00790     int         i;
00791     bool        backSlash = false;
00792     const char* optionName = NULL;
00793 
00794     if (!_line) {
00795             _line = new char[_maxLineLen+1];        
00796             if (!_line)
00797                 return RC(fcOUTOFMEMORY);
00798     }
00799 
00800     DBG(<<"scanning options stream " << _label);
00801 
00802     w_rc_t rc;
00803     while ( !rc.is_error() && (_input.getline(_line, _maxLineLen) != NULL) ) {
00804             _lineNum++;
00805         DBG(<<"scan line " << _lineNum);
00806         
00807         if (strlen(_line)+1 >= _maxLineLen) {
00808             err_stream << "line " << _lineNum << " is too long";
00809             rc = RC(OPT_IllegalDescLine);
00810             break;
00811         }
00812 
00813             // 
00814             //        Find the classOption field
00815             //
00816             optBegin = -1;
00817             optEnd = -1;
00818             for (i = 0; _line[i] != '\0'; i++) {
00819             if (optBegin < 0) {
00820                     /* if whitespace */
00821                     if (isspace(_line[i])) {
00822                             continue; 
00823                     } else {
00824                             optBegin = i;
00825                     }
00826             }
00827             if (_line[i] == '\\') {
00828                 backSlash = !backSlash;
00829                 if (backSlash) continue;
00830             }
00831             if (_line[i] == ':' && !backSlash) {
00832                 optEnd = i;        
00833                 break; /* out of for loop */
00834             } 
00835             backSlash = false;
00836             }
00837 
00838             // check for a comment or blank line and skip it
00839             if (optBegin < 0 || _line[optBegin] == '#' || _line[optBegin] == '!') {
00840             continue;        
00841             }
00842 
00843             // check syntax
00844             if (optEnd < 0) {
00845                     err_stream << "syntax error at " << _label << ":" << _lineNum;
00846                     rc = RC(OPT_Syntax);
00847                     break;
00848             }
00849         _line[optEnd] = '\0';
00850 
00851         optionName = _line+optBegin;
00852 
00853             rc = _optList->lookup_by_class(optionName, optInfo, exact);
00854         if (!rc.is_error() && optInfo == NULL) {
00855             //option name was not found
00856             rc = RC(OPT_NoOptionMatch);
00857         }
00858 
00859             switch (rc.err_num()) {
00860             case 0:
00861                     break;
00862             case OPT_NoClassMatch:
00863                 // no error message needed since this is ok
00864                     break;
00865             case OPT_NoOptionMatch:
00866                 if(!mismatch_ok) {
00867                     err_stream << "unknown option at " << _label << ":" << _lineNum;
00868                 }
00869                     break;
00870             case OPT_Duplicate:
00871                     err_stream << "option name is not unique at "
00872                         << _label << ":" << _lineNum;
00873                     break;
00874             case OPT_Syntax:
00875                     err_stream << "syntax error at " << _label << ":" << _lineNum;
00876                     break;
00877             case OPT_IllegalClass:
00878                     err_stream << "illegal/missing option class at "
00879                         << _label << ":" << _lineNum;
00880                     break;
00881             default:
00882                     err_stream << "general error in option at "
00883                         << _label << ":" << _lineNum;
00884                     break;        
00885             }
00886 
00887             if (rc.is_error()) {
00888             if (rc.err_num() == OPT_NoClassMatch) {
00889                 // this is ok, we just skip the line
00890                 rc = RCOK;
00891             }
00892             if (mismatch_ok && rc.err_num() == OPT_NoOptionMatch) {
00893                 // this is ok, we just skip the line
00894                 rc = RCOK;
00895             }
00896             continue;
00897             }
00898 
00899             // 
00900             //        Find the option value field
00901             //
00902             valBegin = -1;
00903             valEnd = -1;
00904             for (i = optEnd+1; _line[i] != '\0'; i++) {
00905             /* if whitespace */
00906             if (isspace(_line[i])) {
00907                 if (valBegin < 0) {
00908                     continue; 
00909                 }        
00910             } else {
00911                 if (valBegin < 0) {
00912                     valBegin = i;
00913                 }        
00914                 valEnd = i;
00915             }
00916             }
00917 
00918             if (valBegin < 0) {
00919             err_stream << "syntax error (missing option value) at "
00920                 << _label << ":" << _lineNum;
00921             rc = RC(OPT_Syntax);
00922             break;
00923             }
00924 
00925             // remove any quote marks
00926             if (_line[valBegin] == '"') {
00927             valBegin++;
00928             if (_line[valEnd] != '"') {
00929                     err_stream << "syntax error (missing \") at "
00930                         << _label << ":" << _lineNum;
00931                 rc = RC(OPT_Syntax);
00932                 break;
00933             }
00934             valEnd--;
00935             }
00936             valLength = valEnd - valBegin + 1;
00937 
00938             if (valLength < 0) {
00939             err_stream << "syntax error (bad option value) at "
00940                 << _label << ":" << _lineNum;
00941             rc = RC(OPT_Syntax);
00942             break;
00943             }
00944 
00945             if (rc.is_error()) {
00946             continue;
00947             }
00948 
00949             // if option was found to set 
00950             if (optInfo != NULL) {
00951             _line[valEnd+1] = '\0';
00952             rc = optInfo->set_value(_line+valBegin, overRide, &err_stream);
00953             if (rc.is_error()) {
00954                 err_stream << "Option value error at "
00955                         << _label << ":" << _lineNum;
00956                 break;
00957             }
00958             }
00959     
00960     }
00961     DBG(<<"last line scanned: " << _lineNum);
00962 
00963     return rc; 
00964 }
00965 
00966 option_file_scan_t::option_file_scan_t(const char* optFile, option_group_t* list)
00967 : _fileName(optFile),
00968   _optList(list)
00969 {
00970 }
00971 
00972 option_file_scan_t::~option_file_scan_t()
00973 {
00974 }
00975 
00976 w_rc_t option_file_scan_t::scan(
00977         bool overRide, 
00978         ostream& err_stream, 
00979         bool exact,
00980         bool mismatch_ok
00981 )
00982 {
00983     w_rc_t        e;
00984 
00985     DBG(<<"scanning options file " << _fileName);
00986 
00987     ifstream f(_fileName);
00988 
00989     if (!f) {
00990         e = RC(fcOS);    
00991         DBG(<<"scan: open failure file " << _fileName);
00992         err_stream << "Could not open the option file " << _fileName;
00993         return e;
00994     }
00995     DBG(<<"scanning options file " << _fileName);
00996 
00997     option_stream_scan_t        ss(f, _optList);
00998     ss.setLabel(_fileName);
00999 
01000     return ss.scan(overRide, err_stream, exact, mismatch_ok);
01001 }
01002 

Generated on Mon Jan 2 15:13:56 2012 for Shore Storage Manager by  doxygen 1.4.7