src/tools/tConfiguration.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023   
00024 ***************************************************************************
00025 
00026 */
00027 
00028 #include "aa_config.h"
00029 #include <fstream>
00030 #include <iomanip>
00031 #include <iostream>
00032 #include "tConfiguration.h"
00033 #include <stdlib.h>
00034 #include <ctype.h>
00035 #include <string>
00036 #include <sstream>
00037 #include "tString.h"
00038 #include "tToDo.h"
00039 #include "tConsole.h"
00040 #include "tDirectories.h"
00041 #include "tLocale.h"
00042 #include "tRecorder.h"
00043 #include "tCommandLine.h"
00044 #include "tResourceManager.h"
00045 #include "tError.h"
00046 
00047 #include <vector>
00048 #include <string.h>
00049 
00050 #ifndef WIN32
00051 #include <signal.h>
00052 #endif
00053 
00054 bool           tConfItemBase::printChange=true;
00055 bool           tConfItemBase::printErrors=true;
00056 
00057 
00060 tCurrentAccessLevel::tCurrentAccessLevel( tAccessLevel newLevel, bool allowElevation )
00061 {
00062     // prevent elevation
00063     if ( !allowElevation && newLevel < currentLevel_ )
00064     {
00065         // you probably want to know when this happens in the debugger
00066         st_Breakpoint();
00067         newLevel = currentLevel_;
00068     }
00069 
00070     lastLevel_ = currentLevel_;
00071     currentLevel_ = newLevel;
00072 }
00073 
00074 
00075 tCurrentAccessLevel::tCurrentAccessLevel()
00076 {
00077     lastLevel_ = currentLevel_;
00078 }
00079 
00080 tCurrentAccessLevel::~tCurrentAccessLevel()
00081 {
00082     currentLevel_ = lastLevel_;
00083 }
00084 
00086 tAccessLevel tCurrentAccessLevel::GetAccessLevel()
00087 {
00088     return currentLevel_;
00089 }
00090 
00091 // returns the name of an access level
00092 tString tCurrentAccessLevel::GetName( tAccessLevel level )
00093 {
00094     std::ostringstream s;
00095     s << "$config_accesslevel_" << level;
00096     return tString( tOutput( s.str().c_str() ) );
00097 }
00098 
00099 tAccessLevel tCurrentAccessLevel::currentLevel_ = tAccessLevel_Owner; 
00100 
00101 tAccessLevelSetter::tAccessLevelSetter( tConfItemBase & item, tAccessLevel level )
00102 {
00103     item.requiredLevel = level;
00104 }
00105 
00106 static std::map< tString, tConfItemBase * > * st_confMap = 0;
00107 tConfItemBase::tConfItemMap & tConfItemBase::ConfItemMap()
00108 {
00109     if (!st_confMap)
00110         st_confMap = tNEW( tConfItemMap );
00111     return *st_confMap;
00112 }
00113 
00114 #ifdef KRAWALL_SERVER
00115 
00116 // changes the access level of a configuration item
00117 class tConfItemLevel: public tConfItemBase
00118 {
00119 public:
00120     tConfItemLevel()
00121     : tConfItemBase( "ACCESS_LEVEL" )
00122     {
00123         requiredLevel = tAccessLevel_Owner;
00124     }
00125 
00126     virtual void ReadVal(std::istream &s)
00127     {
00128         // read name and access level
00129         tString name;
00130         s >> name;
00131 
00132         int levelInt;
00133         s >> levelInt;
00134         tAccessLevel level = static_cast< tAccessLevel >( levelInt );
00135 
00136         if ( s.fail() )
00137         {
00138             if(printErrors)
00139             {
00140                 con << tOutput( "$access_level_usage" );
00141             }
00142             return;
00143         }
00144 
00145         // make name uppercase:
00146         tToUpper( name );
00147 
00148         // find the item
00149         tConfItemMap & confmap = ConfItemMap();
00150         tConfItemMap::iterator iter = confmap.find( name );
00151         if ( iter != confmap.end() )
00152         {
00153             // and change the level
00154             tConfItemBase * ci = (*iter).second;
00155             if ( ci->requiredLevel != level )
00156             {
00157                 ci->requiredLevel = level;
00158                 if(printChange)
00159                 {
00160                     con << tOutput( "$access_level_change", name, tCurrentAccessLevel::GetName( level ) );
00161                 }
00162             }
00163         }
00164         else if(printErrors)
00165         {
00166             con << tOutput( "$config_command_unknown", name );
00167         }
00168     }
00169 
00170     virtual void WriteVal(std::ostream &s)
00171     {
00172         tASSERT(0);
00173     }
00174 
00175     virtual bool Writable(){
00176         return false;
00177     }
00178 
00179     virtual bool Save(){
00180         return false;
00181     }
00182 };
00183 
00184 static tConfItemLevel st_confLevel;
00185 
00186 static char const *st_casacl = "CASACL";
00187 
00189 class tCasacl: tConfItemBase
00190 {
00191 public:
00192     tCasacl()
00193     : tConfItemBase( st_casacl )
00194     {
00195         requiredLevel = tAccessLevel_Program;
00196     }
00197 
00198     virtual void ReadVal( std::istream & s )
00199     {
00200         int required_int = 0, elevated_int = 20;
00201 
00202         // read required and elevated access levels
00203         s >> required_int;
00204         s >> elevated_int;
00205 
00206         tAccessLevel elevated = static_cast< tAccessLevel >( elevated_int );
00207         tAccessLevel required = static_cast< tAccessLevel >( required_int );
00208 
00209         if ( s.fail() )
00210         {
00211             con << tOutput( "$casacl_usage" );
00212             throw tAbortLoading( st_casacl );
00213         }
00214         else if ( tCurrentAccessLevel::GetAccessLevel() > required )
00215         {
00216             con << tOutput( "$access_level_error",
00217                             "SUDO",
00218                             tCurrentAccessLevel::GetName( required ),
00219                             tCurrentAccessLevel::GetName( tCurrentAccessLevel::GetAccessLevel() )
00220                 );
00221             throw tAbortLoading( st_casacl );
00222         }
00223         else
00224         {
00225             tString().ReadLine(s); // prevent commands following this one without a newline
00226             tCurrentAccessLevel::currentLevel_ = elevated;
00227         }
00228     }
00229 
00230     virtual void WriteVal(std::ostream &s)
00231     {
00232         tASSERT(0);
00233     }
00234 
00235     virtual bool Writable(){
00236         return false;
00237     }
00238 
00239     virtual bool Save(){
00240         return false;
00241     }
00242 };
00243 
00244 static tCasacl st_sudo;
00245 
00246 #endif
00247 
00248 bool st_FirstUse=true;
00249 static tConfItem<bool> fu("FIRST_USE",st_FirstUse);
00250 
00251 tAbortLoading::tAbortLoading( char const * command )
00252 : command_( command )
00253 {
00254 }
00255 
00256 tString tAbortLoading::DoGetName() const
00257 {
00258     return tString(tOutput( "$abort_loading_name"));
00259 }
00260 
00261 tString tAbortLoading::DoGetDescription() const
00262 {
00263     return tString(tOutput( "$abort_loading_description", command_ ));
00264 }
00265 
00266 tConfItemBase::tConfItemBase(const char *t, callbackFunc *cb)
00267         :id(-1),title(t),
00268 changed(false),callback(cb){
00269 
00270     tConfItemMap & confmap = ConfItemMap();
00271     if ( confmap.find( title ) != confmap.end() )
00272         tERR_ERROR_INT("Two tConfItems with the same name " << t << "!");
00273 
00274     // compose help name
00275     tString helpname;
00276     helpname << title << "_help";
00277     tToLower( helpname );
00278 
00279     const_cast<tOutput&>(help).AddLocale(helpname);
00280 
00281     confmap[title] = this;
00282 
00283     requiredLevel = tAccessLevel_Admin;
00284 }
00285 
00286 tConfItemBase::tConfItemBase(const char *t, const tOutput& h, callbackFunc *cb)
00287         :id(-1),title(t), help(h),
00288 changed(false),callback(cb){
00289 
00290     tConfItemMap & confmap = ConfItemMap();
00291     if ( confmap.find( title ) != confmap.end() )
00292         tERR_ERROR_INT("Two tConfItems with the same name " << t << "!");
00293 
00294     confmap[title] = this;
00295 
00296     requiredLevel = tAccessLevel_Admin;
00297 }
00298 
00299 tConfItemBase::~tConfItemBase()
00300 {
00301     tConfItemMap & confmap = ConfItemMap();
00302     confmap.erase(title);
00303     if ( confmap.size() == 0 )
00304     {
00305         delete st_confMap;
00306         st_confMap = 0;
00307     }
00308 }
00309 
00310 void tConfItemBase::SaveAll(std::ostream &s){
00311     tConfItemMap & confmap = ConfItemMap();
00312     for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
00313     {
00314         tConfItemBase * ci = (*iter).second;
00315         if (ci->Save()){
00316             s << std::setw(28) << ci->title << " ";
00317             ci->WriteVal(s);
00318             s << '\n';
00319         }
00320     }
00321 }
00322 
00323 int tConfItemBase::EatWhitespace(std::istream &s){
00324     int c=' ';
00325 
00326     while(isblank(c) &&
00327             c!='\n'    &&
00328             s.good()  &&
00329             !s.eof())
00330         c=s.get();
00331 
00332     s.putback(c);
00333 
00334     return c;
00335 }
00336 
00337 void tConfItemBase::LoadLine(std::istream &s){
00338     if(!s.eof() && s.good()){
00339         tString name;
00340         s >> name;
00341 
00342         // make name uppercase:
00343         tToUpper( name );
00344 
00345         bool found=false;
00346 
00347         if (name.Size()==0) // ignore empty lines
00348             found=true;
00349         else if (name[0]=='#'){ // comment. ignore rest of line
00350             char c=' ';
00351             while(c!='\n' && s.good() && !s.eof()) c=s.get();
00352             found=true;
00353         }
00354 
00355         tConfItemMap & confmap = ConfItemMap();
00356         tConfItemMap::iterator iter = confmap.find( name );
00357         if ( iter != confmap.end() )
00358         {
00359             tConfItemBase * ci = (*iter).second;
00360 
00361             bool cb=ci->changed;
00362             ci->changed=false;
00363 
00364             if ( ci->requiredLevel >= tCurrentAccessLevel::GetAccessLevel() )
00365             {
00366                 ci->ReadVal(s);
00367                 if (ci->changed)
00368                     ci->WasChanged();
00369                 else
00370                     ci->changed=cb;
00371             }
00372             else
00373             {
00374                 tString discard;
00375                 discard.ReadLine(s);
00376                 
00377                 con << tOutput( "$access_level_error",
00378                                 name,  
00379                                 tCurrentAccessLevel::GetName( ci->requiredLevel ),
00380                                 tCurrentAccessLevel::GetName( tCurrentAccessLevel::GetAccessLevel() )
00381                     );
00382                 return;
00383             }
00384 
00385             found=true;
00386         }
00387 
00388         if (!found){
00389             // eat rest of input line
00390             tString rest;
00391             rest.ReadLine( s );
00392 #ifdef MACOSX
00393             printErrors = false;
00394 #endif
00395             if (printErrors)
00396             {
00397                 tOutput o;
00398                 o.SetTemplateParameter(1, name);
00399                 o << "$config_command_unknown";
00400                 con << o;
00401 
00402                 if (printChange)
00403                 {
00404                     int sim_maxlen=-1;
00405 
00406                     for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
00407                     {
00408                         tConfItemBase * ci = (*iter).second;
00409                         if (strstr(ci->title,name) &&
00410                                 static_cast<int>(strlen(ci->title)) > sim_maxlen)
00411                             sim_maxlen=strlen(ci->title);
00412                     }
00413 
00414                     if (sim_maxlen>0 && printChange ){
00415                         int len = name.Len()-1;
00416                         int printMax = 1 + 3 * len * len * len;
00417                         con << tOutput("$config_command_other");
00418                         for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
00419                         {
00420                             tConfItemBase * ci = (*iter).second;
00421                             if (strstr(ci->title,name))
00422                             {
00423                                 tString help ( ci->help );
00424                                 if ( --printMax > 0 )
00425                                 {
00426                                     tString mess;
00427                                     mess << ci->title;
00428                                     mess.SetPos( sim_maxlen+2, false );
00429                                     mess << "(";
00430                                     mess << help;
00431                                     mess << ")\n";
00432                                     con << mess;
00433                                 }
00434                             }
00435                         }
00436                         if (printMax <= 0 )
00437                             con << tOutput("$config_command_more");
00438                     }
00439                 }
00440                 else
00441                 {
00442                     con << '\n';
00443                 }
00444             }
00445         }
00446     }
00447 
00448     //  std::cout << line << " lines read.\n";
00449 }
00450 
00451 static char const * recordingSection = "CONFIG";
00452 
00453 /*
00454 bool LoadAllHelper(std::istream * s)
00455 {
00456     tString line;
00457 
00458     // read line from recording
00459     if ( s || !tRecorder::Playback( recordingSection, line ) )
00460     {
00461         // return on failure
00462         if (!s)
00463             return false;
00464 
00465         // read line from stream
00466         line.ReadLine( *s );
00467 
00468         // write line to recording
00469         tRecorder::Record( recordingSection, line );
00470     }
00471     line << '\n';
00472 
00473     // process line
00474     std::stringstream str(static_cast< char const * >( line ) );
00475     tConfItemBase::LoadLine(str);
00476 
00477     return true;
00478 }
00479 */
00480 
00481 // test if a line should enter the recording; check if the line contains one of the passed
00482 // substrings. The array of substrings is supposed to be zero terminated.
00483 static bool s_Veto( tString line_in, std::vector< tString > const & vetos )
00484 {
00485     // make name uppercase:
00486     tToUpper( line_in );
00487 
00488     // eat whitespace at the beginning
00489     char const * test = line_in;
00490     while( isblank(*test) )
00491         test++;
00492 
00493     // skip "LAST_"
00494     tString line( test );
00495     if ( line.StartsWith( "LAST_" ) )
00496         line = tString( static_cast< char const * >(line) + 5 );
00497 
00498     // iterate throug vetoed config items and test each one
00499     for ( std::vector< tString >::const_iterator iter = vetos.begin(); iter != vetos.end(); ++iter )
00500     {
00501         tString const & veto = *iter;
00502 
00503         if ( line.StartsWith( veto ) )
00504         {
00505 #ifdef DEBUG_X
00506             if ( !line.StartsWith( "INCLUDE" ) && tRecorder::IsRunning() )
00507             {
00508                 con << "Veto on config line: " << line << "\n";
00509             }
00510 #endif
00511 
00512             return true;
00513         }
00514     }
00515 
00516     return false;
00517 }
00518 
00519 // test if a line should be read from a recording
00520 // sound and video mode settings shold not
00521 static std::vector< tString > st_Stringify( char const * vetos[] )
00522 {
00523     std::vector< tString > ret;
00524 
00525     char const * * v = vetos;
00526     while ( *v )
00527     {
00528         ret.push_back( tString( *v ) );
00529         ++v;
00530     }
00531 
00532     return ret;
00533 }
00534 
00535 static bool s_VetoPlayback( tString const & line )
00536 {
00537     static char const * vetos_char[]=
00538         { "USE_DISPLAYLISTS", "CHECK_ERRORS", "ZDEPTH",
00539           "COLORDEPTH", "FULLSCREEN ", "ARMAGETRON_LAST_WINDOWSIZE",
00540           "ARMAGETRON_WINDOWSIZE", "ARMAGETRON_LAST_SCREENMODE",
00541           "ARMAGETRON_SCREENMODE", "CUSTOM_SCREEN", "SOUND",
00542           "PASSWORD", "ADMIN_PASS", "RECORDING_DEBUGLEVEL",
00543           "ZTRICK", "MOUSE_GRAB", "PNG_SCREENSHOT", // "WHITE_SPARKS", "SPARKS",
00544           "KEEP_WINDOW_ACTIVE", "TEXTURE_MODE", "TEXTURES_HI", "LAG_O_METER", "INFINITY_PLANE",
00545           "SKY_WOBBLE", "LOWER_SKY", "UPPER_SKY", "DITHER", "HIGH_RIM", "FLOOR_DETAIL",
00546           "FLOOR_MIRROR", "SHOW_FPS", "TEXT_OUT", "SMOOTH_SHADING", "ALPHA_BLEND",
00547           "PERSP_CORRECT", "POLY_ANTIALIAS", "LINE_ANTIALIAS", "FAST_FORWARD_MAXSTEP",
00548           "DEBUG_GNUPLOT", "FLOOR_", "MOVIEPACK_", "RIM_WALL_", "INCLUDE", "SINCLUDE",
00549           0 };
00550 
00551     static std::vector< tString > vetos = st_Stringify( vetos_char );
00552 
00553     // delegate
00554     return s_Veto( line, vetos );
00555 }
00556 
00557 // test if a line should enter the recording
00558 // passwords should not.
00559 static bool s_VetoRecording( tString const & line )
00560 {
00561     static char const * vetos_char[]=
00562         { "#", "PASSWORD", "ADMIN_PASS", "LOCAL_USER", "LOCAL_TEAM",
00563           0 };
00564 
00565     static std::vector< tString > vetos = st_Stringify( vetos_char );
00566 
00567     // delegate
00568     return s_Veto( line, vetos );
00569 }
00570 
00571 void tConfItemBase::LoadAll(std::istream &s){
00572     tCurrentAccessLevel levelResetter;
00573 
00574     try{
00575 
00576     while(!s.eof() && s.good())
00577     {
00578         tString line;
00579 
00580         // read line from stream
00581         line.ReadLine( s );
00582 
00584         while ( line.Size() > 0 && line[line.Size()-1] == '\\' && s.good() && !s.eof() )
00585         {
00586             line = line.SubStr( 0, line.Size()-1 );
00587 
00588             // unless it is a double backslash
00589             if ( line.Size() > 0 && line[line.Size()-1] == '\\' )
00590             {
00591                 break;
00592             }
00593 
00594             tString rest;
00595             rest.ReadLine( s );
00596             line << rest;
00597         }
00598 
00599         if ( line.Len() <= 1 )
00600             continue;
00601 
00602         // write line to recording
00603         if ( !s_VetoRecording( line ) )
00604         {
00605             // don't record supid admins' instant chat logins
00606             static tString instantChat("INSTANT_CHAT_STRING");
00607             if ( line.StartsWith( instantChat ) && strstr( line, "/login" ) )
00608             {
00609                 tString newLine = line.SubStr( 0, strstr( line, "/login" ) - (char const *)line );
00610                 newLine += "/login NONE";
00611                 if ( line[strlen(line)-1] == '\\' )
00612                     newLine += '\\';
00613                 tRecorder::Record( recordingSection, newLine );
00614             }
00615             else
00616                 tRecorder::Record( recordingSection, line );
00617         }
00618 
00619         //        std::cout << line << '\n';
00620 
00621         // process line
00622         // line << '\n';
00623         if ( !tRecorder::IsPlayingBack() || s_VetoPlayback( line ) )
00624         {
00625             std::stringstream str(static_cast< char const * >( line ) );
00626             tConfItemBase::LoadLine(str);
00627             // std::cout << line << '\n';
00628         }
00629     }
00630     }
00631     catch( tAbortLoading const & e )
00632     {
00633         // loading was aborted
00634         con << e.GetDescription() << "\n";
00635     }
00636 }
00637 
00638 void tConfItemBase::DocAll(std::ostream &s){
00639     tConfItemMap & confmap = ConfItemMap();
00640     for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
00641     {
00642         tConfItemBase * ci = (*iter).second;
00643 
00644         tString help ( ci->help );
00645         if ( help != "UNDOCUMENTED" )
00646         {
00647             tString line;
00648             line << ci->title;
00649             line.SetPos( 30, false );
00650             line << help;
00651             s << line << '\n';
00652         }
00653     }
00654 }
00655 
00656 std::deque<tString> tConfItemBase::GetCommands(){
00657     std::deque<tString> ret;
00658     tConfItemMap & confmap = ConfItemMap();
00659     for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
00660     {
00661         tConfItemBase * ci = (*iter).second;
00662 
00663         ret.push_back(ci->title.ToLower());
00664     }
00665     return ret;
00666 }
00667 tConfItemBase *tConfItemBase::FindConfigItem(tString const &name) {
00668     tConfItemMap & confmap = ConfItemMap();
00669     tConfItemMap::iterator iter = confmap.find( name.ToUpper() );
00670     if ( iter != confmap.end() ) {
00671         return iter->second;
00672     } else {
00673         return 0;
00674     }
00675 }
00676 
00677 /*
00678   void tConfItemBase::ReadVal(std::istream &s);
00679   void tConfItemBase::WriteVal(std::istream &s);
00680 */
00681 
00682 /*
00683 tString configfile(){
00684         tString f;
00685         //#ifndef WIN32
00686         //  f << static_cast<const char *>(getenv("HOME"));
00687         //  f << st_LogDir << 
00688         //  f << "/.ArmageTronrc";
00689         //#else
00690                 const tPath& vpath = tDirectories::Var();
00691                 for ( int prio = vpath.MaxPriority(); prio>=0; --prio )
00692                 {
00693                         tString path = vpath.Path( prio );
00694                         prio = -1;
00695 
00696         f << st_LogDir << "/user.cfg";
00697         //#endif
00698         return f;
00699 }
00700 */
00701 
00702 bool tConfItemBase::LoadPlayback( bool print )
00703 {
00704     if ( !tRecorder::IsPlayingBack() )
00705         return false;
00706 
00707     // read line from recording
00708     tString line;
00709     while ( tRecorder::Playback( recordingSection, line ) )
00710     {
00711         tRecorder::Record( recordingSection, line );
00712         if ( !s_VetoPlayback( line ) )
00713         {
00714             // process line
00715             if ( print ) con << "Playback input : " << line << '\n';
00716             std::stringstream str(static_cast< char const * >( line ) );
00717             tConfItemBase::LoadLine(str);
00718         }
00719     }
00720 
00721     return true;
00722 }
00723 
00724 static bool Load( const tPath& path, const char* filename )
00725 {
00726     // read from file
00727     if ( !filename )
00728     {
00729         return false;
00730     }
00731 
00732     std::ifstream s;
00733     if ( path.Open( s, filename ) )
00734     {
00735         tConfItemBase::LoadAll( s );
00736         return true;
00737     }
00738     else
00739     {
00740         return false;
00741     }
00742 }
00743 
00744 // flag indicating whether settings were read from a playback
00745 static bool st_settingsFromRecording = false;
00746 
00747 #ifdef DEDICATED
00748 tString extraConfig("NONE");
00749 
00750 class tExtraConfigCommandLineAnalyzer: public tCommandLineAnalyzer
00751 {
00752 private:
00753     virtual bool DoAnalyze( tCommandLineParser & parser )
00754     {
00755         return parser.GetOption(extraConfig, "--extraconfig", "-e");
00756     }
00757 
00758     virtual void DoHelp( std::ostream & s )
00759     {                                      //
00760         s << "-e, --extraconfig            : open an extra configuration file after\n"
00761         << "                               settings_dedicated.cfg\n";
00762     }
00763 };
00764 
00765 static tExtraConfigCommandLineAnalyzer s_extraAnalyzer;
00766 #endif
00767 
00768 // configuration files to load. The first one found will be loaded, and
00769 // only the very first one will be written to. Use it to protect stable client's
00770 // config from the experimental client's wrath.
00771 char const * st_userConfigs[] = { "user_3_1.cfg", "user_3_0.cfg", "user.cfg", 0 };
00772 
00773 static void st_InstallSigHupHandler();
00774 
00775 void st_LoadConfig( bool printChange )
00776 {
00777     st_InstallSigHupHandler();
00778 
00779     const tPath& var = tDirectories::Var();
00780     const tPath& config = tDirectories::Config();
00781     const tPath& data = tDirectories::Data();
00782 
00783     tConfItemBase::printChange=printChange;
00784 #ifdef DEDICATED
00785     tConfItemBase::printErrors=false;
00786 #endif
00787     {
00788         // load the first available user configuration file
00789         char const * const * userConfig = st_userConfigs;
00790         while ( *userConfig && !Load( var, *userConfig ) )
00791             userConfig++;
00792     }
00793     tConfItemBase::printErrors=true;
00794 
00795     Load( config, "settings.cfg" );
00796 #ifdef DEDICATED
00797     Load( config, "settings_dedicated.cfg" );
00798     if( extraConfig != "NONE" ) Load( config, extraConfig );
00799 #else
00800     if (st_FirstUse)
00801     {
00802         Load( config, "default.cfg" );
00803     }
00804 #endif
00805 
00806     Load( data, "moviepack/settings.cfg" );
00807 
00808     Load( config, "autoexec.cfg" );
00809     Load( var, "autoexec.cfg" );
00810 
00811     // load configuration from playback
00812     tConfItemBase::LoadPlayback();
00813     st_settingsFromRecording = tRecorder::IsPlayingBack();
00814 
00815     tConfItemBase::printChange=true;
00816 }
00817 
00818 void st_SaveConfig()
00819 {
00820     // don't save while playing back
00821     if ( st_settingsFromRecording )
00822     {
00823         return;
00824     }
00825 
00826     std::ofstream s;
00827     if ( tDirectories::Var().Open( s, st_userConfigs[0], std::ios::out, true ) )
00828     {
00829         tConfItemBase::SaveAll(s);
00830     }
00831     else
00832     {
00833         tOutput o("$config_file_write_error");
00834         con << o;
00835         std::cerr << o;
00836     }
00837 }
00838 
00839 void st_LoadConfig()
00840 {
00841     st_LoadConfig( false );
00842 }
00843 
00844 static void st_DoHandleSigHup()
00845 {
00846     con << tOutput("$config_sighup");
00847     st_SaveConfig();
00848     st_LoadConfig();
00849 }
00850 
00851 static void st_HandleSigHup( int signal )
00852 {
00853     st_ToDo_Signal( st_DoHandleSigHup );
00854 }
00855 
00856 static void st_InstallSigHupHandler()
00857 {
00858 #ifndef WIN32
00859     static bool installed = false;
00860     if ( !installed )
00861     {
00862         signal( SIGHUP, &st_HandleSigHup );
00863         installed = true;
00864     }
00865 #endif
00866 }
00867 
00868 void tConfItemLine::ReadVal(std::istream &s){
00869     tString dummy;
00870     dummy.ReadLine(s, true);
00871     if(strcmp(dummy,*target)){
00872         if (printChange)
00873         {
00874             tColoredString oldval;
00875             oldval << *target << tColoredString::ColorString(1,1,1);
00876             tColoredString newval;
00877             newval << dummy << tColoredString::ColorString(1,1,1);
00878             tOutput o;
00879             o.SetTemplateParameter(1, title);
00880             o.SetTemplateParameter(2, oldval);
00881             o.SetTemplateParameter(3, newval);
00882             o << "$config_value_changed";
00883             con << o;
00884         }
00885         *target=dummy;
00886         changed=true;
00887 
00888         ExecuteCallback();
00889     }
00890 
00891     *target=dummy;
00892 }
00893 
00894 
00895 void tConfItemLine::WriteVal(std::ostream &s){
00896     tConfItem<tString>::WriteVal(s);
00897 
00898     // double trailing backslash so it is read back as a single backslash, not
00899     // a continued line (HACK: this would actually be the job of the calling function)
00900     if ( target->Len() >= 2 &&
00901             target->operator()(target->Len() - 2) == '\\' )
00902         s << "\\";
00903 }
00904 
00905 tConfItemFunc::tConfItemFunc
00906 (const char *title, CONF_FUNC *func)
00907     :tConfItemBase(title),f(func){}
00908 
00909 tConfItemFunc::~tConfItemFunc(){}
00910 
00911 void tConfItemFunc::ReadVal(std::istream &s){(*f)(s);}
00912 void tConfItemFunc::WriteVal(std::ostream &){}
00913 
00914 bool tConfItemFunc::Save(){return false;}
00915 
00916 void st_Include( tString const & file, bool reportError )
00917 {
00918     // refuse to load illegal paths
00919     if( !tPath::IsValidPath( file ) )
00920         return;
00921 
00922     if ( !Load( tDirectories::Var(), file ) )
00923     {
00924         if (!Load( tDirectories::Config(), file ) && reportError )
00925         {
00926             con << tOutput( "$config_include_not_found", file );
00927         }
00928     }
00929 }
00930 
00931 static void Include(std::istream& s, bool error )
00932 {
00933     tString file;
00934     s >> file;
00935 
00936     st_Include( file, error );
00937 }
00938 
00939 static void Include(std::istream& s )
00940 {
00941     Include( s, true );
00942 }
00943 
00944 static void SInclude(std::istream& s )
00945 {
00946     Include( s, false );
00947 }
00948 
00949 static tConfItemFunc s_Include("INCLUDE",  &Include);
00950 static tConfItemFunc s_SInclude("SINCLUDE",  &SInclude);
00951 
00952 // obsoleted settings that still are around in some distruted configuration files
00953 static void st_Dummy(std::istream &s){tString rest; rest.ReadLine(s);}
00954 static tConfItemFunc st_DummyMpHack("MOVIEPACK_HACK",&st_Dummy);
00955 
00956 #ifdef DEDICATED
00957 // settings missing in the dedicated server
00958 static tConfItemFunc st_Dummy1("ARENA_WALL_SHADOW_NEAR", &st_Dummy);
00959 static tConfItemFunc st_Dummy2("ARENA_WALL_SHADOW_DIST", &st_Dummy);
00960 static tConfItemFunc st_Dummy3("ARENA_WALL_SHADOW_SIDEDIST", &st_Dummy);
00961 static tConfItemFunc st_Dummy4("ARENA_WALL_SHADOW_SIZE", &st_Dummy);
00962 static tConfItemFunc st_Dummy5("BUG_TRANSPARENCY_DEMAND", &st_Dummy);
00963 static tConfItemFunc st_Dummy6("BUG_TRANSPARENCY", &st_Dummy);
00964 static tConfItemFunc st_Dummy7("SHOW_OWN_NAME", &st_Dummy);
00965 static tConfItemFunc st_Dummy8("FADEOUT_NAME_DELAY", &st_Dummy);
00966 static tConfItemFunc st_Dummy9("FLOOR_MIRROR_INT", &st_Dummy);
00967 #endif
00968 #ifndef DEBUG
00969 // settings missing in optimized mode
00970 static tConfItemFunc st_Dummy10("SIMULATE_RECEIVE_PACKET_LOSS", &st_Dummy);
00971 static tConfItemFunc st_Dummy11("SIMULATE_SEND_PACKET_LOSS", &st_Dummy);
00972 #endif
00973 

Generated on Sat Mar 15 22:55:59 2008 for Armagetron Advanced by  doxygen 1.5.4