diff --git a/src/navigation.c b/src/navigation.c index e1518d84..dfdba864 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -10,8 +10,6 @@ #include #endif -#include - #include "common/avl/avl.h" #include "navigation.h" @@ -67,3 +65,88 @@ int mount_identifier_compare(mount_identifier_t *a, mount_id { return mount_identifier_compare__for_tree(NULL, a, b); } + +static inline int navigation_history_pop(navigation_history_t *history) +{ + if (history->fill == 0) + return 0; + history->fill--; + refobject_unref(history->history[history->fill]); + history->history[history->fill] = NULL; + return 1; +} + +static inline int navigation_history_push(navigation_history_t *history, mount_identifier_t *identifier) +{ + if (refobject_ref(identifier) != 0) + return -1; + + if (history->fill == (sizeof(history->history)/sizeof(*history->history))) { + refobject_unref(history->history[0]); + memmove(history->history, &(history->history[1]), sizeof(history->history) - sizeof(*history->history)); + history->fill--; + } + + history->history[history->fill++] = identifier; + + return 0; +} + +void navigation_history_clear(navigation_history_t *history) +{ + if (!history) + return; + while (navigation_history_pop(history)); +} + +mount_identifier_t * navigation_history_get_up(navigation_history_t *history) +{ + if (!history) + return NULL; + + if (history->fill < 2) + return NULL; + + if (refobject_ref(history->history[history->fill - 2]) != 0) + return NULL; + + return history->history[history->fill - 2]; +} + +int navigation_history_navigate_to(navigation_history_t *history, mount_identifier_t *identifier, navigation_direction_t direction) +{ + if (!history || !identifier) + return -1; + + switch (direction) { + case NAVIGATION_DIRECTION_UP: + if (history->fill < 2) + return -1; + if (mount_identifier_compare(history->history[history->fill - 2], identifier) != 0) + return -1; + return navigation_history_pop(history); + break; + case NAVIGATION_DIRECTION_DOWN: + return navigation_history_push(history, identifier); + break; + case NAVIGATION_DIRECTION_REPLACE_CURRENT: + if (history->fill == 0) { + return navigation_history_push(history, identifier); + } else { + if (refobject_ref(identifier) != 0) + return -1; + refobject_unref(history->history[history->fill - 1]); + history->history[history->fill - 1] = identifier; + return 0; + } + break; + case NAVIGATION_DIRECTION_REPLACE_ALL: + navigation_history_clear(history); + if (history->fill != 0) + return -1; + return navigation_history_push(history, identifier); + break; + } + + return -1; +} diff --git a/src/navigation.h b/src/navigation.h index b42d7370..32e97341 100644 --- a/src/navigation.h +++ b/src/navigation.h @@ -9,8 +9,24 @@ #ifndef __NAVIGATION_H__ #define __NAVIGATION_H__ +#include + #include "refobject.h" +#define MAX_NAVIGATION_HISTORY_SIZE 8 + +typedef struct { + mount_identifier_t *history[MAX_NAVIGATION_HISTORY_SIZE]; + size_t fill; +} navigation_history_t; + +typedef enum { + NAVIGATION_DIRECTION_UP, + NAVIGATION_DIRECTION_DOWN, + NAVIGATION_DIRECTION_REPLACE_CURRENT, + NAVIGATION_DIRECTION_REPLACE_ALL +} navigation_direction_t; + REFOBJECT_FORWARD_TYPE(mount_identifier_t); void navigation_initialize(void); @@ -20,4 +36,9 @@ mount_identifier_t * mount_identifier_new(const char *mount); #define mount_identifier_get_mount(identifier) refobject_get_name((identifier)) int mount_identifier_compare(mount_identifier_t *a, mount_identifier_t *b); +#define navigation_history_init(history) memset((history), 0, sizeof(navigation_history_t)) +void navigation_history_clear(navigation_history_t *history); +mount_identifier_t * navigation_history_get_up(navigation_history_t *history); +int navigation_history_navigate_to(navigation_history_t *history, mount_identifier_t *identifier, navigation_direction_t direction); + #endif