Adonthell 0.4
prefs.cc
Go to the documentation of this file.
00001 /*
00002    $Id: prefs.cc,v 1.36 2006/09/03 20:48:08 ksterker Exp $
00003 
00004    Copyright (C) 2000/2001/2002/2003 Kai Sterker <kaisterker@linuxgames.com>
00005    Part of the Adonthell Project http://adonthell.linuxgames.com
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 /** 
00016  * @file prefs.cc
00017  *
00018  * @author Kai Sterker
00019  * @brief Adonthell's configuration
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #include <config.h>
00024 #endif
00025 #include <getopt.h>
00026 #include <stdio.h>
00027 #include <iostream> 
00028 #include <sys/stat.h>
00029 #include <dirent.h>
00030 #include <unistd.h>
00031 #include "prefs.h"
00032 #include "python_class.h"
00033 #include "game.h"
00034 
00035 config::config () 
00036 {
00037     // set some default values where possible
00038 #if defined (WIN32) || defined (__APPLE__)
00039     screen_mode = 1;                // Fullscreen
00040 #else
00041     screen_mode = 0;                // Fullscreen
00042 #endif
00043 #if defined (QTOPIA)
00044     double_screen = 0;              // Double screen
00045 #else
00046     double_screen = 1;              // Double screen
00047 #endif
00048     quick_load = 0;                 // Quick-load disabled
00049     audio_channels = 1;             // Stereo
00050     audio_resolution = 1;           // 16 bit
00051     audio_sample_rate = 2;          // 11025, 22050 or 44100 Hz
00052     audio_volume = 100;             // 0 - 100%
00053     language = "";                  // Let the user's environment decide
00054     font = "";                      // use default font
00055 
00056     // set the path to the adonthellrc file:
00057 #ifndef SINGLE_DIR_INST
00058     adonthellrc = string (getenv ("HOME")) + "/.adonthell";
00059 #else
00060     adonthellrc = string (".");
00061 #endif
00062 }
00063  
00064 /**
00065  * Displays the help message - for internal use only.
00066  * 
00067  */ 
00068 void print_help_message (char * argv[]) 
00069 {
00070     cout << "Usage: " << argv[0] << " [OPTIONS] GAME" << endl;
00071     cout << endl;
00072     cout << "Where [OPTIONS] can be:\n";
00073     cout << "-h         print this help message" << endl; 
00074     cout << "-d         print the data directory and exit" << endl; 
00075     cout << "-v         print version and exit" << endl; 
00076     cout << "-l         list installed games and exit" << endl;
00077     cout << "-g dir     play the game contained in dir (for development only)" << endl;
00078     cout << "-c         byte-compile all Python scripts in this directory (for " << endl;
00079     cout << "           development only)" << endl; 
00080 }
00081 
00082 /**
00083  * Displays the available games - for internal use only.
00084  * 
00085  */ 
00086 void print_available_games () 
00087 {
00088     struct dirent * d;
00089     DIR * mydir = opendir ((game::global_data_dir() + "/games").c_str()); 
00090     bool nogames = true; 
00091  
00092     if (!mydir) 
00093     {
00094         cerr << "Cannot open directory " << game::global_data_dir() + "/games!" << endl;
00095         exit (1); 
00096     }
00097 
00098     while ((d = readdir (mydir)) != NULL)
00099     {
00100         string s (d->d_name); 
00101         if (s != "." && s != "..")
00102         {
00103             if (nogames) 
00104             {
00105                 nogames = false;
00106                 cout << "Installed games (Suitable for the GAME parameter):\n"; 
00107             }
00108             cout << " - " << d->d_name << endl; 
00109         }
00110     }
00111 
00112     if (nogames) cout << "No games available.\n"; 
00113     
00114     closedir (mydir); 
00115 }
00116 
00117 void config::parse_arguments (int argc, char * argv[])
00118 {     
00119     int c;
00120     
00121     // Check for options
00122     while (1)
00123     {
00124         c = getopt (argc, argv, "lcdhvg:");
00125         if (c == -1)
00126             break;
00127         
00128         switch (c)
00129         { 
00130             case 'l':
00131                 print_available_games (); 
00132                 exit (0); 
00133                 break;
00134                 
00135             case 'd':
00136                 cout << game::global_data_dir() << endl;
00137                 exit (0); 
00138                 break;
00139                 
00140             case 'v':
00141                 cout << VERSION << endl;
00142                 exit (0); 
00143                 break;
00144                 
00145             case 'c':
00146             {
00147                 python::init (); 
00148                 python::exec_string ("import compileall; compileall.compile_dir (\".\", 0);");  
00149                 python::cleanup (); 
00150                 exit (0); 
00151                 break;
00152             }
00153 
00154             case 'g':
00155             {
00156                 gamedir = optarg;
00157                 if (gamedir[gamedir.size () - 1] == '/')
00158                     gamedir.erase (gamedir.size () - 1);
00159                 
00160                 // Check whether the requested game directory exists
00161                 DIR * mydir = opendir (gamedir.c_str ()); 
00162                 
00163                 if (!mydir) 
00164                 {
00165                     cerr << "Cannot open directory " << gamedir << "!" << endl;
00166                     exit (1); 
00167                 }
00168                 closedir (mydir);
00169                 
00170                 break;
00171             }
00172             
00173             case '?':
00174             case 'h':
00175                 print_help_message (argv);
00176                 exit (0);
00177                 break;                 
00178         }
00179     }
00180 
00181     // Check whether the GAME parameter is needed
00182     if (gamedir == "")
00183     {
00184         // Check whether the GAME parameter is given
00185         if (argc - optind != 1)
00186         {
00187             print_help_message (argv);
00188             exit (0);
00189         }
00190         
00191         // Check whether the requested game exists
00192         struct dirent * d;
00193         DIR * mydir = opendir ((game::global_data_dir() + "/games").c_str()); 
00194         bool found = false; 
00195         
00196         if (!mydir) 
00197         {
00198             cerr << "Cannot open directory " << game::global_data_dir() + "/games!" << endl;
00199             exit (1); 
00200         }
00201         
00202         while ((d = readdir (mydir)) != NULL)
00203         {
00204             if (string (d->d_name) == argv[optind]) found = true; 
00205         }
00206         
00207         closedir (mydir); 
00208         
00209         if (!found) 
00210         {
00211             cerr << "Game '" << argv[optind] << "' can't be found.\n"
00212                  << "Run '" << argv[0] << " -l' for a list of available games.\n"; 
00213             exit (1); 
00214         }
00215         
00216         // The game exists, so let the show continue...
00217         gamedir = game::global_data_dir() + "/games/"; 
00218         gamedir += argv[optind];
00219     }
00220 
00221     // Now check whether the directory is a valid game directory
00222     string tfile = gamedir + "/gamename.txt"; 
00223     ifstream f (tfile.c_str ()); 
00224     if (!f.is_open ()) 
00225     {
00226         cerr << "Directory " << gamedir << " is not a valid game directory.\n";
00227         exit (1); 
00228     }
00229     char t[256];
00230     f.getline (t, 256); 
00231     game_name = t;
00232     f.close ();
00233 }
00234 
00235 
00236 
00237 // That's more or less a move operator, as the source is destroyed
00238 config& config::operator =(const config *c)
00239 {
00240     screen_mode = c->screen_mode;
00241     audio_channels = c->audio_channels; 
00242     audio_resolution = c->audio_resolution;
00243     audio_sample_rate = c->audio_sample_rate;
00244     audio_volume = c->audio_volume;
00245     adonthellrc = c->adonthellrc;
00246 
00247     delete c;
00248     return *this;
00249 }
00250 
00251 char *config::get_adonthellrc ()
00252 {
00253     return (char *) adonthellrc.c_str ();
00254 }
00255 
00256 // write a default configuration file
00257 void config::write_adonthellrc ()
00258 {
00259     string fname;
00260 
00261 #ifndef WIN32
00262     fname = adonthellrc + "/adonthellrc";
00263 #else
00264     fname = adonthellrc + "/adonthell.ini";
00265 #endif
00266     
00267     ofstream rc (fname.c_str ());
00268 
00269     rc << "# Sample Adonthell configuration file;\n"
00270        << "# edit to your needs!\n\n"
00271        << "# Screen-mode num\n#   0  Windowed mode\n"
00272        << "#   1  Fullscreen mode\n    Screen-mode " << (int) screen_mode 
00273        << "\n\n" << "# Double-size num\n#   0  320x240 mode\n"
00274        << "#   1  640x480 (double) mode\n    Double-size " 
00275        << (int) double_screen << "\n\n"
00276        << "# Language [locale]\n#   Where locale has the form fr_FR or de_DE, etc.\n"
00277        << "    Language [" << language << "]\n\n"
00278        << "# Font [font.ttf]\n#   Path to a true type font to use. Leave empty for default\n"
00279        << "    Font [" << font << "]\n\n"
00280        << "# Quick-load num\n#   0  off\n#   1  on\n    Quick-load "
00281        << (int) quick_load << "\n\n"
00282        << "# Audio-channels num\n#   0  Mono\n#   1  Stereo\n"
00283        << "    Audio-channels " << (int) audio_channels << "\n\n"
00284        << "# Audio-resolution num\n#   0  8 bit\n#   1  16 bit\n"
00285        << "    Audio-resolution " << (int) audio_resolution << "\n\n"
00286        << "# Audio-sample-rate num\n#   0  11025 Hz\n#   1  22050 Hz\n#   2  44100 Hz\n"
00287        << "    Audio-sample-rate " << (int) audio_sample_rate << "\n\n"
00288        << "# Audio-volume num\n#   0 - 100 %\n"
00289        << "    Audio-volume " << (int) audio_volume << "\n\n"
00290        << "# Version number of this file. Please don't edit\n    Version [" << VERSION << "]\n";
00291 
00292     rc.close ();
00293 }
00294 
00295 bool config::read_adonthellrc ()
00296 {
00297     int n, i = 1;
00298     u_int32 major = 0, minor = 0, micro = 0, MAJOR, MINOR, MICRO;
00299     char suffix[16] = "\0", SUFFIX[16] = "\0"; 
00300     string s, fname;
00301 
00302 #ifndef WIN32
00303     fname = adonthellrc + "/adonthellrc";
00304 #else
00305     fname = adonthellrc + "/adonthell.ini";
00306 #endif
00307 
00308     // try to create that directory in case it dosn't exist
00309 #ifdef WIN32
00310     mkdir (adonthellrc.c_str ());
00311 #else
00312     mkdir (adonthellrc.c_str (), 0700);
00313 #endif
00314     
00315     // prefsin is declared in lex.prefs.c
00316     prefsin = fopen (fname.c_str (), "r");
00317 
00318     // open failed -> try to write new configuration 
00319     if (!prefsin)
00320     {
00321         write_adonthellrc ();
00322 
00323         // now try again
00324         if (!(prefsin = fopen (fname.c_str (), "r")))
00325         {
00326             fprintf (stderr, "*** warning: prefs::read_adonthellrc: creating config file failed\n");
00327             return false;
00328         }
00329     }
00330 
00331     // adonthellrc opened -> read configuration
00332     while (i)
00333     {
00334         switch (i = parse_adonthellrc (n, s))
00335         {
00336             case PREFS_LANGUAGE:
00337             {
00338                 if (parse_adonthellrc (n, s) == PREFS_STR) language = s;
00339                 break;
00340             }
00341             case PREFS_FONT:
00342             {
00343                 if (parse_adonthellrc (n, s) == PREFS_NUM) font = s;
00344                 break;
00345             }
00346             case PREFS_SCREEN_MODE:
00347             {
00348                 if (parse_adonthellrc (n, s) == PREFS_NUM) screen_mode = n;
00349                 break;
00350             }
00351 
00352             case PREFS_DOUBLE_SCREEN:
00353             {
00354                 if (parse_adonthellrc (n, s) == PREFS_NUM) double_screen = n;
00355                 break;
00356             }
00357 
00358             case PREFS_QUICK_LOAD:
00359             {
00360                 if (parse_adonthellrc (n, s) == PREFS_NUM) quick_load = n;
00361                 break;
00362             }
00363 
00364             case PREFS_AUDIO_RESOLUTION:
00365             {
00366                 if (parse_adonthellrc (n, s) == PREFS_NUM) audio_resolution = n;
00367                 break;
00368             }
00369 
00370             case PREFS_AUDIO_CHANNELS:
00371             {
00372                 if (parse_adonthellrc (n, s) == PREFS_NUM) audio_channels = n;
00373                 break;
00374             }
00375 
00376             case PREFS_AUDIO_SAMPLE_RATE:
00377             {
00378                 if (parse_adonthellrc (n, s) == PREFS_NUM) audio_sample_rate = n;
00379                 break;
00380             }
00381 
00382             case PREFS_AUDIO_VOLUME:
00383             {
00384                 if (parse_adonthellrc (n, s) == PREFS_NUM) audio_volume = n;
00385                 break;
00386             }
00387 
00388             case PREFS_VERSION:
00389             {
00390                 // get config file version number
00391                 if (parse_adonthellrc (n, s) == PREFS_STR) 
00392                     sscanf (s.c_str (), "%d.%d.%d%15s", &major, &minor, &micro, suffix);
00393                 break;
00394             }
00395             default: break;
00396         }
00397     }    
00398 
00399     fclose (prefsin);
00400 
00401     // get engine version numbers
00402     sscanf (VERSION, "%d.%d.%d%15s", &MAJOR, &MINOR, &MICRO, SUFFIX);
00403     
00404     // compare version of config file and engine
00405     if (major < MAJOR || 
00406         (major == MAJOR && minor < MINOR) ||
00407         (major == MAJOR && minor == MINOR && micro < MICRO) ||
00408         strcmp (suffix, SUFFIX) != 0)
00409     {
00410         // update config file if engine is newer
00411         write_adonthellrc ();
00412     }
00413 
00414     return true;
00415 }