From 4b559e585bb5e36155c932913d6f44d5c0977453 Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Sun, 4 Mar 2012 15:56:54 +0100 Subject: [PATCH] Implement support to use both database backends. --- Makefile | 14 +-- config.c | 17 ++- config.mk | 9 +- database-plain.c | 302 +++++++++++++++++++++++++++++++--------------- database-plain.h | 43 +++++++ database-sqlite.c | 204 ++++++++++++++++++++----------- database-sqlite.h | 43 +++++++ database.c | 59 +++++++++ database.h | 38 ++++-- zathura.c | 24 +++- zathura.h | 3 +- 11 files changed, 555 insertions(+), 201 deletions(-) create mode 100644 database-plain.h create mode 100644 database-sqlite.h create mode 100644 database.c diff --git a/Makefile b/Makefile index 4379478..fb9b6e5 100644 --- a/Makefile +++ b/Makefile @@ -4,17 +4,14 @@ include config.mk include common.mk PROJECT = zathura -OSOURCE = $(shell find . -maxdepth 1 -iname "*.c" -a ! -iname "database-*") +OSOURCE = $(shell find . -maxdepth 1 -iname "*.c" -a ! -iname "database-sqlite.c") HEADER = $(shell find . -maxdepth 1 -iname "*.h") -ifeq (${DATABASE}, sqlite) +ifneq (${WITH_SQLITE},0) INCS += $(SQLITE_INC) LIBS += $(SQLITE_LIB) SOURCE = $(OSOURCE) database-sqlite.c -else -ifeq (${DATABASE}, plain) -SOURCE = $(OSOURCE) database-plain.c -endif +CPPFLAGS += -DWITH_SQLITE endif OBJECTS = $(patsubst %.c, %.o, $(SOURCE)) @@ -45,9 +42,6 @@ version.h: version.h.in config.mk @mkdir -p .depend $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${DFLAGS} -o $@ $< -MMD -MF .depend/$@.dep -# force recompilation of database.o if DATABASE has changed -database.o: database-${DATABASE}.o - ${OBJECTS}: config.mk version.h ${DOBJECTS}: config.mk version.h @@ -91,7 +85,7 @@ dist: clean $(QUIET)mkdir -p ${PROJECT}-${VERSION}/tests $(QUIET)cp LICENSE Makefile config.mk common.mk README AUTHORS Doxyfile \ ${PROJECT}.1.rst ${PROJECT}rc.5.rst ${OSOURCE} ${HEADER} ${PROJECT}.pc.in \ - ${PROJECT}.desktop version.h.in database-*.c \ + ${PROJECT}.desktop version.h.in database-sqlite.c \ ${PROJECT}-${VERSION} $(QUIET)cp tests/Makefile tests/config.mk tests/*.c \ ${PROJECT}-${VERSION}/tests diff --git a/config.c b/config.c index b668cfb..9ff4f3d 100644 --- a/config.c +++ b/config.c @@ -47,7 +47,6 @@ config_load_default(zathura_t* zathura) int int_value = 0; float float_value = 0; - char* string_value = NULL; bool bool_value = false; girara_session_t* gsession = zathura->ui.session; @@ -65,18 +64,19 @@ config_load_default(zathura_t* zathura) girara_mode_set(gsession, zathura->modes.normal); /* zathura settings */ + girara_setting_add(gsession, "database", "plain", STRING, true, "Database backend", NULL, NULL); int_value = 10; - girara_setting_add(gsession, "zoom-step", &int_value, INT, false, "Zoom step", NULL, NULL); + girara_setting_add(gsession, "zoom-step", &int_value, INT, false, "Zoom step", NULL, NULL); int_value = 1; - girara_setting_add(gsession, "page-padding", &int_value, INT, true, "Padding between pages", NULL, NULL); + girara_setting_add(gsession, "page-padding", &int_value, INT, true, "Padding between pages", NULL, NULL); int_value = 1; - girara_setting_add(gsession, "pages-per-row", &int_value, INT, false, "Number of pages per row", cb_pages_per_row_value_changed, NULL); + girara_setting_add(gsession, "pages-per-row", &int_value, INT, false, "Number of pages per row", cb_pages_per_row_value_changed, NULL); float_value = 40; - girara_setting_add(gsession, "scroll-step", &float_value, FLOAT, false, "Scroll step", NULL, NULL); + girara_setting_add(gsession, "scroll-step", &float_value, FLOAT, false, "Scroll step", NULL, NULL); int_value = 10; - girara_setting_add(gsession, "zoom-min", &int_value, INT, false, "Zoom minimum", NULL, NULL); + girara_setting_add(gsession, "zoom-min", &int_value, INT, false, "Zoom minimum", NULL, NULL); int_value = 1000; - girara_setting_add(gsession, "zoom-max", &int_value, INT, false, "Zoom maximum", NULL, NULL); + girara_setting_add(gsession, "zoom-max", &int_value, INT, false, "Zoom maximum", NULL, NULL); girara_setting_add(gsession, "recolor-darkcolor", NULL, STRING, false, "Recoloring (dark color)", cb_color_change, NULL); girara_setting_set(gsession, "recolor-darkcolor", "#FFFFFF"); @@ -91,8 +91,7 @@ config_load_default(zathura_t* zathura) girara_setting_add(gsession, "highlight-transparency", &float_value, FLOAT, false, "Transparency for highlighting", NULL, NULL); bool_value = true; girara_setting_add(gsession, "render-loading", &bool_value, BOOLEAN, false, "Render 'Loading ...'", NULL, NULL); - string_value = "best-fit"; - girara_setting_add(gsession, "adjust-open", string_value, STRING, false, "Adjust to when opening file", NULL, NULL); + girara_setting_add(gsession, "adjust-open", "best-fit", STRING, false, "Adjust to when opening file", NULL, NULL); bool_value = false; girara_setting_add(gsession, "show-hidden", &bool_value, BOOLEAN, false, "Show hidden files and directories", NULL, NULL); diff --git a/config.mk b/config.mk index ebd4f8f..6069be1 100644 --- a/config.mk +++ b/config.mk @@ -10,6 +10,10 @@ VERSION = ${ZATHURA_VERSION_MAJOR}.${ZATHURA_VERSION_MINOR}.${ZATHURA_VERSION_RE # the GTK version to use ZATHURA_GTK_VERSION ?= 2 +# database +# build with sqlite support +WITH_SQLITE ?= 1 + # paths PREFIX ?= /usr MANPREFIX ?= ${PREFIX}/share/man @@ -26,8 +30,10 @@ GTK_LIB ?= $(shell pkg-config --libs gtk+-${ZATHURA_GTK_VERSION}.0 gthread-2.0) GIRARA_INC ?= $(shell pkg-config --cflags girara-gtk${ZATHURA_GTK_VERSION}) GIRARA_LIB ?= $(shell pkg-config --libs girara-gtk${ZATHURA_GTK_VERSION}) +ifneq (${WITH_SQLITE},0) SQLITE_INC ?= $(shell pkg-config --cflags sqlite3) SQLITE_LIB ?= $(shell pkg-config --libs sqlite3) +endif #set it to an empty value if you don't need to link against ld for dlopen and friends DL_LIB ?= -ldl @@ -54,6 +60,3 @@ SFLAGS ?= -s # set to something != 0 if you want verbose build output VERBOSE ?= 0 -# database -# possible values are sqlite and plain -DATABASE ?= plain diff --git a/database-plain.c b/database-plain.c index 1099117..991fbbc 100644 --- a/database-plain.c +++ b/database-plain.c @@ -11,7 +11,7 @@ #include #include -#include "database.h" +#include "database-plain.h" #define BOOKMARKS "bookmarks" #define HISTORY "history" @@ -27,6 +27,24 @@ fcntl(fd, F_SETLK, lock); \ } +static void zathura_database_interface_init(ZathuraDatabaseInterface* iface); + +G_DEFINE_TYPE_WITH_CODE(ZathuraPlainDatabase, zathura_plaindatabase, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(ZATHURA_TYPE_DATABASE, zathura_database_interface_init)) + +static void plain_finalize(GObject* object); +static bool plain_add_bookmark(zathura_database_t* db, const char* file, + zathura_bookmark_t* bookmark); +static bool plain_remove_bookmark(zathura_database_t* db, const char* file, const + char* id); +static girara_list_t* plain_load_bookmarks(zathura_database_t* db, const char* + file); +static bool plain_set_fileinfo(zathura_database_t* db, const char* file, unsigned + int page, int offset, double scale, int rotation); +static bool plain_get_fileinfo(zathura_database_t* db, const char* file, unsigned + int* page, int* offset, double* scale, int* rotation); +static void plain_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec); + /* forward declaration */ static bool zathura_db_check_file(const char* path); static GKeyFile* zathura_db_read_key_file_from_file(const char* path); @@ -34,8 +52,7 @@ static void zathura_db_write_key_file_to_file(const char* file, GKeyFile* key_fi static void cb_zathura_db_watch_file(GFileMonitor* monitor, GFile* file, GFile* other_file, GFileMonitorEvent event, zathura_database_t* database); -struct zathura_database_s -{ +typedef struct zathura_plaindatabase_private_s { char* bookmark_path; GKeyFile* bookmarks; GFileMonitor* bookmark_monitor; @@ -43,143 +60,232 @@ struct zathura_database_s char* history_path; GKeyFile* history; GFileMonitor* history_monitor; +} zathura_plaindatabase_private_t; + +#define ZATHURA_PLAINDATABASE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ZATHURA_TYPE_PLAINDATABASE, zathura_plaindatabase_private_t)) + +enum +{ + PROP_0, + PROP_PATH }; -zathura_database_t* -zathura_db_init(const char* dir) +static void +zathura_database_interface_init(ZathuraDatabaseInterface* iface) { - if (dir == NULL) { - goto error_ret; - } + /* initialize interface */ + iface->add_bookmark = plain_add_bookmark; + iface->remove_bookmark = plain_remove_bookmark; + iface->load_bookmarks = plain_load_bookmarks; + iface->set_fileinfo = plain_set_fileinfo; + iface->get_fileinfo = plain_get_fileinfo; +} - zathura_database_t* db = calloc(1, sizeof(zathura_database_t)); - if (db == NULL) { - goto error_ret; +static void +zathura_plaindatabase_class_init(ZathuraPlainDatabaseClass* class) +{ + /* add private members */ + g_type_class_add_private(class, sizeof(zathura_plaindatabase_private_t)); + + /* override methods */ + GObjectClass* object_class = G_OBJECT_CLASS(class); + object_class->finalize = plain_finalize; + object_class->set_property = plain_set_property; + + g_object_class_install_property(object_class, PROP_PATH, + g_param_spec_string("path", "path", "path to directory where the bookmarks and history are locates", + NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +zathura_plaindatabase_init(ZathuraPlainDatabase* db) +{ + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); + priv->bookmark_path = NULL; + priv->bookmark_monitor = NULL; + priv->bookmarks = NULL; + priv->history_path = NULL; + priv->history_monitor = NULL; + priv->history = NULL; +} + +zathura_database_t* +zathura_plaindatabase_new(const char* path) +{ + g_return_val_if_fail(path != NULL && strlen(path) != 0, NULL); + + zathura_database_t* db = g_object_new(ZATHURA_TYPE_PLAINDATABASE, "path", path, NULL); + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); + if (priv->bookmark_path == NULL) { + g_object_unref(db); + return NULL; } + return db; +} + +static void +plain_db_init(ZathuraPlainDatabase* db, const char* dir) +{ + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); /* bookmarks */ - db->bookmark_path = g_build_filename(dir, BOOKMARKS, NULL); - if (db->bookmark_path == NULL || - zathura_db_check_file(db->bookmark_path) == false) { + priv->bookmark_path = g_build_filename(dir, BOOKMARKS, NULL); + if (zathura_db_check_file(priv->bookmark_path) == false) { goto error_free; } - GFile* bookmark_file = g_file_new_for_path(db->bookmark_path); + GFile* bookmark_file = g_file_new_for_path(priv->bookmark_path); if (bookmark_file != NULL) { - db->bookmark_monitor = g_file_monitor(bookmark_file, G_FILE_MONITOR_NONE, NULL, NULL); + priv->bookmark_monitor = g_file_monitor(bookmark_file, G_FILE_MONITOR_NONE, NULL, NULL); } else { goto error_free; } g_object_unref(bookmark_file); g_signal_connect( - G_OBJECT(db->bookmark_monitor), + G_OBJECT(priv->bookmark_monitor), "changed", G_CALLBACK(cb_zathura_db_watch_file), db ); - db->bookmarks = zathura_db_read_key_file_from_file(db->bookmark_path); - if (db->bookmarks == NULL) { + priv->bookmarks = zathura_db_read_key_file_from_file(priv->bookmark_path); + if (priv->bookmarks == NULL) { goto error_free; } /* history */ - db->history_path = g_build_filename(dir, HISTORY, NULL); - if (db->history_path == NULL || - zathura_db_check_file(db->history_path) == false) { + priv->history_path = g_build_filename(dir, HISTORY, NULL); + if (zathura_db_check_file(priv->history_path) == false) { goto error_free; } - GFile* history_file = g_file_new_for_path(db->history_path); + GFile* history_file = g_file_new_for_path(priv->history_path); if (history_file != NULL) { - db->history_monitor = g_file_monitor(history_file, G_FILE_MONITOR_NONE, NULL, NULL); + priv->history_monitor = g_file_monitor(history_file, G_FILE_MONITOR_NONE, NULL, NULL); } else { goto error_free; } g_object_unref(history_file); g_signal_connect( - G_OBJECT(db->history_monitor), + G_OBJECT(priv->history_monitor), "changed", G_CALLBACK(cb_zathura_db_watch_file), db ); - db->history = zathura_db_read_key_file_from_file(db->history_path); - if (db->history == NULL) { + priv->history = zathura_db_read_key_file_from_file(priv->history_path); + if (priv->history == NULL) { goto error_free; } - return db; - error_free: - zathura_db_free(db); - -error_ret: - - return NULL; -} - -void -zathura_db_free(zathura_database_t* db) -{ - if (db == NULL) { - return; - } - /* bookmarks */ - g_free(db->bookmark_path); + g_free(priv->bookmark_path); + priv->bookmark_path = NULL; - if (db->bookmark_monitor != NULL) { - g_object_unref(db->bookmark_monitor); + if (priv->bookmark_monitor != NULL) { + g_object_unref(priv->bookmark_monitor); + priv->bookmark_monitor = NULL; } - if (db->bookmarks != NULL) { - g_key_file_free(db->bookmarks); + if (priv->bookmarks != NULL) { + g_key_file_free(priv->bookmarks); + priv->bookmarks = NULL; } /* history */ - g_free(db->history_path); + g_free(priv->history_path); + priv->history_path = NULL; - if (db->history_monitor != NULL) { - g_object_unref(db->history_monitor); + if (priv->history_monitor != NULL) { + g_object_unref(priv->history_monitor); + priv->history_monitor = NULL; } - /* database */ - free(db); + if (priv->history != NULL) { + g_key_file_free(priv->history); + priv->history = NULL; + } } -bool -zathura_db_add_bookmark(zathura_database_t* db, const char* file, +static void +plain_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) +{ + ZathuraPlainDatabase* db = ZATHURA_PLAINDATABASE(object); + + switch (prop_id) { + case PROP_PATH: + plain_db_init(db, g_value_get_string(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void +plain_finalize(GObject* object) +{ + ZathuraPlainDatabase* db = ZATHURA_PLAINDATABASE(object); + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); + /* bookmarks */ + g_free(priv->bookmark_path); + + if (priv->bookmark_monitor != NULL) { + g_object_unref(priv->bookmark_monitor); + } + + if (priv->bookmarks != NULL) { + g_key_file_free(priv->bookmarks); + } + + /* history */ + g_free(priv->history_path); + + if (priv->history_monitor != NULL) { + g_object_unref(priv->history_monitor); + } + + if (priv->history != NULL) { + g_key_file_free(priv->history); + } + + G_OBJECT_CLASS(zathura_plaindatabase_parent_class)->finalize(object); +} + +static bool +plain_add_bookmark(zathura_database_t* db, const char* file, zathura_bookmark_t* bookmark) { - if (db == NULL || db->bookmarks == NULL || db->bookmark_path == NULL || file - == NULL || bookmark == NULL || bookmark->id == NULL) { + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); + if (priv->bookmarks == NULL || priv->bookmark_path == NULL || + bookmark->id == NULL) { return false; } - g_key_file_set_integer(db->bookmarks, file, bookmark->id, bookmark->page); + g_key_file_set_integer(priv->bookmarks, file, bookmark->id, bookmark->page); - zathura_db_write_key_file_to_file(db->bookmark_path, db->bookmarks); + zathura_db_write_key_file_to_file(priv->bookmark_path, priv->bookmarks); return true; } -bool -zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char* - id) +static bool +plain_remove_bookmark(zathura_database_t* db, const char* file, const char* + GIRARA_UNUSED(id)) { - if (db == NULL || db->bookmarks == NULL || db->bookmark_path == NULL || file - == NULL || id == NULL) { + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); + if (priv->bookmarks == NULL || priv->bookmark_path == NULL) { return false; } - if (g_key_file_has_group(db->bookmarks, file) == TRUE) { - g_key_file_remove_group(db->bookmarks, file, NULL); + if (g_key_file_has_group(priv->bookmarks, file) == TRUE) { + g_key_file_remove_group(priv->bookmarks, file, NULL); - zathura_db_write_key_file_to_file(db->bookmark_path, db->bookmarks); + zathura_db_write_key_file_to_file(priv->bookmark_path, priv->bookmarks); return true; } @@ -187,27 +293,23 @@ zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char* return false; } -girara_list_t* -zathura_db_load_bookmarks(zathura_database_t* db, const char* file) +static girara_list_t* +plain_load_bookmarks(zathura_database_t* db, const char* file) { - if (db == NULL || db->bookmarks == NULL || file == NULL) { + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); + if (priv->bookmarks == NULL) { return NULL; } - if (g_key_file_has_group(db->bookmarks, file) == FALSE) { + if (g_key_file_has_group(priv->bookmarks, file) == FALSE) { return NULL; } girara_list_t* result = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare, (girara_free_function_t) zathura_bookmark_free); - if (result == NULL) { - return NULL; - } - - girara_list_set_free_function(result, (girara_free_function_t) zathura_bookmark_free); gsize length; - char** keys = g_key_file_get_keys(db->bookmarks, file, &length, NULL); + char** keys = g_key_file_get_keys(priv->bookmarks, file, &length, NULL); if (keys == NULL) { girara_list_free(result); return NULL; @@ -217,7 +319,7 @@ zathura_db_load_bookmarks(zathura_database_t* db, const char* file) zathura_bookmark_t* bookmark = g_malloc0(sizeof(zathura_bookmark_t)); bookmark->id = g_strdup(keys[i]); - bookmark->page = g_key_file_get_integer(db->bookmarks, file, keys[i], NULL); + bookmark->page = g_key_file_get_integer(priv->bookmarks, file, keys[i], NULL); girara_list_append(result, bookmark); } @@ -225,45 +327,46 @@ zathura_db_load_bookmarks(zathura_database_t* db, const char* file) return result; } -bool -zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned int +static bool +plain_set_fileinfo(zathura_database_t* db, const char* file, unsigned int page, int offset, double scale, int rotation) { - if (db == NULL || db->history == NULL || file == NULL) { + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); + if (priv->history == NULL) { return false; } char* tmp = g_strdup_printf("%f", scale); - g_key_file_set_integer(db->history, file, KEY_PAGE, page); - g_key_file_set_integer(db->history, file, KEY_OFFSET, offset); - g_key_file_set_string (db->history, file, KEY_SCALE, tmp); - g_key_file_set_integer(db->history, file, KEY_ROTATE, rotation); + g_key_file_set_integer(priv->history, file, KEY_PAGE, page); + g_key_file_set_integer(priv->history, file, KEY_OFFSET, offset); + g_key_file_set_string (priv->history, file, KEY_SCALE, tmp); + g_key_file_set_integer(priv->history, file, KEY_ROTATE, rotation); g_free(tmp); - zathura_db_write_key_file_to_file(db->history_path, db->history); + zathura_db_write_key_file_to_file(priv->history_path, priv->history); return true; } -bool -zathura_db_get_fileinfo(zathura_database_t* db, const char* file, unsigned int* +static bool +plain_get_fileinfo(zathura_database_t* db, const char* file, unsigned int* page, int* offset, double* scale, int* rotation) { - if (db == NULL || db->history == NULL || file == NULL || page == NULL || - offset == NULL || scale == NULL || rotation == NULL) { + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); + if (priv->history == NULL) { return false; } - if (g_key_file_has_group(db->history, file) == FALSE) { + if (g_key_file_has_group(priv->history, file) == FALSE) { return false; } - *page = g_key_file_get_integer(db->history, file, KEY_PAGE, NULL); - *offset = g_key_file_get_integer(db->history, file, KEY_OFFSET, NULL); - *scale = strtod(g_key_file_get_string(db->history, file, KEY_SCALE, NULL), NULL); - *rotation = g_key_file_get_integer(db->history, file, KEY_ROTATE, NULL); + *page = g_key_file_get_integer(priv->history, file, KEY_PAGE, NULL); + *offset = g_key_file_get_integer(priv->history, file, KEY_OFFSET, NULL); + *scale = strtod(g_key_file_get_string(priv->history, file, KEY_SCALE, NULL), NULL); + *rotation = g_key_file_get_integer(priv->history, file, KEY_ROTATE, NULL); return true; } @@ -392,9 +495,10 @@ cb_zathura_db_watch_file(GFileMonitor* UNUSED(monitor), GFile* file, GFile* UNUS return; } - if (database->bookmark_path && strcmp(database->bookmark_path, path) == 0) { - database->bookmarks = zathura_db_read_key_file_from_file(database->bookmark_path); - } else if (database->history_path && strcmp(database->history_path, path) == 0) { - database->history = zathura_db_read_key_file_from_file(database->history_path); + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(database); + if (priv->bookmark_path && strcmp(priv->bookmark_path, path) == 0) { + priv->bookmarks = zathura_db_read_key_file_from_file(priv->bookmark_path); + } else if (priv->history_path && strcmp(priv->history_path, path) == 0) { + priv->history = zathura_db_read_key_file_from_file(priv->history_path); } } diff --git a/database-plain.h b/database-plain.h new file mode 100644 index 0000000..a2f290e --- /dev/null +++ b/database-plain.h @@ -0,0 +1,43 @@ +/* See LICENSE file for license and copyright information */ + +#ifndef ZATHURA_DATABASE_PLAIN_H +#define ZATHURA_DATABASE_PLAIN_H + +#include "database.h" + +#define ZATHURA_TYPE_PLAINDATABASE \ + (zathura_plaindatabase_get_type ()) +#define ZATHURA_PLAINDATABASE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), ZATHURA_TYPE_PLAINDATABASE, ZathuraPlainDatabase)) +#define ZATHURA_IS_PLAINDATABASE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ZATHURA_TYPE_PLAINDATABASE)) +#define ZATHURA_PLAINDATABASE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), ZATHURA_TYPE_PLAINDATABASE, ZathuraPlainDatabaseClass)) +#define ZATHURA_IS_PLAINDATABASE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), ZATHURA_TYPE_PLAINDATABASE)) +#define ZATHURA_PLAINDATABASE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), ZATHURA_TYPE_PLAINDATABASE, ZathuraPlainDatabaseClass)) + +typedef struct _ZathuraPlainDatabase ZathuraPlainDatabase; +typedef struct _ZathuraPlainDatabaseClass ZathuraPlainDatabaseClass; + +struct _ZathuraPlainDatabase +{ + GObject parent_instance; +}; + +struct _ZathuraPlainDatabaseClass +{ + GObjectClass parent_class; +}; + +GType zathura_plaindatabase_get_type(void); +/** + * Initialize database system. + * + * @param dir Path to the directory where the database file should be located. + * @return A valid zathura_database_t instance or NULL on failure + */ +zathura_database_t* zathura_plaindatabase_new(const char* dir); + +#endif diff --git a/database-sqlite.c b/database-sqlite.c index 3cd8e3b..bc07f62 100644 --- a/database-sqlite.c +++ b/database-sqlite.c @@ -1,32 +1,108 @@ /* See LICENSE file for license and copyright information */ -#include #include #include #include +#include -#include "database.h" +#include "database-sqlite.h" #define DATABASE "bookmarks.sqlite" -struct zathura_database_s -{ +static void zathura_database_interface_init(ZathuraDatabaseInterface* iface); + +G_DEFINE_TYPE_WITH_CODE(ZathuraSQLDatabase, zathura_sqldatabase, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(ZATHURA_TYPE_DATABASE, zathura_database_interface_init)) + +static void sqlite_finalize(GObject* object); +static bool sqlite_add_bookmark(zathura_database_t* db, const char* file, + zathura_bookmark_t* bookmark); +static bool sqlite_remove_bookmark(zathura_database_t* db, const char* file, const + char* id); +static girara_list_t* sqlite_load_bookmarks(zathura_database_t* db, const char* + file); +static bool sqlite_set_fileinfo(zathura_database_t* db, const char* file, unsigned + int page, int offset, double scale, int rotation); +static bool sqlite_get_fileinfo(zathura_database_t* db, const char* file, unsigned + int* page, int* offset, double* scale, int* rotation); +static void sqlite_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec); + +typedef struct zathura_sqldatabase_private_s { sqlite3* session; +} zathura_sqldatabase_private_t; + +#define ZATHURA_SQLDATABASE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ZATHURA_TYPE_SQLDATABASE, zathura_sqldatabase_private_t)) + +enum +{ + PROP_0, + PROP_PATH }; -zathura_database_t* -zathura_db_init(const char* dir) +static void +zathura_database_interface_init(ZathuraDatabaseInterface* iface) { - if (dir == NULL) { + /* initialize interface */ + iface->add_bookmark = sqlite_add_bookmark; + iface->remove_bookmark = sqlite_remove_bookmark; + iface->load_bookmarks = sqlite_load_bookmarks; + iface->set_fileinfo = sqlite_set_fileinfo; + iface->get_fileinfo = sqlite_get_fileinfo; +} + +static void +zathura_sqldatabase_class_init(ZathuraSQLDatabaseClass* class) +{ + /* add private members */ + g_type_class_add_private(class, sizeof(zathura_sqldatabase_private_t)); + + /* override methods */ + GObjectClass* object_class = G_OBJECT_CLASS(class); + object_class->finalize = sqlite_finalize; + object_class->set_property = sqlite_set_property; + + g_object_class_install_property(object_class, PROP_PATH, + g_param_spec_string("path", "path", "path to the database", NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +zathura_sqldatabase_init(ZathuraSQLDatabase* db) +{ + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); + priv->session = NULL; +} + +zathura_database_t* +zathura_sqldatabase_new(const char* path) +{ + g_return_val_if_fail(path != NULL && strlen(path) != 0, NULL); + + zathura_database_t* db = g_object_new(ZATHURA_TYPE_SQLDATABASE, "path", path, NULL); + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); + if (priv->session == NULL) { + g_object_unref(db); return NULL; } + return db; +} - char* path = g_build_filename(dir, DATABASE, NULL); - if (path == NULL) { - return NULL; +static void +sqlite_finalize(GObject* object) +{ + ZathuraSQLDatabase* db = ZATHURA_SQLDATABASE(object); + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); + if (priv->session) { + sqlite3_close(priv->session); } - zathura_database_t* db = g_malloc0(sizeof(zathura_database_t)); + G_OBJECT_CLASS(zathura_sqldatabase_parent_class)->finalize(object); +} + +static void +sqlite_db_init(ZathuraSQLDatabase* db, const char* path) +{ + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); /* create bookmarks database */ static const char SQL_BOOKMARK_INIT[] = @@ -44,43 +120,41 @@ zathura_db_init(const char* dir) "scale FLOAT," "rotation INTEGER);"; - if (sqlite3_open(path, &(db->session)) != SQLITE_OK) { + sqlite3* session = NULL; + if (sqlite3_open(path, &session) != SQLITE_OK) { girara_error("Could not open database: %s\n", path); - goto error_free; - } - - if (sqlite3_exec(db->session, SQL_BOOKMARK_INIT, NULL, 0, NULL) != SQLITE_OK) { - girara_error("Failed to initialize database: %s\n", path); - goto error_free; - } - - if (sqlite3_exec(db->session, SQL_FILEINFO_INIT, NULL, 0, NULL) != SQLITE_OK) { - girara_error("Failed to initialize database: %s\n", path); - goto error_free; - } - - return db; - -error_free: - - zathura_db_free(db); - g_free(path); - - return NULL; -} - -void -zathura_db_free(zathura_database_t* db) -{ - if (db == NULL) { return; } - if (db->session != NULL) { - sqlite3_close(db->session); + if (sqlite3_exec(session, SQL_BOOKMARK_INIT, NULL, 0, NULL) != SQLITE_OK) { + girara_error("Failed to initialize database: %s\n", path); + sqlite3_close(session); + return; } - g_free(db); + if (sqlite3_exec(session, SQL_FILEINFO_INIT, NULL, 0, NULL) != SQLITE_OK) { + girara_error("Failed to initialize database: %s\n", path); + sqlite3_close(session); + return; + } + + priv->session = session; +} + +static void +sqlite_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) +{ + ZathuraSQLDatabase* db = ZATHURA_SQLDATABASE(object); + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); + + switch (prop_id) { + case PROP_PATH: + g_return_if_fail(priv->session == NULL); + sqlite_db_init(db, g_value_get_string(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } } static sqlite3_stmt* @@ -106,16 +180,16 @@ prepare_statement(sqlite3* session, const char* statement) return pp_stmt; } -bool -zathura_db_add_bookmark(zathura_database_t* db, const char* file, +static bool +sqlite_add_bookmark(zathura_database_t* db, const char* file, zathura_bookmark_t* bookmark) { - g_return_val_if_fail(db && file && bookmark, false); + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); static const char SQL_BOOKMARK_ADD[] = "REPLACE INTO bookmarks (file, id, page) VALUES (?, ?, ?);"; - sqlite3_stmt* stmt = prepare_statement(db->session, SQL_BOOKMARK_ADD); + sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_BOOKMARK_ADD); if (stmt == NULL) { return false; } @@ -133,16 +207,16 @@ zathura_db_add_bookmark(zathura_database_t* db, const char* file, return res == SQLITE_DONE; } -bool -zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char* +static bool +sqlite_remove_bookmark(zathura_database_t* db, const char* file, const char* id) { - g_return_val_if_fail(db && file && id, false); + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); static const char SQL_BOOKMARK_ADD[] = "DELETE FROM bookmarks WHERE file = ? AND id = ?;"; - sqlite3_stmt* stmt = prepare_statement(db->session, SQL_BOOKMARK_ADD); + sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_BOOKMARK_ADD); if (stmt == NULL) { return false; } @@ -159,15 +233,15 @@ zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char* return res == SQLITE_DONE; } -girara_list_t* -zathura_db_load_bookmarks(zathura_database_t* db, const char* file) +static girara_list_t* +sqlite_load_bookmarks(zathura_database_t* db, const char* file) { - g_return_val_if_fail(db && file, NULL); + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); static const char SQL_BOOKMARK_SELECT[] = "SELECT id, page FROM bookmarks WHERE file = ?;"; - sqlite3_stmt* stmt = prepare_statement(db->session, SQL_BOOKMARK_SELECT); + sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_BOOKMARK_SELECT); if (stmt == NULL) { return NULL; } @@ -180,11 +254,6 @@ zathura_db_load_bookmarks(zathura_database_t* db, const char* file) girara_list_t* result = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare, (girara_free_function_t) zathura_bookmark_free); - if (result == NULL) { - sqlite3_finalize(stmt); - return NULL; - } - while (sqlite3_step(stmt) == SQLITE_ROW) { zathura_bookmark_t* bookmark = g_malloc0(sizeof(zathura_bookmark_t)); @@ -197,16 +266,16 @@ zathura_db_load_bookmarks(zathura_database_t* db, const char* file) return result; } -bool -zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned int +static bool +sqlite_set_fileinfo(zathura_database_t* db, const char* file, unsigned int page, int offset, double scale, int rotation) { - g_return_val_if_fail(db && file, false); + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); static const char SQL_FILEINFO_SET[] = "REPLACE INTO fileinfo (file, page, offset, scale, rotation) VALUES (?, ?, ?, ?, ?);"; - sqlite3_stmt* stmt = prepare_statement(db->session, SQL_FILEINFO_SET); + sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_FILEINFO_SET); if (stmt == NULL) { return false; } @@ -226,16 +295,16 @@ zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned int return res == SQLITE_DONE; } -bool -zathura_db_get_fileinfo(zathura_database_t* db, const char* file, unsigned int* +static bool +sqlite_get_fileinfo(zathura_database_t* db, const char* file, unsigned int* page, int* offset, double* scale, int* rotation) { - g_return_val_if_fail(db && file && page && offset && scale && rotation, false); + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); static const char SQL_FILEINFO_GET[] = "SELECT page, offset, scale, rotation FROM fileinfo WHERE file = ?;"; - sqlite3_stmt* stmt = prepare_statement(db->session, SQL_FILEINFO_GET); + sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_FILEINFO_GET); if (stmt == NULL) { return false; } @@ -259,4 +328,3 @@ zathura_db_get_fileinfo(zathura_database_t* db, const char* file, unsigned int* sqlite3_finalize(stmt); return true; } - diff --git a/database-sqlite.h b/database-sqlite.h new file mode 100644 index 0000000..bd45ccf --- /dev/null +++ b/database-sqlite.h @@ -0,0 +1,43 @@ +/* See LICENSE file for license and copyright information */ + +#ifndef ZATHURA_DATABASE_SQLITE_H +#define ZATHURA_DATABASE_SQLITE_H + +#include "database.h" + +#define ZATHURA_TYPE_SQLDATABASE \ + (zathura_sqldatabase_get_type ()) +#define ZATHURA_SQLDATABASE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), ZATHURA_TYPE_SQLDATABASE, ZathuraSQLDatabase)) +#define ZATHURA_IS_SQLDATABASE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ZATHURA_TYPE_SQLDATABASE)) +#define ZATHURA_SQLDATABASE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), ZATHURA_TYPE_SQLDATABASE, ZathuraSQLDatabaseClass)) +#define ZATHURA_IS_SQLDATABASE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), ZATHURA_TYPE_SQLDATABASE)) +#define ZATHURA_SQLDATABASE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), ZATHURA_TYPE_SQLDATABASE, ZathuraSQLDatabaseClass)) + +typedef struct _ZathuraSQLDatabase ZathuraSQLDatabase; +typedef struct _ZathuraSQLDatabaseClass ZathuraSQLDatabaseClass; + +struct _ZathuraSQLDatabase +{ + GObject parent_instance; +}; + +struct _ZathuraSQLDatabaseClass +{ + GObjectClass parent_class; +}; + +GType zathura_sqldatabase_get_type(void); +/** + * Initialize database system. + * + * @param dir Path to the sqlite database. + * @return A valid zathura_database_t instance or NULL on failure + */ +zathura_database_t* zathura_sqldatabase_new(const char* path); + +#endif diff --git a/database.c b/database.c new file mode 100644 index 0000000..408dfc9 --- /dev/null +++ b/database.c @@ -0,0 +1,59 @@ +/* See LICENSE file for license and copyright information */ + +#include "database.h" + +G_DEFINE_INTERFACE(ZathuraDatabase, zathura_database, G_TYPE_OBJECT) + +static void +zathura_database_default_init(ZathuraDatabaseInterface* GIRARA_UNUSED(iface)) +{ +} + +void zathura_db_free(zathura_database_t* db) +{ + if (db == NULL) { + return; + } + + g_object_unref(db); +} + +bool zathura_db_add_bookmark(zathura_database_t* db, const char* file, + zathura_bookmark_t* bookmark) +{ + g_return_val_if_fail(ZATHURA_IS_DATABASE(db) && file && bookmark, false); + + return ZATHURA_DATABASE_GET_INTERFACE(db)->add_bookmark(db, file, bookmark); +} + +bool zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const + char* id) +{ + g_return_val_if_fail(ZATHURA_IS_DATABASE(db) && file && id, false); + + return ZATHURA_DATABASE_GET_INTERFACE(db)->remove_bookmark(db, file, id); +} + +girara_list_t* zathura_db_load_bookmarks(zathura_database_t* db, const char* + file) +{ + g_return_val_if_fail(ZATHURA_IS_DATABASE(db) && file, NULL); + + return ZATHURA_DATABASE_GET_INTERFACE(db)->load_bookmarks(db, file); +} + +bool zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned + int page, int offset, double scale, int rotation) +{ + g_return_val_if_fail(ZATHURA_IS_DATABASE(db) && file, false); + + return ZATHURA_DATABASE_GET_INTERFACE(db)->set_fileinfo(db, file, page, offset, scale, rotation); +} + +bool zathura_db_get_fileinfo(zathura_database_t* db, const char* file, unsigned + int* page, int* offset, double* scale, int* rotation) +{ + g_return_val_if_fail(ZATHURA_IS_DATABASE(db) && file && page && offset && scale && rotation, false); + + return ZATHURA_DATABASE_GET_INTERFACE(db)->get_fileinfo(db, file, page, offset, scale, rotation); +} diff --git a/database.h b/database.h index 44172e5..6039f5e 100644 --- a/database.h +++ b/database.h @@ -5,17 +5,39 @@ #include #include +#include -#include "zathura.h" #include "bookmarks.h" -/** - * Initialize database system. - * - * @param dir Path to the directory where the database file should be located. - * @return A valid zathura_database_t instance or NULL on failure - */ -zathura_database_t* zathura_db_init(const char* dir); +#define ZATHURA_TYPE_DATABASE \ + (zathura_database_get_type ()) +#define ZATHURA_DATABASE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), ZATHURA_TYPE_DATABASE, ZathuraDatabase)) +#define ZATHURA_IS_DATABASE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ZATHURA_TYPE_DATABASE)) +#define ZATHURA_DATABASE_GET_INTERFACE(obj) \ + (G_TYPE_INSTANCE_GET_INTERFACE ((obj), ZATHURA_TYPE_DATABASE, ZathuraDatabaseInterface)) + +typedef struct _ZathuraDatabase ZathuraDatabase; +typedef struct _ZathuraDatabaseInterface ZathuraDatabaseInterface; + +struct _ZathuraDatabaseInterface +{ + GTypeInterface parent_iface; + + /* interface methords */ + bool (*add_bookmark)(ZathuraDatabase* db, const char* file, zathura_bookmark_t* bookmark); + bool (*remove_bookmark)(ZathuraDatabase* db, const char* file, const char* id); + girara_list_t* (*load_bookmarks)(ZathuraDatabase* db, const char* file); + + bool (*set_fileinfo)(ZathuraDatabase* db, const char* file, unsigned + int page, int offset, double scale, int rotation); + + bool (*get_fileinfo)(ZathuraDatabase* db, const char* file, unsigned + int* page, int* offset, double* scale, int* rotation); +}; + +GType zathura_database_get_type(void); /** * Free database instance. diff --git a/zathura.c b/zathura.c index cf6b29c..98a7f32 100644 --- a/zathura.c +++ b/zathura.c @@ -17,7 +17,10 @@ #include "bookmarks.h" #include "callbacks.h" #include "config.h" -#include "database.h" +#ifdef WITH_SQLITE +#include "database-sqlite.h" +#endif +#include "database-plain.h" #include "document.h" #include "shortcuts.h" #include "zathura.h" @@ -231,7 +234,24 @@ zathura_init(int argc, char* argv[]) gtk_table_set_col_spacings(GTK_TABLE(zathura->ui.page_widget), zathura->global.page_padding); /* database */ - zathura->database = zathura_db_init(zathura->config.data_dir); + char* database = NULL; + girara_setting_get(zathura->ui.session, "database", &database); + + if (g_strcmp0(database, "plain") == 0) { + girara_info("Using plain database backend."); + zathura->database = zathura_plaindatabase_new(zathura->config.data_dir); +#ifdef WITH_SQLITE + } else if (g_strcmp0(database, "sqlite") == 0) { + girara_info("Using sqlite database backend."); + char* tmp = g_build_filename(zathura->config.data_dir, "bookmarks.sqlite", NULL); + zathura->database = zathura_sqldatabase_new(tmp); + g_free(tmp); +#endif + } else { + girara_error("Database backend '%s' is not supported.", database); + } + g_free(database); + if (zathura->database == NULL) { girara_error("Unable to initialize database. Bookmarks won't be available."); } diff --git a/zathura.h b/zathura.h index 004761c..8c92fa7 100644 --- a/zathura.h +++ b/zathura.h @@ -26,8 +26,7 @@ typedef struct zathura_document_s zathura_document_t; typedef struct zathura_page_s zathura_page_t; /* forward declaration for types form database.h */ -struct zathura_database_s; -typedef struct zathura_database_s zathura_database_t; +typedef struct _ZathuraDatabase zathura_database_t; /* forward declaration for types from render.h */ struct render_thread_s;