File not being closed.
[supertux.git] / lib / app / setup.cpp
1 //  $Id$
2 //
3 //  SuperTux -  A Jump'n Run
4 //  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #include <cassert>
21 #include <cstdio>
22 #include <iostream>
23 #include <cstdio>
24 #include <cstdlib>
25 #include <cstring>
26 #include <cerrno>
27 #include <unistd.h>
28
29 #include "SDL.h"
30 #include "SDL_image.h"
31 #ifndef NOOPENGL
32 #include "SDL_opengl.h"
33 #endif
34
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <dirent.h>
38 #ifndef WIN32
39 #include <libgen.h>
40 #endif
41
42 #include <cctype>
43
44 #include "../app/globals.h"
45 #include "../app/setup.h"
46 #include "../video/screen.h"
47 #include "../video/surface.h"
48 #include "../gui/menu.h"
49 #include "../utils/configfile.h"
50 #include "../audio/sound_manager.h"
51 #include "../app/gettext.h"
52
53 using namespace SuperTux;
54
55 #ifdef WIN32
56 #define mkdir(dir, mode)    mkdir(dir)
57 // on win32 we typically don't want LFS paths
58 #undef DATA_PREFIX
59 #define DATA_PREFIX "./data/"
60 #endif
61
62 /* Local function prototypes: */
63
64 void seticon(void);
65 void usage(char * prog, int ret);
66
67 /* Does the given file exist and is it accessible? */
68 int FileSystem::faccessible(const std::string& filename)
69 {
70   struct stat filestat;
71   if (stat(filename.c_str(), &filestat) == -1)
72     {
73       return false;
74     }
75   else
76     {
77       if(S_ISREG(filestat.st_mode))
78         return true;
79       else
80         return false;
81     }
82 }
83
84 /* Can we write to this location? */
85 int FileSystem::fwriteable(const std::string& filename)
86 {
87   FILE* fi;
88   fi = fopen(filename.c_str(), "wa");
89   if (fi == NULL)
90     {
91       return false;
92     }
93   fclose(fi);
94   return true;
95 }
96
97 /* Makes sure a directory is created in either the SuperTux home directory or the SuperTux base directory.*/
98 int FileSystem::fcreatedir(const std::string& relative_dir)
99 {
100   std::string path = st_dir + "/" + relative_dir + "/";
101   if(mkdir(path.c_str(),0755) != 0)
102     {
103       path = datadir + "/" + relative_dir + "/";
104       if(mkdir(path.c_str(),0755) != 0)
105         {
106           return false;
107         }
108       else
109         {
110           return true;
111         }
112     }
113   else
114     {
115       return true;
116     }
117 }
118
119 /* Get all names of sub-directories in a certain directory. */
120 /* Returns the number of sub-directories found. */
121 /* Note: The user has to free the allocated space. */
122 std::set<std::string> FileSystem::dsubdirs(const std::string &rel_path,const  std::string& expected_file)
123 {
124   DIR *dirStructP;
125   struct dirent *direntp;
126   std::set<std::string> sdirs;
127   std::string filename;
128   std::string path = st_dir + "/" + rel_path;
129
130   if((dirStructP = opendir(path.c_str())) != NULL)
131     {
132       while((direntp = readdir(dirStructP)) != NULL)
133         {
134           std::string absolute_filename;
135           struct stat buf;
136
137           absolute_filename = path + "/" + direntp->d_name;
138
139           if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode))
140             {
141               if(!expected_file.empty())
142                 {
143                   filename = path + "/" + direntp->d_name + "/" + expected_file;
144                   if(!faccessible(filename))
145                     continue;
146                 }
147
148               sdirs.insert(direntp->d_name);
149             }
150         }
151       closedir(dirStructP);
152     }
153
154   path = datadir + "/" + rel_path;
155   if((dirStructP = opendir(path.c_str())) != NULL)
156     {
157       while((direntp = readdir(dirStructP)) != NULL)
158         {
159           std::string absolute_filename;
160           struct stat buf;
161
162           absolute_filename = path + "/" + direntp->d_name;
163
164           if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode))
165             {
166               if(!expected_file.empty())
167                 {
168                   filename = path + "/" + direntp->d_name + "/" + expected_file;
169                   if(!faccessible(filename.c_str()))
170                     {
171                       continue;
172                     }
173                   else
174                     {
175                       filename = st_dir + "/" + rel_path + "/" + direntp->d_name + "/" + expected_file;
176                       if(faccessible(filename.c_str()))
177                         continue;
178                     }
179                 }
180
181               sdirs.insert(direntp->d_name);
182             }
183         }
184       closedir(dirStructP);
185     }
186
187   return sdirs;
188 }
189
190 std::set<std::string> FileSystem::dfiles(const std::string& rel_path, const  std::string& glob, const  std::string& exception_str)
191 {
192   DIR *dirStructP;
193   struct dirent *direntp;
194   std::set<std::string> sdirs;
195   std::string path = st_dir + "/" + rel_path;
196
197   if((dirStructP = opendir(path.c_str())) != NULL)
198     {
199       while((direntp = readdir(dirStructP)) != NULL)
200         {
201           std::string absolute_filename;
202           struct stat buf;
203
204           absolute_filename = path + "/" + direntp->d_name;
205
206           if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode))
207             {
208               if(!exception_str.empty())
209                 {
210                   if(strstr(direntp->d_name,exception_str.c_str()) != NULL)
211                     continue;
212                 }
213               if(!glob.empty())
214                 if(strstr(direntp->d_name,glob.c_str()) == NULL)
215                   continue;
216
217               sdirs.insert(direntp->d_name);
218             }
219         }
220       closedir(dirStructP);
221     }
222
223   path = datadir + "/" + rel_path;
224   if((dirStructP = opendir(path.c_str())) != NULL)
225     {
226       while((direntp = readdir(dirStructP)) != NULL)
227         {
228           std::string absolute_filename;
229           struct stat buf;
230
231           absolute_filename = path + "/" + direntp->d_name;
232
233           if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode))
234             {
235               if(!exception_str.empty())
236                 {
237                   if(strstr(direntp->d_name,exception_str.c_str()) != NULL)
238                     continue;
239                 }
240               if(!glob.empty())
241                 if(strstr(direntp->d_name,glob.c_str()) == NULL)
242                   continue;
243
244               sdirs.insert(direntp->d_name);
245             }
246         }
247       closedir(dirStructP);
248     }
249
250   return sdirs;
251 }
252
253 void Setup::info(const std::string& _package_name, const std::string& _package_symbol_name, const std::string& _package_version)
254 {
255 package_name = _package_name;
256 package_symbol_name = _package_symbol_name;
257 package_version = _package_version;
258 }
259
260 /* --- SETUP --- */
261 /* Set SuperTux configuration and save directories */
262 void Setup::directories(void)
263 {
264   std::string home;
265   /* Get home directory (from $HOME variable)... if we can't determine it,
266      use the current directory ("."): */
267   if (getenv("HOME") != NULL)
268     home = getenv("HOME");
269   else
270     home = ".";
271
272   st_dir = home + "/." + package_symbol_name;
273
274   /* Remove .supertux config-file from old SuperTux versions */
275   if(FileSystem::faccessible(st_dir))
276     {
277       remove(st_dir.c_str());
278     }
279
280   st_save_dir = st_dir + "/save";
281
282   /* Create them. In the case they exist they won't destroy anything. */
283   mkdir(st_dir.c_str(), 0755);
284   mkdir(st_save_dir.c_str(), 0755);
285
286   mkdir((st_dir + "/levels").c_str(), 0755);
287
288   // User has not that a datadir, so we try some magic
289   if (datadir.empty())
290     {
291 #ifndef WIN32
292       // Detect datadir
293       char exe_file[PATH_MAX];
294       if (readlink("/proc/self/exe", exe_file, PATH_MAX) < 0)
295         {
296           puts("Couldn't read /proc/self/exe, using default path: " DATA_PREFIX);
297           datadir = DATA_PREFIX;
298         }
299       else
300         {
301           std::string exedir = std::string(dirname(exe_file)) + "/";
302           
303           datadir = exedir + "../data"; // SuperTux run from source dir
304           if (access(datadir.c_str(), F_OK) != 0)
305             {
306               datadir = exedir + "../../data";  //SuperTux run from source dir (with libtool script)
307               
308               if (access(datadir.c_str(), F_OK) != 0)
309               {
310               datadir = exedir + "../share/" + package_symbol_name; // SuperTux run from PATH
311               if (access(datadir.c_str(), F_OK) != 0) 
312                 { // If all fails, fall back to compiled path
313                   datadir = DATA_PREFIX; 
314                 }
315               }
316             }
317         }
318 #else
319   datadir = DATA_PREFIX;
320 #endif
321     }
322   printf("Datadir: %s\n", datadir.c_str());
323 }
324
325 void Setup::general(void)
326 {
327   /* Seed random number generator: */
328
329   srand(SDL_GetTicks());
330
331   /* Set icon image: */
332
333   seticon();
334
335   /* Unicode needed for input handling: */
336
337   SDL_EnableUNICODE(1);
338
339   /* Load GUI/menu images: */
340   checkbox = new Surface(datadir + "/images/status/checkbox.png", true);
341   checkbox_checked = new Surface(datadir + "/images/status/checkbox-checked.png", true);
342   back = new Surface(datadir + "/images/status/back.png", true);
343   arrow_left = new Surface(datadir + "/images/icons/left.png", true);
344   arrow_right = new Surface(datadir + "/images/icons/right.png", true);
345
346   /* Load the mouse-cursor */
347   mouse_cursor = new MouseCursor( datadir + "/images/status/mousecursor.png",1);
348   MouseCursor::set_current(mouse_cursor);
349   
350 }
351
352 void Setup::general_free(void)
353 {
354
355   /* Free GUI/menu images: */
356   delete checkbox;
357   delete checkbox_checked;
358   delete back;
359   delete arrow_left;
360   delete arrow_right;
361
362   /* Free mouse-cursor */
363   delete mouse_cursor;
364   
365 }
366
367 void Setup::video(unsigned int screen_w, unsigned int screen_h)
368 {
369   /* Init SDL Video: */
370   if (SDL_Init(SDL_INIT_VIDEO) < 0)
371     {
372       fprintf(stderr,
373               "\nError: I could not initialize video!\n"
374               "The Simple DirectMedia error that occured was:\n"
375               "%s\n\n", SDL_GetError());
376       exit(1);
377     }
378
379   /* Open display: */
380   if(use_gl)
381     video_gl(screen_w, screen_h);
382   else
383     video_sdl(screen_w, screen_h);
384
385   Surface::reload_all();
386
387   /* Set window manager stuff: */
388   SDL_WM_SetCaption((package_name + " " + package_version).c_str(), package_name.c_str());
389 }
390
391 void Setup::video_sdl(unsigned int screen_w, unsigned int screen_h)
392 {
393   if (use_fullscreen)
394     {
395       screen = SDL_SetVideoMode(screen_w, screen_h, 0, SDL_FULLSCREEN ) ; /* | SDL_HWSURFACE); */
396       if (screen == NULL)
397         {
398           fprintf(stderr,
399                   "\nWarning: I could not set up fullscreen video for "
400                   "800x600 mode.\n"
401                   "The Simple DirectMedia error that occured was:\n"
402                   "%s\n\n", SDL_GetError());
403           use_fullscreen = false;
404         }
405     }
406   else
407     {
408       screen = SDL_SetVideoMode(screen_w, screen_h, 0, SDL_HWSURFACE | SDL_DOUBLEBUF );
409
410       if (screen == NULL)
411         {
412           fprintf(stderr,
413                   "\nError: I could not set up video for 800x600 mode.\n"
414                   "The Simple DirectMedia error that occured was:\n"
415                   "%s\n\n", SDL_GetError());
416           exit(1);
417         }
418     }
419 }
420
421 void Setup::video_gl(unsigned int screen_w, unsigned int screen_h)
422 {
423 #ifndef NOOPENGL
424
425   SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
426   SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
427   SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
428   SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
429   SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
430
431   if (use_fullscreen)
432     {
433       screen = SDL_SetVideoMode(screen_w, screen_h, 0, SDL_FULLSCREEN | SDL_OPENGL) ; /* | SDL_HWSURFACE); */
434       if (screen == NULL)
435         {
436           fprintf(stderr,
437                   "\nWarning: I could not set up fullscreen video for "
438                   "640x480 mode.\n"
439                   "The Simple DirectMedia error that occured was:\n"
440                   "%s\n\n", SDL_GetError());
441           use_fullscreen = false;
442         }
443     }
444   else
445     {
446       screen = SDL_SetVideoMode(screen_w, screen_h, 0, SDL_OPENGL);
447
448       if (screen == NULL)
449         {
450           fprintf(stderr,
451                   "\nError: I could not set up video for 640x480 mode.\n"
452                   "The Simple DirectMedia error that occured was:\n"
453                   "%s\n\n", SDL_GetError());
454           exit(1);
455         }
456     }
457
458   /*
459    * Set up OpenGL for 2D rendering.
460    */
461   glDisable(GL_DEPTH_TEST);
462   glDisable(GL_CULL_FACE);
463
464   glViewport(0, 0, screen->w, screen->h);
465   glMatrixMode(GL_PROJECTION);
466   glLoadIdentity();
467   glOrtho(0, screen->w, screen->h, 0, -1.0, 1.0);
468
469   glMatrixMode(GL_MODELVIEW);
470   glLoadIdentity();
471   glTranslatef(0.0f, 0.0f, 0.0f);
472
473 #endif
474
475 }
476
477 void Setup::joystick(void)
478 {
479
480   /* Init Joystick: */
481
482   use_joystick = true;
483
484   if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
485     {
486       fprintf(stderr, "Warning: I could not initialize joystick!\n"
487               "The Simple DirectMedia error that occured was:\n"
488               "%s\n\n", SDL_GetError());
489
490       use_joystick = false;
491     }
492   else
493     {
494       /* Open joystick: */
495       if (SDL_NumJoysticks() <= 0)
496         {
497           fprintf(stderr, "Info: No joysticks were found.\n");
498
499           use_joystick = false;
500         }
501       else
502         {
503           js = SDL_JoystickOpen(joystick_num);
504
505           if (js == NULL)
506             {
507               fprintf(stderr, "Warning: Could not open joystick %d.\n"
508                       "The Simple DirectMedia error that occured was:\n"
509                       "%s\n\n", joystick_num, SDL_GetError());
510
511               use_joystick = false;
512             }
513           else
514             {
515               if (SDL_JoystickNumAxes(js) < 2)
516                 {
517                   fprintf(stderr,
518                           "Warning: Joystick does not have enough axes!\n");
519
520                   use_joystick = false;
521                 }
522               else
523                 {
524                   if (SDL_JoystickNumButtons(js) < 2)
525                     {
526                       fprintf(stderr,
527                               "Warning: "
528                               "Joystick does not have enough buttons!\n");
529
530                       use_joystick = false;
531                     }
532                 }
533             }
534         }
535     }
536 }
537
538 void Setup::audio(void)
539 {
540
541   /* Init SDL Audio silently even if --disable-sound : */
542
543   if (SoundManager::get()->audio_device_available())
544     {
545       if (SDL_Init(SDL_INIT_AUDIO) < 0)
546         {
547           /* only print out message if sound or music
548              was not disabled at command-line
549            */
550           if (SoundManager::get()->sound_enabled() || SoundManager::get()->music_enabled())
551             {
552               fprintf(stderr,
553                       "\nWarning: I could not initialize audio!\n"
554                       "The Simple DirectMedia error that occured was:\n"
555                       "%s\n\n", SDL_GetError());
556             }
557           /* keep the programming logic the same :-)
558              because in this case, use_sound & use_music' values are ignored
559              when there's no available audio device
560           */
561           SoundManager::get()->enable_sound(false);
562           SoundManager::get()->enable_music(false);
563           SoundManager::get()->set_audio_device_available(false);
564         }
565     }
566
567
568   /* Open sound silently regarless the value of "use_sound": */
569
570   if (SoundManager::get()->audio_device_available())
571     {
572       if (SoundManager::get()->open_audio(44100, AUDIO_S16, 2, 2048) < 0)
573         {
574           /* only print out message if sound or music
575              was not disabled at command-line
576            */
577           if (SoundManager::get()->sound_enabled() || SoundManager::get()->music_enabled())
578             {
579               fprintf(stderr,
580                       "\nWarning: I could not set up audio for 44100 Hz "
581                       "16-bit stereo.\n"
582                       "The Simple DirectMedia error that occured was:\n"
583                       "%s\n\n", SDL_GetError());
584             }
585           SoundManager::get()->enable_sound(false);
586           SoundManager::get()->enable_music(false);
587           SoundManager::get()->set_audio_device_available(false);
588         }
589     }
590
591 }
592
593
594 /* --- SHUTDOWN --- */
595
596 void Termination::shutdown(void)
597 {
598   config->save();
599   SoundManager::get()->close_audio();
600   SDL_Quit();
601 }
602
603 /* --- ABORT! --- */
604
605 void Termination::abort(const std::string& reason, const std::string& details)
606 {
607   fprintf(stderr, "\nError: %s\n%s\n\n", reason.c_str(), details.c_str());
608   shutdown();
609   ::abort();
610 }
611
612 /* Set Icon (private) */
613
614 void seticon(void)
615 {
616 //  int masklen;
617 //  Uint8 * mask;
618   SDL_Surface * icon;
619
620
621   /* Load icon into a surface: */
622
623   icon = IMG_Load((datadir + "/images/" + package_symbol_name + ".xpm").c_str());
624   if (icon == NULL)
625     {
626       fprintf(stderr,
627               "\nError: I could not load the icon image: %s%s\n"
628               "The Simple DirectMedia error that occured was:\n"
629               "%s\n\n", datadir.c_str(), ("/images/" + package_symbol_name + ".xpm").c_str(), SDL_GetError());
630       exit(1);
631     }
632
633
634   /* Create mask: */
635 /*
636   masklen = (((icon -> w) + 7) / 8) * (icon -> h);
637   mask = (Uint8*) malloc(masklen * sizeof(Uint8));
638   memset(mask, 0xFF, masklen);
639 */
640
641   /* Set icon: */
642
643   SDL_WM_SetIcon(icon, NULL);//mask);
644
645
646   /* Free icon surface & mask: */
647
648 //  free(mask);
649   SDL_FreeSurface(icon);
650 }
651
652
653 /* Parse command-line arguments: */
654
655 void Setup::parseargs(int argc, char * argv[])
656 {
657   int i;
658
659   config->load();
660
661   /* Parse arguments: */
662
663   for (i = 1; i < argc; i++)
664     {
665       if (strcmp(argv[i], "--fullscreen") == 0 ||
666           strcmp(argv[i], "-f") == 0)
667         {
668           use_fullscreen = true;
669         }
670       else if (strcmp(argv[i], "--window") == 0 ||
671                strcmp(argv[i], "-w") == 0)
672         {
673           use_fullscreen = false;
674         }
675       else if (strcmp(argv[i], "--joystick") == 0 || strcmp(argv[i], "-j") == 0)
676         {
677           assert(i+1 < argc);
678           joystick_num = atoi(argv[++i]);
679         }
680       else if (strcmp(argv[i], "--joymap") == 0)
681         {
682           assert(i+1 < argc);
683           if (sscanf(argv[++i],
684                      "%d:%d:%d:%d:%d", 
685                      &joystick_keymap.x_axis, 
686                      &joystick_keymap.y_axis, 
687                      &joystick_keymap.a_button, 
688                      &joystick_keymap.b_button, 
689                      &joystick_keymap.start_button) != 5)
690             {
691               puts("Warning: Invalid or incomplete joymap, should be: 'XAXIS:YAXIS:A:B:START'");
692             }
693           else
694             {
695               std::cout << "Using new joymap:\n"
696                         << "  X-Axis:       " << joystick_keymap.x_axis << "\n"
697                         << "  Y-Axis:       " << joystick_keymap.y_axis << "\n"
698                         << "  A-Button:     " << joystick_keymap.a_button << "\n"
699                         << "  B-Button:     " << joystick_keymap.b_button << "\n"
700                         << "  Start-Button: " << joystick_keymap.start_button << std::endl;
701             }
702         }
703       else if (strcmp(argv[i], "--leveleditor") == 0)
704         {
705           launch_leveleditor_mode = true;
706         }
707       else if (strcmp(argv[i], "--worldmap") == 0)
708         {
709           launch_worldmap_mode = true;
710         }
711       else if (strcmp(argv[i], "--flip-levels") == 0)
712         {
713           flip_levels_mode = true;
714         }
715       else if (strcmp(argv[i], "--datadir") == 0 
716                || strcmp(argv[i], "-d") == 0 )
717         {
718           assert(i+1 < argc);
719           datadir = argv[++i];
720         }
721       else if (strcmp(argv[i], "--show-fps") == 0)
722         {
723           /* Use full screen: */
724
725           show_fps = true;
726         }
727       else if (strcmp(argv[i], "--opengl") == 0 ||
728                strcmp(argv[i], "-gl") == 0)
729         {
730 #ifndef NOOPENGL
731           /* Use OpengGL: */
732
733           use_gl = true;
734 #endif
735         }
736       else if (strcmp(argv[i], "--sdl") == 0)
737           {
738             use_gl = false;
739           }
740       else if (strcmp(argv[i], "--usage") == 0)
741         {
742           /* Show usage: */
743
744           usage(argv[0], 0);
745         }
746       else if (strcmp(argv[i], "--version") == 0)
747         {
748           /* Show version: */
749           printf((package_name + " " + package_version + "\n").c_str() );
750           exit(0);
751         }
752       else if (strcmp(argv[i], "--disable-sound") == 0)
753         {
754           /* Disable the compiled in sound feature */
755           printf("Sounds disabled \n");
756           SoundManager::get()->enable_sound(false); 
757         }
758       else if (strcmp(argv[i], "--disable-music") == 0)
759         {
760           /* Disable the compiled in sound feature */
761           printf("Music disabled \n");
762           SoundManager::get()->enable_music(false); 
763         }
764       else if (strcmp(argv[i], "--debug") == 0)
765         {
766           /* Enable the debug-mode */
767           debug_mode = true;
768
769         }
770       else if (strcmp(argv[i], "--help") == 0)
771         {     /* Show help: */
772           puts(_(("  SuperTux  " + package_version + "\n"
773                "  Please see the file \"README.txt\" for more details.\n").c_str()));
774           printf(_("Usage: %s [OPTIONS] FILENAME\n\n"), argv[0]);
775           puts(_("Display Options:\n"
776                "  -f, --fullscreen    Run in fullscreen mode.\n"
777                "  -w, --window        Run in window mode.\n"
778                "  --opengl            If OpenGL support was compiled in, this will tell\n"
779                "                      SuperTux to make use of it.\n"
780                "  --sdl               Use the SDL software graphical renderer\n"
781                "\n"
782                "Sound Options:\n"
783                "  --disable-sound     If sound support was compiled in,  this will\n"
784                "                      disable sound for this session of the game.\n"
785                "  --disable-music     Like above, but this will disable music.\n"
786                "\n"
787                "Misc Options:\n"
788                "  -j, --joystick NUM  Use joystick NUM (default: 0)\n" 
789                "  --joymap XAXIS:YAXIS:A:B:START\n"
790                "                      Define how joystick buttons and axis should be mapped\n"
791                "  --leveleditor       Opens the leveleditor in a file.\n"
792                "  --worldmap          Opens the specified worldmap file.\n"
793                "  --flip-levels       Flip levels upside-down.\n"
794                "  -d, --datadir DIR   Load Game data from DIR (default: automatic)\n"
795                "  --debug             Enables the debug mode, which is useful for developers.\n"
796                "  --help              Display a help message summarizing command-line\n"
797                "                      options, license and game controls.\n"
798                "  --usage             Display a brief message summarizing command-line options.\n"
799                "  --version           Display the version of SuperTux you're running.\n\n"
800                ));
801           exit(0);
802         }
803       else if (argv[i][0] != '-')
804         {
805           level_startup_file = argv[i];
806         }
807       else
808         {
809           /* Unknown - complain! */
810
811           usage(argv[0], 1);
812         }
813     }
814 }
815
816
817 /* Display usage: */
818
819 void usage(char * prog, int ret)
820 {
821   FILE * fi;
822
823
824   /* Determine which stream to write to: */
825
826   if (ret == 0)
827     fi = stdout;
828   else
829     fi = stderr;
830
831
832   /* Display the usage message: */
833
834   fprintf(fi, _("Usage: %s [--fullscreen] [--opengl] [--disable-sound] [--disable-music] [--debug] | [--usage | --help | --version] [--leveleditor] [--worldmap] [--flip-levels] FILENAME\n"),
835           prog);
836
837
838   /* Quit! */
839
840   exit(ret);
841 }
842
843 std::set<std::string> FileSystem::read_directory(const std::string& pathname)
844 {
845   std::set<std::string> dirnames;
846   
847   DIR* dir = opendir(pathname.c_str());
848   if (dir)
849     {
850       struct dirent *direntp;
851       
852       while((direntp = readdir(dir)))
853         {
854           dirnames.insert(direntp->d_name);
855         }
856       
857       closedir(dir);
858     }
859
860   return dirnames;
861 }
862
863 /* EOF */