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 #ifndef ArmageTron_CONFIGURATION_H
29 #define ArmageTron_CONFIGURATION_H
30 
31 #include "tList.h"
32 #include "tString.h"
33 #include "tLinkedList.h"
34 #include "tException.h"
35 #include "tLocale.h"
36 #include "tConsole.h"
37 #include "tLocale.h"
38 #include <iostream>
39 #include <ctype.h>
40 #include <string>
41 #include <map>
42 
43 // Define this to disable compiling the new interface
44 #define NEW_CONFIGURATION_NO_COMPILE
45 
46 /***********************************************************************
47  * The new Configuration interface, currently not completely implemented
48  */
49 
50 #ifndef NEW_CONFIGURATION_NO_COMPILE
51 
52 // This class stores a single configuration item
53 class tConfigurationItem {
54 public:
55     // Constructors for each data type supported
56     tConfigurationItem(string newValue);
57     tConfigurationItem(int newValue);
58     tConfigurationItem(double newValue);
59     tConfigurationItem(bool newValue);
60 
61     // Sets the source of this directive.  Possible values are:
62     //   GAME = set during the game
63     //   $path = path to the file it came from
64     //   DEFAULT = default value, set by the object that registered it
65     void setSource(string source);
66 
67     // Sets the destination of this directive.  Optional, defaults to "NONE"
68     // Possible values are:
69     //   NONE = throw it away when the game shuts down
70     //   $path = save it to $path
71     void setDestination(string dest);
72 
73     // Setters for each type of data supported
74     void setValue(string newValue);
75     void setValue(int newValue);
76     void setValue(double newValue);
77     void setValue(bool newValue);
78 private:
79     // _value is the authoritative value of the directive
80     string _value;
81 
82     string _source;
83     string _destination;
84 
85     int _intCache;
86     double _doubleCache;
87     bool _boolCache;
88 }
89 
90 // This class is the workhorse configuration class.  Use it and only it
91 class tConfiguration {
92 public:
93     // Use this function to get the instance of the configuration object
94     //   If it doesn't exist, it will be created
95     static const tConfiguration* GetConfiguration();
96 
97     // Use this function to register your own configuration directive
98     //   returns true if it was successful, false if not
99     //   should return true even if it didn't register the new directive because
100     //       it was already there
101     bool registerDirective(string newDirective, string defValue);
102 
103     // Use this function to set a configuration directive from a string
104     bool setDirective(string oldDirective, string newValue);
105 
106     // Use this function to set a configuration directive from an int
107     bool setDirective(string oldDirective, int newValue);
108 
109     // Use this function to set a configuration directive from a float
110     bool setDirective(string oldDirective, double newValue);
111 
112     // Use this function to set a configuration directive from a bool
113     bool setDirective(string oldDirective, bool newValue);
114 
115     // Use this function to get a configuration directive as a string
116     const string& getDirective(string oldDirective);
117 
118     // Use this function to get a configuration directive as an int
119     const int& getDirectiveI(string oldDirective);
120 
121     // Use this function to get a configuration directive as a double
122     const double& getDirectiveF(string oldDirective);
123 
124     // Use this function to get a configuration directive as a bool
125     const bool& getDirectiveB(string oldDirective);
126 
127     // Use this function to load a file
128     //  You *MUST* pass it a complete path from the root directory!
129     //  Returns TRUE if it can open the file and load at least some of it
130     //  Returns FALSE if complete failure.
131     bool LoadFile(string filename);
132 
133     // Use this function to save current configuration to files
134     //   Returns TRUE on success, FALSE on failure
135     bool SaveFile();
136 
137 private:
138     static tConfiguration* _instance;
139 
140     // This function is used internally to actually set each directive
141     bool _setDirective(string oldDirective, tConfigurationItem& newItem);
142 
143     // This function registers basic configuration directives
144     //  Create a new configuration directive by going to this function and
145     //  putting the appropriate line, then just use it in the game
146     //  It registers global defaults, but not object-specific defaults
147     void _registerDefaults();
148 }
149 
150 #endif
151 /*
152  * The old stuff follows
153  ************************************************************************/
154 
155 //! access levels for admin interfaces; lower numeric values are better
156 enum tAccessLevel
157 {
158     tAccessLevel_Owner = 0,        // the server owner
159     tAccessLevel_Admin = 1,        // one of his admins
160     tAccessLevel_Moderator = 2,    // one of the moderators
161     tAccessLevel_3 = 3,            // reserved
162     tAccessLevel_4 = 4,            // reserved
163     tAccessLevel_Armatrator = 5,   // reserved
164     tAccessLevel_6 = 6,            // reserved
165     tAccessLevel_TeamLeader = 7,   // a team leader
166     tAccessLevel_TeamMember = 8,   // a team member
167     tAccessLevel_9 = 9,            // reserved
168     tAccessLevel_10 = 10,          // reserved
169     tAccessLevel_11 = 11,          // reserved
170     tAccessLevel_Local      = 12,  // user with a local account
171     tAccessLevel_13 = 13,          // reserved
172     tAccessLevel_14 = 14,          // reserved
173     tAccessLevel_Remote = 15,      // user with remote account
174     tAccessLevel_DefaultAuthenticated = 15,     // default access level for authenticated users
175     tAccessLevel_FallenFromGrace = 16,          // authenticated, but not liked
176     tAccessLevel_Shunned = 17,          // authenticated, but disliked
177     tAccessLevel_18 = 18,          // reserved
178     tAccessLevel_Authenticated = 19,// any authenticated player
179     tAccessLevel_Program = 20,     // a regular player
180     tAccessLevel_21 = 21,          // reserved
181     tAccessLevel_22 = 22,          // reserved
182     tAccessLevel_23 = 23,          // reserved
183     tAccessLevel_24 = 24,          // reserved
184     tAccessLevel_25 = 25,          // reserved
185     tAccessLevel_Invalid = 255,    // completely invalid level
186     tAccessLevel_Default = 20
187 };
188 
189 //! class to temporarily allow/forbid the use of casacl
190 class tCasaclPreventer
191 {
192 public:
193     tCasaclPreventer( bool prevent = true );
194     ~tCasaclPreventer();
195 private:
196     bool previous_; //!< previous value of prevention flag
197 };
198 
199 //! class managing the current access level
200 class tCurrentAccessLevel
201 {
202     friend class tCasacl;
203 public:
204     //! for the lifetime of this object, change the user's admit level to the passed one.
205     tCurrentAccessLevel( tAccessLevel newLevel, bool allowElevation = false );
206 
207     //! does not change the access level on construction, but resets it on destruction
208     tCurrentAccessLevel();
209     ~tCurrentAccessLevel();
210 
211     //! returns the current access level
212     static tAccessLevel GetAccessLevel();
213 
214     //! returns the name of an access level
215     static tString GetName( tAccessLevel level );
216 private:
217     tCurrentAccessLevel( tCurrentAccessLevel const & );
218     tCurrentAccessLevel & operator = ( tCurrentAccessLevel const & );
219 
220     tAccessLevel lastLevel_; //!< used to restore the last admin level when the object goes out of scope
221     static tAccessLevel currentLevel_; //!< the current access level
222 };
223 
224 class tConfItemBase
225 {
226     friend class tCheckedPTRBase;
227     friend class tConfItemLevel;
228     friend class tAccessLevelSetter;
229 
230     int id;
231 protected:
232     const tString title;
233     const tOutput help;
234     bool changed;
235 
236     tAccessLevel requiredLevel; //!< access level required to change this setting
237     tAccessLevel setLevel;      //!< access level of the user making the last change to this setting
238 
239     typedef std::map< tString, tConfItemBase * > tConfItemMap;
240     static tConfItemMap & ConfItemMap();
241 
242     // static tConfItemBase* s_ConfItemAnchor;
243     //static tConfItemBase* Anchor(){return dynamic_cast<tConfItemBase *>(s_ConfItemAnchor);}
244 public:
245     static bool printChange; //!< if set, setting changes are printed to the console and, if printErrors is set as well, suggestions of typo fixes are given.
246     static bool printErrors; //!< if set, unknown settings are pointed out.
247 
248     tConfItemBase(const char *title, const tOutput& help);
249     tConfItemBase(const char *title);
250     virtual ~tConfItemBase();
251 
GetTitle()252     tString const & GetTitle() const {
253         return title;
254     }
255 
GetRequiredLevel()256     tAccessLevel GetRequiredLevel() const { return requiredLevel; }
GetSetLevel()257     tAccessLevel GetSetLevel() const { return setLevel; }
258 
259     static int EatWhitespace(std::istream &s); // eat whitespace from stream; return: first non-whitespace char
260 
261     static void SaveAll(std::ostream &s);
262     static void LoadAll(std::istream &s, bool record = false );  //! loads configuration from stream
263     static void LoadAll(std::ifstream &s, bool record = false );  //! loads configuration from file
264     static void LoadLine(std::istream &s); //! loads one configuration line
265     static bool LoadPlayback( bool print = false ); //! loads configuration from playback
266     static void DocAll(std::ostream &s);
267 
268     // helper functions for files (use these, they manage recording and playback properly)
269     enum SearchPath
270     {
271         Config = 1,
272         Var    = 2,
273         All    = 3
274     };
275 
276     static bool OpenFile( std::ifstream & s, tString const & filename, SearchPath path ); //! opens a file stream for configuration reading
277     static void ReadFile( std::ifstream & s ); //! loads configuration from a file
278 
279     virtual void ReadVal(std::istream &s)=0;
280     virtual void WriteVal(std::ostream &s)=0;
281 
WasChanged()282     virtual void WasChanged(){} // what to do if a read changed the thing
283 
Writable()284     virtual bool Writable(){
285         return true;
286     }
287 
Save()288     virtual bool Save(){
289         return true;
290     }
291 };
292 
293 //! just to do some work in static initializers, to modify default access levels:
294 class tAccessLevelSetter
295 {
296 public:
297     //! modifies the access level of <item> to <level>
298     tAccessLevelSetter( tConfItemBase & item, tAccessLevel level );
299 };
300 
301 // Arg! Msvc++ could not handle bool IO. Seems to be fine now.
302 #ifdef _MSC_VER_XXX
303 inline std::istream & operator >> (std::istream &s,bool &b){
304     int x;
305     s >> x;
306     b=(x!=0);
307     return s;
308 }
309 
310 inline std::ostream & operator << (std::ostream &s,bool b){
311     if (b)
312         return s << 1;
313     else
314         return s << 0;
315 }
316 #endif
317 
318 //! type modifying class mapping types in memory to types to stream
319 template< class T > struct tTypeToConfig
320 {
321     typedef T TOSTREAM;             //!< type to put into the stream
322     typedef int DUMMYREQUIRED;      //!< change this type to "int *" to indicate the conversion is required
323 };
324 
325 //! macro declaring that type TYPE should be converted to type STREAM before
326 // recording (and back after playback) by specializing the tTypeToStream class template
327 #define tCONFIG_AS( TYPE, STREAM ) \
328 template<> struct tTypeToConfig< TYPE > \
329 { \
330     typedef STREAM TOSTREAM; \
331   typedef int * DUMMYREQUIRED; \
332 } \
333 
334 //! macro for configuration enums: convert them to int.
335 #define tCONFIG_ENUM( TYPE ) tCONFIG_AS( TYPE, int )
336 
337 tCONFIG_ENUM( tAccessLevel );
338 
339 //! exception to be thrown when the current script should be aborted
340 class tAbortLoading: public tException
341 {
342 public:
343     tAbortLoading( char const * command );
344 private:
345     tString command_; //!< the command responsible for the abort
346 
347     virtual tString DoGetName() const;
348     virtual tString DoGetDescription() const;
349 };
350 
351 template<class T> class tConfItem:virtual public tConfItemBase{
352 public:
353     typedef bool (*ShouldChangeFuncT)(T const &newValue);
354 protected:
355     T    *target;
356     ShouldChangeFuncT shouldChangeFunc_;
357 
tConfItem(T & t)358     tConfItem(T &t):tConfItemBase(""),target(&t), shouldChangeFunc_(NULL) {}
359 public:
tConfItem(const char * title,const tOutput & help,T & t)360     tConfItem(const char *title,const tOutput& help,T& t)
361             :tConfItemBase(title,help),target(&t), shouldChangeFunc_(NULL) {}
362 
tConfItem(const char * title,T & t)363     tConfItem(const char *title,T& t)
364             :tConfItemBase(title),target(&t), shouldChangeFunc_(NULL) {}
365 
tConfItem(const char * title,T & t,ShouldChangeFuncT changeFunc)366     tConfItem(const char*title, T& t, ShouldChangeFuncT changeFunc)
367             :tConfItemBase(title),target(&t),shouldChangeFunc_(changeFunc) {}
368 
~tConfItem()369     virtual ~tConfItem(){}
370 
371     typedef typename tTypeToConfig< T >::DUMMYREQUIRED DUMMYREQUIRED;
372 
373     // read without conversion
DoRead(std::istream & s,T & value,int)374     static void DoRead(std::istream &s, T & value, int )
375     {
376         s >> value;
377     }
378 
379     // read with conversion
DoRead(std::istream & s,T & value,int *)380     static void DoRead(std::istream &s, T & value, int * )
381     {
382         typename tTypeToConfig< T >::TOSTREAM dummy;
383         s >> dummy;
384         value = static_cast< T >( dummy );
385     }
386 
387     // write without conversion
DoWrite(std::ostream & s,T const & value,int)388     static void DoWrite(std::ostream &s, T const & value, int )
389     {
390         s << value;
391     }
392 
393     // write with conversion
DoWrite(std::ostream & s,T const & value,int *)394     static void DoWrite(std::ostream &s, T const & value, int * )
395     {
396         s << static_cast< typename tTypeToConfig< T >::TOSTREAM >( value );
397     }
398 
ReadVal(std::istream & s)399     virtual void ReadVal(std::istream &s){
400         // eat whitepsace
401         int c= EatWhitespace(s);
402 
403         T dummy( *target );
404         if (c!='\n' && s && !s.eof() && s.good()){
405             DoRead( s, dummy, DUMMYREQUIRED() );
406             if (!s.good() && !s.eof() )
407             {
408                 tOutput o;
409                 o.SetTemplateParameter(1, title);
410                 o << "$config_error_read";
411                 con << o;
412             }
413             else
414                 if (dummy!=*target){
415                     if (!Writable())
416                     {
417                         tOutput o;
418                         o.SetTemplateParameter(1, title);
419                         o << "$nconfig_error_protected";
420                         con << "";
421                     }
422                     else{
423                         if (!shouldChangeFunc_ || shouldChangeFunc_(dummy))
424                         {
425                             if (printChange)
426                             {
427                                 tOutput o;
428                                 o.SetTemplateParameter(1, title);
429                                 o.SetTemplateParameter(2, *target);
430                                 o.SetTemplateParameter(3, dummy);
431                                 o << "$config_value_changed";
432                                 con << o;
433                             }
434 
435                             *target = dummy;
436                             changed = true;
437                         }
438                     }
439                 }
440         }
441         else
442         {
443             tOutput o;
444             o.SetTemplateParameter(1, title);
445             o.SetTemplateParameter(2, *target);
446             o << "$config_message_info";
447             con << o;
448         }
449 
450         // read the rest of the line
451         c=' ';
452         while (c!='\n' && s.good() && !s.eof()) c=s.get();
453     }
454 
WriteVal(std::ostream & s)455     virtual void WriteVal(std::ostream &s){
456         DoWrite( s, *target, DUMMYREQUIRED() );
457     }
458 };
459 
460 template<class T> class tSettingItem:public tConfItem<T>{
461 public:
462     //  tSettingItem(const char *title,const tOutput& help,T& t)
463     //    :tConfItemBase(title,help),tConfItem<T>(t){}
464 
tSettingItem(const char * title,T & t)465     tSettingItem(const char *title,T& t)
466             :tConfItemBase(title),tConfItem<T>(title, t){}
467 
tSettingItem(const char * title,T & t,typename tConfItem<T>::ShouldChangeFuncT changeFunc)468     tSettingItem(const char *title, T& t, typename tConfItem<T>::ShouldChangeFuncT changeFunc)
469             :tConfItemBase(title), tConfItem<T>(title, t, changeFunc) {}
470 
~tSettingItem()471     virtual ~tSettingItem(){}
472 
Save()473     virtual bool Save(){
474         return false;
475     }
476 };
477 
478 
479 class tConfItemLine:public tConfItem<tString>, virtual public tConfItemBase{
480 public:
tConfItemLine(const char * title,const char * help,tString & s)481     tConfItemLine(const char *title,const char *help,tString &s)
482             :tConfItemBase(title,help),tConfItem<tString>(title,help,s){}
483 
~tConfItemLine()484     virtual ~tConfItemLine(){}
485 
tConfItemLine(const char * title,tString & s)486     tConfItemLine(const char *title, tString &s)
487             :tConfItemBase(title),tConfItem<tString>(title,s){}
488 
489     virtual void ReadVal(std::istream &s);
490     virtual void WriteVal(std::ostream &s);
491 };
492 
493 typedef void CONF_FUNC(std::istream &s);
494 
495 class tConfItemFunc:public tConfItemBase{
496     CONF_FUNC *f;
497 public:
498     tConfItemFunc(const char *title, CONF_FUNC *func);
499     virtual ~tConfItemFunc();
500 
501     virtual void ReadVal(std::istream &s);
502     virtual void WriteVal(std::ostream &s);
503 
504     virtual bool Save();
505 };
506 
507 void st_LoadConfig();
508 void st_SaveConfig();
509 
510 extern bool st_FirstUse;
511 
512 #endif
513 
514