/* * 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 * * */ #ifndef OCARINA_CORE_FILE_H #define OCARINA_CORE_FILE_H #include #include #include #include enum open_mode { CLOSED, /* File is not open. */ OPEN_READ, /* File is open for reading text. */ OPEN_READ_BINARY, /* File is open for reading binary data. */ OPEN_WRITE, /* File is open for writing text. */ OPEN_WRITE_BINARY, /* File is open for writing binary data. */ }; 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. */ 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. */ 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_mode = CLOSED, \ .f_version = OCARINA_MINOR_VERSION, \ .f_prev = 0, \ .f_min = min, \ .f_user_dir = g_get_user_data_dir, \ } /* 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. * NOTE: This function allocates a new string that MUST be freed with g_free(). */ gchar *file_write_path(struct file *); /* Returns the version number of the file. */ const unsigned int file_version(struct file *); /* Returns true if the file exists on disk and false otherwise. */ bool 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 / OPEN_READ_BINARY): * - Check if the file exists * - If open for reading text (OPEN_READ): * - Read in file->_prev_version from the start of the file. * * When opening a file for writing (OPEN_WRITE / OPEN_WRITE_BINARY): * - Create missing directories as needed. * - Open a temporary file to protect data if Ocarina crashes. * - If open for writing text (OPEN_WRITE): * - Write file->_version to the start of the file (data files only). * * Returns true if the open was successful and false otherwise. */ bool file_open(struct file *, enum open_mode); /* * Closes an open file, setting file->f_file to NULL and file->f_mode * to CLOSED. If the file was opened for writing, then rename the * temporary file to file_path(). */ void file_close(struct file *); /* * Called to read an unsigned int, signed int, single word, or entire * line from the file. * NOTE: file_readw() and file_readl() both return a new string that * MUST be freed with g_free() */ gchar *file_readw(struct file *); gchar *file_readl(struct file *); unsigned int file_readu(struct file *); static inline int file_readd(struct file *file) { return (int)file_readu(file); } static inline unsigned short int file_readhu(struct file *file) { return (unsigned short int)file_readu(file); } /* * Write to a file with an fprintf(3) style format string. * Returns the number of bytes successfully written. */ int file_writef(struct file *, const char *, ...); /* * Reads the contents of a file as binary data. * NOTE: This function returns a new string which MUST be freed with g_free(). */ gchar *file_read(struct file *); /* * Write binary data a cache file, similar to fwrite(3). * Returns the number of bytes successfully written. */ int file_write(struct file *, const void *, size_t); /* Import a file into the cache. */ bool file_import(struct file *, const gchar *); /* Removes a closed file from disk. */ bool file_remove(struct file *); #endif /* OCARINA_CORE_FILE_H */