ocarina/include/core/file.h

148 lines
4.5 KiB
C

/*
* Copyright 2013 (c) Anna Schumaker.
*
* File data is store in the user's home directory according to the
* XDG / freedesktop.org specification, meaning all of our data will
* be stored in a subdirectory of $XDG_DATA_HOME. The actual subdirectory
* changes based on what configuration values the user has set when Ocarina
* is compiled.
*
* Config Value | Ocarina Directory
* ---------------|--------------------
* default | $XDG_DATA_HOME/ocarina/
* CONFIG_DEBUG | $XDG_DATA_HOME/ocarina-debug/
* CONFIG_TESTING | $XDG_DATA_HOME/ocarina-test/
*
* The beginning of every file is the current file version followed by a
* newline. For example:
*
* 42
* <data> <more data>
* <even more data>
*/
#ifndef OCARINA_CORE_FILE_H
#define OCARINA_CORE_FILE_H
#include <core/version.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <stdbool.h>
enum open_mode {
OPEN_READ,
OPEN_WRITE,
};
struct data_file {
enum open_mode f_mode; /* The file's current open mode. */
unsigned int f_version; /* The file's current data version. */
unsigned int f_prev; /* The file's on-disk data version. */
unsigned int f_min; /* The file's minimum data version. */
};
struct file {
FILE *f_file; /* The file's IO stream. */
const gchar *f_name; /* The file's basename. */
const gchar *f_subdir; /* The file's subdirectory. */
struct data_file f_data;
const gchar *(*f_user_dir)(void); /* The file's user directory. */
};
#define FILE_INIT_DATA(fdir, fname, min) \
{ \
.f_file = NULL, \
.f_name = fname, \
.f_subdir = fdir, \
.f_user_dir = g_get_user_data_dir, \
.f_data = { \
.f_mode = OPEN_READ, \
.f_version = OCARINA_MINOR_VERSION, \
.f_prev = 0, \
.f_min = min, \
} \
}
/* Initialize a file object. */
void file_init_data(struct file *, const gchar *, const gchar *, unsigned int);
void file_init_cache(struct file *, const gchar *, const gchar *);
/*
* Returns the full path of the file or an empty string if filename is not set.
* NOTE: This function allocates a new string that MUST be freed with g_free().
*/
gchar *file_path(struct file *);
/*
* Returns the path to the temporary file used for writes.
* This function allocates a new string that MUST be freed with g_free().
*/
gchar *data_file_write_path(struct file *);
gchar *cache_file_write_path(struct file *);
/* Returns the version number of the file. */
const unsigned int data_file_version(struct file *);
/* Returns true if the file exists on disk and false otherwise. */
bool data_file_exists(struct file *);
bool cache_file_exists(struct file *);
/*
* Call to open a file for either reading or writing. Callers
* are expected to call file_close() when IO is completed.
*
* When opening a file for reading (OPEN_READ):
* - Check if the file exists.
* - Read in file->_prev_version from the start of the file.
*
* When opening a file for writing (OPEN_WRITE):
* - Create missing directories as needed.
* - Open a temporary file to protect data if Ocarina crashes.
* - Write file->_version to the start of the file (data files only).
*
* Returns true if the open was successful and false otherwise.
* Oening a cache file with OPEN_READ is currently unsupported.
*/
bool data_file_open(struct file *, enum open_mode);
bool cache_file_open(struct file *, enum open_mode);
/*
* Closes an open file, setting file->{f|cf}_file to NULL. If the file was opened
* with OPEN_WRITE, then rename the temporary file to file_path().
*/
void data_file_close(struct file *);
void cache_file_close(struct file *);
/*
* Read an entire line from the file and return it to the caller.
* This function allocates a new string that MUST be freed with g_free().
*/
gchar *data_file_readl(struct file *);
/*
* Read from a file with an fscanf(3) style format string.
* Returns the number of items matched.
*/
int data_file_readf(struct file *, const char *, ...);
/*
* Write to a file with an fprintf(3) style format string.
* Returns the number of bytes successfully written.
*/
int data_file_writef(struct file *, const char *, ...);
/*
* Write binary data to a cache file similar to fwrite(3).
* Returns the number of bytes successfully written.
*/
int cache_file_write(struct file *, const void *, size_t);
/* Import a file into the cache. */
bool cache_file_import(struct file *, const gchar *);
/* Removes a closed file from disk. */
bool data_file_remove(struct file *);
#endif /* OCARINA_CORE_FILE_H */