From 47eddd0e8689ab70d6346140cc37e61797aa9513 Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Thu, 14 Mar 2013 22:13:39 +0100 Subject: [PATCH 1/3] Implement sqlite backend for input history Signed-off-by: Sebastian Ramacher --- database-sqlite.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++- zathura.c | 3 ++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/database-sqlite.c b/database-sqlite.c index 8e7600f..2cd7ba4 100644 --- a/database-sqlite.c +++ b/database-sqlite.c @@ -3,14 +3,17 @@ #include #include #include +#include #include #include "database-sqlite.h" static void zathura_database_interface_init(ZathuraDatabaseInterface* iface); +static void io_interface_init(GiraraInputHistoryIOInterface* iface); G_DEFINE_TYPE_WITH_CODE(ZathuraSQLDatabase, zathura_sqldatabase, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(ZATHURA_TYPE_DATABASE, zathura_database_interface_init)) + G_IMPLEMENT_INTERFACE(ZATHURA_TYPE_DATABASE, zathura_database_interface_init) + G_IMPLEMENT_INTERFACE(GIRARA_TYPE_INPUT_HISTORY_IO, io_interface_init)) static void sqlite_finalize(GObject* object); static bool sqlite_add_bookmark(zathura_database_t* db, const char* file, @@ -25,6 +28,8 @@ static bool sqlite_get_fileinfo(zathura_database_t* db, const char* file, zathura_fileinfo_t* file_info); static void sqlite_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec); +static void sqlite_io_append(GiraraInputHistoryIO* db, const char*); +static girara_list_t* sqlite_io_read(GiraraInputHistoryIO* db); typedef struct zathura_sqldatabase_private_s { sqlite3* session; @@ -49,6 +54,14 @@ zathura_database_interface_init(ZathuraDatabaseInterface* iface) iface->get_fileinfo = sqlite_get_fileinfo; } +static void +io_interface_init(GiraraInputHistoryIOInterface* iface) +{ + /* initialize interface */ + iface->append = sqlite_io_append; + iface->read = sqlite_io_read; +} + static void zathura_sqldatabase_class_init(ZathuraSQLDatabaseClass* class) { @@ -132,6 +145,12 @@ sqlite_db_init(ZathuraSQLDatabase* db, const char* path) static const char SQL_FILEINFO_ALTER2[] = "ALTER TABLE fileinfo ADD COLUMN first_page_column INTEGER;"; + static const char SQL_HISTORY_INIT[] = + "CREATE TABLE IF NOT EXISTS history (" + "time TIMESTAMP," + "line TEXT," + "PRIMARY KEY(line));"; + sqlite3* session = NULL; if (sqlite3_open(path, &session) != SQLITE_OK) { girara_error("Could not open database: %s\n", path); @@ -150,6 +169,12 @@ sqlite_db_init(ZathuraSQLDatabase* db, const char* path) return; } + if (sqlite3_exec(session, SQL_HISTORY_INIT, NULL, 0, NULL) != SQLITE_OK) { + girara_error("Failed to initialize database: %s\n", path); + sqlite3_close(session); + return; + } + const char* data_type = NULL; if (sqlite3_table_column_metadata(session, NULL, "fileinfo", "pages_per_row", &data_type, NULL, NULL, NULL, NULL) != SQLITE_OK) { girara_debug("old database table layout detected; updating ..."); @@ -380,3 +405,51 @@ sqlite_get_fileinfo(zathura_database_t* db, const char* file, return true; } + +static void +sqlite_io_append(GiraraInputHistoryIO* db, const char* input) +{ + static const char SQL_HISTORY_SET[] = + "REPLACE INTO history (line, time) VALUES (?, DATETIME('now'));"; + + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); + sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_HISTORY_SET); + if (stmt == NULL) { + return; + } + + if (sqlite3_bind_text(stmt, 1, input, -1, NULL) != SQLITE_OK) { + sqlite3_finalize(stmt); + girara_error("Failed to bind arguments."); + return; + } + + sqlite3_step(stmt); + sqlite3_finalize(stmt); +} + +static girara_list_t* +sqlite_io_read(GiraraInputHistoryIO* db) +{ + static const char SQL_HISTORY_GET[] = + "SELECT line FROM history ORDER BY time"; + + zathura_sqldatabase_private_t* priv = ZATHURA_SQLDATABASE_GET_PRIVATE(db); + sqlite3_stmt* stmt = prepare_statement(priv->session, SQL_HISTORY_GET); + if (stmt == NULL) { + return NULL; + } + + girara_list_t* list = girara_list_new2((girara_free_function_t) g_free); + if (list == NULL) { + sqlite3_finalize(stmt); + return NULL; + } + + while (sqlite3_step(stmt) == SQLITE_ROW) { + girara_list_append(list, g_strdup((const char*) sqlite3_column_text(stmt, 0))); + } + + sqlite3_finalize(stmt); + return list; +} diff --git a/zathura.c b/zathura.c index 4762e8f..5af318a 100644 --- a/zathura.c +++ b/zathura.c @@ -219,6 +219,9 @@ zathura_init(zathura_t* zathura) girara_debug("Using sqlite database backend."); char* tmp = g_build_filename(zathura->config.data_dir, "bookmarks.sqlite", NULL); zathura->database = zathura_sqldatabase_new(tmp); + if (zathura->database != NULL) { + g_object_set(zathura->ui.session->global.command_history, "io", zathura->database, NULL); + } g_free(tmp); #endif } else { From 92f87846058b633a1ae453b6e21f704608f72fd7 Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Sun, 17 Mar 2013 16:19:10 +0100 Subject: [PATCH 2/3] Implement input history IO in plain database Signed-off-by: Sebastian Ramacher --- database-plain.c | 118 ++++++++++++++++++++++++++++++++++++++++++++--- zathura.c | 5 +- 2 files changed, 113 insertions(+), 10 deletions(-) diff --git a/database-plain.c b/database-plain.c index fcc0558..90de64c 100644 --- a/database-plain.c +++ b/database-plain.c @@ -1,6 +1,7 @@ /* See LICENSE file for license and copyright information */ #define _POSIX_SOURCE +#define _XOPEN_SOURCE 500 #include #include @@ -10,11 +11,13 @@ #include #include #include +#include #include "database-plain.h" #define BOOKMARKS "bookmarks" #define HISTORY "history" +#define INPUT_HISTORY "input-history" #define KEY_PAGE "page" #define KEY_OFFSET "offset" @@ -37,9 +40,11 @@ #endif static void zathura_database_interface_init(ZathuraDatabaseInterface* iface); +static void io_interface_init(GiraraInputHistoryIOInterface* iface); G_DEFINE_TYPE_WITH_CODE(ZathuraPlainDatabase, zathura_plaindatabase, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(ZATHURA_TYPE_DATABASE, zathura_database_interface_init)) + G_IMPLEMENT_INTERFACE(ZATHURA_TYPE_DATABASE, zathura_database_interface_init) + G_IMPLEMENT_INTERFACE(GIRARA_TYPE_INPUT_HISTORY_IO, io_interface_init)) static void plain_finalize(GObject* object); static bool plain_add_bookmark(zathura_database_t* db, const char* file, @@ -54,6 +59,8 @@ static bool plain_get_fileinfo(zathura_database_t* db, const char* file, zathura_fileinfo_t* file_info); static void plain_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec); +static void plain_io_append(GiraraInputHistoryIO* db, const char*); +static girara_list_t* plain_io_read(GiraraInputHistoryIO* db); /* forward declaration */ static bool zathura_db_check_file(const char* path); @@ -70,6 +77,8 @@ typedef struct zathura_plaindatabase_private_s { char* history_path; GKeyFile* history; GFileMonitor* history_monitor; + + char* input_history_path; } zathura_plaindatabase_private_t; #define ZATHURA_PLAINDATABASE_GET_PRIVATE(obj) \ @@ -105,6 +114,14 @@ zathura_database_interface_init(ZathuraDatabaseInterface* iface) iface->get_fileinfo = plain_get_fileinfo; } +static void +io_interface_init(GiraraInputHistoryIOInterface* iface) +{ + /* initialize interface */ + iface->append = plain_io_append; + iface->read = plain_io_read; +} + static void zathura_plaindatabase_class_init(ZathuraPlainDatabaseClass* class) { @@ -126,12 +143,13 @@ 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; + priv->bookmark_path = NULL; + priv->bookmark_monitor = NULL; + priv->bookmarks = NULL; + priv->history_path = NULL; + priv->history_monitor = NULL; + priv->history = NULL; + priv->input_history_path = NULL; } zathura_database_t* @@ -208,6 +226,12 @@ plain_db_init(ZathuraPlainDatabase* db, const char* dir) goto error_free; } + /* input history */ + priv->input_history_path = g_build_filename(dir, INPUT_HISTORY, NULL); + if (zathura_db_check_file(priv->input_history_path) == false) { + goto error_free; + } + return; error_free: @@ -239,6 +263,10 @@ error_free: g_key_file_free(priv->history); priv->history = NULL; } + + /* input history */ + g_free(priv->input_history_path); + priv->input_history_path = NULL; } static void @@ -283,6 +311,9 @@ plain_finalize(GObject* object) g_key_file_free(priv->history); } + /* input history */ + g_free(priv->input_history_path); + G_OBJECT_CLASS(zathura_plaindatabase_parent_class)->finalize(object); } @@ -595,3 +626,76 @@ cb_zathura_db_watch_file(GFileMonitor* UNUSED(monitor), GFile* file, GFile* UNUS g_free(path); } + +static girara_list_t* +plain_io_read(GiraraInputHistoryIO* db) +{ + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); + + /* open file */ + FILE* file = fopen(priv->input_history_path, "r"); + if (file == NULL) { + return NULL; + } + + /* read input history file */ + file_lock_set(fileno(file), F_RDLCK); + char* content = girara_file_read2(file); + file_lock_set(fileno(file), F_UNLCK); + fclose(file); + + girara_list_t* res = girara_list_new2(g_free); + char** tmp = g_strsplit(content, "\n", 0); + for (size_t i = 0; tmp[i] != NULL; ++i) { + if (strlen(tmp[i]) == 0 || strchr(":/", tmp[i][0]) == NULL) { + continue; + } + girara_list_append(res, g_strdup(tmp[i])); + } + g_strfreev(tmp); + free(content); + + return res; +} + +#include + +static void +plain_io_append(GiraraInputHistoryIO* db, const char* input) +{ + zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db); + + /* open file */ + FILE* file = fopen(priv->input_history_path, "r+"); + if (file == NULL) { + return; + } + + /* read input history file */ + file_lock_set(fileno(file), F_WRLCK); + char* content = girara_file_read2(file); + + rewind(file); + if (ftruncate(fileno(file), 0) != 0) { + free(content); + file_lock_set(fileno(file), F_UNLCK); + fclose(file); + return; + } + + char** tmp = g_strsplit(content, "\n", 0); + free(content); + + /* write input history file */ + for (size_t i = 0; tmp[i] != NULL; ++i) { + if (strlen(tmp[i]) == 0 || strchr(":/", tmp[i][0]) == NULL || strcmp(tmp[i], input) == 0) { + continue; + } + fprintf(file, "%s\n", tmp[i]); + } + g_strfreev(tmp); + fprintf(file, "%s\n", input); + + file_lock_set(fileno(file), F_UNLCK); + fclose(file); +} diff --git a/zathura.c b/zathura.c index 5af318a..b110a6d 100644 --- a/zathura.c +++ b/zathura.c @@ -219,9 +219,6 @@ zathura_init(zathura_t* zathura) girara_debug("Using sqlite database backend."); char* tmp = g_build_filename(zathura->config.data_dir, "bookmarks.sqlite", NULL); zathura->database = zathura_sqldatabase_new(tmp); - if (zathura->database != NULL) { - g_object_set(zathura->ui.session->global.command_history, "io", zathura->database, NULL); - } g_free(tmp); #endif } else { @@ -231,6 +228,8 @@ zathura_init(zathura_t* zathura) if (zathura->database == NULL) { girara_error("Unable to initialize database. Bookmarks won't be available."); + } else { + g_object_set(zathura->ui.session->global.command_history, "io", zathura->database, NULL); } /* bookmarks */ From c20b5e25c76782006565da5123ac179d809519e6 Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Sun, 17 Mar 2013 16:25:02 +0100 Subject: [PATCH 3/3] Use the correct command history Signed-off-by: Sebastian Ramacher --- zathura.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zathura.c b/zathura.c index b110a6d..8d2ed74 100644 --- a/zathura.c +++ b/zathura.c @@ -229,7 +229,7 @@ zathura_init(zathura_t* zathura) if (zathura->database == NULL) { girara_error("Unable to initialize database. Bookmarks won't be available."); } else { - g_object_set(zathura->ui.session->global.command_history, "io", zathura->database, NULL); + g_object_set(zathura->ui.session->command_history, "io", zathura->database, NULL); } /* bookmarks */