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