summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/file-storage.c159
-rw-r--r--src/file-storage.h31
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile3
-rw-r--r--tests/test-file-storage.c132
5 files changed, 325 insertions, 1 deletions
diff --git a/src/file-storage.c b/src/file-storage.c
new file mode 100644
index 0000000..925f669
--- /dev/null
+++ b/src/file-storage.c
@@ -0,0 +1,159 @@
+/**
+ * vimb - a webkit based vim like browser.
+ *
+ * Copyright (C) 2012-2019 Daniel Carl
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include <sys/file.h>
+#include <glib/gstdio.h>
+
+#include "file-storage.h"
+#include "util.h"
+
+struct filestorage {
+ char *file_path;
+ gboolean readonly;
+ GString *str;
+};
+
+/**
+ * Create new file storage instance for given directory and filename. If the
+ * file does not exists in the directory and give mode is not 0 the file is
+ * created with the given mode.
+ *
+ * The returned FileStorage must be freed by file_storage_free().
+ *
+ * @dir: Directory in which the file is searched.
+ * @filename: Filename to built the absolute path with.
+ * @mode: Mode (file permission as chmod(2)) used for the file when
+ * creating it. If 0 the file is not created and the storage is
+ * used in read only mode - no data written to the file.
+ */
+FileStorage *file_storage_new(const char *dir, const char *filename, int mode)
+{
+ char *fullpath;
+ FileStorage *storage;
+
+ storage = g_slice_new(FileStorage);
+ storage->readonly = (mode == 0);
+
+ /* Built the full path out of dir and given file name. */
+ fullpath = g_build_filename(dir, filename, NULL);
+ if (g_file_test(fullpath, G_FILE_TEST_IS_REGULAR)) {
+ storage->file_path = fullpath;
+ } else if (mode) {
+ /* If create option was given - create the file. */
+ fclose(fopen(fullpath, "a"));
+
+ storage->file_path = fullpath;
+ g_chmod(fullpath, mode);
+ } else {
+ storage->file_path = NULL;
+ g_free(fullpath);
+ }
+
+ /* Use gstring as storage in case when the file is used read only. */
+ if (storage->readonly) {
+ storage->str = g_string_new(NULL);
+ }
+
+ return storage;
+}
+
+/**
+ * Free memory for given file storage.
+ */
+void file_storage_free(FileStorage *storage)
+{
+ if (storage) {
+ if (storage->file_path) {
+ g_free(storage->file_path);
+ }
+ if (storage->str) {
+ g_string_free(storage->str, TRUE);
+ }
+ g_slice_free(FileStorage, storage);
+ }
+}
+
+/**
+ * Append new data to file.
+ *
+ * @fileStorage: FileStorage to append the data to
+ * @format: Format string used to process va_list
+ */
+gboolean file_storage_append(FileStorage *storage, const char *format, ...)
+{
+ FILE *f;
+ va_list args;
+
+ g_assert(storage);
+
+ /* Write data to in memory list in case the file storage is read only. */
+ if (storage->readonly) {
+ va_start(args, format);
+ g_string_append_vprintf(storage->str, format, args);
+ va_end(args);
+ return TRUE;
+ }
+ if (storage->file_path && (f = fopen(storage->file_path, "a+"))) {
+ flock(fileno(f), LOCK_EX);
+ va_start(args, format);
+ vfprintf(f, format, args);
+ va_end(args);
+ flock(fileno(f), LOCK_UN);
+ fclose(f);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Retrieves all the lines from file storage.
+ *
+ * The result have to be freed by g_strfreev().
+ */
+char **file_storage_get_lines(FileStorage *storage)
+{
+ char *fullcontent = NULL;
+ char *content = NULL;
+ char **lines = NULL;
+
+ if (storage->file_path) {
+ content = util_get_file_contents(storage->file_path, NULL);
+ }
+
+ if (storage->str && storage->str->len) {
+ if (content) {
+ fullcontent = g_strconcat(content, storage->str->str, NULL);
+ lines = g_strsplit(fullcontent, "\n", -1);
+ g_free(fullcontent);
+ } else {
+ lines = g_strsplit(storage->str->str, "\n", -1);
+ }
+ } else {
+ lines = g_strsplit(content ? content : "", "\n", -1);
+ }
+
+ if (content) {
+ g_free(content);
+ }
+
+ return lines;
+}
diff --git a/src/file-storage.h b/src/file-storage.h
new file mode 100644
index 0000000..3beecce
--- /dev/null
+++ b/src/file-storage.h
@@ -0,0 +1,31 @@
+/**
+ * vimb - a webkit based vim like browser.
+ *
+ * Copyright (C) 2012-2019 Daniel Carl
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ */
+
+#ifndef _FILE_STORAGE_H
+#define _FILE_STORAGE_H
+
+#include <glib.h>
+
+typedef struct filestorage FileStorage;
+FileStorage *file_storage_new(const char *dir, const char *filename, int mode);
+void file_storage_free(FileStorage *storage);
+gboolean file_storage_append(FileStorage *storage, const char *format, ...);
+char **file_storage_get_lines(FileStorage *storage);
+
+#endif /* end of include guard: _FILE_STORAGE_H */
diff --git a/tests/.gitignore b/tests/.gitignore
index c802245..362dcd3 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1 +1,2 @@
/test-*
+!/test-*.c
diff --git a/tests/Makefile b/tests/Makefile
index 6ebc85d..c3ce1ca 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -4,7 +4,8 @@ include ../config.mk
TEST_PROGS = test-util \
test-shortcut \
- test-handler
+ test-handler \
+ test-file-storage
all: $(TEST_PROGS)
$(Q)LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):." gtester --verbose $(TEST_PROGS)
diff --git a/tests/test-file-storage.c b/tests/test-file-storage.c
new file mode 100644
index 0000000..28859b2
--- /dev/null
+++ b/tests/test-file-storage.c
@@ -0,0 +1,132 @@
+/**
+ * vimb - a webkit based vim like browser.
+ *
+ * Copyright (C) 2012-2019 Daniel Carl
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ */
+
+#include <src/file-storage.h>
+#include <gio/gio.h>
+#include <stdio.h>
+
+static char *pwd;
+static char *none_existing_file = "_absent.txt";
+static char *created_file = "_created.txt";
+static char *existing_file = "_existent.txt";
+
+static void test_ephemeral_no_file(void)
+{
+ FileStorage *s;
+ char **lines;
+ char *file_path;
+
+ file_path = g_build_filename(pwd, none_existing_file, NULL);
+
+ /* make sure the file does not exist */
+ remove(file_path);
+ s = file_storage_new(pwd, none_existing_file, 0);
+ g_assert_nonnull(s);
+
+ /* empty file storage */
+ lines = file_storage_get_lines(s);
+ g_assert_cmpint(g_strv_length(lines), ==, 0);
+ g_strfreev(lines);
+
+ file_storage_append(s, "-%s\n", "foo");
+ file_storage_append(s, "-%s\n", "bar");
+
+ /* File must not be created on appending data to storage */
+ g_assert_false(g_file_test(file_path, G_FILE_TEST_IS_REGULAR));
+
+ lines = file_storage_get_lines(s);
+ g_assert_cmpint(g_strv_length(lines), ==, 3);
+ g_assert_cmpstr(lines[0], ==, "-foo");
+ g_assert_cmpstr(lines[1], ==, "-bar");
+ g_strfreev(lines);
+ file_storage_free(s);
+ g_free(file_path);
+}
+
+static void test_file_created(void)
+{
+ FileStorage *s;
+ char *file_path;
+
+ file_path = g_build_filename(pwd, created_file, NULL);
+ remove(file_path);
+
+ g_assert_false(g_file_test(file_path, G_FILE_TEST_IS_REGULAR));
+ s = file_storage_new(pwd, created_file, 0640);
+ g_assert_true(g_file_test(file_path, G_FILE_TEST_IS_REGULAR));
+
+ file_storage_free(s);
+ g_free(file_path);
+}
+
+static void test_ephemeral_with_file(void)
+{
+ FileStorage *s;
+ char *file_path;
+ char **lines;
+ char *content = NULL;
+ gboolean result;
+
+ file_path = g_build_filename(pwd, existing_file, NULL);
+ result = g_file_set_contents(file_path, "one\n", -1, NULL);
+ g_assert_true(result);
+
+ s = file_storage_new(pwd, existing_file, 0);
+ g_assert_nonnull(s);
+
+ /* empty file storage but file with two lines */
+ lines = file_storage_get_lines(s);
+ g_assert_cmpint(g_strv_length(lines), ==, 2);
+ g_strfreev(lines);
+
+ file_storage_append(s, "%s\n", "two ephemeral");
+
+ lines = file_storage_get_lines(s);
+ g_assert_cmpint(g_strv_length(lines), ==, 3);
+ g_assert_cmpstr(lines[0], ==, "one");
+ g_assert_cmpstr(lines[1], ==, "two ephemeral");
+ g_strfreev(lines);
+
+ /* now make sure the file was not changed */
+ g_file_get_contents(file_path, &content, NULL, NULL);
+ g_assert_cmpstr(content, ==, "one\n");
+
+ file_storage_free(s);
+ g_free(file_path);
+}
+
+int main(int argc, char *argv[])
+{
+ int result;
+ g_test_init(&argc, &argv, NULL);
+
+ pwd = g_get_current_dir();
+
+ g_test_add_func("/test-file-storage/ephemeral-no-file", test_ephemeral_no_file);
+ g_test_add_func("/test-file-storage/file-created", test_file_created);
+ g_test_add_func("/test-file-storage/ephemeral-with-file", test_ephemeral_with_file);
+
+ result = g_test_run();
+
+ remove(existing_file);
+ remove(created_file);
+ g_free(pwd);
+
+ return result;
+}