1 /*
2
3 *************************************************************************
4
5 ArmageTron -- Just another Tron Lightcycle Game in 3D.
6 Copyright (C) 2000 Manuel Moos (manuel@moosnet.de)
7
8 **************************************************************************
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 ***************************************************************************
25
26 */
27
28 #include "config.h"
29 #include <fstream>
30 #include <iomanip>
31 #include <iostream>
32 #include "tConfiguration.h"
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <string>
36 #include <sstream>
37 #include "tString.h"
38 #include "tToDo.h"
39 #include "tConsole.h"
40 #include "tDirectories.h"
41 #include "tLocale.h"
42 #include "tRecorder.h"
43 #include "tCommandLine.h"
44 #include "tResourceManager.h"
45 #include "tError.h"
46
47 #include <vector>
48 #include <string.h>
49
50 #ifndef WIN32
51 #include <signal.h>
52 #endif
53
54 /***********************************************************************
55 * The new Configuration interface, currently not completely implemented
56 */
57
58 #ifndef NEW_CONFIGURATION_NO_COMPILE
59
60 // Use this function to register your own configuration directive
61 // returns true if it was successful, false if not
62 // should return true even if it didn't register the new directive because
63 // it was already there
registerDirective(string newDirective,string defValue)64 bool tConfiguration::registerDirective(string newDirective, string defValue) {
65 // THIS IS A STUB
66 }
67
68 // Use this function to set a configuration directive from a string
setDirective(string oldDirective,string newValue)69 bool tConfiguration::setDirective(string oldDirective, string newValue) {
70 // THIS IS A STUB
71 }
72
73 // Use this function to set a configuration directive from an int
setDirective(string oldDirective,int newValue)74 bool tConfiguration::setDirective(string oldDirective, int newValue) {
75 // THIS IS A STUB
76 }
77
78 // Use this function to set a configuration directive from a float
setDirective(string oldDirective,double newValue)79 bool tConfiguration::setDirective(string oldDirective, double newValue) {
80 // THIS IS A STUB
81 }
82
83 // Use this function to set a configuration directive from a bool
setDirective(string oldDirective,bool newValue)84 bool tConfiguration::setDirective(string oldDirective, bool newValue) {
85 // THIS IS A STUB
86 }
87
88 // Use this function to get a configuration directive as a string
getDirective(string oldDirective)89 const string& tConfiguration::getDirective(string oldDirective) {
90 // THIS IS A STUB
91 }
92
93 // Use this function to get a configuration directive as an int
getDirectiveI(string oldDirective)94 const int& tConfiguration::getDirectiveI(string oldDirective) {
95 // THIS IS A STUB
96 }
97
98 // Use this function to get a configuration directive as a double
getDirectiveF(string oldDirective)99 const double& tConfiguration::getDirectiveF(string oldDirective) {
100 // THIS IS A STUB
101 }
102
103 // Use this function to get a configuration directive as a bool
getDirectiveB(string oldDirective)104 const bool& tConfiguration::getDirectiveB(string oldDirective) {
105 // THIS IS A STUB
106 }
107
108 // Use this function to load a file
109 // You *MUST* pass it a complete path from the root directory!
110 // Returns TRUE if it can open the file and load at least some of it
111 // Returns FALSE if complete failure.
LoadFile(string filename)112 bool tConfiguration::LoadFile(string filename) {
113 // THIS IS A STUB
114 }
115
116 // Use this function to save current configuration to files
117 // Returns TRUE on success, FALSE on failure
SaveFile()118 bool tConfiguration::SaveFile() {
119 // THIS IS A STUB
120 }
121
122 // This function is used internally to actually set each directive
_setDirective(string oldDirective,tConfigurationItem & newItem)123 bool tConfiguration::_setDirective(string oldDirective, tConfigurationItem& newItem) {
124 // THIS IS A STUB
125 }
126
127 // This function registers basic configuration directives
128 // Create a new configuration directive by going to this function and
129 // putting the appropriate line, then just use it in the game
130 // It registers global defaults, but not object-specific defaults
_registerDefaults()131 void tConfiguration::_registerDefaults() {
132 // THIS IS A STUB
133 }
134
135 tConfiguration* tConfiguration::_instance = 0;
136
GetConfiguration()137 const tConfiguration* tConfiguration::GetConfiguration() {
138 if(_instance = 0) {
139 _instance = new tConfiguration;
140 }
141
142 return _instance;
143 }
144
145 #endif
146 /*
147 * The old stuff follows
148 ************************************************************************/
149
150 bool tConfItemBase::printChange=true;
151 bool tConfItemBase::printErrors=true;
152
153
154 //! @param newLevel the new access level to set over the course of the lifetime of this object
155 //! @param allowElevation only if set to true, getting higher access rights is possible. Use with extreme care.
tCurrentAccessLevel(tAccessLevel newLevel,bool allowElevation)156 tCurrentAccessLevel::tCurrentAccessLevel( tAccessLevel newLevel, bool allowElevation )
157 {
158 // prevent elevation
159 if ( !allowElevation && newLevel < currentLevel_ )
160 {
161 // you probably want to know when this happens in the debugger
162 st_Breakpoint();
163 newLevel = currentLevel_;
164 }
165
166 lastLevel_ = currentLevel_;
167 currentLevel_ = newLevel;
168 }
169
170
tCurrentAccessLevel()171 tCurrentAccessLevel::tCurrentAccessLevel()
172 {
173 lastLevel_ = currentLevel_;
174 }
175
~tCurrentAccessLevel()176 tCurrentAccessLevel::~tCurrentAccessLevel()
177 {
178 currentLevel_ = lastLevel_;
179 }
180
181 //! returns the current access level
GetAccessLevel()182 tAccessLevel tCurrentAccessLevel::GetAccessLevel()
183 {
184 tASSERT( currentLevel_ != tAccessLevel_Invalid );
185 return currentLevel_;
186 }
187
188 // returns the name of an access level
GetName(tAccessLevel level)189 tString tCurrentAccessLevel::GetName( tAccessLevel level )
190 {
191 std::ostringstream s;
192 s << "$config_accesslevel_" << level;
193 return tString( tOutput( s.str().c_str() ) );
194 }
195
196 tAccessLevel tCurrentAccessLevel::currentLevel_ = tAccessLevel_Invalid; //!< the current access level
197
tAccessLevelSetter(tConfItemBase & item,tAccessLevel level)198 tAccessLevelSetter::tAccessLevelSetter( tConfItemBase & item, tAccessLevel level )
199 {
200 #ifdef KRAWALL_SERVER
201 item.requiredLevel = level;
202 #endif
203 }
204
205 static std::map< tString, tConfItemBase * > * st_confMap = 0;
ConfItemMap()206 tConfItemBase::tConfItemMap & tConfItemBase::ConfItemMap()
207 {
208 if (!st_confMap)
209 st_confMap = tNEW( tConfItemMap );
210 return *st_confMap;
211 }
212
213 static bool st_preventCasacl = false;
214
tCasaclPreventer(bool prevent)215 tCasaclPreventer::tCasaclPreventer( bool prevent )
216 {
217 previous_ = st_preventCasacl;
218 st_preventCasacl = prevent;
219 }
220
~tCasaclPreventer()221 tCasaclPreventer::~tCasaclPreventer()
222 {
223 st_preventCasacl = previous_;
224 }
225
226 // changes the access level of a configuration item
227 class tConfItemLevel: public tConfItemBase
228 {
229 public:
tConfItemLevel()230 tConfItemLevel()
231 : tConfItemBase( "ACCESS_LEVEL" )
232 {
233 requiredLevel = tAccessLevel_Owner;
234 }
235
ReadVal(std::istream & s)236 virtual void ReadVal(std::istream &s)
237 {
238 // read name and access level
239 tString name;
240 s >> name;
241
242 int levelInt;
243 s >> levelInt;
244 tAccessLevel level = static_cast< tAccessLevel >( levelInt );
245
246 if ( s.fail() )
247 {
248 if(printErrors)
249 {
250 con << tOutput( "$access_level_usage" );
251 }
252 return;
253 }
254
255 // make name uppercase:
256 tToUpper( name );
257
258 // find the item
259 tConfItemMap & confmap = ConfItemMap();
260 tConfItemMap::iterator iter = confmap.find( name );
261 if ( iter != confmap.end() )
262 {
263 // and change the level
264 tConfItemBase * ci = (*iter).second;
265 if ( ci->requiredLevel != level )
266 {
267 ci->requiredLevel = level;
268 if(printChange)
269 {
270 con << tOutput( "$access_level_change", name, tCurrentAccessLevel::GetName( level ) );
271 }
272 }
273 }
274 else if(printErrors)
275 {
276 con << tOutput( "$config_command_unknown", name );
277 }
278 }
279
WriteVal(std::ostream & s)280 virtual void WriteVal(std::ostream &s)
281 {
282 tASSERT(0);
283 }
284
Writable()285 virtual bool Writable(){
286 return false;
287 }
288
Save()289 virtual bool Save(){
290 return false;
291 }
292 };
293
294 static tConfItemLevel st_confLevel;
295
296 #ifdef KRAWALL_SERVER
297
298 static char const *st_casacl = "CASACL";
299
300 //! casacl (Check And Set ACcess Level) command: elevates the access level for the context of the current configuration file
301 class tCasacl: tConfItemBase
302 {
303 public:
tCasacl()304 tCasacl()
305 : tConfItemBase( st_casacl )
306 {
307 requiredLevel = tAccessLevel_Program;
308 }
309
ReadVal(std::istream & s)310 virtual void ReadVal( std::istream & s )
311 {
312 int required_int = 0, elevated_int = 20;
313
314 // read required and elevated access levels
315 s >> required_int;
316 s >> elevated_int;
317
318 tAccessLevel elevated = static_cast< tAccessLevel >( elevated_int );
319 tAccessLevel required = static_cast< tAccessLevel >( required_int );
320
321 if ( s.fail() )
322 {
323 con << tOutput( "$casacl_usage" );
324 throw tAbortLoading( st_casacl );
325 }
326 else if ( tCurrentAccessLevel::GetAccessLevel() > required )
327 {
328 con << tOutput( "$access_level_error",
329 "SUDO",
330 tCurrentAccessLevel::GetName( required ),
331 tCurrentAccessLevel::GetName( tCurrentAccessLevel::GetAccessLevel() )
332 );
333 throw tAbortLoading( st_casacl );
334 }
335 else if ( st_preventCasacl )
336 {
337 con << tOutput( "$casacl_not_allowed" );
338 throw tAbortLoading( st_casacl );
339 }
340 else
341 {
342 tString().ReadLine(s); // prevent commands following this one without a newline
343 tCurrentAccessLevel::currentLevel_ = elevated;
344 }
345 }
346
WriteVal(std::ostream & s)347 virtual void WriteVal(std::ostream &s)
348 {
349 tASSERT(0);
350 }
351
Writable()352 virtual bool Writable(){
353 return false;
354 }
355
Save()356 virtual bool Save(){
357 return false;
358 }
359 };
360
361 static tCasacl st_sudo;
362
363 #endif
364
365 bool st_FirstUse=true;
366 static tConfItem<bool> fu("FIRST_USE",st_FirstUse);
367 //static tConfItem<bool> fu("FIRST_USE","help_first_use",st_FirstUse);
368
369
tAbortLoading(char const * command)370 tAbortLoading::tAbortLoading( char const * command )
371 : command_( command )
372 {
373 }
374
DoGetName() const375 tString tAbortLoading::DoGetName() const
376 {
377 return tString(tOutput( "$abort_loading_name"));
378 }
379
DoGetDescription() const380 tString tAbortLoading::DoGetDescription() const
381 {
382 return tString(tOutput( "$abort_loading_description", command_ ));
383 }
384
tConfItemBase(const char * t)385 tConfItemBase::tConfItemBase(const char *t)
386 :id(-1),title(t),
387 changed(false){
388
389 tConfItemMap & confmap = ConfItemMap();
390 if ( confmap.find( title ) != confmap.end() )
391 tERR_ERROR_INT("Two tConfItems with the same name " << t << "!");
392
393 // compose help name
394 tString helpname;
395 helpname << title << "_help";
396 tToLower( helpname );
397
398 const_cast<tOutput&>(help).AddLocale(helpname);
399
400 confmap[title] = this;
401
402 requiredLevel = tAccessLevel_Admin;
403 setLevel = tAccessLevel_Owner;
404 }
405
tConfItemBase(const char * t,const tOutput & h)406 tConfItemBase::tConfItemBase(const char *t, const tOutput& h)
407 :id(-1),title(t), help(h),
408 changed(false){
409
410 tConfItemMap & confmap = ConfItemMap();
411 if ( confmap.find( title ) != confmap.end() )
412 tERR_ERROR_INT("Two tConfItems with the same name " << t << "!");
413
414 confmap[title] = this;
415
416 requiredLevel = tAccessLevel_Admin;
417 setLevel = tAccessLevel_Owner;
418 }
419
~tConfItemBase()420 tConfItemBase::~tConfItemBase()
421 {
422 tConfItemMap & confmap = ConfItemMap();
423 confmap.erase(title);
424 if ( confmap.size() == 0 )
425 {
426 delete st_confMap;
427 st_confMap = 0;
428 }
429 }
430
SaveAll(std::ostream & s)431 void tConfItemBase::SaveAll(std::ostream &s){
432 tConfItemMap & confmap = ConfItemMap();
433 for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
434 {
435 tConfItemBase * ci = (*iter).second;
436 if (ci->Save()){
437 s << std::setw(28) << ci->title << " ";
438 ci->WriteVal(s);
439 s << '\n';
440 }
441 }
442 }
443
EatWhitespace(std::istream & s)444 int tConfItemBase::EatWhitespace(std::istream &s){
445 int c=' ';
446
447 while(isblank(c) &&
448 c!='\n' &&
449 s.good() &&
450 !s.eof())
451 c=s.get();
452
453 if( s.good() )
454 {
455 s.putback(c);
456 }
457
458 return c;
459 }
460
LoadLine(std::istream & s)461 void tConfItemBase::LoadLine(std::istream &s){
462 if(!s.eof() && s.good()){
463 tString name;
464 s >> name;
465
466 // make name uppercase:
467 tToUpper( name );
468
469 bool found=false;
470
471 if (name[0]=='#'){ // comment. ignore rest of line
472 char c=' ';
473 while(c!='\n' && s.good() && !s.eof()) c=s.get();
474 found=true;
475 }
476
477 if (strlen(name)==0) // ignore empty lines
478 found=true;
479
480 tConfItemMap & confmap = ConfItemMap();
481 tConfItemMap::iterator iter = confmap.find( name );
482 if ( iter != confmap.end() )
483 {
484 tConfItemBase * ci = (*iter).second;
485
486 bool cb=ci->changed;
487 ci->changed=false;
488
489 if ( ci->requiredLevel >= tCurrentAccessLevel::GetAccessLevel() )
490 {
491 ci->setLevel = tCurrentAccessLevel::GetAccessLevel();
492
493 ci->ReadVal(s);
494 if (ci->changed)
495 {
496 ci->WasChanged();
497 }
498 else
499 {
500 ci->changed=cb;
501 }
502 }
503 else
504 {
505 tString discard;
506 discard.ReadLine(s);
507
508 con << tOutput( "$access_level_error",
509 name,
510 tCurrentAccessLevel::GetName( ci->requiredLevel ),
511 tCurrentAccessLevel::GetName( tCurrentAccessLevel::GetAccessLevel() )
512 );
513 return;
514 }
515
516 found=true;
517 }
518
519 if (!found){
520 // eat rest of input line
521 tString rest;
522 rest.ReadLine( s );
523
524 if (printErrors)
525 {
526 tOutput o;
527 o.SetTemplateParameter(1, name);
528 o << "$config_command_unknown";
529 con << o;
530
531 if (printChange)
532 {
533 int sim_maxlen=-1;
534
535 for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
536 {
537 tConfItemBase * ci = (*iter).second;
538 if (strstr(ci->title,name) &&
539 static_cast<int>(strlen(ci->title)) > sim_maxlen)
540 sim_maxlen=strlen(ci->title);
541 }
542
543 if (sim_maxlen>0 && printChange ){
544 int len = name.Len()-1;
545 int printMax = 1 + 3 * len * len * len;
546 con << tOutput("$config_command_other");
547 for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
548 {
549 tConfItemBase * ci = (*iter).second;
550 if (strstr(ci->title,name))
551 {
552 tString help ( ci->help );
553 if ( --printMax > 0 )
554 {
555 tString mess;
556 mess << ci->title;
557 mess.SetPos( sim_maxlen+2, false );
558 mess << "(";
559 mess << help;
560 mess << ")\n";
561 con << mess;
562 }
563 }
564 }
565 if (printMax <= 0 )
566 con << tOutput("$config_command_more");
567 }
568 }
569 else
570 {
571 con << '\n';
572 }
573 }
574 }
575 }
576
577 // std::cout << line << " lines read.\n";
578 }
579
580 static char const * recordingSection = "CONFIG";
581
582 /*
583 bool LoadAllHelper(std::istream * s)
584 {
585 tString line;
586
587 // read line from recording
588 if ( s || !tRecorder::Playback( recordingSection, line ) )
589 {
590 // return on failure
591 if (!s)
592 return false;
593
594 // read line from stream
595 line.ReadLine( *s );
596
597 // write line to recording
598 tRecorder::Record( recordingSection, line );
599 }
600 line << '\n';
601
602 // process line
603 std::stringstream str(static_cast< char const * >( line ) );
604 tConfItemBase::LoadLine(str);
605
606 return true;
607 }
608 */
609
610 // test if a line should enter the recording; check if the line contains one of the passed
611 // substrings. The array of substrings is supposed to be zero terminated.
s_Veto(tString line_in,std::vector<tString> const & vetos)612 static bool s_Veto( tString line_in, std::vector< tString > const & vetos )
613 {
614 // make name uppercase:
615 tToUpper( line_in );
616
617 // eat whitespace at the beginning
618 char const * test = line_in;
619 while( isblank(*test) )
620 test++;
621
622 // skip "LAST_"
623 tString line( test );
624 if ( line.StartsWith( "LAST_" ) )
625 line = tString( static_cast< char const * >(line) + 5 );
626
627 // iterate throug vetoed config items and test each one
628 for ( std::vector< tString >::const_iterator iter = vetos.begin(); iter != vetos.end(); ++iter )
629 {
630 tString const & veto = *iter;
631
632 if ( line.StartsWith( veto ) )
633 {
634 #ifdef DEBUG_X
635 if ( !line.StartsWith( "INCLUDE" ) && tRecorder::IsRunning() )
636 {
637 con << "Veto on config line: " << line << "\n";
638 }
639 #endif
640
641 return true;
642 }
643 }
644
645 return false;
646 }
647
648 // test if a line should be read from a recording
649 // sound and video mode settings shold not
st_Stringify(char const * vetos[])650 static std::vector< tString > st_Stringify( char const * vetos[] )
651 {
652 std::vector< tString > ret;
653
654 char const * * v = vetos;
655 while ( *v )
656 {
657 ret.push_back( tString( *v ) );
658 ++v;
659 }
660
661 return ret;
662 }
663
s_VetoPlayback(tString const & line)664 static bool s_VetoPlayback( tString const & line )
665 {
666 static char const * vetos_char[]=
667 { "USE_DISPLAYLISTS", "CHECK_ERRORS", "ZDEPTH",
668 "COLORDEPTH", "FULLSCREEN ", "ARMAGETRON_LAST_WINDOWSIZE",
669 "ARMAGETRON_WINDOWSIZE", "ARMAGETRON_LAST_SCREENMODE",
670 "ARMAGETRON_SCREENMODE", "CUSTOM_SCREEN", "SOUND",
671 "PASSWORD", "ADMIN_PASS",
672 "ZTRICK", "MOUSE_GRAB", "PNG_SCREENSHOT", // "WHITE_SPARKS", "SPARKS",
673 "KEEP_WINDOW_ACTIVE", "TEXTURE_MODE", "TEXTURES_HI", "LAG_O_METER", "INFINITY_PLANE",
674 "SKY_WOBBLE", "LOWER_SKY", "UPPER_SKY", "DITHER", "HIGH_RIM", "FLOOR_DETAIL",
675 "FLOOR_MIRROR", "SHOW_FPS", "TEXT_OUT", "SMOOTH_SHADING", "ALPHA_BLEND",
676 "PERSP_CORRECT", "POLY_ANTIALIAS", "LINE_ANTIALIAS", "FAST_FORWARD_MAXSTEP",
677 "DEBUG_GNUPLOT", "FLOOR_", "MOVIEPACK_", "RIM_WALL_",
678 0 };
679
680 static std::vector< tString > vetos = st_Stringify( vetos_char );
681
682 // delegate
683 return s_Veto( line, vetos );
684 }
685
686 // test if a line should enter the recording
687 // passwords should not.
s_VetoRecording(tString const & line)688 static bool s_VetoRecording( tString const & line )
689 {
690 static char const * vetos_char[]=
691 { "#", "PASSWORD", "ADMIN_PASS", "LOCAL_USER", "LOCAL_TEAM",
692 0 };
693
694 static std::vector< tString > vetos = st_Stringify( vetos_char );
695
696 // delegate
697 return s_Veto( line, vetos ) || s_VetoPlayback( line );
698 }
699
700
701 //! @param s stream to read from
702 //! @param record set to true if the configuration is to be recorded and played back. That's usually only required if s is a file stream.
LoadAll(std::istream & s,bool record)703 void tConfItemBase::LoadAll(std::istream &s, bool record ){
704 tCurrentAccessLevel levelResetter;
705
706 try{
707
708 while(!s.eof() && s.good())
709 {
710 tString line;
711
712 // read line from stream
713 line.ReadLine( s );
714
715 /// concatenate lines ending in a backslash
716 while ( line.Len() > 1 && line[line.Len()-2] == '\\' && s.good() && !s.eof() )
717 {
718 line[line.Len()-2] = '\0';
719
720 // unless it is a double backslash
721 if ( line.Len() > 2 && line[line.Len()-3] == '\\' )
722 {
723 break;
724 }
725
726 line.SetLen( line.Len()-1 );
727 tString rest;
728 rest.ReadLine( s );
729 line << rest;
730 }
731
732 if ( line.Len() <= 1 )
733 continue;
734
735 // write line to recording
736 if ( record && !s_VetoRecording( line ) )
737 {
738 // don't record supid admins' instant chat logins
739 static tString instantChat("INSTANT_CHAT_STRING");
740 if ( line.StartsWith( instantChat ) && strstr( line, "/login" ) )
741 {
742 tString newLine = line.SubStr( 0, strstr( line, "/login" ) - (char const *)line );
743 newLine += "/login NONE";
744 if ( line[strlen(line)-1] == '\\' )
745 newLine += '\\';
746 tRecorder::Record( recordingSection, newLine );
747 }
748 else
749 tRecorder::Record( recordingSection, line );
750 }
751
752 // std::cout << line << '\n';
753
754 // process line
755 // line << '\n';
756 if ( !record || !tRecorder::IsPlayingBack() || s_VetoPlayback( line ) )
757 {
758 std::stringstream str(static_cast< char const * >( line ) );
759 tConfItemBase::LoadLine(str);
760 // std::cout << line << '\n';
761 }
762 }
763 }
764 catch( tAbortLoading const & e )
765 {
766 // loading was aborted
767 con << e.GetDescription() << "\n";
768 }
769 }
770
DocAll(std::ostream & s)771 void tConfItemBase::DocAll(std::ostream &s){
772 tConfItemMap & confmap = ConfItemMap();
773 for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
774 {
775 tConfItemBase * ci = (*iter).second;
776
777 tString help ( ci->help );
778 if ( help != "UNDOCUMENTED" )
779 {
780 tString line;
781 line << ci->title;
782 line.SetPos( 30, false );
783 line << help;
784 s << line << '\n';
785 }
786 }
787 }
788
789 //! @param s stream to read from
790 //! @param record set to true if the configuration is to be recorded and played back. That's usually only required if s is a file stream, so it defaults to true here.
LoadAll(std::ifstream & s,bool record)791 void tConfItemBase::LoadAll(std::ifstream &s, bool record )
792 {
793 std::istream &ss(s);
794 LoadAll( ss, record );
795 }
796
797
798 //! @param s file stream to be used for reading later
799 //! @param filename name of the file to open
800 //! @param path whether to look in var directory
801 //! @return success flag
OpenFile(std::ifstream & s,tString const & filename,SearchPath path)802 bool tConfItemBase::OpenFile( std::ifstream & s, tString const & filename, SearchPath path )
803 {
804 bool ret = ( ( path & Config ) && tDirectories::Config().Open(s, filename ) ) || ( ( path & Var ) && st_StringEndsWith(filename, ".cfg") && tDirectories::Var().Open(s, filename ) );
805
806 static char const * section = "INCLUDE_VOTE";
807 tRecorder::Playback( section, ret );
808 tRecorder::Record( section, ret );
809
810 return ret;
811 }
812
813 //! @param s file to read from
ReadFile(std::ifstream & s)814 void tConfItemBase::ReadFile( std::ifstream & s )
815 {
816 if ( !tRecorder::IsPlayingBack() )
817 {
818 tConfItemBase::LoadAll(s, true );
819 }
820 else
821 {
822 tConfItemBase::LoadPlayback();
823 }
824 }
825
826 /*
827 void tConfItemBase::ReadVal(std::istream &s);
828 void tConfItemBase::WriteVal(std::istream &s);
829 */
830
831 /*
832 tString configfile(){
833 tString f;
834 //#ifndef WIN32
835 // f << static_cast<const char *>(getenv("HOME"));
836 // f << st_LogDir <<
837 // f << "/.ArmageTronrc";
838 //#else
839 const tPath& vpath = tDirectories::Var();
840 for ( int prio = vpath.MaxPriority(); prio>=0; --prio )
841 {
842 tString path = vpath.Path( prio );
843 prio = -1;
844
845 f << st_LogDir << "/user.cfg";
846 //#endif
847 return f;
848 }
849 */
850
LoadPlayback(bool print)851 bool tConfItemBase::LoadPlayback( bool print )
852 {
853 if ( !tRecorder::IsPlayingBack() )
854 return false;
855
856 // read line from recording
857 tString line;
858 while ( tRecorder::Playback( recordingSection, line ) )
859 {
860 tRecorder::Record( recordingSection, line );
861 if ( !s_VetoPlayback( line ) )
862 {
863 // process line
864 if ( print ) con << "Playback input : " << line << '\n';
865 std::stringstream str(static_cast< char const * >( line ) );
866 tConfItemBase::LoadLine(str);
867 }
868 }
869
870 return true;
871 }
872
Load(const tPath & path,const char * filename)873 static bool Load( const tPath& path, const char* filename )
874 {
875 // read from file
876 if ( !filename )
877 {
878 return false;
879 }
880
881 std::ifstream s;
882 if ( path.Open( s, filename ) )
883 {
884 tConfItemBase::LoadAll( s, true );
885 return true;
886 }
887 else
888 {
889 return false;
890 }
891 }
892
893 // flag indicating whether settings were read from a playback
894 static bool st_settingsFromRecording = false;
895
896 #ifdef DEDICATED
897 tString extraConfig("NONE");
898
899 class tExtraConfigCommandLineAnalyzer: public tCommandLineAnalyzer
900 {
901 private:
DoAnalyze(tCommandLineParser & parser)902 virtual bool DoAnalyze( tCommandLineParser & parser )
903 {
904 return parser.GetOption(extraConfig, "--extraconfig", "-e");
905 }
906
DoHelp(std::ostream & s)907 virtual void DoHelp( std::ostream & s )
908 { //
909 s << "-e, --extraconfig : open an extra configuration file after\n"
910 << " settings_dedicated.cfg\n";
911 }
912 };
913
914 static tExtraConfigCommandLineAnalyzer s_extraAnalyzer;
915 #endif
916
917 static void st_InstallSigHupHandler();
918
st_LoadConfig(bool printChange)919 void st_LoadConfig( bool printChange )
920 {
921 // default include files are executed at owner level
922 tCurrentAccessLevel level( tAccessLevel_Owner, true );
923
924 st_InstallSigHupHandler();
925
926 const tPath& var = tDirectories::Var();
927 const tPath& config = tDirectories::Config();
928 const tPath& data = tDirectories::Data();
929
930 tConfItemBase::printChange=printChange;
931 #ifdef DEDICATED
932 tConfItemBase::printErrors=false;
933 #endif
934 {
935 Load( var, "user.cfg" );
936 }
937 tConfItemBase::printErrors=true;
938
939 Load( config, "settings.cfg" );
940 #ifdef DEDICATED
941 Load( config, "settings_dedicated.cfg" );
942 if( extraConfig != "NONE" ) Load( config, extraConfig );
943 #else
944 if (st_FirstUse)
945 {
946 Load( config, "default.cfg" );
947 }
948 #endif
949
950 Load( data, "moviepack/settings.cfg" );
951
952 Load( config, "autoexec.cfg" );
953 Load( var, "autoexec.cfg" );
954
955 // load configuration from playback
956 tConfItemBase::LoadPlayback();
957 st_settingsFromRecording = tRecorder::IsPlayingBack();
958
959 tConfItemBase::printChange=true;
960 }
961
st_SaveConfig()962 void st_SaveConfig()
963 {
964 // don't save while playing back
965 if ( st_settingsFromRecording )
966 {
967 return;
968 }
969
970 std::ofstream s;
971 if ( tDirectories::Var().Open( s, "user.cfg", std::ios::out, true ) )
972 {
973 tConfItemBase::SaveAll(s);
974 }
975 else
976 {
977 tOutput o("$config_file_write_error");
978 con << o;
979 std::cerr << o;
980 }
981 }
982
st_LoadConfig()983 void st_LoadConfig()
984 {
985 st_LoadConfig( false );
986 }
987
st_DoHandleSigHup()988 static void st_DoHandleSigHup()
989 {
990 con << tOutput("$config_sighup");
991 st_SaveConfig();
992 st_LoadConfig();
993 }
994
st_HandleSigHup(int signal)995 static void st_HandleSigHup( int signal )
996 {
997 st_ToDo_Signal( st_DoHandleSigHup );
998 }
999
st_InstallSigHupHandler()1000 static void st_InstallSigHupHandler()
1001 {
1002 #ifndef WIN32
1003 static bool installed = false;
1004 if ( !installed )
1005 {
1006 signal( SIGHUP, &st_HandleSigHup );
1007 installed = true;
1008 }
1009 #endif
1010 }
1011
ReadVal(std::istream & s)1012 void tConfItemLine::ReadVal(std::istream &s){
1013 tString dummy;
1014 dummy.ReadLine(s, true);
1015 if(strcmp(dummy,*target)){
1016 if (printChange)
1017 {
1018 tColoredString oldval;
1019 oldval << *target << tColoredString::ColorString(1,1,1);
1020 tColoredString newval;
1021 newval << dummy << tColoredString::ColorString(1,1,1);
1022 tOutput o;
1023 o.SetTemplateParameter(1, title);
1024 o.SetTemplateParameter(2, oldval);
1025 o.SetTemplateParameter(3, newval);
1026 o << "$config_value_changed";
1027 con << o;
1028 }
1029 *target=dummy;
1030 changed=true;
1031 }
1032
1033 *target=dummy;
1034 }
1035
1036
WriteVal(std::ostream & s)1037 void tConfItemLine::WriteVal(std::ostream &s){
1038 tConfItem<tString>::WriteVal(s);
1039
1040 // double trailing backslash so it is read back as a single backslash, not
1041 // a continued line (HACK: this would actually be the job of the calling function)
1042 if ( target->Len() >= 2 &&
1043 target->operator()(target->Len() - 2) == '\\' )
1044 s << "\\";
1045 }
1046
tConfItemFunc(const char * title,CONF_FUNC * func)1047 tConfItemFunc::tConfItemFunc
1048 (const char *title, CONF_FUNC *func)
1049 :tConfItemBase(title),f(func){}
1050
~tConfItemFunc()1051 tConfItemFunc::~tConfItemFunc(){}
1052
ReadVal(std::istream & s)1053 void tConfItemFunc::ReadVal(std::istream &s){(*f)(s);}
WriteVal(std::ostream &)1054 void tConfItemFunc::WriteVal(std::ostream &){}
1055
Save()1056 bool tConfItemFunc::Save(){return false;}
1057
Include(std::istream & s,bool error)1058 static void Include(std::istream& s, bool error )
1059 {
1060 // allow CASACL
1061 tCasaclPreventer allower(false);
1062
1063 tString file;
1064 s >> file;
1065
1066 // refuse to load illegal paths
1067 if( !tPath::IsValidPath( file ) )
1068 return;
1069
1070 if ( !tRecorder::IsPlayingBack() )
1071 {
1072 // really load include file
1073 if ( !st_StringEndsWith(file, ".cfg") || !Load( tDirectories::Var(), file ) )
1074 {
1075 if (!Load( tDirectories::Config(), file ) && error )
1076 {
1077 con << tOutput( "$config_include_not_found", file );
1078 }
1079 }
1080 }
1081 else
1082 {
1083 // just read configuration, and don't forget to reset the config level
1084 tCurrentAccessLevel levelResetter;
1085 tConfItemBase::LoadPlayback();
1086 }
1087
1088 // mark section
1089 char const * section = "INCLUDE_END";
1090 tRecorder::Record( section );
1091 tRecorder::PlaybackStrict( section );
1092
1093 }
1094
Include(std::istream & s)1095 static void Include(std::istream& s )
1096 {
1097 Include( s, true );
1098 }
1099
SInclude(std::istream & s)1100 static void SInclude(std::istream& s )
1101 {
1102 Include( s, false );
1103 }
1104
1105 static tConfItemFunc s_Include("INCLUDE", &Include);
1106 static tConfItemFunc s_SInclude("SINCLUDE", &SInclude);
1107
1108 // obsoleted settings that still are around in some distruted configuration files
st_Dummy(std::istream & s)1109 static void st_Dummy(std::istream &s){tString rest; rest.ReadLine(s);}
1110 static tConfItemFunc st_DummyMpHack("MOVIEPACK_HACK",&st_Dummy);
1111
1112 #ifdef DEDICATED
1113 // settings missing in the dedicated server
1114 static tConfItemFunc st_Dummy1("ARENA_WALL_SHADOW_NEAR", &st_Dummy);
1115 static tConfItemFunc st_Dummy2("ARENA_WALL_SHADOW_DIST", &st_Dummy);
1116 static tConfItemFunc st_Dummy3("ARENA_WALL_SHADOW_SIDEDIST", &st_Dummy);
1117 static tConfItemFunc st_Dummy4("ARENA_WALL_SHADOW_SIZE", &st_Dummy);
1118 static tConfItemFunc st_Dummy5("BUG_TRANSPARENCY_DEMAND", &st_Dummy);
1119 static tConfItemFunc st_Dummy6("BUG_TRANSPARENCY", &st_Dummy);
1120 static tConfItemFunc st_Dummy7("SHOW_OWN_NAME", &st_Dummy);
1121 static tConfItemFunc st_Dummy8("FADEOUT_NAME_DELAY", &st_Dummy);
1122 static tConfItemFunc st_Dummy9("FLOOR_MIRROR_INT", &st_Dummy);
1123 #endif
1124 #ifndef DEBUG
1125 // settings missing in optimized mode
1126 static tConfItemFunc st_Dummy10("SIMULATE_RECEIVE_PACKET_LOSS", &st_Dummy);
1127 static tConfItemFunc st_Dummy11("SIMULATE_SEND_PACKET_LOSS", &st_Dummy);
1128 #endif
1129
1130