/* ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** This program 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 Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ #include "zbxalgo.h" /****************************************************************************** * * * Purpose: create singly linked list (with custom memory functions) * * * * Parameters: list - [IN/OUT] * * mem_malloc_func - [IN] callback for malloc * * mem_free_func - [IN] callback for free * * * ******************************************************************************/ void zbx_list_create_ext(zbx_list_t *list, zbx_mem_malloc_func_t mem_malloc_func, zbx_mem_free_func_t mem_free_func) { memset(list, 0, sizeof(*list)); list->mem_malloc_func = mem_malloc_func; list->mem_free_func = mem_free_func; } /****************************************************************************** * * * Purpose: create singly linked list * * * * Parameters: list - [IN] * * * ******************************************************************************/ void zbx_list_create(zbx_list_t *list) { zbx_list_create_ext(list, ZBX_DEFAULT_MEM_MALLOC_FUNC, ZBX_DEFAULT_MEM_FREE_FUNC); } void zbx_list_destroy(zbx_list_t *list) { while (FAIL != zbx_list_pop(list, NULL)) ; } /****************************************************************************** * * * Purpose: allocate memory and initialize a new list item * * * * Parameters: list - [IN] * * value - [IN] Data to be stored. Ownership of 'value' goes * * to list item. * * created - [OUT] pointer to the created list item * * * ******************************************************************************/ static void list_create_item(zbx_list_t *list, void *value, zbx_list_item_t **created) { zbx_list_item_t *item; if (NULL != (item = (zbx_list_item_t *)list->mem_malloc_func(NULL, sizeof(zbx_list_item_t)))) { item->next = NULL; item->data = value; } *created = item; } /****************************************************************************** * * * Purpose: insert value after specified position in the list * * * * Parameters: list - [IN] * * after - [IN] specified position (can be NULL to insert at * * the end of the list) * * value - [IN] Value to be inserted. Ownership of 'value' * * goes to list item. * * inserted - [OUT] pointer to the inserted list item * * * * Return value: SUCCEED - the item was prepended successfully * * FAIL - memory allocation error * * * ******************************************************************************/ int zbx_list_insert_after(zbx_list_t *list, zbx_list_item_t *after, void *value, zbx_list_item_t **inserted) { zbx_list_item_t *item; list_create_item(list, value, &item); if (NULL == item) return FAIL; if (NULL == after) after = list->tail; if (NULL != after) { item->next = after->next; after->next = item; } else { list->head = item; } if (after == list->tail) list->tail = item; if (NULL != inserted) *inserted = item; return SUCCEED; } /****************************************************************************** * * * Purpose: append value to the end of the list * * * * Parameters: list - [IN] * * value - [IN] Value to append. Ownership of 'value' goes to * * list item. * * inserted - [OUT] pointer to the inserted list item * * * * Return value: SUCCEED - the item was prepended successfully * * FAIL - memory allocation error * * * ******************************************************************************/ int zbx_list_append(zbx_list_t *list, void *value, zbx_list_item_t **inserted) { return zbx_list_insert_after(list, NULL, value, inserted); } /****************************************************************************** * * * Purpose: prepend value to the beginning of the list * * * * Parameters: list - [IN] * * value - [IN] Value to prepend. Ownership of 'value' goes to * * list item. * * inserted - [OUT] pointer to the inserted list item * * * * Return value: SUCCEED - the item was prepended successfully * * FAIL - memory allocation error * * * ******************************************************************************/ int zbx_list_prepend(zbx_list_t *list, void *value, zbx_list_item_t **inserted) { zbx_list_item_t *item; list_create_item(list, value, &item); if (NULL == item) return FAIL; item->next = list->head; list->head = item; if (NULL == list->tail) list->tail = item; if (NULL != inserted) *inserted = item; return SUCCEED; } /****************************************************************************** * * * Purpose: removes a value from the beginning of the list * * * * Parameters: list - [IN] * * value - [IN/OUT] pointer to data removed from list. Ownership * * goes to caller. * * * * Return value: SUCCEED is returned if list is not empty, otherwise, FAIL is * * returned. * * * ******************************************************************************/ int zbx_list_pop(zbx_list_t *list, void **value) { zbx_list_item_t *head; if (NULL == list->head) return FAIL; head = list->head; if (NULL != value) *value = head->data; list->head = list->head->next; list->mem_free_func(head); if (NULL == list->head) list->tail = NULL; return SUCCEED; } /****************************************************************************** * * * Purpose: get value from the list without removing * * * * Parameters: list - [IN] * * value - [OUT] non-owning pointer to data stored in first * * element of list * * * * Return value: SUCCEED is returned if list is not empty, otherwise, FAIL is * * returned. * * * ******************************************************************************/ int zbx_list_peek(const zbx_list_t *list, void **value) { if (NULL != list->head) { *value = list->head->data; return SUCCEED; } return FAIL; } /****************************************************************************** * * * Purpose: initialize list iterator * * * * Parameters: list - [IN] * * iterator - [OUT] iterator to be initialized * * * ******************************************************************************/ void zbx_list_iterator_init(zbx_list_t *list, zbx_list_iterator_t *iterator) { iterator->list = list; iterator->next = list->head; iterator->current = NULL; } /****************************************************************************** * * * Purpose: initialize list iterator starting with the specified item * * * * Parameters: list - [IN] * * next - [IN] item to start with, if NULL the iterator * * will be start with first item * * iterator - [OUT] iterator to be initialized * * * * Return value: SUCCEED - iterator was initialized successfully * * FAIL - list is empty * * * ******************************************************************************/ int zbx_list_iterator_init_with(zbx_list_t *list, zbx_list_item_t *next, zbx_list_iterator_t *iterator) { if (NULL == next) { zbx_list_iterator_init(list, iterator); return zbx_list_iterator_next(iterator); } iterator->list = list; iterator->next = next->next; iterator->current = next; return SUCCEED; } /****************************************************************************** * * * Purpose: advance list iterator * * * * Parameters: iterator - [IN] iterator to be advanced * * * * Return value: SUCCEED is returned if next list item exists, otherwise, * * FAIL is returned. * * * ******************************************************************************/ int zbx_list_iterator_next(zbx_list_iterator_t *iterator) { if (NULL != iterator->next) { iterator->current = iterator->next; iterator->next = iterator->next->next; return SUCCEED; } iterator->current = NULL; return FAIL; } /****************************************************************************** * * * Purpose: get value without removing it from list * * * * Parameters: iterator - [IN] initialized list iterator * * value - [OUT] non-owning pointer to data stored in element * * pointed to by iterator * * * * Return value: SUCCEED is returned if item exists, otherwise, FAIL is * * returned. * * * ******************************************************************************/ int zbx_list_iterator_peek(const zbx_list_iterator_t *iterator, void **value) { if (NULL != iterator->current) { *value = iterator->current->data; return SUCCEED; } return FAIL; } /****************************************************************************** * * * Purpose: clears iterator leaving it in uninitialized state * * * * Parameters: iterator - [IN] list iterator * * * ******************************************************************************/ void zbx_list_iterator_clear(zbx_list_iterator_t *iterator) { memset(iterator, 0, sizeof(zbx_list_iterator_t)); } /****************************************************************************** * * * Purpose: tests if two iterators points at the same list item * * * * Parameters: iterator1 - [IN] first list iterator * * iterator2 - [IN] second list iterator * * * * Return value: SUCCEED is returned if both iterator point at the same item, * * FAIL otherwise. * * * ******************************************************************************/ int zbx_list_iterator_equal(const zbx_list_iterator_t *iterator1, const zbx_list_iterator_t *iterator2) { if (iterator1->list == iterator2->list && iterator1->current == iterator2->current) return SUCCEED; return FAIL; } /****************************************************************************** * * * Purpose: checks if the iterator points at some list item * * * * Parameters: iterator - [IN] list iterator * * * * Return value: SUCCEED is returned if iterator is set, FAIL otherwise. * * * ******************************************************************************/ int zbx_list_iterator_isset(const zbx_list_iterator_t *iterator) { return (NULL == iterator->list ? FAIL : SUCCEED); } /****************************************************************************** * * * Purpose: updates iterator * * * * Parameters: iterator - [IN] list iterator * * * * Comments: This function must be used after an item has been inserted in * * list during iteration process. * * * ******************************************************************************/ void zbx_list_iterator_update(zbx_list_iterator_t *iterator) { if (NULL != iterator->current) iterator->next = iterator->current->next; } /****************************************************************************** * * * Purpose: removes next iterator value from list * * * * Parameters: iterator - [IN] list iterator * * * * Return value: The data held by the removed item. * * * ******************************************************************************/ void *zbx_list_iterator_remove_next(zbx_list_iterator_t *iterator) { zbx_list_item_t *next; void *data; if (NULL == iterator->current || NULL == iterator->next) return NULL; next = iterator->next; data = next->data; if (iterator->list->tail == next) iterator->list->tail = iterator->current; iterator->current->next = next->next; iterator->next = next->next; iterator->list->mem_free_func(next); return data; }