2014-10-17 17:15:02 -04:00
|
|
|
/**
|
2013-08-10 23:38:57 -04:00
|
|
|
* Copyright 2013 (c) Anna Schumaker.
|
|
|
|
*/
|
2014-06-05 10:19:22 -04:00
|
|
|
#include <core/database.h>
|
2013-08-10 23:38:57 -04:00
|
|
|
|
2013-12-30 18:18:23 -05:00
|
|
|
|
2015-10-31 11:44:29 -04:00
|
|
|
db_entry :: db_entry()
|
2015-09-23 09:33:55 -04:00
|
|
|
: dbe_index(0), dbe_key(NULL)
|
2013-12-01 22:31:35 -05:00
|
|
|
{
|
|
|
|
}
|
2014-03-25 10:57:09 -04:00
|
|
|
|
2015-10-31 11:44:29 -04:00
|
|
|
db_entry :: ~db_entry() {}
|
2015-11-04 12:23:00 -05:00
|
|
|
|
|
|
|
static void __dbe_free(struct database *db, struct db_entry *dbe)
|
|
|
|
{
|
|
|
|
if (dbe) {
|
|
|
|
db->db_keys.erase(dbe->dbe_key);
|
|
|
|
g_free(dbe->dbe_key);
|
|
|
|
|
|
|
|
db->db_entries[dbe->dbe_index] = NULL;
|
|
|
|
db->db_ops->dbe_free(dbe);
|
|
|
|
|
|
|
|
db->db_size--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct db_entry *__dbe_next(const struct database *db, unsigned int index)
|
|
|
|
{
|
|
|
|
for (; index < db->db_entries.size(); index++) {
|
|
|
|
if (db->db_entries[index])
|
|
|
|
return db->db_entries[index];
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct db_entry *__dbe_read(struct database *db, unsigned int index)
|
|
|
|
{
|
|
|
|
struct db_entry *dbe = NULL;
|
|
|
|
int valid;
|
|
|
|
|
|
|
|
file_readf(&db->db_file, "%d", &valid);
|
|
|
|
if (valid)
|
|
|
|
dbe = db->db_ops->dbe_read(&db->db_file);
|
|
|
|
|
|
|
|
db->db_entries[index] = dbe;
|
|
|
|
return dbe;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __dbe_setup(struct database *db, unsigned int index)
|
|
|
|
{
|
|
|
|
struct db_entry *dbe = db->db_entries[index];
|
|
|
|
|
|
|
|
if (dbe) {
|
|
|
|
dbe->dbe_index = index;
|
|
|
|
dbe->dbe_key = db->db_ops->dbe_key(dbe);
|
|
|
|
db->db_keys[dbe->dbe_key] = index;
|
|
|
|
db->db_size++;
|
|
|
|
if (db->db_ops->dbe_setup)
|
|
|
|
db->db_ops->dbe_setup(dbe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __dbe_write(struct database *db, struct db_entry *dbe)
|
|
|
|
{
|
|
|
|
if (dbe) {
|
|
|
|
file_writef(&db->db_file, "%u ", true);
|
|
|
|
db->db_ops->dbe_write(&db->db_file, dbe);
|
|
|
|
} else
|
|
|
|
file_writef(&db->db_file, "%u", false);
|
|
|
|
file_writef(&db->db_file, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void db_init(struct database *db, const char *filepath, bool autosave,
|
|
|
|
const struct db_ops *ops)
|
|
|
|
{
|
|
|
|
db->db_ops = ops;
|
|
|
|
db->db_size = 0;
|
|
|
|
db->db_autosave = autosave;
|
|
|
|
file_init(&db->db_file, filepath, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void db_deinit(struct database *db)
|
|
|
|
{
|
|
|
|
struct db_entry *dbe, *next;
|
|
|
|
db_for_each(dbe, next, db)
|
|
|
|
__dbe_free(db, dbe);
|
|
|
|
}
|
|
|
|
|
|
|
|
void db_save(struct database *db)
|
|
|
|
{
|
|
|
|
if (file_open(&db->db_file, OPEN_WRITE) == false)
|
|
|
|
return;
|
|
|
|
|
|
|
|
file_writef(&db->db_file, "%u\n", db_actual_size(db));
|
|
|
|
for (unsigned int i = 0; i < db_actual_size(db); i++)
|
|
|
|
__dbe_write(db, db->db_entries[i]);
|
|
|
|
|
|
|
|
file_close(&db->db_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
void db_autosave(struct database *db)
|
|
|
|
{
|
|
|
|
if (db->db_autosave == true)
|
|
|
|
db_save(db);
|
|
|
|
}
|
|
|
|
|
|
|
|
void db_load(struct database *db)
|
|
|
|
{
|
|
|
|
unsigned int size;
|
|
|
|
|
|
|
|
if (file_open(&db->db_file, OPEN_READ) == false)
|
|
|
|
return;
|
|
|
|
|
|
|
|
file_readf(&db->db_file, "%u", &size);
|
|
|
|
db->db_entries.resize(size);
|
|
|
|
for (unsigned int i = 0; i < size; i++) {
|
|
|
|
if (__dbe_read(db, i))
|
|
|
|
__dbe_setup(db, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
file_close(&db->db_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct db_entry *db_insert(struct database *db, struct db_entry *item)
|
|
|
|
{
|
|
|
|
if (item) {
|
|
|
|
db->db_entries.push_back(item);
|
|
|
|
__dbe_setup(db, db_actual_size(db) - 1);
|
|
|
|
db_autosave(db);
|
|
|
|
}
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
void db_remove(struct database *db, struct db_entry *item)
|
|
|
|
{
|
|
|
|
if (item == NULL)
|
|
|
|
return;
|
|
|
|
if (db_at(db, item->dbe_index) != item)
|
|
|
|
return;
|
|
|
|
__dbe_free(db, item);
|
|
|
|
db_autosave(db);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int db_actual_size(const struct database *db)
|
|
|
|
{
|
|
|
|
return db->db_entries.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct db_entry *db_first(const struct database *db)
|
|
|
|
{
|
|
|
|
return __dbe_next(db, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct db_entry *db_next(const struct database *db, struct db_entry *ent)
|
|
|
|
{
|
|
|
|
if (ent)
|
|
|
|
return __dbe_next(db, ent->dbe_index + 1);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct db_entry *db_at(struct database *db, unsigned int index)
|
|
|
|
{
|
|
|
|
if (index >= db_actual_size(db))
|
|
|
|
return NULL;
|
|
|
|
return db->db_entries[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
struct db_entry *db_get(struct database *db, const gchar *key)
|
|
|
|
{
|
|
|
|
std::map<const std::string, unsigned int>::iterator it;
|
|
|
|
it = db->db_keys.find(key);
|
|
|
|
if (it == db->db_keys.end())
|
|
|
|
return NULL;
|
|
|
|
return db->db_entries[it->second];
|
|
|
|
}
|
|
|
|
|
|
|
|
struct db_entry *db_find(struct database *db, const gchar *key)
|
|
|
|
{
|
|
|
|
struct db_entry *dbe = db_get(db, key);
|
|
|
|
if (dbe)
|
|
|
|
return dbe;
|
|
|
|
dbe = db->db_ops->dbe_alloc(key);
|
|
|
|
return db_insert(db, dbe);
|
|
|
|
}
|