BESKeys.cc

Go to the documentation of this file.
00001 // BESKeys.cc
00002 
00003 // This file is part of bes, A C++ back-end server implementation framework
00004 // for the OPeNDAP Data Access Protocol.
00005 
00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 // 
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 // 
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact University Corporation for Atmospheric Research at
00024 // 3080 Center Green Drive, Boulder, CO 80301
00025  
00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
00028 //
00029 // Authors:
00030 //      pwest       Patrick West <pwest@ucar.edu>
00031 //      jgarcia     Jose Garcia <jgarcia@ucar.edu>
00032 
00033 #include "config.h"
00034 
00035 #ifdef __cplusplus
00036 extern "C" {
00037 #include <sys/types.h>
00038 #include "regex.h"
00039 }
00040 #endif
00041 
00042 #include <cerrno>
00043 #include <cstring>
00044 
00045 #if HAVE_UNISTD_H
00046 #include <unistd.h>
00047 #endif
00048 
00049 #include "BESKeys.h"
00050 #include "BESUtil.h"
00051 #include "BESFSDir.h"
00052 #include "BESFSFile.h"
00053 #include "BESInternalFatalError.h"
00054 #include "BESSyntaxUserError.h"
00055 
00056 #define BES_INCLUDE_KEY "BES.Include"
00057 
00074 BESKeys::BESKeys( const string &keys_file_name )
00075     : _keys_file( 0 ),
00076       _keys_file_name( keys_file_name ),
00077       _the_keys( 0 ),
00078       _own_keys( true )
00079 {
00080     _the_keys = new map<string,vector<string> >;
00081     initialize_keys( ) ;
00082 }
00083 
00084 BESKeys::BESKeys( const string &keys_file_name, map<string,vector<string> > *keys)
00085     : _keys_file( 0 ),
00086       _keys_file_name( keys_file_name ),
00087       _the_keys( keys ),
00088       _own_keys( false )
00089 {
00090     initialize_keys( ) ;
00091 }
00092 
00095 BESKeys::~BESKeys()
00096 {
00097     clean() ;
00098 }
00099 
00100 void
00101 BESKeys::initialize_keys( )
00102 {
00103     _keys_file = new ifstream( _keys_file_name.c_str() ) ;
00104     int myerrno = errno ;
00105     if( !(*_keys_file) )
00106     {
00107         char path[500] ;
00108         getcwd( path, sizeof( path ) ) ;
00109         string s = string("BES: fatal, cannot open BES configuration file ")
00110                    + _keys_file_name + ": " ;
00111         char *err = strerror( myerrno ) ;
00112         if( err )
00113             s += err ;
00114         else
00115             s += "Unknown error" ;
00116 
00117         s += (string)".\n" + "The current working directory is " + path + "\n" ;
00118         throw BESInternalFatalError( s, __FILE__, __LINE__ ) ;
00119     }
00120 
00121     try
00122     {
00123         load_keys() ;
00124     }
00125     catch( BESError &e )
00126     {
00127         // be sure we're throwing a fatal error, since the BES can't run
00128         // within the configuration file
00129         clean() ;
00130         throw BESInternalFatalError( e.get_message(),
00131                                      e.get_file(), e.get_line() ) ;
00132     }
00133     catch(...)
00134     {
00135         clean() ;
00136         string s = (string)"Undefined exception while trying to load keys "
00137                    + "from bes configuration file " + _keys_file_name ;
00138         throw BESInternalFatalError( s, __FILE__, __LINE__ ) ;
00139     }
00140 }
00141 
00142 void
00143 BESKeys::clean()
00144 {
00145     if( _keys_file )
00146     {
00147         _keys_file->close() ;
00148         delete _keys_file ;
00149     }
00150     if( _the_keys && _own_keys )
00151     {
00152         delete _the_keys ;
00153     }
00154 }
00155 
00156 void
00157 BESKeys::load_keys()
00158 {
00159     char buffer[255];
00160     string key,value;
00161     while(!(*_keys_file).eof())
00162     {
00163         if((*_keys_file).getline(buffer,255))
00164         {
00165             bool addto = false ;
00166             if( break_pair( buffer, key, value, addto ) )
00167             {
00168                 if( key == BES_INCLUDE_KEY )
00169                 {
00170                     load_include_files( value ) ;
00171                 }
00172                 else
00173                 {
00174                     map<string,vector<string> >::iterator i ;
00175                     i = _the_keys->find( key ) ;
00176                     if( i == _the_keys->end() )
00177                     {
00178                         vector<string> vals ;
00179                         (*_the_keys)[key] = vals ;
00180                     }
00181                     if( !value.empty() )
00182                     {
00183                         (*_the_keys)[key].push_back( value ) ;
00184                     }
00185                 }
00186             }
00187         }
00188     }
00189 }
00190 
00191 // The string contained in the character buffer b should be of the
00192 // format key=value or key+=value. The pair is broken apart, storing the
00193 // key in the key parameter and the value of the key in the value
00194 // parameter. If += is used, then the value should be added to the value
00195 // of key, not replacing.
00196 //
00197 // It used to be that we would validate the key=value line. Instead,
00198 // anything after the equal sign is considered the value of the key.
00199 inline bool
00200 BESKeys::break_pair( const char* b, string& key, string &value, bool &addto )
00201 {
00202     addto = false ;
00203     // Ignore comments and lines with only spaces
00204     if( b && ( b[0] != '#' ) && ( !only_blanks( b ) ) )
00205     {
00206         register size_t l = strlen( b ) ;
00207         if( l > 1 )
00208         {
00209             int pos = 0 ;
00210             bool done = false ;
00211             for( register size_t j = 0; j < l && !done ; j++ )
00212             {
00213                 if( b[j] == '=' )
00214                 {
00215                     if( !addto ) pos = j ;
00216                     else
00217                     {
00218                         if( pos != j-1 )
00219                         {
00220                             string s = string("BES: Invalid entry ") + b
00221                                        + " in configuration file "
00222                                        + _keys_file_name
00223                                        + " '+' character found in variable name"
00224                                        + " or attempting '+=' with space"
00225                                        + " between the characters.\n" ;
00226                             throw BESInternalFatalError( s, __FILE__, __LINE__);
00227                         }
00228                     }
00229                     done = true ;
00230                 }
00231                 else if( b[j] == '+' )
00232                 {
00233                     addto = true ;
00234                     pos = j ;
00235                 }
00236             }
00237             if( !done )
00238             {
00239                 string s = string("BES: Invalid entry ") + b
00240                            + " in configuration file "
00241                            + _keys_file_name + ": "
00242                            + " '=' character not found.\n" ;
00243                 throw BESInternalFatalError( s, __FILE__, __LINE__);
00244             }
00245 
00246             string s = b ;
00247             key = s.substr( 0, pos ) ;
00248             BESUtil::removeLeadingAndTrailingBlanks( key ) ;
00249             if( addto ) value = s.substr( pos+2, s.size() ) ;
00250             else value = s.substr( pos+1, s.size() ) ;
00251             BESUtil::removeLeadingAndTrailingBlanks( value ) ;
00252 
00253             return true;
00254         }
00255 
00256         return false;
00257     }
00258 
00259     return false;
00260 }
00261 
00271 void
00272 BESKeys::load_include_files( const string &files )
00273 {
00274     string newdir ;
00275     BESFSFile allfiles( files ) ;
00276 
00277     // If the files specified begin with a /, then use that directory
00278     // instead of the current keys file directory.
00279     if( !files.empty() && files[0] == '/' )
00280     {
00281         newdir = allfiles.getDirName() ;
00282     }
00283     else
00284     {
00285         // determine the directory of the current keys file. All included
00286         // files will be relative to this file.
00287         BESFSFile currfile( _keys_file_name ) ;
00288         string currdir = currfile.getDirName() ;
00289 
00290         string alldir = allfiles.getDirName() ;
00291 
00292         if( ( currdir == "./" || currdir == "." )
00293             && ( alldir == "./" || alldir == "." ) ) newdir = "./" ;
00294         else newdir = currdir + "/" + alldir ;
00295     }
00296 
00297     // load the files one at a time. If the directory doesn't exist,
00298     // then don't load any configuration files
00299     BESFSDir fsd( newdir, allfiles.getFileName() ) ;
00300     BESFSDir::fileIterator i = fsd.beginOfFileList() ;
00301     BESFSDir::fileIterator e = fsd.endOfFileList() ;
00302     for( ; i != e; i++ )
00303     {
00304         load_include_file( (*i).getFullPath() ) ;
00305     }
00306 }
00307 
00314 void
00315 BESKeys::load_include_file( const string &file )
00316 {
00317     // make sure the file exists and is readable
00318     // throws exception if unable to read
00319     BESKeys tmp( file, _the_keys ) ;
00320 }
00321 
00322 bool
00323 BESKeys::only_blanks(const char *line)
00324 {
00325     int val;
00326     regex_t rx;
00327     string expr = "[^[:space:]]" ;
00328     val = regcomp( &rx, expr.c_str(), REG_ICASE ) ;
00329 
00330     if( val != 0 )
00331     {
00332         string s = (string)"Regular expression " + expr
00333                    + " did not compile correctly "
00334                    + " in configuration file " + _keys_file_name ;
00335         throw BESInternalFatalError( s, __FILE__, __LINE__ ) ;
00336     }
00337     val = regexec( &rx, line, 0, 0, REG_NOTBOL ) ;
00338     if( val == 0 )
00339     {
00340         regfree( &rx ) ;
00341         return false ;
00342     }
00343     else
00344     {
00345         if( val == REG_NOMATCH )
00346         {
00347             regfree( &rx ) ;
00348             return true ;
00349         }
00350         else if( val == REG_ESPACE )
00351         {
00352             string s = (string)"Execution of regular expression out of space"
00353                        + " in configuration file " + _keys_file_name ;
00354             throw BESInternalFatalError( s, __FILE__, __LINE__ ) ;
00355         }
00356         else
00357         {
00358             string s = (string)"Execution of regular expression has unknown "
00359                        + " problem in configuration file " + _keys_file_name ;
00360             throw BESInternalFatalError( s, __FILE__, __LINE__ ) ;
00361         }
00362     }
00363 }
00364 
00381 void
00382 BESKeys::set_key( const string &key, const string &val, bool addto )
00383 {
00384     map<string,vector<string> >::iterator i ;
00385     i = _the_keys->find( key ) ;
00386     if( i == _the_keys->end() )
00387     {
00388         vector<string> vals ;
00389         (*_the_keys)[key] = vals ;
00390     }
00391     if( !addto ) (*_the_keys)[key].clear() ;
00392     if( !val.empty() )
00393     {
00394         (*_the_keys)[key].push_back( val ) ;
00395     }
00396 }
00397 
00409 void
00410 BESKeys::set_key( const string &pair )
00411 {
00412     string key ;
00413     string val ;
00414     bool addto = false ;
00415     break_pair( pair.c_str(), key, val, addto ) ;
00416     set_key( key, val, addto ) ;
00417 }
00418 
00433 void
00434 BESKeys::get_value( const string& s, string &val, bool &found ) 
00435 {
00436     found = false ;
00437     map<string,vector<string> >::iterator i ;
00438     i = _the_keys->find( s ) ;
00439     if( i != _the_keys->end() )
00440     {
00441         found = true ;
00442         if( (*i).second.size() > 1 )
00443         {
00444             string err = string("Multiple values for the key ") + s
00445                          + " found, should only be one." ;
00446             throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00447         }
00448         if( (*i).second.size() == 1 )
00449         {
00450             val = (*i).second[0] ;
00451         }
00452         else
00453         {
00454             val = "" ;
00455         }
00456     }
00457 }
00458 
00470 void
00471 BESKeys::get_values( const string& s, vector<string> &vals, bool &found ) 
00472 {
00473     found = false ;
00474     map<string,vector<string> >::iterator i ;
00475     i = _the_keys->find( s ) ;
00476     if( i != _the_keys->end() )
00477     {
00478         found = true ;
00479         vals = (*i).second ;
00480     }
00481 }
00482 
00489 void
00490 BESKeys::dump( ostream &strm ) const
00491 {
00492     strm << BESIndent::LMarg << "BESKeys::dump - ("
00493                              << (void *)this << ")" << endl ;
00494     BESIndent::Indent() ;
00495     strm << BESIndent::LMarg << "key file:" << _keys_file_name << endl ;
00496     if( _keys_file && *_keys_file )
00497     {
00498         strm << BESIndent::LMarg << "key file is valid" << endl ;
00499     }
00500     else
00501     {
00502         strm << BESIndent::LMarg << "key file is NOT valid" << endl ;
00503     }
00504     if( _the_keys && _the_keys->size() )
00505     {
00506         strm << BESIndent::LMarg << "    keys:" << endl ;
00507         BESIndent::Indent() ;
00508         Keys_citer i = _the_keys->begin() ;
00509         Keys_citer ie = _the_keys->end() ;
00510         for( ; i != ie; i++ )
00511         {
00512             strm << BESIndent::LMarg << (*i).first << ":" << endl ;
00513             BESIndent::Indent() ;
00514             vector<string>::const_iterator v = (*i).second.begin() ;
00515             vector<string>::const_iterator ve = (*i).second.end() ;
00516             for( ; v != ve; v++ )
00517             {
00518                 strm << (*v) << endl ;
00519             }
00520             BESIndent::UnIndent() ;
00521         }
00522         BESIndent::UnIndent() ;
00523     }
00524     else
00525     {
00526         strm << BESIndent::LMarg << "keys: none" << endl ;
00527     }
00528     BESIndent::UnIndent() ;
00529 }
00530 

Generated on Thu Feb 11 09:13:14 2010 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.4.7