weechat/src/core/wee-list.c

470 lines
9.8 KiB
C

/*
* wee-list.c - sorted lists
*
* Copyright (C) 2003-2020 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "weechat.h"
#include "wee-list.h"
#include "wee-log.h"
#include "wee-string.h"
#include "../plugins/plugin.h"
/*
* Creates a new list.
*
* Returns pointer to new list, NULL if error.
*/
struct t_weelist *
weelist_new ()
{
struct t_weelist *new_weelist;
new_weelist = malloc (sizeof (*new_weelist));
if (new_weelist)
{
new_weelist->items = NULL;
new_weelist->last_item = NULL;
new_weelist->size = 0;
}
return new_weelist;
}
/*
* Searches for position of data (to keep list sorted).
*/
struct t_weelist_item *
weelist_find_pos (struct t_weelist *weelist, const char *data)
{
struct t_weelist_item *ptr_item;
if (!weelist || !data)
return NULL;
for (ptr_item = weelist->items; ptr_item;
ptr_item = ptr_item->next_item)
{
if (string_strcasecmp (data, ptr_item->data) < 0)
return ptr_item;
}
/* position not found, best position is at the end */
return NULL;
}
/*
* Inserts an element in the list (keeping list sorted).
*/
void
weelist_insert (struct t_weelist *weelist, struct t_weelist_item *item,
const char *where)
{
struct t_weelist_item *pos_item;
if (!weelist || !item)
return;
if (weelist->items)
{
/* remove element if already in list */
pos_item = weelist_search (weelist, item->data);
if (pos_item)
weelist_remove (weelist, pos_item);
}
if (weelist->items)
{
/* search position for new element, according to pos asked */
pos_item = NULL;
if (string_strcasecmp (where, WEECHAT_LIST_POS_BEGINNING) == 0)
pos_item = weelist->items;
else if (string_strcasecmp (where, WEECHAT_LIST_POS_END) == 0)
pos_item = NULL;
else
pos_item = weelist_find_pos (weelist, item->data);
if (pos_item)
{
/* insert data into the list (before position found) */
item->prev_item = pos_item->prev_item;
item->next_item = pos_item;
if (pos_item->prev_item)
(pos_item->prev_item)->next_item = item;
else
weelist->items = item;
pos_item->prev_item = item;
}
else
{
/* add data to the end */
item->prev_item = weelist->last_item;
item->next_item = NULL;
(weelist->last_item)->next_item = item;
weelist->last_item = item;
}
}
else
{
item->prev_item = NULL;
item->next_item = NULL;
weelist->items = item;
weelist->last_item = item;
}
}
/*
* Creates new data and add it to the list.
*
* Returns pointer to new item, NULL if error.
*/
struct t_weelist_item *
weelist_add (struct t_weelist *weelist, const char *data, const char *where,
void *user_data)
{
struct t_weelist_item *new_item;
if (!weelist || !data || !data[0] || !where || !where[0])
return NULL;
new_item = malloc (sizeof (*new_item));
if (new_item)
{
new_item->data = strdup (data);
new_item->user_data = user_data;
weelist_insert (weelist, new_item, where);
weelist->size++;
}
return new_item;
}
/*
* Searches for data in a list (case sensitive).
*
* Returns pointer to item found, NULL if not found.
*/
struct t_weelist_item *
weelist_search (struct t_weelist *weelist, const char *data)
{
struct t_weelist_item *ptr_item;
if (!weelist || !data)
return NULL;
for (ptr_item = weelist->items; ptr_item;
ptr_item = ptr_item->next_item)
{
if (strcmp (data, ptr_item->data) == 0)
return ptr_item;
}
/* data not found in list */
return NULL;
}
/*
* Searches for data in a list (case sensitive).
*
* Returns position of item found (>= 0), -1 if not found.
*/
int
weelist_search_pos (struct t_weelist *weelist, const char *data)
{
struct t_weelist_item *ptr_item;
int i;
if (!weelist || !data)
return -1;
i = 0;
for (ptr_item = weelist->items; ptr_item;
ptr_item = ptr_item->next_item)
{
if (strcmp (data, ptr_item->data) == 0)
return i;
i++;
}
/* data not found in list */
return -1;
}
/*
* Searches for data in a list (case insensitive).
*
* Returns pointer to item found, NULL if not found.
*/
struct t_weelist_item *
weelist_casesearch (struct t_weelist *weelist, const char *data)
{
struct t_weelist_item *ptr_item;
if (!weelist || !data)
return NULL;
for (ptr_item = weelist->items; ptr_item;
ptr_item = ptr_item->next_item)
{
if (string_strcasecmp (data, ptr_item->data) == 0)
return ptr_item;
}
/* data not found in list */
return NULL;
}
/*
* Searches for data in a list (case insensitive).
*
* Returns position of item found (>= 0), -1 if not found.
*/
int
weelist_casesearch_pos (struct t_weelist *weelist, const char *data)
{
struct t_weelist_item *ptr_item;
int i;
if (!weelist || !data)
return -1;
i = 0;
for (ptr_item = weelist->items; ptr_item;
ptr_item = ptr_item->next_item)
{
if (string_strcasecmp (data, ptr_item->data) == 0)
return i;
i++;
}
/* data not found in list */
return -1;
}
/*
* Gets an item in a list by position (0 is first element).
*/
struct t_weelist_item *
weelist_get (struct t_weelist *weelist, int position)
{
int i;
struct t_weelist_item *ptr_item;
if (!weelist)
return NULL;
i = 0;
ptr_item = weelist->items;
while (ptr_item)
{
if (i == position)
return ptr_item;
ptr_item = ptr_item->next_item;
i++;
}
/* item not found */
return NULL;
}
/*
* Sets a new value for an item.
*/
void
weelist_set (struct t_weelist_item *item, const char *value)
{
if (!item || !value)
return;
if (item->data)
free (item->data);
item->data = strdup (value);
}
/*
* Gets next item.
*
* Returns NULL if end of list has been reached.
*/
struct t_weelist_item *
weelist_next (struct t_weelist_item *item)
{
if (item)
return item->next_item;
return NULL;
}
/*
* Gets previous item.
*
* Returns NULL if beginning of list has been reached.
*/
struct t_weelist_item *
weelist_prev (struct t_weelist_item *item)
{
if (item)
return item->prev_item;
return NULL;
}
/*
* Gets string pointer to item data.
*/
const char *
weelist_string (struct t_weelist_item *item)
{
if (item)
return item->data;
return NULL;
}
/*
* Gets user data pointer to item data.
*/
void *
weelist_user_data (struct t_weelist_item *item)
{
if (item)
return item->user_data;
return NULL;
}
/*
* Gets size of list.
*/
int
weelist_size (struct t_weelist *weelist)
{
if (weelist)
return weelist->size;
return 0;
}
/*
* Removes an item from a list.
*/
void
weelist_remove (struct t_weelist *weelist, struct t_weelist_item *item)
{
struct t_weelist_item *new_items;
if (!weelist || !item)
return;
/* remove item from list */
if (weelist->last_item == item)
weelist->last_item = item->prev_item;
if (item->prev_item)
{
(item->prev_item)->next_item = item->next_item;
new_items = weelist->items;
}
else
new_items = item->next_item;
if (item->next_item)
(item->next_item)->prev_item = item->prev_item;
/* free data */
if (item->data)
free (item->data);
free (item);
weelist->items = new_items;
weelist->size--;
}
/*
* Removes all items from a list.
*/
void
weelist_remove_all (struct t_weelist *weelist)
{
if (!weelist)
return;
while (weelist->items)
{
weelist_remove (weelist, weelist->items);
}
}
/*
* Frees a list.
*/
void
weelist_free (struct t_weelist *weelist)
{
if (!weelist)
return;
weelist_remove_all (weelist);
free (weelist);
}
/*
* Prints list in WeeChat log file (usually for crash dump).
*/
void
weelist_print_log (struct t_weelist *weelist, const char *name)
{
struct t_weelist_item *ptr_item;
int i;
log_printf ("[weelist %s (addr:0x%lx)]", name, weelist);
log_printf (" items. . . . . . . . . : 0x%lx", weelist->items);
log_printf (" last_item. . . . . . . : 0x%lx", weelist->last_item);
log_printf (" size . . . . . . . . . : %d", weelist->size);
i = 0;
for (ptr_item = weelist->items; ptr_item;
ptr_item = ptr_item->next_item)
{
log_printf (" [item %d (addr:0x%lx)]", i, ptr_item);
log_printf (" data . . . . . . . . : '%s'", ptr_item->data);
log_printf (" user_data. . . . . . : 0x%lx", ptr_item->user_data);
log_printf (" prev_item. . . . . . : 0x%lx", ptr_item->prev_item);
log_printf (" next_item. . . . . . : 0x%lx", ptr_item->next_item);
i++;
}
}