about summary refs log tree commit diff stats
path: root/src/tools/history.c
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2013-02-02 21:43:59 +0000
committerJames Booth <boothj5@gmail.com>2013-02-02 21:43:59 +0000
commit740e5b422832f8d043d96f33a0d33bf1725dbbc0 (patch)
treee28525525de760b696bfd4f7dbb326334db8ee29 /src/tools/history.c
parentfc5bfb7d33dc6e1a6a53c46d414df4f9324f6ad5 (diff)
downloadprofani-tty-740e5b422832f8d043d96f33a0d33bf1725dbbc0.tar.gz
Added command and tools subdirs to source
Diffstat (limited to 'src/tools/history.c')
-rw-r--r--src/tools/history.c267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/tools/history.c b/src/tools/history.c
new file mode 100644
index 00000000..5ac41969
--- /dev/null
+++ b/src/tools/history.c
@@ -0,0 +1,267 @@
+/*
+ * history.c
+ *
+ * Copyright (C) 2012, 2013 James Booth <boothj5@gmail.com>
+ *
+ * This file is part of Profanity.
+ *
+ * Profanity 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.
+ *
+ * Profanity 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 Profanity.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "history.h"
+
+struct history_session_t {
+    GList *items;
+    GList *sess_curr;
+    GList *sess_new;
+    GList *orig_curr;
+};
+
+struct history_t {
+    GList *items;
+    guint max_size;
+    struct history_session_t session;
+};
+
+static void _replace_history_with_session(History history);
+static gboolean _adding_new(History history);
+static void _reset_session(History history);
+static gboolean _has_session(History history);
+static void _remove_first(History history);
+static void _update_current_session_item(History history, char *item);
+static void _add_to_history(History history, char *item);
+static void _remove_last_session_item(History history);
+static void _replace_current_with_original(History history);
+static void _create_session(History history);
+static void _session_previous(History history);
+static void _session_next(History history);
+
+History
+history_new(unsigned int size)
+{
+    History new_history = malloc(sizeof(struct history_t));
+    new_history->items = NULL;
+    new_history->max_size = size;
+
+    _reset_session(new_history);
+
+    return new_history;
+}
+
+void
+history_append(History history, char *item)
+{
+    char *copied = "";
+    if (item != NULL) {
+        copied = strdup(item);
+    }
+
+    if (history->items == NULL) {
+        _add_to_history(history, copied);
+        return;
+    }
+
+    if (!_has_session(history)) {
+        if (g_list_length(history->items) == history->max_size) {
+            _remove_first(history);
+        }
+
+        _add_to_history(history, copied);
+
+    } else {
+        _update_current_session_item(history, copied);
+
+        if (_adding_new(history)) {
+            if (strcmp(history->session.sess_curr->data, "") == 0) {
+                _remove_last_session_item(history);
+            }
+
+            _replace_history_with_session(history);
+
+        } else {
+            _remove_last_session_item(history);
+
+            char *new = strdup(history->session.sess_curr->data);
+            history->session.items = g_list_append(history->session.items, new);
+
+            _replace_current_with_original(history);
+            _replace_history_with_session(history);
+        }
+    }
+}
+
+char *
+history_previous(History history, char *item)
+{
+    // no history
+    if (history->items == NULL) {
+        return NULL;
+    }
+
+    char *copied = "";
+    if (item != NULL) {
+        copied = strdup(item);
+    }
+
+    if (!_has_session(history)) {
+        _create_session(history);
+
+        // add the new item
+        history->session.items = g_list_append(history->session.items, copied);
+        history->session.sess_new = g_list_last(history->session.items);
+
+        char *result = strdup(history->session.sess_curr->data);
+        return result;
+    } else {
+        _update_current_session_item(history, copied);
+        _session_previous(history);
+    }
+
+    char *result = strdup(history->session.sess_curr->data);
+    return result;
+}
+
+char *
+history_next(History history, char *item)
+{
+    // no history, or no session, return NULL
+    if ((history->items == NULL) || (history->session.items == NULL)) {
+        return NULL;
+    }
+
+    char *copied = "";
+    if (item != NULL) {
+        copied = strdup(item);
+    }
+
+    _update_current_session_item(history, copied);
+    _session_next(history);
+
+    char *result = strdup(history->session.sess_curr->data);
+    return result;
+}
+
+static void
+_replace_history_with_session(History history)
+{
+    g_list_free(history->items);
+    history->items = g_list_copy(history->session.items);
+
+    if (g_list_length(history->items) > history->max_size) {
+        _remove_first(history);
+    }
+
+    _reset_session(history);
+}
+
+static gboolean
+_adding_new(History history)
+{
+    return (history->session.sess_curr ==
+        g_list_last(history->session.items));
+}
+
+static void
+_reset_session(History history)
+{
+    history->session.items = NULL;
+    history->session.sess_curr = NULL;
+    history->session.sess_new = NULL;
+    history->session.orig_curr = NULL;
+}
+
+static gboolean
+_has_session(History history)
+{
+    return (history->session.items != NULL);
+}
+
+static void
+_remove_first(History history)
+{
+    GList *first = g_list_first(history->items);
+    char *first_item = first->data;
+    history->items = g_list_remove(history->items, first_item);
+}
+
+static void
+_update_current_session_item(History history, char *item)
+{
+    history->session.sess_curr->data = item;
+}
+
+static void
+_add_to_history(History history, char *item)
+{
+    history->items = g_list_append(history->items, item);
+}
+
+static void
+_remove_last_session_item(History history)
+{
+    history->session.items = g_list_reverse(history->session.items);
+    GList *first = g_list_first(history->session.items);
+    history->session.items =
+        g_list_remove(history->session.items, first->data);
+    history->session.items = g_list_reverse(history->session.items);
+}
+
+static void
+_replace_current_with_original(History history)
+{
+    history->session.sess_curr->data = strdup(history->session.orig_curr->data);
+}
+
+static void
+_create_session(History history)
+{
+    history->session.items = g_list_copy(history->items);
+    history->session.sess_curr = g_list_last(history->session.items);
+    history->session.orig_curr = g_list_last(history->items);
+}
+
+static void
+_session_previous(History history)
+{
+    history->session.sess_curr =
+        g_list_previous(history->session.sess_curr);
+    if (history->session.orig_curr == NULL)
+        history->session.orig_curr = g_list_last(history->items);
+    else
+        history->session.orig_curr =
+            g_list_previous(history->session.orig_curr);
+
+    if (history->session.sess_curr == NULL) {
+        history->session.sess_curr = g_list_first(history->session.items);
+        history->session.orig_curr = g_list_first(history->items);
+    }
+}
+
+static void
+_session_next(History history)
+{
+    history->session.sess_curr = g_list_next(history->session.sess_curr);
+    history->session.orig_curr = g_list_next(history->session.orig_curr);
+
+    if (history->session.sess_curr == NULL) {
+        history->session.sess_curr = g_list_last(history->session.items);
+        history->session.orig_curr = NULL;
+    }
+}