ParFile.cc

00001 // --8<--8<--8<--8<--
00002 //
00003 // Copyright (C) 2006 Smithsonian Astrophysical Observatory
00004 //
00005 // This file is part of paramxx
00006 //
00007 // paramxx is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2
00010 // of the License, or (at your option) any later version.
00011 //
00012 // paramxx is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with this program; if not, write to the 
00019 //       Free Software Foundation, Inc. 
00020 //       51 Franklin Street, Fifth Floor
00021 //       Boston, MA  02110-1301, USA
00022 //
00023 // -->8-->8-->8-->8--
00024 
00025 #include <errno.h>
00026 #include <stdlib.h>
00027 #include <string>
00028 #include <fstream>
00029 
00030 #include <getline/getline.h>
00031 #include <suplib/str.h>
00032 #include <suplibxx/io.h>
00033 
00034 #include "ParFile.h"
00035 #include "ParTxt.h"
00036 #include "NameAttributeValue.h"
00037 #include "BoolPar.h"
00038 #include "CommentPar.h"
00039 #include "LongPar.h"
00040 #include "RealPar.h"
00041 #include "StringPar.h"
00042 
00043 using namespace std;
00044 
00045 #define  MODE "mode"
00046 
00047 ParFile::~ParFile( ) {
00048   if ( parameters ) {
00049     size_t count = 0;
00050     while( parameters[ count ] ) {
00051       delete parameters[ count ];
00052       ++count;
00053     }
00054     delete [] parameters;
00055     parameters = NULL;
00056   }
00057 }
00058 
00059 ParFile::ParFile( int argc, char** argv, const char* file )
00060   throw ( ParFileException, Exception ) : parameters( NULL ) {
00061 
00062     try {
00063 
00064       init_ParFile( argc, argv, file );
00065 
00066     } catch( ParFileException& pfe ) {
00067       throw;
00068     }
00069 
00070 }
00071 
00072 void ParFile::pget( const char* name, bool& result ) const
00073   throw ( ParFileException ) {
00074 
00075     try {
00076       result = pgetb( name );
00077     } catch ( ParFileException& pfe ) {
00078       throw;
00079     }
00080 
00081 }
00082 
00083 void ParFile::pget( const char* name, double& result ) const
00084   throw ( ParFileException ) {
00085 
00086     try {
00087       result = pgetd( name );
00088     } catch ( ParFileException& pfe ) {
00089       throw;
00090     }
00091 
00092 }
00093 
00094 void ParFile::pget( const char* name, int& result ) const
00095   throw ( ParFileException ) {
00096 
00097     try {
00098       result = pgeti( name );
00099     } catch ( ParFileException& pfe ) {
00100       throw;
00101     }
00102 
00103 }
00104 
00105 void ParFile::pget( const char* name, long& result ) const
00106   throw ( ParFileException ) {
00107 
00108     try {
00109       result = pgetl( name );
00110     } catch ( ParFileException& pfe ) {
00111       throw;
00112     }
00113 
00114 }
00115 
00116 void ParFile::pget( const char* name, char result[], size_t size ) const
00117   throw ( ParFileException ) {
00118 
00119     try {
00120       pgetstr( name, result, size );
00121     } catch ( ParFileException& pfe ) {
00122       throw;
00123     }
00124     
00125 }
00126 
00127 void ParFile::pget( const char* name, string& result ) const
00128   throw ( ParFileException ) {
00129 
00130     try {
00131       result = pgetstring( name );
00132     } catch ( ParFileException& pfe ) {
00133       throw;
00134     }
00135     
00136 }
00137 
00138 bool ParFile::pgetb( const char* name ) const throw ( ParFileException ) {
00139 
00140   try {
00141     Par* par = get_par( name );
00142     return par->pgetb( );
00143   } catch ( ParFileException& pfe ) {
00144     throw;
00145   }
00146 
00147 }
00148 
00149 double ParFile::pgetd( const char* name ) const throw ( ParFileException ) {
00150 
00151   try {
00152     Par* par = get_par( name );
00153     return par->pgetd( );
00154   } catch ( ParFileException& pfe ) {
00155     throw;
00156   }
00157 
00158 }
00159 
00160 int ParFile::pgeti( const char* name ) const throw ( ParFileException ) {
00161 
00162   try {
00163     Par* par = get_par( name );
00164     return par->pgeti( );
00165   } catch ( ParFileException& pfe ) {
00166     throw;
00167   }
00168 
00169 }
00170 
00171 long ParFile::pgetl( const char* name ) const throw ( ParFileException ) {
00172 
00173   try {
00174     Par* par = get_par( name );
00175     return par->pgetl( );
00176   } catch ( ParFileException& pfe ) {
00177     throw;
00178   }
00179 
00180 }
00181 
00182 void ParFile::pgetstr( const char* name, char result[], size_t size ) const
00183   throw ( ParFileException ) {
00184 
00185     try {
00186       Par* par = get_par( name );
00187       string str = par->pgetstring( );
00188       strncpy( result, str.c_str( ), size );
00189       result[ size - 1 ] = '\0';
00190       return;
00191     } catch ( ParFileException& pfe ) {
00192       throw;
00193     }
00194 
00195 }
00196 
00197 string ParFile::pgetstring( const char* name ) const
00198   throw ( ParFileException ) {
00199 
00200     try {
00201       Par* par = get_par( name );
00202       return par->pgetstring( );
00203     } catch ( ParFileException& pfe ) {
00204       throw;
00205     }
00206 
00207 }
00208 
00209 // check to see the parameter mode of the file.
00210 // The value of the parameter `mode' is the mode of the parameter file.
00211 // If it is batch mode, then die on error, i.e. never ask any questions
00212 // else querry the user till the right answer is enterred
00213 void ParFile::get_mode_of_parameter_file( int argc, char** argv ) 
00214   throw ( ParFileException ) {
00215 
00216     try {
00217 
00218       // just in case the parameter MODE is not present in the parameter file.
00219       Par* par = search_name( MODE );
00220 
00221     } catch( ParFileException& pfe ) {
00222 
00223       return;
00224 
00225     }
00226 
00227     try {
00228 
00229       Par* par = search_name( MODE );
00230 
00231       // User did supplied a mode parameter in the parameter file.  Find out 
00232       // what it is then decide whether the program is to return or querry.
00233       set_return_on_error( par->get_mode( ) );
00234 
00235       // check if the user has entered the mode option at the command line
00236       for ( int i = 1; i < argc; i++ ) {
00237 
00238         NameAttributeValue cmdline_mode( argv[ i ] );
00239 
00240         if ( cmdline_mode.get_name( ) == MODE )
00241           set_return_on_error( cmdline_mode.get_value( ) );
00242 
00243       }
00244 
00245     } catch( ParFileException& pfe ) {
00246 
00247       throw;
00248 
00249     }
00250 
00251   return;
00252 
00253 }
00254 
00255 Par* ParFile::get_par( const char* str ) const throw ( ParFileException ) {
00256 
00257   try {
00258 
00259     const char* original_name = str;
00260 
00261     // indirrection level cannot exceed the
00262     // number of parameters within the file
00263     size_t max_count = 0;
00264     while( parameters[ max_count ] )
00265       ++max_count;
00266 
00267     for ( size_t ii = 0; ii < max_count; ii++ ) {
00268 
00269       Par* par = search_name( str );
00270 
00271       string new_value = par->get_value( );
00272 
00273       if ( Par::is_indirrect( new_value ) ) {
00274         str = new_value.c_str( );
00275         ++str;
00276       } else
00277         return par;
00278 
00279     }
00280 
00281     // Have infinite loop
00282     const char* format =
00283       "ParFile::get_par( %s ) : Encountered an infinite loop\n";
00284     char tmp[ 256 ];
00285     sprintf( tmp, format, original_name );
00286     throw ParFileException( tmp );
00287 
00288   } catch ( ParFileException& pfe ) {
00289     throw;
00290   }
00291 
00292 }
00293 
00294 void ParFile::init_ParFile( int argc, char** argv, const char* file )
00295   throw ( ParFileException, Exception ) {
00296 
00297     try {
00298 
00299       // Set the default to return as though one is in a batch mode.
00300       return_on_error = true;
00301 
00302       read_ParFile( argc, argv, file );
00303 
00304       // All the parameters have been read.  Check to see what the mode of the
00305       // parameter file is.  From  this value, see if the program is to return
00306       // to user or querry the user untill a legitimate input is entered.
00307       get_mode_of_parameter_file( argc, argv );
00308 
00309       is_duplicate_cmdline_args( argc, argv );
00310 
00311       for ( int ii = 1; ii < argc; ii++ )
00312         setpar( argv[ ii ] );
00313 
00314     } catch( ParFileException& pfe ) {
00315 
00316       throw;
00317 
00318     } catch( Exception& e ) {
00319 
00320       throw;
00321 
00322     }
00323 
00324 }
00325 
00326 bool ParFile::is_parlist( string& cmdline_name, string& cmdline_value ) {
00327 
00328   if ( parameters ) {
00329     for ( size_t count = 0; NULL != parameters[ count ]; count++ )
00330       if ( parameters[ count ]->get_name( ) == cmdline_name )
00331         return false;
00332   }
00333 
00334   if ( 0 == cmdline_value.compare( "" ) )
00335     return true;
00336   else
00337     return false;
00338 
00339 }
00340 
00341 bool ParFile::is_duplicate_cmdline_args( int argc, char** argv )
00342   throw( ParFileException ) {
00343 
00344     vector< string > cmdline_options;
00345 
00346     // Store the names of command line arguments in the map
00347     for ( int i = 1; i < argc; i++ ) {
00348 
00349       NameAttributeValue arg( argv[ i ] );
00350       string name = arg.get_name( );
00351     
00352       vector< string >::const_iterator iter_begin = cmdline_options.begin( );
00353       vector< string >::const_iterator iter_end = cmdline_options.end( );
00354       for ( vector< string >::const_iterator iter = iter_begin;
00355             iter != iter_end; iter++ )
00356         if ( *iter == name ) {
00357           string msg( "ParFile::is_duplicate_cmdline_args( ) : Duplicate " );
00358           msg += name;
00359           throw ParFileException( msg );
00360         }
00361 
00362     }
00363 
00364     return false;
00365     
00366 }
00367 
00368 void ParFile::print( ostream& os ) const {
00369  
00370   if ( parameters ) {
00371     size_t count = 0;
00372     while( parameters[ count ] ) {
00373       parameters[ count ]->print( os );
00374       if ( parameters[ ++count ] )
00375         os << '\n';
00376     }
00377   }
00378   
00379 }
00380 
00381 void ParFile::querry_user( Par* item, char* str ) {
00382 
00383   if ( return_on_error )
00384     return;
00385 
00386   const char* format = "%s (%s) : ";
00387   
00388   string prompt = item->get_prompt();
00389 
00390   // Put in the initial value so the user can recall it if s/he wishes
00391   gl_histadd( str );
00392 
00393   do {
00394 
00395     size_t length =
00396       strlen( format ) + prompt.size( ) + strlen( str ) + 10;
00397     char* ptr = new char[ length ];
00398 
00399     sprintf( ptr, format, prompt.c_str( ), str );
00400 
00401     str = gl_getline( ptr );
00402     gl_histadd( str );
00403     delete [] ptr;
00404     ptr = NULL;
00405 
00406     if ( ! is_comment( str ) )
00407       str_prune( str );
00408 
00409   } while( EXIT_FAILURE == item->check_value( str ) );
00410 
00411   item->set_val( str );
00412 
00413   return;
00414 
00415 }
00416 
00417 void ParFile::set_return_on_error( const string& mode_of_parfile ) {
00418 
00419   if ( string::npos == mode_of_parfile.find( "b" ) )
00420     // user wants to be querried for the correct input
00421     return_on_error = false;
00422   else
00423     // The calling program is in a batch mode.  Do not querry for answer.
00424     return_on_error = true;
00425 
00426 }
00427 
00428 static char mytmp[ 512 ];
00429 
00430 void ParFile::read_ParFile( int argc, char** argv, const char* file )
00431   throw ( ParFileException ) {
00432 
00433     try {
00434 
00435       parFilename.init_ParFilename( argc, argv, file );
00436       string fname( parFilename.get_filename( ) );
00437 
00438       ifstream input( fname.c_str( ), ios::in );
00439       if ( ! input ) {
00440         string msg( "ParFile::read_Parfile( ) : Unable to open file '" +
00441                     fname +"'\n" );
00442         throw ParFileException( msg );
00443       }
00444 
00445       parameters = new Par* [ 512 ];
00446       size_t count = 0;
00447 
00448       string mytxt;
00449       while( suplib::getrecord( input, mytxt, suplib::READ_LOGICAL |
00450                                 suplib::STRIP | suplib::CLEAN ) ) {
00451 
00452         ParTxt parTxt( (char*) mytxt.c_str( ) );
00453         char** buffer_argv = (char**) parTxt;
00454 
00455         if ( NULL == buffer_argv ) {
00456 
00457           parameters[ count ] = new CommentPar( parTxt );
00458 
00459         } else if ( Par::BOOLEAN == buffer_argv[ Par::PARTYPE ][ 0 ] ) {
00460 
00461           parameters[ count ] = new BoolPar( parTxt );
00462 
00463         } else if ( Par::INTEGER == buffer_argv[ Par::PARTYPE ][ 0 ] ) {
00464 
00465           parameters[ count ] = new LongPar( parTxt );
00466 
00467         } else if ( Par::REAL == buffer_argv[ Par::PARTYPE ][ 0 ] ) {
00468 
00469           parameters[ count ] = new RealPar( parTxt );
00470 
00471         } else if ( Par::STRING == buffer_argv[ Par::PARTYPE ][ 0 ] ) {
00472 
00473           parameters[ count ] = new StringPar( parTxt );
00474 
00475         }
00476 
00477         count++;
00478 
00479         // delete [] txt;
00480 
00481       }
00482 
00483       parameters[ count ] = NULL;
00484 
00485     } catch( ParFileException& pfe ) {
00486       throw;
00487     }
00488 
00489 }
00490 
00491 Par* ParFile::search_name( const char* str ) const
00492   throw ( ParFileException ) {
00493 
00494     if ( parameters ) {
00495       for ( size_t count = 0; NULL != parameters[ count ]; count++ )
00496         if ( parameters[ count ]->get_name( ) == str )
00497           return parameters[ count ];
00498     }
00499     
00500     string msg( "ParFile::search_name( " );
00501     msg.append( str );
00502     msg.append( " ) : Unable to find the parameter\n" );
00503   
00504     throw ParFileException( msg );
00505   
00506 }
00507 
00508 
00509 void ParFile::setpar( char* str ) throw ( ParFileException, Exception ) {
00510 
00511   try {
00512 
00513     NameAttributeValue cmdline( str );
00514 
00515     string cmdline_name( cmdline.get_name( ) );
00516 
00517     // If the user has entered PFILE=foo.par at the command line then the 
00518     // file `foo.par' is to be used as the parameter file, if it exists.
00519     // Hence do not set the parameter to anything.  Simply return.
00520     if ( cmdline_name == PFILE )
00521       return;
00522 
00523     string cmdline_value( cmdline.get_value( ) );
00524 
00525     /*
00526     cout << "ParFile::setpar( " << str << " ) : "
00527          << "name = `" << cmdline.get_name( ) << '\t';
00528     cout << "value = `" << cmdline.get_value( ) << "'\n";
00529     */
00530 
00531     // parlist foo.par
00532     if ( is_parlist( cmdline_name, cmdline_value ) )
00533       return;
00534 
00535     Par* par = search_name( cmdline_name.c_str( ) );
00536 
00537     if ( return_on_error )
00538       // In batch mode, ie the parameter mode contains a b
00539       par->set_val( cmdline_value.c_str( ) );
00540     else {
00541       // User has requested to be querried, ie the parameter mode contains a q
00542       if ( EXIT_FAILURE == par->check_value( cmdline_value.c_str( ) ) ) {
00543         querry_user( par, (char*) cmdline_value.c_str( ) );
00544       } else {
00545         par->set_val( cmdline_value.c_str( ) );
00546       }
00547     }
00548 
00549   } catch( ParFileException& pfe ) {
00550 
00551     throw;
00552 
00553   } catch( Exception& e ) {
00554 
00555     throw;
00556 
00557   }
00558 
00559 }
00560 
00561 int ParFile::traverse( int (*fct)( Par* ) ) const {
00562 
00563   if ( parameters ) {
00564     size_t count = 0;
00565     while( parameters[ count ] ) {
00566       int status = (*fct)( parameters[ count++ ] );
00567       if ( 0 != status )
00568         return status;
00569     }
00570   }
00571 
00572   return 0;
00573 
00574 }
00575 
00576 int ParFile::is_blank( const char *str ) {
00577 
00578   while( isspace( *str++ ) )
00579     ;
00580 
00581   return ! (*--str);
00582 
00583 }
00584 
00585 int ParFile::is_comment( const char* str, char delimit ) {
00586 
00587   // move to first non-space character
00588   while ( isspace( *str ) )
00589     str++;
00590 
00595   return str[0] == delimit || ParFile::is_blank( str );
00596 
00597 }
00598 
00599 #undef MODE

Generated on Thu Oct 2 17:54:19 2008 for paramxx by  doxygen 1.5.6