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