]> git.mxchange.org Git - flightgear.git/blob - src/Main/options.cxx
Bernie Bright:
[flightgear.git] / src / Main / options.cxx
1 // options.cxx -- class to handle command line options
2 //
3 // Written by Curtis Olson, started April 1998.
4 //
5 // Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <simgear/compiler.h>
29 #include <simgear/misc/exception.hxx>
30
31 #include <math.h>               // rint()
32 #include <stdio.h>
33 #include <stdlib.h>             // atof(), atoi()
34 #include <string.h>             // strcmp()
35
36 #include STL_STRING
37
38 #include <simgear/math/sg_random.h>
39 #include <simgear/misc/sgstream.hxx>
40 #include <simgear/misc/sg_path.hxx>
41 #include <simgear/route/route.hxx>
42 #include <simgear/route/waypoint.hxx>
43
44 // #include <Include/general.hxx>
45 // #include <Airports/simple.hxx>
46 // #include <Cockpit/cockpit.hxx>
47 // #include <FDM/flight.hxx>
48 // #include <FDM/UIUCModel/uiuc_aircraftdir.h>
49 #ifdef FG_NETWORK_OLK
50 #  include <NetworkOLK/network.h>
51 #endif
52
53 #include <GUI/gui.h>
54
55 #include "globals.hxx"
56 #include "fg_init.hxx"
57 #include "fg_props.hxx"
58 #include "options.hxx"
59 #include "viewmgr.hxx"
60
61 SG_USING_STD(string);
62 SG_USING_NAMESPACE(std);
63
64
65 #define NEW_DEFAULT_MODEL_HZ 120
66
67 enum
68 {
69     FG_OPTIONS_OK = 0,
70     FG_OPTIONS_HELP = 1,
71     FG_OPTIONS_ERROR = 2
72 };
73
74 static double
75 atof( const string& str )
76 {
77
78 #ifdef __MWERKS__ 
79     // -dw- if ::atof is called, then we get an infinite loop
80     return std::atof( str.c_str() );
81 #else
82     return ::atof( str.c_str() );
83 #endif
84 }
85
86 static int
87 atoi( const string& str )
88 {
89 #ifdef __MWERKS__ 
90     // -dw- if ::atoi is called, then we get an infinite loop
91     return std::atoi( str.c_str() );
92 #else
93     return ::atoi( str.c_str() );
94 #endif
95 }
96
97
98 /**
99  * Set a few fail-safe default property values.
100  *
101  * These should all be set in $FG_ROOT/preferences.xml, but just
102  * in case, we provide some initial sane values here. This method 
103  * should be invoked *before* reading any init files.
104  */
105 void
106 fgSetDefaults ()
107 {
108     // set a possibly independent location for scenery data
109     char *envp = ::getenv( "FG_SCENERY" );
110
111     if ( envp != NULL ) {
112         // fg_root could be anywhere, so default to environmental
113         // variable $FG_ROOT if it is set.
114         globals->set_fg_scenery(envp);
115     } else {
116         // Otherwise, default to Scenery being in $FG_ROOT/Scenery
117         globals->set_fg_scenery("");
118     }
119                                 // Position (deliberately out of range)
120     fgSetDouble("/position/longitude-deg", 9999.0);
121     fgSetDouble("/position/latitude-deg", 9999.0);
122     fgSetDouble("/position/altitude-ft", -9999.0);
123
124                                 // Orientation
125     fgSetDouble("/orientation/heading-deg", 270);
126     fgSetDouble("/orientation/roll-deg", 0);
127     fgSetDouble("/orientation/pitch-deg", 0.424);
128
129                                 // Velocities
130     fgSetString("/sim/startup/speed-set", "knots");
131     fgSetDouble("/velocities/uBody-fps", 0.0);
132     fgSetDouble("/velocities/vBody-fps", 0.0);
133     fgSetDouble("/velocities/wBody-fps", 0.0);
134     fgSetDouble("/velocities/speed-north-fps", 0.0);
135     fgSetDouble("/velocities/speed-east-fps", 0.0);
136     fgSetDouble("/velocities/speed-down-fps", 0.0);
137     fgSetDouble("/velocities/airspeed-kt", 0.0);
138     fgSetDouble("/velocities/mach", 0.0);
139
140                                 // Miscellaneous
141     fgSetBool("/sim/startup/game-mode", false);
142     fgSetBool("/sim/startup/splash-screen", true);
143     fgSetBool("/sim/startup/intro-music", true);
144     // we want mouse-pointer to have an undefined value if nothing is
145     // specified so we can do the right thing for voodoo-1/2 cards.
146     // fgSetString("/sim/startup/mouse-pointer", "disabled");
147     fgSetString("/sim/control-mode", "joystick");
148     fgSetBool("/sim/auto-coordination", false);
149 #if !defined(WIN32)
150     fgSetString("/sim/startup/browser-app", "netscape");
151 #else
152     fgSetString("/sim/startup/browser-app", "webrun.bat");
153 #endif
154                                 // Features
155     fgSetBool("/sim/hud/visibility", false);
156     fgSetBool("/sim/panel/visibility", true);
157     fgSetBool("/sim/sound/audible", true);
158     fgSetBool("/sim/hud/antialiased", false);
159
160                                 // Flight Model options
161     fgSetString("/sim/flight-model", "jsb");
162     fgSetString("/sim/aero", "c172");
163     fgSetInt("/sim/model-hz", NEW_DEFAULT_MODEL_HZ);
164     fgSetInt("/sim/speed-up", 1);
165     fgSetBool("/sim/startup/trim", false);
166     fgSetBool("/sim/startup/onground", true);
167
168                                 // Rendering options
169     fgSetString("/sim/rendering/fog", "nicest");
170     fgSetBool("/environment/clouds/status", true);
171     fgSetBool("/sim/startup/fullscreen", false);
172     fgSetBool("/sim/rendering/shading", true);
173     fgSetBool("/sim/rendering/skyblend", true);
174     fgSetBool("/sim/rendering/textures", true);
175     fgSetBool("/sim/rendering/wireframe", false);
176     fgSetInt("/sim/startup/xsize", 800);
177     fgSetInt("/sim/startup/ysize", 600);
178     fgSetInt("/sim/rendering/bits-per-pixel", 16);
179     fgSetString("/sim/view-mode", "pilot");
180     fgSetDouble("/sim/current-view/heading-offset-deg", 0);
181     fgSetDouble("/environment/visibility-m", 20000);
182
183                                 // HUD options
184     fgSetString("/sim/startup/units", "feet");
185     fgSetString("/sim/hud/frame-stat-type", "tris");
186         
187                                 // Time options
188     fgSetInt("/sim/startup/time-offset", 0);
189     fgSetString("/sim/startup/time-offset-type", "system-offset");
190     fgSetLong("/sim/time/cur-time-override", 0);
191
192     fgSetBool("/sim/networking/network-olk", false);
193     fgSetString("/sim/networking/call-sign", "Johnny");
194
195                                 // Freeze options
196     fgSetBool("/sim/freeze/master", false);
197     fgSetBool("/sim/freeze/position", false);
198     fgSetBool("/sim/freeze/clock", false);
199     fgSetBool("/sim/freeze/fuel", false);
200 }
201
202
203 static bool
204 parse_wind (const string &wind, double * min_hdg, double * max_hdg,
205             double * speed, double * gust)
206 {
207   string::size_type pos = wind.find('@');
208   if (pos == string::npos)
209     return false;
210   string dir = wind.substr(0, pos);
211   string spd = wind.substr(pos+1);
212   pos = dir.find(':');
213   if (pos == string::npos) {
214     *min_hdg = *max_hdg = atof(dir.c_str());
215   } else {
216     *min_hdg = atof(dir.substr(0,pos).c_str());
217     *max_hdg = atof(dir.substr(pos+1).c_str());
218   }
219   pos = spd.find(':');
220   if (pos == string::npos) {
221     *speed = *gust = atof(spd.c_str());
222   } else {
223     *speed = atof(spd.substr(0,pos).c_str());
224     *gust = atof(spd.substr(pos+1).c_str());
225   }
226   return true;
227 }
228
229 // parse a time string ([+/-]%f[:%f[:%f]]) into hours
230 static double
231 parse_time(const string& time_in) {
232     char *time_str, num[256];
233     double hours, minutes, seconds;
234     double result = 0.0;
235     int sign = 1;
236     int i;
237
238     time_str = (char *)time_in.c_str();
239
240     // printf("parse_time(): %s\n", time_str);
241
242     // check for sign
243     if ( strlen(time_str) ) {
244         if ( time_str[0] == '+' ) {
245             sign = 1;
246             time_str++;
247         } else if ( time_str[0] == '-' ) {
248             sign = -1;
249             time_str++;
250         }
251     }
252     // printf("sign = %d\n", sign);
253
254     // get hours
255     if ( strlen(time_str) ) {
256         i = 0;
257         while ( (time_str[0] != ':') && (time_str[0] != '\0') ) {
258             num[i] = time_str[0];
259             time_str++;
260             i++;
261         }
262         if ( time_str[0] == ':' ) {
263             time_str++;
264         }
265         num[i] = '\0';
266         hours = atof(num);
267         // printf("hours = %.2lf\n", hours);
268
269         result += hours;
270     }
271
272     // get minutes
273     if ( strlen(time_str) ) {
274         i = 0;
275         while ( (time_str[0] != ':') && (time_str[0] != '\0') ) {
276             num[i] = time_str[0];
277             time_str++;
278             i++;
279         }
280         if ( time_str[0] == ':' ) {
281             time_str++;
282         }
283         num[i] = '\0';
284         minutes = atof(num);
285         // printf("minutes = %.2lf\n", minutes);
286
287         result += minutes / 60.0;
288     }
289
290     // get seconds
291     if ( strlen(time_str) ) {
292         i = 0;
293         while ( (time_str[0] != ':') && (time_str[0] != '\0') ) {
294             num[i] = time_str[0];
295             time_str++;
296             i++;
297         }
298         num[i] = '\0';
299         seconds = atof(num);
300         // printf("seconds = %.2lf\n", seconds);
301
302         result += seconds / 3600.0;
303     }
304
305     return(sign * result);
306 }
307
308
309 // parse a date string (yyyy:mm:dd:hh:mm:ss) into a time_t (seconds)
310 static long int 
311 parse_date( const string& date)
312 {
313     struct tm gmt;
314     char * date_str, num[256];
315     int i;
316     // initialize to zero
317     gmt.tm_sec = 0;
318     gmt.tm_min = 0;
319     gmt.tm_hour = 0;
320     gmt.tm_mday = 0;
321     gmt.tm_mon = 0;
322     gmt.tm_year = 0;
323     gmt.tm_isdst = 0; // ignore daylight savings time for the moment
324     date_str = (char *)date.c_str();
325     // get year
326     if ( strlen(date_str) ) {
327         i = 0;
328         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
329             num[i] = date_str[0];
330             date_str++;
331             i++;
332         }
333         if ( date_str[0] == ':' ) {
334             date_str++;
335         }
336         num[i] = '\0';
337         gmt.tm_year = atoi(num) - 1900;
338     }
339     // get month
340     if ( strlen(date_str) ) {
341         i = 0;
342         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
343             num[i] = date_str[0];
344             date_str++;
345             i++;
346         }
347         if ( date_str[0] == ':' ) {
348             date_str++;
349         }
350         num[i] = '\0';
351         gmt.tm_mon = atoi(num) -1;
352     }
353     // get day
354     if ( strlen(date_str) ) {
355         i = 0;
356         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
357             num[i] = date_str[0];
358             date_str++;
359             i++;
360         }
361         if ( date_str[0] == ':' ) {
362             date_str++;
363         }
364         num[i] = '\0';
365         gmt.tm_mday = atoi(num);
366     }
367     // get hour
368     if ( strlen(date_str) ) {
369         i = 0;
370         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
371             num[i] = date_str[0];
372             date_str++;
373             i++;
374         }
375         if ( date_str[0] == ':' ) {
376             date_str++;
377         }
378         num[i] = '\0';
379         gmt.tm_hour = atoi(num);
380     }
381     // get minute
382     if ( strlen(date_str) ) {
383         i = 0;
384         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
385             num[i] = date_str[0];
386             date_str++;
387             i++;
388         }
389         if ( date_str[0] == ':' ) {
390             date_str++;
391         }
392         num[i] = '\0';
393         gmt.tm_min = atoi(num);
394     }
395     // get second
396     if ( strlen(date_str) ) {
397         i = 0;
398         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
399             num[i] = date_str[0];
400             date_str++;
401             i++;
402         }
403         if ( date_str[0] == ':' ) {
404             date_str++;
405         }
406         num[i] = '\0';
407         gmt.tm_sec = atoi(num);
408     }
409     time_t theTime = sgTimeGetGMT( gmt.tm_year, gmt.tm_mon, gmt.tm_mday,
410                                    gmt.tm_hour, gmt.tm_min, gmt.tm_sec );
411     //printf ("Date is %s\n", ctime(&theTime));
412     //printf ("in seconds that is %d\n", theTime);
413     //exit(1);
414     return (theTime);
415 }
416
417
418 // parse angle in the form of [+/-]ddd:mm:ss into degrees
419 static double
420 parse_degree( const string& degree_str) {
421     double result = parse_time( degree_str );
422
423     // printf("Degree = %.4f\n", result);
424
425     return(result);
426 }
427
428
429 // parse time offset string into seconds
430 static int
431 parse_time_offset( const string& time_str) {
432     int result;
433
434     // printf("time offset = %s\n", time_str);
435
436 #ifdef HAVE_RINT
437     result = (int)rint(parse_time(time_str) * 3600.0);
438 #else
439     result = (int)(parse_time(time_str) * 3600.0);
440 #endif
441
442     // printf("parse_time_offset(): %d\n", result);
443
444     return( result );
445 }
446
447
448 // Parse --fov=x.xx type option 
449 static double
450 parse_fov( const string& arg ) {
451     double fov = atof(arg);
452
453     if ( fov < FG_FOV_MIN ) { fov = FG_FOV_MIN; }
454     if ( fov > FG_FOV_MAX ) { fov = FG_FOV_MAX; }
455
456     fgSetDouble("/sim/current-view/field-of-view", fov);
457
458     // printf("parse_fov(): result = %.4f\n", fov);
459
460     return fov;
461 }
462
463
464 // Parse I/O channel option
465 //
466 // Format is "--protocol=medium,direction,hz,medium_options,..."
467 //
468 //   protocol = { native, nmea, garmin, fgfs, rul, pve, etc. }
469 //   medium = { serial, socket, file, etc. }
470 //   direction = { in, out, bi }
471 //   hz = number of times to process channel per second (floating
472 //        point values are ok.
473 //
474 // Serial example "--nmea=serial,dir,hz,device,baud" where
475 // 
476 //  device = OS device name of serial line to be open()'ed
477 //  baud = {300, 1200, 2400, ..., 230400}
478 //
479 // Socket exacmple "--native=socket,dir,hz,machine,port,style" where
480 // 
481 //  machine = machine name or ip address if client (leave empty if server)
482 //  port = port, leave empty to let system choose
483 //  style = tcp or udp
484 //
485 // File example "--garmin=file,dir,hz,filename" where
486 // 
487 //  filename = file system file name
488
489 static bool 
490 add_channel( const string& type, const string& channel_str ) {
491     // cout << "Channel string = " << channel_str << endl;
492
493     globals->get_channel_options_list()->push_back( type + "," + channel_str );
494
495     return true;
496 }
497
498
499 static void
500 setup_wind (double min_hdg, double max_hdg, double speed, double gust)
501 {
502   fgSetDouble("/environment/wind-from-heading-deg", min_hdg);
503   fgSetDouble("/environment/params/min-wind-from-heading-deg", min_hdg);
504   fgSetDouble("/environment/params/max-wind-from-heading-deg", max_hdg);
505   fgSetDouble("/environment/wind-speed-kt", speed);
506   fgSetDouble("/environment/params/base-wind-speed-kt", speed);
507   fgSetDouble("/environment/params/gust-wind-speed-kt", gust);
508
509   SG_LOG(SG_GENERAL, SG_INFO, "WIND: " << min_hdg << '@' << 
510          speed << " knots" << endl);
511
512 #ifdef FG_WEATHERCM
513   // convert to fps
514   speed *= SG_NM_TO_METER * SG_METER_TO_FEET * (1.0/3600);
515   while (min_hdg > 360)
516     min_hdg -= 360;
517   while (min_hdg <= 0)
518     min_hdg += 360;
519   min_hdg *= SGD_DEGREES_TO_RADIANS;
520   fgSetDouble("/environment/wind-from-north-fps", speed * cos(dir));
521   fgSetDouble("/environment/wind-from-east-fps", speed * sin(dir));
522 #endif // FG_WEATHERCM
523 }
524
525
526 // Parse --wp=ID[@alt]
527 static bool 
528 parse_wp( const string& arg ) {
529     string id, alt_str;
530     double alt = 0.0;
531
532     string::size_type pos = arg.find( "@" );
533     if ( pos != string::npos ) {
534         id = arg.substr( 0, pos );
535         alt_str = arg.substr( pos + 1 );
536         // cout << "id str = " << id << "  alt str = " << alt_str << endl;
537         alt = atof( alt_str.c_str() );
538         if ( !strcmp(fgGetString("/sim/startup/units"), "feet") ) {
539             alt *= SG_FEET_TO_METER;
540         }
541     } else {
542         id = arg;
543     }
544
545     FGAirport a;
546     if ( fgFindAirportID( id, &a ) ) {
547         SGWayPoint wp( a.longitude, a.latitude, alt, SGWayPoint::WGS84, id );
548         globals->get_route()->add_waypoint( wp );
549
550         return true;
551     } else {
552         return false;
553     }
554 }
555
556
557 // Parse --flight-plan=[file]
558 static bool 
559 parse_flightplan(const string& arg)
560 {
561     sg_gzifstream in(arg.c_str());
562     if ( !in.is_open() ) {
563         return false;
564     }
565     while ( true ) {
566         string line;
567
568 #if defined( macintosh )
569         getline( in, line, '\r' );
570 #else
571         getline( in, line, '\n' );
572 #endif
573
574         // catch extraneous (DOS) line ending character
575         if ( line[line.length() - 1] < 32 ) {
576             line = line.substr( 0, line.length()-1 );
577         }
578
579         if ( in.eof() ) {
580             break;
581         }
582         parse_wp(line);
583     }
584
585     return true;
586 }
587
588
589 // Parse a single option
590 static int 
591 parse_option (const string& arg) 
592 {
593     // General Options
594     if ( (arg == "--help") || (arg == "-h") ) {
595         // help/usage request
596         return(FG_OPTIONS_HELP);
597     } else if ( arg == "--disable-game-mode") {
598         fgSetBool("/sim/startup/game-mode", false);
599     } else if ( arg == "--enable-game-mode" ) {
600         fgSetBool("/sim/startup/game-mode", true);
601     } else if ( arg == "--disable-splash-screen" ) {
602         fgSetBool("/sim/startup/splash-screen", false); 
603     } else if ( arg == "--enable-splash-screen" ) {
604         fgSetBool("/sim/startup/splash-screen", true);
605     } else if ( arg == "--disable-intro-music" ) {
606         fgSetBool("/sim/startup/intro-music", false);
607     } else if ( arg == "--enable-intro-music" ) {
608         fgSetBool("/sim/startup/intro-music", true);
609     } else if ( arg == "--disable-mouse-pointer" ) {
610         fgSetString("/sim/startup/mouse-pointer", "disabled");
611     } else if ( arg == "--enable-mouse-pointer" ) {
612         fgSetString("/sim/startup/mouse-pointer", "enabled");
613     } else if ( arg == "--disable-random-objects" ) {
614         fgSetBool("/sim/rendering/random-objects", false);
615     } else if ( arg == "--enable-random-objects" ) {
616         fgSetBool("/sim/rendering/random-objects", true);
617     } else if ( arg == "--disable-freeze" ) {
618         fgSetBool("/sim/freeze/master", false);
619     } else if ( arg == "--enable-freeze" ) {
620         fgSetBool("/sim/freeze/master", true);
621     } else if ( arg == "--disable-fuel-freeze" ) {
622         fgSetBool("/sim/freeze/fuel", false);
623     } else if ( arg == "--enable-fuel-freeze" ) {
624         fgSetBool("/sim/freeze/fuel", true);
625     } else if ( arg == "--disable-clock-freeze" ) {
626         fgSetBool("/sim/freeze/clock", false);
627     } else if ( arg == "--enable-clock-freeze" ) {
628         fgSetBool("/sim/freeze/clock", true);
629     } else if ( arg == "--disable-anti-alias-hud" ) {
630         fgSetBool("/sim/hud/antialiased", false);
631     } else if ( arg == "--enable-anti-alias-hud" ) {
632         fgSetBool("/sim/hud/antialiased", true);
633     } else if ( arg.find( "--control=") == 0 ) {
634         fgSetString("/sim/control-mode", arg.substr(10).c_str());
635     } else if ( arg == "--disable-auto-coordination" ) {
636         fgSetBool("/sim/auto-coordination", false);
637     } else if ( arg == "--enable-auto-coordination" ) {
638         fgSetBool("/sim/auto-coordination", true);
639     } else if ( arg.find( "--browser-app=") == 0 ) {
640         fgSetString("/sim/startup/browser-app", arg.substr(14).c_str());
641     } else if ( arg == "--disable-hud" ) {
642         fgSetBool("/sim/hud/visibility", false);
643     } else if ( arg == "--enable-hud" ) {
644         fgSetBool("/sim/hud/visibility", true);
645     } else if ( arg == "--disable-panel" ) {
646         fgSetBool("/sim/panel/visibility", false);
647     } else if ( arg == "--enable-panel" ) {
648         fgSetBool("/sim/panel/visibility", true);
649     } else if ( arg == "--disable-sound" ) {
650         fgSetBool("/sim/sound/audible", false);
651     } else if ( arg == "--enable-sound" ) {
652         fgSetBool("/sim/sound/audible", true);
653     } else if ( arg.find( "--airport-id=") == 0 ) {
654                                 // NB: changed property name!!!
655         fgSetString("/sim/startup/airport-id", arg.substr(13).c_str());
656     } else if ( arg.find( "--offset-distance=") == 0 ) {
657         fgSetDouble("/sim/startup/offset-distance", atof(arg.substr(18)));
658     } else if ( arg.find( "--offset-azimuth=") == 0 ) {
659         fgSetDouble("/sim/startup/offset-azimuth", atof(arg.substr(17))); 
660     } else if ( arg.find( "--lon=" ) == 0 ) {
661         fgSetDouble("/position/longitude-deg",
662                               parse_degree(arg.substr(6)));
663         fgSetString("/sim/startup/airport-id", "");
664     } else if ( arg.find( "--lat=" ) == 0 ) {
665         fgSetDouble("/position/latitude-deg",
666                               parse_degree(arg.substr(6)));
667         fgSetString("/sim/startup/airport-id", "");
668     } else if ( arg.find( "--altitude=" ) == 0 ) {
669         fgSetBool("/sim/startup/onground", false);
670         if ( !strcmp(fgGetString("/sim/startup/units"), "feet") )
671             fgSetDouble("/position/altitude-ft", atof(arg.substr(11)));
672         else
673             fgSetDouble("/position/altitude-ft",
674                         atof(arg.substr(11)) * SG_METER_TO_FEET);
675     } else if ( arg.find( "--uBody=" ) == 0 ) {
676         fgSetString("/sim/startup/speed-set", "UVW");
677         if ( !strcmp(fgGetString("/sim/startup/units"), "feet") )
678           fgSetDouble("/velocities/uBody-fps", atof(arg.substr(8)));
679         else
680           fgSetDouble("/velocities/uBody-fps",
681                                atof(arg.substr(8)) * SG_METER_TO_FEET);
682     } else if ( arg.find( "--vBody=" ) == 0 ) {
683         fgSetString("/sim/startup/speed-set", "UVW");
684         if ( !strcmp(fgGetString("/sim/startup/units"), "feet") )
685           fgSetDouble("/velocities/vBody-fps", atof(arg.substr(8)));
686         else
687           fgSetDouble("/velocities/vBody-fps",
688                                atof(arg.substr(8)) * SG_METER_TO_FEET);
689     } else if ( arg.find( "--wBody=" ) == 0 ) {
690         fgSetString("/sim/startup/speed-set", "UVW");
691         if ( !strcmp(fgGetString("/sim/startup/units"), "feet") )
692           fgSetDouble("/velocities/wBody-fps", atof(arg.substr(8)));
693         else
694           fgSetDouble("/velocities/wBody-fps",
695                                atof(arg.substr(8)) * SG_METER_TO_FEET);
696     } else if ( arg.find( "--vNorth=" ) == 0 ) {
697         fgSetString("/sim/startup/speed-set", "NED");
698         if ( !strcmp(fgGetString("/sim/startup/units"), "feet") )
699           fgSetDouble("/velocities/speed-north-fps", atof(arg.substr(9)));
700         else
701           fgSetDouble("/velocities/speed-north-fps",
702                                atof(arg.substr(9)) * SG_METER_TO_FEET);
703     } else if ( arg.find( "--vEast=" ) == 0 ) {
704         fgSetString("/sim/startup/speed-set", "NED");
705         if ( !strcmp(fgGetString("/sim/startup/units"), "feet") )
706           fgSetDouble("/velocities/speed-east-fps", atof(arg.substr(8)));
707         else
708           fgSetDouble("/velocities/speed-east-fps",
709                       atof(arg.substr(8)) * SG_METER_TO_FEET);
710     } else if ( arg.find( "--vDown=" ) == 0 ) {
711         fgSetString("/sim/startup/speed-set", "NED");
712         if ( !strcmp(fgGetString("/sim/startup/units"), "feet") )
713           fgSetDouble("/velocities/speed-down-fps", atof(arg.substr(8)));
714         else
715           fgSetDouble("/velocities/speed-down-fps",
716                                atof(arg.substr(8)) * SG_METER_TO_FEET);
717     } else if ( arg.find( "--vc=" ) == 0) {
718         fgSetString("/sim/startup/speed-set", "knots");
719         fgSetDouble("/velocities/airspeed-kt", atof(arg.substr(5)));
720     } else if ( arg.find( "--mach=" ) == 0) {
721         fgSetString("/sim/startup/speed-set", "mach");
722         fgSetDouble("/velocities/mach", atof(arg.substr(7)));
723     } else if ( arg.find( "--heading=" ) == 0 ) {
724         fgSetDouble("/orientation/heading-deg", atof(arg.substr(10)));
725     } else if ( arg.find( "--roll=" ) == 0 ) {
726         fgSetDouble("/orientation/roll-deg", atof(arg.substr(7)));
727     } else if ( arg.find( "--pitch=" ) == 0 ) {
728         fgSetDouble("/orientation/pitch-deg", atof(arg.substr(8)));
729     } else if ( arg.find( "--glideslope=" ) == 0 ) {
730         fgSetDouble("/velocities/glideslope", atof(arg.substr(13))
731                                           *SG_DEGREES_TO_RADIANS);
732     }  else if ( arg.find( "--roc=" ) == 0 ) {
733         fgSetDouble("/velocities/vertical-speed-fps", atof(arg.substr(6))/60);
734     } else if ( arg.find( "--fg-root=" ) == 0 ) {
735         globals->set_fg_root(arg.substr( 10 ));
736     } else if ( arg.find( "--fg-scenery=" ) == 0 ) {
737         globals->set_fg_scenery(arg.substr( 13 ));
738     } else if ( arg.find( "--fdm=" ) == 0 ) {
739         fgSetString("/sim/flight-model", arg.substr(6).c_str());
740     } else if ( arg.find( "--aero=" ) == 0 ) {
741         fgSetString("/sim/aero", arg.substr(7).c_str());
742     } else if ( arg.find( "--aircraft-dir=" ) == 0 ) {
743         fgSetString("/sim/aircraft-dir", arg.substr(15).c_str());
744     } else if ( arg.find( "--model-hz=" ) == 0 ) {
745         fgSetInt("/sim/model-hz", atoi(arg.substr(11)));
746     } else if ( arg.find( "--speed=" ) == 0 ) {
747         fgSetInt("/sim/speed-up", atoi(arg.substr(8)));
748     } else if ( arg.find( "--trim") == 0) {
749         fgSetBool("/sim/startup/trim", true);
750     } else if ( arg.find( "--notrim") == 0) {
751         fgSetBool("/sim/startup/trim", false);
752     } else if ( arg.find( "--on-ground") == 0) {
753         fgSetBool("/sim/startup/onground", true);
754     } else if ( arg.find( "--in-air") == 0) {
755         fgSetBool("/sim/startup/onground", false);
756     } else if ( arg == "--fog-disable" ) {
757         fgSetString("/sim/rendering/fog", "disabled");
758     } else if ( arg == "--fog-fastest" ) {
759         fgSetString("/sim/rendering/fog", "fastest");
760     } else if ( arg == "--fog-nicest" ) {
761         fgSetString("/sim/fog", "nicest");
762     } else if ( arg == "--disable-clouds" ) {
763         fgSetBool("/environment/clouds/status", false);
764     } else if ( arg == "--enable-clouds" ) {
765         fgSetBool("/environment/clouds/status", true);
766     } else if ( arg.find( "--fov=" ) == 0 ) {
767         parse_fov( arg.substr(6) );
768     } else if ( arg == "--disable-fullscreen" ) {
769         fgSetBool("/sim/startup/fullscreen", false);
770     } else if ( arg== "--enable-fullscreen") {
771         fgSetBool("/sim/startup/fullscreen", true);
772     } else if ( arg == "--shading-flat") {
773         fgSetBool("/sim/rendering/shading", false);
774     } else if ( arg == "--shading-smooth") {
775         fgSetBool("/sim/rendering/shading", true);
776     } else if ( arg == "--disable-skyblend") {
777         fgSetBool("/sim/rendering/skyblend", false);
778     } else if ( arg== "--enable-skyblend" ) {
779         fgSetBool("/sim/rendering/skyblend", true);
780     } else if ( arg == "--disable-textures" ) {
781         fgSetBool("/sim/rendering/textures", false);
782     } else if ( arg == "--enable-textures" ) {
783         fgSetBool("/sim/rendering/textures", true);
784     } else if ( arg == "--disable-wireframe" ) {
785         fgSetBool("/sim/rendering/wireframe", false);
786     } else if ( arg == "--enable-wireframe" ) {
787         fgSetBool("/sim/rendering/wireframe", true);
788     } else if ( arg.find( "--geometry=" ) == 0 ) {
789         bool geometry_ok = true;
790         int xsize = 0, ysize = 0;
791         string geometry = arg.substr( 11 );
792         string::size_type i = geometry.find('x');
793
794         if (i != string::npos) {
795             xsize = atoi(geometry.substr(0, i));
796             ysize = atoi(geometry.substr(i+1));
797         } else {
798             geometry_ok = false;
799         }
800
801         if ( xsize <= 0 || ysize <= 0 ) {
802             xsize = 640;
803             ysize = 480;
804             geometry_ok = false;
805         }
806
807         if ( !geometry_ok ) {
808             SG_LOG( SG_GENERAL, SG_ALERT, "Unknown geometry: " << geometry );
809             SG_LOG( SG_GENERAL, SG_ALERT,
810                     "Setting geometry to " << xsize << 'x' << ysize << '\n');
811         } else {
812           SG_LOG( SG_GENERAL, SG_INFO,
813                   "Setting geometry to " << xsize << 'x' << ysize << '\n');
814           fgSetInt("/sim/startup/xsize", xsize);
815           fgSetInt("/sim/startup/ysize", ysize);
816         }
817     } else if ( arg.find( "--bpp=" ) == 0 ) {
818         string bits_per_pix = arg.substr( 6 );
819         if ( bits_per_pix == "16" ) {
820             fgSetInt("/sim/rendering/bits-per-pixel", 16);
821         } else if ( bits_per_pix == "24" ) {
822             fgSetInt("/sim/rendering/bits-per-pixel", 24);
823         } else if ( bits_per_pix == "32" ) {
824             fgSetInt("/sim/rendering/bits-per-pixel", 32);
825         } else {
826           SG_LOG(SG_GENERAL, SG_ALERT, "Unsupported bpp " << bits_per_pix);
827         }
828     } else if ( arg == "--units-feet" ) {
829         fgSetString("/sim/startup/units", "feet");
830     } else if ( arg == "--units-meters" ) {
831         fgSetString("/sim/startup/units", "meters");
832     } else if ( arg.find( "--time-offset" ) == 0 ) {
833         fgSetInt("/sim/startup/time-offset",
834                  parse_time_offset( (arg.substr(14)) ));
835         fgSetString("/sim/startup/time-offset-type", "system-offset");
836     } else if ( arg.find( "--time-match-real") == 0 ) {
837         fgSetString("/sim/startup/time-offset-type", "system-offset");
838     } else if ( arg.find( "--time-match-local") == 0 ) {
839         fgSetString("/sim/startup/time-offset-type", "latitude-offset");
840     } else if ( arg.find( "--start-date-sys=") == 0 ) {
841         fgSetInt("/sim/startup/time-offset", parse_date((arg.substr(17))));
842         fgSetString("/sim/startup/time-offset-type", "system");
843     } else if ( arg.find( "--start-date-lat=") == 0 ) {
844         fgSetInt("/sim/startup/time-offset", parse_date((arg.substr(17))));
845         fgSetString("/sim/startup/time-offset-type", "latitude");
846     } else if ( arg.find( "--start-date-gmt=") == 0 ) {
847         fgSetInt("/sim/startup/time-offset", parse_date((arg.substr(17))));
848         fgSetString("/sim/startup/time-offset-type", "gmt");
849     } else if ( arg == "--hud-tris" ) {
850         fgSetString("/sim/hud/frame-stat-type", "tris");
851     } else if ( arg == "--hud-culled" ) {
852         fgSetString("/sim/hud/frame-stat-type", "culled");
853     } else if ( arg.find( "--atc610x" ) == 0 ) {
854         add_channel( "atc610x", "dummy" );
855     } else if ( arg.find( "--atlas=" ) == 0 ) {
856         add_channel( "atlas", arg.substr(8) );
857     } else if ( arg.find( "--httpd=" ) == 0 ) {
858         add_channel( "httpd", arg.substr(8) );
859 #ifdef FG_JPEG_SERVER
860     } else if ( arg.find( "--jpg-httpd=" ) == 0 ) {
861         add_channel( "jpg-httpd", arg.substr(12) );
862 #endif
863     } else if ( arg.find( "--native=" ) == 0 ) {
864         add_channel( "native", arg.substr(9) );
865     } else if ( arg.find( "--native-ctrls=" ) == 0 ) {
866         add_channel( "native_ctrls", arg.substr(15) );
867     } else if ( arg.find( "--native-fdm=" ) == 0 ) {
868         add_channel( "native_fdm", arg.substr(13) );
869     } else if ( arg.find( "--opengc=" ) == 0 ) {
870         // char stop;
871         // cout << "Adding channel for OpenGC Display" << endl; cin >> stop;
872         add_channel( "opengc", arg.substr(9) );
873     } else if ( arg.find( "--garmin=" ) == 0 ) {
874         add_channel( "garmin", arg.substr(9) );
875     } else if ( arg.find( "--nmea=" ) == 0 ) {
876         add_channel( "nmea", arg.substr(7) );
877     } else if ( arg.find( "--props=" ) == 0 ) {
878         add_channel( "props", arg.substr(8) );
879     } else if ( arg.find( "--telnet=" ) == 0 ) {
880         add_channel( "telnet", arg.substr(9) );
881     } else if ( arg.find( "--pve=" ) == 0 ) {
882         add_channel( "pve", arg.substr(6) );
883     } else if ( arg.find( "--ray=" ) == 0 ) {
884         add_channel( "ray", arg.substr(6) );
885     } else if ( arg.find( "--rul=" ) == 0 ) {
886         add_channel( "rul", arg.substr(6) );
887     } else if ( arg.find( "--joyclient=" ) == 0 ) {
888         add_channel( "joyclient", arg.substr(12) );
889 #ifdef FG_NETWORK_OLK
890     } else if ( arg == "--disable-network-olk" ) {
891         fgSetBool("/sim/networking/olk", false);
892     } else if ( arg== "--enable-network-olk") {
893         fgSetBool("/sim/networking/olk", true);
894     } else if ( arg == "--net-hud" ) {
895         fgSetBool("/sim/hud/net-display", true);
896         net_hud_display = 1;    // FIXME
897     } else if ( arg.find( "--net-id=") == 0 ) {
898         fgSetString("sim/networking/call-sign", arg.substr(9).c_str());
899 #endif
900     } else if ( arg.find( "--prop:" ) == 0 ) {
901         string assign = arg.substr(7);
902         string::size_type pos = assign.find('=');
903         if ( pos == arg.npos || pos == 0 ) {
904             SG_LOG( SG_GENERAL, SG_ALERT, "Bad property assignment: " << arg );
905             return FG_OPTIONS_ERROR;
906         }
907         string name = assign.substr(0, pos);
908         string value = assign.substr(pos + 1);
909         fgSetString(name.c_str(), value.c_str());
910         // SG_LOG(SG_GENERAL, SG_INFO, "Setting default value of property "
911         //        << name << " to \"" << value << '"');
912     } else if ( arg.find("--trace-read=") == 0) {
913         string name = arg.substr(13);
914         SG_LOG(SG_GENERAL, SG_INFO, "Tracing reads for property " << name);
915         fgGetNode(name.c_str(), true)
916           ->setAttribute(SGPropertyNode::TRACE_READ, true);
917     } else if ( arg.find("--trace-write=") == 0) {
918         string name = arg.substr(14);
919         SG_LOG(SG_GENERAL, SG_INFO, "Tracing writes for property " << name);
920         fgGetNode(name.c_str(), true)
921           ->setAttribute(SGPropertyNode::TRACE_WRITE, true);
922     } else if ( arg.find( "--view-offset=" ) == 0 ) {
923         // $$$ begin - added VS Renganathan, 14 Oct 2K
924         // for multi-window outside window imagery
925         string woffset = arg.substr( 14 );
926         double default_view_offset = 0.0;
927         if ( woffset == "LEFT" ) {
928                default_view_offset = SGD_PI * 0.25;
929         } else if ( woffset == "RIGHT" ) {
930             default_view_offset = SGD_PI * 1.75;
931         } else if ( woffset == "CENTER" ) {
932             default_view_offset = 0.00;
933         } else {
934             default_view_offset = atof( woffset.c_str() ) * SGD_DEGREES_TO_RADIANS;
935         }
936         /* apparently not used (CLO, 11 Jun 2002) 
937            FGViewer *pilot_view =
938               (FGViewer *)globals->get_viewmgr()->get_view( 0 ); */
939         // this will work without calls to the viewer...
940         fgSetDouble( "/sim/current-view/heading-offset-deg",
941                      default_view_offset  * SGD_RADIANS_TO_DEGREES );
942     // $$$ end - added VS Renganathan, 14 Oct 2K
943     } else if ( arg.find( "--visibility=" ) == 0 ) {
944         fgSetDouble("/environment/visibility-m", atof(arg.substr(13)));
945     } else if ( arg.find( "--visibility-miles=" ) == 0 ) {
946         double visibility = atof(arg.substr(19)) * 5280.0 * SG_FEET_TO_METER;
947         fgSetDouble("/environment/visibility-m", visibility);
948     } else if ( arg.find( "--random-wind" ) == 0 ) {
949         double min_hdg = sg_random() * 360.0;
950         double max_hdg = min_hdg + (20 - sqrt(sg_random() * 400));
951         double speed = 40 - sqrt(sg_random() * 1600.0);
952         double gust = speed + (10 - sqrt(sg_random() * 100));
953         setup_wind(min_hdg, max_hdg, speed, gust);
954     } else if ( arg.find( "--wind=" ) == 0 ) {
955         double min_hdg, max_hdg, speed, gust;
956         if (!parse_wind(arg.substr(7), &min_hdg, &max_hdg, &speed, &gust)) {
957           SG_LOG( SG_GENERAL, SG_ALERT, "bad wind value " << arg.substr(7) );
958           return FG_OPTIONS_ERROR;
959         }
960         setup_wind(min_hdg, max_hdg, speed, gust);
961     } else if ( arg.find( "--wp=" ) == 0 ) {
962         parse_wp( arg.substr( 5 ) );
963     } else if ( arg.find( "--flight-plan=") == 0) {
964         parse_flightplan ( arg.substr (14) );
965     } else if ( arg.find( "--config=" ) == 0 ) {
966         string file = arg.substr(9);
967         try {
968           readProperties(file, globals->get_props());
969         } catch (const sg_exception &e) {
970           string message = "Error loading config file: ";
971           message += e.getFormattedMessage();
972           SG_LOG(SG_INPUT, SG_ALERT, message);
973           exit(2);
974         }
975     } else if ( arg.find( "--aircraft=" ) == 0 ) {
976         // read in the top level aircraft definition file
977         SGPath apath( globals->get_fg_root() );
978         apath.append( "Aircraft" );
979         apath.append( arg.substr(11) );
980         apath.concat( "-set.xml" );
981         SG_LOG(SG_INPUT, SG_INFO, "Reading aircraft: " << arg.substr(11)
982             << " from " << apath.str());
983         readProperties( apath.str(), globals->get_props() );
984     } else {
985         SG_LOG( SG_GENERAL, SG_ALERT, "Unknown option '" << arg << "'" );
986         return FG_OPTIONS_ERROR;
987     }
988     
989     return FG_OPTIONS_OK;
990 }
991
992
993 // Scan the command line options for an fg_root definition and set
994 // just that.
995 string
996 fgScanForRoot (int argc, char **argv) 
997 {
998     int i = 1;
999
1000     SG_LOG(SG_GENERAL, SG_INFO, "Scanning for root: command line");
1001
1002     while ( i < argc ) {
1003         SG_LOG( SG_GENERAL, SG_DEBUG, "argv[" << i << "] = " << argv[i] );
1004
1005         string arg = argv[i];
1006         if ( arg.find( "--fg-root=" ) == 0 ) {
1007             return arg.substr( 10 );
1008         }
1009
1010         i++;
1011     }
1012
1013     return "";
1014 }
1015
1016
1017 // Scan the config file for an fg_root definition and set just that.
1018 string
1019 fgScanForRoot (const string& path)
1020 {
1021     sg_gzifstream in( path );
1022     if ( !in.is_open() )
1023       return "";
1024
1025     SG_LOG( SG_GENERAL, SG_INFO, "Scanning for root: " << path );
1026
1027     in >> skipcomment;
1028 #ifndef __MWERKS__
1029     while ( ! in.eof() ) {
1030 #else
1031     char c = '\0';
1032     while ( in.get(c) && c != '\0' ) {
1033         in.putback(c);
1034 #endif
1035         string line;
1036
1037 #if defined( macintosh )
1038         getline( in, line, '\r' );
1039 #else
1040         getline( in, line, '\n' );
1041 #endif
1042
1043         // catch extraneous (DOS) line ending character
1044         if ( line[line.length() - 1] < 32 ) {
1045             line = line.substr( 0, line.length()-1 );
1046         }
1047
1048         if ( line.find( "--fg-root=" ) == 0 ) {
1049             return line.substr( 10 );
1050         }
1051
1052         in >> skipcomment;
1053     }
1054
1055     return "";
1056 }
1057
1058
1059 // Parse the command line options
1060 void
1061 fgParseArgs (int argc, char **argv)
1062 {
1063     bool in_options = true;
1064
1065     SG_LOG(SG_GENERAL, SG_INFO, "Processing command line arguments");
1066
1067     for (int i = 1; i < argc; i++) {
1068         string arg = argv[i];
1069
1070         if (in_options && (arg.find('-') == 0)) {
1071           if (arg == "--") {
1072             in_options = false;
1073           } else {
1074             int result = parse_option(arg);
1075             if ( (result == FG_OPTIONS_HELP) ||
1076                  (result == FG_OPTIONS_ERROR) ) {
1077               fgUsage();
1078               exit(-1);
1079             }
1080           }
1081         } else {
1082           in_options = false;
1083           SG_LOG(SG_GENERAL, SG_INFO,
1084                  "Reading command-line property file " << arg);
1085           readProperties(arg, globals->get_props());
1086         }
1087     }
1088
1089     SG_LOG(SG_GENERAL, SG_INFO, "Finished command line arguments");
1090 }
1091
1092
1093 // Parse config file options
1094 void
1095 fgParseOptions (const string& path) {
1096     sg_gzifstream in( path );
1097     if ( !in.is_open() ) {
1098         return;
1099     }
1100
1101     SG_LOG( SG_GENERAL, SG_INFO, "Processing config file: " << path );
1102
1103     in >> skipcomment;
1104 #ifndef __MWERKS__
1105     while ( ! in.eof() ) {
1106 #else
1107     char c = '\0';
1108     while ( in.get(c) && c != '\0' ) {
1109         in.putback(c);
1110 #endif
1111         string line;
1112
1113 #if defined( macintosh )
1114         getline( in, line, '\r' );
1115 #else
1116         getline( in, line, '\n' );
1117 #endif
1118
1119         // catch extraneous (DOS) line ending character
1120         if ( line[line.length() - 1] < 32 ) {
1121             line = line.substr( 0, line.length()-1 );
1122         }
1123
1124         if ( parse_option( line ) == FG_OPTIONS_ERROR ) {
1125             SG_LOG( SG_GENERAL, SG_ALERT, 
1126                     "Config file parse error: " << path << " '" 
1127                     << line << "'" );
1128             fgUsage();
1129             exit(-1);
1130         }
1131         in >> skipcomment;
1132     }
1133 }
1134
1135
1136 // Print usage message
1137 void 
1138 fgUsage ()
1139 {
1140     SGPropertyNode options_root;
1141     SGPath opath( globals->get_fg_root() );
1142     opath.append( "options.xml" );
1143
1144     cout << "" << endl;
1145
1146     try {
1147         readProperties(opath.c_str(), &options_root);
1148     } catch (const sg_exception &ex) {
1149         cout << "Unable to read the help file." << endl;
1150         cout << "Make sure the file options.xml is located in the FlightGear base directory," << endl;
1151         cout << "and the location of the base directory is specified bij setting $FG_ROOT or" << endl;
1152         cout << "by adding --fg-root=path as a program argument." << endl;
1153         
1154         exit(-1);
1155     }
1156
1157     SGPropertyNode *options = options_root.getNode("options");
1158     if (!options) {
1159         SG_LOG( SG_GENERAL, SG_ALERT,
1160                 "Error reading options.xml: <options> directive not found." );
1161         exit(-1);
1162     }
1163
1164     SGPropertyNode *usage = options->getNode("usage");
1165     if (usage) {
1166         cout << "Usage: " << usage->getStringValue() << endl;
1167     }
1168
1169     vector<SGPropertyNode_ptr>section = options->getChildren("section");
1170     for (unsigned int j = 0; j < section.size(); j++) {
1171
1172         SGPropertyNode *name = section[j]->getNode("name");
1173         if (name) {
1174             cout << endl << name->getStringValue() << ":" << endl;
1175         }
1176
1177         vector<SGPropertyNode_ptr>option = section[j]->getChildren("option");
1178         for (unsigned int k = 0; k < option.size(); k++) {
1179
1180             SGPropertyNode *name = option[k]->getNode("name");
1181             SGPropertyNode *short_name = option[k]->getNode("short");
1182             SGPropertyNode *key = option[k]->getNode("key");
1183             SGPropertyNode *arg = option[k]->getNode("arg");
1184
1185             if (name) {
1186                 string tmp = name->getStringValue();
1187
1188                 if (key){
1189                     tmp.append(":");
1190                     tmp.append(key->getStringValue());
1191                 }
1192                 if (arg) {
1193                     tmp.append("=");
1194                     tmp.append(arg->getStringValue());
1195                 }
1196                 if (short_name) {
1197                     tmp.append(", -");
1198                     tmp.append(short_name->getStringValue());
1199                 }
1200
1201                 char cstr[96];
1202                 if (tmp.size() <= 25) {
1203                     snprintf(cstr, 96, "   --%-27s", tmp.c_str());
1204                 } else {
1205                     snprintf(cstr, 96, "\n   --%s\n%32c", tmp.c_str(), ' ');
1206                 }
1207                 string msg = cstr;
1208
1209                 SGPropertyNode *desc = option[k]->getNode("description");
1210                 if (desc) {
1211                     msg += desc->getStringValue();
1212
1213                     for ( unsigned int l = 1;
1214                           (desc = option[k]->getNode("description", l, false));
1215                           l++ )
1216                     {
1217                         snprintf(cstr, 96, "\n%32c%s", ' ',
1218                                  desc->getStringValue());
1219                         msg += cstr;
1220                     }
1221                 }
1222                 cout << msg << endl;
1223             }
1224         }
1225     }
1226 }