PJS: moving to configfile c++ library

git-svn-id: https://projectm.svn.sourceforge.net/svnroot/projectm/personal/carm/dev-1.0@353 6778bc44-b910-0410-a7a0-be141de4315d
This commit is contained in:
psperl
2007-08-28 19:17:43 +00:00
parent 37c3ee4cab
commit 42a30734f5
9 changed files with 465 additions and 32 deletions

View File

@ -4,14 +4,13 @@ ADD_LIBRARY(projectM SHARED projectM.cpp projectM.hpp PBuffer.cpp PBuffer.hpp In
Param.cpp CustomWave.cpp CustomShape.hpp CustomShape.cpp Param.hpp CustomWave.hpp BeatDetect.hpp console_interface.h
Func.hpp Func.cpp Eval.cpp wipemalloc.h PerFrameEqn.cpp PerPointEqn.cpp fftsg.cpp console_interface.cpp
CValue.hpp Expr.hpp timer.cpp wipemalloc.cpp PerFrameEqn.hpp PerPixelEqn.hpp PerPointEqn.hpp BuiltinFuncs.hpp
BuiltinFuncs.cpp compare.h event.h fatal.h fftsg.h timer.h BuiltinParams.hpp BuiltinParams.cpp Preset.hpp Renderer.cpp Renderer.hpp ParamUtils.hpp PresetLoader.cpp PresetLoader.hpp PresetChooser.hpp PresetChooser.cpp PresetFrameIO.cpp PresetFrameIO.hpp PresetMerge.cpp PresetMerge.hpp)
BuiltinFuncs.cpp compare.h event.h fatal.h fftsg.h timer.h BuiltinParams.hpp BuiltinParams.cpp Preset.hpp Renderer.cpp Renderer.hpp ParamUtils.hpp PresetLoader.cpp PresetLoader.hpp PresetChooser.hpp PresetChooser.cpp PresetFrameIO.cpp PresetFrameIO.hpp PresetMerge.cpp PresetMerge.hpp ConfigFile.h ConfigFile.cpp)
OPTION(USE_FTGL "Use FTGL for on-screen fonts" ON)
ADD_DEFINITIONS(-DLINUX -DUSE_FBO)
FIND_PACKAGE(OpenGL)
#FIND_PACKAGE(LibXml2)
INCLUDE(FindPkgConfig.cmake)
@ -26,15 +25,13 @@ IF(USE_FTGL)
ENDIF(USE_FTGL)
CONFIGURE_FILE("libprojectM.pc.in" "libprojectM.pc" @ONLY)
CONFIGURE_FILE("config.1.00.in" "config.1.00" @ONLY)
CONFIGURE_FILE("config.xml.in" "config.xml" @ONLY)
CONFIGURE_FILE("config.inp.in" "config.inp" @ONLY)
FILE(GLOB presets "presets/*.milk")
INSTALL(FILES ${presets} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/projectM/presets)
FILE(GLOB fonts "fonts/*.ttf")
INSTALL(FILES ${fonts} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/projectM/fonts)
INSTALL(FILES "${CMAKE_BINARY_DIR}/libprojectM.pc" DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
INSTALL(FILES config.1.00 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/projectM)
INSTALL(FILES config.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/projectM)
INSTALL(FILES config.inp DESTINATION ${CMAKE_INSTALL_PREFIX}/share/projectM)
INSTALL(FILES projectM.hpp PBuffer.hpp PCM.hpp BeatDetect.hpp Preset.hpp event.h console_interface.h dlldefs.h fatal.h PresetFrameIO.hpp PCM.hpp Renderer.hpp PresetChooser.hpp DESTINATION include/libprojectM)
INSTALL(TARGETS projectM DESTINATION lib)

View File

@ -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;
}

View File

@ -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()

View File

