1 /* bzflag
2  * Copyright (c) 1993-2021 Tim Riker
3  *
4  * This package is free software;  you can redistribute it and/or
5  * modify it under the terms of the license found in the file
6  * named COPYING that should have accompanied this file.
7  *
8  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11  */
12 
13 // interface header
14 #include "StateDatabase.h"
15 
16 // system headers
17 #include <assert.h>
18 #include <ctype.h>
19 #include <stack>
20 #include <set>
21 #include <iostream>
22 #include <math.h>
23 #include <string>
24 #include <string.h>
25 
26 // local implementation headers
27 #include "ErrorHandler.h"
28 #include "TextUtils.h"
29 
30 #if defined(DEBUG) || defined(_DEBUG)
31 // headers needed only for _debugLookups()
32 #include <map>
33 #include "TimeKeeper.h"
34 
_debugLookups(const std::string & name)35 void    _debugLookups(const std::string &name)
36 {
37     if (!BZDB.getDebug())
38         return;
39 
40     typedef std::map<std::string,int> EvalCntMap;
41     static const float interval = 20.0f;
42 
43     /* This bit of nastyness help debug BDZB->eval accesses sorted from worst to best*/
44     static EvalCntMap cnts;
45     static TimeKeeper last = TimeKeeper::getCurrent();
46 
47     EvalCntMap::iterator it = cnts.find(name);
48     if (it == cnts.end())
49         cnts[name] = 1;
50     else
51         it->second++;
52 
53     TimeKeeper now = TimeKeeper::getCurrent();
54     if (now - last > interval)
55     {
56         std::multimap<int,std::string> order;
57         for (it = cnts.begin(); it != cnts.end(); it++)
58         {
59             order.insert(std::pair<int,std::string>(-it->second, it->first));
60             it->second = 0;
61         }
62 
63         for (std::multimap<int,std::string>::iterator it2 = order.begin(); it2 != order.end(); ++it2)
64         {
65             if (-it2->first / interval < 1.0f)
66                 break;
67             logDebugMessage(1,"%-25s = %.2f acc/sec\n", it2->second.c_str(), -it2->first / interval);
68         }
69         last = now;
70     }
71 }
72 
73 #define debugLookups(name) _debugLookups(name)
74 #else
75 #define debugLookups(name)
76 #endif
77 
78 const std::string StateDatabase::BZDB_AGILITYADVEL     = std::string("_agilityAdVel");
79 const std::string StateDatabase::BZDB_AGILITYTIMEWINDOW    = std::string("_agilityTimeWindow");
80 const std::string StateDatabase::BZDB_AGILITYVELDELTA      = std::string("_agilityVelDelta");
81 const std::string StateDatabase::BZDB_AMBIENTLIGHT     = std::string("_ambientLight");
82 const std::string StateDatabase::BZDB_ANGLETOLERANCE       = std::string("_angleTolerance");
83 const std::string StateDatabase::BZDB_ANGULARAD        = std::string("_angularAd");
84 const std::string StateDatabase::BZDB_AVENUESIZE       = std::string("_avenueSize");
85 const std::string StateDatabase::BZDB_BASESIZE         = std::string("_baseSize");
86 const std::string StateDatabase::BZDB_BOXBASE          = std::string("_boxBase");
87 const std::string StateDatabase::BZDB_BOXHEIGHT        = std::string("_boxHeight");
88 const std::string StateDatabase::BZDB_BURROWDEPTH      = std::string("_burrowDepth");
89 const std::string StateDatabase::BZDB_BURROWSPEEDAD    = std::string("_burrowSpeedAd");
90 const std::string StateDatabase::BZDB_BURROWANGULARAD      = std::string("_burrowAngularAd");
91 const std::string StateDatabase::BZDB_COLDETDEPTH      = std::string("_coldetDepth");
92 const std::string StateDatabase::BZDB_COLDETELEMENTS       = std::string("_coldetElements");
93 const std::string StateDatabase::BZDB_COUNTDOWNRESDELAY    = std::string("_countdownResumeDelay");
94 const std::string StateDatabase::BZDB_CULLDEPTH        = std::string("_cullDepth");
95 const std::string StateDatabase::BZDB_CULLELEMENTS     = std::string("_cullElements");
96 const std::string StateDatabase::BZDB_CULLOCCLUDERS    = std::string("_cullOccluders");
97 const std::string StateDatabase::BZDB_DISABLEBOTS      = std::string("_disableBots");
98 const std::string StateDatabase::BZDB_DRAWCELESTIAL    = std::string("_drawCelestial");
99 const std::string StateDatabase::BZDB_DRAWCLOUDS       = std::string("_drawClouds");
100 const std::string StateDatabase::BZDB_DRAWGROUND       = std::string("_drawGround");
101 const std::string StateDatabase::BZDB_DRAWGROUNDLIGHTS     = std::string("_drawGroundLights");
102 const std::string StateDatabase::BZDB_DRAWMOUNTAINS    = std::string("_drawMountains");
103 const std::string StateDatabase::BZDB_DRAWSKY          = std::string("_drawSky");
104 const std::string StateDatabase::BZDB_ENDSHOTDETECTION     = std::string("_endShotDetection");
105 const std::string StateDatabase::BZDB_EXPLODETIME      = std::string("_explodeTime");
106 const std::string StateDatabase::BZDB_FLAGALTITUDE     = std::string("_flagAltitude");
107 const std::string StateDatabase::BZDB_FLAGEFFECTTIME       = std::string("_flagEffectTime");
108 const std::string StateDatabase::BZDB_FLAGHEIGHT       = std::string("_flagHeight");
109 const std::string StateDatabase::BZDB_FLAGPOLEWIDTH    = std::string("_flagPoleWidth");
110 const std::string StateDatabase::BZDB_FLAGPOLESIZE     = std::string("_flagPoleSize");
111 const std::string StateDatabase::BZDB_FLAGRADIUS       = std::string("_flagRadius");
112 const std::string StateDatabase::BZDB_FOGMODE          = std::string("_fogMode");
113 const std::string StateDatabase::BZDB_FOGDENSITY       = std::string("_fogDensity");
114 const std::string StateDatabase::BZDB_FOGSTART         = std::string("_fogStart");
115 const std::string StateDatabase::BZDB_FOGEND           = std::string("_fogEnd");
116 const std::string StateDatabase::BZDB_FOGCOLOR         = std::string("_fogColor");
117 const std::string StateDatabase::BZDB_FRICTION         = std::string("_friction");
118 const std::string StateDatabase::BZDB_GMACTIVATIONTIME     = std::string("_gmActivationTime");
119 const std::string StateDatabase::BZDB_GMADLIFE         = std::string("_gmAdLife");
120 const std::string StateDatabase::BZDB_GMSIZE           = std::string("_gmSize");
121 const std::string StateDatabase::BZDB_GMTURNANGLE      = std::string("_gmTurnAngle");
122 const std::string StateDatabase::BZDB_GRAVITY          = std::string("_gravity");
123 const std::string StateDatabase::BZDB_HANDICAPSCOREDIFF    = std::string("_handicapScoreDiff");
124 const std::string StateDatabase::BZDB_HANDICAPVELAD    = std::string("_handicapVelAd");
125 const std::string StateDatabase::BZDB_HANDICAPANGAD    = std::string("_handicapAngAd");
126 const std::string StateDatabase::BZDB_HANDICAPSHOTAD       = std::string("_handicapShotAd");
127 const std::string StateDatabase::BZDB_HIDEFLAGSONRADAR     = std::string("_hideFlagsOnRadar");
128 const std::string StateDatabase::BZDB_HIDETEAMFLAGSONRADAR = std::string("_hideTeamFlagsOnRadar");
129 const std::string StateDatabase::BZDB_IDENTIFYRANGE    = std::string("_identifyRange");
130 const std::string StateDatabase::BZDB_JUMPVELOCITY     = std::string("_jumpVelocity");
131 const std::string StateDatabase::BZDB_LASERADVEL       = std::string("_laserAdVel");
132 const std::string StateDatabase::BZDB_LASERADRATE      = std::string("_laserAdRate");
133 const std::string StateDatabase::BZDB_LASERADLIFE      = std::string("_laserAdLife");
134 const std::string StateDatabase::BZDB_LATITUDE         = std::string("_latitude");
135 const std::string StateDatabase::BZDB_LOCKONANGLE      = std::string("_lockOnAngle");
136 const std::string StateDatabase::BZDB_LONGITUDE        = std::string("_longitude");
137 const std::string StateDatabase::BZDB_LRADRATE         = std::string("_lRAdRate");
138 const std::string StateDatabase::BZDB_MAXBUMPHEIGHT    = std::string("_maxBumpHeight");
139 const std::string StateDatabase::BZDB_MAXFLAGGRABS     = std::string("_maxFlagGrabs");
140 const std::string StateDatabase::BZDB_MAXLOD           = std::string("_maxLOD");
141 const std::string StateDatabase::BZDB_MIRROR           = std::string("_mirror");
142 const std::string StateDatabase::BZDB_MOMENTUMLINACC       = std::string("_momentumLinAcc");
143 const std::string StateDatabase::BZDB_MOMENTUMANGACC       = std::string("_momentumAngAcc");
144 const std::string StateDatabase::BZDB_MOMENTUMFRICTION     = std::string("_momentumFriction");
145 const std::string StateDatabase::BZDB_MGUNADVEL        = std::string("_mGunAdVel");
146 const std::string StateDatabase::BZDB_MGUNADRATE       = std::string("_mGunAdRate");
147 const std::string StateDatabase::BZDB_MGUNADLIFE       = std::string("_mGunAdLife");
148 const std::string StateDatabase::BZDB_MUZZLEFRONT      = std::string("_muzzleFront");
149 const std::string StateDatabase::BZDB_MUZZLEHEIGHT     = std::string("_muzzleHeight");
150 const std::string StateDatabase::BZDB_NOCLIMB          = std::string("_noClimb");
151 const std::string StateDatabase::BZDB_NOSHADOWS        = std::string("_noShadows");
152 const std::string StateDatabase::BZDB_NOSMALLPACKETS       = std::string("_noSmallPackets");
153 const std::string StateDatabase::BZDB_NOTRESPONDINGTIME    = std::string("_notRespondingTime");
154 const std::string StateDatabase::BZDB_OBESEFACTOR      = std::string("_obeseFactor");
155 const std::string StateDatabase::BZDB_PAUSEDROPTIME    = std::string("_pauseDropTime");
156 const std::string StateDatabase::BZDB_POSITIONTOLERANCE    = std::string("_positionTolerance");
157 const std::string StateDatabase::BZDB_PYRBASE          = std::string("_pyrBase");
158 const std::string StateDatabase::BZDB_PYRHEIGHT        = std::string("_pyrHeight");
159 const std::string StateDatabase::BZDB_RADARLIMIT       = std::string("_radarLimit");
160 const std::string StateDatabase::BZDB_REJOINTIME       = std::string("_rejoinTime");
161 const std::string StateDatabase::BZDB_RELOADTIME       = std::string("_reloadTime");
162 const std::string StateDatabase::BZDB_RFIREADVEL       = std::string("_rFireAdVel");
163 const std::string StateDatabase::BZDB_RFIREADRATE      = std::string("_rFireAdRate");
164 const std::string StateDatabase::BZDB_RFIREADLIFE      = std::string("_rFireAdLife");
165 const std::string StateDatabase::BZDB_SHIELDFLIGHT     = std::string("_shieldFlight");
166 const std::string StateDatabase::BZDB_SHOCKADLIFE      = std::string("_shockAdLife");
167 const std::string StateDatabase::BZDB_SHOCKINRADIUS    = std::string("_shockInRadius");
168 const std::string StateDatabase::BZDB_SHOCKOUTRADIUS       = std::string("_shockOutRadius");
169 const std::string StateDatabase::BZDB_SHOTRADIUS       = std::string("_shotRadius");
170 const std::string StateDatabase::BZDB_SHOTRANGE        = std::string("_shotRange");
171 const std::string StateDatabase::BZDB_SHOTSPEED        = std::string("_shotSpeed");
172 const std::string StateDatabase::BZDB_SHOTTAILLENGTH       = std::string("_shotTailLength");
173 const std::string StateDatabase::BZDB_SHOTSKEEPVERTICALV   = std::string("_shotsKeepVerticalVelocity");
174 const std::string StateDatabase::BZDB_SPEEDCHECKSLOGONLY   = std::string("_speedChecksLogOnly");
175 const std::string StateDatabase::BZDB_SRRADIUSMULT     = std::string("_srRadiusMult");
176 const std::string StateDatabase::BZDB_SQUISHFACTOR     = std::string("_squishFactor");
177 const std::string StateDatabase::BZDB_SQUISHTIME       = std::string("_squishTime");
178 const std::string StateDatabase::BZDB_SYNCTIME         = std::string("_syncTime");
179 const std::string StateDatabase::BZDB_SYNCLOCATION     = std::string("_syncLocation");
180 const std::string StateDatabase::BZDB_TANKANGVEL       = std::string("_tankAngVel");
181 const std::string StateDatabase::BZDB_TANKEXPLOSIONSIZE    = std::string("_tankExplosionSize");
182 const std::string StateDatabase::BZDB_TANKHEIGHT       = std::string("_tankHeight");
183 const std::string StateDatabase::BZDB_TANKLENGTH       = std::string("_tankLength");
184 const std::string StateDatabase::BZDB_TANKRADIUS       = std::string("_tankRadius");
185 const std::string StateDatabase::BZDB_TANKSPEED        = std::string("_tankSpeed");
186 const std::string StateDatabase::BZDB_TANKWIDTH        = std::string("_tankWidth");
187 const std::string StateDatabase::BZDB_TARGETINGANGLE       = std::string("_targetingAngle");
188 const std::string StateDatabase::BZDB_TARGETINGDISTANCE    = std::string("_targetingDistance");
189 const std::string StateDatabase::BZDB_TELEBREADTH      = std::string("_teleportBreadth");
190 const std::string StateDatabase::BZDB_TELEHEIGHT       = std::string("_teleportHeight");
191 const std::string StateDatabase::BZDB_TELEPORTTIME     = std::string("_teleportTime");
192 const std::string StateDatabase::BZDB_TELEWIDTH        = std::string("_teleportWidth");
193 const std::string StateDatabase::BZDB_THIEFADLIFE      = std::string("_thiefAdLife");
194 const std::string StateDatabase::BZDB_THIEFADRATE      = std::string("_thiefAdRate");
195 const std::string StateDatabase::BZDB_THIEFADSHOTVEL       = std::string("_thiefAdShotVel");
196 const std::string StateDatabase::BZDB_THIEFTINYFACTOR      = std::string("_thiefTinyFactor");
197 const std::string StateDatabase::BZDB_THIEFVELAD       = std::string("_thiefVelAd");
198 const std::string StateDatabase::BZDB_THIEFDROPTIME    = std::string("_thiefDropTime");
199 const std::string StateDatabase::BZDB_TINYFACTOR       = std::string("_tinyFactor");
200 const std::string StateDatabase::BZDB_TRACKFADE        = std::string("_trackFade");
201 const std::string StateDatabase::BZDB_UPDATETHROTTLERATE   = std::string("_updateThrottleRate");
202 const std::string StateDatabase::BZDB_VELOCITYAD       = std::string("_velocityAd");
203 const std::string StateDatabase::BZDB_WALLHEIGHT       = std::string("_wallHeight");
204 const std::string StateDatabase::BZDB_WEAPONS          = std::string("_weapons");
205 const std::string StateDatabase::BZDB_WIDEANGLEANG     = std::string("_wideAngleAng");
206 const std::string StateDatabase::BZDB_WINGSGRAVITY     = std::string("_wingsGravity");
207 const std::string StateDatabase::BZDB_WINGSJUMPCOUNT       = std::string("_wingsJumpCount");
208 const std::string StateDatabase::BZDB_WINGSJUMPVELOCITY    = std::string("_wingsJumpVelocity");
209 const std::string StateDatabase::BZDB_WINGSSLIDETIME       = std::string("_wingsSlideTime");
210 const std::string StateDatabase::BZDB_WORLDSIZE        = std::string("_worldSize");
211 
212 //
213 // StateDatabase::Item
214 //
215 
Item()216 StateDatabase::Item::Item() : value(),
217     defValue(),
218     isSet(false),
219     isTrue(false),
220     save(true), // FIXME -- false by default?
221     permission(ReadWrite)
222 {
223     // do nothing
224 }
225 
226 
227 //
228 // StateDatabase
229 //
230 
231 
StateDatabase()232 StateDatabase::StateDatabase() : debug(false), saveDefault(false)
233 {
234     // do nothing
235 }
236 
~StateDatabase()237 StateDatabase::~StateDatabase()
238 {
239     // do nothing
240 }
241 
set(const std::string & name,const std::string & value,Permission access)242 void            StateDatabase::set(const std::string& name,
243                                    const std::string& value,
244                                    Permission access)
245 {
246     Map::iterator index = lookup(name);
247     if (access >= index->second.permission)
248     {
249         index->second.value  = value;
250         index->second.isSet  = true;
251         std::string valuelow = TextUtils::tolower(value);
252         index->second.isTrue = (valuelow != "0" &&
253                                 valuelow != "off" &&
254                                 valuelow != "false" &&
255                                 valuelow != "no" &&
256                                 valuelow != "disable");
257 
258         if (saveDefault)
259             index->second.defValue = value;
260         notify(index);
261     }
262 }
263 
setInt(const std::string & name,const int & value,Permission access)264 void             StateDatabase::setInt(const std::string& name,
265                                        const int& value,
266                                        Permission access)
267 {
268     set(name,TextUtils::format("%d",value),access);
269 }
270 
setBool(const std::string & name,const bool & value,Permission access)271 void            StateDatabase::setBool(const std::string& name,
272                                        const bool& value,
273                                        Permission access)
274 {
275     set(name,value ? std::string("1") : std::string("0"),access);
276 }
277 
setFloat(const std::string & name,const float & value,Permission access)278 void           StateDatabase::setFloat(const std::string& name,
279                                        const float& value,
280                                        Permission access)
281 {
282     set(name,TextUtils::format("%f",value),access);
283 }
284 
setPointer(const std::string & name,const void * value,Permission access)285 void            StateDatabase::setPointer(const std::string& name,
286         const void * value,
287         Permission access)
288 {
289     char address[32];
290     memset(address, 0, 32);
291     snprintf(address, 32, "%lu", (unsigned long)value);
292     std::string ssaddress = address;
293     this->set(name, ssaddress, access);
294 }
295 
296 
unset(const std::string & name,Permission access)297 void            StateDatabase::unset(const std::string& name,
298                                      Permission access)
299 {
300     Map::iterator index = lookup(name);
301     if (access >= index->second.permission)
302     {
303         index->second.value  = "";
304         index->second.isSet  = false;
305         index->second.isTrue = false;
306         notify(index);
307     }
308 }
309 
touch(const std::string & name,Permission access)310 void            StateDatabase::touch(const std::string& name,
311                                      Permission access)
312 {
313     Map::iterator index = lookup(name);
314     if (access >= index->second.permission)
315         notify(index);
316 }
317 
setPersistent(const std::string & name,bool save)318 void            StateDatabase::setPersistent(
319     const std::string& name, bool save)
320 {
321     Map::iterator index = lookup(name);
322     index->second.save = save;
323 }
324 
setDefault(const std::string & name,const std::string & value)325 void            StateDatabase::setDefault(
326     const std::string& name, const std::string& value)
327 {
328     Map::iterator index = lookup(name);
329     index->second.defValue = value;
330 }
331 
setPermission(const std::string & name,Permission permission)332 void            StateDatabase::setPermission(
333     const std::string& name,
334     Permission permission)
335 {
336     Map::iterator index = lookup(name);
337     index->second.permission = permission;
338 }
339 
addCallback(const std::string & name,Callback callback,void * userData)340 void            StateDatabase::addCallback(
341     const std::string& name,
342     Callback callback,
343     void* userData)
344 {
345     Map::iterator index = lookup(name);
346     index->second.callbacks.add(callback, userData);
347 }
348 
removeCallback(const std::string & name,Callback callback,void * userData)349 void            StateDatabase::removeCallback(
350     const std::string& name,
351     Callback callback,
352     void* userData)
353 {
354     Map::iterator index = lookup(name);
355     index->second.callbacks.remove(callback, userData);
356 }
357 
addGlobalCallback(Callback callback,void * userData)358 void StateDatabase::addGlobalCallback(Callback callback, void* userData)
359 {
360     globalCallbacks.add(callback, userData);
361 }
362 
removeGlobalCallback(Callback callback,void * userData)363 void StateDatabase::removeGlobalCallback(Callback callback, void* userData)
364 {
365     globalCallbacks.remove(callback, userData);
366 }
367 
368 
isSet(const std::string & name) const369 bool            StateDatabase::isSet(const std::string& name) const
370 {
371     debugLookups(name);
372     Map::const_iterator index = items.find(name);
373     return !(index == items.end() || !index->second.isSet);
374 }
375 
get(const std::string & name) const376 std::string     StateDatabase::get(const std::string& name) const
377 {
378     debugLookups(name);
379     Map::const_iterator index = items.find(name);
380     if (index == items.end() || !index->second.isSet)
381         return std::string();
382     else
383         return index->second.value;
384 }
385 
getIntClamped(const std::string & name,const int min,const int max) const386 int     StateDatabase::getIntClamped(const std::string& name, const int min, const int max) const
387 {
388     int val;
389     debugLookups(name);
390     Map::const_iterator index = items.find(name);
391     if (index == items.end() || !index->second.isSet)
392         val=0;
393     else
394         val = atoi(index->second.value.c_str());
395     if (val < min)
396         return min;
397     else if (val > max)
398         return max;
399     return val;
400 }
401 
getPointer(const std::string & name) const402 void *      StateDatabase::getPointer(const std::string& name) const
403 {
404     debugLookups(name);
405     Map::const_iterator index = items.find(name);
406     if (index == items.end() || !index->second.isSet)
407         return (void *)NULL;
408     else
409         return (void *)strtoul(index->second.value.c_str(), NULL, 0);
410 }
411 
eval(const std::string & name)412 float           StateDatabase::eval(const std::string& name)
413 {
414     typedef std::set<std::string> VariableSet;
415     debugLookups(name);
416 
417     EvalMap::const_iterator cit = evalCache.find(name);
418     if (cit != evalCache.end())
419         return cit->second;
420 
421     //this is to catch recursive definitions
422     static VariableSet variables;
423     // ugly hack, since gcc 2.95 doesn't have <limits>
424     float NaN;
425     memset(&NaN, 0xff, sizeof(float));
426 
427     if (variables.find(name) != variables.end())
428         return NaN;
429 
430     VariableSet::iterator ins_it = variables.insert(name).first;
431 
432     Map::const_iterator index = items.find(name);
433     if (index == items.end() || !index->second.isSet || index->second.value.empty())
434     {
435         variables.erase(ins_it);
436         return NaN;
437     }
438     Expression pre, inf;
439     std::string value = index->second.value;
440     if (!value.size())
441         return NaN;
442     value >> inf;
443     pre = infixToPrefix(inf);
444     float retn = evaluate(pre);
445     variables.erase(ins_it);
446 
447     if (retn != NaN)
448         evalCache[name] = retn;
449     return retn;
450 }
451 
evalInt(const std::string & name)452 int         StateDatabase::evalInt(const std::string& name)
453 {
454     return (int)eval(name);
455 }
456 
evalTriplet(const std::string & name,float data[4])457 bool        StateDatabase::evalTriplet(const std::string& name, float data[4])
458 {
459     if (!isSet(name) || !data)
460         return false;
461     if (sscanf(get(name).c_str(), "%f %f %f", data, data+1, data+2) != 3)
462         return false;
463     return true;
464 }
465 
evalPair(const std::string & name,float data[2])466 bool        StateDatabase::evalPair(const std::string& name, float data[2])
467 {
468     if (!isSet(name) || !data)
469         return false;
470     if (sscanf(get(name).c_str(), "%f %f", data, data+1) != 2)
471         return false;
472     return true;
473 }
474 
isTrue(const std::string & name) const475 bool            StateDatabase::isTrue(const std::string& name) const
476 {
477     debugLookups(name);
478     Map::const_iterator index = items.find(name);
479     return !(index == items.end() || !index->second.isTrue);
480 }
481 
isEmpty(const std::string & name) const482 bool            StateDatabase::isEmpty(const std::string& name) const
483 {
484     debugLookups(name);
485     Map::const_iterator index = items.find(name);
486     return (index == items.end() || !index->second.isSet ||
487             index->second.value.empty());
488 }
489 
isPersistent(const std::string & name) const490 bool            StateDatabase::isPersistent(const std::string& name) const
491 {
492     debugLookups(name);
493     Map::const_iterator index = items.find(name);
494     return (index != items.end() && index->second.save);
495 }
496 
getDefault(const std::string & name) const497 std::string     StateDatabase::getDefault(const std::string& name) const
498 {
499     debugLookups(name);
500     Map::const_iterator index = items.find(name);
501     if (index != items.end())
502         return index->second.defValue;
503     else
504         return "";
505 }
506 
507 StateDatabase::Permission
getPermission(const std::string & name) const508 StateDatabase::getPermission(const std::string& name) const
509 {
510     debugLookups(name);
511     Map::const_iterator index = items.find(name);
512     if (index != items.end())
513         return index->second.permission;
514     else
515         return ReadWrite;
516 }
517 
518 StateDatabase::Map::iterator
lookup(const std::string & name)519 StateDatabase::lookup(const std::string& name)
520 {
521     debugLookups(name);
522     Map::iterator index = items.find(name);
523     if (index == items.end())
524     {
525         Item tmp;
526         return items.insert(std::make_pair(name, tmp)).first;
527     }
528     else
529         return index;
530 }
531 
notify(Map::iterator index)532 void            StateDatabase::notify(Map::iterator index)
533 {
534     const std::string& name = index->first;
535     const Item& item = index->second;
536 
537     evalCache.erase(index->first);
538 
539     void* namePtr = const_cast<void*>(static_cast<const void*>(&name));
540     globalCallbacks.iterate(&onCallback, namePtr);
541     item.callbacks.iterate(&onCallback, namePtr);
542 }
543 
onCallback(Callback callback,void * userData,void * iterateData)544 bool            StateDatabase::onCallback(Callback callback,
545         void* userData,
546         void* iterateData)
547 {
548     callback(*static_cast<std::string*>(iterateData), userData);
549     return true;
550 }
551 
iterate(Callback callback,void * userData) const552 void            StateDatabase::iterate(Callback callback, void* userData) const
553 {
554     assert(callback != NULL);
555 
556     for (Map::const_iterator index = items.begin(); index != items.end(); ++index)
557     {
558         if (index->second.isSet)
559             (*callback)(index->first, userData);
560     }
561 }
562 
write(Callback callback,void * userData) const563 void            StateDatabase::write(Callback callback, void* userData) const
564 {
565     assert(callback != NULL);
566 
567     for (Map::const_iterator index = items.begin(); index != items.end(); ++index)
568     {
569         if (index->second.isSet && index->second.save)
570             (*callback)(index->first, userData);
571     }
572 }
573 
setDebug(bool print)574 void             StateDatabase::setDebug(bool print)
575 {
576     debug = print;
577 }
578 
setSaveDefault(bool save)579 void             StateDatabase::setSaveDefault(bool save)
580 {
581     saveDefault = save;
582 }
583 
ExpressionToken()584 StateDatabase::ExpressionToken::ExpressionToken()
585 {
586     tokenType = Number;
587     tokenContents.number = 0;
588 }
589 
ExpressionToken(Type _tokenType)590 StateDatabase::ExpressionToken::ExpressionToken(Type _tokenType)
591 {
592     tokenType = _tokenType;
593     switch (tokenType)
594     {
595     case Number:
596         tokenContents.number = 0;
597         break;
598     case Variable:
599         break;
600     case Oper:
601         tokenContents.oper = none;
602         break;
603     }
604 }
605 
ExpressionToken(Type _tokenType,Contents _tokenContents)606 StateDatabase::ExpressionToken::ExpressionToken(Type _tokenType, Contents _tokenContents)
607 {
608     tokenType = _tokenType;
609     tokenContents = _tokenContents;
610 }
611 
setType(Type _tokenType)612 void StateDatabase::ExpressionToken::setType(Type _tokenType)
613 {
614     tokenType = _tokenType;
615     switch (tokenType)
616     {
617     case Number:
618         tokenContents.number = 0;
619         break;
620     case Variable:
621         break;
622     case Oper:
623         tokenContents.oper = none;
624         break;
625     }
626 }
627 
setContents(Contents _tokenContents)628 void StateDatabase::ExpressionToken::setContents(Contents _tokenContents)
629 {
630     tokenContents = _tokenContents;
631 }
632 
setNumber(double num)633 void StateDatabase::ExpressionToken::setNumber(double num)
634 {
635     tokenType = Number;
636     tokenContents.number = num;
637 }
638 
setVariable(std::string var)639 void StateDatabase::ExpressionToken::setVariable(std::string var)
640 {
641     tokenType = Variable;
642     tokenContents.variable = var;
643 }
644 
setOper(Operator op)645 void StateDatabase::ExpressionToken::setOper(Operator op)
646 {
647     tokenType = Oper;
648     tokenContents.oper = op;
649 }
650 
getTokenType() const651 StateDatabase::ExpressionToken::Type StateDatabase::ExpressionToken::getTokenType() const
652 {
653     return tokenType;
654 }
655 
getTokenContents() const656 StateDatabase::ExpressionToken::Contents StateDatabase::ExpressionToken::getTokenContents() const
657 {
658     return tokenContents;
659 }
660 
getNumber() const661 double StateDatabase::ExpressionToken::getNumber() const
662 {
663     // note that the necessary type check must be done first
664     return tokenContents.number;
665 }
666 
getVariable() const667 std::string StateDatabase::ExpressionToken::getVariable() const
668 {
669     // note that the necessary type check must be done first
670     return tokenContents.variable;
671 }
672 
getOperator() const673 StateDatabase::ExpressionToken::Operator StateDatabase::ExpressionToken::getOperator() const
674 {
675     // note that the necessary type check must be done first
676     return tokenContents.oper;
677 }
678 
getPrecedence() const679 int StateDatabase::ExpressionToken::getPrecedence() const
680 {
681     switch (tokenContents.oper)
682     {
683     case add:
684     case subtract:
685         return 1;
686     case multiply:
687     case divide:
688         return 2;
689     case power:
690         return 3;
691     case lparen:
692         return 4;
693     case rparen:
694     default:
695         return 0;
696     }
697 }
698 
operator >>(std::istream & src,StateDatabase::ExpressionToken & dst)699 std::istream&operator >> (std::istream& src, StateDatabase::ExpressionToken& dst)
700 {
701     char temp;
702     std::string tempname;
703 
704     src >> temp;
705     if ((temp >= '0' && temp <= '9') || temp == '.')
706     {
707         // number
708         tempname += temp;
709         temp = src.peek();
710         while ((temp >= '0' && temp <= '9') || temp == '.')
711         {
712             src >> temp;
713             tempname += temp;
714             temp = src.peek();
715         }
716         dst.setNumber(atof(tempname.c_str()));
717     }
718     else if (temp == '+' || temp == '-' || temp == '*' || temp == '/' || temp == '^' || temp == '(' || temp == ')')
719     {
720         // operator
721         switch (temp)
722         {
723         case '+':
724             dst.setOper(StateDatabase::ExpressionToken::add);
725             break;
726         case '-':
727             dst.setOper(StateDatabase::ExpressionToken::subtract);
728             break;
729         case '*':
730             dst.setOper(StateDatabase::ExpressionToken::multiply);
731             break;
732         case '/':
733             dst.setOper(StateDatabase::ExpressionToken::divide);
734             break;
735         case '^':
736             dst.setOper(StateDatabase::ExpressionToken::power);
737             break;
738         case '(':
739             dst.setOper(StateDatabase::ExpressionToken::lparen);
740             break;
741         case ')':
742             dst.setOper(StateDatabase::ExpressionToken::rparen);
743             break;
744         }
745     }
746     else if ((temp >= 'a' && temp <= 'z') || (temp >= 'A' && temp <= 'Z') || temp == '_')
747     {
748         // variable (perhaps prefix with $?)
749         tempname += temp;
750         temp = src.peek();
751         while ((temp >= 'a' && temp <= 'z') || (temp >= 'A' && temp <= 'Z') || temp == '_')
752         {
753             src >> temp;
754             tempname += temp;
755             temp = src.peek();
756         }
757         dst.setVariable(tempname);
758     }
759     else
760     {
761         // throw an error?
762     }
763     return src;
764 }
765 
operator >>(std::string & src,StateDatabase::ExpressionToken & dst)766 std::string& operator >> (std::string& src, StateDatabase::ExpressionToken& dst)
767 {
768     char temp;
769     std::string tempname;
770 
771     if (src.size() == 0)
772         return src;
773 
774     temp = src[0];
775     src = src.substr(1);
776     if ((temp >= '0' && temp <= '9') || temp == '.')
777     {
778         // number
779         tempname += temp;
780         if (!src.empty())
781             temp = src[0];
782         while (((temp >= '0' && temp <= '9') || temp == '.') && (src.length() != 0))
783         {
784             src = src.substr(1);
785             tempname += temp;
786             if (!src.empty())
787                 temp = src[0];
788         }
789         dst.setNumber(atof(tempname.c_str()));
790     }
791     else if (temp == '+' || temp == '-' || temp == '*' || temp == '/' || temp == '^' || temp == '(' || temp == ')')
792     {
793         // operator
794         switch (temp)
795         {
796         case '+':
797             dst.setOper(StateDatabase::ExpressionToken::add);
798             break;
799         case '-':
800             dst.setOper(StateDatabase::ExpressionToken::subtract);
801             break;
802         case '*':
803             dst.setOper(StateDatabase::ExpressionToken::multiply);
804             break;
805         case '/':
806             dst.setOper(StateDatabase::ExpressionToken::divide);
807             break;
808         case '^':
809             dst.setOper(StateDatabase::ExpressionToken::power);
810             break;
811         case '(':
812             dst.setOper(StateDatabase::ExpressionToken::lparen);
813             break;
814         case ')':
815             dst.setOper(StateDatabase::ExpressionToken::rparen);
816             break;
817         }
818     }
819     else if ((temp >= 'a' && temp <= 'z') || (temp >= 'A' && temp <= 'Z') || temp == '_')
820     {
821         tempname += temp;
822         if (!src.empty())
823             temp = src[0];
824         while (((temp >= 'a' && temp <= 'z') || (temp >= 'A' && temp <= 'Z') || temp == '_') && (src.length() != 0))
825         {
826             src = src.substr(1);
827             tempname += temp;
828             if (!src.empty())
829                 temp = src[0];
830         }
831         dst.setVariable(tempname);
832     }
833     else
834     {
835         // throw an error?
836     }
837     return src;
838 }
839 
operator <<(std::ostream & dst,const StateDatabase::ExpressionToken & src)840 std::ostream& operator << (std::ostream& dst, const StateDatabase::ExpressionToken& src)
841 {
842     switch (src.getTokenType())
843     {
844     case StateDatabase::ExpressionToken::Number:
845         dst << src.getNumber();
846         break;
847     case StateDatabase::ExpressionToken::Oper:
848         switch (src.getOperator())
849         {
850         case StateDatabase::ExpressionToken::add:
851             dst << '+';
852             break;
853         case StateDatabase::ExpressionToken::subtract:
854             dst << '-';
855             break;
856         case StateDatabase::ExpressionToken::multiply:
857             dst << '*';
858             break;
859         case StateDatabase::ExpressionToken::divide:
860             dst << '/';
861             break;
862         case StateDatabase::ExpressionToken::power:
863             dst << '^';
864             break;
865         case StateDatabase::ExpressionToken::lparen:
866             dst << '(';
867             break;
868         case StateDatabase::ExpressionToken::rparen:
869             dst << ')';
870             break;
871         case StateDatabase::ExpressionToken::none:
872             break;
873         }
874         break;
875     case StateDatabase::ExpressionToken::Variable:
876         dst << src.getVariable();
877         break;
878     }
879     return dst;
880 }
881 
operator >>(std::istream & src,StateDatabase::Expression & dst)882 std::istream& operator >> (std::istream& src, StateDatabase::Expression& dst)
883 {
884     StateDatabase::ExpressionToken temp;
885     char tempc;
886 
887     dst.clear();
888     src.unsetf(std::ios::skipws);
889     while (src.peek() != '\n')
890     {
891         while (src.peek() == ' ' || src.peek() == '\t')
892             src >> tempc;
893         src >> temp;
894         dst.push_back(temp);
895     }
896     src >> tempc;
897     src.setf(std::ios::skipws);
898     return src;
899 }
900 
operator >>(std::string & src,StateDatabase::Expression & dst)901 std::string& operator >> (std::string& src, StateDatabase::Expression& dst)
902 {
903     StateDatabase::ExpressionToken temp;
904 
905     dst.clear();
906     while (src.length() != 0)
907     {
908         while (src[0] == ' ' || src[0] == '\t')
909             src = src.substr(1);
910         if (src.length() != 0)
911         {
912             src >> temp;
913             dst.push_back(temp);
914         }
915     }
916     return src;
917 }
918 
operator <<(std::ostream & dst,const StateDatabase::Expression & src)919 std::ostream& operator << (std::ostream& dst, const StateDatabase::Expression& src)
920 {
921     if (src.size())
922     {
923         for (unsigned int i = 0; i < src.size() - 1; i++)
924             dst << src[i] << ' ';
925         dst << src[src.size() - 1];
926     }
927     return dst;
928 }
929 
infixToPrefix(const Expression & infix)930 StateDatabase::Expression StateDatabase::infixToPrefix(const Expression &infix)
931 {
932     Expression postfix, prefix;
933     std::stack<ExpressionToken> operators;
934 
935     for (Expression::const_iterator i = infix.begin(); i != infix.end(); ++i)
936     {
937         if (i->getTokenType() == ExpressionToken::Variable || i->getTokenType() == ExpressionToken::Number)
938             postfix.push_back(*i);
939         else if (i->getTokenType() == ExpressionToken::Oper)
940         {
941             if (i->getOperator() == ExpressionToken::lparen)
942                 operators.push(*i);
943             else if (i->getOperator() == ExpressionToken::rparen)
944             {
945                 // unstack operators until a matching ( is found
946                 while (!operators.empty() && (operators.top().getOperator() != ExpressionToken::lparen))
947                 {
948                     postfix.push_back(operators.top());
949                     operators.pop();
950                 }
951                 // discard (
952                 if (!operators.empty()) // handle extra-rparen case
953                     operators.pop();
954             }
955             else
956             {
957                 while (!operators.empty() && (operators.top().getPrecedence() < i->getPrecedence())
958                         && (operators.top().getOperator() != ExpressionToken::lparen))
959                 {
960                     postfix.push_back(operators.top());
961                     operators.pop();
962                 }
963                 operators.push(*i);
964             }
965         }
966     }
967     while (!operators.empty())
968     {
969         postfix.push_back(operators.top());
970         operators.pop();
971     }
972 
973     for (Expression::reverse_iterator ri = postfix.rbegin(); ri != postfix.rend(); ++ri)
974         prefix.push_back(*ri);
975     return prefix;
976 }
977 
evaluate(Expression e) const978 float StateDatabase::evaluate(Expression e) const
979 {
980     std::stack<ExpressionToken> evaluationStack;
981     ExpressionToken tok, lvalue, rvalue;
982     bool unary;
983 
984     for (Expression::reverse_iterator i = e.rbegin(); i != e.rend(); ++i)
985     {
986         unary = false;
987         switch (i->getTokenType())
988         {
989         case ExpressionToken::Number:
990             evaluationStack.push(*i);
991             break;
992         case ExpressionToken::Variable:
993             // strip off '$'?
994             tok.setNumber(BZDB.eval(i->getVariable()));
995             evaluationStack.push(tok);
996             break;
997         case ExpressionToken::Oper:
998             if ((i->getOperator() == ExpressionToken::lparen) ||
999                     (i->getOperator() == ExpressionToken::rparen))
1000             {
1001                 break;  // should not have any parens here, skip them
1002             }
1003             if (evaluationStack.empty())
1004             {
1005                 // syntax error
1006                 // ugly hack, since gcc 2.95 doesn't have <limits>
1007                 float NaN;
1008                 memset(&NaN, 0xff, sizeof(NaN));
1009                 return NaN;
1010             }
1011             // rvalue and lvalue are switched, since we're reversed
1012             rvalue = evaluationStack.top();
1013             evaluationStack.pop();
1014             if (evaluationStack.empty())
1015             {
1016                 unary = true; // syntax error or unary operator
1017             }
1018             if (!unary)
1019             {
1020                 lvalue = evaluationStack.top();
1021                 evaluationStack.pop();
1022             }
1023             switch (i->getOperator())
1024             {
1025             case ExpressionToken::add:
1026                 tok.setNumber(lvalue.getNumber() + rvalue.getNumber());
1027                 evaluationStack.push(tok);
1028                 break;
1029             case ExpressionToken::subtract:
1030                 if (unary)
1031                     tok.setNumber(-rvalue.getNumber());
1032                 else
1033                     tok.setNumber(lvalue.getNumber() - rvalue.getNumber());
1034                 evaluationStack.push(tok);
1035                 break;
1036             case ExpressionToken::multiply:
1037                 tok.setNumber(lvalue.getNumber() * rvalue.getNumber());
1038                 evaluationStack.push(tok);
1039                 break;
1040             case ExpressionToken::divide:
1041                 tok.setNumber(lvalue.getNumber() / rvalue.getNumber());
1042                 evaluationStack.push(tok);
1043                 break;
1044             case ExpressionToken::power:
1045                 tok.setNumber(pow(lvalue.getNumber(), rvalue.getNumber()));
1046                 evaluationStack.push(tok);
1047                 break;
1048             default:
1049                 // lparen and rparen should have been stripped out
1050                 // throw something here, too
1051                 break;
1052             }
1053             break;
1054         }
1055     }
1056     if (evaluationStack.empty())
1057         return 0; // yeah we are screwed. TODO, don't let us get this far
1058 
1059     return (float)evaluationStack.top().getNumber();
1060 }
1061 
1062 
1063 // Local Variables: ***
1064 // mode: C++ ***
1065 // tab-width: 4 ***
1066 // c-basic-offset: 4 ***
1067 // indent-tabs-mode: nil ***
1068 // End: ***
1069 // ex: shiftwidth=4 tabstop=4
1070