1// SuperTux
2// Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "supertux/command_line_arguments.hpp"
18
19#include <boost/format.hpp>
20#include <config.h>
21#include <physfs.h>
22
23#include "supertux/gameconfig.hpp"
24#include "util/gettext.hpp"
25#include "version.h"
26
27CommandLineArguments::CommandLineArguments() :
28 m_action(NO_ACTION),
29 m_log_level(LOG_WARNING),
30 datadir(),
31 userdir(),
32 fullscreen_size(),
33 fullscreen_refresh_rate(),
34 window_size(),
35 aspect_size(),
36 use_fullscreen(),
37 video(),
38 show_fps(),
39 show_player_pos(),
40 sound_enabled(),
41 music_enabled(),
42 filenames(),
43 enable_script_debugger(),
44 start_demo(),
45 record_demo(),
46 tux_spawn_pos(),
47 sector(),
48 spawnpoint(),
49 developer_mode(),
50 christmas_mode(),
51 repository_url(),
52 editor(),
53 resave()
54{
55}
56
57void
58CommandLineArguments::print_datadir() const
59{
60 // Print the datadir searchpath to stdout, one path per
61 // line. Then exit. Intended for use by the supertux-editor.
62 char **sp;
63 sp = PHYSFS_getSearchPath();
64 if (sp)
65 for (size_t sp_index = 0; sp[sp_index]; sp_index++)
66 std::cout << sp[sp_index] << std::endl;
67 PHYSFS_freeList(sp);
68}
69
70void
71CommandLineArguments::print_help(const char* arg0) const
72{
73 std::cerr
74 << boost::format(_("Usage: %s [OPTIONS] [LEVELFILE]")) % arg0 << "\n" << "\n"
75 << _("General Options:") << "\n"
76 << _(" -h, --help Show this help message and quit") << "\n"
77 << _(" -v, --version Show SuperTux version and quit") << "\n"
78 << _(" --verbose Print verbose messages") << "\n"
79 << _(" --debug Print extra verbose messages") << "\n"
80 << _( " --print-datadir Print SuperTux's primary data directory.") << "\n"
81 << "\n"
82 << _("Video Options:") << "\n"
83 << _(" -f, --fullscreen Run in fullscreen mode") << "\n"
84 << _(" -w, --window Run in window mode") << "\n"
85 << _(" -g, --geometry WIDTHxHEIGHT Run SuperTux in given resolution") << "\n"
86 << _(" -a, --aspect WIDTH:HEIGHT Run SuperTux with given aspect ratio") << "\n"
87 << _(" -d, --default Reset video settings to default values") << "\n"
88 << _(" --renderer RENDERER Use sdl, opengl, or auto to render") << "\n"
89 << "\n"
90 << _("Audio Options:") << "\n"
91 << _(" --disable-sound Disable sound effects") << "\n"
92 << _(" --disable-music Disable music") << "\n"
93 << "\n"
94 << _("Game Options:") << "\n"
95 << _(" --edit-level Open given level in editor") << "\n"
96 << _(" --resave Loads given level and saves it") << "\n"
97 << _(" --show-fps Display framerate in levels") << "\n"
98 << _(" --no-show-fps Do not display framerate in levels") << "\n"
99 << _(" --show-pos Display player's current position") << "\n"
100 << _(" --no-show-pos Do not display player's position") << "\n"
101 << _(" --developer Switch on developer feature") << "\n"
102 << _(" -s, --debug-scripts Enable script debugger.") << "\n"
103 << _(" --spawn-pos X,Y Where in the level to spawn Tux. Only used if level is specified.") << "\n"
104 << _(" --sector SECTOR Spawn Tux in SECTOR\n") << "\n"
105 << _(" --spawnpoint SPAWNPOINT Spawn Tux at SPAWNPOINT\n") << "\n"
106 << "\n"
107 << _("Demo Recording Options:") << "\n"
108 << _(" --record-demo FILE LEVEL Record a demo to FILE") << "\n"
109 << _(" --play-demo FILE LEVEL Play a recorded demo") << "\n"
110 << "\n"
111 << _("Directory Options:") << "\n"
112 << _(" --datadir DIR Set the directory for the games datafiles") << "\n"
113 << _(" --userdir DIR Set the directory for user data (savegames, etc.)") << "\n"
114 << "\n"
115 << _("Add-On Options:") << "\n"
116 << _(" --repository-url URL Set the URL to the Add-On repository") << "\n"
117 << "\n"
118 << _("Environment variables:") << "\n"
119 << _(" SUPERTUX2_USER_DIR Directory for user data (savegames, etc.)" ) << "\n"
120 << _(" SUPERTUX2_DATA_DIR Directory for the games datafiles" ) << "\n"
121 << "\n"
122 << std::flush;
123}
124
125void
126CommandLineArguments::print_version() const
127{
128 std::cout << PACKAGE_NAME << " " << PACKAGE_VERSION << std::endl;
129}
130
131void
132CommandLineArguments::parse_args(int argc, char** argv)
133{
134 for (int i = 1; i < argc; ++i)
135 {
136 std::string arg = argv[i];
137
138 if (arg == "--version" || arg == "-v")
139 {
140 m_action = PRINT_VERSION;
141
142 }
143 else if (arg == "--help" || arg == "-h")
144 {
145 m_action = PRINT_HELP;
146 }
147 else if (arg == "--print-datadir")
148 {
149 m_action = PRINT_DATADIR;
150 }
151 else if (arg == "--debug")
152 {
153 m_log_level = LOG_DEBUG;
154 }
155 else if (arg == "--verbose")
156 {
157 if (m_log_level < LOG_INFO)
158 {
159 m_log_level = LOG_INFO;
160 }
161 }
162 else if (arg == "--datadir")
163 {
164 if (i + 1 >= argc)
165 {
166 throw std::runtime_error("Need to specify a directory for --datadir");
167 }
168 else
169 {
170 datadir = argv[++i];
171 }
172 }
173 else if (arg == "--userdir")
174 {
175 if (i + 1 >= argc)
176 {
177 throw std::runtime_error("Need to specify a directory for --userdir");
178 }
179 else
180 {
181 userdir = argv[++i];
182 }
183 }
184 else if (arg == "--fullscreen" || arg == "-f")
185 {
186 use_fullscreen = true;
187 }
188 else if (arg == "--default" || arg == "-d")
189 {
190 use_fullscreen = false;
191
192 window_size = Size(1280, 800);
193 fullscreen_size = Size(1280, 800);
194 fullscreen_refresh_rate = 0;
195 aspect_size = Size(0, 0); // auto detect
196 }
197 else if (arg == "--window" || arg == "-w")
198 {
199 use_fullscreen = false;
200 }
201 else if (arg == "--geometry" || arg == "-g")
202 {
203 i += 1;
204 if (i >= argc)
205 {
206 throw std::runtime_error("Need to specify a size (WIDTHxHEIGHT) for geometry argument");
207 }
208 else
209 {
210 int width, height;
211 if (sscanf(argv[i], "%9dx%9d", &width, &height) != 2)
212 {
213 throw std::runtime_error("Invalid geometry spec, should be WIDTHxHEIGHT");
214 }
215 else
216 {
217 window_size = Size(width, height);
218 fullscreen_size = Size(width, height);
219 fullscreen_refresh_rate = 0;
220 }
221 }
222 }
223 else if (arg == "--aspect" || arg == "-a")
224 {
225 i += 1;
226 if (i >= argc)
227 {
228 throw std::runtime_error("Need to specify a ratio (WIDTH:HEIGHT) for aspect ratio");
229 }
230 else
231 {
232 int aspect_width = 0;
233 int aspect_height = 0;
234 if (strcmp(argv[i], "auto") == 0)
235 {
236 aspect_width = 0;
237 aspect_height = 0;
238 }
239 else if (sscanf(argv[i], "%9d:%9d", &aspect_width, &aspect_height) != 2)
240 {
241 throw std::runtime_error("Invalid aspect spec, should be WIDTH:HEIGHT or auto");
242 }
243 else
244 {
245 // use aspect ratio to calculate logical resolution
246 if (aspect_width / aspect_height > 1) {
247 aspect_size = Size(600 * aspect_width / aspect_height, 600);
248 } else {
249 aspect_size = Size(600, 600 * aspect_height / aspect_width);
250 }
251 }
252 }
253 }
254 else if (arg == "--renderer")
255 {
256 i += 1;
257 if (i >= argc)
258 {
259 throw std::runtime_error("Need to specify a renderer for renderer argument");
260 }
261 else
262 {
263 video = VideoSystem::get_video_system(argv[i]);
264 }
265 }
266 else if (arg == "--show-fps")
267 {
268 show_fps = true;
269 }
270 else if (arg == "--no-show-fps")
271 {
272 show_fps = false;
273 }
274 else if (arg == "--show-pos")
275 {
276 show_player_pos = true;
277 }
278 else if (arg == "--no-show-pos")
279 {
280 show_player_pos = false;
281 }
282 else if (arg == "--developer")
283 {
284 developer_mode = true;
285 }
286 else if (arg == "--christmas")
287 {
288 christmas_mode = true;
289 }
290 else if (arg == "--no-christmas")
291 {
292 christmas_mode = false;
293 }
294 else if (arg == "--disable-sound" || arg == "--disable-sfx")
295 {
296 sound_enabled = false;
297 }
298 else if (arg == "--disable-music")
299 {
300 music_enabled = false;
301 }
302 else if (arg == "--play-demo")
303 {
304 if (i + 1 >= argc)
305 {
306 throw std::runtime_error("Need to specify a demo filename");
307 }
308 else
309 {
310 start_demo = argv[++i];
311 }
312 }
313 else if (arg == "--record-demo")
314 {
315 if (i + 1 >= argc)
316 {
317 throw std::runtime_error("Need to specify a demo filename");
318 }
319 else
320 {
321 record_demo = argv[++i];
322 }
323 }
324 else if (arg == "--spawn-pos")
325 {
326 Vector spawn_pos;
327
328 if (++i >= argc)
329 throw std::runtime_error("Need to specify a spawn-pos X,Y");
330 else
331 {
332 int x, y;
333 if (sscanf(argv[i], "%9d,%9d", &x, &y) != 2)
334 throw std::runtime_error("Invalid spawn-pos, should be X,Y");
335 spawn_pos.x = static_cast<float>(x);
336 spawn_pos.y = static_cast<float>(y);
337 }
338
339 tux_spawn_pos = spawn_pos;
340 }
341 else if (arg == "--sector") {
342 if (++i >= argc) {
343 throw std::runtime_error("--sector SECTOR needs an argument");
344 } else {
345 sector = argv[i];
346 }
347 }
348 else if (arg == "--spawnpoint") {
349 if (++i >= argc) {
350 throw std::runtime_error("--spawnpoint SPAWNPOINT needs an argument");
351 } else {
352 spawnpoint = argv[i];
353 }
354 }
355 else if (arg == "--debug-scripts" || arg == "-s")
356 {
357 enable_script_debugger = true;
358 }
359 else if (arg == "--repository-url")
360 {
361 if (i + 1 >= argc)
362 {
363 throw std::runtime_error("Need to specify a repository URL");
364 }
365 else
366 {
367 repository_url = argv[++i];
368 }
369 }
370 else if (arg == "--editor" || arg == "--edit-level")
371 {
372 editor = true;
373 }
374 else if (arg == "--resave")
375 {
376 resave = true;
377 }
378 else if (arg[0] != '-')
379 {
380 filenames.push_back(arg);
381 }
382 else
383 {
384 throw std::runtime_error((boost::format("Unknown option '%1%''. Use --help to see a list of options") % arg).str());
385 }
386 }
387
388 // some final checks
389 if (filenames.size() > 1 && !(resave && *resave)) {
390 throw std::runtime_error("Only one filename allowed for the given options");
391 }
392}
393
394void
395CommandLineArguments::merge_into(Config& config)
396{
397#define merge_option(x) if (x) { config.x = *(x); }
398
399 merge_option(fullscreen_size);
400 merge_option(fullscreen_refresh_rate);
401 merge_option(window_size);
402 merge_option(aspect_size);
403 merge_option(use_fullscreen);
404 merge_option(video);
405 merge_option(show_fps);
406 merge_option(show_player_pos);
407 merge_option(sound_enabled);
408 merge_option(music_enabled);
409 merge_option(enable_script_debugger);
410 merge_option(start_demo);
411 merge_option(record_demo);
412 merge_option(tux_spawn_pos);
413 merge_option(developer_mode);
414 merge_option(christmas_mode);
415 merge_option(repository_url);
416
417#undef merge_option
418}
419
420/* EOF */
421