/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 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; } } } }