SDL_LIBS := $(shell sdl-config --libs)
PNG_LIBS := $(shell libpng-config --libs)
+FS_LIBS := -lphysfs
# The non-conditionalised values below are specific to the native
# system. The native system of this Makefile is Linux (or GNU+Linux if
OGL_LIBS := -framework OpenGL
endif
-BASE_LIBS := -ljpeg $(PNG_LIBS)
+BASE_LIBS := -ljpeg $(PNG_LIBS) $(FS_LIBS)
ifdef DARWIN
BASE_LIBS += -L/opt/local/lib
share/binary.o \
share/base_config.o \
share/common.o \
+ share/fs.o \
+ share/fs_png.o \
+ share/fs_jpg.o \
+ share/dir.o \
+ share/array.o \
share/mapc.o
BALL_OBJS := \
share/lang.o \
share/cmd.o \
share/array.o \
share/dir.o \
+ share/fs.o \
+ share/fs_png.o \
+ share/fs_jpg.o \
+ share/fs_rwops.o \
+ share/fs_ov.o \
ball/hud.o \
ball/game_common.o \
ball/game_client.o \
share/common.o \
share/syswm.o \
share/list.o \
+ share/fs.o \
+ share/fs_png.o \
+ share/fs_jpg.o \
+ share/fs_rwops.o \
+ share/fs_ov.o \
+ share/dir.o \
+ share/array.o \
putt/hud.o \
putt/game.o \
putt/hole.o \
#define DATELEN 20
-static FILE *demo_fp;
+static fs_file demo_fp;
/*---------------------------------------------------------------------------*/
d->time, d->goal, d->goal_e, d->score, d->balls, d->times);
}
-static int demo_header_read(FILE *fp, struct demo *d)
+static int demo_header_read(fs_file fp, struct demo *d)
{
int magic;
int version;
return 0;
}
-static void demo_header_write(FILE *fp, struct demo *d)
+static void demo_header_write(fs_file fp, struct demo *d)
{
int magic = MAGIC;
int version = DEMO_VERSION;
struct demo *demo_load(const char *path)
{
- FILE *fp;
+ fs_file fp;
struct demo *d;
d = NULL;
- if ((fp = fopen(path, FMODE_RB)))
+ if ((fp = fs_open(path, "r")))
{
d = malloc(sizeof (struct demo));
d = NULL;
}
- fclose(fp);
+ fs_close(fp);
}
return d;
{
char buf[MAXSTR];
- strcpy(buf, config_user(name));
+ strcpy(buf, name);
strcat(buf, REPLAY_EXT);
- return file_exists(buf);
+ return fs_exists(buf);
}
#define MAXSTRLEN(a) (sizeof ((a)) - 1)
memset(&demo, 0, sizeof (demo));
- strncpy(demo.filename, config_user(name), MAXSTR);
+ strncpy(demo.filename, name, MAXSTR);
strcat(demo.filename, REPLAY_EXT);
demo.mode = mode;
demo.balls = b;
demo.times = tt;
- if ((demo_fp = fopen(demo.filename, FMODE_WB)))
+ if ((demo_fp = fs_open(demo.filename, "w")))
{
demo_header_write(demo_fp, &demo);
audio_music_fade_to(2.0f, level->song);
{
if (demo_fp)
{
- long pos = ftell(demo_fp);
+ long pos = fs_tell(demo_fp);
- fseek(demo_fp, 8, SEEK_SET);
+ fs_seek(demo_fp, 8, SEEK_SET);
put_index(demo_fp, &timer);
put_index(demo_fp, &coins);
put_index(demo_fp, &status);
- fseek(demo_fp, pos, SEEK_SET);
+ fs_seek(demo_fp, pos, SEEK_SET);
}
}
{
if (demo_fp)
{
- fclose(demo_fp);
+ fs_close(demo_fp);
demo_fp = NULL;
}
}
demo_exists(USER_REPLAY_FILE) &&
strcmp(name, USER_REPLAY_FILE) != 0)
{
- strcpy(src, config_user(USER_REPLAY_FILE));
+ strcpy(src, USER_REPLAY_FILE);
strcat(src, REPLAY_EXT);
- strcpy(dst, config_user(name));
+ strcpy(dst, name);
strcat(dst, REPLAY_EXT);
- file_rename(src, dst);
+ fs_rename(src, dst);
}
}
void demo_rename_player(const char *name, const char *player)
{
+#if 0
char filename[MAXSTR];
FILE *old_fp, *new_fp;
struct demo d;
}
fclose(old_fp);
}
+#endif
}
/*---------------------------------------------------------------------------*/
int demo_replay_init(const char *name, int *g, int *m, int *b, int *s, int *tt)
{
- demo_fp = fopen(name, FMODE_RB);
+ demo_fp = fs_open(name, "r");
if (demo_fp && demo_header_read(demo_fp, &demo_replay))
{
break;
}
- if (!feof(demo_fp))
+ if (!fs_eof(demo_fp))
{
game_client_step(NULL);
return 1;
{
if (demo_fp)
{
- fclose(demo_fp);
+ fs_close(demo_fp);
demo_fp = NULL;
- if (d) remove(demo_replay.filename);
+ if (d) fs_remove(demo_replay.filename);
}
}
/*---------------------------------------------------------------------------*/
-FILE *demo_file(void) { return demo_fp; }
+fs_file demo_file(void) { return demo_fp; }
/*---------------------------------------------------------------------------*/
#include <stdio.h>
#include "level.h"
+#include "fs.h"
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
-FILE *demo_file(void);
+fs_file demo_file(void);
/*---------------------------------------------------------------------------*/
#include "common.h"
#include "demo.h"
#include "demo_dir.h"
-#include "dir.h"
+#include "fs.h"
/*---------------------------------------------------------------------------*/
Array demo_dir_scan(const char *path)
{
- return dir_scan(path, scan_item, NULL, NULL);
+ return fs_dir_scan(path, scan_item);
}
void demo_dir_free(Array items)
}
}
-void game_client_step(FILE *demo_fp)
+void game_client_step(fs_file demo_fp)
{
union cmd *cmdp;
if (client_state)
game_client_free();
- if (!sol_load_gl(&file, config_data(file_name),
+ if (!sol_load_gl(&file, file_name,
config_get_d(CONFIG_TEXTURES),
config_get_d(CONFIG_SHADOW)))
return (client_state = 0);
first_update = 1;
back_init(grad_name, config_get_d(CONFIG_GEOMETRY));
- sol_load_gl(&back, config_data(back_name),
+ sol_load_gl(&back, back_name,
config_get_d(CONFIG_TEXTURES), 0);
return client_state;
#include <stdio.h>
#include "solid.h"
+#include "fs.h"
/*---------------------------------------------------------------------------*/
int game_client_init(const char *);
void game_client_free(void);
-void game_client_step(FILE *);
+void game_client_step(fs_file);
int curr_clock(void);
int curr_coins(void);
return (int) input_current.c;
}
-int input_put(FILE *fout)
+int input_put(fs_file fout)
{
if (server_state)
{
return 0;
}
-int input_get(FILE *fin)
+int input_get(fs_file fin)
{
if (server_state)
{
get_short(fin, &input_current.r);
get_short(fin, &input_current.c);
- return (feof(fin) ? 0 : 1);
+ return (fs_eof(fin) ? 0 : 1);
}
return 0;
}
if (server_state)
game_server_free();
- if (!sol_load_only_file(&file, config_data(file_name)))
+ if (!sol_load_only_file(&file, file_name))
return (server_state = 0);
server_state = 1;
#define GAME_SERVER_H
#include "solid.h"
+#include "fs.h"
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
-int input_put(FILE *);
-int input_get(FILE *);
+int input_put(fs_file);
+int input_get(fs_file);
/*---------------------------------------------------------------------------*/
#define default_error \
L_("Not a valid level file")
- if (!sol_load_only_head(&sol, config_data(filename)))
+ if (!sol_load_only_head(&sol, filename))
{
const char *error = errno ? strerror(errno) : default_error;
fprintf(stderr, format, filename, error);
#include "gui.h"
#include "set.h"
#include "tilt.h"
+#include "fs.h"
+#include "common.h"
#include "st_conf.h"
#include "st_title.h"
static char filename[MAXSTR];
sprintf(filename, "screen%05d.png", config_screenshot());
- image_snap(config_user(filename));
+ image_snap(filename);
}
/*---------------------------------------------------------------------------*/
SDL_Joystick *joy = NULL;
int t1, t0, uniform;
- config_exec_path = argv[0];
+ if (!fs_init(argv[0]))
+ {
+ fputs("Failure to initialize virtual file system\n", stderr);
+ return 1;
+ }
lang_init("neverball");
parse_args(argc, argv);
- if (!config_data_path(data_path, SET_FILE))
- {
- fputs(L_("Failure to establish game data directory\n"), stderr);
- return 1;
- }
-
- if (!config_user_path(NULL))
- {
- fputs(L_("Failure to establish config directory\n"), stderr);
- return 1;
- }
+ config_paths(data_path);
/* Initialize SDL system and subsystems */
/* Dump replay information and exit. */
- if (display_info)
+ if (display_info && fs_add_path(dir_name(demo_path)))
{
- if (!progress_replay(demo_path))
+ if (!progress_replay(base_name(demo_path, NULL)))
{
fprintf(stderr, L_("Replay file '%s': %s\n"), demo_path,
errno ? strerror(errno) : L_("Not a replay file"));
/* Initialise demo playback. */
- if (replay_demo && progress_replay(demo_path))
+ if (replay_demo && fs_add_path(dir_name(demo_path)) &&
+ progress_replay(base_name(demo_path, NULL)))
{
demo_play_goto(1);
goto_state(&st_demo_play);
#include "image.h"
#include "set.h"
#include "common.h"
+#include "fs.h"
#include "game_server.h"
#include "game_client.h"
/*---------------------------------------------------------------------------*/
-static void put_score(FILE *fp, const struct score *s)
+static void put_score(fs_file fp, const struct score *s)
{
int j;
for (j = 0; j < NSCORE; j++)
- fprintf(fp, "%d %d %s\n", s->timer[j], s->coins[j], s->player[j]);
+ fs_printf(fp, "%d %d %s\n", s->timer[j], s->coins[j], s->player[j]);
}
void set_store_hs(void)
{
const struct set *s = &set_v[set];
- FILE *fout;
+ fs_file fout;
int i;
const struct level *l;
char states[MAXLVL + 1];
- if ((fout = fopen(config_user(s->user_scores), "w")))
+ if ((fout = fs_open(s->user_scores, "w")))
{
for (i = 0; i < s->count; i++)
{
states[i] = 'O';
}
states[s->count] = '\0';
- fprintf(fout, "%s\n",states);
+ fs_printf(fout, "%s\n",states);
put_score(fout, &s->time_score);
put_score(fout, &s->coin_score);
put_score(fout, &l->score.most_coins);
}
- fclose(fout);
+ fs_close(fout);
}
}
-static int get_score(FILE *fp, struct score *s)
+static int get_score(fs_file fp, struct score *s)
{
int j;
int res = 1;
+ char line[MAXSTR];
for (j = 0; j < NSCORE && res; j++)
{
- res = fscanf(fp, "%d %d %s\n",
- &s->timer[j],
- &s->coins[j],
- s->player[j]) == 3;
+ res = (fs_gets(line, sizeof (line), fp) &&
+ sscanf(line, "%d %d %s\n",
+ &s->timer[j],
+ &s->coins[j],
+ s->player[j]) == 3);
}
return res;
}
static void set_load_hs(void)
{
struct set *s = &set_v[set];
- FILE *fin;
+ fs_file fin;
int i;
int res = 0;
struct level *l;
- const char *fn = config_user(s->user_scores);
- char states[MAXLVL + 1];
+ const char *fn = s->user_scores;
+ char states[MAXLVL + sizeof ("\n")];
- if ((fin = fopen(fn, "r")))
+ if ((fin = fs_open(fn, "r")))
{
- res = fscanf(fin, "%s\n", states) == 1 && strlen(states) == s->count;
+ res = (fs_gets(states, sizeof (states), fin) &&
+ strlen(states) - 1 == s->count);
for (i = 0; i < s->count && res; i++)
{
get_score(fin, &l->score.most_coins);
}
- fclose(fin);
+ fs_close(fin);
}
if (!res && errno != ENOENT)
static int set_load(struct set *s, const char *filename)
{
- FILE *fin;
+ fs_file fin;
char *scores, *level_name;
- fin = fopen(config_data(filename), "r");
+ fin = fs_open(filename, "r");
if (!fin)
{
s->count++;
}
- fclose(fin);
+ fs_close(fin);
return 1;
}
free(s->id);
free(s->shot);
- fclose(fin);
+ fs_close(fin);
return 0;
}
int set_init()
{
- FILE *fin;
+ fs_file fin;
char *name;
if (set_state)
set = 0;
count = 0;
- if ((fin = fopen(config_data(SET_FILE), "r")))
+ if ((fin = fs_open(SET_FILE, "r")))
{
while (count < MAXSET && read_line(&name, fin))
{
free(name);
}
- fclose(fin);
+ fs_close(fin);
set_state = 1;
}
if (items)
demo_dir_free(items);
- items = demo_dir_scan(config_user(""));
+ items = demo_dir_scan("");
total = array_len(items);
id = gui_vstack(0);
break;
case HELP_DEMO_1:
- if (demo_replay_init(config_data("gui/demo1.nbr"),
- NULL, NULL, NULL, NULL, NULL))
+ if (demo_replay_init("gui/demo1.nbr", NULL, NULL, NULL, NULL, NULL))
return goto_state(&st_help_demo);
break;
case HELP_DEMO_2:
- if (demo_replay_init(config_data("gui/demo2.nbr"),
- NULL, NULL, NULL, NULL, NULL))
+ if (demo_replay_init("gui/demo2.nbr", NULL, NULL, NULL, NULL, NULL))
return goto_state(&st_help_demo);
break;
if (real_time > 1.0f)
{
if (!items)
- items = demo_dir_scan(config_user(""));
+ items = demo_dir_scan("");
if ((demo = pick_demo(items)))
{
#include "config.h"
#include "course.h"
#include "hole.h"
+#include "fs.h"
/*---------------------------------------------------------------------------*/
void course_init()
{
- FILE *fin;
+ fs_file fin;
+ char buff[MAXSTR];
if (course_state)
course_free();
count = 0;
- if ((fin = fopen(config_data(COURSE_FILE), "r")))
+ if ((fin = fs_open(COURSE_FILE, "r")))
{
- while (fscanf(fin, "%s %s\n",
+ while (fs_gets(buff, sizeof (buff), fin) &&
+ sscanf(buff, "%s %s\n",
course_v[count].holes,
course_v[count].shot) == 2 &&
- fgets(course_v[count].desc, MAXSTR, fin))
+ fs_gets(course_v[count].desc, MAXSTR, fin))
{
char *q = course_v[count].desc + strlen(course_v[count].desc) - 1;
count++;
}
- fclose(fin);
+ fs_close(fin);
course_state = 1;
}
jump_b = 0;
view_init();
- sol_load_gl(&file, config_data(s), config_get_d(CONFIG_TEXTURES),
- config_get_d(CONFIG_SHADOW));
+ sol_load_gl(&file, s,
+ config_get_d(CONFIG_TEXTURES),
+ config_get_d(CONFIG_SHADOW));
}
void game_free(void)
#include "back.h"
#include "audio.h"
#include "config.h"
+#include "fs.h"
/*---------------------------------------------------------------------------*/
static void hole_init_rc(const char *filename)
{
- FILE *fin;
+ fs_file fin;
+ char buff[MAXSTR];
hole = 0;
player = 0;
/* Load the holes list. */
- if ((fin = fopen(config_data(filename), "r")))
+ if ((fin = fs_open(filename, "r")))
{
- while (fscanf(fin, "%s %s %d %s",
- hole_v[count].file,
- hole_v[count].back,
+ while (fs_gets(buff, sizeof (buff), fin) &&
+ sscanf(buff, "%s %s %d %s",
+ hole_v[count].file,
+ hole_v[count].back,
&hole_v[count].par,
- hole_v[count].song) == 4)
+ hole_v[count].song) == 4)
count++;
- fclose(fin);
+ fs_close(fin);
}
}
#include "hole.h"
#include "game.h"
#include "gui.h"
+#include "fs.h"
#include "st_conf.h"
#include "st_all.h"
static char filename[MAXSTR];
sprintf(filename, "screen%05d.png", config_screenshot());
- image_snap(config_user(filename));
+ image_snap(filename);
return 1;
}
int camera = 0;
SDL_Joystick *joy = NULL;
- config_exec_path = argv[0];
+ if (!fs_init(argv[0]))
+ {
+ fputs("Failure to initialize virtual file system\n", stderr);
+ return 1;
+ }
srand((int) time(NULL));
lang_init("neverball");
+ config_paths(argc > 1 ? argv[1] : NULL);
- if (config_data_path((argc > 1 ? argv[1] : NULL), COURSE_FILE))
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) == 0)
{
- if (config_user_path(NULL))
- {
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) == 0)
- {
- config_init();
- config_load();
+ config_init();
+ config_load();
- /* Cache Neverball's camera setting. */
+ /* Cache Neverball's camera setting. */
- camera = config_get_d(CONFIG_CAMERA);
+ camera = config_get_d(CONFIG_CAMERA);
- /* Initialize the joystick. */
+ /* Initialize the joystick. */
- if (SDL_NumJoysticks() > 0)
- {
- joy = SDL_JoystickOpen(config_get_d(CONFIG_JOYSTICK_DEVICE));
- if (joy)
- {
- SDL_JoystickEventState(SDL_ENABLE);
- set_joystick(joy);
- }
- }
+ if (SDL_NumJoysticks() > 0)
+ {
+ joy = SDL_JoystickOpen(config_get_d(CONFIG_JOYSTICK_DEVICE));
+ if (joy)
+ {
+ SDL_JoystickEventState(SDL_ENABLE);
+ set_joystick(joy);
+ }
+ }
- /* Initialize the audio. */
+ /* Initialize the audio. */
- audio_init();
+ audio_init();
- /* Initialize the video. */
+ /* Initialize the video. */
- if (video_init(TITLE, ICON))
- {
- int t1, t0 = SDL_GetTicks();
+ if (video_init(TITLE, ICON))
+ {
+ int t1, t0 = SDL_GetTicks();
- /* Run the main game loop. */
+ /* Run the main game loop. */
- init_state(&st_null);
- goto_state(&st_title);
+ init_state(&st_null);
+ goto_state(&st_title);
- while (loop())
- if ((t1 = SDL_GetTicks()) > t0)
- {
- st_timer((t1 - t0) / 1000.f);
- st_paint(0.001f * t1);
- SDL_GL_SwapBuffers();
+ while (loop())
+ if ((t1 = SDL_GetTicks()) > t0)
+ {
+ st_timer((t1 - t0) / 1000.f);
+ st_paint(0.001f * t1);
+ SDL_GL_SwapBuffers();
- t0 = t1;
+ t0 = t1;
- if (config_get_d(CONFIG_NICE))
- SDL_Delay(1);
- }
+ if (config_get_d(CONFIG_NICE))
+ SDL_Delay(1);
}
+ }
- /* Restore Neverball's camera setting. */
+ /* Restore Neverball's camera setting. */
- config_set_d(CONFIG_CAMERA, camera);
- config_save();
+ config_set_d(CONFIG_CAMERA, camera);
+ config_save();
- SDL_Quit();
- }
- else fprintf(stderr, "%s: %s\n", argv[0], SDL_GetError());
- }
- else fprintf(stderr, L_("Failure to establish config directory\n"));
+ SDL_Quit();
}
- else fprintf(stderr, L_("Failure to establish game data directory\n"));
+ else fprintf(stderr, "%s: %s\n", argv[0], SDL_GetError());
return 0;
}
#include "config.h"
#include "audio.h"
#include "common.h"
+#include "fs.h"
+#include "fs_ov.h"
/*---------------------------------------------------------------------------*/
static struct voice *voices = NULL;
static short *buffer = NULL;
+static ov_callbacks callbacks = {
+ fs_ov_read, fs_ov_seek, fs_ov_close, fs_ov_tell
+};
+
/*---------------------------------------------------------------------------*/
#define MIX(d, s) { \
static struct voice *voice_init(const char *filename, float a)
{
struct voice *V;
- FILE *fp;
+ fs_file fp;
/* Allocate and initialize a new voice structure. */
/* Attempt to open the named Ogg stream. */
- if ((fp = fopen(config_data(filename), FMODE_RB)))
+ if ((fp = fs_open(filename, "r")))
{
- if (ov_open(fp, &V->vf, NULL, 0) == 0)
+ if (ov_open_callbacks(fp, &V->vf, NULL, 0, callbacks) == 0)
{
vorbis_info *info = ov_info(&V->vf, -1);
/* The file will be closed when the Ogg is cleared. */
}
- else fclose(fp);
+ else fs_close(fp);
}
}
return V;
inner_alpha = 1.0f;
outer_alpha = 1.0f;
- if ((has_solid = sol_load_gl(&solid, config_data(solid_file), T, 0)))
+ if ((has_solid = sol_load_gl(&solid, solid_file, T, 0)))
solid_flags = ball_opts(&solid, &solid_alpha);
- if ((has_inner = sol_load_gl(&inner, config_data(inner_file), T, 0)))
+ if ((has_inner = sol_load_gl(&inner, inner_file, T, 0)))
inner_flags = ball_opts(&inner, &inner_alpha);
- if ((has_outer = sol_load_gl(&outer, config_data(outer_file), T, 0)))
+ if ((has_outer = sol_load_gl(&outer, outer_file, T, 0)))
outer_flags = ball_opts(&outer, &outer_alpha);
}
#include "glext.h"
#include "vec3.h"
#include "common.h"
+#include "fs.h"
+#include "dir.h"
+#include "array.h"
/*---------------------------------------------------------------------------*/
-/* Define the mkdir symbol. */
-
-#ifdef _WIN32
-#include <direct.h>
-#else
-#include <sys/stat.h>
-#endif
-
-/*---------------------------------------------------------------------------*/
-
-static char data_path[MAXSTR];
-static char user_path[MAXSTR];
-
-/*
- * Given a path and a file name relative to that path, create an
- * absolute path name and return a temporary pointer to it.
- */
-static const char *config_file(const char *path, const char *file)
+static const char *pick_data_path(const char *arg_data_path)
{
- static char absolute[MAXSTR];
+ static char dir[MAXSTR];
+ char *env;
- size_t d = path ? strlen(path) : 0;
+ if (arg_data_path)
+ return arg_data_path;
- strncpy(absolute, path ? path : "", MAXSTR - 1);
- strncat(absolute, "/", MAXSTR - d - 1);
- strncat(absolute, file ? file : "", MAXSTR - d - 2);
+ if ((env = getenv("NEVERBALL_DATA")))
+ return env;
- return absolute;
-}
+ if (path_is_abs(CONFIG_DATA))
+ return CONFIG_DATA;
-static int config_test(const char *path, const char *file)
-{
- if (file)
- {
- FILE *fp;
-
- if ((fp = fopen(config_file(path, file), "r")))
- {
- fclose(fp);
- return 1;
- }
- return 0;
- }
- return 1;
-}
+ strncpy(dir, fs_base_dir(), sizeof (dir) - 1);
+ strncat(dir, "/", sizeof (dir) - strlen(dir) - 1);
+ strncat(dir, CONFIG_DATA, sizeof (dir) - strlen(dir) - 1);
-const char *config_data(const char *file)
-{
- return config_file(data_path, file);
+ return dir;
}
-const char *config_user(const char *file)
+static const char *pick_home_path(void)
{
- return config_file(user_path, file);
-}
+ const char *path;
-/*---------------------------------------------------------------------------*/
-
-const char *config_exec_path;
+#ifdef _WIN32
+ return (path = getenv("APPDATA")) ? path : fs_base_dir();
+#else
+ return (path = getenv("HOME")) ? path : fs_base_dir();
+#endif
+}
-/*
- * Attempt to find the game data directory. Search the command line
- * parameter, the environment, and the hard-coded default, in that
- * order. Confirm it by checking for presence of the named file.
- */
-int config_data_path(const char *path, const char *file)
+void config_paths(const char *arg_data_path)
{
- char *dir;
+ const char *data, *home, *user;
- if (path && config_test(path, file))
- {
- strncpy(data_path, path, MAXSTR);
- return 1;
- }
+ /*
+ * Scan in turn the game data and user directories for archives,
+ * adding each archive to the search path. Archives with names
+ * further down the alphabet take precedence. After each scan,
+ * add the directory itself, taking precedence over archives added
+ * so far.
+ */
- if ((dir = getenv("NEVERBALL_DATA")) && config_test(dir, file))
- {
- strncpy(data_path, dir, MAXSTR);
- return 1;
- }
-
- dir = path_resolve(config_exec_path, CONFIG_DATA);
-
- if (config_test(dir, file))
- {
- strncpy(data_path, dir, MAXSTR);
- return 1;
- }
+ /* Data directory. */
- return 0;
-}
+ data = pick_data_path(arg_data_path);
-/*
- * Determine the location of the user's home directory. Ensure there
- * is a directory there for storing configuration, high scores, and
- * replays.
- *
- * Under Windows check the APPDATA environment variable and if that's
- * not set, just assume the user has permission to write to the data
- * directory.
- */
-int config_user_path(const char *file)
-{
-#ifdef _WIN32
- char *dir;
+ fs_add_path_with_archives(data);
- if ((dir = getenv("APPDATA")) || (dir = data_path))
- {
- size_t d = strlen(dir);
+ /* User directory. */
- strncpy(user_path, dir, MAXSTR - 1);
- strncat(user_path, "\\", MAXSTR - d - 1);
- strncat(user_path, CONFIG_USER, MAXSTR - d - 2);
- }
+ home = pick_home_path();
+ user = concat_string(home, "/", CONFIG_USER, NULL);
- if ((mkdir(user_path) == 0) || (errno == EEXIST))
- if (config_test(user_path, file))
- return 1;
-#else
- char *dir;
+ /* Set up directory for writing, create if needed. */
- if ((dir = getenv("HOME")))
+ if (!fs_set_write_dir(user))
{
- size_t d = strlen(dir);
-
- strncpy(user_path, dir, MAXSTR - 1);
- strncat(user_path, "/", MAXSTR - d - 1);
- strncat(user_path, CONFIG_USER, MAXSTR - d - 2);
+ if (fs_set_write_dir(home) && fs_mkdir(CONFIG_USER))
+ fs_set_write_dir(user);
}
- if ((mkdir(user_path, 0777) == 0) || (errno == EEXIST))
- if (config_test(user_path, file))
- return 1;
-#endif
+ fs_add_path_with_archives(user);
- return 0;
+ free((void *) user);
}
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
-const char *config_data(const char *);
-const char *config_user(const char *);
-
-extern const char *config_exec_path;
-
-int config_data_path(const char *, const char *);
-int config_user_path(const char *);
+void config_paths(const char *);
/*---------------------------------------------------------------------------*/
#include "base_config.h"
#include "base_image.h"
+#include "fs.h"
+#include "fs_png.h"
+#include "fs_jpg.h"
+
/*---------------------------------------------------------------------------*/
void image_size(int *W, int *H, int w, int h)
int *height,
int *bytes)
{
- FILE *fp;
+ fs_file fh;
png_structp readp = NULL;
png_infop infop = NULL;
/* Initialize all PNG import data structures. */
- if (!(fp = fopen(filename, FMODE_RB)))
+ if (!(fh = fs_open(filename, "r")))
return NULL;
if (!(readp = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0)))
/* Read the PNG header. */
- png_init_io(readp, fp);
+ png_set_read_fn(readp, fh, fs_png_read);
png_read_info(readp, infop);
png_set_expand(readp);
/* Free all resources. */
png_destroy_read_struct(&readp, &infop, NULL);
- fclose(fp);
+ fs_close(fh);
return p;
}
int *bytes)
{
GLubyte *p = NULL;
- FILE *fp;
+ fs_file fp;
- if ((fp = fopen(filename, FMODE_RB)))
+ if ((fp = fs_open(filename, "r")))
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
- jpeg_stdio_src(&cinfo, fp);
+
+ /* Set up a VFS source manager. */
+
+ fs_jpg_src(&cinfo, fp);
/* Grab the JPG header info. */
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
- fclose(fp);
+ fs_close(fp);
}
return p;
#include <SDL_endian.h>
+#include "fs.h"
+
/*---------------------------------------------------------------------------*/
-void put_float(FILE *fout, const float *f)
+void put_float(fs_file fout, const float *f)
{
const unsigned char *p = (const unsigned char *) f;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- fputc((int) p[3], fout);
- fputc((int) p[2], fout);
- fputc((int) p[1], fout);
- fputc((int) p[0], fout);
+ fs_putc((int) p[3], fout);
+ fs_putc((int) p[2], fout);
+ fs_putc((int) p[1], fout);
+ fs_putc((int) p[0], fout);
#else
- fputc((int) p[0], fout);
- fputc((int) p[1], fout);
- fputc((int) p[2], fout);
- fputc((int) p[3], fout);
+ fs_putc((int) p[0], fout);
+ fs_putc((int) p[1], fout);
+ fs_putc((int) p[2], fout);
+ fs_putc((int) p[3], fout);
#endif
}
-void put_index(FILE *fout, const int *i)
+void put_index(fs_file fout, const int *i)
{
const unsigned char *p = (const unsigned char *) i;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- fputc((int) p[3], fout);
- fputc((int) p[2], fout);
- fputc((int) p[1], fout);
- fputc((int) p[0], fout);
+ fs_putc((int) p[3], fout);
+ fs_putc((int) p[2], fout);
+ fs_putc((int) p[1], fout);
+ fs_putc((int) p[0], fout);
#else
- fputc((int) p[0], fout);
- fputc((int) p[1], fout);
- fputc((int) p[2], fout);
- fputc((int) p[3], fout);
+ fs_putc((int) p[0], fout);
+ fs_putc((int) p[1], fout);
+ fs_putc((int) p[2], fout);
+ fs_putc((int) p[3], fout);
#endif
}
-void put_short(FILE *fout, const short *s)
+void put_short(fs_file fout, const short *s)
{
const unsigned char *p = (const unsigned char *) s;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- fputc((int) p[1], fout);
- fputc((int) p[0], fout);
+ fs_putc((int) p[1], fout);
+ fs_putc((int) p[0], fout);
#else
- fputc((int) p[0], fout);
- fputc((int) p[1], fout);
+ fs_putc((int) p[0], fout);
+ fs_putc((int) p[1], fout);
#endif
}
-void put_array(FILE *fout, const float *v, size_t n)
+void put_array(fs_file fout, const float *v, size_t n)
{
size_t i;
/*---------------------------------------------------------------------------*/
-void get_float(FILE *fin, float *f)
+void get_float(fs_file fin, float *f)
{
unsigned char *p = (unsigned char *) f;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- p[3] = (unsigned char) fgetc(fin);
- p[2] = (unsigned char) fgetc(fin);
- p[1] = (unsigned char) fgetc(fin);
- p[0] = (unsigned char) fgetc(fin);
+ p[3] = (unsigned char) fs_getc(fin);
+ p[2] = (unsigned char) fs_getc(fin);
+ p[1] = (unsigned char) fs_getc(fin);
+ p[0] = (unsigned char) fs_getc(fin);
#else
- p[0] = (unsigned char) fgetc(fin);
- p[1] = (unsigned char) fgetc(fin);
- p[2] = (unsigned char) fgetc(fin);
- p[3] = (unsigned char) fgetc(fin);
+ p[0] = (unsigned char) fs_getc(fin);
+ p[1] = (unsigned char) fs_getc(fin);
+ p[2] = (unsigned char) fs_getc(fin);
+ p[3] = (unsigned char) fs_getc(fin);
#endif
}
-void get_index(FILE *fin, int *i)
+void get_index(fs_file fin, int *i)
{
unsigned char *p = (unsigned char *) i;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- p[3] = (unsigned char) fgetc(fin);
- p[2] = (unsigned char) fgetc(fin);
- p[1] = (unsigned char) fgetc(fin);
- p[0] = (unsigned char) fgetc(fin);
+ p[3] = (unsigned char) fs_getc(fin);
+ p[2] = (unsigned char) fs_getc(fin);
+ p[1] = (unsigned char) fs_getc(fin);
+ p[0] = (unsigned char) fs_getc(fin);
#else
- p[0] = (unsigned char) fgetc(fin);
- p[1] = (unsigned char) fgetc(fin);
- p[2] = (unsigned char) fgetc(fin);
- p[3] = (unsigned char) fgetc(fin);
+ p[0] = (unsigned char) fs_getc(fin);
+ p[1] = (unsigned char) fs_getc(fin);
+ p[2] = (unsigned char) fs_getc(fin);
+ p[3] = (unsigned char) fs_getc(fin);
#endif
}
-void get_short(FILE *fin, short *s)
+void get_short(fs_file fin, short *s)
{
unsigned char *p = (unsigned char *) s;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- p[1] = (unsigned char) fgetc(fin);
- p[0] = (unsigned char) fgetc(fin);
+ p[1] = (unsigned char) fs_getc(fin);
+ p[0] = (unsigned char) fs_getc(fin);
#else
- p[0] = (unsigned char) fgetc(fin);
- p[1] = (unsigned char) fgetc(fin);
+ p[0] = (unsigned char) fs_getc(fin);
+ p[1] = (unsigned char) fs_getc(fin);
#endif
}
-void get_array(FILE *fin, float *v, size_t n)
+void get_array(fs_file fin, float *v, size_t n)
{
size_t i;
/*---------------------------------------------------------------------------*/
-void put_string(FILE *fout, const char *s)
+void put_string(fs_file fout, const char *s)
{
- fputs(s, fout);
- fputc('\0', fout);
+ fs_puts(s, fout);
+ fs_putc('\0', fout);
}
-void get_string(FILE *fin, char *s, int max)
+void get_string(fs_file fin, char *s, int max)
{
int c = -1;
if (max == 0)
return;
- while (max && c && (c = fgetc(fin)) != EOF)
+ while (max && c && (c = fs_getc(fin)) >= 0)
{
*s++ = c;
max--;
#include <stdlib.h>
#include <string.h>
+#include "fs.h"
+
/*---------------------------------------------------------------------------*/
#define FLOAT_BYTES 4
#define ARRAY_BYTES(n) (FLOAT_BYTES * (n))
#define STRING_BYTES(s) (strlen(s) + 1)
-void put_float(FILE *, const float *);
-void put_index(FILE *, const int *);
-void put_short(FILE *, const short *);
-void put_array(FILE *, const float *, size_t);
+void put_float(fs_file, const float *);
+void put_index(fs_file, const int *);
+void put_short(fs_file, const short *);
+void put_array(fs_file, const float *, size_t);
-void get_float(FILE *, float *);
-void get_index(FILE *, int *);
-void get_short(FILE *, short *);
-void get_array(FILE *, float *, size_t);
+void get_float(fs_file, float *);
+void get_index(fs_file, int *);
+void get_short(fs_file, short *);
+void get_array(fs_file, float *, size_t);
-void put_string(FILE *fout, const char *);
-void get_string(FILE *fin, char *, int );
+void put_string(fs_file fout, const char *);
+void get_string(fs_file fin, char *, int );
/*---------------------------------------------------------------------------*/
*/
#define PUT_FUNC(t) \
- static void cmd_put_ ## t(FILE *fp, const union cmd *cmd) { \
+ static void cmd_put_ ## t(fs_file fp, const union cmd *cmd) { \
const char *cmd_name = #t; \
\
/* This is a write, so BYTES should be safe to eval already. */ \
if (cmd_stats) printf("put"); \
#define GET_FUNC(t) \
- static void cmd_get_ ## t(FILE *fp, union cmd *cmd) { \
+ static void cmd_get_ ## t(fs_file fp, union cmd *cmd) { \
const char *cmd_name = #t; \
\
/* This is a read, so we'll have to eval BYTES later. */ \
#define PUT_CASE(t) case t: cmd_put_ ## t(fp, cmd); break
#define GET_CASE(t) case t: cmd_get_ ## t(fp, cmd); break
-int cmd_put(FILE *fp, const union cmd *cmd)
+int cmd_put(fs_file fp, const union cmd *cmd)
{
if (!fp || !cmd)
return 0;
assert(cmd->type > CMD_NONE && cmd->type < CMD_MAX);
- fputc(cmd->type, fp);
+ fs_putc(cmd->type, fp);
switch (cmd->type)
{
break;
}
- return !feof(fp);
+ return !fs_eof(fp);
}
-int cmd_get(FILE *fp, union cmd *cmd)
+int cmd_get(fs_file fp, union cmd *cmd)
{
int type;
short size;
if (!fp || !cmd)
return 0;
- if ((type = fgetc(fp)) != EOF)
+ if ((type = fs_getc(fp)) >= 0)
{
get_short(fp, &size);
if (type >= CMD_MAX)
{
- fseek(fp, size, SEEK_CUR);
+ fs_seek(fp, size, SEEK_CUR);
type = CMD_NONE;
}
break;
}
- return !feof(fp);
+ return !fs_eof(fp);
}
return 0;
}
/* No module should see this. */
#undef HEADER
-#include <stdio.h>
+#include "fs.h"
-int cmd_put(FILE *, const union cmd *);
-int cmd_get(FILE *, union cmd *);
+int cmd_put(fs_file, const union cmd *);
+int cmd_get(fs_file, union cmd *);
#endif
#include <assert.h>
#include "common.h"
+#include "fs.h"
#define MAXSTR 256
/*---------------------------------------------------------------------------*/
-int read_line(char **dst, FILE *fin)
+int read_line(char **dst, fs_file fin)
{
char buffer[MAXSTR] = "";
int buffer_size = 0;
while (!seen_newline)
{
- if (fgets(buffer, sizeof (buffer), fin) == NULL)
+ if (fs_gets(buffer, sizeof (buffer), fin) == NULL)
{
if (store_size > 0)
break;
#include <time.h>
#include <stdio.h>
+#include "fs.h"
#ifdef __GNUC__
#define NULL_TERMINATED __attribute__ ((__sentinel__))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
-int read_line(char **, FILE *);
+int read_line(char **, fs_file);
char *strip_newline(char *);
char *dupe_string(const char *);
#include "config.h"
#include "common.h"
+#include "fs.h"
/*---------------------------------------------------------------------------*/
void config_load(void)
{
- FILE *fp;
+ fs_file fh;
- if ((fp = fopen(config_user(USER_CONFIG_FILE), "r")))
+ if ((fh = fs_open(USER_CONFIG_FILE, "r")))
{
char *line, *key, *val;
- while (read_line(&line, fp))
+ while (read_line(&line, fh))
{
if (scan_key_and_value(&key, &val, line))
{
}
free(line);
}
- fclose(fp);
+ fs_close(fh);
dirty = 0;
}
void config_save(void)
{
- FILE *fp;
+ fs_file fh;
- if (dirty && (fp = fopen(config_user(USER_CONFIG_FILE), "w")))
+ if (dirty && (fh = fs_open(USER_CONFIG_FILE, "w")))
{
int i;
}
if (s)
- fprintf(fp, "%-25s %s\n", option_d[i].name, s);
+ fs_printf(fh, "%-25s %s\n", option_d[i].name, s);
else
- fprintf(fp, "%-25s %d\n", option_d[i].name, option_d[i].cur);
+ fs_printf(fh, "%-25s %d\n", option_d[i].name, option_d[i].cur);
}
/* Write out string options. */
for (i = 0; i < ARRAYSIZE(option_s); i++)
{
if (option_s[i].cur && *option_s[i].cur)
- fprintf(fp, "%-25s %s\n", option_s[i].name, option_s[i].cur);
+ fs_printf(fh, "%-25s %s\n", option_s[i].name, option_s[i].cur);
}
- fclose(fp);
+ fs_close(fh);
}
dirty = 0;
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <physfs.h>
+
+#include "fs.h"
+#include "dir.h"
+#include "array.h"
+
+/*
+ * This file implements the virtual file system layer. Most file
+ * system and input/output operations are handled here. There are
+ * basically two groups of functions here: low-level functions
+ * implemented directly using the PhysicsFS 1.0 API and higher-level
+ * functions implemented using the former group.
+ */
+
+/* -------------------------------------------------------------------------- */
+
+struct fs_file
+{
+ PHYSFS_file *handle;
+};
+
+int fs_init(const char *argv0)
+{
+ return PHYSFS_init(argv0);
+}
+
+int fs_quit(void)
+{
+ return PHYSFS_deinit();
+}
+
+/* -------------------------------------------------------------------------- */
+
+const char *fs_base_dir(void)
+{
+ return PHYSFS_getBaseDir();
+}
+
+int fs_add_path(const char *path)
+{
+ return PHYSFS_addToSearchPath(path, 0);
+}
+
+int fs_set_write_dir(const char *path)
+{
+ return PHYSFS_setWriteDir(path);
+}
+
+/* -------------------------------------------------------------------------- */
+
+Array fs_dir_scan(const char *path, int (*filter)(struct dir_item *))
+{
+ return dir_scan(path, filter, PHYSFS_enumerateFiles, PHYSFS_freeList);
+}
+
+void fs_dir_free(Array items)
+{
+ dir_free(items);
+}
+
+/* -------------------------------------------------------------------------- */
+
+fs_file fs_open(const char *path, const char *mode)
+{
+ fs_file fh;
+
+ assert((mode[0] == 'r' && !mode[1]) ||
+ (mode[0] == 'w' && (!mode[1] || mode[1] == '+')));
+
+ if ((fh = malloc(sizeof (*fh))))
+ {
+ switch (mode[0])
+ {
+ case 'r':
+ fh->handle = PHYSFS_openRead(path);
+ break;
+
+ case 'w':
+ fh->handle = (mode[1] == '+' ?
+ PHYSFS_openAppend(path) :
+ PHYSFS_openWrite(path));
+ break;
+ }
+
+ if (fh->handle)
+ {
+ PHYSFS_setBuffer(fh->handle, 0x2000);
+ }
+ else
+ {
+ free(fh);
+ fh = NULL;
+ }
+ }
+
+ return fh;
+}
+
+int fs_close(fs_file fh)
+{
+ if (PHYSFS_close(fh->handle))
+ {
+ free(fh);
+ return 1;
+ }
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+int fs_mkdir(const char *path)
+{
+ return PHYSFS_mkdir(path);
+}
+
+int fs_exists(const char *path)
+{
+ return PHYSFS_exists(path);
+}
+
+int fs_remove(const char *path)
+{
+ return PHYSFS_delete(path);
+}
+
+/* -------------------------------------------------------------------------- */
+
+int fs_read(void *data, int size, int count, fs_file fh)
+{
+ return PHYSFS_read(fh->handle, data, size, count);
+}
+
+int fs_write(const void *data, int size, int count, fs_file fh)
+{
+ return PHYSFS_write(fh->handle, data, size, count);
+}
+
+int fs_flush(fs_file fh)
+{
+ return PHYSFS_flush(fh->handle);
+}
+
+long fs_tell(fs_file fh)
+{
+ return PHYSFS_tell(fh->handle);
+}
+
+int fs_seek(fs_file fh, long offset, int whence)
+{
+ PHYSFS_uint64 pos = 0;
+ PHYSFS_sint64 cur = PHYSFS_tell(fh->handle);
+ PHYSFS_sint64 len = PHYSFS_fileLength(fh->handle);
+
+ switch (whence)
+ {
+ case SEEK_SET:
+ pos = offset;
+ break;
+
+ case SEEK_CUR:
+ if (cur < 0)
+ return -1;
+ pos = cur + offset;
+ break;
+
+ case SEEK_END:
+ if (len < 0)
+ return -1;
+ pos = len + offset;
+ break;
+ }
+
+ return PHYSFS_seek(fh->handle, pos);
+}
+
+int fs_eof(fs_file fh)
+{
+ return PHYSFS_eof(fh->handle);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * The code below does not use the PhysicsFS API.
+ */
+
+/* -------------------------------------------------------------------------- */
+
+static int cmp_dir_items(const void *A, const void *B)
+{
+ const struct dir_item *a = A, *b = B;
+ return strcmp(a->path, b->path);
+}
+
+static int is_archive(struct dir_item *item)
+{
+ return strcmp(item->path + strlen(item->path) - 4, ".zip") == 0;
+}
+
+static void add_archives(const char *path)
+{
+ Array archives;
+ int i;
+
+ if ((archives = dir_scan(path, is_archive, NULL, NULL)))
+ {
+ array_sort(archives, cmp_dir_items);
+
+ for (i = 0; i < array_len(archives); i++)
+ fs_add_path(DIR_ITEM_GET(archives, i)->path);
+
+ dir_free(archives);
+ }
+}
+
+int fs_add_path_with_archives(const char *path)
+{
+ add_archives(path);
+ return fs_add_path(path);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void copy_file(fs_file src, fs_file dst)
+{
+ char buff[256];
+ int size;
+
+ while ((size = fs_read(buff, 1, sizeof (buff), src)) > 0)
+ fs_write(buff, 1, size, dst);
+}
+
+int fs_rename(const char *src, const char *dst)
+{
+ fs_file fin, fout;
+ int copied = 0;
+
+ if ((fin = fs_open(src, "r")))
+ {
+ if ((fout = fs_open(dst, "w")))
+ {
+ copy_file(fin, fout);
+ copied = 1;
+ fs_close(fout);
+ }
+ fs_close(fin);
+ }
+
+ return copied && fs_remove(src);
+}
+
+/* -------------------------------------------------------------------------- */
+
+int fs_getc(fs_file fh)
+{
+ unsigned char c;
+
+ if (fs_read(&c, 1, 1, fh) != 1)
+ return -1;
+
+ return (int) c;
+}
+
+int fs_putc(int c, fs_file fh)
+{
+ unsigned char b = (unsigned char) c;
+
+ if (fs_write(&b, 1, 1, fh) != 1)
+ return -1;
+
+ return b;
+}
+
+int fs_puts(const char *src, fs_file fh)
+{
+ while (*src)
+ if (fs_putc(*src++, fh) < 0)
+ return -1;
+
+ return 0;
+}
+
+char *fs_gets(char *dst, int count, fs_file fh)
+{
+ char *s = dst;
+ char *cr = NULL;
+ int c = 0;
+
+ if (fs_eof(fh))
+ return NULL;
+
+ while (count > 1 && (c = fs_getc(fh)) >= 0)
+ {
+ count--;
+
+ *s = c;
+
+ /* Normalize possible CRLF and break. */
+
+ if (*s == '\n')
+ {
+ if (cr + 1 == s)
+ *cr = '\n';
+ else
+ s++;
+
+ break;
+ }
+
+ /* Note carriage return. */
+
+ if (*s == '\r')
+ cr = s;
+
+ s++;
+ }
+
+ if (count > 0)
+ *s = '\0';
+
+ return c < 0 ? NULL : dst;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Write out a multiline string to a file with appropriately converted
+ * linefeed characters.
+ */
+static int write_lines(const char *start, int length, fs_file fh)
+{
+#ifdef _WIN32
+ static const char crlf[] = "\r\n";
+#else
+ static const char crlf[] = "\n";
+#endif
+
+ int total_written = 0;
+
+ int datalen;
+ int written;
+ char *lf;
+
+ while (total_written < length)
+ {
+ lf = strchr(start, '\n');
+
+ datalen = lf ? (int) (lf - start) : length - total_written;
+ written = fs_write(start, 1, datalen, fh);
+
+ if (written < 0)
+ break;
+
+ total_written += written;
+
+ if (written < datalen)
+ break;
+
+ if (lf)
+ {
+ if (fs_puts(crlf, fh) < 0)
+ break;
+
+ total_written += 1;
+ start = lf + 1;
+ }
+ }
+
+ return total_written;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Trying to avoid defining a feature test macro for every platform by
+ * declaring vsnprintf with the C99 signature. This is probably bad.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+extern int vsnprintf(char *, size_t, const char *, va_list);
+
+int fs_printf(fs_file fh, const char *fmt, ...)
+{
+ char *buff;
+ int len;
+
+ va_list ap;
+
+ va_start(ap, fmt);
+ len = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
+ if ((buff = malloc(len)))
+ {
+ int written;
+
+ va_start(ap, fmt);
+ vsnprintf(buff, len, fmt, ap);
+ va_end(ap);
+
+ /*
+ * HACK. This assumes fs_printf is always called with the
+ * intention of writing text, and not arbitrary data.
+ */
+
+ written = write_lines(buff, strlen(buff), fh);
+
+ free(buff);
+
+ return written;
+ }
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
--- /dev/null
+#ifndef FS_H
+#define FS_H
+
+typedef struct fs_file *fs_file;
+
+int fs_init(const char *argv0);
+int fs_quit(void);
+
+const char *fs_error(void);
+
+const char *fs_base_dir(void);
+int fs_add_path(const char *);
+int fs_add_path_with_archives(const char *);
+int fs_set_write_dir(const char *);
+
+int fs_exists(const char *);
+int fs_remove(const char *);
+int fs_rename(const char *, const char *);
+
+fs_file fs_open(const char *path, const char *mode);
+int fs_close(fs_file);
+
+int fs_read(void *data, int size, int count, fs_file);
+int fs_write(const void *data, int size, int count, fs_file);
+int fs_flush(fs_file);
+long fs_tell(fs_file);
+int fs_seek(fs_file, long offset, int whence);
+int fs_eof(fs_file);
+
+int fs_getc(fs_file);
+char *fs_gets(char *dst, int count, fs_file fh);
+int fs_putc(int c, fs_file);
+int fs_puts(const char *src, fs_file);
+
+int fs_mkdir(const char *);
+
+#include <stdarg.h>
+
+int fs_printf(fs_file, const char *fmt, ...);
+
+#include "dir.h"
+#include "array.h"
+
+Array fs_dir_scan(const char *, int (*filter)(struct dir_item *));
+void fs_dir_free(Array);
+
+#endif
--- /dev/null
+/*
+ * jdatasrc.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains decompression data source routines for the case of
+ * reading JPEG data from a file (or any stdio stream). While these routines
+ * are sufficient for most applications, some will want to use a different
+ * source manager.
+ * IMPORTANT: we assume that fread() will correctly transcribe an array of
+ * JOCTETs from 8-bit-wide elements on external storage. If char is wider
+ * than 8 bits on your machine, you may need to do some tweaking.
+ */
+
+/* -------------------------------------------------------------------------- */
+
+#include "fs.h"
+#include "fs_jpg.h"
+
+/* -------------------------------------------------------------------------- */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jpeglib.h"
+#include "jerror.h"
+
+/* Expanded data source object for stdio input */
+
+typedef struct {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ fs_file infile; /* source stream */
+ JOCTET * buffer; /* start of buffer */
+ boolean start_of_file; /* have we gotten any data yet? */
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
+
+
+/*
+ * Initialize source --- called by jpeg_read_header
+ * before any data is actually read.
+ */
+
+METHODDEF(void)
+init_source (j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ /* We reset the empty-input-file flag for each image,
+ * but we don't clear the input buffer.
+ * This is correct behavior for reading a series of images from one source.
+ */
+ src->start_of_file = TRUE;
+}
+
+
+/*
+ * Fill the input buffer --- called whenever buffer is emptied.
+ *
+ * In typical applications, this should read fresh data into the buffer
+ * (ignoring the current state of next_input_byte & bytes_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been reloaded. It is not necessary to
+ * fill the buffer entirely, only to obtain at least one more byte.
+ *
+ * There is no such thing as an EOF return. If the end of the file has been
+ * reached, the routine has a choice of ERREXIT() or inserting fake data into
+ * the buffer. In most cases, generating a warning message and inserting a
+ * fake EOI marker is the best course of action --- this will allow the
+ * decompressor to output however much of the image is there. However,
+ * the resulting error message is misleading if the real problem is an empty
+ * input file, so we handle that case specially.
+ *
+ * In applications that need to be able to suspend compression due to input
+ * not being available yet, a FALSE return indicates that no more data can be
+ * obtained right now, but more may be forthcoming later. In this situation,
+ * the decompressor will return to its caller (with an indication of the
+ * number of scanlines it has read, if any). The application should resume
+ * decompression after it has loaded more data into the input buffer. Note
+ * that there are substantial restrictions on the use of suspension --- see
+ * the documentation.
+ *
+ * When suspending, the decompressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point must be rescanned after resumption, so move it to
+ * the front of the buffer rather than discarding it.
+ */
+
+METHODDEF(boolean)
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+ size_t nbytes;
+
+ nbytes = fs_read(src->buffer, 1, INPUT_BUF_SIZE, src->infile);
+
+ if (nbytes <= 0) {
+ if (src->start_of_file) /* Treat empty input file as fatal error */
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ nbytes = 2;
+ }
+
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+ src->start_of_file = FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Skip data --- used to skip over a potentially large amount of
+ * uninteresting data (such as an APPn marker).
+ *
+ * Writers of suspendable-input applications must note that skip_input_data
+ * is not granted the right to give a suspension return. If the skip extends
+ * beyond the data currently in the buffer, the buffer can be marked empty so
+ * that the next read will cause a fill_input_buffer call that can suspend.
+ * Arranging for additional bytes to be discarded before reloading the input
+ * buffer is the application writer's problem.
+ */
+
+METHODDEF(void)
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ /* Just a dumb implementation for now. Could use fseek() except
+ * it doesn't work on pipes. Not clear that being smart is worth
+ * any trouble anyway --- large skips are infrequent.
+ */
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->pub.bytes_in_buffer) {
+ num_bytes -= (long) src->pub.bytes_in_buffer;
+ (void) fill_input_buffer(cinfo);
+ /* note we assume that fill_input_buffer will never return FALSE,
+ * so suspension need not be handled.
+ */
+ }
+ src->pub.next_input_byte += (size_t) num_bytes;
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+
+/*
+ * An additional method that can be provided by data source modules is the
+ * resync_to_restart method for error recovery in the presence of RST markers.
+ * For the moment, this source module just uses the default resync method
+ * provided by the JPEG library. That method assumes that no backtracking
+ * is possible.
+ */
+
+
+/*
+ * Terminate source --- called by jpeg_finish_decompress
+ * after all data has been read. Often a no-op.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+ * Prepare for input from a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing decompression.
+ */
+
+GLOBAL(void)
+fs_jpg_src (j_decompress_ptr cinfo, fs_file infile)
+{
+ my_src_ptr src;
+
+ /* The source object and input buffer are made permanent so that a series
+ * of JPEG images can be read from the same file by calling jpeg_stdio_src
+ * only before the first one. (If we discarded the buffer at the end of
+ * one image, we'd likely lose the start of the next one.)
+ * This makes it unsafe to use this manager and a different source
+ * manager serially with the same JPEG object. Caveat programmer.
+ */
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ sizeof (my_source_mgr));
+ src = (my_src_ptr) cinfo->src;
+ src->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ INPUT_BUF_SIZE * sizeof (JOCTET));
+ }
+
+ src = (my_src_ptr) cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->pub.term_source = term_source;
+ src->infile = infile;
+ src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+ src->pub.next_input_byte = NULL; /* until buffer loaded */
+}
--- /dev/null
+#ifndef FS_JPG
+#define FS_JPG
+
+/*
+ * jpeglib.h triggers errors due to missing size_t and FILE type
+ * definitions. Include these two headers as a workaround.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <jpeglib.h>
+
+#include "fs.h"
+
+void fs_jpg_src(j_decompress_ptr cinfo, fs_file infile);
+
+#endif
--- /dev/null
+#include "fs.h"
+#include "fs_ov.h"
+
+size_t fs_ov_read(void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+ return fs_read(ptr, size, nmemb, datasource);
+}
+
+int fs_ov_seek(void *datasource, ogg_int64_t offset, int whence)
+{
+ return fs_seek(datasource, offset, whence);
+}
+
+int fs_ov_close(void *datasource)
+{
+ return fs_close(datasource);
+}
+
+long fs_ov_tell(void *datasource)
+{
+ return fs_tell(datasource);
+}
--- /dev/null
+#ifndef FS_OV
+#define FS_OV
+
+#include <vorbis/vorbisfile.h>
+
+size_t fs_ov_read(void *ptr, size_t size, size_t nmemb, void *datasource);
+int fs_ov_seek(void *datasource, ogg_int64_t offset, int whence);
+int fs_ov_close(void *datasource);
+long fs_ov_tell(void *datasource);
+
+#endif
--- /dev/null
+#include <png.h>
+#include <string.h>
+#include "fs_png.h"
+#include "fs.h"
+
+/*---------------------------------------------------------------------------*/
+
+void fs_png_read(png_structp readp, png_bytep data, png_size_t length)
+{
+ int read = fs_read(data, 1, length, png_get_io_ptr(readp));
+
+ if (read < length)
+ memset(data + read, 0, length - read);
+}
+
+void fs_png_write(png_structp writep, png_bytep data, png_size_t length)
+{
+ fs_write(data, 1, length, png_get_io_ptr(writep));
+}
+
+void fs_png_flush(png_structp writep)
+{
+ fs_flush(png_get_io_ptr(writep));
+}
+
+/*---------------------------------------------------------------------------*/
--- /dev/null
+#ifndef FS_PNG
+#define FS_PNG
+
+#include <png.h>
+
+void fs_png_read (png_structp readp, png_bytep data, png_size_t length);
+void fs_png_write(png_structp writep, png_bytep data, png_size_t length);
+void fs_png_flush(png_structp writep);
+
+#endif
--- /dev/null
+#include "fs_rwops.h"
+
+static int rwops_seek(SDL_RWops *ctx, int offset, int whence)
+{
+ fs_file fh = ctx->hidden.unknown.data1;
+ return fs_seek(fh, offset, whence) ? fs_tell(fh) : -1;
+}
+
+static int rwops_read(SDL_RWops *ctx, void *ptr, int size, int maxnum)
+{
+ return fs_read(ptr, size, maxnum, ctx->hidden.unknown.data1);
+}
+
+static int rwops_write(SDL_RWops *ctx, const void *ptr, int size, int num)
+{
+ return fs_write(ptr, size, num, ctx->hidden.unknown.data1);
+}
+
+static int rwops_close(SDL_RWops *ctx)
+{
+ fs_file fh = ctx->hidden.unknown.data1;
+
+ if (!fs_close(fh))
+ return -1;
+
+ SDL_FreeRW(ctx);
+ return 0;
+}
+
+SDL_RWops *fs_rwops_make(fs_file fh)
+{
+ SDL_RWops *ctx;
+
+ if ((ctx = SDL_AllocRW()))
+ {
+ ctx->seek = rwops_seek;
+ ctx->read = rwops_read;
+ ctx->write = rwops_write;
+ ctx->close = rwops_close;
+
+ ctx->hidden.unknown.data1 = fh;
+ }
+
+ return ctx;
+}
+
+SDL_RWops *fs_rwops_open(const char *path, const char *mode)
+{
+ fs_file fh;
+
+ if ((fh = fs_open(path, mode)))
+ return fs_rwops_make(fh);
+
+ return NULL;
+}
--- /dev/null
+#ifndef FS_RWOPS_H
+#define FS_RWOPS_H
+
+#include <SDL_rwops.h>
+#include "fs.h"
+
+SDL_RWops *fs_rwops_make(fs_file);
+SDL_RWops *fs_rwops_open(const char *path, const char *mode);
+
+#endif
#include "gui.h"
#include "common.h"
+#include "fs.h"
+#include "fs_rwops.h"
+
/*---------------------------------------------------------------------------*/
#define MAXWIDGET 256
static int active;
static int radius;
static TTF_Font *font[3] = { NULL, NULL, NULL };
+static SDL_RWops *fontrwops;
static GLuint digit_text[3][11];
static GLuint digit_list[3][11];
{
const char *path;
- path = config_data(_(GUI_FACE));
+ path = _(GUI_FACE);
- if (!file_exists(path))
+ if (!fs_exists(path))
{
fprintf(stderr, _("Font \"%s\" doesn't exist, trying default font.\n"),
path);
- path = config_data(GUI_FACE);
+ path = GUI_FACE;
}
return path;
/* Load small, medium, and large typefaces. */
- font[GUI_SML] = TTF_OpenFont(fontpath, s0);
- font[GUI_MED] = TTF_OpenFont(fontpath, s1);
- font[GUI_LRG] = TTF_OpenFont(fontpath, s2);
+ if (!(fontrwops = fs_rwops_open(fontpath, "r")))
+ {
+ fprintf(stderr, _("Could not open font %s.\n"), fontpath);
+ /* Return or no return, we'll probably crash now. */
+ return;
+ }
+
+ font[GUI_SML] = TTF_OpenFontRW(fontrwops, 0, s0);
+
+ SDL_RWseek(fontrwops, 0, SEEK_SET);
+ font[GUI_MED] = TTF_OpenFontRW(fontrwops, 0, s1);
+
+ SDL_RWseek(fontrwops, 0, SEEK_SET);
+ font[GUI_LRG] = TTF_OpenFontRW(fontrwops, 0, s2);
+
+ /* fontrwops remains open. */
+
radius = s / 60;
/* Initialize digit glyphs and lists for counters and clocks. */
if (font[GUI_MED]) TTF_CloseFont(font[GUI_MED]);
if (font[GUI_SML]) TTF_CloseFont(font[GUI_SML]);
+ if (fontrwops) SDL_RWclose(fontrwops);
+
TTF_Quit();
}
#include "base_image.h"
#include "config.h"
+#include "fs.h"
+#include "fs_png.h"
+
/*---------------------------------------------------------------------------*/
void image_snap(const char *filename)
{
- FILE *filep = NULL;
+ fs_file filep = NULL;
png_structp writep = NULL;
png_infop infop = NULL;
png_bytep *bytep = NULL;
/* Initialize all PNG export data structures. */
- if (!(filep = fopen(filename, FMODE_WB)))
+ if (!(filep = fs_open(filename, "w")))
return;
if (!(writep = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0)))
return;
{
/* Initialize the PNG header. */
- png_init_io (writep, filep);
+ png_set_write_fn(writep, filep, fs_png_write, fs_png_flush);
png_set_IHDR(writep, infop, w, h, 8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
/* Release all resources. */
png_destroy_write_struct(&writep, &infop);
- fclose(filep);
+ fs_close(filep);
}
/*---------------------------------------------------------------------------*/
/* Load the image. */
- if ((p = image_load(config_data(filename), &w, &h, &b)))
+ if ((p = image_load(filename, &w, &h, &b)))
{
o = make_texture(p, w, h, b);
free(p);
amask = 0xFF000000;
#endif
- if ((p = image_load(config_data(filename), &w, &h, &b)))
+ if ((p = image_load(filename, &w, &h, &b)))
{
void *q;
{
int T = config_get_d(CONFIG_TEXTURES);
- sol_load_gl(&item_coin_file, config_data("item/coin/coin.sol"), T, 0);
- sol_load_gl(&item_grow_file, config_data("item/grow/grow.sol"), T, 0);
- sol_load_gl(&item_shrink_file, config_data("item/shrink/shrink.sol"), T, 0);
+ sol_load_gl(&item_coin_file, "item/coin/coin.sol", T, 0);
+ sol_load_gl(&item_grow_file, "item/grow/grow.sol", T, 0);
+ sol_load_gl(&item_shrink_file, "item/shrink/shrink.sol", T, 0);
}
void item_free(void)
#include "lang.h"
#include "common.h"
#include "base_config.h"
+#include "fs.h"
/*---------------------------------------------------------------------------*/
void lang_init(const char *domain)
{
#if ENABLE_NLS
- char *dir = getenv("NEVERBALL_LOCALE");
+ char *dir = strdup(getenv("NEVERBALL_LOCALE"));
if (!dir)
- dir = path_resolve(config_exec_path, CONFIG_LOCALE);
+ dir = concat_string(fs_base_dir(), "/", CONFIG_LOCALE, NULL);
errno = 0;
bindtextdomain(domain, dir);
bind_textdomain_codeset(domain, DEFAULT_CODESET);
textdomain(domain);
+
+ free(dir);
#else
return;
#endif
#include "solid.h"
#include "base_image.h"
#include "base_config.h"
+#include "fs.h"
+#include "common.h"
#define MAXSTR 256
#define MAXKEY 16
strcpy(jpg, name); strcat(jpg, ".jpg");
strcpy(png, name); strcat(png, ".png");
- if (size_load(config_data(png), w, h) ||
- size_load(config_data(jpg), w, h))
+ if (size_load(png, w, h) ||
+ size_load(jpg, w, h))
{
if (image_n + 1 >= image_alloc)
/* Read the given material file, adding a new material to the solid. */
+#define scan_vec4(f, s, v) \
+ if (fs_gets((s), sizeof (s), (f))) \
+ sscanf((s), "%f %f %f %f", (v), (v) + 1, (v) + 2, (v) + 3)
+
static int read_mtrl(struct s_file *fp, const char *name)
{
+ static char line[MAXSTR];
struct s_mtrl *mp;
- FILE *fin;
+ fs_file fin;
int mi;
for (mi = 0; mi < fp->mc; mi++)
mp->fl = 0;
mp->angle = 45.0f;
- if ((fin = fopen(config_data(name), "r")))
+ if ((fin = fs_open(name, "r")))
{
- fscanf(fin,
- "%f %f %f %f "
- "%f %f %f %f "
- "%f %f %f %f "
- "%f %f %f %f "
- "%f %d %f",
- mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
- mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
- mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
- mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
- mp->h, &mp->fl, &mp->angle);
- fclose(fin);
+ scan_vec4(fin, line, mp->d);
+ scan_vec4(fin, line, mp->a);
+ scan_vec4(fin, line, mp->s);
+ scan_vec4(fin, line, mp->e);
+
+ if (fs_gets(line, sizeof (line), fin))
+ mp->h[0] = strtod(line, NULL);
+
+ if (fs_gets(line, sizeof (line), fin))
+ mp->fl = strtol(line, NULL, 10);
+
+ if (fs_gets(line, sizeof (line), fin))
+ mp->angle = strtod(line, NULL);
+
+ fs_close(fin);
}
return mi;
}
+#undef scan_vec4
+
/*---------------------------------------------------------------------------*/
/*
{
char line[MAXSTR];
char mtrl[MAXSTR];
- FILE *fin;
+ fs_file fin;
int v0 = fp->vc;
int t0 = fp->tc;
int s0 = fp->sc;
- if ((fin = fopen(config_data(name), "r")))
+ if ((fin = fs_open(name, "r")))
{
- while (fgets(line, MAXSTR, fin))
+ while (fs_gets(line, MAXSTR, fin))
{
if (strncmp(line, "usemtl", 6) == 0)
{
else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
}
- fclose(fin);
+ fs_close(fin);
}
}
#define T_END 4
#define T_NOP 5
-static int map_token(FILE *fin, int pi, char key[MAXSTR], char val[MAXSTR])
+static int map_token(fs_file fin, int pi, char key[MAXSTR], char val[MAXSTR])
{
char buf[MAXSTR];
- if (fgets(buf, MAXSTR, fin))
+ if (fs_gets(buf, MAXSTR, fin))
{
char c;
float x0, y0, z0;
/* Parse a lump from the given file and add it to the solid. */
-static void read_lump(struct s_file *fp, FILE *fin)
+static void read_lump(struct s_file *fp, fs_file fin)
{
char k[MAXSTR];
char v[MAXSTR];
/*---------------------------------------------------------------------------*/
-static void read_ent(struct s_file *fp, FILE *fin)
+static void read_ent(struct s_file *fp, fs_file fin)
{
char k[MAXKEY][MAXSTR];
char v[MAXKEY][MAXSTR];
if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
}
-static void read_map(struct s_file *fp, FILE *fin)
+static void read_map(struct s_file *fp, fs_file fin)
{
char k[MAXSTR];
char v[MAXSTR];
char src[MAXSTR];
char dst[MAXSTR];
struct s_file f;
- FILE *fin;
+ fs_file fin;
- config_exec_path = argv[0];
+ if (!fs_init(argv[0]))
+ {
+ fprintf(stderr, "Failure to initialize virtual file system\n");
+ return 1;
+ }
if (argc > 2)
{
if (argc > 3 && strcmp(argv[3], "--debug") == 0)
debug_output = 1;
- if (config_data_path(argv[2], NULL))
- {
- strncpy(src, argv[1], MAXSTR);
- strncpy(dst, argv[1], MAXSTR);
+ fs_add_path (dir_name(argv[1]));
+ fs_set_write_dir(dir_name(argv[1]));
- if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
- strcpy(dst + strlen(dst) - 4, ".sol");
- else
- strcat(dst, ".sol");
+ strncpy(src, base_name(argv[1], NULL), MAXSTR);
+ strncpy(dst, src, MAXSTR);
+
+ if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
+ strcpy(dst + strlen(dst) - 4, ".sol");
+ else
+ strcat(dst, ".sol");
- if ((fin = fopen(src, "r")))
+ if ((fin = fs_open(src, "r")))
+ {
+ if (!fs_add_path_with_archives(argv[2]))
{
- init_file(&f);
- read_map(&f, fin);
+ fprintf(stderr, "Failure to establish data directory\n");
+ fs_close(fin);
+ fs_quit();
+ return 1;
+ }
- resolve();
- targets(&f);
+ init_file(&f);
+ read_map(&f, fin);
- clip_file(&f);
- move_file(&f);
- uniq_file(&f);
- smth_file(&f);
- sort_file(&f);
- node_file(&f);
- dump_file(&f, dst);
+ resolve();
+ targets(&f);
- sol_stor(&f, dst);
+ clip_file(&f);
+ move_file(&f);
+ uniq_file(&f);
+ smth_file(&f);
+ sort_file(&f);
+ node_file(&f);
+ dump_file(&f, dst);
- fclose(fin);
+ sol_stor(&f, dst);
- free_imagedata();
- }
+ fs_close(fin);
+
+ free_imagedata();
}
- else fprintf(stderr, "Failure to establish data directory\n");
}
else fprintf(stderr, "Usage: %s <map> <data> [--debug]\n", argv[0]);
#include "solid.h"
#include "base_config.h"
#include "binary.h"
+#include "fs.h"
#define MAGIC 0x4c4f53af
#define SOL_VERSION 6
/*---------------------------------------------------------------------------*/
-static void sol_load_mtrl(FILE *fin, struct s_mtrl *mp)
+static void sol_load_mtrl(fs_file fin, struct s_mtrl *mp)
{
get_array(fin, mp->d, 4);
get_array(fin, mp->a, 4);
get_array(fin, mp->h, 1);
get_index(fin, &mp->fl);
- fread(mp->f, 1, PATHMAX, fin);
+ fs_read(mp->f, 1, PATHMAX, fin);
}
-static void sol_load_vert(FILE *fin, struct s_vert *vp)
+static void sol_load_vert(fs_file fin, struct s_vert *vp)
{
get_array(fin, vp->p, 3);
}
-static void sol_load_edge(FILE *fin, struct s_edge *ep)
+static void sol_load_edge(fs_file fin, struct s_edge *ep)
{
get_index(fin, &ep->vi);
get_index(fin, &ep->vj);
}
-static void sol_load_side(FILE *fin, struct s_side *sp)
+static void sol_load_side(fs_file fin, struct s_side *sp)
{
get_array(fin, sp->n, 3);
get_float(fin, &sp->d);
}
-static void sol_load_texc(FILE *fin, struct s_texc *tp)
+static void sol_load_texc(fs_file fin, struct s_texc *tp)
{
get_array(fin, tp->u, 2);
}
-static void sol_load_geom(FILE *fin, struct s_geom *gp)
+static void sol_load_geom(fs_file fin, struct s_geom *gp)
{
get_index(fin, &gp->mi);
get_index(fin, &gp->ti);
get_index(fin, &gp->vk);
}
-static void sol_load_lump(FILE *fin, struct s_lump *lp)
+static void sol_load_lump(fs_file fin, struct s_lump *lp)
{
get_index(fin, &lp->fl);
get_index(fin, &lp->v0);
get_index(fin, &lp->sc);
}
-static void sol_load_node(FILE *fin, struct s_node *np)
+static void sol_load_node(fs_file fin, struct s_node *np)
{
get_index(fin, &np->si);
get_index(fin, &np->ni);
get_index(fin, &np->lc);
}
-static void sol_load_path(FILE *fin, struct s_path *pp)
+static void sol_load_path(fs_file fin, struct s_path *pp)
{
get_array(fin, pp->p, 3);
get_float(fin, &pp->t);
get_index(fin, &pp->s);
}
-static void sol_load_body(FILE *fin, struct s_body *bp)
+static void sol_load_body(fs_file fin, struct s_body *bp)
{
get_index(fin, &bp->pi);
get_index(fin, &bp->ni);
get_index(fin, &bp->gc);
}
-static void sol_load_item(FILE *fin, struct s_item *hp)
+static void sol_load_item(fs_file fin, struct s_item *hp)
{
get_array(fin, hp->p, 3);
get_index(fin, &hp->t);
get_index(fin, &hp->n);
}
-static void sol_load_goal(FILE *fin, struct s_goal *zp)
+static void sol_load_goal(fs_file fin, struct s_goal *zp)
{
get_array(fin, zp->p, 3);
get_float(fin, &zp->r);
}
-static void sol_load_swch(FILE *fin, struct s_swch *xp)
+static void sol_load_swch(fs_file fin, struct s_swch *xp)
{
get_array(fin, xp->p, 3);
get_float(fin, &xp->r);
get_index(fin, &xp->i);
}
-static void sol_load_bill(FILE *fin, struct s_bill *rp)
+static void sol_load_bill(fs_file fin, struct s_bill *rp)
{
get_index(fin, &rp->fl);
get_index(fin, &rp->mi);
get_array(fin, rp->p, 3);
}
-static void sol_load_jump(FILE *fin, struct s_jump *jp)
+static void sol_load_jump(fs_file fin, struct s_jump *jp)
{
get_array(fin, jp->p, 3);
get_array(fin, jp->q, 3);
get_float(fin, &jp->r);
}
-static void sol_load_ball(FILE *fin, struct s_ball *bp)
+static void sol_load_ball(fs_file fin, struct s_ball *bp)
{
get_array(fin, bp->p, 3);
get_float(fin, &bp->r);
bp->e[2][2] = bp->E[2][2] = 1.0f;
}
-static void sol_load_view(FILE *fin, struct s_view *wp)
+static void sol_load_view(fs_file fin, struct s_view *wp)
{
get_array(fin, wp->p, 3);
get_array(fin, wp->q, 3);
}
-static void sol_load_dict(FILE *fin, struct s_dict *dp)
+static void sol_load_dict(fs_file fin, struct s_dict *dp)
{
get_index(fin, &dp->ai);
get_index(fin, &dp->aj);
}
-static int sol_load_file(FILE *fin, struct s_file *fp)
+static int sol_load_file(fs_file fin, struct s_file *fp)
{
int i;
int magic;
fp->iv = (int *) calloc(fp->ic, sizeof (int));
if (fp->ac)
- fread(fp->av, 1, fp->ac, fin);
+ fs_read(fp->av, 1, fp->ac, fin);
for (i = 0; i < fp->dc; i++) sol_load_dict(fin, fp->dv + i);
for (i = 0; i < fp->mc; i++) sol_load_mtrl(fin, fp->mv + i);
return 1;
}
-static int sol_load_head(FILE *fin, struct s_file *fp)
+static int sol_load_head(fs_file fin, struct s_file *fp)
{
int magic;
int version;
get_index(fin, &fp->wc);
get_index(fin, &fp->ic);
#endif
- fseek(fin, 18 * 4, SEEK_CUR);
+ fs_seek(fin, 18 * 4, SEEK_CUR);
if (fp->ac)
{
fp->av = (char *) calloc(fp->ac, sizeof (char));
- fread(fp->av, 1, fp->ac, fin);
+ fs_read(fp->av, 1, fp->ac, fin);
}
if (fp->dc)
int sol_load_only_file(struct s_file *fp, const char *filename)
{
- FILE *fin;
+ fs_file fin;
int res = 0;
- if ((fin = fopen(filename, FMODE_RB)))
+ if ((fin = fs_open(filename, "r")))
{
res = sol_load_file(fin, fp);
- fclose(fin);
+ fs_close(fin);
}
return res;
}
int sol_load_only_head(struct s_file *fp, const char *filename)
{
- FILE *fin;
+ fs_file fin;
int res = 0;
- if ((fin = fopen(filename, FMODE_RB)))
+ if ((fin = fs_open(filename, "r")))
{
res = sol_load_head(fin, fp);
- fclose(fin);
+ fs_close(fin);
}
return res;
}
/*---------------------------------------------------------------------------*/
-static void sol_stor_mtrl(FILE *fout, struct s_mtrl *mp)
+static void sol_stor_mtrl(fs_file fout, struct s_mtrl *mp)
{
put_array(fout, mp->d, 4);
put_array(fout, mp->a, 4);
put_array(fout, mp->h, 1);
put_index(fout, &mp->fl);
- fwrite(mp->f, 1, PATHMAX, fout);
+ fs_write(mp->f, 1, PATHMAX, fout);
}
-static void sol_stor_vert(FILE *fout, struct s_vert *vp)
+static void sol_stor_vert(fs_file fout, struct s_vert *vp)
{
put_array(fout, vp->p, 3);
}
-static void sol_stor_edge(FILE *fout, struct s_edge *ep)
+static void sol_stor_edge(fs_file fout, struct s_edge *ep)
{
put_index(fout, &ep->vi);
put_index(fout, &ep->vj);
}
-static void sol_stor_side(FILE *fout, struct s_side *sp)
+static void sol_stor_side(fs_file fout, struct s_side *sp)
{
put_array(fout, sp->n, 3);
put_float(fout, &sp->d);
}
-static void sol_stor_texc(FILE *fout, struct s_texc *tp)
+static void sol_stor_texc(fs_file fout, struct s_texc *tp)
{
put_array(fout, tp->u, 2);
}
-static void sol_stor_geom(FILE *fout, struct s_geom *gp)
+static void sol_stor_geom(fs_file fout, struct s_geom *gp)
{
put_index(fout, &gp->mi);
put_index(fout, &gp->ti);
put_index(fout, &gp->vk);
}
-static void sol_stor_lump(FILE *fout, struct s_lump *lp)
+static void sol_stor_lump(fs_file fout, struct s_lump *lp)
{
put_index(fout, &lp->fl);
put_index(fout, &lp->v0);
put_index(fout, &lp->sc);
}
-static void sol_stor_node(FILE *fout, struct s_node *np)
+static void sol_stor_node(fs_file fout, struct s_node *np)
{
put_index(fout, &np->si);
put_index(fout, &np->ni);
put_index(fout, &np->lc);
}
-static void sol_stor_path(FILE *fout, struct s_path *pp)
+static void sol_stor_path(fs_file fout, struct s_path *pp)
{
put_array(fout, pp->p, 3);
put_float(fout, &pp->t);
put_index(fout, &pp->s);
}
-static void sol_stor_body(FILE *fout, struct s_body *bp)
+static void sol_stor_body(fs_file fout, struct s_body *bp)
{
put_index(fout, &bp->pi);
put_index(fout, &bp->ni);
put_index(fout, &bp->gc);
}
-static void sol_stor_item(FILE *fout, struct s_item *hp)
+static void sol_stor_item(fs_file fout, struct s_item *hp)
{
put_array(fout, hp->p, 3);
put_index(fout, &hp->t);
put_index(fout, &hp->n);
}
-static void sol_stor_goal(FILE *fout, struct s_goal *zp)
+static void sol_stor_goal(fs_file fout, struct s_goal *zp)
{
put_array(fout, zp->p, 3);
put_float(fout, &zp->r);
}
-static void sol_stor_swch(FILE *fout, struct s_swch *xp)
+static void sol_stor_swch(fs_file fout, struct s_swch *xp)
{
put_array(fout, xp->p, 3);
put_float(fout, &xp->r);
put_index(fout, &xp->i);
}
-static void sol_stor_bill(FILE *fout, struct s_bill *rp)
+static void sol_stor_bill(fs_file fout, struct s_bill *rp)
{
put_index(fout, &rp->fl);
put_index(fout, &rp->mi);
put_array(fout, rp->p, 3);
}
-static void sol_stor_jump(FILE *fout, struct s_jump *jp)
+static void sol_stor_jump(fs_file fout, struct s_jump *jp)
{
put_array(fout, jp->p, 3);
put_array(fout, jp->q, 3);
put_float(fout, &jp->r);
}
-static void sol_stor_ball(FILE *fout, struct s_ball *bp)
+static void sol_stor_ball(fs_file fout, struct s_ball *bp)
{
put_array(fout, bp->p, 3);
put_float(fout, &bp->r);
}
-static void sol_stor_view(FILE *fout, struct s_view *wp)
+static void sol_stor_view(fs_file fout, struct s_view *wp)
{
put_array(fout, wp->p, 3);
put_array(fout, wp->q, 3);
}
-static void sol_stor_dict(FILE *fout, struct s_dict *dp)
+static void sol_stor_dict(fs_file fout, struct s_dict *dp)
{
put_index(fout, &dp->ai);
put_index(fout, &dp->aj);
}
-static void sol_stor_file(FILE *fout, struct s_file *fp)
+static void sol_stor_file(fs_file fout, struct s_file *fp)
{
int i;
int magic = MAGIC;
put_index(fout, &fp->wc);
put_index(fout, &fp->ic);
- fwrite(fp->av, 1, fp->ac, fout);
+ fs_write(fp->av, 1, fp->ac, fout);
for (i = 0; i < fp->dc; i++) sol_stor_dict(fout, fp->dv + i);
for (i = 0; i < fp->mc; i++) sol_stor_mtrl(fout, fp->mv + i);
int sol_stor(struct s_file *fp, const char *filename)
{
- FILE *fout;
+ fs_file fout;
- if ((fout = fopen(filename, FMODE_WB)))
+ if ((fout = fs_open(filename, "w")))
{
sol_stor_file(fout, fp);
- fclose(fout);
+ fs_close(fout);
return 1;
}
* [*] http://standards.freedesktop.org/wm-spec/latest/
*/
- if ((p = image_load(config_data(filename), &w, &h, &b)))
+ if ((p = image_load(filename, &w, &h, &b)))
{
long *data = NULL;