]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_props.cxx
Juggle fgfs link order to keep GNU ld happy.
[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 <GUI/gui.h>
38
39 #include "globals.hxx"
40 #include "fg_props.hxx"
41
42
43 static bool winding_ccw = true; // FIXME: temporary
44
45 static bool frozen = false;     // FIXME: temporary
46
47 using std::string;
48 \f
49 ////////////////////////////////////////////////////////////////////////
50 // Default property bindings (not yet handled by any module).
51 ////////////////////////////////////////////////////////////////////////
52
53 struct LogClassMapping {
54   sgDebugClass c;
55   string name;
56   LogClassMapping(sgDebugClass cc, string nname) { c = cc; name = nname; }
57 };
58
59 LogClassMapping log_class_mappings [] = {
60   LogClassMapping(SG_NONE, "none"),
61   LogClassMapping(SG_TERRAIN, "terrain"),
62   LogClassMapping(SG_ASTRO, "astro"),
63   LogClassMapping(SG_FLIGHT, "flight"),
64   LogClassMapping(SG_INPUT, "input"),
65   LogClassMapping(SG_GL, "gl"),
66   LogClassMapping(SG_VIEW, "view"),
67   LogClassMapping(SG_COCKPIT, "cockpit"),
68   LogClassMapping(SG_GENERAL, "general"),
69   LogClassMapping(SG_MATH, "math"),
70   LogClassMapping(SG_EVENT, "event"),
71   LogClassMapping(SG_AIRCRAFT, "aircraft"),
72   LogClassMapping(SG_AUTOPILOT, "autopilot"),
73   LogClassMapping(SG_IO, "io"),
74   LogClassMapping(SG_CLIPPER, "clipper"),
75   LogClassMapping(SG_NETWORK, "network"),
76   LogClassMapping(SG_INSTR, "instrumentation"),
77   LogClassMapping(SG_SYSTEMS, "systems"),
78   LogClassMapping(SG_UNDEFD, "")
79 };
80
81
82 /**
83  * Get the logging classes.
84  */
85 // XXX Making the result buffer be global is a band-aid that hopefully
86 // delays its destruction 'til after its last use.
87 namespace
88 {
89 string loggingResult;
90 }
91
92 static const char *
93 getLoggingClasses ()
94 {
95   sgDebugClass classes = logbuf::get_log_classes();
96   loggingResult.clear();
97   for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
98     if ((classes&log_class_mappings[i].c) > 0) {
99       if (!loggingResult.empty())
100         loggingResult += '|';
101       loggingResult += log_class_mappings[i].name;
102     }
103   }
104   return loggingResult.c_str();
105 }
106
107
108 static void
109 addLoggingClass (const string &name)
110 {
111   sgDebugClass classes = logbuf::get_log_classes();
112   for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
113     if (name == log_class_mappings[i].name) {
114       logbuf::set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
115       return;
116     }
117   }
118   SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging class: " << name);
119 }
120
121
122 /**
123  * Set the logging classes.
124  */
125 static void
126 setLoggingClasses (const char * c)
127 {
128   string classes = c;
129   logbuf::set_log_classes(SG_NONE);
130
131   if (classes == "none") {
132     SG_LOG(SG_GENERAL, SG_INFO, "Disabled all logging classes");
133     return;
134   }
135
136   if (classes.empty() || classes == "all") { // default
137     logbuf::set_log_classes(SG_ALL);
138     SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
139            << getLoggingClasses());
140     return;
141   }
142
143   string rest = classes;
144   string name = "";
145   int sep = rest.find('|');
146   while (sep > 0) {
147     name = rest.substr(0, sep);
148     rest = rest.substr(sep+1);
149     addLoggingClass(name);
150     sep = rest.find('|');
151   }
152   addLoggingClass(rest);
153   SG_LOG(SG_GENERAL, SG_INFO, "Set logging classes to "
154          << getLoggingClasses());
155 }
156
157
158 /**
159  * Get the logging priority.
160  */
161 static const char *
162 getLoggingPriority ()
163 {
164   switch (logbuf::get_log_priority()) {
165   case SG_BULK:
166     return "bulk";
167   case SG_DEBUG:
168     return "debug";
169   case SG_INFO:
170     return "info";
171   case SG_WARN:
172     return "warn";
173   case SG_ALERT:
174     return "alert";
175   default:
176     SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
177            << logbuf::get_log_priority());
178     return "unknown";
179   }
180 }
181
182
183 /**
184  * Set the logging priority.
185  */
186 static void
187 setLoggingPriority (const char * p)
188 {
189   if (p == 0)
190       return;
191   string priority = p;
192   if (priority == "bulk") {
193     logbuf::set_log_priority(SG_BULK);
194   } else if (priority == "debug") {
195     logbuf::set_log_priority(SG_DEBUG);
196   } else if (priority.empty() || priority == "info") { // default
197     logbuf::set_log_priority(SG_INFO);
198   } else if (priority == "warn") {
199     logbuf::set_log_priority(SG_WARN);
200   } else if (priority == "alert") {
201     logbuf::set_log_priority(SG_ALERT);
202   } else {
203     SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
204   }
205   SG_LOG(SG_GENERAL, SG_DEBUG, "Logging priority is " << getLoggingPriority());
206 }
207
208
209 /**
210  * Return the current frozen state.
211  */
212 static bool
213 getFreeze ()
214 {
215   return frozen;
216 }
217
218
219 /**
220  * Set the current frozen state.
221  */
222 static void
223 setFreeze (bool f)
224 {
225     frozen = f;
226
227     // Stop sound on a pause
228     SGSoundMgr *smgr = globals->get_soundmgr();
229     if ( smgr != NULL ) {
230         if ( f ) {
231             smgr->suspend();
232         } else if (fgGetBool("/sim/sound/working")) {
233             smgr->resume();
234         }
235     }
236
237     // Pause the particle system
238     simgear::Particles::setFrozen(f);
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 = fgGetDouble("/position/longitude-deg") * SG_DEGREES_TO_RADIANS;
308   double lat = fgGetDouble("/position/latitude-deg") * SG_DEGREES_TO_RADIANS;
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 = fgGetDouble("/orientation/heading-deg") - 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 = fgGetDouble("/orientation/track-deg") - 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 const char *
411 getLongitudeString ()
412 {
413   static SGConstPropertyNode_ptr n = fgGetNode("/position/longitude-deg", true);
414   static SGConstPropertyNode_ptr f = fgGetNode("/sim/lon-lat-format", true);
415   static char buf[32];
416   double d = n->getDoubleValue();
417   int format = f->getIntValue();
418   char c = d < 0.0 ? 'W' : 'E';
419
420   if (format == 0) {
421     snprintf(buf, 32, "%3.6f%c", d, c);
422
423   } else if (format == 1) {
424     // dd mm.mmm' (DMM-Format) -- uses a round-off factor tailored to the
425     // required precision of the minutes field (three decimal places),
426     // preventing minute values of 60.
427     double deg = fabs(d) + 5.0E-4 / 60.0;
428     double min = fabs(deg - int(deg)) * 60.0 - 4.999E-4;
429     snprintf(buf, 32, "%d*%06.3f%c", int(d < 0.0 ? -deg : deg), min, c);
430
431   } else {
432     // mm'ss.s'' (DMS-Format) -- uses a round-off factor tailored to the
433     // required precision of the seconds field (one decimal place),
434     // preventing second values of 60.
435     double deg = fabs(d) + 0.05 / 3600.0;
436     double min = (deg - int(deg)) * 60.0;
437     double sec = (min - int(min)) * 60.0 - 0.049;
438     snprintf(buf, 32, "%d*%02d %04.1f%c", int(d < 0.0 ? -deg : deg),
439         int(min), fabs(sec), c);
440   }
441   buf[31] = '\0';
442   return buf;
443 }
444
445 static const char *
446 getLatitudeString ()
447 {
448   static SGConstPropertyNode_ptr n = fgGetNode("/position/latitude-deg", true);
449   static SGConstPropertyNode_ptr f = fgGetNode("/sim/lon-lat-format", true);
450   static char buf[32];
451   double d = n->getDoubleValue();
452   int format = f->getIntValue();
453   char c = d < 0.0 ? 'S' : 'N';
454
455   if (format == 0) {
456     snprintf(buf, 32, "%3.6f%c", d, c);
457
458   } else if (format == 1) {
459     double deg = fabs(d) + 5.0E-4 / 60.0;
460     double min = fabs(deg - int(deg)) * 60.0 - 4.999E-4;
461     snprintf(buf, 32, "%d*%06.3f%c", int(d < 0.0 ? -deg : deg), min, c);
462
463   } else {
464     double deg = fabs(d) + 0.05 / 3600.0;
465     double min = (deg - int(deg)) * 60.0;
466     double sec = (min - int(min)) * 60.0 - 0.049;
467     snprintf(buf, 32, "%d*%02d %04.1f%c", int(d < 0.0 ? -deg : deg),
468         int(min), fabs(sec), c);
469   }
470   buf[31] = '\0';
471   return buf;
472 }
473
474
475
476 \f
477 ////////////////////////////////////////////////////////////////////////
478 // Tie the properties.
479 ////////////////////////////////////////////////////////////////////////
480
481 FGProperties::FGProperties ()
482 {
483 }
484
485 FGProperties::~FGProperties ()
486 {
487 }
488
489 void
490 FGProperties::init ()
491 {
492 }
493
494 void
495 FGProperties::bind ()
496 {
497                                 // Simulation
498   fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
499   fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
500   fgTie("/sim/freeze/master", getFreeze, setFreeze);
501
502   fgTie("/sim/time/elapsed-sec", getElapsedTime_sec);
503   fgTie("/sim/time/gmt", getDateString, setDateString);
504   fgSetArchivable("/sim/time/gmt");
505   fgTie("/sim/time/gmt-string", getGMTString);
506
507                                 // Position
508   fgTie("/position/latitude-string", getLatitudeString);
509   fgTie("/position/longitude-string", getLongitudeString);
510
511                                 // Orientation
512   fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
513   fgTie("/orientation/track-magnetic-deg", getTrackMag);
514
515   fgTie("/environment/magnetic-variation-deg", getMagVar);
516   fgTie("/environment/magnetic-dip-deg", getMagDip);
517
518   fgTie("/sim/time/warp", getWarp, setWarp, false);
519   fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
520
521                                 // Misc. Temporary junk.
522   fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
523 }
524
525 void
526 FGProperties::unbind ()
527 {
528                                 // Simulation
529   fgUntie("/sim/logging/priority");
530   fgUntie("/sim/logging/classes");
531   fgUntie("/sim/freeze/master");
532
533   fgUntie("/sim/time/elapsed-sec");
534   fgUntie("/sim/time/gmt");
535   fgUntie("/sim/time/gmt-string");
536                                 // Position
537   fgUntie("/position/latitude-string");
538   fgUntie("/position/longitude-string");
539
540                                 // Orientation
541   fgUntie("/orientation/heading-magnetic-deg");
542   fgUntie("/orientation/track-magnetic-deg");
543
544                                 // Environment
545   fgUntie("/environment/magnetic-variation-deg");
546   fgUntie("/environment/magnetic-dip-deg");
547
548   fgUntie("/sim/time/warp");
549   fgUntie("/sim/time/warp-delta");
550
551                                 // Misc. Temporary junk.
552   fgUntie("/sim/temp/winding-ccw");
553   fgUntie("/sim/temp/full-screen");
554   fgUntie("/sim/temp/fdm-data-logging");
555 }
556
557 void
558 FGProperties::update (double dt)
559 {
560     static SGPropertyNode_ptr offset = fgGetNode("/sim/time/local-offset", true);
561     offset->setIntValue(globals->get_time_params()->get_local_offset());
562
563
564     // utc date/time
565     static SGPropertyNode_ptr uyear = fgGetNode("/sim/time/utc/year", true);
566     static SGPropertyNode_ptr umonth = fgGetNode("/sim/time/utc/month", true);
567     static SGPropertyNode_ptr uday = fgGetNode("/sim/time/utc/day", true);
568     static SGPropertyNode_ptr uhour = fgGetNode("/sim/time/utc/hour", true);
569     static SGPropertyNode_ptr umin = fgGetNode("/sim/time/utc/minute", true);
570     static SGPropertyNode_ptr usec = fgGetNode("/sim/time/utc/second", true);
571     static SGPropertyNode_ptr uwday = fgGetNode("/sim/time/utc/weekday", true);
572     static SGPropertyNode_ptr udsec = fgGetNode("/sim/time/utc/day-seconds", true);
573
574     struct tm *u = globals->get_time_params()->getGmt();
575     uyear->setIntValue(u->tm_year + 1900);
576     umonth->setIntValue(u->tm_mon + 1);
577     uday->setIntValue(u->tm_mday);
578     uhour->setIntValue(u->tm_hour);
579     umin->setIntValue(u->tm_min);
580     usec->setIntValue(u->tm_sec);
581     uwday->setIntValue(u->tm_wday);
582
583     udsec->setIntValue(u->tm_hour * 3600 + u->tm_min * 60 + u->tm_sec);
584
585
586     // real local date/time
587     static SGPropertyNode_ptr ryear = fgGetNode("/sim/time/real/year", true);
588     static SGPropertyNode_ptr rmonth = fgGetNode("/sim/time/real/month", true);
589     static SGPropertyNode_ptr rday = fgGetNode("/sim/time/real/day", true);
590     static SGPropertyNode_ptr rhour = fgGetNode("/sim/time/real/hour", true);
591     static SGPropertyNode_ptr rmin = fgGetNode("/sim/time/real/minute", true);
592     static SGPropertyNode_ptr rsec = fgGetNode("/sim/time/real/second", true);
593     static SGPropertyNode_ptr rwday = fgGetNode("/sim/time/real/weekday", true);
594
595     time_t real = time(0);
596     struct tm *r = localtime(&real);
597     ryear->setIntValue(r->tm_year + 1900);
598     rmonth->setIntValue(r->tm_mon + 1);
599     rday->setIntValue(r->tm_mday);
600     rhour->setIntValue(r->tm_hour);
601     rmin->setIntValue(r->tm_min);
602     rsec->setIntValue(r->tm_sec);
603     rwday->setIntValue(r->tm_wday);
604 }
605
606
607 \f
608 ////////////////////////////////////////////////////////////////////////
609 // Save and restore.
610 ////////////////////////////////////////////////////////////////////////
611
612
613 /**
614  * Save the current state of the simulator to a stream.
615  */
616 bool
617 fgSaveFlight (std::ostream &output, bool write_all)
618 {
619
620   fgSetBool("/sim/presets/onground", false);
621   fgSetArchivable("/sim/presets/onground");
622   fgSetBool("/sim/presets/trim", false);
623   fgSetArchivable("/sim/presets/trim");
624   fgSetString("/sim/presets/speed-set", "UVW");
625   fgSetArchivable("/sim/presets/speed-set");
626
627   try {
628     writeProperties(output, globals->get_props(), write_all);
629   } catch (const sg_exception &e) {
630     guiErrorMessage("Error saving flight: ", e);
631     return false;
632   }
633   return true;
634 }
635
636
637 /**
638  * Restore the current state of the simulator from a stream.
639  */
640 bool
641 fgLoadFlight (std::istream &input)
642 {
643   SGPropertyNode props;
644   try {
645     readProperties(input, &props);
646   } catch (const sg_exception &e) {
647     guiErrorMessage("Error reading saved flight: ", e);
648     return false;
649   }
650
651   fgSetBool("/sim/presets/onground", false);
652   fgSetBool("/sim/presets/trim", false);
653   fgSetString("/sim/presets/speed-set", "UVW");
654
655   copyProperties(&props, globals->get_props());
656   // When loading a flight, make it the
657   // new initial state.
658   globals->saveInitialState();
659   return true;
660 }
661
662
663 bool
664 fgLoadProps (const char * path, SGPropertyNode * props, bool in_fg_root, int default_mode)
665 {
666     string fullpath;
667     if (in_fg_root) {
668         SGPath loadpath(globals->get_fg_root());
669         loadpath.append(path);
670         fullpath = loadpath.str();
671     } else {
672         fullpath = path;
673     }
674
675     try {
676         readProperties(fullpath, props, default_mode);
677     } catch (const sg_exception &e) {
678         guiErrorMessage("Error reading properties: ", e);
679         return false;
680     }
681     return true;
682 }
683
684
685 \f
686 ////////////////////////////////////////////////////////////////////////
687 // Property convenience functions.
688 ////////////////////////////////////////////////////////////////////////
689
690 SGPropertyNode *
691 fgGetNode (const char * path, bool create)
692 {
693   return globals->get_props()->getNode(path, create);
694 }
695
696 SGPropertyNode * 
697 fgGetNode (const char * path, int index, bool create)
698 {
699   return globals->get_props()->getNode(path, index, create);
700 }
701
702 bool
703 fgHasNode (const char * path)
704 {
705   return (fgGetNode(path, false) != 0);
706 }
707
708 void
709 fgAddChangeListener (SGPropertyChangeListener * listener, const char * path)
710 {
711   fgGetNode(path, true)->addChangeListener(listener);
712 }
713
714 void
715 fgAddChangeListener (SGPropertyChangeListener * listener,
716                      const char * path, int index)
717 {
718   fgGetNode(path, index, true)->addChangeListener(listener);
719 }
720
721 bool
722 fgGetBool (const char * name, bool defaultValue)
723 {
724   return globals->get_props()->getBoolValue(name, defaultValue);
725 }
726
727 int
728 fgGetInt (const char * name, int defaultValue)
729 {
730   return globals->get_props()->getIntValue(name, defaultValue);
731 }
732
733 int
734 fgGetLong (const char * name, long defaultValue)
735 {
736   return globals->get_props()->getLongValue(name, defaultValue);
737 }
738
739 float
740 fgGetFloat (const char * name, float defaultValue)
741 {
742   return globals->get_props()->getFloatValue(name, defaultValue);
743 }
744
745 double
746 fgGetDouble (const char * name, double defaultValue)
747 {
748   return globals->get_props()->getDoubleValue(name, defaultValue);
749 }
750
751 const char *
752 fgGetString (const char * name, const char * defaultValue)
753 {
754   return globals->get_props()->getStringValue(name, defaultValue);
755 }
756
757 bool
758 fgSetBool (const char * name, bool val)
759 {
760   return globals->get_props()->setBoolValue(name, val);
761 }
762
763 bool
764 fgSetInt (const char * name, int val)
765 {
766   return globals->get_props()->setIntValue(name, val);
767 }
768
769 bool
770 fgSetLong (const char * name, long val)
771 {
772   return globals->get_props()->setLongValue(name, val);
773 }
774
775 bool
776 fgSetFloat (const char * name, float val)
777 {
778   return globals->get_props()->setFloatValue(name, val);
779 }
780
781 bool
782 fgSetDouble (const char * name, double val)
783 {
784   return globals->get_props()->setDoubleValue(name, val);
785 }
786
787 bool
788 fgSetString (const char * name, const char * val)
789 {
790   return globals->get_props()->setStringValue(name, val);
791 }
792
793 void
794 fgSetArchivable (const char * name, bool state)
795 {
796   SGPropertyNode * node = globals->get_props()->getNode(name);
797   if (node == 0)
798     SG_LOG(SG_GENERAL, SG_DEBUG,
799            "Attempt to set archive flag for non-existant property "
800            << name);
801   else
802     node->setAttribute(SGPropertyNode::ARCHIVE, state);
803 }
804
805 void
806 fgSetReadable (const char * name, bool state)
807 {
808   SGPropertyNode * node = globals->get_props()->getNode(name);
809   if (node == 0)
810     SG_LOG(SG_GENERAL, SG_DEBUG,
811            "Attempt to set read flag for non-existant property "
812            << name);
813   else
814     node->setAttribute(SGPropertyNode::READ, state);
815 }
816
817 void
818 fgSetWritable (const char * name, bool state)
819 {
820   SGPropertyNode * node = globals->get_props()->getNode(name);
821   if (node == 0)
822     SG_LOG(SG_GENERAL, SG_DEBUG,
823            "Attempt to set write flag for non-existant property "
824            << name);
825   else
826     node->setAttribute(SGPropertyNode::WRITE, state);
827 }
828
829 void
830 fgUntie(const char * name)
831 {
832   SGPropertyNode* node = globals->get_props()->getNode(name);
833   if (!node) {
834     SG_LOG(SG_GENERAL, SG_WARN, "fgUntie: unknown property " << name);
835     return;
836   }
837   
838   if (!node->isTied()) {
839     return;
840   }
841   
842   if (!node->untie()) {
843     SG_LOG(SG_GENERAL, SG_WARN, "Failed to untie property " << name);
844   }
845 }
846
847
848 // end of fg_props.cxx