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