/* * wee-list.c - sorted lists * * Copyright (C) 2003-2019 Sébastien Helleu * * 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 . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #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 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++; } }