1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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 the
6  * source.
7  *
8 */
9 
10 #include "cmdline/cmdline.h"
11 #include "camera/camera.h" //VIEWER_ZOOM_DEFAULT
12 #include "cfile/cfilesystem.h"
13 #include "fireball/fireballs.h"
14 #include "globalincs/linklist.h"
15 #include "globalincs/pstypes.h"
16 #include "globalincs/systemvars.h"
17 #include "globalincs/version.h"
18 #include "graphics/shadows.h"
19 #include "hud/hudconfig.h"
20 #include "io/joy.h"
21 #include "network/multi.h"
22 #include "options/OptionsManager.h"
23 #include "osapi/osapi.h"
24 #include "parse/sexp.h"
25 #include "scripting/scripting.h"
26 #include "sound/openal.h"
27 #include "sound/speech.h"
28 #include "starfield/starfield.h"
29 
30 #ifdef _WIN32
31 #include <io.h>
32 #include <direct.h>
33 #elif defined(APPLE_APP)
34 #include <CoreFoundation/CoreFoundation.h>
35 #endif
36 
37 #ifdef SCP_UNIX
38 #include "osapi/osapi.h"
39 #include <dirent.h>
40 #endif
41 
42 #include <cstring>
43 #include <cstdlib>
44 #include <cstdio>
45 
46 #include <jansson.h>
47 
48 // Stupid windows workaround...
49 #ifdef MessageBox
50 #undef MessageBox
51 #endif
52 
53 enum cmdline_arg_type
54 {
55 	AT_NONE       =0,
56 	AT_INT,
57 	AT_FLOAT,
58 	AT_STRING
59 };
60 // values and order MUST match cmdline_arg_type
61 const char *cmdline_arg_types[] =
62 {
63 	"NONE",
64 	"INT",
65 	"FLOAT",
66 	"STRING",
67 };
68 
69 enum class flag_output_type {
70 	Binary,
71 	Json_V1,
72 };
73 
74 // variables
75 class cmdline_parm {
76 public:
77 	cmdline_parm *next, *prev;
78 	const char *name;						// name of parameter, must start with '-' char
79 	const char *help;						// help text for this parameter
80 	const bool stacks;					// whether this arg stacks with each use or is replaced by newest use (should only be used for strings!!)
81 	char *args;						// string value for parameter arguments (NULL if no arguments)
82 	int name_found;				// true if parameter on command line, otherwise false
83 	const int arg_type;					// from enum cmdline_arg_type; used for help
84 
85 	cmdline_parm(const char *name, const char *help, const int arg_type, const bool stacks = false) noexcept;
86 	~cmdline_parm() noexcept;
87 	int found();
88 	int get_int();
89 	float get_float();
90 	char *str();
91 	bool check_if_args_is_valid();
92 	bool has_param();
93 };
94 
95 static cmdline_parm Parm_list(NULL, NULL, AT_NONE);
96 static int Parm_list_inited = 0;
97 
98 extern int Show_framerate;	// from freespace.cpp
99 
100 enum
101 {
102 	// DO NOT CHANGE ANYTHING ABOUT THESE FIRST TWO OR WILL MESS UP THE LAUNCHER
103 	EASY_DEFAULT  =  1 << 1,		// Default FS2 (All features off)
104 	EASY_ALL_ON   =  1 << 2,		// All features on
105 
106 	EASY_HI_MEM_ON   =  1 << 3,		// High memory usage features on
107 	EASY_HI_MEM_OFF  =  1 << 4,		// High memory usage features off
108 
109 	// Add new flags here
110 };
111 
112 enum BuildCaps
113 {
114 	BUILD_CAPS_OPENAL = (1<<0),
115 	BUILD_CAPS_NO_D3D = (1<<1),
116 	BUILD_CAPS_NEW_SND = (1<<2),
117 	BUILD_CAPS_SDL = (1<<3)
118 };
119 
120 #define PARSE_COMMAND_LINE_STRING	"-parse_cmdline_only"
121 #define GET_FLAGS_STRING			"-get_flags"
122 
123 typedef struct
124 {
125 	// DO NOT CHANGE THE SIZE OF THIS AT_STRING!
126 	char name[32];
127 
128 } EasyFlag;
129 
130 EasyFlag easy_flags[] =
131 {
132 	{ "Custom" },
133 	{ "Default FS2 (All features off)" },
134 	{ "All features on" },
135 	{ "High memory usage features on" },
136 	{ "High memory usage features off" }
137 };
138 
139 // DO NOT CHANGE **ANYTHING** ABOUT THIS STRUCTURE AND ITS CONTENT
140 typedef struct
141 {
142 	char  name[20];		// The actual flag
143 	char  desc[40];		// The text that will appear in the launcher (unless its blank, other name is shown)
144 	bool  fso_only;		// true if this is a fs2_open only feature
145 	int   on_flags;		// "Easy setting" which will turn this option on
146 	int   off_flags;	// "Easy setting" which will turn this option off
147 	char  type[16];		// Launcher uses this to put flags under different headings
148 	char  web_url[256];	// Link to documentation of feature (please use wiki or somewhere constant)
149 
150 } Flag;
151 
152 // clang-format off
153 // Please group them by type, ie graphics, gameplay etc, maximum 20 different types
154 Flag exe_params[] =
155 {
156 	{ "-nospec",			"Disable specular",							true,	EASY_DEFAULT | EASY_HI_MEM_OFF,		EASY_ALL_ON  | EASY_HI_MEM_ON,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nospec", },
157 	{ "-noglow",			"Disable glow maps",						true,	EASY_DEFAULT | EASY_HI_MEM_OFF,		EASY_ALL_ON  | EASY_HI_MEM_ON,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noglow", },
158 	{ "-noenv",				"Disable environment maps",					true,	EASY_DEFAULT | EASY_HI_MEM_OFF,		EASY_ALL_ON  | EASY_HI_MEM_ON,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noenv", },
159 	{ "-nonormal",			"Disable normal maps",						true,	EASY_DEFAULT | EASY_HI_MEM_OFF,		EASY_ALL_ON  | EASY_HI_MEM_ON,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nonormal" },
160 	{ "-emissive_light",	"Enable emissive light from ships",			true,	0,									EASY_DEFAULT,					"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-emissive_light" },
161 	{ "-noheight",			"Disable height/parallax maps",				true,	EASY_DEFAULT | EASY_HI_MEM_OFF,		EASY_ALL_ON  | EASY_HI_MEM_ON,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noheight" },
162 	{ "-3dshockwave",		"Enable 3D shockwaves",						true,	EASY_ALL_ON  | EASY_HI_MEM_ON,		EASY_DEFAULT | EASY_HI_MEM_OFF,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dshockwave" },
163 	{ "-no_post_process",	"Disable post-processing",					true,	EASY_DEFAULT | EASY_HI_MEM_OFF,		EASY_ALL_ON | EASY_HI_MEM_ON,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_post_process" },
164 	{ "-soft_particles",	"Enable soft particles",					true,	EASY_ALL_ON,						EASY_DEFAULT,					"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-soft_particles" },
165 	{ "-aa",				"Enable Post-process anti-aliasing",		true,	EASY_ALL_ON  | EASY_HI_MEM_ON,		EASY_DEFAULT | EASY_HI_MEM_OFF,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-aa" },
166 	{ "-nolightshafts",		"Disable lightshafts",						true,	EASY_DEFAULT | EASY_HI_MEM_OFF,		EASY_ALL_ON | EASY_HI_MEM_ON,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nolightshafts"},
167 	{ "-fb_explosions",		"Enable Framebuffer Shockwaves",			true,	EASY_ALL_ON,						EASY_DEFAULT,					"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_explosions", },
168     { "-fb_thrusters",      "Enable Framebuffer Thrusters",             true,   EASY_ALL_ON,						EASY_DEFAULT,					"Graphics",     "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_thrusters", },
169 	{ "-no_deferred",		"Disable Deferred Lighting",				true,	EASY_DEFAULT | EASY_HI_MEM_OFF,		EASY_ALL_ON | EASY_HI_MEM_ON,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_deferred"},
170 	{ "-enable_shadows",	"Enable Shadows",							true,	EASY_ALL_ON  | EASY_HI_MEM_ON,		EASY_DEFAULT | EASY_HI_MEM_OFF,	"Graphics",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-enable_shadows"},
171 
172 	{ "-no_vsync",			"Disable vertical sync",					true,	0,									EASY_DEFAULT,					"Game Speed",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_vsync", },
173 
174 	{ "-fps",				"Show frames per second on HUD",			false,	0,									EASY_DEFAULT,					"HUD",			"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fps", },
175 	{ "-dualscanlines",		"Add another pair of scanning lines",		true,	0,									EASY_DEFAULT,					"HUD",			"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-dualscanlines", },
176 	{ "-targetinfo",		"Enable info next to target",				true,	0,									EASY_DEFAULT,					"HUD",			"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-targetinfo", },
177 	{ "-orbradar",			"Enable 3D radar",							true,	0,									EASY_DEFAULT,					"HUD",			"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-orbradar", },
178 	{ "-rearm_timer",		"Enable rearm/repair completion timer",		true,	0,									EASY_DEFAULT,					"HUD",			"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-rearm_timer", },
179 	{ "-ballistic_gauge",	"Enable analog ballistic ammo gauge",		true,	0,									EASY_DEFAULT,					"HUD",			"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-ballistic_gauge", },
180 
181 	{ "-window",			"Run in window",							true,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-window", },
182 	{ "-fullscreen_window",	"Run in fullscreen window",					false,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
183 	{ "-stretch_menu",		"Stretch interface to fill screen",			true,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
184 	{ "-noscalevid",		"Disable scale-to-window for movies",		true,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
185 	{ "-nomotiondebris",	"Disable motion debris",					true,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
186 	{ "-ship_choice_3d",	"Use 3D models for ship selection",			true,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-ship_choice_3d", },
187 	{ "-weapon_choice_3d",	"Use 3D models for weapon selection",		true,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-weapon_choice_3d", },
188 	{ "-3dwarp",			"Enable 3D warp",							true,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dwarp", },
189 	{ "-warp_flash",		"Enable flash upon warp",					true,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-warp_flash", },
190 	{ "-no_ap_interrupt",	"Disable interrupting autopilot",			true,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ap_interrupt", },
191 	{ "-no_screenshake",	"Disable screen shaking",					true,	0,									EASY_DEFAULT,					"Gameplay",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_screenshake", },
192 
193 	{ "-nosound",			"Disable all sound",						false,	0,									EASY_DEFAULT,					"Audio",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nosound", },
194 	{ "-nomusic",			"Disable music",							false,	0,									EASY_DEFAULT,					"Audio",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomusic", },
195 	{ "-no_enhanced_sound",	"Disable enhanced sound",					false,	0,									EASY_DEFAULT,					"Audio",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_enhanced_sound", },
196 
197 	{ "-portable_mode",		"Store config in portable location",		false,	0,									EASY_DEFAULT,					"Launcher",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-portable_mode", },
198 
199 	{ "-standalone",		"Run as standalone server",					false,	0,									EASY_DEFAULT,					"Multiplayer",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-standalone", },
200 	{ "-startgame",			"Skip mainhall and start hosting",			false,	0,									EASY_DEFAULT,					"Multiplayer",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-startgame", },
201 	{ "-closed",			"Start hosted server as closed",			false,	0,									EASY_DEFAULT,					"Multiplayer",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-closed", },
202 	{ "-restricted",		"Host confirms join requests",				false,	0,									EASY_DEFAULT,					"Multiplayer",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-restricted", },
203 	{ "-multilog",			"",											false,	0,									EASY_DEFAULT,					"Multiplayer",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-multilog", },
204 	{ "-clientdamage",		"",											false,	0,									EASY_DEFAULT,					"Multiplayer",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-clientdamage", },
205 	{ "-mpnoreturn",		"Disable flight deck option",				true,	0,									EASY_DEFAULT,					"Multiplayer",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-mpnoreturn", },
206 	{ "-gateway_ip",		"Set gateway IP address",					false,	0,									EASY_DEFAULT,					"Multiplayer",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-gateway_ip", },
207 
208 	{ "-no_set_gamma",		"Disable setting of gamma",					true,	0,									EASY_DEFAULT,					"Troubleshoot",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_set_gamma", },
209 	{ "-nomovies",			"Disable video playback",					true,	0,									EASY_DEFAULT,					"Troubleshoot",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomovies", },
210 	{ "-noparseerrors",		"Disable parsing errors",					true,	0,									EASY_DEFAULT,					"Troubleshoot",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noparseerrors", },
211 	{ "-loadallweps",		"Load all weapons, even those not used",	true,	0,									EASY_DEFAULT,					"Troubleshoot",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-loadallweps", },
212 	{ "-disable_fbo",		"Disable OpenGL RenderTargets",				true,	0,									EASY_DEFAULT,					"Troubleshoot",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-disable_fbo", },
213 	{ "-disable_pbo",		"Disable OpenGL Pixel Buffer Objects",		true,	0,									EASY_DEFAULT,					"Troubleshoot",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-disable_pbo", },
214 	{ "-ati_swap",			"Fix colour issues on some ATI cards",		true,	0,									EASY_DEFAULT,					"Troubleshoot",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-ati_swap", },
215 	{ "-no_3d_sound",		"Use only 2D/stereo for sound effects",		true,	0,									EASY_DEFAULT,					"Troubleshoot",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_3d_sound", },
216 	{ "-mipmap",			"Enable mipmapping",						true,	0,									EASY_DEFAULT | EASY_HI_MEM_OFF,	"Troubleshoot",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-mipmap", },
217 	{ "-use_gldrawelements","Don't use glDrawRangeElements",			true,	0,									EASY_DEFAULT,					"Troubleshoot",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-use_gldrawelements", },
218 	{ "-gl_finish",			"Fix input lag on some ATI+Linux systems",	true,	0,									EASY_DEFAULT,					"Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-gl_finish", },
219 	{ "-no_geo_effects",	"Disable geometry shader for effects",		true,	0,									EASY_DEFAULT,					"Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_geo_effects", },
220 	{ "-set_cpu_affinity",	"Sets processor affinity to config value",	true,	0,									EASY_DEFAULT,					"Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-set_cpu_affinity", },
221 	{ "-nograb",			"Disables mouse grabbing",					true,	0,									EASY_DEFAULT,					"Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nograb", },
222 	{ "-noshadercache",		"Disables the shader cache",				true,	0,									EASY_DEFAULT,					"Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noshadercache", },
223 #ifdef WIN32
224 	{ "-fix_registry",	"Use a different registry path",				true,	0,									EASY_DEFAULT,					"Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fix_registry", },
225 #endif
226 
227 	{ "-ingame_join",		"Allow in-game joining",					true,	0,									EASY_DEFAULT,					"Experimental",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-ingame_join", },
228 	{ "-voicer",			"Enable voice recognition",					true,	0,									EASY_DEFAULT,					"Experimental",	"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-voicer", },
229 
230 	{ "-bmpmanusage",		"Show how many BMPMAN slots are in use",	false,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-bmpmanusage", },
231 	{ "-pos",				"Show position of camera",					false,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-pos", },
232 	{ "-stats",				"Show statistics",							true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stats", },
233 	{ "-coords",			"Show coordinates",							false,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-coords", },
234 	{ "-pofspew",			"Dump model information to pofspew.txt",	false,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-pofspew", },
235 	{ "-weaponspew",		"Dump weapon stats and spreadsheets",		true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-weaponspew", },
236 	{ "-tablecrcs",			"Dump table CRCs for multi validation",		true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-tablecrcs", },
237 	{ "-missioncrcs",		"Dump mission CRCs for multi validation",	true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-missioncrcs", },
238 	{ "-dis_collisions",	"Disable collisions",						true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-dis_collisions", },
239 	{ "-dis_weapons",		"Disable weapon rendering",					true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-dis_weapons", },
240 	{ "-output_sexps",		"Output SEXPs to sexps.html",				true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_sexps", },
241 	{ "-output_scripting",	"Output scripting to scripting.html",		true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_scripting", },
242 	{ "-output_script_json",	"Output scripting doc to scripting.json",	true,	0,								EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_script_json", },
243 	{ "-save_render_target",	"Save render targets to file",			true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-save_render_target", },
244 	{ "-verify_vps",		"Spew VP CRCs to vp_crcs.txt",				true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-verify_vps", },
245 	{ "-reparse_mainhall",	"Reparse mainhall.tbl when loading halls",	false,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-reparse_mainhall", },
246 	{ "-noninteractive",	"Disables interactive dialogs",				true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noninteractive", },
247 	{ "-no_unfocused_pause","Don't pause if the window isn't focused",	true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
248 	{ "-benchmark_mode",	"Puts the game into benchmark mode",		true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-benchmark_mode", },
249 	{ "-profile_frame_time","Profile frame time",						true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_time", },
250 	{ "-profile_write_file", "Write profiling information to file",		true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_write_file", },
251 	{ "-json_profiling",	"Generate JSON profiling output",			true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-json_profiling", },
252 	{ "-debug_window",		"Enable the debug window",					true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-debug_window", },
253 	{ "-gr_debug",		"Output graphics debug information",			true,	0,									EASY_DEFAULT,					"Dev Tool",		"http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-gr_debug", },
254 };
255 // clang-format on
256 
257 // forward declaration
258 const char * get_param_desc(const char *flag_name);
259 
260 // here are the command line parameters that we will be using for FreeSpace
261 
262 // RETAIL options ----------------------------------------------
263 cmdline_parm connect_arg("-connect", "Automatically connect to multiplayer IP:PORT", AT_STRING);			// Cmdline_connect_addr
264 cmdline_parm gamename_arg("-gamename", "Set multiplayer game name", AT_STRING);		// Cmdline_game_name
265 cmdline_parm gamepassword_arg("-password", "Set multiplayer game password", AT_STRING);	// Cmdline_game_password
266 cmdline_parm allowabove_arg("-allowabove", "Ranks above this can join multi", AT_STRING);	// Cmdline_rank_above
267 cmdline_parm allowbelow_arg("-allowbelow", "Ranks below this can join multi", AT_STRING);	// Cmdline_rank_below
268 cmdline_parm standalone_arg("-standalone", NULL, AT_NONE);
269 cmdline_parm nosound_arg("-nosound", NULL, AT_NONE);			// Cmdline_freespace_no_sound
270 cmdline_parm nomusic_arg("-nomusic", NULL, AT_NONE);			// Cmdline_freespace_no_music
271 cmdline_parm noenhancedsound_arg("-no_enhanced_sound", NULL, AT_NONE);	// Cmdline_no_enhanced_sound
272 cmdline_parm startgame_arg("-startgame", NULL, AT_NONE);		// Cmdline_start_netgame
273 cmdline_parm gameclosed_arg("-closed", NULL, AT_NONE);		// Cmdline_closed_game
274 cmdline_parm gamerestricted_arg("-restricted", NULL, AT_NONE);	// Cmdline_restricted_game
275 cmdline_parm port_arg("-port", "Multiplayer network port", AT_INT);
276 cmdline_parm multilog_arg("-multilog", NULL, AT_NONE);		// Cmdline_multi_log
277 cmdline_parm pof_spew("-pofspew", NULL, AT_NONE);			// Cmdline_spew_pof_info
278 cmdline_parm weapon_spew("-weaponspew", nullptr, AT_STRING);			// Cmdline_spew_weapon_stats
279 cmdline_parm mouse_coords("-coords", NULL, AT_NONE);			// Cmdline_mouse_coords
280 cmdline_parm timeout("-timeout", "Multiplayer network timeout (secs)", AT_INT);				// Cmdline_timeout
281 cmdline_parm bit32_arg("-32bit", "Deprecated", AT_NONE);				// (only here for retail compatibility reasons, doesn't actually do anything)
282 
283 char *Cmdline_connect_addr = NULL;
284 char *Cmdline_game_name = NULL;
285 char *Cmdline_game_password = NULL;
286 char *Cmdline_rank_above = NULL;
287 char *Cmdline_rank_below = NULL;
288 int Cmdline_cd_check = 1;
289 int Cmdline_closed_game = 0;
290 int Cmdline_freespace_no_music = 0;
291 int Cmdline_freespace_no_sound = 0;
292 int Cmdline_gimme_all_medals = 0;
293 int Cmdline_mouse_coords = 0;
294 int Cmdline_multi_log = 0;
295 int Cmdline_multi_stream_chat_to_file = 0;
296 int Cmdline_network_port = -1;
297 int Cmdline_restricted_game = 0;
298 int Cmdline_spew_pof_info = 0;
299 WeaponSpewType Cmdline_spew_weapon_stats = WeaponSpewType::NONE;
300 int Cmdline_start_netgame = 0;
301 int Cmdline_timeout = -1;
302 int Cmdline_use_last_pilot = 0;
303 
304 
305 // FSO options -------------------------------------------------
306 
307 // Graphics related
308 cmdline_parm fov_arg("-fov", "Vertical field-of-view factor", AT_FLOAT);					// Cmdline_fov  -- comand line FOV -Bobboau
309 cmdline_parm clip_dist_arg("-clipdist", "Changes the distance from the viewpoint for the near-clipping plane", AT_FLOAT);		// Cmdline_clip_dist
310 cmdline_parm spec_static_arg("-spec_static", "Adjusts suns contribution to specular highlights", AT_FLOAT);
311 cmdline_parm spec_point_arg("-spec_point", "Adjusts laser weapons contribution to specular highlights", AT_FLOAT);
312 cmdline_parm spec_tube_arg("-spec_tube", "Adjusts beam weapons contribution to specular highlights", AT_FLOAT);
313 cmdline_parm ambient_factor_arg("-ambient_factor", "Adjusts ambient light applied to all parts of a ship", AT_INT);		// Cmdline_ambient_factor
314 cmdline_parm env("-noenv", NULL, AT_NONE);								// Cmdline_env
315 cmdline_parm glow_arg("-noglow", NULL, AT_NONE); 						// Cmdline_glow  -- use Bobs glow code
316 cmdline_parm nomotiondebris_arg("-nomotiondebris", NULL, AT_NONE);		// Cmdline_nomotiondebris  -- Removes those ugly floating rocks -C
317 cmdline_parm noscalevid_arg("-noscalevid", NULL, AT_NONE);				// Cmdline_noscalevid  -- disable video scaling that fits to window
318 cmdline_parm spec_arg("-nospec", NULL, AT_NONE);			// Cmdline_spec  --
319 cmdline_parm emissive_arg("-emissive_light", "Enable emissive light from ships", AT_NONE);		// Cmdline_no_emissive  -- don't use emissive light in OGL
320 cmdline_parm normal_arg("-nonormal", NULL, AT_NONE);						// Cmdline_normal  -- disable normal mapping
321 cmdline_parm height_arg("-noheight", NULL, AT_NONE);						// Cmdline_height  -- enable support for parallax mapping
322 cmdline_parm enable_3d_shockwave_arg("-3dshockwave", NULL, AT_NONE);
323 cmdline_parm softparticles_arg("-soft_particles", NULL, AT_NONE);
324 cmdline_parm no_postprocess_arg("-no_post_process", "Disables post-processing", AT_NONE);
325 cmdline_parm bloom_intensity_arg("-bloom_intensity", "Set bloom intensity, requires post-processing", AT_INT);
326 cmdline_parm post_process_aa_arg("-aa", "Enables post-process antialiasing", AT_NONE);
327 cmdline_parm post_process_aa_preset_arg("-aa_preset", "Sets the AA effect to use. See the wiki for details", AT_INT);
328 cmdline_parm deprecated_fxaa_arg("-fxaa", nullptr, AT_NONE);
329 cmdline_parm deprecated_fxaa_preset_arg("-fxaa_preset", "FXAA quality (0-2), requires post-processing and -fxaa", AT_INT);
330 cmdline_parm deprecated_smaa_arg("-smaa", nullptr, AT_NONE);
331 cmdline_parm deprecated_smaa_preset_arg("-smaa_preset", "SMAA quality (0-3), requires post-processing and -smaa", AT_INT);
332 cmdline_parm fb_explosions_arg("-fb_explosions", NULL, AT_NONE);
333 cmdline_parm fb_thrusters_arg("-fb_thrusters", NULL, AT_NONE);
334 cmdline_parm flightshaftsoff_arg("-nolightshafts", NULL, AT_NONE);
335 cmdline_parm shadow_quality_arg("-shadow_quality", NULL, AT_INT);
336 cmdline_parm enable_shadows_arg("-enable_shadows", NULL, AT_NONE);
337 cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE);	// Cmdline_no_deferred
338 cmdline_parm anisotropy_level_arg("-anisotropic_filter", NULL, AT_INT);
339 
340 float Cmdline_clip_dist = Default_min_draw_distance;
341 int Cmdline_ambient_factor = 128;
342 int Cmdline_env = 1;
343 int Cmdline_mipmap = 0;
344 int Cmdline_glow = 1;
345 int Cmdline_noscalevid = 0;
346 int Cmdline_spec = 1;
347 int Cmdline_emissive = 0;
348 int Cmdline_normal = 1;
349 int Cmdline_height = 1;
350 int Cmdline_enable_3d_shockwave = 0;
351 int Cmdline_softparticles = 0;
352 int Cmdline_bloom_intensity = 25;
353 bool Cmdline_force_lightshaft_off = false;
354 int Cmdline_no_deferred_lighting = 0;
355 int Cmdline_aniso_level = 0;
356 
357 // Game Speed related
358 cmdline_parm no_fpscap("-no_fps_capping", "Don't limit frames-per-second", AT_NONE);	// Cmdline_NoFPSCap
359 cmdline_parm no_vsync_arg("-no_vsync", NULL, AT_NONE);		// Cmdline_no_vsync
360 
361 int Cmdline_NoFPSCap = 0; // Disable FPS capping - kazan
362 int Cmdline_no_vsync = 0;
363 
364 // HUD related
365 cmdline_parm ballistic_gauge("-ballistic_gauge", NULL, AT_NONE);	// Cmdline_ballistic_gauge
366 cmdline_parm dualscanlines_arg("-dualscanlines", NULL, AT_NONE); // Cmdline_dualscanlines  -- Change to phreaks options including new targeting code
367 cmdline_parm orb_radar("-orbradar", NULL, AT_NONE);			// Cmdline_orb_radar
368 cmdline_parm rearm_timer_arg("-rearm_timer", NULL, AT_NONE);	// Cmdline_rearm_timer
369 cmdline_parm targetinfo_arg("-targetinfo", NULL, AT_NONE);	// Cmdline_targetinfo  -- Adds ship name/class to right of target box -C
370 
371 int Cmdline_ballistic_gauge = 0;	// WMCoolmon's gauge thingy
372 int Cmdline_dualscanlines = 0;
373 int Cmdline_orb_radar = 0;
374 int Cmdline_rearm_timer = 0;
375 int Cmdline_targetinfo = 0;
376 
377 // Gameplay related
378 cmdline_parm use_3dwarp("-3dwarp", NULL, AT_NONE);			// Cmdline_3dwarp
379 cmdline_parm ship_choice_3d_arg("-ship_choice_3d", NULL, AT_NONE);	// Cmdline_ship_choice_3d
380 cmdline_parm weapon_choice_3d_arg("-weapon_choice_3d", NULL, AT_NONE);	// Cmdline_weapon_choice_3d
381 cmdline_parm use_warp_flash("-warp_flash", NULL, AT_NONE);	// Cmdline_warp_flash
382 cmdline_parm allow_autpilot_interrupt("-no_ap_interrupt", NULL, AT_NONE);
383 cmdline_parm stretch_menu("-stretch_menu", NULL, AT_NONE);	// Cmdline_stretch_menu
384 cmdline_parm no_screenshake("-no_screenshake", nullptr, AT_NONE); // Cmdline_no_screenshake
385 
386 int Cmdline_3dwarp = 0;
387 int Cmdline_ship_choice_3d = 0;
388 int Cmdline_weapon_choice_3d = 0;
389 int Cmdline_warp_flash = 0;
390 int Cmdline_autopilot_interruptable = 1;
391 int Cmdline_stretch_menu = 0;
392 int Cmdline_no_screenshake = 0;
393 
394 // Audio related
395 cmdline_parm voice_recognition_arg("-voicer", NULL, AT_NONE);	// Cmdline_voice_recognition
396 
397 int Cmdline_voice_recognition = 0;
398 int Cmdline_no_enhanced_sound = 0;
399 
400 // MOD related
401 cmdline_parm mod_arg("-mod", "List of folders to overwrite/add-to the default data", AT_STRING, true);	// Cmdline_mod  -- DTP modsupport
402 
403 char *Cmdline_mod = NULL; //DTP for mod argument
404 
405 // Multiplayer/Network related
406 cmdline_parm almission_arg("-almission", "Autoload multiplayer mission", AT_STRING);		// Cmdline_almission  -- DTP for autoload Multi mission
407 cmdline_parm ingamejoin_arg("-ingame_join", NULL, AT_NONE);	// Cmdline_ingamejoin
408 cmdline_parm mpnoreturn_arg("-mpnoreturn", NULL, AT_NONE);	// Cmdline_mpnoreturn  -- Removes 'Return to Flight Deck' in respawn dialog -C
409 cmdline_parm objupd_arg("-cap_object_update", "Multiplayer object update cap (0-3)", AT_INT);
410 cmdline_parm gateway_ip_arg("-gateway_ip", "Set gateway IP address", AT_STRING);
411 
412 char *Cmdline_almission = NULL;	//DTP for autoload multi mission.
413 int Cmdline_ingamejoin = 0;
414 int Cmdline_mpnoreturn = 0;
415 int Cmdline_objupd = 3;		// client object updates on LAN by default
416 char *Cmdline_gateway_ip = nullptr;
417 
418 // Launcher related options
419 cmdline_parm portable_mode("-portable_mode", NULL, AT_NONE);
420 
421 bool Cmdline_portable_mode = false;
422 
423 // Troubleshooting
424 cmdline_parm loadallweapons_arg("-loadallweps", NULL, AT_NONE);	// Cmdline_load_all_weapons
425 cmdline_parm nomovies_arg("-nomovies", NULL, AT_NONE);		// Cmdline_nomovies  -- Allows video streaming
426 cmdline_parm no_set_gamma_arg("-no_set_gamma", NULL, AT_NONE);	// Cmdline_no_set_gamma
427 cmdline_parm no_fbo_arg("-disable_fbo", NULL, AT_NONE);		// Cmdline_no_fbo
428 cmdline_parm no_pbo_arg("-disable_pbo", NULL, AT_NONE);		// Cmdline_no_pbo
429 cmdline_parm mipmap_arg("-mipmap", NULL, AT_NONE);			// Cmdline_mipmap
430 cmdline_parm atiswap_arg("-ati_swap", NULL, AT_NONE);        // Cmdline_atiswap - Fix ATI color swap issue for screenshots.
431 cmdline_parm no3dsound_arg("-no_3d_sound", NULL, AT_NONE);		// Cmdline_no_3d_sound - Disable use of full 3D sounds
432 cmdline_parm no_drawrangeelements("-use_gldrawelements", NULL, AT_NONE); // Cmdline_drawelements -- Uses glDrawElements instead of glDrawRangeElements
433 cmdline_parm keyboard_layout("-keyboard_layout", "Specify keyboard layout (qwertz or azerty)", AT_STRING);
434 cmdline_parm gl_finish ("-gl_finish", NULL, AT_NONE);
435 cmdline_parm no_geo_sdr_effects("-no_geo_effects", NULL, AT_NONE);
436 cmdline_parm set_cpu_affinity("-set_cpu_affinity", NULL, AT_NONE);
437 cmdline_parm nograb_arg("-nograb", NULL, AT_NONE);
438 cmdline_parm noshadercache_arg("-noshadercache", NULL, AT_NONE);
439 #ifdef WIN32
440 cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
441 #endif
442 
443 int Cmdline_load_all_weapons = 0;
444 int Cmdline_nomovies = 0;
445 int Cmdline_no_set_gamma = 0;
446 int Cmdline_no_fbo = 0;
447 int Cmdline_no_pbo = 0;
448 int Cmdline_ati_color_swap = 0;
449 int Cmdline_no_3d_sound = 0;
450 int Cmdline_drawelements = 0;
451 char* Cmdline_keyboard_layout = NULL;
452 bool Cmdline_gl_finish = false;
453 bool Cmdline_no_geo_sdr_effects = false;
454 bool Cmdline_set_cpu_affinity = false;
455 bool Cmdline_nograb = false;
456 bool Cmdline_noshadercache = false;
457 #ifdef WIN32
458 bool Cmdline_alternate_registry_path = false;
459 #endif
460 
461 // Developer/Testing related
462 cmdline_parm start_mission_arg("-start_mission", "Skip mainhall and run this mission", AT_STRING);	// Cmdline_start_mission
463 cmdline_parm dis_collisions("-dis_collisions", NULL, AT_NONE);	// Cmdline_dis_collisions
464 cmdline_parm dis_weapons("-dis_weapons", NULL, AT_NONE);		// Cmdline_dis_weapons
465 cmdline_parm noparseerrors_arg("-noparseerrors", NULL, AT_NONE);	// Cmdline_noparseerrors  -- turns off parsing errors -C
466 cmdline_parm extra_warn_arg("-extra_warn", "Enable 'extra' warnings", AT_NONE);	// Cmdline_extra_warn
467 cmdline_parm fps_arg("-fps", NULL, AT_NONE);					// Cmdline_show_fps
468 cmdline_parm bmpmanusage_arg("-bmpmanusage", NULL, AT_NONE);	// Cmdline_bmpman_usage
469 cmdline_parm pos_arg("-pos", NULL, AT_NONE);					// Cmdline_show_pos
470 cmdline_parm stats_arg("-stats", NULL, AT_NONE);				// Cmdline_show_stats
471 cmdline_parm save_render_targets_arg("-save_render_target", NULL, AT_NONE);	// Cmdline_save_render_targets
472 cmdline_parm window_arg("-window", NULL, AT_NONE);				// Cmdline_window
473 cmdline_parm fullscreen_window_arg("-fullscreen_window", "Fullscreen/borderless window (Windows only)", AT_NONE);
474 cmdline_parm res_arg("-res", "Resolution, formatted like 1600x900", AT_STRING);
475 cmdline_parm center_res_arg("-center_res", "Resolution of center monitor, formatted like 1600x900", AT_STRING);
476 cmdline_parm verify_vps_arg("-verify_vps", NULL, AT_NONE);	// Cmdline_verify_vps  -- spew VP crcs to vp_crcs.txt
477 cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_fso.cfg files", AT_NONE);
478 cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline_reparse_mainhall
479 cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); // Cmdline_profile_write_file
480 cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
481 cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
482 cmdline_parm pilot_arg("-pilot", nullptr, AT_STRING); //Cmdline_pilot
483 cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
484 cmdline_parm json_profiling("-json_profiling", NULL, AT_NONE); //Cmdline_json_profiling
485 cmdline_parm show_video_info("-show_video_info", NULL, AT_NONE); //Cmdline_show_video_info
486 cmdline_parm frame_profile_arg("-profile_frame_time", NULL, AT_NONE); //Cmdline_frame_profile
487 cmdline_parm debug_window_arg("-debug_window", NULL, AT_NONE);	// Cmdline_debug_window
488 cmdline_parm graphics_debug_output_arg("-gr_debug", nullptr, AT_NONE); // Cmdline_graphics_debug_output
489 cmdline_parm log_to_stdout_arg("-stdout_log", nullptr, AT_NONE); // Cmdline_log_to_stdout
490 
491 
492 char *Cmdline_start_mission = NULL;
493 int Cmdline_dis_collisions = 0;
494 int Cmdline_dis_weapons = 0;
495 bool Cmdline_output_sexp_info = false;
496 int Cmdline_noparseerrors = 0;
497 #ifdef Allow_NoWarn
498 int Cmdline_nowarn = 0; // turn warnings off in FRED
499 #endif
500 int Cmdline_extra_warn = 0;
501 int Cmdline_bmpman_usage = 0;
502 int Cmdline_show_pos = 0;
503 int Cmdline_show_stats = 0;
504 int Cmdline_save_render_targets = 0;
505 int Cmdline_window = 0;
506 int Cmdline_fullscreen_window = 0;
507 char *Cmdline_res = 0;
508 char *Cmdline_center_res = 0;
509 int Cmdline_verify_vps = 0;
510 int Cmdline_reparse_mainhall = 0;
511 bool Cmdline_profile_write_file = false;
512 bool Cmdline_no_unfocus_pause = false;
513 bool Cmdline_benchmark_mode = false;
514 const char *Cmdline_pilot = nullptr;
515 bool Cmdline_noninteractive = false;
516 bool Cmdline_json_profiling = false;
517 bool Cmdline_frame_profile = false;
518 bool Cmdline_show_video_info = false;
519 bool Cmdline_debug_window = false;
520 bool Cmdline_graphics_debug_output = false;
521 bool Cmdline_log_to_stdout = false;
522 
523 // Other
524 cmdline_parm get_flags_arg(GET_FLAGS_STRING, "Output the launcher flags file", AT_STRING);
525 cmdline_parm output_sexp_arg("-output_sexps", NULL, AT_NONE); //WMC - outputs all SEXPs to sexps.html
526 cmdline_parm output_scripting_arg("-output_scripting", NULL, AT_NONE);	//WMC
527 cmdline_parm output_script_json_arg("-output_script_json", nullptr, AT_NONE);	// m!m
528 
529 // Deprecated flags - CommanderDJ
530 cmdline_parm deprecated_spec_arg("-spec", "Deprecated", AT_NONE);
531 cmdline_parm deprecated_glow_arg("-glow", "Deprecated", AT_NONE);
532 cmdline_parm deprecated_normal_arg("-normal", "Deprecated", AT_NONE);
533 cmdline_parm deprecated_env_arg("-env", "Deprecated", AT_NONE);
534 cmdline_parm deprecated_tbp_arg("-tbp", "Deprecated", AT_NONE);
535 cmdline_parm deprecated_jpgtga_arg("-jpgtga", "Deprecated", AT_NONE);
536 cmdline_parm deprecated_htl_arg("-nohtl", "Deprecated", AT_NONE);
537 cmdline_parm deprecated_brieflighting_arg("-brief_lighting", "Deprecated", AT_NONE);
538 cmdline_parm deprecated_sndpreload_arg("-snd_preload", "Deprecated", AT_NONE);
539 cmdline_parm deprecated_missile_lighting_arg("-missile_lighting", "Deprecated", AT_NONE);
540 cmdline_parm deprecated_cache_bitmaps_arg("-cache_bitmaps", "Deprecated", AT_NONE);
541 cmdline_parm deprecated_no_emissive_arg("-no_emissive_light", "Deprecated", AT_NONE);
542 cmdline_parm deprecated_postprocess_arg("-post_process", "Deprecated", AT_NONE);
543 
544 int Cmdline_deprecated_spec = 0;
545 int Cmdline_deprecated_glow = 0;
546 int Cmdline_deprecated_normal = 0;
547 int Cmdline_deprecated_env = 0;
548 int Cmdline_deprecated_tbp = 0;
549 int Cmdline_deprecated_jpgtga = 0;
550 int Cmdline_deprecated_nohtl = 0;
551 bool Cmdline_deprecated_brief_lighting = 0;
552 bool Cmdline_deprecated_missile_lighting = false;
553 bool Cmdline_deprecated_cache_bitmaps = false;
554 bool Cmdline_deprecated_postprocess = false;
555 
556 #ifndef NDEBUG
557 // NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
cmdline_debug_print_cmdline()558 void cmdline_debug_print_cmdline()
559 {
560 	cmdline_parm *parmp;
561 	int found = 0;
562 	mprintf(("Passed cmdline options:"));
563 
564 	for (parmp = GET_FIRST(&Parm_list); parmp !=END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp) ) {
565 		if ( parmp->name_found ) {
566 			if ( parmp->args != NULL ) {
567 				mprintf(("\n  %s %s", parmp->name, parmp->args));
568 			} else {
569 				mprintf(("\n  %s", parmp->name));
570 			}
571 			found++;
572 		}
573 	}
574 
575 	if ( !found )
576 		mprintf(("\n  <none>"));
577 
578 	mprintf(("\n"));
579 
580 	//Print log messages about any deprecated flags we found - CommanderDJ
581 	if(Cmdline_deprecated_spec == 1)
582 	{
583 		mprintf(("Deprecated flag '-spec' found. Please remove from your cmdline.\n"));
584 	}
585 
586 	if(Cmdline_deprecated_glow == 1)
587 	{
588 		mprintf(("Deprecated flag '-glow' found. Please remove from your cmdline.\n"));
589 	}
590 
591 	if(Cmdline_deprecated_normal == 1)
592 	{
593 		mprintf(("Deprecated flag '-normal' found. Please remove from your cmdline.\n"));
594 	}
595 
596 	if(Cmdline_deprecated_env == 1)
597 	{
598 		mprintf(("Deprecated flag '-env' found. Please remove from your cmdline.\n"));
599 	}
600 
601 	if(Cmdline_deprecated_tbp == 1)
602 	{
603 		mprintf(("Deprecated flag '-tbp' found. Please remove from your cmdline.\n"));
604 	}
605 
606 	if(Cmdline_deprecated_jpgtga == 1)
607 	{
608 		mprintf(("Deprecated flag '-jpgtga' found. Please remove from your cmdline.\n"));
609 	}
610 
611 	if(Cmdline_deprecated_nohtl == 1)
612 	{
613 		mprintf(("Deprecated flag '-nohtl' found. Please remove from your cmdline.\n"));
614 	}
615 
616 	if(Cmdline_deprecated_brief_lighting == 1)
617 	{
618 		mprintf(("Deprecated flag '-brief_lighting' found. Please remove from your cmdline.\n"));
619 	}
620 
621 	if (Cmdline_deprecated_missile_lighting)
622 	{
623 		mprintf(("Deprecated flag '-missile_lighting' found. Please remove from your cmdline.\n"));
624 	}
625 
626 	if (Cmdline_deprecated_cache_bitmaps) {
627 		mprintf(("Deprecated flag '-cache_bitmaps' found. Please remove from your cmdline.\n"));
628 	}
629 
630 	if (Cmdline_deprecated_postprocess) {
631 		mprintf(("Deprecated flag '-post_process' found. Please remove from your cmdline.\n"));
632 	}
633 }
634 #endif
635 
636 //	Return true if this character is an extra char (white space and quotes)
is_extra_space(char ch)637 int is_extra_space(char ch)
638 {
639 	return ((ch == ' ') || (ch == '\t') || (ch == 0x0a) || (ch == '\'') || (ch == '\"'));
640 }
641 
642 
643 // eliminates all leading and trailing extra chars from a string.  Returns pointer passed in.
drop_extra_chars(char * str)644 char *drop_extra_chars(char *str)
645 {
646 	size_t s;
647 	size_t e;
648 
649 	s = 0;
650 	while (str[s] && is_extra_space(str[s]))
651 		s++;
652 
653 	e = strlen(str);
654 
655 	if (e > 0) {
656 		// we already account for NULL later on, so the -1 is here to make
657 		// sure we do our math without taking it into consideration
658 		e -= 1;
659 	}
660 
661 	while (e > s) {
662 		if (!is_extra_space(str[e])){
663 			break;
664 		}
665 
666 		e--;
667 	}
668 
669 	if (e >= s && e !=0 ){
670 		memmove(str, str + s, e - s + 1);
671 	}
672 
673 	str[e - s + 1] = 0;
674 	return str;
675 }
676 
677 
678 /*
679  * @brief Processes one argument for the given parameter
680  *
681  * @param param The parameter to check
682  * @param argc The argument count
683  * @param argc The argument values
684  * @param argc The current index
685  * @return @c true when an extra parameter was found, @c false otherwise
686  */
parm_stuff_args(cmdline_parm * parm,int argc,char * argv[],int index)687 bool parm_stuff_args(cmdline_parm *parm, int argc, char *argv[], int index)
688 {
689 	Assert(index < argc);
690 
691 	if (index + 1 < argc)
692 	{
693 		char* value = argv[index + 1];
694 		if (value[0] == '-')
695 		{
696 			// Found another argument, just return
697 			return false;
698 		}
699 		else
700 		{
701 			char* saved_args = NULL;
702 
703 			if (parm->args != NULL) {
704 				if (parm->stacks) {
705 					saved_args = parm->args;
706 				}
707 				else {
708 					delete[] parm->args;
709 				}
710 
711 				parm->args = NULL;
712 			}
713 
714 			size_t argsize = strlen(argv[index + 1]);
715 			size_t buffersize = argsize;
716 
717 			if (saved_args != NULL)
718 			{
719 				// Add one for the , separating args
720 				buffersize += strlen(saved_args) + 1;
721 			}
722 
723 			buffersize += 1; // Null-terminator
724 
725 			parm->args = new char[buffersize];
726 			memset(parm->args, 0, buffersize);
727 
728 			if (saved_args != NULL)
729 			{
730 				// saved args go first, then new arg
731 				strcpy_s(parm->args, buffersize, saved_args);
732 				// add a separator too, so that we can tell the args apart
733 				strcat_s(parm->args, buffersize, ",");
734 				// now the new arg
735 				strcat_s(parm->args, buffersize, argv[index + 1]);
736 
737 				delete[] saved_args;
738 			}
739 			else
740 			{
741 				strcpy_s(parm->args, buffersize, argv[index + 1]);
742 			}
743 
744 			return true;
745 		}
746 	}
747 	else
748 	{
749 		// Last argument, can't have any values
750 		return false;
751 	}
752 }
753 
754 
755 // internal function - parse the command line, extracting parameter arguments if they exist
756 // cmdline - command line string passed to the application
os_parse_parms(int argc,char * argv[])757 void os_parse_parms(int argc, char *argv[])
758 {
759 	// locate command line parameters
760 	cmdline_parm *parmp;
761 
762 	for (int i = 0; i < argc; i++)
763 	{
764 		// On OS X this gets passed if the application was launched by double-clicking in the Finder
765 		if (i == 1 && strncmp(argv[i], "-psn", 4) == 0)
766 		{
767 			continue;
768 		}
769 
770 		for (parmp = GET_FIRST(&Parm_list); parmp != END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp)) {
771 			if (!stricmp(parmp->name, argv[i]))
772 			{
773 				parmp->name_found = 1;
774 				if (parm_stuff_args(parmp, argc, argv, i))
775 				{
776 					i++;
777 				}
778 			}
779 		}
780 	}
781 }
782 
783 
784 // validate the command line parameters.  Display an error if an unrecognized parameter is located.
os_validate_parms(int argc,char * argv[])785 void os_validate_parms(int argc, char *argv[])
786 {
787 	cmdline_parm *parmp;
788 	char *token;
789 	int parm_found;
790 
791 	for (int i = 0; i < argc; i++)
792 	{
793 		token = argv[i];
794 
795 		// On OS X this gets passed if the application was launched by double-clicking in the Finder
796 		if (i == 1 && strncmp(token, "-psn", 4) == 0) {
797 			continue;
798 		}
799 
800 		if (token[0] == '-') {
801 			parm_found = 0;
802 
803 			for (parmp = GET_FIRST(&Parm_list); parmp != END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp)) {
804 				if (!stricmp(parmp->name, token)) {
805 					parm_found = 1;
806 					break;
807 				}
808 			}
809 
810 			if (parm_found == 0) {
811 				// if we got a -help, --help, -h, or -? then show the help text, otherwise show unknown option
812 				if (!stricmp(token, "-help") || !stricmp(token, "--help") || !stricmp(token, "-h") || !stricmp(token, "-?")) {
813 					printf("FreeSpace 2 Open, version %s\n", FS_VERSION_FULL);
814 					printf("Website: http://scp.indiegames.us\n");
815 					printf("Github (bug reporting): https://github.com/scp-fs2open/fs2open.github.com/issues\n\n");
816 					printf("Usage: fs2_open [options]\n");
817 
818 					// not the prettiest thing but the job gets done
819 					static const int STR_SIZE = 25;  // max len of exe_params.name + 5 spaces
820 					const int AT_SIZE = 8;  // max len of cmdline_arg_types[] + 2 spaces
821 					size_t atp = 0;
822 					size_t sp = 0;
823 					for (parmp = GET_FIRST(&Parm_list); parmp !=END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp) ) {
824 						// don't output deprecated flags
825 						if (stricmp("deprecated", parmp->help) != 0) {
826 							sp = strlen(parmp->name);
827 							if (parmp->arg_type != AT_NONE) {
828 								atp = strlen(cmdline_arg_types[parmp->arg_type]);
829 								printf("    [ %s ]%*s[ %s ]%*s- %s\n", parmp->name, (int)(STR_SIZE - sp -1), NOX(" "), cmdline_arg_types[parmp->arg_type], (int)(AT_SIZE-atp), NOX(" "), parmp->help);
830 							} else {
831 								printf("    [ %s ]%*s- %s\n", parmp->name, (int)(STR_SIZE - sp -1 +AT_SIZE+4), NOX(" "), parmp->help);
832 							}
833 						}
834 					}
835 
836 					printf("\n");
837 					exit(0);
838 				}
839 				else {
840 					char buffer[128];
841 					sprintf(buffer, "Unrecognized command line parameter %s.", token);
842 
843 					os::dialogs::Message(os::dialogs::MESSAGEBOX_INFORMATION, buffer);
844 				}
845 			}
846 		}
847 	}
848 }
849 
parse_cmdline_string(char * cmdline,char ** argv)850 int parse_cmdline_string(char* cmdline, char** argv)
851 {
852 	size_t length = strlen(cmdline);
853 
854 	bool start_found = false;
855 	bool quoted = false;
856 
857 	size_t argc = 0;
858 	char* current_argv = NULL;
859 	for (size_t i = 0; i < length; i++)
860 	{
861 		if (!start_found && !isspace(cmdline[i]))
862 		{
863 			start_found = true;
864 			current_argv = (cmdline + i);
865 		}
866 		else if (start_found)
867 		{
868 			if (cmdline[i] == '"')
869 			{
870 				quoted = !quoted;
871 
872 				if (!quoted && current_argv != NULL)
873 				{
874 					if (argv != NULL)
875 					{
876 						// Terminate string at quote
877 						cmdline[i] = '\0';
878 						argv[argc] = current_argv;
879 						current_argv = NULL;
880 					}
881 
882 					argc++;
883 				}
884 			}
885 			else if (isspace(cmdline[i]) && !quoted)
886 			{
887 				// Parameter terminated by space
888 				if (current_argv != NULL) // == NULL means that we currently don't have a parameter
889 				{
890 					if (argv != NULL)
891 					{
892 						// Terminate string at quote
893 						cmdline[i] = '\0';
894 						argv[argc] = current_argv;
895 						current_argv = NULL;
896 					}
897 
898 					argc++;
899 				}
900 			}
901 			else if (current_argv == NULL)
902 			{
903 				current_argv = cmdline + i;
904 			}
905 		}
906 	}
907 
908 	if (current_argv != NULL)
909 	{
910 		if (argv != NULL)
911 		{
912 			// Terminate string at quote
913 			argv[argc] = current_argv;
914 			current_argv = NULL;
915 		}
916 
917 		argc++;
918 	}
919 
920 	return (int)argc;
921 }
922 
os_process_cmdline(char * cmdline)923 void os_process_cmdline(char* cmdline)
924 {
925 	int argc = parse_cmdline_string(cmdline, NULL);
926 
927 	char** argv = new char*[argc];
928 
929 	argc = parse_cmdline_string(cmdline, argv);
930 
931 	os_parse_parms(argc, argv);
932 	os_validate_parms(argc, argv);
933 
934 	delete[] argv;
935 }
936 
has_cmdline_only_or_get_flags(int argc,char * argv[])937 bool has_cmdline_only_or_get_flags(int argc, char *argv[])
938 {
939 	for (int i = 0; i < argc; ++i)
940 	{
941 		if (!strcmp(argv[i], PARSE_COMMAND_LINE_STRING) || !strcmp(argv[i], GET_FLAGS_STRING))
942 		{
943 			return true;
944 		}
945 	}
946 
947 	return false;
948 }
949 
950 // remove old parms - needed for tests
reset_cmdline_parms()951 static void reset_cmdline_parms()
952 {
953 	for (cmdline_parm *parmp = GET_FIRST(&Parm_list); parmp != END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp)) {
954 		if (parmp->args != NULL) {
955 			delete[] parmp->args;
956 			parmp->args = NULL;
957 		}
958 		parmp->name_found = 0;
959 	}
960 }
961 
962 // Call once to initialize the command line system
963 //
964 // cmdline - command line string passed to the application
os_init_cmdline(int argc,char * argv[])965 void os_init_cmdline(int argc, char *argv[])
966 {
967 	// Tests call this multiple times, so reset the params here.
968 	// Otherwise e.g. the modlist just grows and grows...
969 	reset_cmdline_parms();
970 
971 	FILE *fp;
972 
973 	// Don't parse any command-line config files if we specified PARSE_COMMAND_LINE_STRING (to explicitly prevent it),
974 	// or GET_FLAGS_STRING (because the engine is going to do a quick exit and for GitHub issue #1221)
975 	if (!has_cmdline_only_or_get_flags(argc, argv)) {
976 		// Only parse the config file in the current directory if we are in legacy config mode
977 		if (os_is_legacy_mode()) {
978 			// read the cmdline_fso.cfg file from the data folder, and pass the command line arguments to
979 			// the the parse_parms and validate_parms line.  Read these first so anything actually on
980 			// the command line will take precedence
981 #ifdef APPLE_APP
982 			char resolved_path[MAX_PATH], data_path[MAX_PATH_LEN];
983 
984 			getcwd(data_path, sizeof(data_path));
985 			snprintf(resolved_path, MAX_PATH, "%s/data/cmdline_fso.cfg", data_path);
986 
987 			fp = fopen(resolved_path, "rt");
988 #else
989 			fp = fopen("data" DIR_SEPARATOR_STR "cmdline_fso.cfg", "rt");
990 #endif
991 			// if the file exists, get a single line, and deal with it
992 			if (fp) {
993 				char *buf, *p;
994 
995 				auto len = static_cast<int>(filelength(fileno(fp))) + 2;
996 				buf = new char[len];
997 
998 				if (fgets(buf, len - 1, fp) != nullptr)
999 				{
1000 					// replace the newline character with a NULL
1001 					if ((p = strrchr(buf, '\n')) != NULL) {
1002 						*p = '\0';
1003 					}
1004 #ifdef SCP_UNIX
1005 					// append a space for the os_parse_parms() check
1006 					strcat_s(buf, len, " ");
1007 #endif
1008 					os_process_cmdline(buf);
1009 				}
1010 				delete[] buf;
1011 				fclose(fp);
1012 			}
1013 		} else {
1014 			// parse user specific cmdline_fso config file (will supersede options in global file)
1015 			fp = fopen(os_get_config_path("data/cmdline_fso.cfg").c_str(), "rt");
1016 
1017 			// if the file exists, get a single line, and deal with it
1018 			if ( fp ) {
1019 				char *buf, *p;
1020 
1021 				auto len = static_cast<int>(filelength( fileno(fp) )) + 2;
1022 				buf = new char [len];
1023 
1024 				if (fgets(buf, len-1, fp) != nullptr)
1025 				{
1026 					// replace the newline character with a NULL
1027 					if ( (p = strrchr(buf, '\n')) != NULL ) {
1028 						*p = '\0';
1029 					}
1030 
1031 					// append a space for the os_parse_parms() check
1032 					strcat_s(buf, len, " ");
1033 
1034 					os_process_cmdline(buf);
1035 				}
1036 				delete [] buf;
1037 				fclose(fp);
1038 			}
1039 		}
1040 	} // If cmdline included PARSE_COMMAND_LINE_STRING or GET_FLAGS_STRING
1041 
1042 	// By parsing cmdline last, anything actually on the command line will take precedence.
1043 	os_parse_parms(argc, argv);
1044 	os_validate_parms(argc, argv);
1045 }
1046 
1047 
1048 /*
1049  * arg constructor
1050  *
1051  * @param name_    name of the parameter, must start with '-' character
1052  * @param help_    help text for this parameter
1053  * @param arg_type_    parameters arguement type (if any)
1054  * @param stacks_    can the parameter be stacked
1055  */
cmdline_parm(const char * name_,const char * help_,const int arg_type_,const bool stacks_)1056 cmdline_parm::cmdline_parm(const char *name_, const char *help_, const int arg_type_, const bool stacks_) noexcept:
1057 	name(name_), help(help_), stacks(stacks_), arg_type(arg_type_)
1058 {
1059 	args = NULL;
1060 	name_found = 0;
1061 
1062 	if (Parm_list_inited == 0) {
1063 		Assertion(&Parm_list == this, "Coding error! 1st initialised cmdline_parm must be static Parm_list\n");
1064 		list_init(this);
1065 		Parm_list_inited = 1;
1066 	} else {
1067 		Assertion(name, "Coding error! cmdline_parm's must have a non-NULL name\n");
1068 		Assertion(name[0] == '-', "Coding error! cmdline_parm's must start with a '-'\n");
1069 		// not in the static Parm_list init, so lookup the NULL help args
1070 		if (help == NULL) {
1071 			help = get_param_desc(name);
1072 		}
1073 		list_append(&Parm_list, this);
1074 	}
1075 }
1076 
1077 
1078 // destructor - frees any allocated memory
~cmdline_parm()1079 cmdline_parm::~cmdline_parm() noexcept
1080 {
1081 #ifndef FRED
1082 	if (args) {
1083 		delete [] args;
1084 		args = NULL;
1085 	}
1086 #endif
1087 }
1088 
1089 // checks if the objects args variable is valid
1090 // returns true if it is, shows an error box and returns false if not valid.
check_if_args_is_valid()1091 bool cmdline_parm::check_if_args_is_valid() {
1092 	if ( args == NULL ) {
1093 		Error(__FILE__, __LINE__,
1094 			"Command line flag passed that requires an argument, but the argument is missing!\r\n"
1095 			"The flag is '%s', make sure that you have an argument that follows it.\r\n"
1096 			"You may need to close your launcher and remove the flag manually from %s/data/cmdline_fso.cfg\r\n",
1097 			name, "<Freespace directory>");
1098 		return false;
1099 	} else {
1100 		return true;
1101 	}
1102 }
1103 
1104 
1105 // returns - true if the parameter exists on the command line, otherwise false
found()1106 int cmdline_parm::found()
1107 {
1108 	return name_found;
1109 }
1110 
1111 // returns - the interger representation for the parameter argument
get_int()1112 int cmdline_parm::get_int()
1113 {
1114 	Assertion(arg_type == AT_INT, "Coding error! Cmdline arg (%s) called cmdline_parm::get_int() with invalid arg_type (%s)", name, cmdline_arg_types[arg_type]);
1115 	check_if_args_is_valid();
1116 
1117 	size_t offset = 0;
1118 
1119 	if (stacks) {
1120 		// first off, DON'T STACK NON-STRINGS!!
1121 		Int3();
1122 
1123 		// secondly, we still need to get it right for the user's sake...
1124 		char *moron = strstr(args, ",");
1125 
1126 		if ( moron && ((strlen(moron) + 1) < strlen(args)) ) {
1127 			// we get the last arg, since it's the newest one
1128 			offset = strlen(args) - strlen(moron) + 1;
1129 		}
1130 	}
1131 
1132 	return atoi(args+offset);
1133 }
1134 
1135 
1136 // returns - the float representation for the parameter argument
get_float()1137 float cmdline_parm::get_float()
1138 {
1139 	Assertion(arg_type == AT_FLOAT, "Coding error! Cmdline arg (%s) called cmdline_parm::get_float() with invalid arg_type (%s)", name, cmdline_arg_types[arg_type]);
1140 	check_if_args_is_valid();
1141 
1142 	size_t offset = 0;
1143 
1144 	if (stacks) {
1145 		// first off, DON'T STACK NON-STRINGS!!
1146 		Int3();
1147 
1148 		// secondly, we still need to get it right for the user's sake
1149 		char *moron = strstr(args, ",");
1150 
1151 		if ( moron && ((strlen(moron) + 1) < strlen(args)) ) {
1152 			// we get the last arg, since it's the newest one
1153 			offset = strlen(args) - strlen(moron) + 1;
1154 		}
1155 	}
1156 
1157 	return (float)atof(args+offset);
1158 }
1159 
1160 
1161 // returns - the string value for the parameter argument
str()1162 char *cmdline_parm::str()
1163 {
1164 	Assertion(arg_type == AT_STRING, "Coding error! Cmdline arg (%s) called cmdline_parm::str() with invalid arg_type (%s)", name, cmdline_arg_types[arg_type]);
1165 	check_if_args_is_valid();
1166 
1167 	return args;
1168 }
has_param()1169 bool cmdline_parm::has_param() {
1170 	return args != nullptr;
1171 }
1172 
1173 #ifdef SCP_UNIX
1174 // Return a vector with all filesystem names of "parent/dir" relative to parent.
1175 // dir must not contain a slash.
unix_get_single_dir_names(const SCP_string & parent,const SCP_string & dir)1176 static SCP_vector<SCP_string> unix_get_single_dir_names(const SCP_string& parent, const SCP_string& dir)
1177 {
1178 	SCP_vector<SCP_string> ret;
1179 
1180 	DIR *dp;
1181 	if ((dp = opendir(parent.c_str())) == NULL) {
1182 		Warning(LOCATION, "Can't open directory '%s' when searching mod paths. Ignoring. errno=%d", parent.c_str(), errno);
1183 		return ret;
1184 	}
1185 
1186 	dirent *dirp;
1187 	while ((dirp = readdir(dp)) != NULL) {
1188 		if (!stricmp(dirp->d_name, dir.c_str())) {
1189 			ret.push_back(dirp->d_name);
1190 		}
1191 	}
1192 	(void)closedir(dp);
1193 
1194 	return ret;
1195 }
1196 
1197 // Return a vector with all filesystem names of "parent/dir" relative to parent.
1198 // Recurses to deal with slashes in dir.
unix_get_dir_names(const SCP_string & parent,const SCP_string & dir)1199 static SCP_vector<SCP_string> unix_get_dir_names(const SCP_string& parent, const SCP_string& dir)
1200 {
1201 	size_t slash = dir.find_first_of("/\\");
1202 
1203 	// no subdirectories, no need to recurse
1204 	if (slash == std::string::npos) {
1205 		return unix_get_single_dir_names(parent, dir);
1206 	}
1207 
1208 	// get the names of the first component of dir
1209 	SCP_vector<SCP_string> this_dir_names = unix_get_single_dir_names(parent, dir.substr(0, slash));
1210 
1211 	SCP_string rest = dir.substr(slash + 1);
1212 
1213 	SCP_vector<SCP_string> ret;
1214 
1215 	// search for the rest of dir in each of these
1216 	SCP_vector<SCP_string>::iterator ii, end = this_dir_names.end();
1217 	for (ii = this_dir_names.begin(); ii != end; ++ii) {
1218 		SCP_string this_dir_path = parent + "/" + *ii;
1219 		SCP_vector<SCP_string> mod_path = unix_get_dir_names(this_dir_path, rest);
1220 
1221 		// add all found paths relative to parent
1222 		SCP_vector<SCP_string>::iterator ii2, end2 = mod_path.end();
1223 		for (ii2 = mod_path.begin(); ii2 != end2; ++ii2) {
1224 			ret.push_back(*ii + "/" + *ii2);
1225 		}
1226 	}
1227 
1228 	return ret;
1229 }
1230 
1231 // For case sensitive filesystems (e.g. Linux/BSD) perform case-insensitive dir matches.
handle_unix_modlist(char ** modlist,size_t * len)1232 static void handle_unix_modlist(char **modlist, size_t *len)
1233 {
1234 	// search filesystem for given paths
1235 	SCP_vector<SCP_string> mod_paths;
1236 	for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ","))
1237 	{
1238 		SCP_vector<SCP_string> this_mod_paths = unix_get_dir_names(".", cur_mod);
1239 		// Ignore non-existing mods for unit tests
1240 		if (!running_unittests && this_mod_paths.empty()) {
1241 			ReleaseWarning(LOCATION, "Can't find mod '%s'. Ignoring.", cur_mod);
1242 		}
1243 		mod_paths.insert(mod_paths.end(), this_mod_paths.begin(), this_mod_paths.end());
1244 	}
1245 
1246 	// create new char[] to replace modlist
1247 	size_t total_len = 0;
1248 	SCP_vector<SCP_string>::iterator ii, end = mod_paths.end();
1249 	for (ii = mod_paths.begin(); ii != end; ++ii) {
1250 		total_len += ii->length() + 1;
1251 	}
1252 
1253 	char *new_modlist = new char[total_len + 1];
1254 	memset(new_modlist, 0, total_len + 1);
1255 	end = mod_paths.end();
1256 	for (ii = mod_paths.begin(); ii != end; ++ii) {
1257 		strcat_s(new_modlist, total_len + 1, ii->c_str());
1258 		strcat_s(new_modlist, total_len + 1, ","); // replace later with NUL
1259 	}
1260 
1261 	// make the rest of the modlist manipulation unaware that anything happened here
1262 	delete [] *modlist;
1263 	*modlist = new_modlist;
1264 	*len = total_len;
1265 }
1266 #endif /* SCP_UNIX */
1267 
1268 // external entry point into this modules
1269 
json_get_v1()1270 static json_t* json_get_v1() {
1271 	auto root = json_object();
1272 
1273 	{
1274 		auto version_obj = json_object();
1275 
1276 		json_object_set_new(version_obj, "full", json_string(FS_VERSION_FULL));
1277 		json_object_set_new(version_obj, "major", json_integer(FS_VERSION_MAJOR));
1278 		json_object_set_new(version_obj, "minor", json_integer(FS_VERSION_MINOR));
1279 		json_object_set_new(version_obj, "build", json_integer(FS_VERSION_BUILD));
1280 
1281 		json_object_set_new(version_obj, "has_revision", json_boolean(FS_VERSION_HAS_REVIS));
1282 		json_object_set_new(version_obj, "revision", json_integer(FS_VERSION_REVIS));
1283 		json_object_set_new(version_obj, "revision_str", json_string(FS_VERSION_REVIS_STR));
1284 
1285 		json_object_set_new(root, "version", version_obj);
1286 	}
1287 	{
1288 		auto easy_array = json_array();
1289 
1290 		for (auto& easy_flag : easy_flags) {
1291 			json_array_append_new(easy_array, json_string(easy_flag.name));
1292 		}
1293 
1294 		json_object_set_new(root, "easy_flags", easy_array);
1295 	}
1296 	{
1297 		auto flags_array = json_array();
1298 
1299 		for (auto& flag : exe_params) {
1300 			auto flag_obj = json_object();
1301 
1302 			json_object_set_new(flag_obj, "name", json_string(flag.name));
1303 			json_object_set_new(flag_obj, "description", json_string(flag.desc));
1304 			json_object_set_new(flag_obj, "fso_only", json_boolean(flag.fso_only));
1305 			json_object_set_new(flag_obj, "on_flags", json_integer(flag.on_flags));
1306 			json_object_set_new(flag_obj, "off_flags", json_integer(flag.off_flags));
1307 			json_object_set_new(flag_obj, "type", json_string(flag.type));
1308 			json_object_set_new(flag_obj, "web_url", json_string(flag.web_url));
1309 
1310 			json_array_append_new(flags_array, flag_obj);
1311 		}
1312 
1313 		json_object_set_new(root, "flags", flags_array);
1314 	}
1315 	{
1316 		auto caps_array = json_array();
1317 
1318 		json_array_append_new(caps_array, json_string("OpenAL"));
1319 		json_array_append_new(caps_array, json_string("No D3D"));
1320 		json_array_append_new(caps_array, json_string("New Sound"));
1321 		json_array_append_new(caps_array, json_string("SDL"));
1322 
1323 		json_object_set_new(root, "caps", caps_array);
1324 	}
1325 	{
1326 		auto voices_array = json_array();
1327 
1328 		auto voices = speech_enumerate_voices();
1329 
1330 		for (auto& voice : voices) {
1331 			json_array_append_new(voices_array, json_string(voice.c_str()));
1332 		}
1333 
1334 		json_object_set_new(root, "voices", voices_array);
1335 	}
1336 	{
1337 		auto resolution_array = json_array();
1338 
1339 		auto displays = gr_enumerate_displays();
1340 
1341 		for (auto& display : displays) {
1342 			auto display_obj = json_object();
1343 
1344 			json_object_set_new(display_obj, "index", json_integer(display.index));
1345 			json_object_set_new(display_obj, "name", json_string(display.name.c_str()));
1346 
1347 			json_object_set_new(display_obj, "x", json_integer(display.x));
1348 			json_object_set_new(display_obj, "y", json_integer(display.y));
1349 			json_object_set_new(display_obj, "width", json_integer(display.width));
1350 			json_object_set_new(display_obj, "height", json_integer(display.height));
1351 
1352 			auto modes_array = json_array();
1353 
1354 			for (auto& mode : display.video_modes) {
1355 				auto mode_obj = json_object();
1356 
1357 				json_object_set_new(mode_obj, "x", json_integer(mode.width));
1358 				json_object_set_new(mode_obj, "y", json_integer(mode.height));
1359 				json_object_set_new(mode_obj, "bits", json_integer(mode.bit_depth));
1360 
1361 				json_array_append_new(modes_array, mode_obj);
1362 			}
1363 
1364 			json_object_set_new(display_obj, "modes", modes_array);
1365 
1366 			json_array_append_new(resolution_array, display_obj);
1367 		}
1368 
1369 		json_object_set_new(root, "displays", resolution_array);
1370 	}
1371 	{
1372 		auto openal_obj = json_object();
1373 
1374 		auto openal_info = openal_get_platform_information();
1375 
1376 		json_object_set_new(openal_obj, "version_major", json_integer(openal_info.version_major));
1377 		json_object_set_new(openal_obj, "version_minor", json_integer(openal_info.version_minor));
1378 
1379 		json_object_set(openal_obj, "default_playback", json_string(openal_info.default_playback_device.c_str()));
1380 		json_object_set(openal_obj, "default_capture", json_string(openal_info.default_capture_device.c_str()));
1381 
1382 		{
1383 			auto playback_array = json_array();
1384 
1385 			for (auto& device : openal_info.playback_devices) {
1386 				json_array_append_new(playback_array, json_string(device.c_str()));
1387 			}
1388 
1389 			json_object_set_new(openal_obj, "playback_devices", playback_array);
1390 		}
1391 		{
1392 			auto capture_array = json_array();
1393 
1394 			for (auto& device : openal_info.capture_devices) {
1395 				json_array_append_new(capture_array, json_string(device.c_str()));
1396 			}
1397 
1398 			json_object_set_new(openal_obj, "capture_devices", capture_array);
1399 		}
1400 		{
1401 			auto efx_support_obj = json_object();
1402 
1403 			for (auto& pair : openal_info.efx_support) {
1404 				json_object_set_new(efx_support_obj, pair.first.c_str(), json_boolean(pair.second));
1405 			}
1406 
1407 			json_object_set_new(openal_obj, "efx_support", efx_support_obj);
1408 		}
1409 
1410 		json_object_set_new(root, "openal", openal_obj);
1411 	}
1412 	{
1413 		auto joystick_array = json_array();
1414 
1415 		auto joysticks = io::joystick::getJoystickInformations();
1416 		for (auto& info : joysticks) {
1417 			auto joystick_obj = json_object();
1418 
1419 			json_object_set_new(joystick_obj, "name", json_string(info.name.c_str()));
1420 			json_object_set_new(joystick_obj, "guid", json_string(info.guid.c_str()));
1421 
1422 			json_object_set_new(joystick_obj, "num_axes", json_integer(info.num_axes));
1423 			json_object_set_new(joystick_obj, "num_balls", json_integer(info.num_balls));
1424 			json_object_set_new(joystick_obj, "num_buttons", json_integer(info.num_buttons));
1425 			json_object_set_new(joystick_obj, "num_hats", json_integer(info.num_hats));
1426 
1427 			json_object_set_new(joystick_obj, "is_haptic", json_boolean(info.is_haptic));
1428 
1429 			json_array_append_new(joystick_array, joystick_obj);
1430 		}
1431 
1432 		json_object_set_new(root, "joysticks", joystick_array);
1433 	}
1434 	{
1435 		json_object_set_new(root, "pref_path", json_string(os_get_config_path().c_str()));
1436 	}
1437 
1438 	return root;
1439 }
1440 
write_flags_file()1441 static void write_flags_file() {
1442 	FILE *fp = fopen("flags.lch","w");
1443 
1444 	if (fp == NULL) {
1445 		os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "Error creating flag list for launcher");
1446 		return;
1447 	}
1448 
1449 	int easy_flag_size	= sizeof(EasyFlag);
1450 	int flag_size		= sizeof(Flag);
1451 
1452 	int num_easy_flags	= sizeof(easy_flags) / easy_flag_size;
1453 	int num_flags		= sizeof(exe_params) / flag_size;
1454 
1455 	// Launcher will check its using structures of the same size
1456 	fwrite(&easy_flag_size, sizeof(int), 1, fp);
1457 	fwrite(&flag_size, sizeof(int), 1, fp);
1458 
1459 	fwrite(&num_easy_flags, sizeof(int), 1, fp);
1460 	fwrite(&easy_flags, sizeof(easy_flags), 1, fp);
1461 
1462 	fwrite(&num_flags, sizeof(int), 1, fp);
1463 	fwrite(&exe_params, sizeof(exe_params), 1, fp);
1464 
1465 	{
1466 		// cheap and bastardly cap check for builds
1467 		// (needs to be compatible with older Launchers, which means having
1468 		//  this implies an OpenAL build for old Launchers)
1469 		ubyte build_caps = 0;
1470 
1471 		/* portej05 defined this always */
1472 		build_caps |= BUILD_CAPS_OPENAL;
1473 		build_caps |= BUILD_CAPS_NO_D3D;
1474 		build_caps |= BUILD_CAPS_NEW_SND;
1475 		build_caps |= BUILD_CAPS_SDL;
1476 
1477 		fwrite(&build_caps, 1, 1, fp);
1478 	}
1479 
1480 	fflush(fp);
1481 	fclose(fp);
1482 }
1483 
get_flags_output_type()1484 static flag_output_type get_flags_output_type() {
1485 	Assertion(get_flags_arg.found(), "This function is only valid if " GET_FLAGS_STRING " is present!");
1486 
1487 	if (!get_flags_arg.has_param()) {
1488 		// Default to binary mode
1489 		return flag_output_type::Binary;
1490 	}
1491 
1492 	SCP_string type(get_flags_arg.str());
1493 
1494 	if (type == "binary") {
1495 		return flag_output_type::Binary;
1496 	} else if (type == "json_v1") {
1497 		return flag_output_type::Json_V1;
1498 	} else {
1499 		// This is supposed to make it easy for the launcher to recognize an unsupported type
1500 		printf("OUTPUT TYPE NOT SUPPORTED!\n");
1501 		// Default to json in this case so that no flags.lch file is created
1502 		return flag_output_type::Json_V1;
1503 	}
1504 }
1505 
write_flags()1506 static void write_flags() {
1507 	auto type = get_flags_output_type();
1508 	switch(type) {
1509 	case flag_output_type::Binary:
1510 		write_flags_file();
1511 		break;
1512 	case flag_output_type::Json_V1:
1513 		json_t* root = json_get_v1();
1514 
1515 		json_dumpf(root, stdout, JSON_INDENT(4));
1516 		json_decref(root);
1517 		break;
1518 	}
1519 }
1520 
SetCmdlineParams()1521 bool SetCmdlineParams()
1522 // Sets externed variables used for communication cmdline information
1523 {
1524 	//getcwd(FreeSpace_Directory, 256); // set the directory to our fs2 root
1525 
1526 	// DO THIS FIRST to avoid unrecognized flag warnings when just getting flag file
1527 	if ( get_flags_arg.found() ) {
1528 		write_flags();
1529 
1530 		return false;
1531 	}
1532 
1533 	if (no_fpscap.found())
1534 	{
1535 		Cmdline_NoFPSCap = 1;
1536 	}
1537 
1538 	if(loadallweapons_arg.found())
1539 	{
1540 		Cmdline_load_all_weapons = 1;
1541 	}
1542 
1543 	if(voice_recognition_arg.found())
1544 	{
1545 		Cmdline_voice_recognition = 1;
1546 	}
1547 
1548 #ifdef Allow_NoWarn
1549 	if (nowarn_arg.found())
1550 	{
1551 		Cmdline_nowarn = 1;
1552 	}
1553 #endif
1554 
1555 	if (extra_warn_arg.found())
1556 	{
1557 		Cmdline_extra_warn = 1;
1558 	}
1559 
1560 	if (!Fred_running) { //There is no standalone FRED
1561 		// is this a standalone server??
1562 		if (standalone_arg.found()) {
1563 			Is_standalone = 1;
1564 		}
1565 	}
1566 
1567 	// object update control
1568 	if(objupd_arg.found()){
1569 		Cmdline_objupd = objupd_arg.get_int();
1570 		if (Cmdline_objupd < 0)
1571 		{
1572 			Cmdline_objupd = 0;
1573 		}
1574 		if (Cmdline_objupd > 3)
1575 		{
1576 			Cmdline_objupd = 3;
1577 		}
1578 	}
1579 
1580 	if(mpnoreturn_arg.found()) {
1581 		Cmdline_mpnoreturn = 1;
1582 	}
1583 
1584 	// run with no sound
1585 	if ( nosound_arg.found() ) {
1586 		Cmdline_freespace_no_sound = 1;
1587 		// and since music is automatically unusable...
1588 		Cmdline_freespace_no_music = 1;
1589 	}
1590 
1591 	// run with no music
1592 	if ( nomusic_arg.found() ) {
1593 		Cmdline_freespace_no_music = 1;
1594 	}
1595 
1596 	// Disable enhanced sound
1597 	if (noenhancedsound_arg.found()) {
1598 		Cmdline_no_enhanced_sound = 1;
1599 	}
1600 
1601 	// should we start a network game
1602 	if ( startgame_arg.found() ) {
1603 		Cmdline_use_last_pilot = 1;
1604 		Cmdline_start_netgame = 1;
1605 	}
1606 
1607 	// closed network game
1608 	if ( gameclosed_arg.found() ) {
1609 		Cmdline_closed_game = 1;
1610 	}
1611 
1612 	// restircted network game
1613 	if ( gamerestricted_arg.found() ) {
1614 		Cmdline_restricted_game = 1;
1615 	}
1616 
1617 	// get the name of the network game
1618 	if ( gamename_arg.found() ) {
1619 		Cmdline_game_name = gamename_arg.str();
1620 
1621 		// be sure that this string fits in our limits
1622 		if ( strlen(Cmdline_game_name) >= MAX_GAMENAME_LEN ) {
1623 			Cmdline_game_name[MAX_GAMENAME_LEN-1] = '\0';
1624 		}
1625 	}
1626 
1627 	// get the password for a pssword game
1628 	if ( gamepassword_arg.found() ) {
1629 		Cmdline_game_password = gamepassword_arg.str();
1630 
1631 		// be sure that this string fits in our limits
1632 		if ( strlen(Cmdline_game_password) >= MAX_PASSWD_LEN ) {
1633 			ReleaseWarning(LOCATION, "Multi game password is longer than max of %d charaters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
1634 			Cmdline_game_password[MAX_PASSWD_LEN-1] = '\0';
1635 		}
1636 	}
1637 
1638 	// set the rank above/below arguments
1639 	if ( allowabove_arg.found() ) {
1640 		Cmdline_rank_above = allowabove_arg.str();
1641 	}
1642 	if ( allowbelow_arg.found() ) {
1643 		Cmdline_rank_below = allowbelow_arg.str();
1644 	}
1645 
1646 	// get the port number for games
1647 	if ( port_arg.found() ) {
1648 		Cmdline_network_port = port_arg.get_int();
1649 	}
1650 
1651 	// get IP address of gateway, for auto port forwarding
1652 	if ( gateway_ip_arg.found() ) {
1653 		Cmdline_gateway_ip = gateway_ip_arg.str();
1654 	}
1655 
1656 	// the connect argument specifies to join a game at this particular address
1657 	if ( connect_arg.found() ) {
1658 		Cmdline_use_last_pilot = 1;
1659 		Cmdline_connect_addr = connect_arg.str();
1660 	}
1661 
1662 	// see if the multilog flag was set
1663 	if ( multilog_arg.found() ){
1664 		Cmdline_multi_log = 1;
1665 	}
1666 
1667 	// spew pof info
1668 	if(pof_spew.found()){
1669 		Cmdline_spew_pof_info = 1;
1670 	}
1671 
1672 	// spew weapon stats
1673 	if (weapon_spew.found()) {
1674 		Cmdline_spew_weapon_stats = WeaponSpewType::STANDARD;
1675 
1676 		// currently just one argument
1677 		if (weapon_spew.has_param()) {
1678 			if (!stricmp(weapon_spew.str(), "all")) {
1679 				Cmdline_spew_weapon_stats = WeaponSpewType::ALL;
1680 			}
1681 		}
1682 	}
1683 
1684 	// mouse coords
1685 	if(mouse_coords.found()){
1686 		Cmdline_mouse_coords = 1;
1687 	}
1688 
1689 	// net timeout
1690 	if(timeout.found()){
1691 		Cmdline_timeout = timeout.get_int();
1692 	}
1693 
1694 	// d3d windowed
1695 	if(window_arg.found()) {
1696 		// We need to set both values since we don't know if we are going to use the new config system
1697 		options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "0");
1698 		Cmdline_window = 1;
1699 	}
1700 
1701 	if ( fullscreen_window_arg.found( ) )
1702 	{
1703 		options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "1");
1704 		Cmdline_fullscreen_window = 1;
1705 		Cmdline_window = 0; /* Make sure no-one sets both */
1706 	}
1707 
1708 	if(res_arg.found()){
1709 		Cmdline_res = res_arg.str();
1710 
1711 		int width = 0;
1712 		int height = 0;
1713 
1714 		if ( sscanf(Cmdline_res, "%dx%d", &width, &height) == 2 ) {
1715 			SCP_string override;
1716 			sprintf(override, "{\"width\":%d,\"height\":%d}", width, height);
1717 			options::OptionsManager::instance()->setOverride("Graphics.Resolution", override);
1718 		} else {
1719 			mprintf(("Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".\n", Cmdline_res));
1720 		}
1721 	}
1722 	if(center_res_arg.found()){
1723 		Cmdline_center_res = center_res_arg.str();
1724 	}
1725 	if(almission_arg.found()){//DTP for autoload mission // developer oritentated
1726 		Cmdline_almission = almission_arg.str();
1727 		Cmdline_use_last_pilot = 1;
1728 		Cmdline_start_netgame = 1;
1729 	}
1730 
1731 	if(dualscanlines_arg.found() ) {
1732 		Cmdline_dualscanlines = 1;
1733 	}
1734 
1735 	if(targetinfo_arg.found())
1736 	{
1737 		Cmdline_targetinfo = 1;
1738 	}
1739 
1740 	if(nomovies_arg.found() ) {
1741 		Cmdline_nomovies = 1;
1742 	}
1743 
1744 	if ( noscalevid_arg.found() ) {
1745 		Cmdline_noscalevid = 1;
1746 	}
1747 
1748 	if(noparseerrors_arg.found()) {
1749 		Cmdline_noparseerrors = 1;
1750 	}
1751 
1752 
1753 	if(mod_arg.found() ) {
1754 		Cmdline_mod = mod_arg.str();
1755 
1756 		// strip off blank space it it's there
1757 		if ( Cmdline_mod[strlen(Cmdline_mod)-1] == ' ' ) {
1758 			Cmdline_mod[strlen(Cmdline_mod)-1] = '\0';
1759 		}
1760 
1761 		// Ok - mod stacking support
1762 		size_t len = strlen(Cmdline_mod);
1763 		char *modlist = new char[len+2];
1764 		memset( modlist, 0, len + 2 );
1765 		strcpy_s(modlist, len+2, Cmdline_mod);
1766 
1767 #ifdef SCP_UNIX
1768 		// handle case-insensitive searching
1769 		handle_unix_modlist(&modlist, &len);
1770 #endif
1771 
1772 		// null terminate each individual
1773 		for (size_t i = 0; i < len; i++)
1774 		{
1775 			if (modlist[i] == ',')
1776 				modlist[i] = '\0';
1777 		}
1778 
1779 		//copy over - we don't have to delete[] Cmdline_mod because it's a pointer to an automatic global char*
1780 		Cmdline_mod = modlist;
1781 	}
1782 
1783 
1784 	if (fps_arg.found())
1785 	{
1786 		Show_framerate = 1;
1787 	}
1788 
1789 	if (bmpmanusage_arg.found())
1790 	{
1791 		Cmdline_bmpman_usage = 1;
1792 	}
1793 
1794 	if(pos_arg.found())
1795 	{
1796 		Cmdline_show_pos = 1;
1797 	}
1798 
1799 	if ( nomotiondebris_arg.found() ) {
1800 		Motion_debris_enabled = false;
1801 	}
1802 
1803 	if( mipmap_arg.found() ) {
1804 		Cmdline_mipmap = 1;
1805 	}
1806 
1807 	if( stats_arg.found() ) {
1808 		Cmdline_show_stats = 1;
1809 	}
1810 
1811 	if ( fov_arg.found() ) {
1812 		auto val = fov_arg.get_float();
1813 		if (val > 0.1) {
1814 			VIEWER_ZOOM_DEFAULT = val;
1815 		} else {
1816 			VIEWER_ZOOM_DEFAULT = 0.75f;
1817 		}
1818 	}
1819 
1820 	if( clip_dist_arg.found() ) {
1821 		Min_draw_distance = Cmdline_clip_dist = clip_dist_arg.get_float();
1822 	}
1823 
1824 	if (orb_radar.found())
1825 	{
1826 		Cmdline_orb_radar = 1;
1827 	}
1828 
1829 	if ( use_3dwarp.found() ) {
1830 		Fireball_use_3d_warp = true;
1831 	}
1832 
1833 	if ( use_warp_flash.found() ) {
1834 		Cmdline_warp_flash = 1;
1835 	}
1836 
1837 	if ( allow_autpilot_interrupt.found() )	{
1838 		Cmdline_autopilot_interruptable = 0;
1839 	}
1840 
1841 	if ( no_screenshake.found() ) {
1842 		Cmdline_no_screenshake = 1;
1843 	}
1844 
1845 	if ( stretch_menu.found() )	{
1846 		Cmdline_stretch_menu = 1;
1847 	}
1848 
1849 	// specular comand lines
1850 	if ( spec_point_arg.found() ) {
1851 		static_point_factor = spec_point_arg.get_float();
1852 	}
1853 
1854 	if ( spec_static_arg.found() ) {
1855 		static_light_factor = spec_static_arg.get_float();
1856 	}
1857 
1858 	if ( spec_tube_arg.found() ) {
1859 		static_tube_factor = spec_tube_arg.get_float();
1860 	}
1861 
1862 	if ( spec_arg.found() )
1863 	{
1864 		Cmdline_spec = 0;
1865 	}
1866 
1867 	if( no_set_gamma_arg.found() )
1868 	{
1869 		Cmdline_no_set_gamma = 1;
1870 	}
1871 
1872 	if(no_vsync_arg.found() )
1873 	{
1874 		Gr_enable_vsync = false;
1875 	}
1876 
1877 	if ( normal_arg.found() ) {
1878 		Cmdline_normal = 0;
1879 	}
1880 
1881 	if ( height_arg.found() ) {
1882 		Cmdline_height = 0;
1883 	}
1884 
1885 	if (post_process_aa_arg.found() || post_process_aa_preset_arg.found()) {
1886 		Gr_aa_mode = AntiAliasMode::SMAA_Low;
1887 
1888 		if (post_process_aa_preset_arg.found()) {
1889 			switch (post_process_aa_preset_arg.get_int()) {
1890 			case 0:
1891 				Gr_aa_mode = AntiAliasMode::FXAA_Low;
1892 				break;
1893 			case 1:
1894 				Gr_aa_mode = AntiAliasMode::FXAA_Medium;
1895 				break;
1896 			case 2:
1897 				Gr_aa_mode = AntiAliasMode::FXAA_High;
1898 				break;
1899 			case 3:
1900 				Gr_aa_mode = AntiAliasMode::SMAA_Low;
1901 				break;
1902 			case 4:
1903 				Gr_aa_mode = AntiAliasMode::SMAA_Medium;
1904 				break;
1905 			case 5:
1906 				Gr_aa_mode = AntiAliasMode::SMAA_High;
1907 				break;
1908 			case 6:
1909 				Gr_aa_mode = AntiAliasMode::SMAA_Ultra;
1910 				break;
1911 			}
1912 		}
1913 	}
1914 
1915 	if ( glow_arg.found() )
1916 		Cmdline_glow = 0;
1917 
1918 	if ( ship_choice_3d_arg.found() )
1919 		Cmdline_ship_choice_3d = 1;
1920 
1921 	if ( weapon_choice_3d_arg.found() )
1922 		Cmdline_weapon_choice_3d = 1;
1923 
1924 	if (ingamejoin_arg.found() )
1925 		Cmdline_ingamejoin = 1;
1926 
1927 	if ( start_mission_arg.found() ) {
1928 		Cmdline_start_mission = start_mission_arg.str();
1929 	}
1930 
1931 	if ( ambient_factor_arg.found() )
1932 		Cmdline_ambient_factor = ambient_factor_arg.get_int();
1933 
1934 	if ( output_scripting_arg.found() )
1935 		Output_scripting_meta = true;
1936 
1937 	if (output_script_json_arg.found() )
1938 		Output_scripting_json = true;
1939 
1940 	if (output_sexp_arg.found() ) {
1941 		Cmdline_output_sexp_info = true;
1942 	}
1943 
1944 	if ( no_pbo_arg.found() )
1945 	{
1946 		Cmdline_no_pbo = 1;
1947 	}
1948 
1949 	if ( no_drawrangeelements.found() )
1950 	{
1951 		Cmdline_drawelements = 1;
1952 	}
1953 
1954 	if( keyboard_layout.found())
1955 	{
1956 		Cmdline_keyboard_layout = keyboard_layout.str();
1957 	}
1958 
1959 	if (gl_finish.found())
1960 	{
1961 		Cmdline_gl_finish = true;
1962 	}
1963 
1964 	if ( no_geo_sdr_effects.found() )
1965 	{
1966 		Cmdline_no_geo_sdr_effects = true;
1967 	}
1968 
1969 	if (set_cpu_affinity.found())
1970 	{
1971 		Cmdline_set_cpu_affinity = true;
1972 	}
1973 
1974 	if (nograb_arg.found())
1975 	{
1976 		Cmdline_nograb = true;
1977 	}
1978 
1979 	if (noshadercache_arg.found())
1980 	{
1981 		Cmdline_noshadercache = true;
1982 	}
1983 
1984 	if (portable_mode.found())
1985 	{
1986 		Cmdline_portable_mode = true;
1987 	}
1988 
1989 #ifdef WIN32
1990 	if (fix_registry.found()) {
1991 		Cmdline_alternate_registry_path = true;
1992 	}
1993 #endif
1994 
1995 	if ( env.found() ) {
1996 		Cmdline_env = 0;
1997 	}
1998 
1999 	if ( ballistic_gauge.found() ) {
2000 		Cmdline_ballistic_gauge = 1;
2001 	}
2002 
2003 	if(dis_collisions.found())
2004 		Cmdline_dis_collisions = 1;
2005 
2006 	if(dis_weapons.found())
2007 		Cmdline_dis_weapons = 1;
2008 
2009 	if ( no_fbo_arg.found() ) {
2010 		Cmdline_no_fbo = 1;
2011 	}
2012 
2013 	if ( emissive_arg.found() ) {
2014 		Cmdline_emissive = 1;
2015 	}
2016 
2017 	if ( rearm_timer_arg.found() )
2018 		Cmdline_rearm_timer = 1;
2019 
2020 	if ( save_render_targets_arg.found() )
2021 		Cmdline_save_render_targets = 1;
2022 
2023 	if ( verify_vps_arg.found() )
2024 		Cmdline_verify_vps = 1;
2025 
2026 	if ( no3dsound_arg.found() )
2027 		Cmdline_no_3d_sound = 1;
2028 
2029     if ( atiswap_arg.found() )
2030     {
2031         Cmdline_ati_color_swap = 1;
2032     }
2033 
2034 	if ( enable_3d_shockwave_arg.found() )
2035 	{
2036 		Cmdline_enable_3d_shockwave = 1;
2037 	}
2038 
2039 	if ( softparticles_arg.found() )
2040 	{
2041 		Cmdline_softparticles = 1;
2042 	}
2043 
2044 	if ( fb_explosions_arg.found() )
2045 	{
2046 		Gr_framebuffer_effects.set(FramebufferEffects::Shockwaves, true);
2047 	}
2048 
2049     if (fb_thrusters_arg.found())
2050     {
2051 	    Gr_framebuffer_effects.set(FramebufferEffects::Thrusters, true);
2052     }
2053 
2054 	if ( no_postprocess_arg.found() )
2055 	{
2056 		Gr_post_processing_enabled = false;
2057 	}
2058 
2059 	if ( bloom_intensity_arg.found() )
2060 	{
2061 		Cmdline_bloom_intensity = bloom_intensity_arg.get_int();
2062 	}
2063 
2064 	if ( flightshaftsoff_arg.found() )
2065 	{
2066 		Cmdline_force_lightshaft_off = true;
2067 	}
2068 
2069 	if( reparse_mainhall_arg.found() )
2070 	{
2071 		Cmdline_reparse_mainhall = 1;
2072 	}
2073 
2074 	if( enable_shadows_arg.found() )
2075 	{
2076 		Shadow_quality = ShadowQuality::Medium;
2077 	}
2078 
2079 	if( shadow_quality_arg.found() )
2080 	{
2081 		switch (shadow_quality_arg.get_int()) {
2082 		case 0:
2083 			Shadow_quality = ShadowQuality::Disabled;
2084 			break;
2085 		case 1:
2086 			Shadow_quality = ShadowQuality::Low;
2087 			break;
2088 		case 2:
2089 			Shadow_quality = ShadowQuality::Medium;
2090 			break;
2091 		case 3:
2092 			Shadow_quality = ShadowQuality::High;
2093 			break;
2094 		case 4:
2095 			Shadow_quality = ShadowQuality::Ultra;
2096 			break;
2097 		default:
2098 			mprintf(("Invalid shadow quality %d. Disabling shadows...\n", shadow_quality_arg.get_int()));
2099 			Shadow_quality = ShadowQuality::Disabled;
2100 			break;
2101 		}
2102 	}
2103 
2104 	if( no_deferred_lighting_arg.found() )
2105 	{
2106 		Cmdline_no_deferred_lighting = 1;
2107 	}
2108 
2109 	if (anisotropy_level_arg.found())
2110 	{
2111 		Cmdline_aniso_level = anisotropy_level_arg.get_int();
2112 	}
2113 
2114 	if (frame_profile_write_file.found())
2115 	{
2116 		Cmdline_profile_write_file = true;
2117 	}
2118 
2119 	if (no_unfocused_pause_arg.found())
2120 	{
2121 		Cmdline_no_unfocus_pause = true;
2122 	}
2123 
2124 	if (benchmark_mode_arg.found())
2125 	{
2126 		Cmdline_benchmark_mode = true;
2127 	}
2128 
2129 	if (pilot_arg.found())
2130 	{
2131 		Cmdline_pilot = pilot_arg.str();
2132 	}
2133 
2134 	if (noninteractive_arg.found())
2135 	{
2136 		Cmdline_noninteractive = true;
2137 	}
2138 
2139 	if (json_profiling.found())
2140 	{
2141 		Cmdline_json_profiling = true;
2142 	}
2143 
2144 	if (frame_profile_arg.found() )
2145 	{
2146 		Cmdline_frame_profile = true;
2147 	}
2148 
2149 	if (debug_window_arg.found()) {
2150 		Cmdline_debug_window = true;
2151 	}
2152 
2153 	if (graphics_debug_output_arg.found()) {
2154 		Cmdline_graphics_debug_output = true;
2155 	}
2156 
2157 	if (log_to_stdout_arg.found()) {
2158 		Cmdline_log_to_stdout = true;
2159 	}
2160 
2161 	if (show_video_info.found())
2162 	{
2163 		Cmdline_show_video_info = true;
2164 	}
2165 
2166 	//Deprecated flags - CommanderDJ
2167 	if( deprecated_spec_arg.found() )
2168 	{
2169 		Cmdline_deprecated_spec = 1;
2170 	}
2171 
2172 	if( deprecated_glow_arg.found() )
2173 	{
2174 		Cmdline_deprecated_glow = 1;
2175 	}
2176 
2177 	if( deprecated_normal_arg.found() )
2178 	{
2179 		Cmdline_deprecated_normal = 1;
2180 	}
2181 
2182 	if( deprecated_env_arg.found() )
2183 	{
2184 		Cmdline_deprecated_env = 1;
2185 	}
2186 
2187 	if( deprecated_tbp_arg.found() )
2188 	{
2189 		Cmdline_deprecated_tbp = 1;
2190 	}
2191 
2192 	if( deprecated_jpgtga_arg.found() )
2193 	{
2194 		Cmdline_deprecated_jpgtga = 1;
2195 	}
2196 
2197 	if ( deprecated_htl_arg.found() )
2198 	{
2199 		Cmdline_deprecated_nohtl = 1;
2200 	}
2201 
2202 	if ( deprecated_brieflighting_arg.found() )
2203 	{
2204 		Cmdline_deprecated_brief_lighting = 1;
2205 	}
2206 
2207 	if (deprecated_missile_lighting_arg.found())
2208 	{
2209 		Cmdline_deprecated_missile_lighting = true;
2210 	}
2211 
2212 	if (deprecated_cache_bitmaps_arg.found()) {
2213 		Cmdline_deprecated_cache_bitmaps = true;
2214 	}
2215 
2216 	if (deprecated_no_emissive_arg.found()) {
2217 		Cmdline_emissive = 0;
2218 	}
2219 
2220 	if (deprecated_postprocess_arg.found()) {
2221 		Cmdline_deprecated_postprocess = true;
2222 	}
2223 
2224 	if (deprecated_fxaa_arg.found() ) {
2225 		Gr_aa_mode = AntiAliasMode::FXAA_Medium;
2226 
2227 		if (deprecated_fxaa_preset_arg.found()) {
2228 			auto val = deprecated_fxaa_preset_arg.get_int();
2229 			if (val > 6) {
2230 				Gr_aa_mode = AntiAliasMode::FXAA_High;
2231 			} else if (val > 3) {
2232 				Gr_aa_mode = AntiAliasMode::FXAA_Medium;
2233 			} else {
2234 				Gr_aa_mode = AntiAliasMode::FXAA_Low;
2235 			}
2236 		}
2237 	}
2238 
2239 	if (deprecated_smaa_arg.found()) {
2240 		Gr_aa_mode = AntiAliasMode::SMAA_Medium;
2241 
2242 		if (deprecated_smaa_preset_arg.found()) {
2243 			switch (deprecated_smaa_preset_arg.get_int()) {
2244 			case 0:
2245 				Gr_aa_mode = AntiAliasMode::SMAA_Low;
2246 				break;
2247 			case 1:
2248 				Gr_aa_mode = AntiAliasMode::SMAA_Medium;
2249 				break;
2250 			case 2:
2251 				Gr_aa_mode = AntiAliasMode::SMAA_High;
2252 				break;
2253 			case 3:
2254 				Gr_aa_mode = AntiAliasMode::SMAA_Ultra;
2255 				break;
2256 			default:
2257 				Gr_aa_mode = AntiAliasMode::SMAA_Ultra;
2258 				break;
2259 			}
2260 		}
2261 	}
2262 
2263 	return true;
2264 }
2265 
parse_cmdline(int argc,char * argv[])2266 int parse_cmdline(int argc, char *argv[])
2267 {
2268 //	mprintf(("I got to parse_cmdline()!!\n"));
2269 
2270 	os_init_cmdline(argc, argv);
2271 
2272 	// --------------- Kazan -------------
2273 	// If you're looking for the list of if (someparam.found()) { cmdline_someparam = something; } look above at this function
2274 	// I did this because of fred2_parse_cmdline()
2275 	return SetCmdlineParams();
2276 }
2277 
get_param_desc(const char * flag_name)2278 const char * get_param_desc(const char *flag_name)
2279 {
2280 	int i;
2281 	int flag_size = sizeof(Flag);
2282 	int num_flags = sizeof(exe_params) / flag_size;
2283 	for (i = 0; i < num_flags; ++i) {
2284 		if (!strcmp(flag_name, exe_params[i].name)) {
2285 			return exe_params[i].desc;
2286 		}
2287 	}
2288 	return "UNKNOWN - FIXME!";
2289 }
2290