db9be296cb
Printing out the filename of the file that broke is generally helpful. Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
155 lines
2.9 KiB
C
155 lines
2.9 KiB
C
/*
|
|
* Copyright 2013 (c) Anna Schumaker.
|
|
*/
|
|
#include <core/file.h>
|
|
#include <core/string.h>
|
|
#include <errno.h>
|
|
|
|
#ifdef CONFIG_TESTING
|
|
const gchar *OCARINA_DIR = "ocarina-test";
|
|
#elif CONFIG_DEBUG
|
|
const gchar *OCARINA_DIR = "ocarina-debug";
|
|
#else
|
|
const gchar *OCARINA_DIR = "ocarina";
|
|
#endif
|
|
|
|
#define REPORT_ERROR(fname) \
|
|
printf("%s (%s:%d): %s: %s\n", __func__, __FILE__, __LINE__, fname, strerror(errno))
|
|
|
|
|
|
static gchar *__file_path(gchar *name)
|
|
{
|
|
return g_strjoin("/", g_get_user_data_dir(), OCARINA_DIR, name, NULL);
|
|
}
|
|
|
|
static bool __file_mkdir()
|
|
{
|
|
gchar *dir = __file_path(NULL);
|
|
int ret = g_mkdir_with_parents(dir, 0755);
|
|
|
|
g_free(dir);
|
|
if (ret != 0)
|
|
REPORT_ERROR(dir);
|
|
return ret == 0;
|
|
}
|
|
|
|
|
|
void file_init(struct file *file, const gchar *name, unsigned int version)
|
|
{
|
|
file->f_mode = OPEN_READ;
|
|
file->f_version = version;
|
|
file->f_prev = 0;
|
|
file->f_file = NULL;
|
|
g_strlcpy(file->f_name, (name == NULL) ? "" : name, FILE_MAX_LEN);
|
|
}
|
|
|
|
gchar *file_path(struct file *file)
|
|
{
|
|
if (strlen(file->f_name) != 0)
|
|
return __file_path(file->f_name);
|
|
return g_strdup("");
|
|
}
|
|
|
|
const unsigned int file_version(struct file *file)
|
|
{
|
|
if (file->f_file && (file->f_mode == OPEN_READ))
|
|
return file->f_prev;
|
|
return file->f_version;
|
|
}
|
|
|
|
bool file_exists(struct file *file)
|
|
{
|
|
gchar *path = file_path(file);
|
|
bool ret = g_file_test(path, G_FILE_TEST_EXISTS);
|
|
|
|
g_free(path);
|
|
return ret;
|
|
}
|
|
|
|
static bool __file_open_common(struct file *file, enum open_mode mode)
|
|
{
|
|
gchar *path = file_path(file);
|
|
file->f_file = g_fopen(path, (mode == OPEN_READ) ? "r" : "w");
|
|
g_free(path);
|
|
|
|
if (!file->f_file) {
|
|
REPORT_ERROR(file->f_name);
|
|
return false;
|
|
}
|
|
|
|
file->f_mode = mode;
|
|
return true;
|
|
}
|
|
|
|
static bool __file_open_read(struct file *file)
|
|
{
|
|
if (!file_exists(file))
|
|
return false;
|
|
if (!__file_open_common(file, OPEN_READ))
|
|
return false;
|
|
return file_readf(file, "%u\n", &file->f_prev) == 1;
|
|
}
|
|
|
|
static bool __file_open_write(struct file *file)
|
|
{
|
|
if (!__file_mkdir())
|
|
return false;
|
|
if (!__file_open_common(file, OPEN_WRITE))
|
|
return false;
|
|
return file_writef(file, "%d\n", file->f_version) > 0;
|
|
}
|
|
|
|
bool file_open(struct file *file, enum open_mode mode)
|
|
{
|
|
if ((strlen(file->f_name) == 0) || (file->f_file != NULL))
|
|
return false;
|
|
|
|
if (mode == OPEN_READ)
|
|
return __file_open_read(file);
|
|
return __file_open_write(file);
|
|
}
|
|
|
|
void file_close(struct file *file)
|
|
{
|
|
if (file->f_file)
|
|
fclose(file->f_file);
|
|
file->f_file = NULL;
|
|
}
|
|
|
|
int file_readf(struct file *file, const char *fmt, ...)
|
|
{
|
|
va_list argp;
|
|
int ret;
|
|
|
|
va_start(argp, fmt);
|
|
ret = vfscanf(file->f_file, fmt, argp);
|
|
va_end(argp);
|
|
|
|
return ret;
|
|
}
|
|
|
|
gchar *file_readl(struct file *file)
|
|
{
|
|
gchar *res;
|
|
|
|
if (file_readf(file, "%m[^\n]\n", &res) == 0)
|
|
return g_strdup("");
|
|
|
|
g_strstrip(res);
|
|
return res;
|
|
}
|
|
|
|
int file_writef(struct file *file, const char *fmt, ...)
|
|
{
|
|
va_list argp;
|
|
int ret;
|
|
|
|
va_start(argp, fmt);
|
|
ret = g_vfprintf(file->f_file, fmt, argp);
|
|
va_end(argp);
|
|
|
|
if (ret < 0)
|
|
REPORT_ERROR(file->f_name);
|
|
return ret;
|
|
}
|