From 6bcf419d2e8f739b432d4790d1ba9d48ab65365b Mon Sep 17 00:00:00 2001 From: fcolin Date: Fri, 18 Nov 2011 12:14:12 +0000 Subject: --- ARMFCaptureD3D/ConfigFile/AntBlueMaize.jpg | Bin 0 -> 6533 bytes ARMFCaptureD3D/ConfigFile/ArrowHome.gif | Bin 0 -> 187 bytes ARMFCaptureD3D/ConfigFile/ConfigFile.cpp | 142 +++++++++++++ ARMFCaptureD3D/ConfigFile/ConfigFile.h | 253 ++++++++++++++++++++++ ARMFCaptureD3D/ConfigFile/ConfigFile.html | 72 +++++++ ARMFCaptureD3D/ConfigFile/Makefile | 24 +++ ARMFCaptureD3D/ConfigFile/README | 57 +++++ ARMFCaptureD3D/ConfigFile/Triplet.h | 34 +++ ARMFCaptureD3D/ConfigFile/example.cpp | 111 ++++++++++ ARMFCaptureD3D/ConfigFile/example.inp | 14 ++ ARMFCaptureD3D/ConfigFile/main.css | 37 ++++ ARMFCaptureD3D/ConfigFile/test.inp | 83 ++++++++ ARMFCaptureD3D/ConfigFile/tester.cpp | 331 +++++++++++++++++++++++++++++ 13 files changed, 1158 insertions(+) create mode 100644 ARMFCaptureD3D/ConfigFile/AntBlueMaize.jpg create mode 100644 ARMFCaptureD3D/ConfigFile/ArrowHome.gif create mode 100644 ARMFCaptureD3D/ConfigFile/ConfigFile.cpp create mode 100644 ARMFCaptureD3D/ConfigFile/ConfigFile.h create mode 100644 ARMFCaptureD3D/ConfigFile/ConfigFile.html create mode 100644 ARMFCaptureD3D/ConfigFile/Makefile create mode 100644 ARMFCaptureD3D/ConfigFile/README create mode 100644 ARMFCaptureD3D/ConfigFile/Triplet.h create mode 100644 ARMFCaptureD3D/ConfigFile/example.cpp create mode 100644 ARMFCaptureD3D/ConfigFile/example.inp create mode 100644 ARMFCaptureD3D/ConfigFile/main.css create mode 100644 ARMFCaptureD3D/ConfigFile/test.inp create mode 100644 ARMFCaptureD3D/ConfigFile/tester.cpp (limited to 'ARMFCaptureD3D/ConfigFile') diff --git a/ARMFCaptureD3D/ConfigFile/AntBlueMaize.jpg b/ARMFCaptureD3D/ConfigFile/AntBlueMaize.jpg new file mode 100644 index 0000000..3dc2845 Binary files /dev/null and b/ARMFCaptureD3D/ConfigFile/AntBlueMaize.jpg differ diff --git a/ARMFCaptureD3D/ConfigFile/ArrowHome.gif b/ARMFCaptureD3D/ConfigFile/ArrowHome.gif new file mode 100644 index 0000000..b38dd5b Binary files /dev/null and b/ARMFCaptureD3D/ConfigFile/ArrowHome.gif differ diff --git a/ARMFCaptureD3D/ConfigFile/ConfigFile.cpp b/ARMFCaptureD3D/ConfigFile/ConfigFile.cpp new file mode 100644 index 0000000..f041064 --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/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/ARMFCaptureD3D/ConfigFile/ConfigFile.h b/ARMFCaptureD3D/ConfigFile/ConfigFile.h new file mode 100644 index 0000000..82b099a --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/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( "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 +#include +#include +#include +#include + +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 myContents; // extracted keys and values + + typedef std::map::iterator mapi; + typedef std::map::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 T read( const string& key ) const; // call as read + template T read( const string& key, const T& value ) const; + template bool readInto( T& var, const string& key ) const; + template + bool readInto( T& var, const string& key, const T& value ) const; + + // Modify keys and values + template 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 static string T_as_string( const T& t ); + template 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 +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 +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( 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( 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 = (char)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 +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( p->second ); +} + + +template +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( p->second ); +} + + +template +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( p->second ); + return found; +} + + +template +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( p->second ); + else + var = value; + return found; +} + + +template +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/ARMFCaptureD3D/ConfigFile/ConfigFile.html b/ARMFCaptureD3D/ConfigFile/ConfigFile.html new file mode 100644 index 0000000..2f29e41 --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/ConfigFile.html @@ -0,0 +1,72 @@ + + + + + + + + + + Configuration File Reader for C++ + + + + +

Configuration File Reader for C++

+ +ConfigFile is a C++ class for reading configuration files. Such files are handy, for example, in running computer simulations. The simulation program can be set to read its input parameters and settings from a configuration file. Then, changing the simulation conditions is as easy as editing text in the configuration file rather than editing and recompiling the source code. + +

With this purpose in mind, ConfigFile is designed to be convenient, portable, and free. Take a look at the +class header, +class definition, +example program, and +sample input. +Or, download the complete package in +zip +or +tarball +format. + +

Features: +

    +
  • Human-readable configuration files: +
      +
    • atoms = 250 +
    • length = 8.0  # nanometers +
    • name = Reece Surcher +
    +
  • Simple file opening with ConfigFile config( "config.inp" ); +
  • Convenient reading of any data type: +
      +
    • int atoms = config.read<int>( "atoms" ); +
    • double length = config.read( "length", 10.0 ); +
    • string author = config.read<string>( "name", "none" ); +
    +
  • Ability to modify and save configuration files +
  • Thorough example program +
  • Validation tests +
  • Open source code under MIT License +
+ +

If you like this software, also try my version of the +Mersenne Twister +random number generator. + + + +

+ + +
+ ^ home +
+ Rick Wagner ( + wagnerr@umich.edu + ) 26 May 04 +
+ + + diff --git a/ARMFCaptureD3D/ConfigFile/Makefile b/ARMFCaptureD3D/ConfigFile/Makefile new file mode 100644 index 0000000..fd503f8 --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/Makefile @@ -0,0 +1,24 @@ +# Makefile for ConfigFile class + +CC = g++ +CFLAGS = -Wall -ansi + +all: example tester + +example: example.cpp ConfigFile.cpp + $(CC) $(CFLAGS) -o example example.cpp ConfigFile.cpp + +tester: tester.cpp ConfigFile.cpp + $(CC) $(CFLAGS) -o tester tester.cpp ConfigFile.cpp + +run: example + ./example | tee example.out + +test: tester + ./tester | tee test.out + +tidy: + @ rm -f *.o + +clean: tidy + @ rm -f example tester example.out test.out core* diff --git a/ARMFCaptureD3D/ConfigFile/README b/ARMFCaptureD3D/ConfigFile/README new file mode 100644 index 0000000..27406cf --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/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 diff --git a/ARMFCaptureD3D/ConfigFile/Triplet.h b/ARMFCaptureD3D/ConfigFile/Triplet.h new file mode 100644 index 0000000..e26dc47 --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/Triplet.h @@ -0,0 +1,34 @@ +// Triplet.h +// A sample user-defined data type for illustrating ConfigFile +// Operators << and >> are defined to allow writing to and reading from files +// Richard J. Wagner 24 May 2004 + +#include + +struct Triplet +{ + int a, b, c; + + Triplet() {} + Triplet( int u, int v, int w ) : a(u), b(v), c(w) {} + Triplet( const Triplet& orig ) : a(orig.a), b(orig.b), c(orig.c) {} + + Triplet& operator=( const Triplet& orig ) + { a = orig.a; b = orig.b; c = orig.c; return *this; } +}; + + +std::ostream& operator<<( std::ostream& os, const Triplet& t ) +{ + // Save a triplet to os + os << t.a << " " << t.b << " " << t.c; + return os; +} + + +std::istream& operator>>( std::istream& is, Triplet& t ) +{ + // Load a triplet from is + is >> t.a >> t.b >> t.c; + return is; +} diff --git a/ARMFCaptureD3D/ConfigFile/example.cpp b/ARMFCaptureD3D/ConfigFile/example.cpp new file mode 100644 index 0000000..e0d24c0 --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/example.cpp @@ -0,0 +1,111 @@ +// example.cpp +// Program to demonstrate ConfigFile class + +#include +#include +#include "ConfigFile.h" +#include "Triplet.h" + +using std::string; +using std::cout; +using std::endl; + +int main( void ) +{ + // A configuration file can be loaded with a simple + + ConfigFile config( "example.inp" ); + + // Values can be read from the file by name + + int apples; + config.readInto( apples, "apples" ); + cout << "The number of apples is " << apples << endl; + + double price; + config.readInto( price, "price" ); + cout << "The price is $" << price << endl; + + string title; + config.readInto( title, "title" ); + cout << "The title of the song is " << title << endl; + + // We can provide default values in case the name is not found + + int oranges; + config.readInto( oranges, "oranges", 0 ); + cout << "The number of oranges is " << oranges << endl; + + int fruit = 0; + fruit += config.read( "apples", 0 ); + fruit += config.read( "pears", 0 ); + fruit += config.read( "oranges", 0 ); + cout << "The total number of apples, pears, and oranges is "; + cout << fruit << endl; + + // Sometimes we must tell the compiler what data type we want to + // read when it's not clear from arguments given to read() + + int pears = config.read( "pears" ); + cout << "The number of pears is " << pears; + cout << ", but you knew that already" << endl; + + // The value is interpreted as the requested data type + + cout << "The weight is "; + cout << config.read("weight"); + cout << " as a string" << endl; + + cout << "The weight is "; + cout << config.read("weight"); + cout << " as a double" << endl; + + cout << "The weight is "; + cout << config.read("weight"); + cout << " as an integer" << endl; + + // When reading boolean values, a wide variety of words are + // recognized, including "true", "yes", and "1" + + if( config.read( "sale", false ) ) + cout << "The fruit is on sale" << endl; + else + cout << "The fruit is full price" << endl; + + // We can also read user-defined types, as long as the input and + // output operators, >> and <<, are defined + + Triplet point; + config.readInto( point, "zone" ); + cout << "The first point in the zone is " << point << endl; + + // The readInto() functions report whether the named value was found + + int pommes = 0; + if( config.readInto( pommes, "pommes" ) ) + cout << "The input file is in French: "; + else if( config.readInto( pommes, "apples" ) ) + cout << "The input file is in English: "; + cout << "The number of pommes (apples) is " << pommes << endl; + + // Named values can be added to a ConfigFile + + config.add( "zucchini", 12 ); + int zucchini = config.read( "zucchini", 0 ); + cout << "The number of zucchini was set to " << zucchini << endl; + + // And values can be removed + + config.remove( "pears" ); + if( config.readInto( pears, "pears" ) ) + cout << "The pears are ready" << endl; + else + cout << "The pears have been eaten" << endl; + + // An entire ConfigFile can written (and restored) + + cout << "Here is the modified configuration file:" << endl; + cout << config; + + return 0; +} diff --git a/ARMFCaptureD3D/ConfigFile/example.inp b/ARMFCaptureD3D/ConfigFile/example.inp new file mode 100644 index 0000000..503fb1b --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/example.inp @@ -0,0 +1,14 @@ +# example.inp +# Example configuration file for ConfigFile class + +apples = 7 # comment after apples +pears = 3 # comment after pears +price = 1.99 # comment after price +sale = true # comment after sale +title = one fine day # comment after title +weight = 2.5 kg # comment after weight +zone = 1 2 3 # comment after 1st point + 4 5 6 # comment after 2nd point + 7 8 9 # comment after 3rd point + +This is also a comment since it has no equals sign and follows a blank line. diff --git a/ARMFCaptureD3D/ConfigFile/main.css b/ARMFCaptureD3D/ConfigFile/main.css new file mode 100644 index 0000000..08bbd90 --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/main.css @@ -0,0 +1,37 @@ +body { text-align: justify; + margin: 0.5em 1.5em; + color: #002244; + background-color: white; + background: url("AntGreenWhite.jpg"); + font-family: "new century schoolbook", serif } + +a:link { color: #0055cc } +a:visited { color: #303077 } +a:active { color: #aaaa00 } + +h1 { text-align: center; font-size: 200%; margin: 0em 0em 0.2em; color: #000066 } +h2 { text-align: left; font-size: 150%; margin: 0em 0em 0.4em; color: #000000 } +h3 { text-align: left; font-size: 120%; margin: 0em 0em 0.4em; color: #000000 } +li { margin: 0em 0em 0.2em } + +.left { text-align: left } +.center { text-align: center } +.right { text-align: right } +.justify { text-align: justify } +.top { vertical-align: top } +.middle { vertical-align: middle } +.bottom { vertical-align: bottom } +.bold { font-weight: bold } + +.caption { text-align: center; font-size: 90%; font-style: italic } +.preview { vertical-align: top; margin: 0.2em 3.0em 0.2em 2.0em } +.clear { clear: both } +a.plain { text-decoration: none; font-size: larger; font-weight: bold } + +.in0 { text-indent: 0.000em; line-height: 110% } +.in1 { text-indent: 0.143em; line-height: 110% } +.in2 { text-indent: 0.518em; line-height: 110% } +.in3 { text-indent: 0.982em; line-height: 110% } +.in4 { text-indent: 1.357em; line-height: 110% } +.in5 { text-indent: 1.500em; line-height: 110% } + diff --git a/ARMFCaptureD3D/ConfigFile/test.inp b/ARMFCaptureD3D/ConfigFile/test.inp new file mode 100644 index 0000000..1370918 --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/test.inp @@ -0,0 +1,83 @@ +# test.inp +# Test configuration file for ConfigFile class + +################################ +# Run through the basic syntax # +################################ + +integer = 7 # comment after apples +double = 1.99 # comment after double +boolean = true # comment after bool +string = one fine day # comment after string +weight = 2.5 kg # comment after weight +triplets = 1 2 3 # comment after 1st triplet + 4 5 6 # comment after 2nd triplet + 7 8 9 # comment after 3rd triplet + +This is also a comment since it has no equals sign and follows a blank line. + + +########################################## +# Run through some more difficult syntax # +########################################## + +# Repeated keys should overwrite previous values +repeated = 1 +repeated = 2 + +# Key recognition should be case-sensitive +oneStall = 1 +onesTall = 111 + +# Keys with embedded spaces should be recognized +space key = true + +# An all-space value should be legal +noValue = + +# An all-space key, though weird, should be legal too += 5 + +# On a line with two delimiters, the second should belong to the value +equation = y = mx + b + +# Blank lines should terminate multiple-line values +multilinePause = + first + second + third + + fourth + +# But comments should not terminate multiple-line values +multilineComment = + first # 1st + second # 2nd + third # 3rd + fourth # 4th + +# Commented lines in multiple-line values should simply be skipped +multilineSkip = + first + second +# third + fourth + +# Assignments within comments should be ignored +# postComment = 9 + +# Alternative delimiters should be recognized +atDelimiter @ 7 + +# Alternative comment separators should be recognized +! alternateComment = 9 + +# A space should work as an alternative delimiter +spaceDelimiter 7 + +# Assignments after an active end of file sentry should be ignored +end = before commented sentry +# EndConfigFile +end = before uncommented sentry +EndConfigFile +end = before EOF diff --git a/ARMFCaptureD3D/ConfigFile/tester.cpp b/ARMFCaptureD3D/ConfigFile/tester.cpp new file mode 100644 index 0000000..ff82c27 --- /dev/null +++ b/ARMFCaptureD3D/ConfigFile/tester.cpp @@ -0,0 +1,331 @@ +// tester.cpp +// Program to test ConfigFile class + +#include +#include +#include "ConfigFile.h" +#include "Triplet.h" + +using std::string; +using std::cout; +using std::endl; + +string title = ""; +bool success = true; +int errors = 0; + +void announce( const string& name ) +{ + title = name; + success = true; + cout << "Test " << title << ":" << endl; +} + +void judge() +{ + if( success ) + { + cout << "Passed " << title << "." << endl << endl; + return; + } + cout << "Error - Failed " << title << "." << endl << endl; + ++errors; +} + +void evaluate( const bool& test ) +{ + success = success && test; +} + +int main( void ) +{ + cout << "This is a test of the ConfigFile class." << endl; + + try { + + ConfigFile cf( "test.inp" ); + + cout << "Here is the configuration read from test.inp:" << endl; + cout << cf << endl; + + // Test reading of basic types + + announce("reading of basic types"); + + int valInt = cf.read( "integer", 0 ); + cout << "Value of 'integer' is " << valInt << endl; + evaluate( valInt == 7 ); + + double valDbl = cf.read( "double", 0.0 ); + cout << "Value of 'double' is " << valDbl << endl; + evaluate( valDbl == 1.99 ); + + bool valBoo = cf.read( "boolean", false ); + cout << "Value of 'boolean' is " << valBoo << endl; + evaluate( valBoo ); + + string valStr = cf.read( "string", "nothing" ); + cout << "Value of 'string' is " << valStr << endl; + evaluate( valStr == "one fine day" ); + + judge(); + + // Test reading by different methods + + announce("reading by different methods"); + + int methodExplicit = cf.read( "integer" ); + cout << "Read integer explicitly as " << methodExplicit << endl; + evaluate( methodExplicit == 7 ); + + int methodDefault = cf.read( "integer", 0 ); + cout << "Read integer with default as " << methodDefault << endl; + evaluate( methodDefault == 7 ); + + int valInto = 0; + bool methodInto = cf.readInto( valInto, "integer" ); + cout << "Read integer into variable as " << valInto << endl; + evaluate( methodInto ); + + methodInto = cf.readInto( valInto, "integer", 0 ); + cout << "Read integer into variable with default as " << valInto << endl; + evaluate( methodInto ); + + judge(); + + // Test interpretation as different types + + announce("interpretation as different types"); + + string typeStr = cf.read( "weight", "nothing" ); + cout << "Value of weight as a string is " << typeStr << endl; + evaluate( typeStr == "2.5 kg" ); + + double typeDbl = cf.read( "weight", 0.0 ); + cout << "Value of weight as a double is " << typeDbl << endl; + evaluate( typeDbl == 2.5 ); + + int typeInt = cf.read( "weight", 0 ); + cout << "Value of weight as an integer is " << typeInt << endl; + evaluate( typeInt == 2 ); + + judge(); + + // Test reading of user-defined types + + announce("reading of user-defined types"); + + Triplet trip = cf.read( "triplets" ); + cout << "First Triplet in 'triplets' is " << trip << endl; + evaluate( trip.a==1 && trip.b==2 && trip.c==3 ); + + judge(); + + // Test reading of repeated keys + + announce("reading of repeated keys"); + + int repeat = cf.read( "repeated" ); + cout << "Value of 'repeated' is " << repeat << endl; + evaluate( repeat == 2 ); + + judge(); + + // Test case-sensitivity of key recognition + + announce("case-sensitivity of key recognition"); + + int oneStall = cf.read( "oneStall" ); + cout << "Value of oneStall is " << oneStall << endl; + evaluate( oneStall == 1 ); + + int onesTall = cf.read( "onesTall" ); + cout << "Value of onesTall is " << onesTall << endl; + evaluate( onesTall == 111 ); + + judge(); + + // Test recognition of keys with embedded spaces + + announce("recognition of keys with embedded spaces"); + + bool spaceInKey = cf.read( "space key", false ); + cout << "Value of 'space key' is " << spaceInKey << endl; + evaluate( spaceInKey ); + + judge(); + + // Test legality of all-space values + + announce("legality of all-space values"); + + string noValue = cf.read( "noValue", "something" ); + cout << "Value of 'noValue' is " << noValue << endl; + evaluate( noValue == "" ); + + judge(); + + // Test legality of all-space keys + + announce("legality of all-space keys"); + + int spaceKey = cf.read( "" ); + cout << "Value of nothing is " << spaceKey << endl; + evaluate( spaceKey == 5 ); + + judge(); + + // Test reading of values that include a delimiter + + announce("reading of values that include a delimiter"); + + string equation = cf.read( "equation" ); + cout << "Value of 'equation' is " << equation << endl; + evaluate( equation == "y = mx + b" ); + + judge(); + + // Test termination of multiple-line values by blank lines + + announce("termination of multiple-line values by blank lines"); + + string multiPause = cf.read( "multilinePause" ); + cout << "Value of 'multilinePause' is " << multiPause << endl; + evaluate( multiPause.find("third") != string::npos && + multiPause.find("fourth") == string::npos ); + + judge(); + + // Test continuation of multiple-line values after comments + + announce("continuation of multiple-line values after comments"); + + string multiComment = cf.read( "multilineComment" ); + cout << "Value of 'multilineComment' is " << multiComment << endl; + evaluate( multiComment.find("fourth") != string::npos ); + + judge(); + + // Test skipping of commented lines in multiple-line values + + announce("skipping of commented lines in multiple-line values"); + + string multiSkip = cf.read( "multilineSkip" ); + cout << "Value of 'multilineSkip' is " << multiSkip << endl; + evaluate( multiSkip.find("third") == string::npos && + multiSkip.find("fourth") != string::npos ); + + judge(); + + // Test skipping of assignments within comments + + announce("skipping of assignments within comments"); + + int postComment = cf.read( "postComment", 0 ); + cout << "Value of 'postComment' is " << postComment << endl; + evaluate( postComment == 0 ); + + judge(); + + // Test alternative delimiters + + announce("alternative delimiters"); + string cfDelim = cf.getDelimiter(); + + int atDelimiter = cf.read( "atDelimiter", 0 ); + cout << "Value of 'atDelimiter' with '" << cfDelim; + cout << "' delimiter is " << atDelimiter << endl; + evaluate( atDelimiter == 0 ); + + ConfigFile atcf( "test.inp", "@" ); + atDelimiter = atcf.read( "atDelimiter", 0 ); + cout << "Value of 'atDelimiter' with '" << atcf.getDelimiter(); + cout << "' delimiter is " << atDelimiter << endl; + evaluate( atDelimiter == 7 ); + + judge(); + + // Test alternative comment separators + + announce("alternative comment separators"); + string cfComm = cf.getComment(); + + int altComment = cf.read( "! alternateComment", 0 ); + cout << "Value of '! alternateComment' with '" << cfComm; + cout << "' comment separator is " << altComment << endl; + evaluate( altComment == 9 ); + + altComment = cf.read( "alternateComment", 0 ); + cout << "Value of 'alternateComment' with '" << cfComm; + cout << "' comment separator is " << altComment << endl; + evaluate( altComment == 0 ); + + ConfigFile excf( "test.inp", cf.getDelimiter(), "!" ); + altComment = excf.read( "! alternateComment", 0 ); + cout << "Value of '! alternateComment' with '" << excf.getComment(); + cout << "' comment separator is " << altComment << endl; + evaluate( altComment == 0 ); + + altComment = excf.read( "alternateComment", 0 ); + cout << "Value of 'alternateComment' with '" << excf.getComment(); + cout << "' comment separator is " << altComment << endl; + evaluate( altComment == 0 ); + + judge(); + + // Test legality of a space as a delimiter + + announce("legality of a space as a delimiter"); + + int spaceDelimiter = cf.read( "spaceDelimiter", 0 ); + cout << "Value of 'spaceDelimiter' with '" << cfDelim; + cout << "' delimiter is " << spaceDelimiter << endl; + evaluate( spaceDelimiter == 0 ); + + ConfigFile spcf( "test.inp", " " ); + spaceDelimiter = spcf.read( "spaceDelimiter", 0 ); + cout << "Value of 'spaceDelimiter' with '" << spcf.getDelimiter(); + cout << "' delimiter is " << spaceDelimiter << endl; + evaluate( spaceDelimiter == 7 ); + + judge(); + + // Test interaction of assignments with end of file sentry + + announce("interaction of assignments with end of file sentry"); + + string endStr = cf.read( "end" ); + cout << "Value of 'end' with '" << cf.getSentry(); + cout << "' sentry is " << endStr << endl; + evaluate( endStr == "before uncommented sentry" ); + + ConfigFile eofcf( "test.inp", cfDelim, cfComm, "" ); + endStr = eofcf.read( "end" ); + cout << "Value of 'end' with '" << eofcf.getSentry(); + cout << "' sentry is " << endStr << endl; + evaluate( endStr == "before EOF" ); + judge(); + + // Report results + + } catch( ConfigFile::file_not_found& e ) { + cout << "Error - File '" << e.filename << "' not found."; + cout << endl << endl; + ++errors; + } catch( ConfigFile::key_not_found& e ) { + cout << "Error - Key '" << e.key << "' not found."; + cout << endl << endl; + ++errors; + } + + if( errors > 0 ) + { + cout << "Failed " << errors << " tests of ConfigFile.\n"; + cout << "Please send a copy of this output to wagnerr@umich.edu.\n"; + return 1; + } + + cout << "Passed all tests of ConfigFile." << endl; + + return 0; +} -- cgit v1.1