]> git.mxchange.org Git - flightgear.git/blob - src/Main/options.cxx
User-visible
[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 #if defined(FX) && defined(XMESA)
29 bool global_fullscreen = true;
30 #endif
31
32 #include <simgear/compiler.h>
33
34 #include <math.h>            // rint()
35 #include <stdio.h>
36 #include <stdlib.h>          // atof(), atoi()
37 #include <string.h>
38
39 #include STL_STRING
40
41 #include <simgear/constants.h>
42 #include <simgear/debug/logstream.hxx>
43 #include <simgear/misc/fgstream.hxx>
44
45 #include <Include/general.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 #include <Time/fg_time.hxx>
53
54 #include "views.hxx"
55 #include "options.hxx"
56
57 FG_USING_STD(string);
58 FG_USING_NAMESPACE(std);
59
60 // from GLUTmain.cxx
61 extern void fgReshape( int width, int height );
62
63 inline double
64 atof( const string& str )
65 {
66
67 #ifdef __MWERKS__ 
68     // -dw- if ::atof is called, then we get an infinite loop
69     return std::atof( str.c_str() );
70 #else
71     return ::atof( str.c_str() );
72 #endif
73 }
74
75 inline int
76 atoi( const string& str )
77 {
78 #ifdef __MWERKS__ 
79     // -dw- if ::atoi is called, then we get an infinite loop
80     return std::atoi( str.c_str() );
81 #else
82     return ::atoi( str.c_str() );
83 #endif
84 }
85
86
87 // Defined the shared options class here
88 fgOPTIONS current_options;
89
90
91 // Constructor
92 fgOPTIONS::fgOPTIONS() :
93     // starting longitude in degrees (west = -)
94     // starting latitude in degrees (south = -)
95
96     // Default initial position is Globe, AZ (P13)
97     lon(-110.6642444),
98     lat(  33.3528917),
99
100     // North of the city of Globe
101     // lon(-110.7),
102     // lat(  33.4),
103
104     // North of the city of Globe
105     // lon(-110.742578),
106     // lat(  33.507122),
107
108     // Near where I used to live in Globe, AZ
109     // lon(-110.766000),
110     // lat(  33.377778),
111
112     // 10125 Jewell St. NE
113     // lon(-93.15),
114     // lat( 45.15),
115
116     // Near KHSP (Hot Springs, VA)
117     // lon(-79.8338964 + 0.01),
118     // lat( 37.9514564 + 0.008),
119
120     // (SEZ) SEDONA airport
121     // lon(-111.7884614 + 0.01),
122     // lat(  34.8486289 - 0.015),
123
124     // Jim Brennon's Kingmont Observatory
125     // lon(-121.1131667),
126     // lat(  38.8293917),
127
128     // Huaras, Peru (S09d 31.871'  W077d 31.498')
129     // lon(-77.5249667),
130     // lat( -9.5311833),
131  
132     // Eclipse Watching w73.5 n10 (approx) 18:00 UT
133     // lon(-73.5),
134     // lat( 10.0),
135
136     // Timms Hill (WI)
137     // lon(-90.1953055556),
138     // lat( 45.4511388889),
139
140     // starting altitude in meters (this will be reset to ground level
141     // if it is lower than the terrain
142     altitude(-9999.0),
143
144     // Initial Orientation
145     heading(270.0),      // heading (yaw) angle in degress (Psi)
146     roll(0.0),           // roll angle in degrees (Phi)
147     pitch(0.424),        // pitch angle in degrees (Theta)
148
149     // Initialize current options velocities to 0.0
150     uBody(0.0), vBody(0.0), wBody(0.0),
151
152     // Miscellaneous
153     game_mode(0),
154     splash_screen(1),
155     intro_music(1),
156     mouse_pointer(0),
157     pause(0),
158     control_mode(FG_JOYSTICK),
159     auto_coordination(FG_AUTO_COORD_NOT_SPECIFIED),
160
161     // Features
162     hud_status(1),
163     panel_status(0),
164     sound(1),
165
166     // Flight Model options
167     flight_model( FGInterface::FG_LARCSIM ),
168     aircraft( "c172" ),
169     model_hz( NEW_DEFAULT_MODEL_HZ ),
170     speed_up( 1 ),
171
172     // Rendering options
173     fog(FG_FOG_NICEST),  // nicest
174     clouds(true),
175     clouds_asl(5000*FEET_TO_METER),
176     fov(55.0),
177     fullscreen(0),
178     shading(1),
179     skyblend(1),
180     textures(1),
181     wireframe(0),
182     xsize(640),
183     ysize(480),
184     view_mode(FG_VIEW_PILOT),
185
186     // Scenery options
187     tile_diameter(5),
188
189     // HUD options
190     units(FG_UNITS_FEET),
191     tris_or_culled(0),
192         
193     // Time options
194     time_offset(0),
195
196     network_olk(false)
197 {
198     // set initial values/defaults
199     time_offset_type=FG_TIME_SYS_OFFSET;
200     char* envp = ::getenv( "FG_ROOT" );
201
202     if ( envp != NULL ) {
203         // fg_root could be anywhere, so default to environmental
204         // variable $FG_ROOT if it is set.
205         fg_root = envp;
206     } else {
207         // Otherwise, default to a random compiled in location if
208         // $FG_ROOT is not set.  This can still be overridden from the
209         // command line or a config file.
210
211 #if defined( WIN32 )
212         fg_root = "\\FlightGear";
213 #elif defined( MACOS )
214         fg_root = "";
215 #else
216         fg_root = PKGLIBDIR;
217 #endif
218     }
219
220     airport_id = "";            // default airport id
221     net_id = "Johnney";         // default pilot's name
222
223     // initialize port config string list
224     channel_options_list.clear();
225 }
226
227 void 
228 fgOPTIONS::toggle_panel() {
229     
230     FGTime *t = FGTime::cur_time_params;
231     
232     int toggle_pause = t->getPause();
233     
234     if( !toggle_pause )
235         t->togglePauseMode();
236     
237     if( panel_status ) {
238         panel_status = false;
239         if ( current_panel != NULL )
240           current_panel->setVisibility(false);
241     } else {
242         panel_status = true;
243         if ( current_panel != NULL )
244           current_panel->setVisibility(true);
245     }
246     if ( panel_status ) {
247         fov *= 0.4232;
248     } else {
249         fov *= (1.0 / 0.4232);
250     }
251     fgReshape( xsize, ysize);
252     
253     if( !toggle_pause )
254         t->togglePauseMode();
255 }
256
257 double
258 fgOPTIONS::parse_time(const string& time_in) {
259     char *time_str, num[256];
260     double hours, minutes, seconds;
261     double result = 0.0;
262     int sign = 1;
263     int i;
264
265     time_str = (char *)time_in.c_str();
266
267     // printf("parse_time(): %s\n", time_str);
268
269     // check for sign
270     if ( strlen(time_str) ) {
271         if ( time_str[0] == '+' ) {
272             sign = 1;
273             time_str++;
274         } else if ( time_str[0] == '-' ) {
275             sign = -1;
276             time_str++;
277         }
278     }
279     // printf("sign = %d\n", sign);
280
281     // get hours
282     if ( strlen(time_str) ) {
283         i = 0;
284         while ( (time_str[0] != ':') && (time_str[0] != '\0') ) {
285             num[i] = time_str[0];
286             time_str++;
287             i++;
288         }
289         if ( time_str[0] == ':' ) {
290             time_str++;
291         }
292         num[i] = '\0';
293         hours = atof(num);
294         // printf("hours = %.2lf\n", hours);
295
296         result += hours;
297     }
298
299     // get minutes
300     if ( strlen(time_str) ) {
301         i = 0;
302         while ( (time_str[0] != ':') && (time_str[0] != '\0') ) {
303             num[i] = time_str[0];
304             time_str++;
305             i++;
306         }
307         if ( time_str[0] == ':' ) {
308             time_str++;
309         }
310         num[i] = '\0';
311         minutes = atof(num);
312         // printf("minutes = %.2lf\n", minutes);
313
314         result += minutes / 60.0;
315     }
316
317     // get seconds
318     if ( strlen(time_str) ) {
319         i = 0;
320         while ( (time_str[0] != ':') && (time_str[0] != '\0') ) {
321             num[i] = time_str[0];
322             time_str++;
323             i++;
324         }
325         num[i] = '\0';
326         seconds = atof(num);
327         // printf("seconds = %.2lf\n", seconds);
328
329         result += seconds / 3600.0;
330     }
331
332     return(sign * result);
333 }
334
335
336 long int fgOPTIONS::parse_date( const string& date)
337 {
338     struct tm gmt;
339     char * date_str, num[256];
340     int i;
341     // initialize to zero
342     gmt.tm_sec = 0;
343     gmt.tm_min = 0;
344     gmt.tm_hour = 0;
345     gmt.tm_mday = 0;
346     gmt.tm_mon = 0;
347     gmt.tm_year = 0;
348     gmt.tm_isdst = 0; // ignore daylight savings time for the moment
349     date_str = (char *)date.c_str();
350     // get year
351     if ( strlen(date_str) ) {
352         i = 0;
353         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
354             num[i] = date_str[0];
355             date_str++;
356             i++;
357         }
358         if ( date_str[0] == ':' ) {
359             date_str++;
360         }
361         num[i] = '\0';
362         gmt.tm_year = atoi(num) - 1900;
363     }
364     // get month
365     if ( strlen(date_str) ) {
366         i = 0;
367         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
368             num[i] = date_str[0];
369             date_str++;
370             i++;
371         }
372         if ( date_str[0] == ':' ) {
373             date_str++;
374         }
375         num[i] = '\0';
376         gmt.tm_mon = atoi(num) -1;
377     }
378     // get day
379     if ( strlen(date_str) ) {
380         i = 0;
381         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
382             num[i] = date_str[0];
383             date_str++;
384             i++;
385         }
386         if ( date_str[0] == ':' ) {
387             date_str++;
388         }
389         num[i] = '\0';
390         gmt.tm_mday = atoi(num);
391     }
392     // get hour
393     if ( strlen(date_str) ) {
394         i = 0;
395         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
396             num[i] = date_str[0];
397             date_str++;
398             i++;
399         }
400         if ( date_str[0] == ':' ) {
401             date_str++;
402         }
403         num[i] = '\0';
404         gmt.tm_hour = atoi(num);
405     }
406     // get minute
407     if ( strlen(date_str) ) {
408         i = 0;
409         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
410             num[i] = date_str[0];
411             date_str++;
412             i++;
413         }
414         if ( date_str[0] == ':' ) {
415             date_str++;
416         }
417         num[i] = '\0';
418         gmt.tm_min = atoi(num);
419     }
420     // get second
421     if ( strlen(date_str) ) {
422         i = 0;
423         while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
424             num[i] = date_str[0];
425             date_str++;
426             i++;
427         }
428         if ( date_str[0] == ':' ) {
429             date_str++;
430         }
431         num[i] = '\0';
432         gmt.tm_sec = atoi(num);
433     }
434     time_t theTime = FGTime::cur_time_params->get_gmt(gmt.tm_year,
435                                                       gmt.tm_mon,
436                                                       gmt.tm_mday,
437                                                       gmt.tm_hour,
438                                                       gmt.tm_min,
439                                                       gmt.tm_sec);
440     //printf ("Date is %s\n", ctime(&theTime));
441     //printf ("in seconds that is %d\n", theTime);
442     //exit(1);
443     return (theTime);
444 }
445
446
447 // parse degree in the form of [+/-]hhh:mm:ss
448 void fgOPTIONS::parse_control( const string& mode ) {
449     if ( mode == "joystick" ) {
450         control_mode = FG_JOYSTICK;
451     } else if ( mode == "mouse" ) {
452         control_mode = FG_MOUSE;
453     } else {
454         control_mode = FG_KEYBOARD;
455     }
456 }
457
458
459 /// parse degree in the form of [+/-]hhh:mm:ss
460 double
461 fgOPTIONS::parse_degree( const string& degree_str) {
462     double result = parse_time( degree_str );
463
464     // printf("Degree = %.4f\n", result);
465
466     return(result);
467 }
468
469
470 // parse time offset command line option
471 int
472 fgOPTIONS::parse_time_offset( const string& time_str) {
473     int result;
474
475     // printf("time offset = %s\n", time_str);
476
477 #ifdef HAVE_RINT
478     result = (int)rint(parse_time(time_str) * 3600.0);
479 #else
480     result = (int)(parse_time(time_str) * 3600.0);
481 #endif
482
483     // printf("parse_time_offset(): %d\n", result);
484
485     return( result );
486 }
487
488
489 // Parse --tile-diameter=n type option 
490
491 int
492 fgOPTIONS::parse_tile_radius( const string& arg ) {
493     int radius = atoi( arg );
494
495     if ( radius < FG_RADIUS_MIN ) { radius = FG_RADIUS_MIN; }
496     if ( radius > FG_RADIUS_MAX ) { radius = FG_RADIUS_MAX; }
497
498     // printf("parse_tile_radius(): radius = %d\n", radius);
499
500     return(radius);
501 }
502
503
504 // Parse --fdm=abcdefg type option 
505 int
506 fgOPTIONS::parse_fdm( const string& fm ) {
507     // cout << "fdm = " << fm << endl;
508
509     if ( fm == "balloon" ) {
510         return FGInterface::FG_BALLOONSIM;
511     } else if ( fm == "external" ) {
512         return FGInterface::FG_EXTERNAL;
513     } else if ( fm == "jsb" ) {
514         return FGInterface::FG_JSBSIM;
515     } else if ( (fm == "larcsim") || (fm == "LaRCsim") ) {
516         return FGInterface::FG_LARCSIM;
517     } else if ( fm == "magic" ) {
518         return FGInterface::FG_MAGICCARPET;
519     } else {
520         FG_LOG( FG_GENERAL, FG_ALERT, "Unknown fdm = " << fm );
521         exit(-1);
522     }
523
524     // we'll never get here, but it makes the compiler happy.
525     return -1;
526 }
527
528
529 // Parse --fov=x.xx type option 
530 double
531 fgOPTIONS::parse_fov( const string& arg ) {
532     double fov = atof(arg);
533
534     if ( fov < FG_FOV_MIN ) { fov = FG_FOV_MIN; }
535     if ( fov > FG_FOV_MAX ) { fov = FG_FOV_MAX; }
536
537     // printf("parse_fov(): result = %.4f\n", fov);
538
539     return(fov);
540 }
541
542
543 // Parse I/O channel option
544 //
545 // Format is "--protocol=medium,direction,hz,medium_options,..."
546 //
547 //   protocol = { native, nmea, garmin, fgfs, rul, pve, etc. }
548 //   medium = { serial, socket, file, etc. }
549 //   direction = { in, out, bi }
550 //   hz = number of times to process channel per second (floating
551 //        point values are ok.
552 //
553 // Serial example "--nmea=serial,dir,hz,device,baud" where
554 // 
555 //  device = OS device name of serial line to be open()'ed
556 //  baud = {300, 1200, 2400, ..., 230400}
557 //
558 // Socket exacmple "--native=socket,dir,hz,machine,port" where
559 // 
560 //  machine = machine name or ip address if client (leave empty if server)
561 //  port = port, leave empty to let system choose
562 //
563 // File example "--garmin=file,dir,hz,filename" where
564 // 
565 //  filename = file system file name
566
567 bool 
568 fgOPTIONS::parse_channel( const string& type, const string& channel_str ) {
569     // cout << "Channel string = " << channel_str << endl;
570
571     channel_options_list.push_back( type + "," + channel_str );
572
573     return true;
574 }
575
576
577 // Parse a single option
578 int fgOPTIONS::parse_option( const string& arg ) {
579     // General Options
580     if ( (arg == "--help") || (arg == "-h") ) {
581         // help/usage request
582         return(FG_OPTIONS_HELP);
583     } else if ( arg == "--disable-game-mode") {
584         game_mode = false;
585     } else if ( arg == "--enable-game-mode" ) {
586         game_mode = true;
587     } else if ( arg == "--disable-splash-screen" ) {
588         splash_screen = false;
589     } else if ( arg == "--enable-splash-screen" ) {
590         splash_screen = true;
591     } else if ( arg == "--disable-intro-music" ) {
592         intro_music = false;
593     } else if ( arg == "--enable-intro-music" ) {
594         intro_music = true;
595     } else if ( arg == "--disable-mouse-pointer" ) {
596         mouse_pointer = 1;
597     } else if ( arg == "--enable-mouse-pointer" ) {
598         mouse_pointer = 2;
599     } else if ( arg == "--disable-pause" ) {
600         pause = false;  
601     } else if ( arg == "--enable-pause" ) {
602         pause = true;   
603     } else if ( arg.find( "--control=") != string::npos ) {
604         parse_control( arg.substr(10) );
605     } else if ( arg == "--disable-auto-coordination" ) {
606         auto_coordination = FG_AUTO_COORD_DISABLED;     
607     } else if ( arg == "--enable-auto-coordination" ) {
608         auto_coordination = FG_AUTO_COORD_ENABLED;      
609     } else if ( arg == "--disable-hud" ) {
610         hud_status = false;     
611     } else if ( arg == "--enable-hud" ) {
612         hud_status = true;      
613     } else if ( arg == "--disable-panel" ) {
614         panel_status = false;
615         if ( current_panel != NULL )
616           current_panel->setVisibility(false);
617     } else if ( arg == "--enable-panel" ) {
618         panel_status = true;
619         if ( current_panel != NULL )
620           current_panel->setVisibility(true);
621         fov *= 0.4232;
622     } else if ( arg == "--disable-sound" ) {
623         sound = false;
624     } else if ( arg == "--enable-sound" ) {
625         sound = true;
626     } else if ( arg.find( "--airport-id=") != string::npos ) {
627         airport_id = arg.substr( 13 );
628     } else if ( arg.find( "--lon=" ) != string::npos ) {
629         lon = parse_degree( arg.substr(6) );
630     } else if ( arg.find( "--lat=" ) != string::npos ) {
631         lat = parse_degree( arg.substr(6) );
632     } else if ( arg.find( "--altitude=" ) != string::npos ) {
633         if ( units == FG_UNITS_FEET ) {
634             altitude = atof( arg.substr(11) ) * FEET_TO_METER;
635         } else {
636             altitude = atof( arg.substr(11) );
637         }
638     } else if ( arg.find( "--uBody=" ) != string::npos ) {
639         if ( units == FG_UNITS_FEET ) {
640             uBody = atof( arg.substr(8) );
641         } else {
642             uBody = atof( arg.substr(8) ) * FEET_TO_METER;
643         }
644     } else if ( arg.find( "--vBody=" ) != string::npos ) {
645         if ( units == FG_UNITS_FEET ) {
646             vBody = atof( arg.substr(8) );
647         } else {
648             vBody = atof( arg.substr(8) ) * FEET_TO_METER;
649         }
650     } else if ( arg.find( "--wBody=" ) != string::npos ) {
651         if ( units == FG_UNITS_FEET ) {
652             wBody = atof( arg.substr(8) );
653         } else {
654             wBody = atof( arg.substr(8) ) * FEET_TO_METER;
655         }
656     } else if ( arg.find( "--heading=" ) != string::npos ) {
657         heading = atof( arg.substr(10) );
658     } else if ( arg.find( "--roll=" ) != string::npos ) {
659         roll = atof( arg.substr(7) );
660     } else if ( arg.find( "--pitch=" ) != string::npos ) {
661         pitch = atof( arg.substr(8) );
662     } else if ( arg.find( "--fg-root=" ) != string::npos ) {
663         fg_root = arg.substr( 10 );
664     } else if ( arg.find( "--fdm=" ) != string::npos ) {
665         flight_model = parse_fdm( arg.substr(6) );
666     } else if ( arg.find( "--aircraft=" ) != string::npos ) {
667         aircraft = arg.substr(11);
668     } else if ( arg.find( "--aircraft-dir=" ) != string::npos ) {
669         aircraft_dir =  arg.substr(15); //  (UIUC)
670     } else if ( arg.find( "--model-hz=" ) != string::npos ) {
671         model_hz = atoi( arg.substr(11) );
672     } else if ( arg.find( "--speed=" ) != string::npos ) {
673         speed_up = atoi( arg.substr(8) );
674     } else if ( arg == "--fog-disable" ) {
675         fog = FG_FOG_DISABLED;  
676     } else if ( arg == "--fog-fastest" ) {
677         fog = FG_FOG_FASTEST;   
678     } else if ( arg == "--fog-nicest" ) {
679         fog = FG_FOG_NICEST;    
680     } else if ( arg == "--disable-clouds" ) {
681         clouds = false; 
682     } else if ( arg == "--enable-clouds" ) {
683         clouds = true;  
684     } else if ( arg.find( "--clouds-asl=" ) != string::npos ) {
685         if ( units == FG_UNITS_FEET ) {
686             clouds_asl = atof( arg.substr(13) ) * FEET_TO_METER;
687         } else {
688             clouds_asl = atof( arg.substr(13) );
689         }
690     } else if ( arg.find( "--fov=" ) != string::npos ) {
691         fov = parse_fov( arg.substr(6) );
692     } else if ( arg == "--disable-fullscreen" ) {
693         fullscreen = false;     
694     } else if ( arg== "--enable-fullscreen") {
695         fullscreen = true;      
696     } else if ( arg == "--shading-flat") {
697         shading = 0;    
698     } else if ( arg == "--shading-smooth") {
699         shading = 1;    
700     } else if ( arg == "--disable-skyblend") {
701         skyblend = false;       
702     } else if ( arg== "--enable-skyblend" ) {
703         skyblend = true;        
704     } else if ( arg == "--disable-textures" ) {
705         textures = false;       
706     } else if ( arg == "--enable-textures" ) {
707         textures = true;
708     } else if ( arg == "--disable-wireframe" ) {
709         wireframe = false;      
710     } else if ( arg == "--enable-wireframe" ) {
711         wireframe = true;
712     } else if ( arg.find( "--geometry=" ) != string::npos ) {
713         bool geometry_ok = true;
714         string geometry = arg.substr( 11 );
715         string::size_type i = geometry.find('x');
716
717         if (i != string::npos) {
718             xsize = atoi(geometry.substr(0, i));
719             ysize = atoi(geometry.substr(i+1));
720             // cout << "Geometry is " << xsize << 'x' << ysize << '\n';
721         } else {
722             geometry_ok = false;
723         }
724
725         if ( xsize <= 0 || ysize <= 0 ) {
726             xsize = 640;
727             ysize = 480;
728             geometry_ok = false;
729         }
730
731         if ( !geometry_ok ) {
732             FG_LOG( FG_GENERAL, FG_ALERT, "Unknown geometry: " << geometry );
733             FG_LOG( FG_GENERAL, FG_ALERT,
734                     "Setting geometry to " << xsize << 'x' << ysize << '\n');
735         }
736     } else if ( arg == "--units-feet" ) {
737         units = FG_UNITS_FEET;  
738     } else if ( arg == "--units-meters" ) {
739         units = FG_UNITS_METERS;        
740     } else if ( arg.find( "--tile-radius=" ) != string::npos ) {
741         tile_radius = parse_tile_radius( arg.substr(14) );
742         tile_diameter = tile_radius * 2 + 1;
743     } else if ( arg.find( "--time-offset" ) != string::npos ) {
744         time_offset = parse_time_offset( (arg.substr(14)) );
745         //time_offset_type = FG_TIME_SYS_OFFSET;
746     } else if ( arg.find( "--time-match-real") != string::npos ) {
747       //time_offset = parse_time_offset(arg.substr(18));
748         time_offset_type = FG_TIME_SYS_OFFSET;
749     } else if ( arg.find( "--time-match-local") != string::npos ) {
750       //time_offset = parse_time_offset(arg.substr(18));
751         time_offset_type = FG_TIME_LAT_OFFSET;
752     } else if ( arg.find( "--start-date-sys=") != string::npos ) {
753         time_offset = parse_date( (arg.substr(17)) );
754         time_offset_type = FG_TIME_SYS_ABSOLUTE;
755     } else if ( arg.find( "--start-date-lat=") != string::npos ) {
756         time_offset = parse_date( (arg.substr(17)) );
757         time_offset_type = FG_TIME_LAT_ABSOLUTE;
758     } else if ( arg.find( "--start-date-gmt=") != string::npos ) {
759         time_offset = parse_date( (arg.substr(17)) );
760         time_offset_type = FG_TIME_GMT_ABSOLUTE;
761
762     } else if ( arg == "--hud-tris" ) {
763         tris_or_culled = 0;     
764     } else if ( arg == "--hud-culled" ) {
765         tris_or_culled = 1;
766     } else if ( arg.find( "--native=" ) != string::npos ) {
767         parse_channel( "native", arg.substr(9) );
768     } else if ( arg.find( "--garmin=" ) != string::npos ) {
769         parse_channel( "garmin", arg.substr(9) );
770     } else if ( arg.find( "--nmea=" ) != string::npos ) {
771         parse_channel( "nmea", arg.substr(7) );
772     } else if ( arg.find( "--pve=" ) != string::npos ) {
773         parse_channel( "pve", arg.substr(6) );
774     } else if ( arg.find( "--rul=" ) != string::npos ) {
775         parse_channel( "rul", arg.substr(6) );
776     } else if ( arg.find( "--joyclient=" ) != string::npos ) {
777         parse_channel( "joyclient", arg.substr(12) );
778 #ifdef FG_NETWORK_OLK
779     } else if ( arg == "--disable-network-olk" ) {
780         network_olk = false;    
781     } else if ( arg== "--enable-network-olk") {
782         network_olk = true;     
783     } else if ( arg == "--net-hud" ) {
784         net_hud_display = 1;    
785     } else if ( arg.find( "--net-id=") != string::npos ) {
786         net_id = arg.substr( 9 );
787 #endif
788     } else {
789         FG_LOG( FG_GENERAL, FG_ALERT, "Unknown option '" << arg << "'" );
790         return FG_OPTIONS_ERROR;
791     }
792     
793     return FG_OPTIONS_OK;
794 }
795
796
797 // Parse the command line options
798 int fgOPTIONS::parse_command_line( int argc, char **argv ) {
799     int i = 1;
800     int result;
801
802     FG_LOG(FG_GENERAL, FG_INFO, "Processing command line arguments");
803
804     while ( i < argc ) {
805         FG_LOG( FG_GENERAL, FG_DEBUG, "argv[" << i << "] = " << argv[i] );
806
807         result = parse_option(argv[i]);
808         if ( (result == FG_OPTIONS_HELP) || (result == FG_OPTIONS_ERROR) ) {
809             return(result);
810         }
811
812         i++;
813     }
814     
815     return(FG_OPTIONS_OK);
816 }
817
818
819 // Parse config file options
820 int fgOPTIONS::parse_config_file( const string& path ) {
821     fg_gzifstream in( path );
822     if ( !in.is_open() )
823         return(FG_OPTIONS_ERROR);
824
825     FG_LOG( FG_GENERAL, FG_INFO, "Processing config file: " << path );
826
827     in >> skipcomment;
828 #ifndef __MWERKS__
829     while ( ! in.eof() ) {
830 #else
831     char c = '\0';
832     while ( in.get(c) && c != '\0' ) {
833         in.putback(c);
834 #endif
835         string line;
836
837 #ifdef GETLINE_NEEDS_TERMINATOR
838         getline( in, line, '\n' );
839 #elif defined (MACOS)
840         getline( in, line, '\r' );
841 #else
842         getline( in, line );
843 #endif
844
845         if ( parse_option( line ) == FG_OPTIONS_ERROR ) {
846             FG_LOG( FG_GENERAL, FG_ALERT, 
847                     "Config file parse error: " << path << " '" 
848                     << line << "'" );
849             exit(-1);
850         }
851         in >> skipcomment;
852     }
853
854     return FG_OPTIONS_OK;
855 }
856
857
858 // Print usage message
859 void fgOPTIONS::usage ( void ) {
860     cout << "Usage: fg [ options ... ]" << endl;
861     cout << endl;
862
863     cout << "General Options:" << endl;
864     cout << "\t--help -h:  print usage" << endl;
865     cout << "\t--fg-root=path:  specify the root path for all the data files"
866          << endl;
867     cout << "\t--disable-game-mode:  disable full-screen game mode" << endl;
868     cout << "\t--enable-game-mode:  enable full-screen game mode" << endl;
869     cout << "\t--disable-splash-screen:  disable splash screen" << endl;
870     cout << "\t--enable-splash-screen:  enable splash screen" << endl;
871     cout << "\t--disable-intro-music:  disable introduction music" << endl;
872     cout << "\t--enable-intro-music:  enable introduction music" << endl;
873     cout << "\t--disable-mouse-pointer:  disable extra mouse pointer" << endl;
874     cout << "\t--enable-mouse-pointer:  enable extra mouse pointer (i.e. for"
875          << endl;
876     cout << "\t\tfull screen voodoo/voodoo-II based cards.)" << endl;
877     cout << "\t--disable-pause:  start out in an active state" << endl;
878     cout << "\t--enable-pause:  start out in a paused state" << endl;
879     cout << "\t--control=mode:  primary control mode " 
880          << "(joystick, keyboard, mouse)" << endl;
881     cout << endl;
882
883     cout << "Features:" << endl;
884     cout << "\t--disable-hud:  disable heads up display" << endl;
885     cout << "\t--enable-hud:  enable heads up display" << endl;
886     cout << "\t--disable-panel:  disable instrument panel" << endl;
887     cout << "\t--enable-panel:  enable instrumetn panel" << endl;
888     cout << "\t--disable-sound:  disable sound effects" << endl;
889     cout << "\t--enable-sound:  enable sound effects" << endl;
890     cout << endl;
891  
892     cout << "Flight Model:" << endl;
893     cout << "\t--fdm=abcd:  selects the core flight model code." << endl;
894     cout << "\t\tcan be one of jsb, larcsim, magic, or external" << endl;
895     cout << "\t--aircraft=abcd:  aircraft model to load" << endl;
896     cout << "\t--model-hz=n:  run the FDM this rate (iterations per second)" 
897          << endl;
898     cout << "\t--speed=n:  run the FDM this much faster than real time" << endl;
899     cout << endl;
900     //(UIUC)
901     cout <<"Aircraft model directory" << endl;
902     cout <<"\t--aircraft-dir=<path> path is relative to the path of the executable" << endl;
903     cout << endl;
904
905     cout << "Initial Position and Orientation:" << endl;
906     cout << "\t--airport-id=ABCD:  specify starting postion by airport id" 
907          << endl;
908     cout << "\t--lon=degrees:  starting longitude in degrees (west = -)" 
909          << endl;
910     cout << "\t--lat=degrees:  starting latitude in degrees (south = -)"
911          << endl;
912     cout << "\t--altitude=feet:  starting altitude in feet" << endl;
913     cout << "\t\t(unless --units-meters specified" << endl;
914     cout << "\t--heading=degrees:  heading (yaw) angle in degress (Psi)"
915          << endl;
916     cout << "\t--roll=degrees:  roll angle in degrees (Phi)" << endl;
917     cout << "\t--pitch=degrees:  pitch angle in degrees (Theta)" << endl;
918     cout << "\t--uBody=feet per second:  velocity along the body X axis"
919          << endl;
920     cout << "\t--vBody=feet per second:  velocity along the body Y axis"
921          << endl;
922     cout << "\t--wBody=feet per second:  velocity along the body Z axis"
923          << endl;
924     cout << "\t\t(unless --units-meters specified" << endl;
925     cout << endl;
926
927     cout << "Rendering Options:" << endl;
928     cout << "\t--fog-disable:  disable fog/haze" << endl;
929     cout << "\t--fog-fastest:  enable fastest fog/haze" << endl;
930     cout << "\t--fog-nicest:  enable nicest fog/haze" << endl;
931     cout << "\t--enable-clouds:  enable demo cloud layer" << endl;
932     cout << "\t--disable-clouds:  disable demo cloud layer" << endl;
933     cout << "\t--clouds-asl=xxx:  specify altitude of cloud layer above sea level" << endl;
934     cout << "\t--fov=xx.x:  specify initial field of view angle in degrees"
935          << endl;
936     cout << "\t--disable-fullscreen:  disable fullscreen mode" << endl;
937     cout << "\t--enable-fullscreen:  enable fullscreen mode" << endl;
938     cout << "\t--shading-flat:  enable flat shading" << endl;
939     cout << "\t--shading-smooth:  enable smooth shading" << endl;
940     cout << "\t--disable-skyblend:  disable sky blending" << endl;
941     cout << "\t--enable-skyblend:  enable sky blending" << endl;
942     cout << "\t--disable-textures:  disable textures" << endl;
943     cout << "\t--enable-textures:  enable textures" << endl;
944     cout << "\t--disable-wireframe:  disable wireframe drawing mode" << endl;
945     cout << "\t--enable-wireframe:  enable wireframe drawing mode" << endl;
946     cout << "\t--geometry=WWWxHHH:  window geometry: 640x480, 800x600, etc."
947          << endl;
948     cout << endl;
949
950     cout << "Scenery Options:" << endl;
951     cout << "\t--tile-radius=n:  specify tile radius, must be 1 - 4" << endl;
952     cout << endl;
953
954     cout << "Hud Options:" << endl;
955     cout << "\t--units-feet:  Hud displays units in feet" << endl;
956     cout << "\t--units-meters:  Hud displays units in meters" << endl;
957     cout << "\t--hud-tris:  Hud displays number of triangles rendered" << endl;
958     cout << "\t--hud-culled:  Hud displays percentage of triangles culled"
959          << endl;
960     cout << endl;
961         
962     cout << "Time Options:" << endl;
963     cout << "\t--time-offset=[+-]hh:mm:ss: add this time offset" << endl;
964     cout << "\t--time-match-real: Synchronize real-world and FlightGear" << endl
965          << "\t\ttime. Can be used in combination with --time-offset." << endl;
966     cout << "\t--time-match-local:Synchronize local real-world and " << endl
967          << "\t\tFlightGear time" << endl;   
968     cout << "\t--start-date-sys=yyyy:mm:dd:hh:mm:ss: specify a starting" << endl
969          << "\t\tdate/time. Uses your system time " << endl;
970     cout << "\t--start-date-gmt=yyyy:mm:dd:hh:mm:ss: specify a starting" << endl
971          << "\t\tdate/time. Uses Greenwich Mean Time" << endl;
972     cout << "\t--start-date-lat=yyyy:mm:dd:hh:mm:ss: specify a starting" << endl
973          << "\t\tdate/time. Uses Local Aircraft Time" << endl;
974 #ifdef FG_NETWORK_OLK
975     cout << "" << endl;
976
977     cout << "Network Options:" << endl;
978     cout << "\t--net-hud:  Hud displays network info" << endl;
979     cout << "\t--net-id=name:  specify your own callsign" << endl;
980 #endif
981 }
982
983
984 // Destructor
985 fgOPTIONS::~fgOPTIONS( void ) {
986 }