]> git.mxchange.org Git - flightgear.git/blob - src/Main/options.cxx
11951ed088f5ec29153ece6df74af1a90af15734
[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     aircraft_dir=""; // Initialize the Aircraft directory to "" (UIUC)
199
200     // set initial values/defaults
201     time_offset_type=FG_TIME_SYS_OFFSET;
202     char* envp = ::getenv( "FG_ROOT" );
203
204     if ( envp != NULL ) {
205         // fg_root could be anywhere, so default to environmental
206         // variable $FG_ROOT if it is set.
207         fg_root = envp;
208     } else {
209         // Otherwise, default to a random compiled in location if
210         // $FG_ROOT is not set.  This can still be overridden from the
211         // command line or a config file.
212
213 #if defined( WIN32 )
214         fg_root = "\\FlightGear";
215 #elif defined( MACOS )
216         fg_root = "";
217 #else
218         fg_root = PKGLIBDIR;
219 #endif
220     }
221
222     airport_id = "";            // default airport id
223     net_id = "Johnney";         // default pilot's name
224
225     // initialize port config string list
226     channel_options_list.clear();
227 }
228
229 void 
230 fgOPTIONS::toggle_panel() {
231     
232     FGTime *t = FGTime::cur_time_params;
233     
234     int toggle_pause = t->getPause();
235     
236     if( !toggle_pause )
237         t->togglePauseMode();
238     
239     if( panel_status ) {
240         panel_status = false;
241     } else {
242         panel_status = true;
243     }
244     if ( panel_status ) {
245         if( FGPanel::OurPanel == 0)
246             new FGPanel;
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     } else if ( arg == "--enable-panel" ) {
616         panel_status = true;
617         fov *= 0.4232;
618     } else if ( arg == "--disable-sound" ) {
619         sound = false;
620     } else if ( arg == "--enable-sound" ) {
621         sound = true;
622     } else if ( arg.find( "--airport-id=") != string::npos ) {
623         airport_id = arg.substr( 13 );
624     } else if ( arg.find( "--lon=" ) != string::npos ) {
625         lon = parse_degree( arg.substr(6) );
626     } else if ( arg.find( "--lat=" ) != string::npos ) {
627         lat = parse_degree( arg.substr(6) );
628     } else if ( arg.find( "--altitude=" ) != string::npos ) {
629         if ( units == FG_UNITS_FEET ) {
630             altitude = atof( arg.substr(11) ) * FEET_TO_METER;
631         } else {
632             altitude = atof( arg.substr(11) );
633         }
634     } else if ( arg.find( "--uBody=" ) != string::npos ) {
635         if ( units == FG_UNITS_FEET ) {
636             uBody = atof( arg.substr(8) );
637         } else {
638             uBody = atof( arg.substr(8) ) * FEET_TO_METER;
639         }
640     } else if ( arg.find( "--vBody=" ) != string::npos ) {
641         if ( units == FG_UNITS_FEET ) {
642             vBody = atof( arg.substr(8) );
643         } else {
644             vBody = atof( arg.substr(8) ) * FEET_TO_METER;
645         }
646     } else if ( arg.find( "--wBody=" ) != string::npos ) {
647         if ( units == FG_UNITS_FEET ) {
648             wBody = atof( arg.substr(8) );
649         } else {
650             wBody = atof( arg.substr(8) ) * FEET_TO_METER;
651         }
652     } else if ( arg.find( "--heading=" ) != string::npos ) {
653         heading = atof( arg.substr(10) );
654     } else if ( arg.find( "--roll=" ) != string::npos ) {
655         roll = atof( arg.substr(7) );
656     } else if ( arg.find( "--pitch=" ) != string::npos ) {
657         pitch = atof( arg.substr(8) );
658     } else if ( arg.find( "--fg-root=" ) != string::npos ) {
659         fg_root = arg.substr( 10 );
660     } else if ( arg.find( "--fdm=" ) != string::npos ) {
661         flight_model = parse_fdm( arg.substr(6) );
662     } else if ( arg.find( "--aircraft=" ) != string::npos ) {
663         aircraft = arg.substr(11);
664     } else if ( arg.find( "--aircraft-dir=" ) != string::npos ) {
665         aircraft_dir =  arg.substr(15); //  (UIUC)
666     } else if ( arg.find( "--model-hz=" ) != string::npos ) {
667         model_hz = atoi( arg.substr(11) );
668     } else if ( arg.find( "--speed=" ) != string::npos ) {
669         speed_up = atoi( arg.substr(8) );
670     } else if ( arg == "--fog-disable" ) {
671         fog = FG_FOG_DISABLED;  
672     } else if ( arg == "--fog-fastest" ) {
673         fog = FG_FOG_FASTEST;   
674     } else if ( arg == "--fog-nicest" ) {
675         fog = FG_FOG_NICEST;    
676     } else if ( arg == "--disable-clouds" ) {
677         clouds = false; 
678     } else if ( arg == "--enable-clouds" ) {
679         clouds = true;  
680     } else if ( arg.find( "--clouds-asl=" ) != string::npos ) {
681         if ( units == FG_UNITS_FEET ) {
682             clouds_asl = atof( arg.substr(13) ) * FEET_TO_METER;
683         } else {
684             clouds_asl = atof( arg.substr(13) );
685         }
686     } else if ( arg.find( "--fov=" ) != string::npos ) {
687         fov = parse_fov( arg.substr(6) );
688     } else if ( arg == "--disable-fullscreen" ) {
689         fullscreen = false;     
690     } else if ( arg== "--enable-fullscreen") {
691         fullscreen = true;      
692     } else if ( arg == "--shading-flat") {
693         shading = 0;    
694     } else if ( arg == "--shading-smooth") {
695         shading = 1;    
696     } else if ( arg == "--disable-skyblend") {
697         skyblend = false;       
698     } else if ( arg== "--enable-skyblend" ) {
699         skyblend = true;        
700     } else if ( arg == "--disable-textures" ) {
701         textures = false;       
702     } else if ( arg == "--enable-textures" ) {
703         textures = true;
704     } else if ( arg == "--disable-wireframe" ) {
705         wireframe = false;      
706     } else if ( arg == "--enable-wireframe" ) {
707         wireframe = true;
708     } else if ( arg.find( "--geometry=" ) != string::npos ) {
709         bool geometry_ok = true;
710         string geometry = arg.substr( 11 );
711         string::size_type i = geometry.find('x');
712
713         if (i != string::npos) {
714             xsize = atoi(geometry.substr(0, i));
715             ysize = atoi(geometry.substr(i+1));
716             // cout << "Geometry is " << xsize << 'x' << ysize << '\n';
717         } else {
718             geometry_ok = false;
719         }
720
721         if ( xsize <= 0 || ysize <= 0 ) {
722             xsize = 640;
723             ysize = 480;
724             geometry_ok = false;
725         }
726
727         if ( !geometry_ok ) {
728             FG_LOG( FG_GENERAL, FG_ALERT, "Unknown geometry: " << geometry );
729             FG_LOG( FG_GENERAL, FG_ALERT,
730                     "Setting geometry to " << xsize << 'x' << ysize << '\n');
731         }
732     } else if ( arg == "--units-feet" ) {
733         units = FG_UNITS_FEET;  
734     } else if ( arg == "--units-meters" ) {
735         units = FG_UNITS_METERS;        
736     } else if ( arg.find( "--tile-radius=" ) != string::npos ) {
737         tile_radius = parse_tile_radius( arg.substr(14) );
738         tile_diameter = tile_radius * 2 + 1;
739     } else if ( arg.find( "--time-offset" ) != string::npos ) {
740         time_offset = parse_time_offset( (arg.substr(14)) );
741         //time_offset_type = FG_TIME_SYS_OFFSET;
742     } else if ( arg.find( "--time-match-real") != string::npos ) {
743       //time_offset = parse_time_offset(arg.substr(18));
744         time_offset_type = FG_TIME_SYS_OFFSET;
745     } else if ( arg.find( "--time-match-local") != string::npos ) {
746       //time_offset = parse_time_offset(arg.substr(18));
747         time_offset_type = FG_TIME_LAT_OFFSET;
748     } else if ( arg.find( "--start-date-sys=") != string::npos ) {
749         time_offset = parse_date( (arg.substr(17)) );
750         time_offset_type = FG_TIME_SYS_ABSOLUTE;
751     } else if ( arg.find( "--start-date-lat=") != string::npos ) {
752         time_offset = parse_date( (arg.substr(17)) );
753         time_offset_type = FG_TIME_LAT_ABSOLUTE;
754     } else if ( arg.find( "--start-date-gmt=") != string::npos ) {
755         time_offset = parse_date( (arg.substr(17)) );
756         time_offset_type = FG_TIME_GMT_ABSOLUTE;
757
758     } else if ( arg == "--hud-tris" ) {
759         tris_or_culled = 0;     
760     } else if ( arg == "--hud-culled" ) {
761         tris_or_culled = 1;
762     } else if ( arg.find( "--native=" ) != string::npos ) {
763         parse_channel( "native", arg.substr(9) );
764     } else if ( arg.find( "--garmin=" ) != string::npos ) {
765         parse_channel( "garmin", arg.substr(9) );
766     } else if ( arg.find( "--nmea=" ) != string::npos ) {
767         parse_channel( "nmea", arg.substr(7) );
768     } else if ( arg.find( "--pve=" ) != string::npos ) {
769         parse_channel( "pve", arg.substr(6) );
770     } else if ( arg.find( "--rul=" ) != string::npos ) {
771         parse_channel( "rul", arg.substr(6) );
772 #ifdef FG_NETWORK_OLK
773     } else if ( arg == "--disable-network-olk" ) {
774         network_olk = false;    
775     } else if ( arg== "--enable-network-olk") {
776         network_olk = true;     
777     } else if ( arg == "--net-hud" ) {
778         net_hud_display = 1;    
779     } else if ( arg.find( "--net-id=") != string::npos ) {
780         net_id = arg.substr( 9 );
781 #endif
782     } else {
783         FG_LOG( FG_GENERAL, FG_ALERT, "Unknown option '" << arg << "'" );
784         return FG_OPTIONS_ERROR;
785     }
786     
787     return FG_OPTIONS_OK;
788 }
789
790
791 // Parse the command line options
792 int fgOPTIONS::parse_command_line( int argc, char **argv ) {
793     int i = 1;
794     int result;
795
796     FG_LOG(FG_GENERAL, FG_INFO, "Processing command line arguments");
797
798     while ( i < argc ) {
799         FG_LOG( FG_GENERAL, FG_DEBUG, "argv[" << i << "] = " << argv[i] );
800
801         result = parse_option(argv[i]);
802         if ( (result == FG_OPTIONS_HELP) || (result == FG_OPTIONS_ERROR) ) {
803             return(result);
804         }
805
806         i++;
807     }
808     
809     return(FG_OPTIONS_OK);
810 }
811
812
813 // Parse config file options
814 int fgOPTIONS::parse_config_file( const string& path ) {
815     fg_gzifstream in( path );
816     if ( !in.is_open() )
817         return(FG_OPTIONS_ERROR);
818
819     FG_LOG( FG_GENERAL, FG_INFO, "Processing config file: " << path );
820
821     in >> skipcomment;
822 #ifndef __MWERKS__
823     while ( ! in.eof() ) {
824 #else
825     char c = '\0';
826     while ( in.get(c) && c != '\0' ) {
827         in.putback(c);
828 #endif
829         string line;
830
831 #ifdef GETLINE_NEEDS_TERMINATOR
832         getline( in, line, '\n' );
833 #elif defined (MACOS)
834         getline( in, line, '\r' );
835 #else
836         getline( in, line );
837 #endif
838
839         if ( parse_option( line ) == FG_OPTIONS_ERROR ) {
840             FG_LOG( FG_GENERAL, FG_ALERT, 
841                     "Config file parse error: " << path << " '" 
842                     << line << "'" );
843             exit(-1);
844         }
845         in >> skipcomment;
846     }
847
848     return FG_OPTIONS_OK;
849 }
850
851
852 // Print usage message
853 void fgOPTIONS::usage ( void ) {
854     cout << "Usage: fg [ options ... ]" << endl;
855     cout << endl;
856
857     cout << "General Options:" << endl;
858     cout << "\t--help -h:  print usage" << endl;
859     cout << "\t--fg-root=path:  specify the root path for all the data files"
860          << endl;
861     cout << "\t--disable-game-mode:  disable full-screen game mode" << endl;
862     cout << "\t--enable-game-mode:  enable full-screen game mode" << endl;
863     cout << "\t--disable-splash-screen:  disable splash screen" << endl;
864     cout << "\t--enable-splash-screen:  enable splash screen" << endl;
865     cout << "\t--disable-intro-music:  disable introduction music" << endl;
866     cout << "\t--enable-intro-music:  enable introduction music" << endl;
867     cout << "\t--disable-mouse-pointer:  disable extra mouse pointer" << endl;
868     cout << "\t--enable-mouse-pointer:  enable extra mouse pointer (i.e. for"
869          << endl;
870     cout << "\t\tfull screen voodoo/voodoo-II based cards.)" << endl;
871     cout << "\t--disable-pause:  start out in an active state" << endl;
872     cout << "\t--enable-pause:  start out in a paused state" << endl;
873     cout << "\t--control=mode:  primary control mode " 
874          << "(joystick, keyboard, mouse)" << endl;
875     cout << endl;
876
877     cout << "Features:" << endl;
878     cout << "\t--disable-hud:  disable heads up display" << endl;
879     cout << "\t--enable-hud:  enable heads up display" << endl;
880     cout << "\t--disable-panel:  disable instrument panel" << endl;
881     cout << "\t--enable-panel:  enable instrumetn panel" << endl;
882     cout << "\t--disable-sound:  disable sound effects" << endl;
883     cout << "\t--enable-sound:  enable sound effects" << endl;
884     cout << endl;
885  
886     cout << "Flight Model:" << endl;
887     cout << "\t--fdm=abcd:  selects the core flight model code." << endl;
888     cout << "\t\tcan be one of jsb, larcsim, magic, or external" << endl;
889     cout << "\t--aircraft=abcd:  aircraft model to load" << endl;
890     cout << "\t--model-hz=n:  run the FDM this rate (iterations per second)" 
891          << endl;
892     cout << "\t--speed=n:  run the FDM this much faster than real time" << endl;
893     cout << endl;
894     //(UIUC)
895     cout <<"Aircraft model directory" << endl;
896     cout <<"\t--aircraft-dir=<path> path is relative to the path of the executable" << endl;
897     cout << endl;
898
899     cout << "Initial Position and Orientation:" << endl;
900     cout << "\t--airport-id=ABCD:  specify starting postion by airport id" 
901          << endl;
902     cout << "\t--lon=degrees:  starting longitude in degrees (west = -)" 
903          << endl;
904     cout << "\t--lat=degrees:  starting latitude in degrees (south = -)"
905          << endl;
906     cout << "\t--altitude=feet:  starting altitude in feet" << endl;
907     cout << "\t\t(unless --units-meters specified" << endl;
908     cout << "\t--heading=degrees:  heading (yaw) angle in degress (Psi)"
909          << endl;
910     cout << "\t--roll=degrees:  roll angle in degrees (Phi)" << endl;
911     cout << "\t--pitch=degrees:  pitch angle in degrees (Theta)" << endl;
912     cout << "\t--uBody=feet per second:  velocity along the body X axis"
913          << endl;
914     cout << "\t--vBody=feet per second:  velocity along the body Y axis"
915          << endl;
916     cout << "\t--wBody=feet per second:  velocity along the body Z axis"
917          << endl;
918     cout << "\t\t(unless --units-meters specified" << endl;
919     cout << endl;
920
921     cout << "Rendering Options:" << endl;
922     cout << "\t--fog-disable:  disable fog/haze" << endl;
923     cout << "\t--fog-fastest:  enable fastest fog/haze" << endl;
924     cout << "\t--fog-nicest:  enable nicest fog/haze" << endl;
925     cout << "\t--enable-clouds:  enable demo cloud layer" << endl;
926     cout << "\t--disable-clouds:  disable demo cloud layer" << endl;
927     cout << "\t--clouds-asl=xxx:  specify altitude of cloud layer above sea level" << endl;
928     cout << "\t--fov=xx.x:  specify initial field of view angle in degrees"
929          << endl;
930     cout << "\t--disable-fullscreen:  disable fullscreen mode" << endl;
931     cout << "\t--enable-fullscreen:  enable fullscreen mode" << endl;
932     cout << "\t--shading-flat:  enable flat shading" << endl;
933     cout << "\t--shading-smooth:  enable smooth shading" << endl;
934     cout << "\t--disable-skyblend:  disable sky blending" << endl;
935     cout << "\t--enable-skyblend:  enable sky blending" << endl;
936     cout << "\t--disable-textures:  disable textures" << endl;
937     cout << "\t--enable-textures:  enable textures" << endl;
938     cout << "\t--disable-wireframe:  disable wireframe drawing mode" << endl;
939     cout << "\t--enable-wireframe:  enable wireframe drawing mode" << endl;
940     cout << "\t--geometry=WWWxHHH:  window geometry: 640x480, 800x600, etc."
941          << endl;
942     cout << endl;
943
944     cout << "Scenery Options:" << endl;
945     cout << "\t--tile-radius=n:  specify tile radius, must be 1 - 4" << endl;
946     cout << endl;
947
948     cout << "Hud Options:" << endl;
949     cout << "\t--units-feet:  Hud displays units in feet" << endl;
950     cout << "\t--units-meters:  Hud displays units in meters" << endl;
951     cout << "\t--hud-tris:  Hud displays number of triangles rendered" << endl;
952     cout << "\t--hud-culled:  Hud displays percentage of triangles culled"
953          << endl;
954     cout << endl;
955         
956     cout << "Time Options:" << endl;
957     cout << "\t--time-offset=[+-]hh:mm:ss: add this time offset" << endl;
958     cout << "\t--time-match-real: Synchronize real-world and FlightGear" << endl
959          << "\t\ttime. Can be used in combination with --time-offset." << endl;
960     cout << "\t--time-match-local:Synchronize local real-world and " << endl
961          << "\t\tFlightGear time" << endl;   
962     cout << "\t--start-date-sys=yyyy:mm:dd:hh:mm:ss: specify a starting" << endl
963          << "\t\tdate/time. Uses your system time " << endl;
964     cout << "\t--start-date-gmt=yyyy:mm:dd:hh:mm:ss: specify a starting" << endl
965          << "\t\tdate/time. Uses Greenwich Mean Time" << endl;
966     cout << "\t--start-date-lat=yyyy:mm:dd:hh:mm:ss: specify a starting" << endl
967          << "\t\tdate/time. Uses Local Aircraft Time" << endl;
968 #ifdef FG_NETWORK_OLK
969     cout << "" << endl;
970
971     cout << "Network Options:" << endl;
972     cout << "\t--net-hud:  Hud displays network info" << endl;
973     cout << "\t--net-id=name:  specify your own callsign" << endl;
974 #endif
975 }
976
977
978 // Destructor
979 fgOPTIONS::~fgOPTIONS( void ) {
980 }