ocarina/core/tempq.c
Anna Schumaker fea5da5c10 tempq: Close file if version check fails
We were returning right away if the file version check fails, without
closing the file.  This could cause future reads or writes to fail to
open.

Fixes #25: File version checking doesn't look quite right
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-17 11:48:04 -04:00

151 lines
3.2 KiB
C

/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/collection.h>
#include <core/file.h>
#include <core/history.h>
#include <core/tempq.h>
#include <glib.h>
static GSList *tempq_list;
static struct file tempq_file;
static struct queue *__tempq_alloc(struct queue_ops *ops, unsigned int flags)
{
struct queue *queue = g_malloc(sizeof(struct queue));
tempq_list = g_slist_append(tempq_list, queue);
queue_init(queue, flags | Q_ENABLED | Q_SAVE_FLAGS | Q_SAVE_SORT, ops);
return queue;
}
static void __tempq_free(struct queue *queue)
{
tempq_list = g_slist_remove(tempq_list, queue);
queue_deinit(queue);
g_free(queue);
}
static struct queue *__tempq_read_queue()
{
unsigned int flags, count, i, track;
struct queue *queue;
file_readf(&tempq_file, "%u %u", &flags, &count);
queue = __tempq_alloc(NULL, flags);
for (i = 0; i < count; i++) {
file_readf(&tempq_file, "%u", &track);
queue_add(queue, track_get(track));
}
return queue;
}
static void __tempq_write_queue(struct queue *queue)
{
struct _q_iter it;
struct track *track;
file_writef(&tempq_file, "%u %u", queue->q_flags, queue_size(queue));
_q_for_each(&queue->q_tracks, &it) {
track = (struct track *)_q_iter_val(&it);
file_writef(&tempq_file, " %u", track->tr_dbe.dbe_index);
}
file_writef(&tempq_file, "\n");
}
void tempq_init(struct queue_ops *ops)
{
struct queue *queue;
unsigned int num, i;
file_init(&tempq_file, "deck", 1);
if (!file_open(&tempq_file, OPEN_READ))
return;
if (file_version(&tempq_file) < 1)
goto out;
file_readf(&tempq_file, "%u", &num);
for (i = 0; i < num; i++) {
queue = __tempq_read_queue();
queue->q_ops = ops;
}
out:
file_close(&tempq_file);
}
void tempq_deinit()
{
while (tempq_list)
__tempq_free((struct queue *)tempq_list->data);
}
void tempq_save(struct queue *queue, enum queue_flags flag)
{
GSList *cur;
if (!file_open(&tempq_file, OPEN_WRITE))
return;
file_writef(&tempq_file, "%zu\n", g_slist_length(tempq_list));
for (cur = tempq_list; cur; cur = g_slist_next(cur))
__tempq_write_queue((struct queue *)cur->data);
file_close(&tempq_file);
}
struct queue *tempq_alloc(struct queue_ops *ops, unsigned int flags)
{
struct queue *queue = __tempq_alloc(ops, flags);
tempq_save(queue, Q_ENABLED);
return queue;
}
void tempq_free(struct queue *queue)
{
__tempq_free(queue);
tempq_save(NULL, Q_ENABLED);
}
struct queue *tempq_get(unsigned int index)
{
return (struct queue *)g_slist_nth_data(tempq_list, index);
}
void tempq_move(struct queue *queue, unsigned int index)
{
GSList *cur = g_slist_find(tempq_list, queue);
GSList *nth = g_slist_nth(tempq_list, index);
if (cur && nth && (cur != nth)) {
tempq_list = g_slist_remove(tempq_list, queue);
tempq_list = g_slist_insert_before(tempq_list, nth, queue);
tempq_save(queue, Q_ENABLED);
}
}
struct track *tempq_next()
{
struct track *track = NULL;
struct queue *queue = NULL;
GSList *cur;
for (cur = tempq_list; cur; cur = g_slist_next(cur)) {
queue = (struct queue *)cur->data;
if (queue_has_flag(queue, Q_ENABLED)) {
track = queue_next(queue);
break;
}
}
if (queue && queue_size(queue) == 0)
tempq_free(queue);
return track;
}
unsigned int tempq_count()
{
return g_slist_length(tempq_list);
}