1 /*
2 * IceBreaker
3 * Copyright (c) 2001-2002 Matthew Miller <mattdm@mattdm.org> and
4 * Enrico Tassi <gareuselesinge@infinito.it>
5 *
6 * <http://www.mattdm.org/icebreaker/>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc., 59
20 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24 #include <SDL.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <stdlib.h>
29 #include "icebreaker.h"
30 #include "globals.h"
31 #include "icebreaker.h"
32 #include "options.h"
33 #include "themes.h"
34 #include "stdarg.h"
35
36 GameOptionsType options;
37 GameOptionsType commandline;
38
39 GameFlagsType gameflags;
40
41 static int findflag(int argc,char** argv,char* option);
42 static void printversion(void);
43 static void printhelp(void);
44 static void printthemelist(void);
45
46 #ifdef WIN32
47 # include <windows.h>
48 typedef struct
49 {
50 HKEY hK;
51 DWORD line;
52 }reg_file;
53 # define ICEBREAKER_KEY "Software\\IceBreaker"
54 # define OPTFILEHANDLER reg_file
55 #else
56 # define OPTFILEHANDLER FILE
57 #endif
58
59
60 OPTFILEHANDLER *openoptionfile(char* filename,char* mode);
61 void closeoptionfile(OPTFILEHANDLER *f);
62 char* readoptionline(char* buffer,int len,OPTFILEHANDLER *f);
63 int writeoptionline(OPTFILEHANDLER *f,char* format,...);
64
65 #define FLAGVERSION "-v"
66 #define FLAGVERSIONLONG "--version"
67 #define FLAGHELP "-h"
68 #define FLAGHELPLONG "--help"
69 #define FLAGSOUND "-s"
70 #define FLAGSOUNDLONG "--sound"
71 #define FLAGNOSOUND "-n"
72 #define FLAGNOSOUNDLONG "--nosound"
73 #define FLAGFULLSCREEN "-f"
74 #define FLAGFULLSCREENLONG "--fullscreen"
75 #define FLAGWINDOWED "-w"
76 #define FLAGWINDOWEDLONG "--windowed"
77 #define FLAGTHEME "-t"
78 #define FLAGTHEMELONG "--theme"
79 #define FLAGLISTTHEMES "-l"
80 #define FLAGLISTTHEMESLONG "--listthemes"
81 #define FLAGBENCHMARK "-b"
82 #define FLAGBENCHMARKLONG "--benchmark"
83
setdefaultoptions(void)84 void setdefaultoptions(void)
85 {
86 options.sound=SOUNDON;
87 options.autopause=AUTOPAUSEOFF;
88 options.difficulty=NORMAL;
89 options.fullscreen=FULLSCREENOFF;
90 strcpy(options.theme,"linux");
91 }
92
readoptions(void)93 int readoptions(void)
94 {
95 OPTFILEHANDLER * optionfile;
96 char linebuf[50];
97 char filename[255]; // fix -- use defined OS constant
98 char optbuf[21];
99 char valbuf[10+MAXTHEMENAMELENGTH];
100 char scanformat[20];
101 int i;
102
103 setdefaultoptions();
104
105 snprintf(filename,sizeof(filename),"%s/%s",homedir,OPTIONFILE);
106
107 optionfile=openoptionfile(filename,"r");
108 if (optionfile==NULL)
109 {
110 fprintf(stderr, OPTIONFILE " doesn't exist.\nWelcome to IceBreaker.\n");
111 return true;
112 }
113
114 while(readoptionline(linebuf,50,optionfile))
115 {
116 for (i=0;i<50;i++)
117 {
118 if (linebuf[i]=='\0') break;
119 linebuf[i]=tolower(linebuf[i]);
120 }
121
122 sprintf(scanformat,"%%20s %%%ds",10+MAXTHEMENAMELENGTH);
123 if (sscanf(linebuf,"%19s %9s",optbuf,valbuf)==2)
124 {
125 if (!strcmp(optbuf,"sound"))
126 {
127 if (!strcmp(valbuf,"on"))
128 options.sound=SOUNDON;
129 else if (!strcmp(valbuf,"off"))
130 options.sound=SOUNDOFF;
131 }
132 else if (!strcmp(optbuf,"autopause"))
133 {
134 if (!strcmp(valbuf,"on"))
135 options.autopause=AUTOPAUSEON;
136 else if (!strcmp(valbuf,"off"))
137 options.autopause=AUTOPAUSEOFF;
138 }
139 else if (!strcmp(optbuf,"fullscreen"))
140 {
141 if (!strcmp(valbuf,"off"))
142 options.fullscreen=FULLSCREENOFF;
143 else if (!strcmp(valbuf,"on"))
144 options.fullscreen=FULLSCREENON;
145 else if (!strcmp(valbuf,"always"))
146 options.fullscreen=FULLSCREENALWAYS;
147 }
148 else if (!strcmp(optbuf,"difficulty"))
149 {
150 if (!strcmp(valbuf,"normal"))
151 options.difficulty=NORMAL;
152 else if (!strcmp(valbuf,"hard"))
153 options.difficulty=HARD;
154 else if (!strcmp(valbuf,"easy"))
155 options.difficulty=EASY;
156 }
157 else if (!strcmp(optbuf,"theme"))
158 {
159 snprintf(options.theme,sizeof(options.theme),"%s",valbuf);
160 }
161 // FIX: add username
162 }
163 }
164
165 closeoptionfile(optionfile);
166
167 return false;
168 }
169
writeoptions(void)170 int writeoptions(void)
171 {
172 OPTFILEHANDLER * optionfile;
173 char filename[255];
174 snprintf(filename,sizeof(filename),"%s/%s",homedir,OPTIONFILE);
175
176 optionfile=openoptionfile(filename,"w");
177 if (optionfile==NULL)
178 {
179 fprintf(stderr, "Can't write to " OPTIONFILE ".\n");
180 return true;
181 }
182
183 writeoptionline(optionfile,"# Icebreaker config file 1.0\n#\n");
184 writeoptionline(optionfile,"# Separate keywords from values by whitespace. Not case sensitive.\n#\n");
185 writeoptionline(optionfile,"# %s/" OPTIONFILE " will be overwritten automatically.\n#\n",homedir);
186
187 writeoptionline(optionfile,"\n# Change this if the crashing noise annoys your neighbors.\n");
188 if (options.sound==SOUNDON)
189 writeoptionline(optionfile,"Sound On\n");
190 else if (options.sound==SOUNDOFF)
191 writeoptionline(optionfile,"Sound Off\n");
192
193 writeoptionline(optionfile,"\n# AutoPause makes the game pause when the window is out of focus.\n");
194 if (options.autopause==AUTOPAUSEON)
195 writeoptionline(optionfile,"AutoPause On\n");
196 else if (options.autopause==AUTOPAUSEOFF)
197 writeoptionline(optionfile,"AutoPause Off\n");
198
199 writeoptionline(optionfile,"\n# Set FullScreen to Always if you want it that way every time.\n");
200 writeoptionline(optionfile,"# On will use full screen mode once, but then change back to Off.\n");
201 if (options.fullscreen==FULLSCREENOFF || options.fullscreen==FULLSCREENON)
202 writeoptionline(optionfile,"FullScreen Off\n");
203 else if (options.fullscreen==FULLSCREENALWAYS)
204 writeoptionline(optionfile,"FullScreen Always\n");
205
206 writeoptionline(optionfile,"\n# Normal is the best way to play. Easy is okay to get started,\n");
207 writeoptionline(optionfile,"# but you won't get very high scores. Hard is for those who really\n");
208 writeoptionline(optionfile,"# want a challenge, but scores only slightly higher than normal.\n");
209
210
211 if (options.difficulty==NORMAL)
212 writeoptionline(optionfile,"Difficulty Normal\n");
213 else if (options.difficulty==HARD)
214 writeoptionline(optionfile,"Difficulty Hard\n");
215 else if (options.difficulty==EASY)
216 writeoptionline(optionfile,"Difficulty Easy\n");
217
218
219 writeoptionline(optionfile,"\n# Themes provide an easy way to select (or tweak!) the appearance\n");
220 writeoptionline(optionfile,"# and sound of the game. Select from " THEMEFILEEXTENSION " files in the game data\n");
221 writeoptionline(optionfile,"# directory. Check the docs for info on creating your own themes, too.\n");
222
223 writeoptionline(optionfile,"Theme %s\n",options.theme);
224
225 closeoptionfile(optionfile);
226
227 return false;
228 }
229
parsecommandline(int argc,char ** argv)230 int parsecommandline(int argc, char** argv)
231 {
232 int i;
233
234 commandline.sound=SOUNDON;
235 commandline.autopause=AUTOPAUSEOFF;
236 commandline.difficulty=NORMAL;
237 commandline.fullscreen=FULLSCREENUNKNOWN;
238 *(commandline.theme)='\0'; // makes this ""
239
240 if ( findflag(argc,argv,FLAGVERSION) || findflag(argc,argv,FLAGVERSIONLONG) )
241 {
242 printversion();
243 return 1;
244 }
245
246 if ( findflag(argc,argv,FLAGHELP) || findflag(argc,argv,FLAGHELPLONG) )
247 {
248 printhelp();
249 return 2;
250 }
251
252 if ( findflag(argc,argv,FLAGLISTTHEMES) || findflag(argc,argv,FLAGLISTTHEMESLONG) )
253 {
254 printthemelist();
255 return 3;
256 }
257
258 if ( findflag(argc,argv,FLAGNOSOUND) || findflag(argc,argv,FLAGNOSOUNDLONG) )
259 commandline.sound=SOUNDOFF;
260
261 if ( findflag(argc,argv,FLAGBENCHMARK) || findflag(argc,argv,FLAGBENCHMARKLONG) )
262 gameflags.benchmarkmode=true;
263 else
264 gameflags.benchmarkmode =false;
265
266
267 if ( findflag(argc,argv,FLAGSOUND) || findflag(argc,argv,FLAGSOUNDLONG) )
268 {
269 if (commandline.sound==SOUNDOFF)
270 {
271 fprintf(stderr,"You asked for sound to be both on and off. Sorry Schrodinger, we can't do that.\n"
272 "We'll assume \'off\' is what you really meant.\n");
273 }
274 else
275 {
276 commandline.sound=SOUNDON; // redundant. but more clear. :)
277 }
278 }
279
280
281 if ( findflag(argc,argv,FLAGFULLSCREEN) || findflag(argc,argv,FLAGFULLSCREENLONG) )
282 commandline.fullscreen=FULLSCREENON;
283
284 if ( findflag(argc,argv,FLAGWINDOWED) || findflag(argc,argv,FLAGWINDOWEDLONG) )
285 {
286 if (commandline.fullscreen==FULLSCREENON)
287 {
288 fprintf(stderr,"You asked for both fullscreen and windowed mode. You're mad! Mad, I tell you.\n"
289 "We'll assume \'windowed\' is what you really meant.\n");
290 }
291 commandline.fullscreen=FULLSCREENOFF;
292 }
293
294 // find theme name -- can't use findflag because this option
295 // takes a parameter and that function isn't that smart.
296 for(i=1; i<argc; i++)
297 {
298 if (strncmp(argv[i],FLAGTHEME,strlen(FLAGTHEME)) == 0)
299 {
300 if (strlen(argv[i])==strlen(FLAGTHEME))
301 {
302 fprintf(stderr,"Warning: " FLAGTHEME " option given but no theme specified. Perhaps this is because you\n"
303 " wrote \"" FLAGTHEME " themename\" or \"" FLAGTHEME "=themename\". Sorry, I'm too dumb to understand\n"
304 " that -- you'll have to use the form " FLAGTHEME "themename or " FLAGTHEMELONG "=themename. As it\n"
305 " is, I'm just going to ignore you.\n");
306 }
307 else if (strlen(argv[i]) > MAXTHEMENAMELENGTH+strlen(FLAGTHEME))
308 {
309 fprintf(stderr,"Warning: the theme name you've given is too long. The maximum is %d characters.\n"
310 " Not because I don't understand long filenames, by the way -- it's so the\n"
311 " options menu looks nice. I'm very fussy about my appearance.\n",MAXTHEMENAMELENGTH);
312 }
313 else
314 {
315 // fix -- we should probably search for malicious characters here.
316 snprintf(commandline.theme,sizeof(commandline.theme),"%s",argv[i]+strlen(FLAGTHEME));
317 }
318 }
319 else if (strncmp(argv[i],FLAGTHEMELONG "=" ,strlen(FLAGTHEMELONG "=")) == 0)
320 {
321 if (strlen(argv[i])==strlen(FLAGTHEMELONG "="))
322 {
323 fprintf(stderr,"Warning: " FLAGTHEMELONG "= what exactly? The theme name has to go right after the equals\n"
324 " sign or else I will ignore you. Which is what I'm doing now. La la la la la la\n"
325 " la la la I can't hear you la la la....\n");
326 }
327 else if (strlen(argv[i]) > MAXTHEMENAMELENGTH+strlen(FLAGTHEMELONG "="))
328 {
329 fprintf(stderr,"Warning: the theme name you've given is too long. The maximum is %d characters.\n"
330 " Not because I don't understand long filenames, by the way -- it's so the\n"
331 " options menu looks nice. I'm very fussy about my appearance.\n",MAXTHEMENAMELENGTH);
332 }
333 else
334 {
335 // fix -- we should probably search for malicious characters here.
336 snprintf(commandline.theme,sizeof(commandline.theme),"%s",argv[i]+strlen(FLAGTHEMELONG "="));
337 }
338 }
339 else if (strncmp(argv[i],FLAGTHEMELONG,strlen(FLAGTHEMELONG)) == 0)
340 {
341 fprintf(stderr,"Warning: the " FLAGTHEMELONG " parameter needs to be followed directly by an \'=\' and\n"
342 " then the name of the theme you want. Like, \"" FLAGTHEMELONG "=linux\". Otherwise, I\n"
343 " will pretend to not understand you.\n");
344 }
345
346
347 }
348
349 return 0;
350 }
351
findflag(int argc,char ** argv,char * option)352 int findflag(int argc,char** argv, char* option)
353 {
354 int i;
355 for (i=1; i<argc; i++)
356 {
357 //printf("[%d] = %s\n",i,argv[i]);
358 if (strcmp(argv[i],option) == 0)
359 return true;
360 }
361 return false;
362 }
363
printversion()364 void printversion()
365 {
366 printf("\nIceBreaker v%d.%d.%d Copyright 2000-2002 Matthew Miller, et al.\n\n",VERMAJOR,VERMINOR,VERSUB);
367
368 printf("Written by Matthew Miller with additional code and help from Enrico Tassi\n"
369 "and others. Like to contribute to the project? Good code, graphics, sounds,\n"
370 "and even just advice are all appreciated and often even accepted.\n\n"
371 "Visit the IceBreaker web site at <http://www.mattdm.org/icebreaker/> for more\n"
372 "information or to download the latest version.\n\n"
373 "This program is free software; you can redistribute it and/or modify it\n"
374 "under the terms of the GNU General Public License as published by the Free\n"
375 "Software Foundation; either version 2 of the License, or (at your option)\n"
376 "any later version. IceBreaker uses the SDL library, which is distributed\n"
377 "under the GNU LGPL; see <http://www.libsdl.org/> for details.\n\n");
378 }
379
printhelp()380 void printhelp()
381 {
382 printf("Usage: icebreaker [OPTION...]\n");
383 printf("%20s, %-15s %-35s\n",FLAGNOSOUND,FLAGNOSOUNDLONG,"disable game sounds");
384 printf("%20s, %-15s %-35s\n",FLAGFULLSCREEN,FLAGFULLSCREENLONG,"start fullscreen if possible");
385 printf("%20s, %-15s %-35s\n",FLAGWINDOWED,FLAGWINDOWEDLONG,"start windowed (resets \"Always\" option)");
386 printf("%20s, %-15s %-35s\n",FLAGVERSION,FLAGVERSIONLONG,"display version and copyright info");
387 printf("%20s, %-15s %-35s\n",FLAGHELP,FLAGHELPLONG,"display this help screen");
388 printf("%20s, %-15s %-35s\n",FLAGLISTTHEMES,FLAGLISTTHEMESLONG,"list available themes");
389 printf("%18s%s,\n","",FLAGTHEME "themename");
390 printf("%18s %-18s %-35s\n","",FLAGTHEMELONG "=themename","select theme");
391
392 printf("\nFor game play help, see the included documentation, the in-game help, or the\n"
393 "web site at <http://www.mattdm.org/icebreaker/>\n\n");
394 }
395
printthemelist()396 void printthemelist()
397 {
398 char** themelist;
399 int themecount;
400 int t;
401
402 printf("I've found the following themes:\n\n");
403
404 themecount=getthemenames(&themelist);
405 if (themecount==0)
406 {
407 printf(" (none)\n");
408 printf("\nThis probably means IceBreaker was installed incorrectly.\n");
409 }
410 else
411 {
412 for (t=0;t<themecount;t++)
413 printf(" %s\n",themelist[t]);
414
415 printf("\nAdditionally, you can use \'random\', which does about what you'd expect.\n");
416 }
417 freethemenames(&themelist,themecount);
418 }
419
openoptionfile(char * filename,char * mode)420 OPTFILEHANDLER *openoptionfile(char* filename,char* mode)
421 {
422 OPTFILEHANDLER *rc = NULL;
423
424 #ifdef WIN32
425 DWORD res,err;
426 rc = (OPTFILEHANDLER *)malloc(sizeof(OPTFILEHANDLER));
427 rc->line = 0;
428 err = RegCreateKeyExA(HKEY_CURRENT_USER,ICEBREAKER_KEY,0,NULL,REG_OPTION_NON_VOLATILE,KEY_READ|KEY_WRITE,NULL,&(rc->hK),&res);
429 if(err != ERROR_SUCCESS)
430 {
431 fprintf(stderr,"Unable to open the regisrty\n");
432 // fix - handle better
433 }
434 if (res == REG_CREATED_NEW_KEY)
435 {
436 closeoptionfile(rc);
437 rc = NULL;
438 }
439 #else
440 rc = fopen(filename,mode);
441 #endif
442
443 return rc;
444 }
445
closeoptionfile(OPTFILEHANDLER * f)446 void closeoptionfile(OPTFILEHANDLER *f)
447 {
448 #ifdef WIN32
449 RegCloseKey(f->hK);
450 free(f);
451 #else
452 fclose(f);
453 #endif
454 }
455
readoptionline(char * buffer,int len,OPTFILEHANDLER * f)456 char* readoptionline(char* buffer,int len,OPTFILEHANDLER *f)
457 {
458 char* rc = NULL;
459
460 #ifdef WIN32
461 DWORD err;
462 char name[50],value[50];
463 DWORD name_len = 50, value_len = 50, type;
464
465 err = RegEnumValueA(f->hK,f->line,name,&name_len,NULL,&type,value,&value_len);
466 if(err == ERROR_NO_MORE_ITEMS )
467 {
468 rc = NULL;
469 }
470 else if ( err != ERROR_SUCCESS )
471 {
472 rc = NULL;
473 fprintf(stderr,"Unable to read the registry.\n");
474 // fix - handle better
475 }
476 else if ( type != REG_SZ )
477 {
478 rc = NULL;
479 fprintf(stderr,"Registry key has a strange type.\n");
480 }
481 else
482 {
483 if(name_len + value_len > len)
484 {
485 fprintf(stderr,"Registry key is too long for buffer\n");
486 return NULL;
487 }
488 snprintf(buffer,len,"%s %s",name,value);
489 rc = buffer;
490 }
491
492 f->line ++;
493 #else
494 rc = fgets(buffer,len,f);
495 #endif
496 return rc;
497 }
498
writeoptionline(OPTFILEHANDLER * f,char * fmt,...)499 int writeoptionline(OPTFILEHANDLER *f,char* fmt,...)
500 {
501 int rc = 0;
502
503 #ifdef WIN32
504 DWORD err;
505 char name[50],value[50],line[100];
506 DWORD value_len = 0, i;
507
508 va_list args;
509 va_start(args, fmt);
510 vsnprintf(line,100,fmt,args);
511 va_end(args);
512
513 if( line[0] == '#' || line[0] == '\n')
514 {
515 return 0; //skip comments
516 }
517
518 else
519
520 {
521 rc = strlen(line) + 1;
522 //erase \n, they could be in the middle ??
523 for(i = 0 ; line[i] != '\0'; i++)
524 if(line[i] == '\n')
525 line[i] = ' ';
526 // find the separator
527 for(i = 0 ; line[i] != '\0' && line[i]!=' ' ; i++);
528
529 if(line[i+1] != '\0' && line[i] == ' ')
530 {
531 line[i] = '\0';
532 snprintf(name,50,"%s",line);
533 snprintf(value,50,"%s",&line[i+1]);
534 value_len = sizeof(char) * (strlen(value)+1);
535 err = RegSetValueExA(f->hK,name,0,REG_SZ,value,value_len);
536 if(err != ERROR_SUCCESS)
537 {
538 rc = 0;
539 fprintf(stderr,"Unable to write the registry\n");
540 // fix - handle better
541 }
542 }
543
544 }
545
546 #else
547 va_list args;
548 va_start(args, fmt);
549 rc = vfprintf(f,fmt,args);
550 va_end(args);
551 #endif
552 return rc;
553 }
554