2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Cmdline/cmdline.cpp $
16 * Revision 1.7 2005/10/01 21:40:38 taylor
17 * deal with OS X apps a little better, sets the path only based on ".app" in the name rather than the name itself
18 * make sure a global cmdline.cfg file works with OS X when built as an app
20 * Revision 1.6 2003/06/22 12:50:11 taylor
21 * fix memory error, code cleanup
23 * Revision 1.5 2003/05/06 07:20:14 taylor
24 * implement command line options
26 * Revision 1.4 2002/06/21 03:34:05 relnev
27 * implemented a stub and fixed a path
29 * Revision 1.3 2002/06/09 04:41:15 relnev
30 * added copyright header
32 * Revision 1.2 2002/05/07 03:16:43 theoddone33
33 * The Great Newline Fix
35 * Revision 1.1.1.1 2002/05/03 03:28:08 root
39 * 8 8/26/99 8:51p Dave
40 * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
42 * 7 7/15/99 3:07p Dave
43 * 32 bit detection support. Mouse coord commandline.
45 * 6 7/13/99 1:15p Dave
46 * 32 bit support. Whee!
48 * 5 6/22/99 9:37p Dave
51 * 4 1/12/99 5:45p Dave
52 * Moved weapon pipeline in multiplayer to almost exclusively client side.
53 * Very good results. Bandwidth goes down, playability goes up for crappy
54 * connections. Fixed object update problem for ship subsystems.
56 * 3 11/17/98 11:12a Dave
57 * Removed player identification by address. Now assign explicit id #'s.
59 * 2 10/07/98 10:52a Dave
62 * 1 10/07/98 10:48a Dave
64 * 38 10/02/98 3:22p Allender
65 * fix up the -connect option and fix the -port option
67 * 37 9/15/98 4:04p Allender
68 * added back in the -ip_addr command line switch because it needs to be
69 * in the standalone server only executable
71 * 36 9/14/98 11:52a Allender
74 * 35 9/14/98 11:28a Allender
75 * support for server bashing of address when received from client. Added
76 * a cmdline.cfg file to process command line arguments from a file
78 * 34 9/08/98 2:20p Allender
79 * temporary code to force IP address to a specific value.
81 * 33 8/20/98 5:30p Dave
82 * Put in handy multiplayer logfile system. Now need to put in useful
83 * applications of it all over the code.
85 * 32 8/07/98 10:39a Allender
86 * fixed debug standalone problem where stats would continually get sent
87 * to tracker. more debug code to help find stats problem
89 * 31 7/24/98 11:14a Allender
90 * start of new command line options for version 1.04
92 * 30 5/21/98 1:50a Dave
93 * Remove obsolete command line functions. Reduce shield explosion packets
94 * drastically. Tweak PXO screen even more. Fix file xfer system so that
95 * we can guarantee file uniqueness.
97 * 29 5/18/98 9:10p Dave
98 * Put in many new PXO features. Fixed skill level bashing in multiplayer.
99 * Removed several old command line options. Put in network config files.
101 * 28 5/09/98 7:16p Dave
102 * Put in CD checking. Put in standalone host password. Made pilot into
105 * 27 4/23/98 8:27p Allender
106 * basic support for cutscene playback. Into movie code in place. Tech
107 * room can view cutscenes stored in CDROM_dir variable
109 * 26 4/09/98 5:43p Dave
110 * Remove all command line processing from the demo. Began work fixing up
111 * the new multi host options screen.
113 * 25 4/02/98 11:40a Lawrance
114 * check for #ifdef DEMO instead of #ifdef DEMO_RELEASE
116 * 24 4/01/98 5:56p Dave
117 * Fixed a messaging bug which caused msg_all mode in multiplayer not to
118 * work. Compile out a host of multiplayer options not available in the
121 * 23 3/14/98 2:48p Dave
122 * Cleaned up observer joining code. Put in support for file xfers to
123 * ingame joiners (observers or not). Revamped and reinstalled pseudo
126 * 22 2/22/98 12:19p John
127 * Externalized some strings
129 * 21 1/31/98 4:32p Dave
130 * Put in new support for VMT player validation, game logging in and game
133 * 20 12/10/97 4:45p Dave
134 * Added in more detailed support for multiplayer packet lag/loss. Fixed
135 * some multiplayer stuff. Added some controls to the standalone.
137 * 19 12/09/97 6:14p Lawrance
140 * 18 12/01/97 5:10p Dave
141 * Fixed a syntax bug.
143 * 17 12/01/97 4:59p Dave
144 * Synchronized multiplayer debris objects. Put in pilot popup in main
145 * hall. Optimized simulated multiplayer lag module. Fixed a potential
148 * 16 11/28/97 7:04p Dave
149 * Emergency checkin due to big system crash.
151 * 15 11/28/97 5:06p Dave
152 * Put in facilities for simulating multiplayer lag.
154 * 14 11/24/97 5:42p Dave
155 * Fixed a file xfer buffer free/malloc problem. Lengthened command line
156 * switch string parse length.
158 * 13 11/12/97 4:39p Dave
159 * Put in multiplayer campaign support parsing, loading and saving. Made
160 * command-line variables better named. Changed some things on the initial
161 * pilot select screen.
163 * 12 11/11/97 4:54p Dave
164 * Put in support for single vs. multiplayer pilots. Put in initial player
165 * selection screen (no command line option yet). Started work on
166 * multiplayer campaign file save gaming.
168 * 11 11/11/97 11:55a Allender
169 * initialize network at beginning of application. create new call to set
170 * which network protocol to use
172 * 10 9/18/97 10:12p Dave
173 * Added -gimmemedals, which gives the current pilot all the medals in the
176 * 9 9/18/97 9:20a Dave
177 * Minor modifications
179 * 8 9/15/97 11:40p Lawrance
180 * remove demo granularity switch
182 * 7 9/09/97 3:39p Sandeep
183 * warning level 4 bugs
185 * 6 9/03/97 5:03p Lawrance
186 * add support for -nosound command line parm
188 * 5 8/22/97 8:52a Dave
189 * Removed a return statement which would have broken the parser out too
192 * 4 8/21/97 4:55p Dave
193 * Added a switch for multiplayer chat streaming. Added a section for
194 * global command line vars.
196 * 3 8/06/97 2:26p Dave
197 * Made the command line parse more robust. Made it easier to add and
198 * process new command-line switches.
200 * 2 8/04/97 3:13p Dave
201 * Added command line functions. See cmdline.cpp for directions on adding
204 * 1 8/04/97 9:58a Dave
213 #include "linklist.h"
214 #include "systemvars.h"
218 #include "osregistry.h"
221 #include "cfilesystem.h"
226 cmdline_parm *next, *prev;
227 const char *name; // name of parameter, must start with '-' char
228 const char *name2; // name - alternate
229 const char *help; // help text for this parameter
230 char *args; // string value for parameter arguements (NULL if no arguements)
231 int name_found; // true if parameter on command line, otherwise false
233 cmdline_parm(const char *name, const char *name2, const char *help);
241 // here are the command line parameters that we will be using for FreeSpace
242 cmdline_parm standalone_arg("-standalone", "-d", NULL);
243 cmdline_parm nosound_arg("-nosound", "-s", NULL);
244 cmdline_parm nomusic_arg("-nomusic", NULL, NULL);
245 cmdline_parm startgame_arg("-startgame", "-S", NULL);
246 cmdline_parm gamename_arg("-gamename", "-N", NULL);
247 cmdline_parm gamepassword_arg("-password", "-p", NULL);
248 cmdline_parm gameclosed_arg("-closed", "-c", NULL);
249 cmdline_parm gamerestricted_arg("-restricted", "-r", NULL);
250 cmdline_parm allowabove_arg("-allowabove", "-a", NULL);
251 cmdline_parm allowbelow_arg("-allowbelow", "-b", NULL);
252 cmdline_parm port_arg("-port", "-o", NULL);
253 cmdline_parm connect_arg("-connect", "-C", NULL);
254 cmdline_parm multilog_arg("-multilog", "-m", NULL);
255 cmdline_parm server_firing_arg("-oldfire", "-F", NULL);
256 cmdline_parm client_dodamage("-clientdamage", "-D", NULL);
257 cmdline_parm pof_spew("-pofspew", "-P", NULL);
258 cmdline_parm d3d_32bit("-32bit", NULL, NULL);
259 cmdline_parm mouse_coords("-coords", "-M", NULL);
260 cmdline_parm timeout("-timeout", "-t", NULL);
261 cmdline_parm d3d_window("-window", "-w", NULL);
262 cmdline_parm d3d_fullscreen("-fullscreen", "-f", NULL);
263 cmdline_parm help("-help", "-h", NULL);
264 cmdline_parm no_grab("-nograb", "-g", NULL);
265 cmdline_parm fs_version("-version", "-v", NULL);
266 cmdline_parm no_movies("-nomovies", "-n", NULL);
269 int Cmdline_multi_stream_chat_to_file = 0;
270 int Cmdline_freespace_no_sound = 0;
271 int Cmdline_freespace_no_music = 0;
272 int Cmdline_gimme_all_medals = 0;
273 int Cmdline_use_last_pilot = 0;
274 int Cmdline_multi_protocol = -1;
275 int Cmdline_cd_check = 1;
276 int Cmdline_start_netgame = 0;
277 int Cmdline_closed_game = 0;
278 int Cmdline_restricted_game = 0;
279 int Cmdline_network_port = -1;
280 char *Cmdline_game_name = NULL;
281 char *Cmdline_game_password = NULL;
282 char *Cmdline_rank_above= NULL;
283 char *Cmdline_rank_below = NULL;
284 char *Cmdline_connect_addr = NULL;
285 int Cmdline_multi_log = 0;
286 int Cmdline_server_firing = 0;
287 int Cmdline_client_dodamage = 0;
288 int Cmdline_spew_pof_info = 0;
289 int Cmdline_force_32bit = 0;
290 int Cmdline_mouse_coords = 0;
291 int Cmdline_timeout = -1;
292 int Cmdline_no_grab = 0;
293 int Cmdline_play_movies = 1;
294 int Cmdline_fullscreen = 0;
295 int Cmdline_window = 0;
297 static cmdline_parm Parm_list(NULL, NULL, NULL);
299 static int Parm_list_inited = 0;
302 // Return true if this character is an extra char (white space and quotes)
303 static int is_extra_space(char ch)
305 return ((ch == ' ') || (ch == '\t') || (ch == 0x0a) || (ch == '\'') || (ch == '\"'));
309 // eliminates all leading and trailing extra chars from a string. Returns pointer passed in.
310 static char *drop_extra_chars(char *str)
315 while (str[s] && is_extra_space(str[s]))
320 if (!is_extra_space(str[e])){
328 memmove(str, str + s, e - s + 1);
336 // internal function - copy the value for a parameter agruement into the cmdline_parm arg field
337 static void parm_stuff_args(cmdline_parm *parm, char *cmdline)
339 char buffer[1024] = { 0 };
342 while ((*cmdline != 0) && (*cmdline != '-') && ((size_t)(dest-buffer) < sizeof(buffer))) {
343 *dest++ = *cmdline++;
346 drop_extra_chars(buffer);
348 // mwa 9/14/98 -- made it so that newer command line arguments found will overwrite
350 // SDL_assert(parm->args == NULL);
351 if ( parm->args != NULL ) {
352 delete [] parm->args;
356 int size = strlen(buffer);
358 parm->args = new (std::nothrow) char[size+1];
360 if (parm->args != NULL) {
361 memset(parm->args, 0, size+1);
362 SDL_strlcpy(parm->args, buffer, size+1);
368 // internal function - parse the command line, extracting parameter arguements if they exist
369 // cmdline - command line string passed to the application
370 static void os_parse_parms(char *cmdline)
372 // locate command line parameters
374 char *cmdline_offset = NULL;
375 char pname[33] = { 0 };
377 if ( !cmdline || (strlen(cmdline) <= 1) ) {
381 for (parmp = GET_FIRST(&Parm_list); parmp !=END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp) ) {
382 // check with space to make sure we get the correct option name
383 SDL_snprintf(pname, sizeof(pname)-1, "%s ", parmp->name);
384 cmdline_offset = strstr(cmdline, pname);
386 if (cmdline_offset) {
387 cmdline_offset += strlen(parmp->name);
388 } else if (parmp->name2 != NULL) {
389 // check with space to make sure we get the correct option name
390 SDL_snprintf(pname, sizeof(pname)-1, "%s ", parmp->name2);
391 cmdline_offset = strstr(cmdline, pname);
393 if (cmdline_offset) {
394 cmdline_offset += strlen(parmp->name2);
398 if (cmdline_offset) {
399 parmp->name_found = 1;
400 parm_stuff_args(parmp, cmdline_offset);
405 static bool os_find_parm(const cmdline_parm *parmp, const char *token)
407 // allow for double '-'
408 if ( (strlen(token) > 2) && (token[1] == '-') ) {
412 if ( !strcmp(parmp->name, token) ) {
416 if ( (parmp->name2 != NULL) && !strcmp(parmp->name2, token) ) {
423 // help for available cmdline options
424 static void print_instructions()
426 printf("http://icculus.org/freespace2\n");
427 printf("Support - FAQ: http://icculus.org/lgfaq\n");
428 printf(" Web: http://bugzilla.icculus.org\n\n");
431 printf("Usage: freespace [options]\n");
433 printf("Usage: freespace2 [options]\n");
436 printf(" General:\n");
437 printf(" [-h | --help] Show this help message\n");
438 printf(" [-v | --version] Show game version\n");
439 printf(" [-s | --nosound] Do not access the sound card\n");
440 printf(" [-f | --fullscreen] Run the game fullscreen\n");
441 printf(" [-w | --window] Run the game in a window\n");
442 printf(" [-g | --nograb] Do not automatically grab mouse\n");
443 printf(" [-n | --nomovies] Do not play movies\n");
444 printf(" [-P | --pofspew] Save model info to pofspew.txt\n");
445 printf(" [-M | --coords] Show coordinates of the mouse cursor\n");
446 printf(" [--nomusic] Do not play music\n");
448 printf(" Multiplayer:\n");
449 printf(" [-d | --standalone] Run as a dedicated server\n");
450 printf(" [-S | --startgame] Start a multiplayer game\n");
451 printf(" [-N | --gamename] Name of the multiplayer game\n");
452 printf(" [-p | --password] Use this password to connect\n");
453 printf(" [-c | --closed] Closed multiplayer game\n");
454 printf(" [-r | --restricted] Restricted multiplayer game\n");
455 printf(" [-a | --allowabove] Only allow above certain rank\n");
456 printf(" [-b | --allowbelow] Only allow below certain rank\n");
457 printf(" [-o | --port] Port to use for multiplayer games\n");
458 printf(" [-C | --connect] Connect to particular IP address\n");
459 printf(" [-m | --multilog] Log multiplayer events\n");
460 printf(" [-F | --oldfire] Server side firing\n");
461 printf(" [-D | --clientdamage] Client does damage\n");
462 printf(" [-t | --timeout] Multiplayer game timeout\n");
466 printf("FreeSpace v%d.%02d\n", FS_VERSION_MAJOR, FS_VERSION_MINOR);
468 printf("Freespace 2 v%d.%02d\n", FS_VERSION_MAJOR, FS_VERSION_MINOR);
470 printf("icculus.org client v%d.%02d\n\n", IO_VERSION_MAJOR, IO_VERSION_MINOR);
475 // validate the command line parameters. Display an error if an unrecognized parameter is located.
476 static void os_validate_parms(char *cmdline)
479 char seps[] = " ,\t\n";
483 if ( !cmdline || (strlen(cmdline) <= 1) ) {
487 token = strtok(cmdline, seps);
488 while(token != NULL) {
489 if (token[0] == '-') {
491 for (parmp = GET_FIRST(&Parm_list); parmp !=END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp) ) {
492 if ( os_find_parm(parmp, token) ) {
498 if (parm_found == 0) {
499 print_instructions();
503 token = strtok(NULL, seps);
508 // Call once to initialize the command line system
510 // cmdline - command line string passed to the application
511 static void os_init_cmdline(const char *cmdline)
514 char cmdname[1024] = { 0 };
516 // read the cmdline.cfg file from the data folder, and pass the command line arguments to
517 // the the parse_parms and validate_parms line. Read these first so anything actually on
518 // the command line will take precedence
520 if ( cfile_init_paths() ) {
524 mprintf(("Command line: "));
526 SDL_snprintf(cmdname, sizeof(cmdname), "%s%s%scmdline.cfg", Cfile_user_dir, Pathtypes[CF_TYPE_DATA].path, DIR_SEPARATOR_STR);
528 fp = fopen (cmdname, "rt");
531 // if not already found check exec directory
532 SDL_snprintf(cmdname, sizeof(cmdname), "%s%s%scmdline.cfg", Cfile_root_dir, Pathtypes[CF_TYPE_DATA].path, DIR_SEPARATOR_STR);
534 fp = fopen (cmdname, "rt");
537 // if the file exists, get a single line, and deal with it
539 char buf[1024] = { 0 }, *p;
541 while (fgets(buf, sizeof(buf), fp) != NULL) {
542 // replace the newline character with a NUL:
543 if ( (p = strrchr(buf, '\n')) != NULL ) {
547 // make sure that we have a trailing space for option finding to
548 // work properly with single args
549 SDL_strlcat(buf, " ", sizeof(buf));
551 mprintf(("%s", buf));
554 os_validate_parms(buf);
560 if ( cmdline && strlen(cmdline) ) {
561 mprintf(("%s", cmdline));
563 // for proper arg handling make sure cmdline has trailing space
564 int len = strlen(cmdline) + 2;
565 char *m_cmdline = (char*) malloc(len);
568 SDL_strlcpy(m_cmdline, cmdline, len);
569 SDL_strlcat(m_cmdline, " ", len);
571 os_parse_parms(m_cmdline);
572 os_validate_parms(m_cmdline);
582 // name_ - name of the parameter, must start with '-' character
583 // help_ - help text for this parameter
584 cmdline_parm::cmdline_parm(const char *name_, const char *name2_, const char *help_)
592 if (Parm_list_inited == 0) {
593 list_init(&Parm_list);
594 Parm_list_inited = 1;
598 list_append(&Parm_list, this);
603 // destructor - frees any allocated memory
604 cmdline_parm::~cmdline_parm()
613 // returns - true if the parameter exists on the command line, otherwise false
614 int cmdline_parm::found()
620 // returns - the interger representation for the parameter arguement
621 int cmdline_parm::get_int()
628 // returns - the float representation for the parameter arguement
629 float cmdline_parm::get_float()
632 return (float)atof(args);
636 // returns - the string value for the parameter arguement
637 char *cmdline_parm::str()
643 // external entry point into this modules
644 int parse_cmdline(const char *cmdline)
646 os_init_cmdline(cmdline);
648 // is this a standalone server??
649 if (standalone_arg.found()) {
654 if ( nosound_arg.found() ) {
655 Cmdline_freespace_no_sound = 1;
659 if ( nomusic_arg.found() ) {
660 Cmdline_freespace_no_music = 1;
663 // should we start a network game
664 if ( startgame_arg.found() ) {
665 Cmdline_use_last_pilot = 1;
666 Cmdline_start_netgame = 1;
669 // closed network game
670 if ( gameclosed_arg.found() ) {
671 Cmdline_closed_game = 1;
674 // restircted network game
675 if ( gamerestricted_arg.found() ) {
676 Cmdline_restricted_game = 1;
679 // get the name of the network game
680 if ( gamename_arg.found() ) {
681 Cmdline_game_name = gamename_arg.str();
683 // be sure that this string fits in our limits
684 if ( Cmdline_game_name && (strlen(Cmdline_game_name) > MAX_GAMENAME_LEN) ) {
685 Cmdline_game_name[MAX_GAMENAME_LEN-1] = '\0';
689 // get the password for a pssword game
690 if ( gamepassword_arg.found() ) {
691 Cmdline_game_password = gamepassword_arg.str();
693 // be sure that this string fits in our limits
694 if ( Cmdline_game_password && (strlen(Cmdline_game_password) > MAX_PASSWD_LEN) ) {
695 Cmdline_game_password[MAX_PASSWD_LEN-1] = '\0';
699 // set the rank above/below arguments
700 if ( allowabove_arg.found() ) {
701 Cmdline_rank_above = allowabove_arg.str();
703 if ( allowbelow_arg.found() ) {
704 Cmdline_rank_below = allowbelow_arg.str();
707 // get the port number for games
708 if ( port_arg.found() ) {
709 Cmdline_network_port = port_arg.get_int();
712 // the connect argument specifies to join a game at this particular address
713 if ( connect_arg.found() ) {
714 Cmdline_use_last_pilot = 1;
715 Cmdline_connect_addr = connect_arg.str();
718 // see if the multilog flag was set
719 if ( multilog_arg.found() ){
720 Cmdline_multi_log = 1;
723 // maybe use old-school server-side firing
724 if (server_firing_arg.found() ){
725 Cmdline_server_firing = 1;
728 // maybe use old-school client damage
729 if(client_dodamage.found()){
730 Cmdline_client_dodamage = 1;
734 if(pof_spew.found()){
735 Cmdline_spew_pof_info = 1;
739 if(d3d_32bit.found()){
740 Cmdline_force_32bit = 1;
744 if(mouse_coords.found()){
745 Cmdline_mouse_coords = 1;
750 Cmdline_timeout = timeout.get_int();
754 if(d3d_window.found()){
759 if(d3d_fullscreen.found()){
760 Cmdline_fullscreen = 1;
765 print_instructions();
774 if(no_movies.found()){
775 Cmdline_play_movies = 0;
778 // display game version
779 if(fs_version.found()){
780 printf("Freespace 2 version: %d.%02d\n", FS_VERSION_MAJOR, FS_VERSION_MINOR);
781 printf("icculus.org client version: %d.%02d\n", IO_VERSION_MAJOR, IO_VERSION_MINOR);
786 // default to windowed mode in debug builds
787 Cmdline_fullscreen = 0;