summaryrefslogtreecommitdiff
path: root/ARMFCaptureD3D/ConfigFile
diff options
context:
space:
mode:
authorfcolin2011-11-18 12:14:12 +0000
committerfcolin2011-11-18 12:14:12 +0000
commit6bcf419d2e8f739b432d4790d1ba9d48ab65365b (patch)
tree92815e16f189c8e328dff4fcfa38ebe1d0217fdd /ARMFCaptureD3D/ConfigFile
parent487e963b081d7ffe2ddf489e11d927982c9101a6 (diff)
downloadamilis-6bcf419d2e8f739b432d4790d1ba9d48ab65365b.zip
amilis-6bcf419d2e8f739b432d4790d1ba9d48ab65365b.tar.gz
amilis-6bcf419d2e8f739b432d4790d1ba9d48ab65365b.tar.bz2
amilis-6bcf419d2e8f739b432d4790d1ba9d48ab65365b.tar.xz
Diffstat (limited to 'ARMFCaptureD3D/ConfigFile')
-rw-r--r--ARMFCaptureD3D/ConfigFile/AntBlueMaize.jpgbin0 -> 6533 bytes
-rw-r--r--ARMFCaptureD3D/ConfigFile/ArrowHome.gifbin0 -> 187 bytes
-rw-r--r--ARMFCaptureD3D/ConfigFile/ConfigFile.cpp142
-rw-r--r--ARMFCaptureD3D/ConfigFile/ConfigFile.h253
-rw-r--r--ARMFCaptureD3D/ConfigFile/ConfigFile.html72
-rw-r--r--ARMFCaptureD3D/ConfigFile/Makefile24
-rw-r--r--ARMFCaptureD3D/ConfigFile/README57
-rw-r--r--ARMFCaptureD3D/ConfigFile/Triplet.h34
-rw-r--r--ARMFCaptureD3D/ConfigFile/example.cpp111
-rw-r--r--ARMFCaptureD3D/ConfigFile/example.inp14
-rw-r--r--ARMFCaptureD3D/ConfigFile/main.css37
-rw-r--r--ARMFCaptureD3D/ConfigFile/test.inp83
-rw-r--r--ARMFCaptureD3D/ConfigFile/tester.cpp331
13 files changed, 1158 insertions, 0 deletions
diff --git a/ARMFCaptureD3D/ConfigFile/AntBlueMaize.jpg b/ARMFCaptureD3D/ConfigFile/AntBlueMaize.jpg
new file mode 100644
index 0000000..3dc2845
--- /dev/null
+++ b/ARMFCaptureD3D/ConfigFile/AntBlueMaize.jpg
Binary files differ
diff --git a/ARMFCaptureD3D/ConfigFile/ArrowHome.gif b/ARMFCaptureD3D/ConfigFile/ArrowHome.gif
new file mode 100644
index 0000000..b38dd5b
--- /dev/null
+++ b/ARMFCaptureD3D/ConfigFile/ArrowHome.gif
Binary files 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<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 = (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<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/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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+ <meta name="Author" content="Richard Joseph Wagner">
+ <meta name="Description" content="C++ class for configuration file reader">
+ <meta name="Keywords" content="configuration,file,reader,input,text,C++,class,ConfigFile,data,type,datatype">
+ <link href="main.css" rel="stylesheet" type="text/css">
+ <style type="text/css">
+ body { background: url("AntBlueMaize.jpg"); }
+ tr { text-indent: 2em }
+ </style>
+ <title>Configuration File Reader for C++</title>
+</head>
+
+<body>
+
+<h1>Configuration File Reader for C++</h1>
+
+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.
+
+<p>With this purpose in mind, ConfigFile is designed to be convenient, portable, and free. Take a look at the
+<a href="ConfigFile.h">class header</a>,
+<a href="ConfigFile.cpp">class definition</a>,
+<a href="example.cpp">example program<a>, and
+<a href="example.inp">sample input<a>.
+Or, download the complete package in
+<a href="ConfigFile-2.1.zip">zip</a>
+or
+<a href="ConfigFile-2.1.tar.gz">tarball</a>
+format.
+
+<p>Features:
+<ul>
+ <li>Human-readable configuration files:
+ <ul>
+ <li><code>atoms = 250</code>
+ <li><code>length = 8.0 &nbsp;# nanometers</code>
+ <li><code>name = Reece Surcher</code>
+ </ul>
+ <li>Simple file opening with <code>ConfigFile config( "config.inp" );</code>
+ <li>Convenient reading of any data type:
+ <ul>
+ <li><code>int atoms = config.read&lt;int&gt;( "atoms" );</code>
+ <li><code>double length = config.read( "length", 10.0 );</code>
+ <li><code>string author = config.read&lt;string&gt;( "name", "none" );</code>
+ </ul>
+ <li>Ability to modify and save configuration files
+ <li>Thorough example program
+ <li>Validation tests
+ <li>Open source code under MIT License
+</ul>
+
+<p>If you like this software, also try my version of the
+<a href="http://www-personal.engin.umich.edu/~wagnerr/MersenneTwister.html">Mersenne Twister</a>
+random number generator.
+
+<!-- counter included only in online version -->
+
+<p><table align=center><tr>
+ <td><a href="http://www-personal.engin.umich.edu/~wagnerr/index.html">
+ <img class="nav" src="ArrowHome.gif" alt="^ home" height=16 width=16 border=0>
+ </a></td>
+ <td><span class="center"><address>
+ Rick Wagner (
+ <a href="mailto:wagnerr@umich.edu">wagnerr@umich.edu</a>
+ ) 26 May 04
+ </address></span></td>
+</table>
+
+</body>
+</html>
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 <iostream>
+
+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 <string>
+#include <iostream>
+#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<int>( "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<string>("weight");
+ cout << " as a string" << endl;
+
+ cout << "The weight is ";
+ cout << config.read<double>("weight");
+ cout << " as a double" << endl;
+
+ cout << "The weight is ";
+ cout << config.read<int>("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 <string>
+#include <iostream>
+#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<int>( "integer", 0 );
+ cout << "Value of 'integer' is " << valInt << endl;
+ evaluate( valInt == 7 );
+
+ double valDbl = cf.read<double>( "double", 0.0 );
+ cout << "Value of 'double' is " << valDbl << endl;
+ evaluate( valDbl == 1.99 );
+
+ bool valBoo = cf.read<bool>( "boolean", false );
+ cout << "Value of 'boolean' is " << valBoo << endl;
+ evaluate( valBoo );
+
+ string valStr = cf.read<string>( "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<int>( "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<string>( "weight", "nothing" );
+ cout << "Value of weight as a string is " << typeStr << endl;
+ evaluate( typeStr == "2.5 kg" );
+
+ double typeDbl = cf.read<double>( "weight", 0.0 );
+ cout << "Value of weight as a double is " << typeDbl << endl;
+ evaluate( typeDbl == 2.5 );
+
+ int typeInt = cf.read<int>( "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<Triplet>( "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<int>( "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<int>( "oneStall" );
+ cout << "Value of oneStall is " << oneStall << endl;
+ evaluate( oneStall == 1 );
+
+ int onesTall = cf.read<int>( "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<bool>( "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<string>( "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<int>( "" );
+ 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<string>( "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<string>( "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<string>( "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<string>( "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<int>( "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<int>( "atDelimiter", 0 );
+ cout << "Value of 'atDelimiter' with '" << cfDelim;
+ cout << "' delimiter is " << atDelimiter << endl;
+ evaluate( atDelimiter == 0 );
+
+ ConfigFile atcf( "test.inp", "@" );
+ atDelimiter = atcf.read<int>( "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<int>( "! alternateComment", 0 );
+ cout << "Value of '! alternateComment' with '" << cfComm;
+ cout << "' comment separator is " << altComment << endl;
+ evaluate( altComment == 9 );
+
+ altComment = cf.read<int>( "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<int>( "! alternateComment", 0 );
+ cout << "Value of '! alternateComment' with '" << excf.getComment();
+ cout << "' comment separator is " << altComment << endl;
+ evaluate( altComment == 0 );
+
+ altComment = excf.read<int>( "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<int>( "spaceDelimiter", 0 );
+ cout << "Value of 'spaceDelimiter' with '" << cfDelim;
+ cout << "' delimiter is " << spaceDelimiter << endl;
+ evaluate( spaceDelimiter == 0 );
+
+ ConfigFile spcf( "test.inp", " " );
+ spaceDelimiter = spcf.read<int>( "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<string>( "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<string>( "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;
+}