@ -9,7 +9,7 @@
class Preset;
Renderer::Renderer(int width, int height, int gx, int gy, RenderTarget *renderTarget, BeatDetect *beatDetect, char * _fontURL): fontURL(_fontURL), m_presetName("None")
Renderer::Renderer(int width, int height, int gx, int gy, RenderTarget *renderTarget, BeatDetect *beatDetect, std::string _fontURL): fontURL(_fontURL), m_presetName("None")
{
int x; int y;
@ -561,10 +561,10 @@ void Renderer::reset(int w, int h)
if ( title_font == NULL && other_font == NULL ) {
char path[1024];
sprintf( path, "%s%cVera.ttf", this->fontURL, PATH_SEPARATOR );
sprintf( path, "%s%cVera.ttf", this->fontURL.c_str(), PATH_SEPARATOR );
title_font = new FTGLPixmapFont(path);
poly_font = new FTGLPolygonFont(path);
sprintf( path, "%s%cVeraMono.ttf", this->fontURL, PATH_SEPARATOR );
sprintf( path, "%s%cVeraMono.ttf", this->fontURL.c_str(), PATH_SEPARATOR );
other_font = new FTGLPixmapFont(path);
}

View File

@ -51,7 +51,7 @@ FTGLPolygonFont *poly_font;
int studio;
int correction;
char *fontURL;
std::string fontURL;
int noSwitch;
@ -60,7 +60,7 @@ float realfps;
char *title;
int drawtitle;
Renderer( int width, int height, int gx, int gy, RenderTarget *renderTarget, BeatDetect *beatDetect, char *fontURL);
Renderer( int width, int height, int gx, int gy, RenderTarget *renderTarget, BeatDetect *beatDetect, std::string fontURL);
~Renderer();
void RenderFrame(PresetOutputs *presetOutputs, PresetInputs *presetInputs);
void reset(int w, int h);

View File

@ -0,0 +1,16 @@
# projectM.config
# Configuration File for projectM
Texsize = 512 # Size of rendering
Mesh X = 32 # blah
Mesh Y = 24 #
FPS = 35 #
Fullscreen = false # comment after sale
Window Width = 512 # comment after title
Window Height = 512 # comment after weight
Smooth Transition Duration = 5 # in seconds
Preset Duration = 15 # in seconds
Preset Path = @CMAKE_INSTALL_PREFIX@/share/projectM/presets #preset location
Font Path = @CMAKE_INSTALL_PREFIX@/share/projectM/fonts #font location

View File

@ -1,12 +0,0 @@
<projectM>
<texsize desc="Texture Dimensions">512</texsize>
<gridX>32</gridX>
<gridY>24</gridY>
<fps>35</fps>
<WindowHeight>512</WindowHeight>
<WindowWidth>512</WindowWidth>
<Fullscreen>0</Fullscreen>
<smoothDuration>5</smoothDuration>
<presetDuration>15</presetDuration>
<presetURL>@CMAKE_INSTALL_PREFIX@/share/projectM/presets</presetURL>
</projectM>

View File

@ -51,6 +51,7 @@
#include "Renderer.hpp"
#include "PresetChooser.hpp"
#include "ConfigFile.h"
#ifdef LINUX
const std::string projectM::PROJECTM_PRESET_PATH ( "/usr/share/projectM/presets/" );
@ -80,7 +81,38 @@ int oldFrame = 0;
DLLEXPORT projectM::projectM() :smoothFrame(0), beatDetect ( 0 )
{
projectM_reset();
}
DLLEXPORT projectM::projectM(std::string config_file) :smoothFrame(0), beatDetect ( 0 )
{
projectM_reset();
readConfig(config_file);
}
DLLEXPORT void projectM::readConfig(std::string config_file)
{
ConfigFile config(config_file);
int gx = config.read<int>( "Mesh X", 32 );
int gy = config.read<int>( "Mesh Y", 24 );
int texsize = config.read<int>( "Texsize", 512 );
int fps = config.read<int>( "FPS", 35 );
int wvw = config.read<int>( "Window Width", 512 );
int wvh = config.read<int>( "Window Width", 512 );
int fullscreen;
if (config.read("Fullscreen", true)) fullscreen = 1;
else fullscreen = 0;
presetURL = config.read<string>( "Preset Path", "/usr/share/projectM/presets" );
fontURL = config.read<string>( "Font Path", "/usr/share/projectM/fonts" );
projectM_init(gx, gy, fps, texsize, wvw, wvh);
projectM_resetGL( wvw, wvh );
}
@ -258,8 +290,8 @@ DLLEXPORT void projectM::projectM_reset()
// m_activePreset = 0;
// }
this->presetURL = NULL;
this->fontURL = NULL;
this->presetURL = "";
this->fontURL = "";
/** Default variable settings */
this->hasInit = 0;
@ -324,7 +356,7 @@ DLLEXPORT void projectM::projectM_init ( int gx, int gy, int fps, int texsize, i
/* Preset loading function */
initPresetTools();
#if 0
/* Load default preset directory */
#ifdef MACOS2
/** Probe the bundle for info */
@ -434,7 +466,7 @@ DLLEXPORT void projectM::projectM_init ( int gx, int gy, int fps, int texsize, i
}
#endif
#endif
mspf= ( int ) ( 1000.0/ ( float ) presetInputs.fps );
@ -776,7 +808,7 @@ int projectM::initPresetTools()
srand ( time ( NULL ) );
#endif
if ( ( m_presetLoader = new PresetLoader (std::string(presetURL))) == 0 )
if ( ( m_presetLoader = new PresetLoader (presetURL)) == 0 )
{
m_presetLoader = 0;
std::cerr << "[projectM] error allocating preset loader" << std::endl;

View File

@ -39,6 +39,7 @@
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
@ -125,9 +126,9 @@ public:
static Renderer *renderer;
static RenderTarget *renderTarget;
char *presetURL;
std::string presetURL;
char *fontURL;
std::string fontURL;
int hasInit;
@ -181,14 +182,18 @@ public:
DLLEXPORT projectM();
DLLEXPORT void projectM_init(int gx, int gy, int fps, int texsize, int width, int height);
DLLEXPORT void projectM_reset();
void projectM_reset();
DLLEXPORT void projectM_resetGL( int width, int height );
DLLEXPORT void projectM_setTitle( char *title );
DLLEXPORT void renderFrame();
DLLEXPORT void projectM_initengine();
DLLEXPORT void projectM_resetengine();
DLLEXPORT projectM(std::string config_file);
DLLEXPORT void readConfig(std::string config_file);
void get_title();
void key_handler( projectMEvent event,