00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "fs.h"
00025 #include "options.h"
00026 #include "pace.h"
00027 #include "utils.h"
00028 #include "logging.h"
00029 #include <assert.h>
00030 #include <stdio.h>
00031 #include <string.h>
00032 #include <sys/stat.h>
00033 #include <stdarg.h>
00034 #include <stdlib.h>
00035 #include <ctype.h>
00036
00037
00038 #ifndef PATHSEP
00039 # if CONFIG_WIN32
00040 # define PATHSEP '\\'
00041 # else
00042 # define PATHSEP '/'
00043 # endif
00044 #endif
00045
00046
00047 #if HAVE_MKDIR
00048 # if MKDIR_TAKES_ONE_ARG
00049
00050 # define mkdir(a, b) mkdir(a)
00051 # endif
00052 #else
00053 # if HAVE__MKDIR
00054
00055 # define mkdir(a, b) _mkdir(a)
00056 # else
00057 # error "Don't know how to create a directory on this system."
00058 # endif
00059 #endif
00060
00061
00062 #if HAVE_DIRENT_H
00063 # include <dirent.h>
00064 # define NAMLEN(dirent) strlen((dirent)->d_name)
00065 #else
00066 # define dirent direct
00067 # define NAMLEN(dirent) (dirent)->d_namlen
00068 # if HAVE_SYS_NDIR_H
00069 # include <sys/ndir.h>
00070 # endif
00071 # if HAVE_SYS_DIR_H
00072 # include <sys/dir.h>
00073 # endif
00074 # if HAVE_NDIR_H
00075 # include <ndir.h>
00076 # endif
00077 #endif
00078
00079 LOG_DEFAULT_CATEGORY(filesys);
00080
00081 static DIR *save_dir;
00082
00083
00084 typedef struct file {
00085 FILE *handle;
00086 char *path;
00087 } file;
00088
00089
00090
00091
00092
00093 void
00094 fix_pathsep(char *name)
00095 {
00096 #if 0
00097 for (; *name; ++name)
00098 if (*name == '/')
00099 *name = PATHSEP;
00100 #endif
00101 }
00102
00103 static FILE*
00104 try_fopen(const char *fname, const char *mode)
00105 {
00106 FILE* fp = NULL;
00107 assert(fname);
00108 assert(mode);
00109 TRACE3("trying to open `%s' (mode %s)", fname, mode);
00110
00111 fp = fopen(fname, mode);
00112
00113
00114 if (!fp && errno != ENOENT)
00115 {
00116 int esave = errno;
00117 WARNING3("can't access file `%s': %s", fname, strerror(errno));
00118 errno = esave;
00119 }
00120
00121 return fp;
00122 }
00123
00124
00125 static file
00126 s_open_helper(const char *base, const char *name, const char *mode, ...)
00127 {
00128 FILE *fh = NULL;
00129 file f = {NULL, NULL};
00130 int serrno;
00131 char *p = NULL;
00132 char *cooked = xmalloc(1024);
00133 size_t len = 1024, len2 = 0;
00134 size_t len_base = strlen(base), len_name = strlen(name);
00135 va_list ap;
00136
00137 assert(base);
00138 assert(name);
00139 assert(mode);
00140
00141 va_start(ap, mode);
00142 for (p = va_arg(ap, char *); p; p = va_arg(ap, char *))
00143 {
00144 char *s = NULL;
00145 int was_upper = 0;
00146 size_t len_p = strlen(p);
00147
00148 len2 = len_base + len_name + len_p + 3;
00149 if (len2 > len)
00150 cooked = xrealloc(cooked, (len = len2));
00151
00152 sprintf(cooked, "%s/%s/%s", base, p, name);
00153 fix_pathsep(cooked);
00154
00155 fh = try_fopen(cooked, mode);
00156 if (fh)
00157 break;
00158
00159
00160 for (s = cooked + len_base + len_p + 2; *s; ++s)
00161 if (isupper(*s))
00162 {
00163 was_upper |= 1;
00164 *s = tolower(*s);
00165 }
00166
00167 if (was_upper)
00168 fh = try_fopen(cooked, mode);
00169 if (fh)
00170 break;
00171 }
00172 serrno = errno;
00173 va_end(ap);
00174 if (fh)
00175 {
00176 f.handle = fh;
00177 f.path = cooked;
00178 } else
00179 free(cooked);
00180 errno = serrno;
00181 return f;
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 static file
00198 try_find_file(const char *name, const char *mode, int type)
00199 {
00200 file f = {NULL, NULL};
00201 char *gd = options.dir_gamedata;
00202 char *sd = options.dir_savegame;
00203 char *where = "";
00204
00205 DEBUG2("looking for file `%s'", name);
00206
00207
00208 if (type != FT_SAVE)
00209 {
00210 if (strchr(mode, 'b'))
00211 mode = "rb";
00212 else
00213 mode = "r";
00214 }
00215
00216 switch (type)
00217 {
00218 case FT_DATA:
00219 f = s_open_helper(gd, name, mode,
00220 "gamedata",
00221 NULL);
00222 where = "game data";
00223 break;
00224 case FT_SAVE:
00225 f = s_open_helper(sd, name, mode,
00226 ".",
00227 NULL);
00228 where = "savegame";
00229 break;
00230 case FT_AUDIO:
00231 f = s_open_helper(gd, name, mode,
00232 "audio/mission",
00233 "audio/music",
00234 "audio/news",
00235 "audio/sounds",
00236 NULL);
00237 where = "audio";
00238 break;
00239 case FT_VIDEO:
00240 f = s_open_helper(gd, name, mode,
00241 "video/mission",
00242 "video/news",
00243 "video/training",
00244 NULL);
00245 where = "video";
00246 break;
00247 case FT_IMAGE:
00248 f = s_open_helper(gd, name, mode,
00249 "images",
00250 NULL);
00251 where = "image";
00252 break;
00253 case FT_MIDI:
00254 f = s_open_helper(gd, name, mode,
00255 "audio/midi",
00256 "midi",
00257 "audio/music",
00258 NULL);
00259 where = "midi";
00260 break;
00261 default:
00262 assert("Unknown FT_* specified");
00263 }
00264
00265 if (f.handle == NULL)
00266 {
00267 int serrno = errno;
00268 WARNING3("can't find file `%s' in %s dir(s)", name, where);
00269 errno = serrno;
00270 }
00271 return f;
00272 }
00273
00274 FILE*
00275 sOpen(const char *name, const char *mode, int type)
00276 {
00277 file f = try_find_file(name, mode, type);
00278 if (f.path)
00279 {
00280 INFO3("opened file `%s' (mode %s)", f.path, mode);
00281 free(f.path);
00282 }
00283 return f.handle;
00284 }
00285
00286
00287
00288
00289 char*
00290 locate_file(const char *name, int type)
00291 {
00292 file f = try_find_file(name, "rb", type);
00293 if (f.handle)
00294 {
00295 INFO2("found file `%s'", f.path);
00296 fclose(f.handle);
00297 }
00298 return f.path;
00299 }
00300
00301 int
00302 remove_savedat(const char *name)
00303 {
00304 size_t len_base = strlen(options.dir_savegame) + 1;
00305 size_t len_name = strlen(name) + 1;
00306 char *cooked = xmalloc(len_base + len_name);
00307 int rv = 0;
00308
00309 sprintf(cooked, "%s/%s", options.dir_savegame, name);
00310 INFO2("removing save game file `%s'", cooked);
00311 fix_pathsep(cooked);
00312 rv = remove(cooked);
00313 if (rv < 0 && errno != ENOENT)
00314 WARNING3("failed to remove save game file `%s': %s",
00315 cooked, strerror(errno));
00316 free(cooked);
00317 return rv;
00318 }
00319
00320 FILE *
00321 open_gamedat(const char *name)
00322 {
00323 return sOpen(name, "rb", FT_DATA);
00324 }
00325
00326 FILE *
00327 open_savedat(const char *name, const char *mode)
00328 {
00329 return sOpen(name, mode, FT_SAVE);
00330 }
00331
00332 char *
00333 slurp_gamedat(const char *name)
00334 {
00335 FILE *f;
00336 ssize_t len;
00337 char *p = NULL;
00338 size_t buflen = 0;
00339
00340 f = open_gamedat(name);
00341 if (!f)
00342 return NULL;
00343
00344 len = fread_dyn(&p, &buflen, f);
00345
00346 if (len < 0)
00347 {
00348 CRITICAL2("could not read file `%s'", name);
00349 exit(EXIT_FAILURE);
00350 }
00351
00352 fclose(f);
00353
00354 return p;
00355 }
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366 int
00367 create_save_dir(void)
00368 {
00369 if (mkdir(options.dir_savegame, 0777) < 0 && errno != EEXIST) {
00370 WARNING3("can't create savegame directory `%s': %s",
00371 options.dir_savegame, strerror(errno));
00372 return -1;
00373 }
00374 return 0;
00375 }
00376
00377 int
00378 first_saved_game(struct ffblk *ffblk)
00379 {
00380 if (save_dir)
00381 {
00382 closedir(save_dir);
00383 save_dir = NULL;
00384 }
00385
00386 if ((save_dir = opendir(options.dir_savegame)) == NULL)
00387 return (1);
00388
00389 return (next_saved_game(ffblk));
00390 }
00391
00392 int
00393 next_saved_game(struct ffblk *ffblk)
00394 {
00395 struct dirent *dp;
00396 int len;
00397
00398 memset(ffblk, 0, sizeof *ffblk);
00399
00400 if (save_dir == NULL)
00401 return (1);
00402
00403 while ((dp = readdir(save_dir)) != NULL)
00404 {
00405 len = NAMLEN(dp);
00406 if (len < 4)
00407 continue;
00408 if (xstrncasecmp(dp->d_name + len - 4, ".SAV", 4) != 0)
00409 continue;
00410
00411 strncpy(ffblk->ff_name, dp->d_name, sizeof ffblk->ff_name);
00412 ffblk->ff_name[sizeof ffblk->ff_name - 1] = 0;
00413
00414 return (0);
00415 }
00416
00417 return (1);
00418 }
00419
00420