/* Icecast * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * * Copyright 2020, Philipp "ph3-der-loewe" Schafft */ #ifdef HAVE_CONFIG_H #include #endif #include "common/avl/avl.h" #include "navigation.h" #include "logging.h" #define CATMODULE "navigation" struct mount_identifier_tag { /* base object */ refobject_base_t __base; }; REFOBJECT_DEFINE_TYPE(mount_identifier_t); const char * navigation_direction_to_str(navigation_direction_t dir) { switch (dir) { case NAVIGATION_DIRECTION_UP: return "up"; break; case NAVIGATION_DIRECTION_DOWN: return "down"; break; case NAVIGATION_DIRECTION_REPLACE_CURRENT: return "replace-current"; break; case NAVIGATION_DIRECTION_REPLACE_ALL: return "replace-all"; break; } return NULL; } navigation_direction_t navigation_str_to_direction(const char *str, navigation_direction_t def) { if (!str || !*str) return def; if (strcasecmp(str, "up") == 0) { return NAVIGATION_DIRECTION_UP; } else if (strcasecmp(str, "down") == 0) { return NAVIGATION_DIRECTION_DOWN; } else if (strcasecmp(str, "replace_current") == 0 || strcasecmp(str, "replace-current") == 0) { return NAVIGATION_DIRECTION_REPLACE_CURRENT; } else if (strcasecmp(str, "replace_all") == 0 || strcasecmp(str, "replace-all") == 0) { return NAVIGATION_DIRECTION_REPLACE_ALL; } else { return def; } } static int mount_identifier_compare__for_tree(void *compare_arg, void *a, void *b) { const char *id_a, *id_b; id_a = mount_identifier_get_mount(a); id_b = mount_identifier_get_mount(b); if (!id_a || !id_b || id_a == id_b) { return 0; } else { return strcmp(id_a, id_b); } } void navigation_initialize(void) { } void navigation_shutdown(void) { } mount_identifier_t * mount_identifier_new(const char *mount) { mount_identifier_t *n; if (!mount) return NULL; n = refobject_new__new(mount_identifier_t, NULL, mount, NULL); if (!n) return NULL; return n; } int mount_identifier_compare(mount_identifier_t *a, mount_identifier_t *b) { 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 0; } static inline int navigation_history_push(navigation_history_t *history, mount_identifier_t *identifier) { if (history->fill > 0 && mount_identifier_compare(history->history[history->fill - 1], identifier) == 0) return 0; if (refobject_ref(identifier) != 0) { ICECAST_LOG_ERROR("Can not reference identifier=%p, BAD.", identifier); 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) { ICECAST_LOG_DDEBUG("Called with history=%p, identifier=%p (%#H), direction=%s", history, identifier, mount_identifier_get_mount(identifier), navigation_direction_to_str(direction)); if (!history || !identifier) return -1; if (direction == NAVIGATION_DIRECTION_UP && history->fill < 2) direction = NAVIGATION_DIRECTION_REPLACE_ALL; 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 (history->fill > 1 && mount_identifier_compare(history->history[history->fill - 2], identifier) == 0) { return navigation_history_pop(history); } if (refobject_ref(identifier) != 0) { ICECAST_LOG_ERROR("Can not reference identifier=%p, BAD.", identifier); 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; }