1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-06-02 06:01:10 +00:00
icecast-server/src/navigation.c

199 lines
5.7 KiB
C

/* 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 <lion@lion.leolix.org>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#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;
}