diff --git a/Code/Common/CMakeLists.txt b/Code/Common/CMakeLists.txt index 93caf8251173bee7c2c20afc0af49284e6bb2144..a7f6ca89846849d5e8a5d004feef5b3aa6438581 100644 --- a/Code/Common/CMakeLists.txt +++ b/Code/Common/CMakeLists.txt @@ -12,7 +12,7 @@ ENDIF( NOT OTB_USE_PQXX ) ADD_LIBRARY(OTBCommon ${OTBCommon_SRCS}) -TARGET_LINK_LIBRARIES (OTBCommon ITKAlgorithms ITKStatistics ITKCommon) +TARGET_LINK_LIBRARIES (OTBCommon ITKAlgorithms ITKStatistics ITKCommon otbConfigFile) IF (OTB_USE_MAPNIK) TARGET_LINK_LIBRARIES(OTBCommon ${MAPNIK_LIBRARY}) ENDIF(OTB_USE_MAPNIK) diff --git a/Code/Common/otbConfiguration.h b/Code/Common/otbConfiguration.h new file mode 100644 index 0000000000000000000000000000000000000000..6a305502f7bd86194b3c16850c0dd049be9d7298 --- /dev/null +++ b/Code/Common/otbConfiguration.h @@ -0,0 +1,98 @@ +/*========================================================================= + +Program: ORFEO Toolbox +Language: C++ +Date: $Date$ +Version: $Revision$ + + +Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. +See OTBCopyright.txt for details. + + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __otbConfiguration_h +#define __otbConfiguration_h + +#include "itkObject.h" +#include "itkObjectFactory.h" +#include "/home/christop/manuel/Cnes/otb/Dev/OTB/Utilities/otbconfigfile/ConfigFile.h" + +namespace otb +{ + +/** \class Configuration + * \brief Manage OTB configuration file +*/ + + class Configuration + : public itk::Object + { + public: + /** Standard class typedef */ + + typedef Configuration Self; + typedef itk::Object Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Standard macro */ + itkNewMacro(Self); + itkTypeMacro(Configuration,Object); + + + /** Get arg */ +// itkGetStringMacro(Language); +// itkGetStringMacro(GeodidePath); +// itkGetStringMacro(WorldShapePath); +// itkGetStringMacro(SRTMPath); +// itkGetStringMacro(NodeId); +// itkGetStringMacro(NodeId); +// itkGetStringMacro(NodeId); + /** Load parameters from the configuration file*/ +// void Load() { +// +// } + ConfigFile * GetOTBConfig() + { + return m_OTBConfig; + }; + + std::string GetLanguage() + { + return m_OTBConfig->read<std::string>( "LANG" ); + }; + protected: + /** Constructor */ + Configuration() + { + m_OTBConfig = new ConfigFile("/home/christop/example.inp"); +// ConfigFile config( "/home/christop/example.inp" ); +// m_Language = config.read<std::string>( "LANG" ); +// m_GeodidePath = config.read<std::string>( "GEOIDE" ); +// m_WorldShapePath = config.read<std::string>( "WORLD" ); +// m_SRTMPath = config.read<std::string>( "SRTM" ); + }; + /** Destructor */ + ~Configuration() {}; + /** PrintSelf method */ + void PrintSelf(std::ostream& os, itk::Indent indent) const + { + Superclass::PrintSelf(os, indent); + }; + private: +// ConfigFile * m_ConfigFile; +// std::string m_Language; +// std::string m_GeodidePath; +// std::string m_WorldShapePath; +// std::string m_SRTMPath; +// unsigned int m_TileSizeX; +// unsigned int m_TileSizeY; + ConfigFile * m_OTBConfig; +}; +}// end namespace +#endif diff --git a/Testing/Code/Common/CMakeLists.txt b/Testing/Code/Common/CMakeLists.txt old mode 100755 new mode 100644 index 97b8c5b911f4258960cfd08d50e28c1f351bc455..71f9fc5253a4abf77e474397ea97fd5b1246d5ea --- a/Testing/Code/Common/CMakeLists.txt +++ b/Testing/Code/Common/CMakeLists.txt @@ -44,6 +44,11 @@ ADD_TEST(coTuSystemTests_IsA_Methods ${COMMON_TESTS1} ${OTB_DATA_ROOT} ) +# ------- otb::Configuration ------------- +ADD_TEST(coTuConfiguration ${COMMON_TESTS1} + otbConfiguration + ) + # ------- otb::CommandLibneArgumentParser ------------- ADD_TEST(coTuCmdLineArgParserHelpWithArg ${COMMON_TESTS1} @@ -944,6 +949,7 @@ otbVectorDataToLabelMapFilter SET(BasicCommon_SRCS1 otbCommonTests1.cxx otbSystemTest.cxx +otbConfiguration.cxx otbTestCommandLineArgumentParser.cxx #otbTestCommandLineArgumentParserGUI.cxx otbTestCommandLineArgumentParserHelp.cxx diff --git a/Testing/Code/Common/otbCommonTests1.cxx b/Testing/Code/Common/otbCommonTests1.cxx index 0b64f0f7b1ebe68c886ece91ef77a5be06f6dbca..cfc3a32c71b647179a9e3f5588fe0457b3808d87 100644 --- a/Testing/Code/Common/otbCommonTests1.cxx +++ b/Testing/Code/Common/otbCommonTests1.cxx @@ -27,6 +27,7 @@ void RegisterTests() { REGISTER_TEST(otbSystemTest); + REGISTER_TEST(otbConfiguration); REGISTER_TEST(otbTestCommandLineArgumentParser); //REGISTER_TEST(otbTestCommandLineArgumentParserGUI); REGISTER_TEST(otbTestCommandLineArgumentParserHelp); diff --git a/Testing/Code/Common/otbConfiguration.cxx b/Testing/Code/Common/otbConfiguration.cxx new file mode 100644 index 0000000000000000000000000000000000000000..19872c4c0797e566f8b52ee23316a720e0a2b914 --- /dev/null +++ b/Testing/Code/Common/otbConfiguration.cxx @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt for details. + + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "itkExceptionObject.h" +#include "otbMacro.h" +#include <fstream> +#include "otbConfiguration.h" + +int otbConfiguration(int argc, char * argv[]) +{ + + typedef otb::Configuration ConfigurationType; + + //Instantiation + ConfigurationType::Pointer conf = ConfigurationType::New(); + +// conf->Load(); + + std::string lang = conf->GetLanguage(); + + if (lang != "fr") + return EXIT_FAILURE; + + std::cout << "config language " << lang << std::endl; + + return EXIT_SUCCESS; +} diff --git a/Utilities/CMakeLists.txt b/Utilities/CMakeLists.txt index 0cdc7fa58164026bafdd822144854733a4370d0e..16e83a1cf91e48bb696504ef624590cfe8a3a327 100644 --- a/Utilities/CMakeLists.txt +++ b/Utilities/CMakeLists.txt @@ -33,7 +33,7 @@ IF(NOT OTB_USE_EXTERNAL_BOOST) SUBDIRS(BGL) ENDIF(NOT OTB_USE_EXTERNAL_BOOST) -SUBDIRS(otbsvm dxflib InsightJournal otbossim otbossimplugins otb6S tinyXMLlib otbkml otbedison otbsiftfast) +SUBDIRS(otbsvm dxflib InsightJournal otbossim otbossimplugins otb6S tinyXMLlib otbkml otbedison otbsiftfast otbconfigfile) IF(BUILD_TESTING) SUBDIRS( Dart ) diff --git a/Utilities/otbconfigfile/CMakeLists.txt b/Utilities/otbconfigfile/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d8496a9d39e9aec5398a3b49adec2fd8cc3a3db4 --- /dev/null +++ b/Utilities/otbconfigfile/CMakeLists.txt @@ -0,0 +1,24 @@ +PROJECT(otbConfigFilelib) + +FILE(GLOB otbConfigFilelib_SRCS "*.cpp") +FILE(GLOB otbConfigFilelib_HDRS "*.h") +ADD_LIBRARY(otbConfigFile ${otbConfigFilelib_SRCS}) +TARGET_LINK_LIBRARIES(otbConfigFile) +IF(OTB_LIBRARY_PROPERTIES) + SET_TARGET_PROPERTIES(otbConfigFile PROPERTIES ${OTB_LIBRARY_PROPERTIES}) +ENDIF(OTB_LIBRARY_PROPERTIES) + +INCLUDE_DIRECTORIES("${OTB_SOURCE_DIR}/Utilities/otbconfigfile") + +IF(NOT OTB_INSTALL_NO_LIBRARIES) + INSTALL(TARGETS otbConfigFile + RUNTIME DESTINATION ${OTB_INSTALL_BIN_DIR_CM24} COMPONENT RuntimeLibraries + LIBRARY DESTINATION ${OTB_INSTALL_LIB_DIR_CM24} COMPONENT RuntimeLibraries + ARCHIVE DESTINATION ${OTB_INSTALL_LIB_DIR_CM24} COMPONENT Development) +ENDIF(NOT OTB_INSTALL_NO_LIBRARIES) + +IF(NOT OTB_INSTALL_NO_DEVELOPMENT) + INSTALL(FILES ${otbConfigFilelib_HDRS} + DESTINATION ${OTB_INSTALL_INCLUDE_DIR_CM24}/Utilities/otbConfigFilelib + COMPONENT Development) +ENDIF(NOT OTB_INSTALL_NO_DEVELOPMENT) diff --git a/Utilities/otbconfigfile/ConfigFile.cpp b/Utilities/otbconfigfile/ConfigFile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f041064e51720d31643c833bca149d9bd58f9d39 --- /dev/null +++ b/Utilities/otbconfigfile/ConfigFile.cpp @@ -0,0 +1,142 @@ +// ConfigFile.cpp + +#include "ConfigFile.h" + +using std::string; + +ConfigFile::ConfigFile( string filename, string delimiter, + string comment, string sentry ) + : myDelimiter(delimiter), myComment(comment), mySentry(sentry) +{ + // Construct a ConfigFile, getting keys and values from given file + + std::ifstream in( filename.c_str() ); + + if( !in ) throw file_not_found( filename ); + + in >> (*this); +} + + +ConfigFile::ConfigFile() + : myDelimiter( string(1,'=') ), myComment( string(1,'#') ) +{ + // Construct a ConfigFile without a file; empty +} + + +void ConfigFile::remove( const string& key ) +{ + // Remove key and its value + myContents.erase( myContents.find( key ) ); + return; +} + + +bool ConfigFile::keyExists( const string& key ) const +{ + // Indicate whether key is found + mapci p = myContents.find( key ); + return ( p != myContents.end() ); +} + + +/* static */ +void ConfigFile::trim( string& s ) +{ + // Remove leading and trailing whitespace + static const char whitespace[] = " \n\t\v\r\f"; + s.erase( 0, s.find_first_not_of(whitespace) ); + s.erase( s.find_last_not_of(whitespace) + 1U ); +} + + +std::ostream& operator<<( std::ostream& os, const ConfigFile& cf ) +{ + // Save a ConfigFile to os + for( ConfigFile::mapci p = cf.myContents.begin(); + p != cf.myContents.end(); + ++p ) + { + os << p->first << " " << cf.myDelimiter << " "; + os << p->second << std::endl; + } + return os; +} + + +std::istream& operator>>( std::istream& is, ConfigFile& cf ) +{ + // Load a ConfigFile from is + // Read in keys and values, keeping internal whitespace + typedef string::size_type pos; + const string& delim = cf.myDelimiter; // separator + const string& comm = cf.myComment; // comment + const string& sentry = cf.mySentry; // end of file sentry + const pos skip = delim.length(); // length of separator + + string nextline = ""; // might need to read ahead to see where value ends + + while( is || nextline.length() > 0 ) + { + // Read an entire line at a time + string line; + if( nextline.length() > 0 ) + { + line = nextline; // we read ahead; use it now + nextline = ""; + } + else + { + std::getline( is, line ); + } + + // Ignore comments + line = line.substr( 0, line.find(comm) ); + + // Check for end of file sentry + if( sentry != "" && line.find(sentry) != string::npos ) return is; + + // Parse the line if it contains a delimiter + pos delimPos = line.find( delim ); + if( delimPos < string::npos ) + { + // Extract the key + string key = line.substr( 0, delimPos ); + line.replace( 0, delimPos+skip, "" ); + + // See if value continues on the next line + // Stop at blank line, next line with a key, end of stream, + // or end of file sentry + bool terminate = false; + while( !terminate && is ) + { + std::getline( is, nextline ); + terminate = true; + + string nlcopy = nextline; + ConfigFile::trim(nlcopy); + if( nlcopy == "" ) continue; + + nextline = nextline.substr( 0, nextline.find(comm) ); + if( nextline.find(delim) != string::npos ) + continue; + if( sentry != "" && nextline.find(sentry) != string::npos ) + continue; + + nlcopy = nextline; + ConfigFile::trim(nlcopy); + if( nlcopy != "" ) line += "\n"; + line += nextline; + terminate = false; + } + + // Store key and value + ConfigFile::trim(key); + ConfigFile::trim(line); + cf.myContents[key] = line; // overwrites if key is repeated + } + } + + return is; +} diff --git a/Utilities/otbconfigfile/ConfigFile.h b/Utilities/otbconfigfile/ConfigFile.h new file mode 100644 index 0000000000000000000000000000000000000000..c2f002447c35f98d5b51d5c2cd6ad834957f4610 --- /dev/null +++ b/Utilities/otbconfigfile/ConfigFile.h @@ -0,0 +1,253 @@ +// ConfigFile.h +// Class for reading named values from configuration files +// Richard J. Wagner v2.1 24 May 2004 wagnerr@umich.edu + +// Copyright (c) 2004 Richard J. Wagner +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// Typical usage +// ------------- +// +// Given a configuration file "settings.inp": +// atoms = 25 +// length = 8.0 # nanometers +// name = Reece Surcher +// +// Named values are read in various ways, with or without default values: +// ConfigFile config( "settings.inp" ); +// int atoms = config.read<int>( "atoms" ); +// double length = config.read( "length", 10.0 ); +// string author, title; +// config.readInto( author, "name" ); +// config.readInto( title, "title", string("Untitled") ); +// +// See file example.cpp for more examples. + +#ifndef CONFIGFILE_H +#define CONFIGFILE_H + +#include <string> +#include <map> +#include <iostream> +#include <fstream> +#include <sstream> + +using std::string; + +class ConfigFile { +// Data +protected: + string myDelimiter; // separator between key and value + string myComment; // separator between value and comments + string mySentry; // optional string to signal end of file + std::map<string,string> myContents; // extracted keys and values + + typedef std::map<string,string>::iterator mapi; + typedef std::map<string,string>::const_iterator mapci; + +// Methods +public: + ConfigFile( string filename, + string delimiter = "=", + string comment = "#", + string sentry = "EndConfigFile" ); + ConfigFile(); + + // Search for key and read value or optional default value + template<class T> T read( const string& key ) const; // call as read<T> + template<class T> T read( const string& key, const T& value ) const; + template<class T> bool readInto( T& var, const string& key ) const; + template<class T> + bool readInto( T& var, const string& key, const T& value ) const; + + // Modify keys and values + template<class T> void add( string key, const T& value ); + void remove( const string& key ); + + // Check whether key exists in configuration + bool keyExists( const string& key ) const; + + // Check or change configuration syntax + string getDelimiter() const { return myDelimiter; } + string getComment() const { return myComment; } + string getSentry() const { return mySentry; } + string setDelimiter( const string& s ) + { string old = myDelimiter; myDelimiter = s; return old; } + string setComment( const string& s ) + { string old = myComment; myComment = s; return old; } + + // Write or read configuration + friend std::ostream& operator<<( std::ostream& os, const ConfigFile& cf ); + friend std::istream& operator>>( std::istream& is, ConfigFile& cf ); + +protected: + template<class T> static string T_as_string( const T& t ); + template<class T> static T string_as_T( const string& s ); + static void trim( string& s ); + + +// Exception types +public: + struct file_not_found { + string filename; + file_not_found( const string& filename_ = string() ) + : filename(filename_) {} }; + struct key_not_found { // thrown only by T read(key) variant of read() + string key; + key_not_found( const string& key_ = string() ) + : key(key_) {} }; +}; + + +/* static */ +template<class T> +string ConfigFile::T_as_string( const T& t ) +{ + // Convert from a T to a string + // Type T must support << operator + std::ostringstream ost; + ost << t; + return ost.str(); +} + + +/* static */ +template<class T> +T ConfigFile::string_as_T( const string& s ) +{ + // Convert from a string to a T + // Type T must support >> operator + T t; + std::istringstream ist(s); + ist >> t; + return t; +} + + +/* static */ +template<> +inline string ConfigFile::string_as_T<string>( const string& s ) +{ + // Convert from a string to a string + // In other words, do nothing + return s; +} + + +/* static */ +template<> +inline bool ConfigFile::string_as_T<bool>( const string& s ) +{ + // Convert from a string to a bool + // Interpret "false", "F", "no", "n", "0" as false + // Interpret "true", "T", "yes", "y", "1", "-1", or anything else as true + bool b = true; + string sup = s; + for( string::iterator p = sup.begin(); p != sup.end(); ++p ) + *p = toupper(*p); // make string all caps + if( sup==string("FALSE") || sup==string("F") || + sup==string("NO") || sup==string("N") || + sup==string("0") || sup==string("NONE") ) + b = false; + return b; +} + + +template<class T> +T ConfigFile::read( const string& key ) const +{ + // Read the value corresponding to key + mapci p = myContents.find(key); + if( p == myContents.end() ) throw key_not_found(key); + return string_as_T<T>( p->second ); +} + + +template<class T> +T ConfigFile::read( const string& key, const T& value ) const +{ + // Return the value corresponding to key or given default value + // if key is not found + mapci p = myContents.find(key); + if( p == myContents.end() ) return value; + return string_as_T<T>( p->second ); +} + + +template<class T> +bool ConfigFile::readInto( T& var, const string& key ) const +{ + // Get the value corresponding to key and store in var + // Return true if key is found + // Otherwise leave var untouched + mapci p = myContents.find(key); + bool found = ( p != myContents.end() ); + if( found ) var = string_as_T<T>( p->second ); + return found; +} + + +template<class T> +bool ConfigFile::readInto( T& var, const string& key, const T& value ) const +{ + // Get the value corresponding to key and store in var + // Return true if key is found + // Otherwise set var to given default + mapci p = myContents.find(key); + bool found = ( p != myContents.end() ); + if( found ) + var = string_as_T<T>( p->second ); + else + var = value; + return found; +} + + +template<class T> +void ConfigFile::add( string key, const T& value ) +{ + // Add a key with given value + string v = T_as_string( value ); + trim(key); + trim(v); + myContents[key] = v; + return; +} + +#endif // CONFIGFILE_H + +// Release notes: +// v1.0 21 May 1999 +// + First release +// + Template read() access only through non-member readConfigFile() +// + ConfigurationFileBool is only built-in helper class +// +// v2.0 3 May 2002 +// + Shortened name from ConfigurationFile to ConfigFile +// + Implemented template member functions +// + Changed default comment separator from % to # +// + Enabled reading of multiple-line values +// +// v2.1 24 May 2004 +// + Made template specializations inline to avoid compiler-dependent linkage +// + Allowed comments within multiple-line values +// + Enabled blank line termination for multiple-line values +// + Added optional sentry to detect end of configuration file +// + Rewrote messy trimWhitespace() function as elegant trim() diff --git a/Utilities/otbconfigfile/README b/Utilities/otbconfigfile/README new file mode 100644 index 0000000000000000000000000000000000000000..27406cfe8cf708368e3d375017f3fbdd6501f7d5 --- /dev/null +++ b/Utilities/otbconfigfile/README @@ -0,0 +1,57 @@ +README for ConfigFile distribution +Richard J. Wagner v2.1 24 May 2004 + +Instructions +------------ + +The only necessary files for using this configuration file reader are +"ConfigFile.h" and "ConfigFile.cpp". The class name is ConfigFile. + +Usage examples are in "example.cpp". Linux or Unix users can type "make" to +compile and then type "make run" to run the example program. + +The test program in "tester.cpp" will check that the class properly reads +a variety of simple and complex configuration file entries. To run the test +program type "make test". + +When you are done with the examples and the test program, type "make clean" +to get rid of temporary files. + +For Windows or Mac users with a compiler such as Metrowerks CodeWarrior or +Microsoft Visual C++, simply add "example.cpp" and "ConfigFile.cpp" to an +empty C++ console application. Compile and run to see the configuration +file reader in action. Do likewise with "tester.cpp" to check that the +code works properly with your compiler. + +If you encounter any problems, please e-mail a copy of the output and a +description of the test system to me at "wagnerr@umich.edu". Any other +feedback is welcome too. + + +Installation +------------ + +Just copy the files "ConfigFile.h" and "ConfigFile.cpp" to your working +directory or some other place where your compiler can find them. Add +"ConfigFile.cpp" to your project and put the following line at the top of +your program to access the ConfigFile class: + +#include "ConfigFile.h" + + +Contents +-------- + +README - this file +ConfigFile.h - declaration of ConfigFile class +ConfigFile.cpp - definitions of ConfigFile class +example.cpp - examples of using ConfigFile +tester.cpp - tests ConfigFile class +example.inp - configuration file for example program +test.inp - configuration file for tester program +Triplet.h - sample user-defined data type +Makefile - instructions used by "make" command +ConfigFile.html - Web page about ConfigFile +AntBlueMaize.jpg - background for ConfigFile.html +ArrowHome.gif - home icon for ConfigFile.html +main.css - style sheet for ConfigFile.html