354 lines
11 KiB
C++
354 lines
11 KiB
C++
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
Header: FGConfigFile.h
|
|
Author: Jon Berndt
|
|
Date started: 03/29/00
|
|
Purpose: Config file read-in class
|
|
Called by: FGAircraft
|
|
|
|
FUNCTIONAL DESCRIPTION
|
|
--------------------------------------------------------------------------------
|
|
|
|
HISTORY
|
|
--------------------------------------------------------------------------------
|
|
03/16/2000 JSB Created
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
INCLUDES
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include "FGConfigFile.h"
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
namespace JSBSim {
|
|
|
|
static const char *IdSrc = "$Id$";
|
|
static const char *IdHdr = ID_CONFIGFILE;
|
|
|
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
CLASS IMPLEMENTATION
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
|
|
FGConfigFile::FGConfigFile(string cfgFileName)
|
|
{
|
|
#if defined ( sgi ) && !defined( __GNUC__ ) && (_COMPILER_VERSION < 740)
|
|
cfgfile.open(cfgFileName.c_str(), ios::in );
|
|
#else
|
|
cfgfile.open(cfgFileName.c_str(), ios::in | ios::binary );
|
|
#endif
|
|
CommentsOn = false;
|
|
CurrentIndex = 0;
|
|
Opened = true;
|
|
#if defined ( sgi ) && !defined( __GNUC__ ) && (_COMPILER_VERSION < 740)
|
|
if (!cfgfile.fail() && !cfgfile.eof()) GetNextConfigLine();
|
|
#else
|
|
if (cfgfile.is_open()) GetNextConfigLine();
|
|
#endif
|
|
else Opened = false;
|
|
|
|
Debug(0);
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
FGConfigFile::~FGConfigFile()
|
|
{
|
|
cfgfile.close();
|
|
Debug(1);
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
string FGConfigFile::GetNextConfigLine(void)
|
|
{
|
|
int comment_starts_at;
|
|
int comment_ends_at;
|
|
int comment_length;
|
|
int line_length;
|
|
bool start_comment, end_comment;
|
|
string CommentStringTemp;
|
|
|
|
do {
|
|
CurrentLine = GetLine();
|
|
line_length = CurrentLine.length();
|
|
comment_starts_at = CurrentLine.find("<!--");
|
|
|
|
if (comment_starts_at >= 0) start_comment = true;
|
|
else start_comment = false;
|
|
|
|
comment_ends_at = CurrentLine.find("-->");
|
|
|
|
if (comment_ends_at >= 0) end_comment = true;
|
|
else end_comment = false;
|
|
|
|
if (!start_comment && !end_comment) { // command comment
|
|
if (CommentsOn) CommentStringTemp = CurrentLine;
|
|
CommentString += CommentStringTemp + "\r\n";
|
|
} else if (start_comment && comment_ends_at > comment_starts_at) { // <!-- ... -->
|
|
CommentsOn = false;
|
|
comment_length = comment_ends_at + 2 - comment_starts_at + 1;
|
|
LineComment = CurrentLine.substr(comment_starts_at+4, comment_length-4-3);
|
|
CurrentLine.erase(comment_starts_at, comment_length);
|
|
if (CurrentLine.find_first_not_of(" ") == string::npos) {
|
|
CurrentLine.erase();
|
|
}
|
|
} else if ( start_comment && !end_comment) { // <!-- ...
|
|
CommentsOn = true;
|
|
comment_length = line_length - comment_starts_at;
|
|
CommentStringTemp = CurrentLine.substr(comment_starts_at+4, comment_length-4);
|
|
CommentString = CommentStringTemp + "\r\n";
|
|
CurrentLine.erase(comment_starts_at, comment_length);
|
|
} else if (!start_comment && end_comment) { // ... -->
|
|
CommentsOn = false;
|
|
comment_length = comment_ends_at + 2 + 1;
|
|
CommentStringTemp = CurrentLine.substr(0, comment_length-4);
|
|
CommentString += CommentStringTemp + "\r\n";
|
|
CurrentLine.erase(0, comment_length);
|
|
} else if (start_comment && comment_ends_at < comment_starts_at) { // --> command <!--
|
|
cerr << "Old comment ends and new one starts - bad JSBSim config file form." << endl;
|
|
CommentsOn = false;
|
|
comment_length = comment_ends_at + 2 + 1;
|
|
CommentStringTemp = CurrentLine.substr(0, comment_length-4);
|
|
CommentString += CommentStringTemp + "\r\n";
|
|
CurrentLine.erase(0, comment_length);
|
|
}
|
|
} while (CommentsOn);
|
|
|
|
CurrentIndex = 0;
|
|
if (CurrentLine.length() == 0) {
|
|
GetNextConfigLine();
|
|
}
|
|
return CurrentLine;
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
string FGConfigFile::GetValue(string val)
|
|
{
|
|
string::size_type pos, p1, p2, ptest;
|
|
|
|
if (val == "") { // this call is to return the tag value
|
|
pos = CurrentLine.find("<");
|
|
if (pos != CurrentLine.npos) { // beginning brace found "<"
|
|
p1 = CurrentLine.find_first_not_of(" ",pos+1);
|
|
if (p1 != CurrentLine.npos) { // found first character of tag
|
|
p2 = CurrentLine.find_first_of(" >",p1+1);
|
|
if (p2 == CurrentLine.npos) p2 = p1+1;
|
|
return CurrentLine.substr(p1,p2-p1);
|
|
}
|
|
} else { // beginning brace "<" not found; this is a regular data line
|
|
pos = CurrentLine.find_first_not_of(" ");
|
|
if (pos != CurrentLine.npos) { // first character in line found
|
|
p2 = CurrentLine.find_first_of(" ",pos+1);
|
|
if (p2 != CurrentLine.npos) {
|
|
return CurrentLine.substr(pos,p2-pos);
|
|
} else {
|
|
return CurrentLine.substr(pos,CurrentLine.length()-pos);
|
|
}
|
|
}
|
|
}
|
|
} else { // return a value for a specific tag
|
|
pos = CurrentLine.find(val);
|
|
if (pos != CurrentLine.npos) {
|
|
pos = CurrentLine.find("=",pos);
|
|
if (pos != CurrentLine.npos) {
|
|
ptest = CurrentLine.find_first_not_of(" ",pos+1);
|
|
if (ptest != CurrentLine.npos) {
|
|
p1 = ptest + 1;
|
|
if (CurrentLine[ptest] == '"') { // quoted
|
|
p2 = CurrentLine.find_first_of("\"",p1);
|
|
} else { // not quoted
|
|
p2 = CurrentLine.find_first_of(" ",p1);
|
|
}
|
|
if (p2 != CurrentLine.npos) {
|
|
return CurrentLine.substr(p1,p2-p1);
|
|
}
|
|
}
|
|
} else { // "=" not found
|
|
pos = CurrentLine.find(val);
|
|
pos = CurrentLine.find_first_of(" ",pos+1);
|
|
ptest = CurrentLine.find_first_not_of(" ",pos+1);
|
|
if (ptest != CurrentLine.npos) {
|
|
if (CurrentLine[ptest] == '"') { // quoted
|
|
p1 = ptest + 1;
|
|
p2 = CurrentLine.find_first_of("\"",p1);
|
|
} else { // not quoted
|
|
p1 = ptest;
|
|
p2 = CurrentLine.find_first_of(" ",p1);
|
|
}
|
|
if (p2 != CurrentLine.npos) {
|
|
return CurrentLine.substr(p1,p2-p1);
|
|
} else {
|
|
p2 = CurrentLine.length();
|
|
return CurrentLine.substr(p1,p2-p1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return string("");
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
string FGConfigFile::GetValue(void)
|
|
{
|
|
return GetValue("");
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
string FGConfigFile::GetLine(void)
|
|
{
|
|
string scratch = "";
|
|
int test;
|
|
|
|
while ((test = cfgfile.get()) != EOF) {
|
|
if (test >= 0x20 || test == 0x09) {
|
|
if (test == 0x09) {
|
|
scratch += (char)0x20;
|
|
} else {
|
|
scratch += (char)test;
|
|
}
|
|
} else {
|
|
if ((test = cfgfile.get()) != EOF) { // get *next* character
|
|
#if defined ( sgi ) && !defined( __GNUC__ ) && (_COMPILER_VERSION < 740) || defined (_MSC_VER)
|
|
if (test >= 0x20 || test == 0x09) cfgfile.putback(test);
|
|
#else
|
|
if (test >= 0x20 || test == 0x09) cfgfile.unget();
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int index = scratch.find_last_not_of(" ");
|
|
if (index != string::npos && index < (scratch.size()-1)) {
|
|
scratch = scratch.substr(0,index+1);
|
|
}
|
|
|
|
if (cfgfile.eof() && scratch.empty()) return string("EOF");
|
|
return scratch;
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
FGConfigFile& FGConfigFile::operator>>(double& val)
|
|
{
|
|
string::size_type pos, end;
|
|
|
|
pos = CurrentLine.find_first_not_of(", ",CurrentIndex);
|
|
if (pos == CurrentLine.npos) pos = CurrentLine.length();
|
|
end = CurrentLine.find_first_of(", ",pos+1);
|
|
if (end == CurrentLine.npos) end = CurrentLine.length();
|
|
string str = CurrentLine.substr(pos, end - pos);
|
|
val = strtod(str.c_str(),NULL);
|
|
CurrentIndex = end+1;
|
|
if (end == pos) {
|
|
GetNextConfigLine();
|
|
*this >> val;
|
|
} else {
|
|
if (CurrentIndex >= CurrentLine.length()) GetNextConfigLine();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
FGConfigFile& FGConfigFile::operator>>(int& val)
|
|
{
|
|
string::size_type pos, end;
|
|
|
|
pos = CurrentLine.find_first_not_of(", ",CurrentIndex);
|
|
if (pos == CurrentLine.npos) pos = CurrentLine.length();
|
|
end = CurrentLine.find_first_of(", ",pos+1);
|
|
if (end == CurrentLine.npos) end = CurrentLine.length();
|
|
string str = CurrentLine.substr(pos, end - pos);
|
|
val = atoi(str.c_str());
|
|
CurrentIndex = end+1;
|
|
if (end == pos) {
|
|
GetNextConfigLine();
|
|
*this >> val;
|
|
} else {
|
|
if (CurrentIndex >= CurrentLine.length()) GetNextConfigLine();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
FGConfigFile& FGConfigFile::operator>>(string& str)
|
|
{
|
|
string::size_type pos, end;
|
|
|
|
pos = CurrentLine.find_first_not_of(", ",CurrentIndex);
|
|
if (pos == CurrentLine.npos) pos = CurrentLine.length();
|
|
end = CurrentLine.find_first_of(", ",pos+1);
|
|
if (end == CurrentLine.npos) end = CurrentLine.length();
|
|
str = CurrentLine.substr(pos, end - pos);
|
|
CurrentIndex = end+1;
|
|
if (end == pos) {
|
|
GetNextConfigLine();
|
|
*this >> str;
|
|
} else {
|
|
if (CurrentIndex >= CurrentLine.length()) GetNextConfigLine();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
void FGConfigFile::ResetLineIndexToZero(void)
|
|
{
|
|
CurrentIndex = 0;
|
|
}
|
|
|
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
// The bitmasked value choices are as follows:
|
|
// unset: In this case (the default) JSBSim would only print
|
|
// out the normally expected messages, essentially echoing
|
|
// the config files as they are read. If the environment
|
|
// variable is not set, debug_lvl is set to 1 internally
|
|
// 0: This requests JSBSim not to output any messages
|
|
// whatsoever.
|
|
// 1: This value explicity requests the normal JSBSim
|
|
// startup messages
|
|
// 2: This value asks for a message to be printed out when
|
|
// a class is instantiated
|
|
// 4: When this value is set, a message is displayed when a
|
|
// FGModel object executes its Run() method
|
|
// 8: When this value is set, various runtime state variables
|
|
// are printed out periodically
|
|
// 16: When set various parameters are sanity checked and
|
|
// a message is printed out when they go out of bounds
|
|
|
|
void FGConfigFile::Debug(int from)
|
|
{
|
|
if (debug_lvl <= 0) return;
|
|
|
|
if (debug_lvl & 1) { // Standard console startup message output
|
|
}
|
|
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
|
if (from == 0) cout << "Instantiated: FGConfigFile" << endl;
|
|
if (from == 1) cout << "Destroyed: FGConfigFile" << endl;
|
|
}
|
|
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
|
}
|
|
if (debug_lvl & 8 ) { // Runtime state variables
|
|
}
|
|
if (debug_lvl & 16) { // Sanity checking
|
|
}
|
|
if (debug_lvl & 64) {
|
|
if (from == 0) { // Constructor
|
|
cout << IdSrc << endl;
|
|
cout << IdHdr << endl;
|
|
}
|
|
}
|
|
}
|
|
}
|