1 /**
2  * @file configfile.cc
3  * @brief Config file handler
4  * @created 2005-01-22
5  * @date 2014-09-28
6  * @copyright 1991-2014 TLK Games
7  * @author Bruno Ethvignot
8  * @version $Revision: 24 $
9  */
10 /*
11  * copyright (c) 1991-2014 TLK Games all rights reserved
12  * $Id: configfile.cc 24 2014-09-28 15:30:04Z bruno.ethvignot@gmail.com $
13  *
14  * TecnoballZ is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * TecnoballZ is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27  * MA  02110-1301, USA.
28  */
29 #include "config.h"
30 #include "../include/configfile.h"
31 #include "../include/handler_display.h"
32 #include "../include/handler_audio.h"
33 #include "../include/handler_players.h"
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 const char *
40 configfile::language_to_string[MAX_OF_LANGUAGES] =
41 {
42   "en",
43   "fr"
44 };
45 
46 const
47 std::string
48 configfile::CONF_DIR_NAME ("tlk-games");
49 const
50 std::string
51 configfile::CONF_FILENAME ("tecnoballz.conf");
52 
53 /**
54  * Create object
55  */
configfile()56 configfile::configfile ()
57 {
58   thePlayers[0] = thePlayer1;
59   thePlayers[1] = thePlayer2;
60   thePlayers[2] = thePlayer3;
61   thePlayers[3] = thePlayer4;
62   thePlayers[4] = thePlayer5;
63   thePlayers[5] = thePlayer6;
64   for (Uint32 i = 0; i < handler_players::MAX_OF_PLAYERS; i++)
65     {
66       char *p = thePlayers[i];
67       for (Uint32 j = 0; j < 8; j++)
68         {
69           p[j] = 0;
70         }
71     }
72   resetvalue ();
73 }
74 
75 /**
76  * Destroy object
77  */
~configfile()78 configfile::~configfile ()
79 {
80 }
81 
82 /**
83  * Reset all values
84  */
85 void
resetvalue()86 configfile::resetvalue ()
87 {
88 #ifndef SOUNDISOFF
89   handler_audio::is_audio_enable = 1;
90 #endif
91   resolution = 2;
92   has_background = false;
93   is_verbose = false;
94   handler_display::optionfull = false;
95   difficulty_level = DIFFICULTY_NORMAL;
96   initial_num_of_lifes = 5;
97   number_of_players = 1;
98   char *user = getenv ("USER");
99   if (user != NULL)
100     {
101       user = stringname;
102     }
103   for (Uint32 i = 0; i < 6; i++)
104     {
105       strncpy (thePlayers[i], user, 6);
106     }
107   language = LANGUAGE_EN;
108   absolute_mouse_positioning = false;
109 }
110 
111 /**
112  * Display values
113  */
114 void
configinfo()115 configfile::configinfo ()
116 {
117   bool audio;
118 #ifndef SOUNDISOFF
119   audio = handler_audio::is_audio_enable;
120 #else
121   audio = false;
122 #endif
123   fprintf (stdout, "  <config info>\n"
124            "- optionfull : %i\n- is_audio_enable: %i\n- resolution:%i\n"
125            "- is_verbose: %i\n difficulty_level : %i\n",
126            handler_display::optionfull, audio, resolution,
127            is_verbose, difficulty_level);
128 }
129 
130 /**
131  * Check if config directory exists; if not create it and set config_dir
132  */
check_and_create_dir()133 bool configfile::check_and_create_dir ()
134 {
135 #ifdef _WIN32
136   /* opendir don't exist on windows
137    * create directory if not exist */
138   MKDIR (conf_dirname.c_str (), S_IRWXU);
139 #else
140   /* test and create .tlkgames */
141   DIR* dp = opendir (conf_dirname.c_str ());
142   if (!dp)
143     {
144       fprintf (stderr, "couldn't find/open config directory '%s'\n",
145                conf_dirname.c_str ());
146       fprintf (stderr, "attempting to create it... ");
147       MKDIR (conf_dirname.c_str (), S_IRWXU);
148       dp = opendir (conf_dirname.c_str ());
149       if (!dp)
150         {
151           fprintf (stderr, "opendir() was failed\n");
152           return false;
153         }
154     }
155   closedir (dp);
156 #endif
157   return true;
158 }
159 
160 /**
161  * Built the full path of the configuration file.
162  */
163 void
get_fullpathname()164 configfile::get_fullpathname ()
165 {
166   if (!conf_filename.empty ())
167     {
168       return;
169     }
170   if (getenv ("XDG_CONFIG_HOME") != NULL)
171     {
172       conf_dirname = getenv ("XDG_CONFIG_HOME");
173       conf_dirname += "/" + CONF_DIR_NAME;
174     }
175   else
176     {
177       conf_dirname = (getenv ("HOME") ? getenv ("HOME") : ".");
178       conf_dirname += "/.config/" + CONF_DIR_NAME;
179     }
180   conf_filename += conf_dirname + "/" + CONF_FILENAME;
181 }
182 
183 /**
184  * Load configuration file in "~/.tlkgames/tecnoballz.conf"
185  */
186 void
load()187 configfile::load ()
188 {
189   resetvalue ();
190   get_fullpathname ();
191   std::cout << conf_filename << std::endl;
192   lispreader *parser = new lispreader ();
193   lisp_object_t *root_obj = parser->lisp_read_file (conf_filename);
194   if (root_obj == NULL)
195     {
196       std::
197       cerr << "lispreader::lisp_read_file (" << conf_filename <<
198            ") was failed" << std::endl;
199       return;
200     }
201   if (root_obj->type == LISP_TYPE_EOF
202       || root_obj->type == LISP_TYPE_PARSE_ERROR)
203     {
204       fprintf (stderr, "configfile::loadconfig() / conf parsing failed\n");
205       return;
206     }
207 
208   if (strcmp
209       (parser->lisp_symbol (parser->lisp_car (root_obj)),
210        "tecnoballz-config") != 0)
211     {
212       fprintf (stderr, "configfile::loadconfig() / conf parsing failed\n");
213       return;
214     }
215 
216   std::string ptStr;
217 
218   if (!parser->read_string ("lang", &ptStr))
219     {
220       language = LANGUAGE_EN;
221     }
222   else
223     {
224       if (ptStr == "fr")
225         {
226           language = LANGUAGE_FR;
227         }
228       else
229         {
230           language = LANGUAGE_EN;
231         }
232     }
233   //exit(0);
234   if (!parser->read_bool ("fullscreen", &handler_display::optionfull))
235     {
236       handler_display::optionfull = -1;
237     }
238 #ifndef SOUNDISOFF
239   if (!parser->read_bool ("sound", &handler_audio::is_audio_enable))
240     {
241       handler_audio::is_audio_enable = true;
242     }
243 #endif
244   if (!parser->read_bool ("verbose", &is_verbose))
245     {
246       is_verbose = false;
247     }
248   if (!parser->read_bool ("absolute_mouse", &absolute_mouse_positioning))
249     {
250       absolute_mouse_positioning = false;
251     }
252 
253 
254   // read window resolution: 1 = 320*240; 2 = 640*480
255   Sint32 res = 0;
256   if (!parser->read_int ("resolution", &res))
257     {
258       res = 2;
259     }
260   resolution = res;
261   if (resolution < 1 || resolution > 2)
262     {
263       resolution = 2;
264     }
265   if (resolution == 2)
266     {
267       has_background = false;
268     }
269   else
270     {
271       has_background = true;
272     }
273   has_background = false;
274 
275   // read number of lifes from 1 to 9
276   if (!parser->read_int ("lifes", &initial_num_of_lifes))
277     {
278       initial_num_of_lifes = 5;
279     }
280   if (initial_num_of_lifes < 1 || initial_num_of_lifes > 9)
281     {
282       initial_num_of_lifes = 5;
283     }
284 
285   // read difficulty DIFFICULTY_EASY, DIFFICULTY_NORMAL,
286   // DIFFICULTY_MEDIUM or DIFFICULTY_HARD
287   if (!parser->read_int ("difficulty", &difficulty_level))
288     {
289       difficulty_level = DIFFICULTY_NORMAL;
290     }
291   if (difficulty_level < DIFFICULTY_EASY
292       || difficulty_level > DIFFICULTY_HARD)
293     {
294       difficulty_level = DIFFICULTY_NORMAL;
295     }
296 
297   //  read number of players from 1 to 6
298   if (!parser->read_int ("players", &number_of_players))
299     {
300       number_of_players = handler_players::MAX_OF_PLAYERS;
301     }
302   if (number_of_players < 1
303       || number_of_players > (Sint32) handler_players::MAX_OF_PLAYERS)
304     {
305       number_of_players = 1;
306     }
307 
308   // read players names
309   std::string sName (6, ' ');
310   char cName[8] = { "......." };
311   for (Uint32 i = 0; i < 6; i++)
312     {
313       sprintf (cName, "player%01d", i + 1);
314       if (parser->read_string (cName, &sName))
315         {
316           strncpy (thePlayers[i], sName.c_str (), 6);
317         }
318     }
319   delete parser;
320 #ifdef TECNOBALLZ_GP2X
321   resolution = 1;
322 #endif
323 }
324 
325 /**
326  * Return current player name, which read from config file
327  * @param playernum Player number from 0 to 5
328  * @return Pointer to a player name
329  */
330 const char *
get_player_name(Uint32 playernum)331 configfile::get_player_name (Uint32 playernum)
332 {
333   if (playernum >= handler_players::MAX_OF_PLAYERS)
334     {
335       playernum = handler_players::MAX_OF_PLAYERS - 1;
336     }
337   return thePlayers[playernum];
338 }
339 
340 /**
341  * Set player name
342  * @param playernum Player number from 0 to 5
343  * @param name Pointer to a string
344  */
345 void
set_player_name(Uint32 playernum,const char * name)346 configfile::set_player_name (Uint32 playernum, const char *name)
347 {
348   if (playernum >= handler_players::MAX_OF_PLAYERS)
349     {
350       playernum = handler_players::MAX_OF_PLAYERS - 1;
351     }
352   strncpy (thePlayers[playernum], name, 6);
353 }
354 
355 /*
356  * Return current language
357  * @return "en" or fr
358  */
359 const char *
get_language()360 configfile::get_language ()
361 {
362   return language_to_string[language];
363 }
364 
365 /**
366  * Save config file "~/.tlkgames/tecnoballz.conf"
367  */
368 void
save()369 configfile::save ()
370 {
371   bool audio;
372 #ifndef SOUNDISOFF
373   audio = handler_audio::is_audio_enable;
374 #else
375   audio = false;
376 #endif
377   if (!check_and_create_dir ())
378     {
379       return;
380     }
381   FILE *config = fopen_data (conf_filename.c_str (), "w");
382   if (config)
383     {
384       fprintf (config, "(tecnoballz-config\n");
385       fprintf (config,
386                "\t;; the following options can be set to #t or #f:\n");
387       fprintf (config, "\t(fullscreen %s)\n",
388                handler_display::optionfull ? "#t" : "#f");
389       fprintf (config, "\t(sound %s)\n", audio ? "#t" : "#f");
390       fprintf (config, "\t(verbose %s)\n", is_verbose ? "#t" : "#f");
391       fprintf (config, "\t(absolute_mouse %s)\n",
392                absolute_mouse_positioning ? "#t" : "#f");
393       fprintf (config, "\n\t;; window size 1 (low-res) or 2 (high-res):\n");
394       fprintf (config, "\t(resolution  %d)\n", resolution);
395       fprintf (config,
396                "\n\t;; difficulty 1 (easy), 2 (hard), 3 (madness) or 4 (suicidal)\n");
397       fprintf (config, "\t(difficulty   %d)\n", difficulty_level);
398       fprintf (config, "\n\t;; number of lifes (1 to 9)\n");
399       fprintf (config, "\t(lifes   %d)\n", initial_num_of_lifes);
400       fprintf (config, "\n\t;; number of players (1 to 6)\n");
401       fprintf (config, "\t(players   %d)\n", number_of_players);
402       fprintf (config, "\n\t;; players names\n");
403       for (Uint32 i = 0; i < handler_players::MAX_OF_PLAYERS; i++)
404         {
405           fprintf (config, "\t(player%i      \"%s\")\n", i + 1,
406                    thePlayers[i]);
407         }
408       fprintf (config, "\n\t;; language en or fr\n");
409       fprintf (config, "\t(lang      ");
410       switch (language)
411         {
412         case LANGUAGE_FR:
413           fprintf (config, "\"fr\")\n");
414           break;
415         default:
416           fprintf (config, "\"en\")\n");
417           break;
418         }
419       fprintf (config, ")\n");
420     }
421 }
422 
423 /**
424  * Open a file
425  * @param fname
426  * @param fmode
427  * @return
428  */
429 FILE *
fopen_data(const char * fname,const char * fmode)430 configfile::fopen_data (const char *fname, const char *fmode)
431 {
432   FILE *fi;
433   fi = fopen (fname, fmode);
434   if (fi == NULL)
435     {
436       fprintf (stderr, "configfile::fopen_data(): Warning: Unable "
437                "to open the file \"%s\" ", fname);
438       if (strcmp (fmode, "r") == 0)
439         {
440           fprintf (stderr, "for read!!!\n");
441         }
442       else if (strcmp (fmode, "w") == 0)
443         {
444           fprintf (stderr, "for write!!!\n");
445         }
446     }
447   return (fi);
448 }
449 
450 /**
451  * Scan command line arguments
452  * @param arg_count the number of arguments
453  * @param arg_values he command line arguments
454  * @return FALSE if exit, TRUE otherwise
455  */
scan_arguments(Sint32 arg_count,char ** arg_values)456 Sint32 configfile::scan_arguments (Sint32 arg_count, char **arg_values)
457 {
458   Sint32 i;
459   for (i = 1; i < arg_count; i++)
460     {
461       if (*arg_values[i] != '-')
462         {
463           continue;
464         }
465 
466       if (!strcmp (arg_values[i], "-h") || !strcmp (arg_values[i], "--help"))
467         {
468           printf ("\noptions:\n");
469           printf ("-h, --help     print Help (this message) and exit\n");
470           printf ("--version      print version information and exit\n");
471           printf ("--full         full screen\n");
472           printf ("--window       windowed mode\n");
473           printf ("--320          game run in a 320*200 window\n");
474           printf ("--640          game run in a 640*400 window\n");
475           printf ("--verbose      verbose mode\n");
476 #ifndef SOUNDISOFF
477           printf ("--nosound      force no sound\n");
478           printf ("--sound        enable sound\n");
479 #endif
480           printf ("--nosync       disable timer\n");
481           printf ("--bg4          Force using a four-color background\n");
482           printf
483           ("--------------------------------------------------------------\n");
484           printf ("keys recognized during the game:\n");
485           printf ("CTRL+S         enable/disable sound\n");
486           printf ("CTRL+D         enable/disable music\n");
487           printf ("CTRL+F         enable/disable sound effects\n");
488           printf ("CTRL+X         finish the play current\n");
489           printf ("CTRL+Q         return to the main menu\n");
490           printf ("CTRL+ESC       quit TecnoballZ\n");
491           printf ("P              enable/disable pause\n");
492           printf ("F              full screen/window mode\n");
493           printf ("\n");
494           return 0;
495         }
496 
497       if (!strcmp (arg_values[i], "--version"))
498         {
499           printf (TECNOBALLZ_VERSION);
500           printf ("\n");
501           printf ("copyright (c) 1991-2014 TLK Games\n");
502           printf ("website: http://linux.tlk.fr/games/TecnoballZ/\n");
503           return 0;
504         }
505 
506       if (!strcmp (arg_values[i], "--full"))
507         {
508           handler_display::optionfull = true;
509           continue;
510         }
511 
512       if (!strcmp (arg_values[i], "--window"))
513         {
514           handler_display::optionfull = false;
515           continue;
516         }
517 
518       if (!strcmp (arg_values[i], "--verbose") ||
519           !strcmp (arg_values[i], "-v"))
520         {
521           is_verbose = true;
522           continue;
523         }
524 
525       if (!strcmp (arg_values[i], "--320"))
526         {
527           resolution = 1;
528           continue;
529         }
530       if (!strcmp (arg_values[i], "--640"))
531         {
532           resolution = 2;
533           continue;
534         }
535 
536       if (!strcmp (arg_values[i], "--nosync"))
537         {
538           handler_display::optionsync = false;
539           continue;
540         }
541 #ifndef SOUNDISOFF
542       if (!strcmp (arg_values[i], "--sound"))
543         {
544           handler_audio::is_audio_enable = true;
545           continue;
546         }
547       if (!strcmp (arg_values[i], "--nosound"))
548         {
549           handler_audio::is_audio_enable = false;
550           continue;
551         }
552 #endif
553       /* use 4 colors background in 640x480 */
554       if (!strcmp (arg_values[i], "--bg4"))
555         {
556           force_4_colors_tiles = true;
557           continue;
558         }
559 
560 #ifdef UNDER_DEVELOPMENT
561       /* start at brick or guard level */
562       if (!strcmp (arg_values[i], "--guard"))
563         {
564           arg_jumper = 3;
565           continue;
566         }
567       if (!strcmp (arg_values[i], "--brick"))
568         {
569           arg_jumper = 1;
570           continue;
571         }
572 #endif
573     }
574   return 1;
575 }
576 
577 char
578 configfile::stringname[7] = "YANIS ";
579