00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "race.h"
00019 #include "options.h"
00020 #include "macros.h"
00021 #include "pace.h"
00022 #include "fs.h"
00023 #include "utils.h"
00024 #include "logging.h"
00025 #include <assert.h>
00026 #include <ctype.h>
00027 #include <errno.h>
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <SDL.h>
00032
00033 #define ENVIRON_DATADIR ("BARIS_DATA")
00034 #define ENVIRON_SAVEDIR ("BARIS_SAVE")
00035
00036 #if CONFIG_WIN32
00037 # define DEFAULT_DATADIR ("c:/" PACKAGE_TARNAME )
00038 # define DEFAULT_SAVEDIR ("c:/" PACKAGE_TARNAME "/savedat")
00039 #elif CONFIG_LINUX
00040 # define DEFAULT_DATADIR CONFIG_DATADIR
00041 # define DEFAULT_SAVEDIR (".")
00042 #elif CONFIG_MACOSX
00043 # define DEFAULT_DATADIR CONFIG_DATADIR
00044 # define DEFAULT_SAVEDIR (".")
00045 #endif
00046
00047
00048 #ifndef DEFAULT_DATADIR
00049 # define DEFAULT_DATADIR (".")
00050 #endif
00051
00052 #ifndef DEFAULT_SAVEDIR
00053 # define DEFAULT_SAVEDIR (".")
00054 #endif
00055
00056 #if !HAVE_GETENV
00057 # if HAVE_SDL_GETENV
00058 # define getenv SDL_getenv
00059 # else
00060 # warn I don't know a way to read environment on this system
00061 # define getenv(a) (NULL)
00062 # endif
00063 #endif
00064
00065 game_options options;
00066
00067 LOG_DEFAULT_CATEGORY(config);
00068
00069
00070 static struct {
00071 char *name;
00072 char **dest;
00073 char *def_val;
00074 } env_vars[] = {
00075 {ENVIRON_DATADIR, &options.dir_gamedata, DEFAULT_DATADIR},
00076 {ENVIRON_SAVEDIR, &options.dir_savegame, DEFAULT_SAVEDIR},
00077 };
00078
00079 static struct {
00080 char *name;
00081 void *dest;
00082 char *type;
00083 int need_alloc;
00084 char *comment;
00085 } config_strings[] = {
00086 {"datadir", &options.dir_gamedata, "%1024[^\n\r]", 1025,
00087 "Path to directory with game data files." },
00088 {"audio", &options.want_audio, "%u", 0,
00089 "Set to 0 if you don't want audio in game." },
00090 {"nofail", &options.want_cheats, "%u", 0,
00091 "Set to 1 if you want every mission step check to succeeed." },
00092 {"intro", &options.want_intro, "%u", 0,
00093 "Set to 0 if do not want intro displayed at startup." },
00094 {"fullscreen", &options.want_fullscreen, "%u", 0,
00095 "Set to 1 if you want (ugly) full screen game." },
00096 {"debuglevel", &options.want_debug, "%u", 0,
00097 "Set to positive values to increase debugging verbosity" },
00098 };
00099
00100
00101
00102
00103
00104 static void
00105 usage (int fail)
00106 {
00107 fprintf(stderr, "usage: raceintospace [options...]\n"
00108 "options: -a -i -f -v -n\n"
00109 "\t-v verbose mode\n\t\tadd this several times to get to DEBUG level\n"
00110 "\t-f fullscreen mode\n\t\tugly\n"
00111 );
00112 exit((fail) ? EXIT_FAILURE : EXIT_SUCCESS);
00113 }
00114
00115 static void
00116 shift_argv(char ** argv, int len, int shift)
00117 {
00118 int i = 0;
00119
00120 assert(shift >= 0);
00121 assert(len >= 0);
00122
00123 for (i = shift; i < len; ++i)
00124 {
00125 argv[i - shift] = argv[i];
00126 argv[i] = NULL;
00127 }
00128 }
00129
00130 static int
00131 skip_past_newline(FILE * f)
00132 {
00133 assert(f);
00134 return fscanf(f, "%*[^\r\n] ");
00135 }
00136
00137 static int
00138 parse_var_value(FILE * f, int index)
00139 {
00140 char format[128];
00141 int need_alloc;
00142 int res = 0, chars = 0, i = index;
00143 void **target;
00144
00145 assert(f);
00146 assert(i >= 0 && i < (int) ARRAY_LENGTH(config_strings));
00147
00148 target = config_strings[i].dest;
00149 need_alloc = config_strings[i].need_alloc;
00150 if (need_alloc)
00151 *target = xrealloc(*target, need_alloc);
00152
00153 sprintf(format, " %s%%n", config_strings[i].type);
00154 res = fscanf(f, format, *target, &chars);
00155
00156 if (res < 1)
00157 return -1;
00158
00159 if (need_alloc && chars < need_alloc)
00160 *target = xrealloc(*target, chars + 1);
00161
00162 return 0;
00163 }
00164
00165
00166
00167
00168
00169
00170
00171 static int
00172 read_config_file(void)
00173 {
00174 FILE *f = open_savedat("config", "rt");
00175 char config_word[32 + 1];
00176 int err = 0, res = 0, i = 0;
00177 char c[2];
00178
00179 if (!f)
00180 {
00181 WARNING1("could not open config file");
00182 return -1;
00183 }
00184
00185 while (1)
00186 {
00187
00188 if ((res = fscanf(f, " %1[#]", c)) == 1)
00189 goto skip_newline;
00190
00191 if (res == EOF)
00192 break;
00193
00194
00195
00196 res = fscanf(f, "%32[a-zA-Z_-]", config_word);
00197
00198
00199 if (res == 1)
00200 {
00201 for (i = 0; i < (int) ARRAY_LENGTH(config_strings); ++i)
00202 {
00203 if (strcmp(config_word, config_strings[i].name) == 0)
00204 {
00205 res = parse_var_value(f, i);
00206 if (res != 0 && feof(f))
00207 goto skip_newline;
00208 else if (res != 0)
00209 {
00210 NOTICE2("wrong value type for variable `%s'",
00211 config_word);
00212 goto skip_newline;
00213 }
00214 else
00215 break;
00216 }
00217 }
00218
00219
00220 if (i == (int) ARRAY_LENGTH(config_strings))
00221 {
00222 NOTICE2("unknown variable in file `%s'",
00223 config_word);
00224 goto skip_newline;
00225 }
00226 }
00227 else if (res == EOF)
00228 break;
00229 else
00230 {
00231 NOTICE1("expected variable name");
00232 goto skip_newline;
00233 }
00234
00235 skip_newline:
00236 if (EOF == skip_past_newline(f))
00237 break;
00238 }
00239
00240 err = !feof(f);
00241
00242 fclose(f);
00243
00244 return -err;
00245 }
00246
00247 static int
00248 write_default_config(void)
00249 {
00250 int i = 0;
00251 int err = 0;
00252 FILE *f = NULL;
00253
00254 create_save_dir();
00255 f = open_savedat("config", "wt");
00256 if (!f)
00257 {
00258 WARNING4("can't write defaults to file `%s/%s': %s\n",
00259 options.dir_savegame, "config", strerror(errno));
00260 return -1;
00261 }
00262 else
00263 NOTICE3("written defaults to file `%s/%s'",
00264 options.dir_savegame, "config");
00265
00266 fprintf(f, "# This is template configuration file for %s\n",
00267 PACKAGE_STRING);
00268 fprintf(f, "# Comments start with '#' sign and span whole line.\n");
00269 fprintf(f, "# Non comment lines should look like:\n");
00270 fprintf(f, "# variable_name variable_value\n\n");
00271 for (i = 0; i < (int) ARRAY_LENGTH(config_strings); ++i)
00272 fprintf(f, "# %s\n# %s\n\n",
00273 config_strings[i].comment, config_strings[i].name);
00274 err = ferror(f);
00275 if (err)
00276 WARNING2("read error: %s", strerror(errno));
00277 fclose(f);
00278 return err;
00279 }
00280
00281
00282
00283 static char *
00284 get_homedir(void)
00285 {
00286 char *s = NULL;
00287
00288 if ((s = getenv("HOME")))
00289 {
00290 return xstrdup(s);
00291 }
00292 #if CONFIG_WIN32
00293 if ((s = getenv("HOMEPATH")))
00294 {
00295 char *s2 = NULL;
00296
00297 if ((s2 = getenv("HOMEDRIVE")) || (s2 = getenv("HOMESHARE")))
00298 {
00299 return xstrcat2(s2, s);
00300 }
00301 }
00302 if ((s = getenv("USERPROFILE")))
00303 {
00304 return xstrdup(s);
00305 }
00306 #endif
00307 return NULL;
00308 }
00309
00310 static void
00311 fixpath_options(void)
00312 {
00313 fix_pathsep(options.dir_savegame);
00314 fix_pathsep(options.dir_gamedata);
00315 }
00316
00317
00318
00319
00320
00321
00322
00323 int
00324 setup_options(int argc, char *argv[])
00325 {
00326 char *str = NULL;
00327 int pos, i;
00328
00329
00330 for (i = 0; i < (int) ARRAY_LENGTH(env_vars); ++i)
00331 {
00332 if ((str = getenv(env_vars[i].name)))
00333 *env_vars[i].dest = xstrdup(str);
00334 else if (strcmp(env_vars[i].name, ENVIRON_SAVEDIR) == 0
00335 && (str = get_homedir()))
00336 {
00337 size_t len = strlen(str) + strlen(PACKAGE_TARNAME) + 3;
00338
00339 *env_vars[i].dest = xmalloc(len);
00340 sprintf(*env_vars[i].dest, "%s/.%s", str, PACKAGE_TARNAME);
00341 free(str);
00342 }
00343 else
00344 *env_vars[i].dest = xstrdup(env_vars[i].def_val);
00345 }
00346
00347 options.want_audio = 1;
00348 options.want_intro = 1;
00349 options.want_cheats = 0;
00350 options.want_fullscreen = 0;
00351
00352 fixpath_options();
00353
00354
00355 if (read_config_file() < 0)
00356
00357 write_default_config();
00358
00359
00360 for (pos = 1; pos < argc; ++pos)
00361 {
00362 str = argv[pos];
00363
00364 if (str[0] != '-')
00365 continue;
00366
00367 if (!str[1])
00368 continue;
00369
00370 if (strcmp(str, "--") == 0)
00371 {
00372 shift_argv(argv + pos, argc - pos, 1);
00373 argc--;
00374 break;
00375 }
00376
00377
00378 if (strcmp(str, "-h") == 0)
00379 usage(0);
00380 else if (strcmp(str, "-i") == 0)
00381 options.want_intro = 0;
00382 else if (strcmp(str, "-n") == 0)
00383 options.want_cheats = 1;
00384 else if (strcmp(str, "-a") == 0)
00385 options.want_audio = 0;
00386 else if (strcmp(str, "-f") == 0)
00387 options.want_fullscreen = 1;
00388 else if (strcmp(str, "-v") == 0)
00389 options.want_debug++;
00390 else
00391 {
00392 ERROR2("unknown option %s", str);
00393 usage(1);
00394 }
00395
00396 shift_argv(argv + pos, argc - pos, 1);
00397 argc--;
00398 pos--;
00399 }
00400
00401
00402 for (pos = 1; pos < argc; ++pos)
00403 {
00404
00405 char name[32 + 1], *value;
00406 int offset = 0;
00407 int fields = 0;
00408
00409 fields = sscanf(argv[pos], "%32[A-Z_]=%n", name, &offset);
00410
00411
00412 if (fields < 1)
00413 continue;
00414
00415 value = argv[pos] + offset;
00416
00417 for (i = 0; i < (int) ARRAY_LENGTH(env_vars); ++i)
00418 {
00419 if (strcmp(name, env_vars[i].name) == 0)
00420 {
00421 free(*env_vars[i].dest);
00422 *env_vars[i].dest = xstrdup(value);
00423 break;
00424 }
00425 }
00426
00427 if (i == (int) ARRAY_LENGTH(env_vars))
00428 WARNING2("unsupported command line variable `%s'", name);
00429
00430
00431 shift_argv(argv + pos, argc - pos, 1);
00432
00433
00434
00435
00436
00437 pos--;
00438 argc--;
00439 }
00440
00441 fixpath_options();
00442
00443 return argc;
00444 }
00445
00446