Adonthell  0.4
prefs.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000/2001/2002/2003 Kai Sterker <kai.sterker@gmail.com>
3  Part of the Adonthell Project <http://adonthell.nongnu.org>
4 
5  Adonthell is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  Adonthell is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with Adonthell. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 /**
20  * @file prefs.cc
21  *
22  * @author Kai Sterker
23  * @brief Adonthell's configuration
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 #include <getopt.h>
30 #include <iostream>
31 #include <dirent.h>
32 #include "prefs.h"
33 #include "python_class.h"
34 #include "game.h"
35 
37 {
38  // set some default values where possible
39  screen_mode = 0; // Letterbox
40  display = 0; // Display for fullscreen mode
41  quick_load = 0; // Quick-load disabled
42  audio_channels = 1; // Stereo
43  audio_resolution = 1; // 16 bit
44  audio_sample_rate = 2; // 11025, 22050 or 44100 Hz
45  audio_volume = 35; // 0 - 100%
46  language = ""; // Let the user's environment decide
47  font = ""; // use default font
48 
49  // set OS specific directory containing the adonthellrc file
50  adonthellrc = game::get_system_dir(CONFIG);
51 }
52 
53 /**
54  * Displays the help message - for internal use only.
55  *
56  */
57 void print_help_message (char * argv[])
58 {
59  cout << "Usage: " << argv[0] << " [OPTIONS] GAME" << endl;
60  cout << endl;
61  cout << "Where [OPTIONS] can be:\n";
62  cout << "-h print this help message" << endl;
63  cout << "-d print the data directory and exit" << endl;
64  cout << "-v print version and exit" << endl;
65  cout << "-l list installed games and exit" << endl;
66  cout << "-g dir play the game contained in dir (for development only)" << endl;
67  cout << "-c byte-compile all Python scripts in this directory (for " << endl;
68  cout << " development only)" << endl;
69 }
70 
71 /**
72  * Displays the available games - for internal use only.
73  *
74  */
76 {
77  struct dirent * d;
78  DIR * mydir = opendir ((game::global_data_dir() + "/games").c_str());
79  bool nogames = true;
80 
81  if (!mydir)
82  {
83  cerr << "Cannot open directory " << game::global_data_dir() + "/games!" << endl;
84  exit (1);
85  }
86 
87  while ((d = readdir (mydir)) != NULL)
88  {
89  string s (d->d_name);
90  if (s != "." && s != "..")
91  {
92  if (nogames)
93  {
94  nogames = false;
95  cout << "Installed games (Suitable for the GAME parameter):\n";
96  }
97  cout << " - " << d->d_name << endl;
98  }
99  }
100 
101  if (nogames) cout << "No games available.\n";
102 
103  closedir (mydir);
104 }
105 
106 void config::parse_arguments (int argc, char * argv[])
107 {
108  int c;
109 
110  // Check for options
111  while (1)
112  {
113  c = getopt (argc, argv, "lcdhvg:");
114  if (c == -1)
115  break;
116 
117  switch (c)
118  {
119  case 'l':
121  exit (0);
122  break;
123 
124  case 'd':
125  cout << game::global_data_dir() << endl;
126  exit (0);
127  break;
128 
129  case 'v':
130  cout << VERSION << endl;
131  exit (0);
132  break;
133 
134  case 'c':
135  {
136  python::init ();
137 #if PY_VERSION_HEX < 0x03020000
138  python::exec_string ("import compileall; compileall.compile_dir (\".\", 0);");
139 #else
140  // starting with Python 3.2, .pyc files end up in the __pycache__ directory unless
141  // legacy=True parameter is used. See https://www.python.org/dev/peps/pep-3147/
142  python::exec_string ("import compileall; compileall.compile_dir (\".\", maxlevels=0, legacy=True);");
143 #endif
144  python::cleanup ();
145  exit (0);
146  break;
147  }
148 
149  case 'g':
150  {
151  gamedir = optarg;
152  if (gamedir[gamedir.size () - 1] == '/')
153  gamedir.erase (gamedir.size () - 1);
154 
155  // Check whether the requested game directory exists
156  DIR * mydir = opendir (gamedir.c_str ());
157 
158  if (!mydir)
159  {
160  cerr << "Cannot open directory " << gamedir << "!" << endl;
161  exit (1);
162  }
163  closedir (mydir);
164 
165  break;
166  }
167 
168  case '?':
169  case 'h':
170  print_help_message (argv);
171  exit (0);
172  break;
173  }
174  }
175 
176  // Check whether the GAME parameter is needed
177  if (gamedir == "")
178  {
179  // Check whether the GAME parameter is given
180  if (argc - optind != 1)
181  {
182  print_help_message (argv);
183  exit (0);
184  }
185 
186  // Check whether the requested game exists
187  struct dirent * d;
188  DIR * mydir = opendir ((game::global_data_dir() + "/games").c_str());
189  bool found = false;
190 
191  if (!mydir)
192  {
193  cerr << "Cannot open directory " << game::global_data_dir() + "/games!" << endl;
194  exit (1);
195  }
196 
197  while ((d = readdir (mydir)) != NULL)
198  {
199  if (string (d->d_name) == argv[optind]) found = true;
200  }
201 
202  closedir (mydir);
203 
204  if (!found)
205  {
206  cerr << "Game '" << argv[optind] << "' can't be found.\n"
207  << "Run '" << argv[0] << " -l' for a list of available games.\n";
208  exit (1);
209  }
210 
211  // The game exists, so let the show continue...
212  gamedir = game::global_data_dir() + "/games/";
213  gamedir += argv[optind];
214  }
215 
216  // Now check whether the directory is a valid game directory
217  string tfile = gamedir + "/gamename.txt";
218  ifstream f (tfile.c_str ());
219  if (!f.is_open ())
220  {
221  cerr << "Directory " << gamedir << " is not a valid game directory.\n";
222  exit (1);
223  }
224  char t[256];
225  f.getline (t, 256);
226  game_name = t;
227  f.close ();
228 }
229 
230 
231 
232 // That's more or less a move operator, as the source is destroyed
233 config& config::operator =(const config *c)
234 {
235  display = c->display;
241  adonthellrc = c->adonthellrc;
242 
243  delete c;
244  return *this;
245 }
246 
248 {
249  return (char *) adonthellrc.c_str ();
250 }
251 
252 // write a default configuration file
254 {
255  string fname;
256 
257 #ifndef WIN32
258  fname = adonthellrc + "/adonthellrc";
259 #else
260  fname = adonthellrc + "/adonthell.ini";
261 #endif
262 
263  ofstream rc (fname.c_str ());
264 
265  rc << "# Sample Adonthell configuration file;\n"
266  << "# edit to your needs!\n\n"
267  << "# Screen-mode num\n# 0 Windowed mode\n# 1 Letterbox mode\n"
268  << "# 2 Fullscreen mode\n Screen-mode " << (int) screen_mode
269  << "\n\n" << "# Display num\n# Index of the display to use in fullscreen mode"
270  << "\n Display " << (int) display << "\n\n"
271  << "# Language [locale]\n# Where locale has the form fr_FR or de_DE, etc.\n"
272  << " Language [" << language << "]\n\n"
273  << "# Font [font.ttf]\n# Path to a true type font to use. Leave empty for default\n"
274  << " Font [" << font << "]\n\n"
275  << "# Quick-load num\n# 0 off\n# 1 on\n Quick-load "
276  << (int) quick_load << "\n\n"
277  << "# Audio-channels num\n# 0 Mono\n# 1 Stereo\n"
278  << " Audio-channels " << (int) audio_channels << "\n\n"
279  << "# Audio-resolution num\n# 0 8 bit\n# 1 16 bit\n"
280  << " Audio-resolution " << (int) audio_resolution << "\n\n"
281  << "# Audio-sample-rate num\n# 0 11025 Hz\n# 1 22050 Hz\n# 2 44100 Hz\n"
282  << " Audio-sample-rate " << (int) audio_sample_rate << "\n\n"
283  << "# Audio-volume num\n# 0 - 100 %\n"
284  << " Audio-volume " << (int) audio_volume << "\n\n"
285  << "# Version number of this file. Please don't edit\n Version [" << VERSION << "]\n";
286 
287  rc.close ();
288 }
289 
291 {
292  int n, i = 1;
293  u_int32 major = 0, minor = 0, micro = 0, MAJOR, MINOR, MICRO;
294  char suffix[16] = "\0", SUFFIX[16] = "\0";
295  string s, fname;
296 
297 #ifndef WIN32
298  fname = adonthellrc + "/adonthellrc";
299 #else
300  fname = adonthellrc + "/adonthell.ini";
301 #endif
302 
303  // prefsin is declared in lex.prefs.c
304  prefsin = fopen (fname.c_str (), "r");
305 
306  // open failed -> try to write new configuration
307  if (!prefsin)
308  {
310 
311  // now try again
312  if (!(prefsin = fopen (fname.c_str (), "r")))
313  {
314  fprintf (stderr, "*** warning: prefs::read_adonthellrc: creating config file failed\n");
315  return false;
316  }
317  }
318 
319  // adonthellrc opened -> read configuration
320  while (i)
321  {
322  switch (i = parse_adonthellrc (n, s))
323  {
324  case PREFS_LANGUAGE:
325  {
326  if (parse_adonthellrc (n, s) == PREFS_STR) language = s;
327  break;
328  }
329  case PREFS_FONT:
330  {
331  if (parse_adonthellrc (n, s) == PREFS_STR) font = s;
332  break;
333  }
334  case PREFS_SCREEN_MODE:
335  {
336  if (parse_adonthellrc (n, s) == PREFS_NUM) screen_mode = n;
337  break;
338  }
339 
340  case PREFS_DISPLAY:
341  {
342  if (parse_adonthellrc (n, s) == PREFS_NUM) display = n;
343  break;
344  }
345 
346  case PREFS_QUICK_LOAD:
347  {
348  if (parse_adonthellrc (n, s) == PREFS_NUM) quick_load = n;
349  break;
350  }
351 
352  case PREFS_AUDIO_RESOLUTION:
353  {
354  if (parse_adonthellrc (n, s) == PREFS_NUM) audio_resolution = n;
355  break;
356  }
357 
358  case PREFS_AUDIO_CHANNELS:
359  {
360  if (parse_adonthellrc (n, s) == PREFS_NUM) audio_channels = n;
361  break;
362  }
363 
364  case PREFS_AUDIO_SAMPLE_RATE:
365  {
366  if (parse_adonthellrc (n, s) == PREFS_NUM) audio_sample_rate = n;
367  break;
368  }
369 
370  case PREFS_AUDIO_VOLUME:
371  {
372  if (parse_adonthellrc (n, s) == PREFS_NUM) audio_volume = n;
373  break;
374  }
375 
376  case PREFS_VERSION:
377  {
378  // get config file version number
379  if (parse_adonthellrc (n, s) == PREFS_STR)
380  sscanf (s.c_str (), "%u.%u.%u%15s", &major, &minor, &micro, suffix);
381  break;
382  }
383  default: break;
384  }
385  }
386 
387  fclose (prefsin);
388 
389  // get engine version numbers
390  sscanf (VERSION, "%u.%u.%u%15s", &MAJOR, &MINOR, &MICRO, SUFFIX);
391 
392  // compare version of config file and engine
393  if (major < MAJOR ||
394  (major == MAJOR && minor < MINOR) ||
395  (major == MAJOR && minor == MINOR && micro < MICRO) ||
396  strcmp (suffix, SUFFIX) != 0)
397  {
398  // update config file if engine is newer
400  }
401 
402  return true;
403 }
config::audio_channels
u_int8 audio_channels
The number of channels: mono (0) or stereo (1).
Definition: prefs.h:155
config::display
u_int8 display
Index of the display to use for fullscreen mode.
Definition: prefs.h:147
config::read_adonthellrc
bool read_adonthellrc()
Reads the configuration file.
Definition: prefs.cc:290
u_int32
#define u_int32
32 bits long unsigned integer
Definition: types.h:41
config::game_name
string game_name
Name of the game that is running at present.
Definition: prefs.h:135
python_class.h
Defines the python class. This file is named this way so it doesn't conflicts with Python....
print_available_games
void print_available_games()
Displays the available games - for internal use only.
Definition: prefs.cc:75
prefs.h
Adonthell's configuration.
config::get_adonthellrc
char * get_adonthellrc()
Returns the path to the user's private Adonthell directory.
Definition: prefs.cc:247
prefsin
FILE * prefsin
The config file opened by the lexical scanner.
config::language
string language
Language to use if NLS was compiled in.
Definition: prefs.h:130
config::audio_volume
u_int8 audio_volume
The volume: a value betwen 0 and 100.
Definition: prefs.h:168
parse_adonthellrc
int parse_adonthellrc(int &, string &)
Start the lexical scanner to parse the config file, usually fount at ~/.adonthell/adonthellrc.
python::cleanup
static void cleanup()
Cleanup Python.
Definition: python_class.cc:52
config
This class contains the engine's configuration read either from the config file or from the command l...
Definition: prefs.h:74
config::screen_mode
u_int8 screen_mode
Whether the engine shall run in window (0) or fullscreen (1) mode.
Definition: prefs.h:143
config::gamedir
string gamedir
Path of the directory that contains the game running at present.
Definition: prefs.h:139
python::exec_string
static void exec_string(const char *s)
Execute Python statements contained in a string.
Definition: python_class.cc:79
config::parse_arguments
void parse_arguments(int argc, char *argv[])
See whether any options have been specified on the command line.
Definition: prefs.cc:106
config::audio_resolution
u_int8 audio_resolution
The resolution: 8 bit (0) or 16 bit (1)
Definition: prefs.h:159
game.h
Declares the game class.
config::audio_sample_rate
u_int8 audio_sample_rate
The sample rate: 11025 Hz (0), 22050 Hz (1) or 44100 Hz (2)
Definition: prefs.h:163
config::write_adonthellrc
void write_adonthellrc()
Writes a default configuration file with the values set in the constructor.
Definition: prefs.cc:253
game::get_system_dir
static string get_system_dir(const sys_dir_type &type)
Return the OS-specific directory of the given type.
Definition: game.cc:58
config::quick_load
u_int8 quick_load
Whether the quick-load feature is enabled (1) or not (0)
Definition: prefs.h:151
print_help_message
void print_help_message(char *argv[])
Displays the help message - for internal use only.
Definition: prefs.cc:57
config::config
config()
Constructor.
Definition: prefs.cc:36
python::init
static void init()
Initialise Python and insert the Adonthell include paths.
Definition: python_class.cc:44
game::global_data_dir
static string global_data_dir()
Returns the absolute path to the global data directory.
Definition: game.h:91