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

Generated on Wed Jul 7 17:22:32 2010 for Shore Storage Manager by  doxygen 1.4.7