]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_props.cxx
now that there is a true track property, the magnetic track is nice to have, too.
[flightgear.git] / src / Main / fg_props.cxx
1 // fg_props.cxx -- support for FlightGear properties.
2 //
3 // Written by David Megginson, started 2000.
4 //
5 // Copyright (C) 2000, 2001 David Megginson - david@megginson.com
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26
27 #include <simgear/compiler.h>
28 #include <simgear/structure/exception.hxx>
29 #include <simgear/props/props_io.hxx>
30
31 #include <simgear/magvar/magvar.hxx>
32 #include <simgear/timing/sg_time.hxx>
33 #include <simgear/misc/sg_path.hxx>
34 #include <simgear/sound/soundmgr_openal.hxx>
35
36 #include <Aircraft/aircraft.hxx>
37 #include <FDM/flight.hxx>
38 #include <GUI/gui.h>
39
40 #include "globals.hxx"
41 #include "fg_props.hxx"
42
43
44 static bool winding_ccw = true; // FIXME: temporary
45
46 static bool fdm_data_logging = false; // FIXME: temporary
47
48 static bool frozen = false;     // FIXME: temporary
49
50 using std::string;
51 \f
52 ////////////////////////////////////////////////////////////////////////
53 // Default property bindings (not yet handled by any module).
54 ////////////////////////////////////////////////////////////////////////
55
56 struct LogClassMapping {
57   sgDebugClass c;
58   string name;
59   LogClassMapping(sgDebugClass cc, string nname) { c = cc; name = nname; }
60 };
61
62 LogClassMapping log_class_mappings [] = {
63   LogClassMapping(SG_NONE, "none"),
64   LogClassMapping(SG_TERRAIN, "terrain"),
65   LogClassMapping(SG_ASTRO, "astro"),
66   LogClassMapping(SG_FLIGHT, "flight"),
67   LogClassMapping(SG_INPUT, "input"),
68   LogClassMapping(SG_GL, "gl"),
69   LogClassMapping(SG_VIEW, "view"),
70   LogClassMapping(SG_COCKPIT, "cockpit"),
71   LogClassMapping(SG_GENERAL, "general"),
72   LogClassMapping(SG_MATH, "math"),
73   LogClassMapping(SG_EVENT, "event"),
74   LogClassMapping(SG_AIRCRAFT, "aircraft"),
75   LogClassMapping(SG_AUTOPILOT, "autopilot"),
76   LogClassMapping(SG_IO, "io"),
77   LogClassMapping(SG_CLIPPER, "clipper"),
78   LogClassMapping(SG_NETWORK, "network"),
79   LogClassMapping(SG_INSTR, "instrumentation"),
80   LogClassMapping(SG_SYSTEMS, "systems"),
81   LogClassMapping(SG_UNDEFD, "")
82 };
83
84
85 /**
86  * Get the logging classes.
87  */
88 static const char *
89 getLoggingClasses ()
90 {
91   sgDebugClass classes = logbuf::get_log_classes();
92   static string result;
93   result = "";
94   for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
95     if ((classes&log_class_mappings[i].c) > 0) {
96       if (!result.empty())
97         result += '|';
98       result += log_class_mappings[i].name;
99     }
100   }
101   return result.c_str();
102 }
103
104
105 static void
106 addLoggingClass (const string &name)
107 {
108   sgDebugClass classes = logbuf::get_log_classes();
109   for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
110     if (name == log_class_mappings[i].name) {
111       logbuf::set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
112       return;
113     }
114   }
115   SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging class: " << name);
116 }
117
118
119 /**
120  * Set the logging classes.
121  */
122 static void
123 setLoggingClasses (const char * c)
124 {
125   string classes = c;
126   logbuf::set_log_classes(SG_NONE);
127
128   if (classes == "none") {
129     SG_LOG(SG_GENERAL, SG_INFO, "Disabled all logging classes");
130     return;
131   }
132
133   if (classes.empty() || classes == "all") { // default
134     logbuf::set_log_classes(SG_ALL);
135     SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
136            << getLoggingClasses());
137     return;
138   }
139
140   string rest = classes;
141   string name = "";
142   int sep = rest.find('|');
143   while (sep > 0) {
144     name = rest.substr(0, sep);
145     rest = rest.substr(sep+1);
146     addLoggingClass(name);
147     sep = rest.find('|');
148   }
149   addLoggingClass(rest);
150   SG_LOG(SG_GENERAL, SG_INFO, "Set logging classes to "
151          << getLoggingClasses());
152 }
153
154
155 /**
156  * Get the logging priority.
157  */
158 static const char *
159 getLoggingPriority ()
160 {
161   switch (logbuf::get_log_priority()) {
162   case SG_BULK:
163     return "bulk";
164   case SG_DEBUG:
165     return "debug";
166   case SG_INFO:
167     return "info";
168   case SG_WARN:
169     return "warn";
170   case SG_ALERT:
171     return "alert";
172   default:
173     SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
174            << logbuf::get_log_priority());
175     return "unknown";
176   }
177 }
178
179
180 /**
181  * Set the logging priority.
182  */
183 static void
184 setLoggingPriority (const char * p)
185 {
186   if (p == 0)
187       return;
188   string priority = p;
189   if (priority == "bulk") {
190     logbuf::set_log_priority(SG_BULK);
191   } else if (priority == "debug") {
192     logbuf::set_log_priority(SG_DEBUG);
193   } else if (priority.empty() || priority == "info") { // default
194     logbuf::set_log_priority(SG_INFO);
195   } else if (priority == "warn") {
196     logbuf::set_log_priority(SG_WARN);
197   } else if (priority == "alert") {
198     logbuf::set_log_priority(SG_ALERT);
199   } else {
200     SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
201   }
202   SG_LOG(SG_GENERAL, SG_DEBUG, "Logging priority is " << getLoggingPriority());
203 }
204
205
206 /**
207  * Return the current frozen state.
208  */
209 static bool
210 getFreeze ()
211 {
212   return frozen;
213 }
214
215
216 /**
217  * Set the current frozen state.
218  */
219 static void
220 setFreeze (bool f)
221 {
222     frozen = f;
223
224     // Stop sound on a pause
225     SGSoundMgr *smgr = globals->get_soundmgr();
226     if ( smgr != NULL ) {
227         if ( f ) {
228             smgr->suspend();
229         } else if (fgGetBool("/sim/sound/working")) {
230             smgr->resume();
231         }
232     }
233 }
234
235
236 /**
237  * Return the number of milliseconds elapsed since simulation started.
238  */
239 static double
240 getElapsedTime_sec ()
241 {
242   return globals->get_sim_time_sec();
243 }
244
245
246 /**
247  * Return the current Zulu time.
248  */
249 static const char *
250 getDateString ()
251 {
252   static char buf[64];          // FIXME
253   struct tm * t = globals->get_time_params()->getGmt();
254   sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
255           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
256           t->tm_hour, t->tm_min, t->tm_sec);
257   return buf;
258 }
259
260
261 /**
262  * Set the current Zulu time.
263  */
264 static void
265 setDateString (const char * date_string)
266 {
267   static const SGPropertyNode *cur_time_override
268         = fgGetNode("/sim/time/cur-time-override", true);
269
270   SGTime * st = globals->get_time_params();
271   struct tm * current_time = st->getGmt();
272   struct tm new_time;
273
274                                 // Scan for basic ISO format
275                                 // YYYY-MM-DDTHH:MM:SS
276   int ret = sscanf(date_string, "%d-%d-%dT%d:%d:%d",
277                    &(new_time.tm_year), &(new_time.tm_mon),
278                    &(new_time.tm_mday), &(new_time.tm_hour),
279                    &(new_time.tm_min), &(new_time.tm_sec));
280
281                                 // Be pretty picky about this, so
282                                 // that strange things don't happen
283                                 // if the save file has been edited
284                                 // by hand.
285   if (ret != 6) {
286     SG_LOG(SG_INPUT, SG_WARN, "Date/time string " << date_string
287            << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
288     return;
289   }
290
291                                 // OK, it looks like we got six
292                                 // values, one way or another.
293   new_time.tm_year -= 1900;
294   new_time.tm_mon -= 1;
295
296                                 // Now, tell flight gear to use
297                                 // the new time.  This was far
298                                 // too difficult, by the way.
299   long int warp =
300     mktime(&new_time) - mktime(current_time) + globals->get_warp();
301   double lon = current_aircraft.fdm_state->get_Longitude();
302   double lat = current_aircraft.fdm_state->get_Latitude();
303   globals->set_warp(warp);
304   st->update(lon, lat, cur_time_override->getLongValue(), warp);
305 }
306
307 /**
308  * Return the GMT as a string.
309  */
310 static const char *
311 getGMTString ()
312 {
313   static char buf[16];
314   struct tm *t = globals->get_time_params()->getGmt();
315   snprintf(buf, 16, "%.2d:%.2d:%.2d",
316       t->tm_hour, t->tm_min, t->tm_sec);
317   return buf;
318 }
319
320 /**
321  * Return the magnetic variation
322  */
323 static double
324 getMagVar ()
325 {
326   return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
327 }
328
329
330 /**
331  * Return the magnetic dip
332  */
333 static double
334 getMagDip ()
335 {
336   return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
337 }
338
339
340 /**
341  * Return the current heading in degrees.
342  */
343 static double
344 getHeadingMag ()
345 {
346   double magheading;
347   magheading = current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
348   if (magheading < 0) magheading += 360;
349   return magheading;
350 }
351
352 /**
353  * Return the current track in degrees.
354  */
355 static double
356 getTrackMag ()
357 {
358   double magtrack;
359   magtrack = current_aircraft.fdm_state->get_Track() - getMagVar();
360   if (magtrack < 0) magtrack += 360;
361   return magtrack;
362 }
363
364 static long
365 getWarp ()
366 {
367   return globals->get_warp();
368 }
369
370 static void
371 setWarp (long warp)
372 {
373   globals->set_warp(warp);
374 }
375
376 static long
377 getWarpDelta ()
378 {
379   return globals->get_warp_delta();
380 }
381
382 static void
383 setWarpDelta (long delta)
384 {
385   globals->set_warp_delta(delta);
386 }
387
388 static bool
389 getWindingCCW ()
390 {
391   return winding_ccw;
392 }
393
394 static void
395 setWindingCCW (bool state)
396 {
397   winding_ccw = state;
398   if ( winding_ccw )
399     glFrontFace ( GL_CCW );
400   else
401     glFrontFace ( GL_CW );
402 }
403
404 static bool
405 getFDMDataLogging ()
406 {
407   return fdm_data_logging;
408 }
409
410 static void
411 setFDMDataLogging (bool state)
412 {
413                                 // kludge; no getter or setter available
414   if (state != fdm_data_logging) {
415     fgToggleFDMdataLogging();
416     fdm_data_logging = state;
417   }
418 }
419
420 static const char *
421 getLongitudeString ()
422 {
423   static SGConstPropertyNode_ptr n = fgGetNode("/position/longitude-deg", true);
424   static SGConstPropertyNode_ptr f = fgGetNode("/sim/lon-lat-format", true);
425   static char buf[32];
426   double d = n->getDoubleValue();
427   int format = f->getIntValue();
428   char c = d < 0.0 ? 'W' : 'E';
429
430   if (format == 0) {
431     snprintf(buf, 32, "%3.6f%c", d, c);
432
433   } else if (format == 1) {
434     // dd mm.mmm' (DMM-Format) -- uses a round-off factor tailored to the
435     // required precision of the minutes field (three decimal places),
436     // preventing minute values of 60.
437     double deg = fabs(d) + 5.0E-4 / 60.0;
438     double min = fabs(deg - int(deg)) * 60.0 - 4.999E-4;
439     snprintf(buf, 32, "%d*%06.3f%c", int(d < 0.0 ? -deg : deg), min, c);
440
441   } else {
442     // mm'ss.s'' (DMS-Format) -- uses a round-off factor tailored to the
443     // required precision of the seconds field (one decimal place),
444     // preventing second values of 60.
445     double deg = fabs(d) + 0.05 / 3600.0;
446     double min = (deg - int(deg)) * 60.0;
447     double sec = (min - int(min)) * 60.0 - 0.049;
448     snprintf(buf, 32, "%d*%02d %04.1f%c", int(d < 0.0 ? -deg : deg),
449         int(min), fabs(sec), c);
450   }
451   buf[31] = '\0';
452   return buf;
453 }
454
455 static const char *
456 getLatitudeString ()
457 {
458   static SGConstPropertyNode_ptr n = fgGetNode("/position/latitude-deg", true);
459   static SGConstPropertyNode_ptr f = fgGetNode("/sim/lon-lat-format", true);
460   static char buf[32];
461   double d = n->getDoubleValue();
462   int format = f->getIntValue();
463   char c = d < 0.0 ? 'S' : 'N';
464
465   if (format == 0) {
466     snprintf(buf, 32, "%3.6f%c", d, c);
467
468   } else if (format == 1) {
469     double deg = fabs(d) + 5.0E-4 / 60.0;
470     double min = fabs(deg - int(deg)) * 60.0 - 4.999E-4;
471     snprintf(buf, 32, "%d*%06.3f%c", int(d < 0.0 ? -deg : deg), min, c);
472
473   } else {
474     double deg = fabs(d) + 0.05 / 3600.0;
475     double min = (deg - int(deg)) * 60.0;
476     double sec = (min - int(min)) * 60.0 - 0.049;
477     snprintf(buf, 32, "%d*%02d %04.1f%c", int(d < 0.0 ? -deg : deg),
478         int(min), fabs(sec), c);
479   }
480   buf[31] = '\0';
481   return buf;
482 }
483
484
485
486 \f
487 ////////////////////////////////////////////////////////////////////////
488 // Tie the properties.
489 ////////////////////////////////////////////////////////////////////////
490
491 FGProperties::FGProperties ()
492 {
493 }
494
495 FGProperties::~FGProperties ()
496 {
497 }
498
499 void
500 FGProperties::init ()
501 {
502 }
503
504 void
505 FGProperties::bind ()
506 {
507                                 // Simulation
508   fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
509   fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
510   fgTie("/sim/freeze/master", getFreeze, setFreeze);
511
512   fgTie("/sim/time/elapsed-sec", getElapsedTime_sec);
513   fgTie("/sim/time/gmt", getDateString, setDateString);
514   fgSetArchivable("/sim/time/gmt");
515   fgTie("/sim/time/gmt-string", getGMTString);
516
517                                 // Position
518   fgTie("/position/latitude-string", getLatitudeString);
519   fgTie("/position/longitude-string", getLongitudeString);
520
521                                 // Orientation
522   fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
523   fgTie("/orientation/track-magnetic-deg", getTrackMag);
524
525   fgTie("/environment/magnetic-variation-deg", getMagVar);
526   fgTie("/environment/magnetic-dip-deg", getMagDip);
527
528   fgTie("/sim/time/warp", getWarp, setWarp, false);
529   fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
530
531                                 // Misc. Temporary junk.
532   fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
533   fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
534 }
535
536 void
537 FGProperties::unbind ()
538 {
539                                 // Simulation
540   fgUntie("/sim/logging/priority");
541   fgUntie("/sim/logging/classes");
542   fgUntie("/sim/freeze/master");
543
544   fgUntie("/sim/time/elapsed-sec");
545   fgUntie("/sim/time/gmt");
546   fgUntie("/sim/time/gmt-string");
547                                 // Position
548   fgUntie("/position/latitude-string");
549   fgUntie("/position/longitude-string");
550
551                                 // Orientation
552   fgUntie("/orientation/heading-magnetic-deg");
553   fgUntie("/orientation/track-magnetic-deg");
554
555                                 // Environment
556   fgUntie("/environment/magnetic-variation-deg");
557   fgUntie("/environment/magnetic-dip-deg");
558
559   fgUntie("/sim/time/warp");
560   fgUntie("/sim/time/warp-delta");
561
562                                 // Misc. Temporary junk.
563   fgUntie("/sim/temp/winding-ccw");
564   fgUntie("/sim/temp/full-screen");
565   fgUntie("/sim/temp/fdm-data-logging");
566 }
567
568 void
569 FGProperties::update (double dt)
570 {
571     static SGPropertyNode_ptr offset = fgGetNode("/sim/time/local-offset", true);
572     offset->setIntValue(globals->get_time_params()->get_local_offset());
573
574
575     // utc date/time
576     static SGPropertyNode_ptr uyear = fgGetNode("/sim/time/utc/year", true);
577     static SGPropertyNode_ptr umonth = fgGetNode("/sim/time/utc/month", true);
578     static SGPropertyNode_ptr uday = fgGetNode("/sim/time/utc/day", true);
579     static SGPropertyNode_ptr uhour = fgGetNode("/sim/time/utc/hour", true);
580     static SGPropertyNode_ptr umin = fgGetNode("/sim/time/utc/minute", true);
581     static SGPropertyNode_ptr usec = fgGetNode("/sim/time/utc/second", true);
582     static SGPropertyNode_ptr uwday = fgGetNode("/sim/time/utc/weekday", true);
583     static SGPropertyNode_ptr udsec = fgGetNode("/sim/time/utc/day-seconds", true);
584
585     struct tm *u = globals->get_time_params()->getGmt();
586     uyear->setIntValue(u->tm_year + 1900);
587     umonth->setIntValue(u->tm_mon + 1);
588     uday->setIntValue(u->tm_mday);
589     uhour->setIntValue(u->tm_hour);
590     umin->setIntValue(u->tm_min);
591     usec->setIntValue(u->tm_sec);
592     uwday->setIntValue(u->tm_wday);
593
594     udsec->setIntValue(u->tm_hour * 3600 + u->tm_min * 60 + u->tm_sec);
595
596
597     // real local date/time
598     static SGPropertyNode_ptr ryear = fgGetNode("/sim/time/real/year", true);
599     static SGPropertyNode_ptr rmonth = fgGetNode("/sim/time/real/month", true);
600     static SGPropertyNode_ptr rday = fgGetNode("/sim/time/real/day", true);
601     static SGPropertyNode_ptr rhour = fgGetNode("/sim/time/real/hour", true);
602     static SGPropertyNode_ptr rmin = fgGetNode("/sim/time/real/minute", true);
603     static SGPropertyNode_ptr rsec = fgGetNode("/sim/time/real/second", true);
604     static SGPropertyNode_ptr rwday = fgGetNode("/sim/time/real/weekday", true);
605
606     time_t real = time(0);
607     struct tm *r = localtime(&real);
608     ryear->setIntValue(r->tm_year + 1900);
609     rmonth->setIntValue(r->tm_mon + 1);
610     rday->setIntValue(r->tm_mday);
611     rhour->setIntValue(r->tm_hour);
612     rmin->setIntValue(r->tm_min);
613     rsec->setIntValue(r->tm_sec);
614     rwday->setIntValue(r->tm_wday);
615 }
616
617
618 \f
619 ////////////////////////////////////////////////////////////////////////
620 // Save and restore.
621 ////////////////////////////////////////////////////////////////////////
622
623
624 /**
625  * Save the current state of the simulator to a stream.
626  */
627 bool
628 fgSaveFlight (std::ostream &output, bool write_all)
629 {
630
631   fgSetBool("/sim/presets/onground", false);
632   fgSetArchivable("/sim/presets/onground");
633   fgSetBool("/sim/presets/trim", false);
634   fgSetArchivable("/sim/presets/trim");
635   fgSetString("/sim/presets/speed-set", "UVW");
636   fgSetArchivable("/sim/presets/speed-set");
637
638   try {
639     writeProperties(output, globals->get_props(), write_all);
640   } catch (const sg_exception &e) {
641     guiErrorMessage("Error saving flight: ", e);
642     return false;
643   }
644   return true;
645 }
646
647
648 /**
649  * Restore the current state of the simulator from a stream.
650  */
651 bool
652 fgLoadFlight (std::istream &input)
653 {
654   SGPropertyNode props;
655   try {
656     readProperties(input, &props);
657   } catch (const sg_exception &e) {
658     guiErrorMessage("Error reading saved flight: ", e);
659     return false;
660   }
661
662   fgSetBool("/sim/presets/onground", false);
663   fgSetBool("/sim/presets/trim", false);
664   fgSetString("/sim/presets/speed-set", "UVW");
665
666   copyProperties(&props, globals->get_props());
667   // When loading a flight, make it the
668   // new initial state.
669   globals->saveInitialState();
670   return true;
671 }
672
673
674 bool
675 fgLoadProps (const char * path, SGPropertyNode * props, bool in_fg_root, int default_mode)
676 {
677     string fullpath;
678     if (in_fg_root) {
679         SGPath loadpath(globals->get_fg_root());
680         loadpath.append(path);
681         fullpath = loadpath.str();
682     } else {
683         fullpath = path;
684     }
685
686     try {
687         readProperties(fullpath, props, default_mode);
688     } catch (const sg_exception &e) {
689         guiErrorMessage("Error reading properties: ", e);
690         return false;
691     }
692     return true;
693 }
694
695
696 \f
697 ////////////////////////////////////////////////////////////////////////
698 // Property convenience functions.
699 ////////////////////////////////////////////////////////////////////////
700
701 SGPropertyNode *
702 fgGetNode (const char * path, bool create)
703 {
704   return globals->get_props()->getNode(path, create);
705 }
706
707 SGPropertyNode * 
708 fgGetNode (const char * path, int index, bool create)
709 {
710   return globals->get_props()->getNode(path, index, create);
711 }
712
713 bool
714 fgHasNode (const char * path)
715 {
716   return (fgGetNode(path, false) != 0);
717 }
718
719 void
720 fgAddChangeListener (SGPropertyChangeListener * listener, const char * path)
721 {
722   fgGetNode(path, true)->addChangeListener(listener);
723 }
724
725 void
726 fgAddChangeListener (SGPropertyChangeListener * listener,
727                      const char * path, int index)
728 {
729   fgGetNode(path, index, true)->addChangeListener(listener);
730 }
731
732 bool
733 fgGetBool (const char * name, bool defaultValue)
734 {
735   return globals->get_props()->getBoolValue(name, defaultValue);
736 }
737
738 int
739 fgGetInt (const char * name, int defaultValue)
740 {
741   return globals->get_props()->getIntValue(name, defaultValue);
742 }
743
744 int
745 fgGetLong (const char * name, long defaultValue)
746 {
747   return globals->get_props()->getLongValue(name, defaultValue);
748 }
749
750 float
751 fgGetFloat (const char * name, float defaultValue)
752 {
753   return globals->get_props()->getFloatValue(name, defaultValue);
754 }
755
756 double
757 fgGetDouble (const char * name, double defaultValue)
758 {
759   return globals->get_props()->getDoubleValue(name, defaultValue);
760 }
761
762 const char *
763 fgGetString (const char * name, const char * defaultValue)
764 {
765   return globals->get_props()->getStringValue(name, defaultValue);
766 }
767
768 bool
769 fgSetBool (const char * name, bool val)
770 {
771   return globals->get_props()->setBoolValue(name, val);
772 }
773
774 bool
775 fgSetInt (const char * name, int val)
776 {
777   return globals->get_props()->setIntValue(name, val);
778 }
779
780 bool
781 fgSetLong (const char * name, long val)
782 {
783   return globals->get_props()->setLongValue(name, val);
784 }
785
786 bool
787 fgSetFloat (const char * name, float val)
788 {
789   return globals->get_props()->setFloatValue(name, val);
790 }
791
792 bool
793 fgSetDouble (const char * name, double val)
794 {
795   return globals->get_props()->setDoubleValue(name, val);
796 }
797
798 bool
799 fgSetString (const char * name, const char * val)
800 {
801   return globals->get_props()->setStringValue(name, val);
802 }
803
804 void
805 fgSetArchivable (const char * name, bool state)
806 {
807   SGPropertyNode * node = globals->get_props()->getNode(name);
808   if (node == 0)
809     SG_LOG(SG_GENERAL, SG_DEBUG,
810            "Attempt to set archive flag for non-existant property "
811            << name);
812   else
813     node->setAttribute(SGPropertyNode::ARCHIVE, state);
814 }
815
816 void
817 fgSetReadable (const char * name, bool state)
818 {
819   SGPropertyNode * node = globals->get_props()->getNode(name);
820   if (node == 0)
821     SG_LOG(SG_GENERAL, SG_DEBUG,
822            "Attempt to set read flag for non-existant property "
823            << name);
824   else
825     node->setAttribute(SGPropertyNode::READ, state);
826 }
827
828 void
829 fgSetWritable (const char * name, bool state)
830 {
831   SGPropertyNode * node = globals->get_props()->getNode(name);
832   if (node == 0)
833     SG_LOG(SG_GENERAL, SG_DEBUG,
834            "Attempt to set write flag for non-existant property "
835            << name);
836   else
837     node->setAttribute(SGPropertyNode::WRITE, state);
838 }
839
840 void
841 fgUntie (const char * name)
842 {
843   if (!globals->get_props()->untie(name))
844     SG_LOG(SG_GENERAL, SG_WARN, "Failed to untie property " << name);
845 }
846
847
848 // end of fg_props.cxx