2 * Copyright (C) 2003-2010 Neverball authors
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
28 * This file implements the low-level virtual file system routines
32 /*---------------------------------------------------------------------------*/
39 static char *fs_dir_base;
40 static char *fs_dir_write;
43 int fs_init(const char *argv0)
45 fs_dir_base = strdup(dir_name(argv0));
69 fs_path = list_rest(fs_path);
75 const char *fs_error(void)
77 return strerror(errno);
80 /*---------------------------------------------------------------------------*/
82 const char *fs_base_dir(void)
87 int fs_add_path(const char *path)
89 /* TODO: ZIP archive support. */
93 fs_path = list_cons(strdup(path), fs_path);
99 int fs_set_write_dir(const char *path)
101 if (dir_exists(path))
109 fs_dir_write = strdup(path);
115 const char *fs_get_write_dir(void)
120 /*---------------------------------------------------------------------------*/
122 static void add_files(List *items, const char *real)
126 if ((files = dir_list_files(real)))
128 for (file = files; file; file = file->next)
133 /* "Inspired" by PhysicsFS file enumeration code. */
135 for (p = NULL, l = *items; l; p = l, l = l->next)
139 if ((cmp = strcmp(l->data, file->data)) >= 0)
149 p->next = list_cons(file->data, p->next);
151 *items = list_cons(file->data, *items);
153 /* Take over memory management duties. */
159 dir_list_free(files);
163 static List list_files(const char *path)
168 for (p = fs_path; p; p = p->next)
170 char *real = path_join(p->data, path);
171 add_files(&files, real);
178 static void free_files(List files)
183 files = list_rest(files);
187 Array fs_dir_scan(const char *path, int (*filter)(struct dir_item *))
189 return dir_scan(path, filter, list_files, free_files);
192 void fs_dir_free(Array items)
197 /*---------------------------------------------------------------------------*/
199 static char *real_path(const char *path)
204 for (p = fs_path; p; p = p->next)
206 real = path_join(p->data, path);
208 if (file_exists(real))
218 /*---------------------------------------------------------------------------*/
220 fs_file fs_open(const char *path, const char *mode)
224 assert((mode[0] == 'r' && !mode[1]) ||
225 (mode[0] == 'w' && (!mode[1] || mode[1] == '+')));
227 if ((fh = malloc(sizeof (*fh))))
236 if ((real = real_path(path)))
238 fh->handle = fopen(real, "rb");
247 real = path_join(fs_dir_write, path);
249 fh->handle = (mode[1] == '+' ?
268 int fs_close(fs_file fh)
270 if (fclose(fh->handle))
278 /*----------------------------------------------------------------------------*/
280 int fs_mkdir(const char *path)
285 real = path_join(fs_dir_write, path);
292 int fs_exists(const char *path)
296 if ((real = real_path(path)))
304 int fs_remove(const char *path)
309 real = path_join(fs_dir_write, path);
310 rc = (remove(real) == 0);
316 /*---------------------------------------------------------------------------*/
318 int fs_read(void *data, int size, int count, fs_file fh)
320 return fread(data, size, count, fh->handle);
323 int fs_write(const void *data, int size, int count, fs_file fh)
325 return fwrite(data, size, count, fh->handle);
328 int fs_flush(fs_file fh)
330 return fflush(fh->handle);
333 long fs_tell(fs_file fh)
335 return ftell(fh->handle);
338 int fs_seek(fs_file fh, long offset, int whence)
340 return fseek(fh->handle, offset, whence);
343 int fs_eof(fs_file fh)
346 * Unlike PhysicsFS, stdio does not register EOF unless we have
347 * actually attempted to read past the end of the file. Nothing
348 * is done to mitigate this: instead, code that relies on
349 * PhysicsFS behavior should be fixed not to.
351 return feof(fh->handle);
354 int fs_length(fs_file fh)
356 long len, cur = ftell(fh->handle);
358 fseek(fh->handle, 0, SEEK_END);
359 len = ftell(fh->handle);
360 fseek(fh->handle, cur, SEEK_SET);
365 /*---------------------------------------------------------------------------*/