Merge branch 'arraylist'
This commit is contained in:
commit
f53baf628e
@ -1,4 +1,6 @@
|
||||
./doc/docgen.py
|
||||
./src/core/wee-arraylist.c
|
||||
./src/core/wee-arraylist.h
|
||||
./src/core/wee-backtrace.c
|
||||
./src/core/wee-backtrace.h
|
||||
./src/core/weechat.c
|
||||
|
@ -1,5 +1,7 @@
|
||||
SET(WEECHAT_SOURCES
|
||||
./doc/docgen.py
|
||||
./src/core/wee-arraylist.c
|
||||
./src/core/wee-arraylist.h
|
||||
./src/core/wee-backtrace.c
|
||||
./src/core/wee-backtrace.h
|
||||
./src/core/weechat.c
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
set(LIB_CORE_SRC
|
||||
weechat.c weechat.h
|
||||
wee-arraylist.c wee-arraylist.h
|
||||
wee-backtrace.c wee-backtrace.h
|
||||
wee-command.c wee-command.h
|
||||
wee-completion.c wee-completion.h
|
||||
|
@ -23,6 +23,8 @@ noinst_LIBRARIES = lib_weechat_core.a
|
||||
|
||||
lib_weechat_core_a_SOURCES = weechat.c \
|
||||
weechat.h \
|
||||
wee-arraylist.c \
|
||||
wee-arraylist.h \
|
||||
wee-backtrace.c \
|
||||
wee-backtrace.h \
|
||||
wee-command.c \
|
||||
|
632
src/core/wee-arraylist.c
Normal file
632
src/core/wee-arraylist.c
Normal file
@ -0,0 +1,632 @@
|
||||
/*
|
||||
* wee-arraylist.c - array lists management
|
||||
*
|
||||
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "weechat.h"
|
||||
#include "wee-arraylist.h"
|
||||
#include "wee-log.h"
|
||||
#include "wee-string.h"
|
||||
|
||||
|
||||
/*
|
||||
* Creates a new arraylist.
|
||||
*
|
||||
* Returns pointer to arraylist, NULL if error.
|
||||
*/
|
||||
|
||||
struct t_arraylist *
|
||||
arraylist_new (int initial_size,
|
||||
int sorted,
|
||||
int allow_duplicates,
|
||||
t_arraylist_cmp *callback_cmp, void *callback_cmp_data,
|
||||
t_arraylist_free *callback_free, void *callback_free_data)
|
||||
{
|
||||
struct t_arraylist *new_arraylist;
|
||||
|
||||
/* check arguments */
|
||||
if ((initial_size < 0) || !callback_cmp)
|
||||
return NULL;
|
||||
|
||||
new_arraylist = malloc (sizeof (*new_arraylist));
|
||||
if (!new_arraylist)
|
||||
return NULL;
|
||||
|
||||
new_arraylist->size = 0;
|
||||
if (initial_size > 0)
|
||||
{
|
||||
new_arraylist->size_alloc = initial_size;
|
||||
new_arraylist->size_alloc_min = initial_size;
|
||||
new_arraylist->data = calloc (initial_size,
|
||||
sizeof (*new_arraylist->data));
|
||||
if (!new_arraylist->data)
|
||||
{
|
||||
free (new_arraylist);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_arraylist->size_alloc = 0;
|
||||
new_arraylist->size_alloc_min = 0;
|
||||
new_arraylist->data = NULL;
|
||||
}
|
||||
new_arraylist->sorted = sorted;
|
||||
new_arraylist->allow_duplicates = allow_duplicates;
|
||||
new_arraylist->callback_cmp = callback_cmp;
|
||||
new_arraylist->callback_cmp_data = callback_cmp_data;
|
||||
new_arraylist->callback_free = callback_free;
|
||||
new_arraylist->callback_free_data = callback_free_data;
|
||||
|
||||
return new_arraylist;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the size of an arraylist (number of elements).
|
||||
*/
|
||||
|
||||
int
|
||||
arraylist_size (struct t_arraylist *arraylist)
|
||||
{
|
||||
if (!arraylist)
|
||||
return 0;
|
||||
|
||||
return arraylist->size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the pointer to an arraylist element, by index.
|
||||
*/
|
||||
|
||||
void *
|
||||
arraylist_get (struct t_arraylist *arraylist, int index)
|
||||
{
|
||||
if (!arraylist || (index < 0) || (index >= arraylist->size))
|
||||
return NULL;
|
||||
|
||||
return arraylist->data[index];
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjusts the allocated size of arraylist to add one element (if needed),
|
||||
* so that the list has enough allocated data to store (current_size + 1)
|
||||
* elements.
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
arraylist_grow (struct t_arraylist *arraylist)
|
||||
{
|
||||
int new_size_alloc;
|
||||
void **data;
|
||||
|
||||
if (!arraylist)
|
||||
return 0;
|
||||
|
||||
/* if we have enough space allocated, do nothing */
|
||||
if (arraylist->size + 1 <= arraylist->size_alloc)
|
||||
return 1;
|
||||
|
||||
new_size_alloc = (arraylist->size_alloc < 2) ?
|
||||
2 : arraylist->size_alloc + (arraylist->size_alloc / 2);
|
||||
|
||||
data = realloc (arraylist->data,
|
||||
new_size_alloc * sizeof (*arraylist->data));
|
||||
if (!data)
|
||||
return 0;
|
||||
arraylist->data = data;
|
||||
memset (&arraylist->data[arraylist->size_alloc],
|
||||
0,
|
||||
(new_size_alloc - arraylist->size_alloc) *
|
||||
sizeof (*arraylist->data));
|
||||
arraylist->size_alloc = new_size_alloc;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjusts the allocated size of arraylist to remove one element (if needed),
|
||||
* so that the list has enough allocated data to store (current size - 1)
|
||||
* elements.
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
arraylist_shrink (struct t_arraylist *arraylist)
|
||||
{
|
||||
int new_size_alloc;
|
||||
void **data;
|
||||
|
||||
if (!arraylist)
|
||||
return 0;
|
||||
|
||||
/* we don't shrink if we are below the min allocated size */
|
||||
if ((arraylist->size_alloc == 0)
|
||||
|| (arraylist->size_alloc <= arraylist->size_alloc_min))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* clear the arraylist if current allocated size is 1 */
|
||||
if (arraylist->size_alloc == 1)
|
||||
{
|
||||
free (arraylist->data);
|
||||
arraylist->data = NULL;
|
||||
arraylist->size_alloc = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
new_size_alloc = arraylist->size_alloc - (arraylist->size_alloc / 2);
|
||||
|
||||
if (arraylist->size - 1 >= new_size_alloc)
|
||||
return 1;
|
||||
|
||||
data = realloc (arraylist->data,
|
||||
new_size_alloc * sizeof (*arraylist->data));
|
||||
if (!data)
|
||||
return 0;
|
||||
arraylist->data = data;
|
||||
arraylist->size_alloc = new_size_alloc;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a binary search in the arraylist to find an element
|
||||
* (this function must be called only if the arraylist is sorted).
|
||||
*
|
||||
* If "index" is not NULL, it is set with the index of element found (or -1 if
|
||||
* element was not found).
|
||||
*
|
||||
* If "index_insert" is not NULL, it is set with the index that must be used to
|
||||
* insert the element in the arraylist (to keep arraylist sorted).
|
||||
*
|
||||
* Returns pointer to element found, NULL if not found.
|
||||
*/
|
||||
|
||||
void *
|
||||
arraylist_binary_search (struct t_arraylist *arraylist, void *pointer,
|
||||
int *index, int *index_insert)
|
||||
{
|
||||
int ret_index, ret_index_insert, start, end, middle, rc;
|
||||
void *ret_pointer;
|
||||
|
||||
ret_index = -1;
|
||||
ret_index_insert = -1;
|
||||
ret_pointer = NULL;
|
||||
|
||||
if (!arraylist)
|
||||
goto end;
|
||||
|
||||
start = 0;
|
||||
end = arraylist->size - 1;
|
||||
|
||||
/*
|
||||
* statistically we often add at the end, or before first element, so
|
||||
* first check these cases (for performance), before doing the binary
|
||||
* search
|
||||
*/
|
||||
rc = (arraylist->callback_cmp) (arraylist->callback_cmp_data,
|
||||
arraylist,
|
||||
pointer,
|
||||
arraylist->data[end]);
|
||||
if (rc == 0)
|
||||
{
|
||||
ret_index = end;
|
||||
/* by convention, add an element with same value after the last one */
|
||||
ret_index_insert = -1;
|
||||
ret_pointer = arraylist->data[end];
|
||||
goto end;
|
||||
}
|
||||
if (rc > 0)
|
||||
{
|
||||
ret_index = -1;
|
||||
ret_index_insert = -1;
|
||||
ret_pointer = NULL;
|
||||
goto end;
|
||||
}
|
||||
if (arraylist->size == 1)
|
||||
{
|
||||
ret_index = -1;
|
||||
ret_index_insert = 0;
|
||||
ret_pointer = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = (arraylist->callback_cmp) (arraylist->callback_cmp_data,
|
||||
arraylist,
|
||||
pointer,
|
||||
arraylist->data[start]);
|
||||
if (rc == 0)
|
||||
{
|
||||
ret_index = start;
|
||||
ret_index_insert = start;
|
||||
ret_pointer = arraylist->data[start];
|
||||
goto end;
|
||||
}
|
||||
if (rc < 0)
|
||||
{
|
||||
ret_index = -1;
|
||||
ret_index_insert = start;
|
||||
ret_pointer = NULL;
|
||||
goto end;
|
||||
}
|
||||
if (arraylist->size == 2)
|
||||
{
|
||||
ret_index = -1;
|
||||
ret_index_insert = end;
|
||||
ret_pointer = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
start++;
|
||||
end--;
|
||||
|
||||
/* perform a binary search to find the index */
|
||||
while (start <= end)
|
||||
{
|
||||
middle = (start + end) / 2;
|
||||
|
||||
rc = (arraylist->callback_cmp) (arraylist->callback_cmp_data,
|
||||
arraylist,
|
||||
pointer,
|
||||
arraylist->data[middle]);
|
||||
if (rc == 0)
|
||||
{
|
||||
ret_index = middle;
|
||||
ret_index_insert = middle;
|
||||
ret_pointer = arraylist->data[middle];
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
end = middle - 1;
|
||||
else
|
||||
start = middle + 1;
|
||||
|
||||
if (start > end)
|
||||
{
|
||||
ret_index = -1;
|
||||
ret_index_insert = (rc < 0) ? middle : middle + 1;
|
||||
ret_pointer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (index)
|
||||
*index = ret_index;
|
||||
if (index_insert)
|
||||
*index_insert = ret_index_insert;
|
||||
return ret_pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a standard search in the arraylist to find an element
|
||||
* (this function must be called only if the arraylist is NOT sorted).
|
||||
*
|
||||
* If "index" is not NULL, it is set with the index of element found (or -1 if
|
||||
* element was not found).
|
||||
*
|
||||
* If "index_insert" is not NULL, it is set to -1 (elements are always added
|
||||
* at the end of list when it is not sorted).
|
||||
*
|
||||
* Returns pointer to element found, NULL if not found.
|
||||
*/
|
||||
|
||||
void *
|
||||
arraylist_standard_search (struct t_arraylist *arraylist, void *pointer,
|
||||
int *index, int *index_insert)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!arraylist)
|
||||
goto end;
|
||||
|
||||
for (i = 0; i < arraylist->size; i++)
|
||||
{
|
||||
if ((arraylist->callback_cmp) (arraylist->callback_cmp_data,
|
||||
arraylist, arraylist->data[i],
|
||||
pointer) == 0)
|
||||
{
|
||||
if (index)
|
||||
*index = i;
|
||||
if (index_insert)
|
||||
*index_insert = -1;
|
||||
return arraylist->data[i];
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (index)
|
||||
*index = -1;
|
||||
if (index_insert)
|
||||
*index_insert = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Searches an element in the arraylist.
|
||||
*
|
||||
* If "index" is not NULL, it is set with the index of element found (or -1 if
|
||||
* element was not found).
|
||||
*
|
||||
* If "index_insert" is not NULL, it is set with the index that must be used to
|
||||
* insert the element in the arraylist (to keep arraylist sorted).
|
||||
*
|
||||
* Returns pointer to element found, NULL if not found.
|
||||
*/
|
||||
|
||||
void *
|
||||
arraylist_search (struct t_arraylist *arraylist, void *pointer,
|
||||
int *index, int *index_insert)
|
||||
{
|
||||
if (index)
|
||||
*index = -1;
|
||||
if (index_insert)
|
||||
*index_insert = -1;
|
||||
|
||||
if (!arraylist || (arraylist->size == 0))
|
||||
return NULL;
|
||||
|
||||
if (arraylist->sorted)
|
||||
{
|
||||
return arraylist_binary_search (arraylist, pointer,
|
||||
index, index_insert);
|
||||
}
|
||||
else
|
||||
{
|
||||
return arraylist_standard_search (arraylist, pointer,
|
||||
index, index_insert);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Inserts an element at a given index (and shifts next elements by one
|
||||
* position), or at automatic index if the arraylist is sorted.
|
||||
*
|
||||
* If the index is negative and that the arraylist is not sorted, the element
|
||||
* is added at the end of arraylist.
|
||||
*
|
||||
* If the arraylist is sorted, the argument "index" is ignored (the element
|
||||
* will be inserted at appropriate position, to keep arraylist sorted).
|
||||
*
|
||||
* Returns the index of the new element (>= 0) or -1 if error.
|
||||
*/
|
||||
|
||||
int
|
||||
arraylist_insert (struct t_arraylist *arraylist, int index, void *pointer)
|
||||
{
|
||||
int index_insert, i;
|
||||
|
||||
if (!arraylist)
|
||||
return -1;
|
||||
|
||||
if (arraylist->sorted)
|
||||
{
|
||||
(void) arraylist_search (arraylist, pointer, &index, &index_insert);
|
||||
if ((index >= 0) && !arraylist->allow_duplicates)
|
||||
{
|
||||
while ((index < arraylist->size)
|
||||
&& (((arraylist->callback_cmp) (arraylist->callback_cmp_data,
|
||||
arraylist, arraylist->data[index],
|
||||
pointer)) == 0))
|
||||
{
|
||||
if (arraylist->callback_free)
|
||||
{
|
||||
(arraylist->callback_free) (arraylist->callback_free_data,
|
||||
arraylist,
|
||||
arraylist->data[index]);
|
||||
}
|
||||
arraylist_remove (arraylist, index);
|
||||
}
|
||||
}
|
||||
else
|
||||
index = index_insert;
|
||||
}
|
||||
else if (!arraylist->allow_duplicates)
|
||||
{
|
||||
/*
|
||||
* arraylist is not sorted and does not allow duplicates, then we
|
||||
* remove any element with the same value
|
||||
*/
|
||||
i = 0;
|
||||
while (i < arraylist->size)
|
||||
{
|
||||
if ((arraylist->callback_cmp) (arraylist->callback_cmp_data,
|
||||
arraylist, arraylist->data[i],
|
||||
pointer) == 0)
|
||||
{
|
||||
if (arraylist->callback_free)
|
||||
{
|
||||
(arraylist->callback_free) (arraylist->callback_free_data,
|
||||
arraylist,
|
||||
arraylist->data[i]);
|
||||
}
|
||||
arraylist_remove (arraylist, i);
|
||||
}
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* if index is negative or too big, add at the end */
|
||||
if ((index < 0) || (index > arraylist->size))
|
||||
index = arraylist->size;
|
||||
|
||||
if (!arraylist_grow (arraylist))
|
||||
return -1;
|
||||
|
||||
/* shift next elements by one position */
|
||||
if (index < arraylist->size)
|
||||
{
|
||||
memmove (&arraylist->data[index + 1],
|
||||
&arraylist->data[index],
|
||||
(arraylist->size - index) * sizeof (*arraylist->data));
|
||||
}
|
||||
|
||||
/* set element */
|
||||
arraylist->data[index] = pointer;
|
||||
|
||||
(arraylist->size)++;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds an element at the end of arraylist (or in the middle if the arraylist
|
||||
* is sorted).
|
||||
*
|
||||
* Returns the index of the new element (>= 0) or -1 if error.
|
||||
*/
|
||||
|
||||
int
|
||||
arraylist_add (struct t_arraylist *arraylist, void *pointer)
|
||||
{
|
||||
if (!arraylist)
|
||||
return -1;
|
||||
|
||||
return arraylist_insert (arraylist, -1, pointer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes one element from the arraylist.
|
||||
*
|
||||
* Returns the index removed or -1 if error.
|
||||
*/
|
||||
|
||||
int
|
||||
arraylist_remove (struct t_arraylist *arraylist, int index)
|
||||
{
|
||||
if (!arraylist || (index < 0) || (index >= arraylist->size))
|
||||
return -1;
|
||||
|
||||
if (index < arraylist->size - 1)
|
||||
{
|
||||
memmove (&arraylist->data[index],
|
||||
&arraylist->data[index + 1],
|
||||
(arraylist->size - index - 1) * sizeof (*arraylist->data));
|
||||
memset (&arraylist->data[arraylist->size - 1], 0,
|
||||
sizeof (*arraylist->data));
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (&arraylist->data[index], 0, sizeof (*arraylist->data));
|
||||
}
|
||||
|
||||
arraylist_shrink (arraylist);
|
||||
|
||||
(arraylist->size)--;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes all elements in the arraylist.
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
arraylist_clear (struct t_arraylist *arraylist)
|
||||
{
|
||||
if (!arraylist)
|
||||
return 0;
|
||||
|
||||
if (arraylist->data
|
||||
&& (arraylist->size_alloc != arraylist->size_alloc_min))
|
||||
{
|
||||
free (arraylist->data);
|
||||
arraylist->data = NULL;
|
||||
arraylist->size_alloc = 0;
|
||||
if (arraylist->size_alloc_min > 0)
|
||||
{
|
||||
arraylist->data = calloc(arraylist->size_alloc_min,
|
||||
sizeof (*arraylist->data));
|
||||
if (!arraylist->data)
|
||||
return 0;
|
||||
arraylist->size_alloc = arraylist->size_alloc_min;
|
||||
}
|
||||
}
|
||||
|
||||
arraylist->size = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees an arraylist.
|
||||
*/
|
||||
|
||||
void
|
||||
arraylist_free (struct t_arraylist *arraylist)
|
||||
{
|
||||
if (!arraylist)
|
||||
return;
|
||||
|
||||
if (arraylist->data)
|
||||
free (arraylist->data);
|
||||
|
||||
free (arraylist);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints an arraylist in WeeChat log file (usually for crash dump).
|
||||
*/
|
||||
|
||||
void
|
||||
arraylist_print_log (struct t_arraylist *arraylist, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
log_printf ("");
|
||||
log_printf ("[arraylist %s (addr:0x%lx)]", name, arraylist);
|
||||
log_printf (" size . . . . . . . . . : %d", arraylist->size);
|
||||
log_printf (" size_alloc . . . . . . : %d", arraylist->size_alloc);
|
||||
log_printf (" size_alloc_min . . . . : %d", arraylist->size_alloc_min);
|
||||
log_printf (" sorted . . . . . . . . : %d", arraylist->sorted);
|
||||
log_printf (" allow_duplicates . . . : %d", arraylist->allow_duplicates);
|
||||
log_printf (" data . . . . . . . . . : 0x%lx", arraylist->data);
|
||||
if (arraylist->data)
|
||||
{
|
||||
for (i = 0; i < arraylist->size_alloc; i++)
|
||||
{
|
||||
log_printf (" data[%08d] . . . : 0x%lx",
|
||||
i, arraylist->data[i]);
|
||||
}
|
||||
}
|
||||
log_printf (" callback_cmp . . . . . : 0x%lx", arraylist->callback_cmp);
|
||||
log_printf (" callback_cmp_data. . . : 0x%lx", arraylist->callback_cmp_data);
|
||||
log_printf (" callback_free. . . . . : 0x%lx", arraylist->callback_free);
|
||||
log_printf (" callback_free_data . . : 0x%lx", arraylist->callback_free_data);
|
||||
}
|
64
src/core/wee-arraylist.h
Normal file
64
src/core/wee-arraylist.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WEECHAT_ARRAYLIST_H
|
||||
#define WEECHAT_ARRAYLIST_H 1
|
||||
|
||||
struct t_arraylist;
|
||||
|
||||
typedef int (t_arraylist_cmp)(void *data, struct t_arraylist *arraylist,
|
||||
void *pointer1, void *pointer2);
|
||||
typedef void (t_arraylist_free)(void *data, struct t_arraylist *arraylist,
|
||||
void *pointer);
|
||||
|
||||
struct t_arraylist
|
||||
{
|
||||
int size; /* number of items in data */
|
||||
int size_alloc; /* number of allocated items */
|
||||
int size_alloc_min; /* min number of allocated items */
|
||||
int sorted; /* 1 if the arraylist is sorted */
|
||||
int allow_duplicates; /* 1 if duplicates are allowed */
|
||||
void **data; /* pointers to data */
|
||||
t_arraylist_cmp *callback_cmp; /* compare two elements */
|
||||
void *callback_cmp_data; /* data for compare callback */
|
||||
t_arraylist_free *callback_free; /* free an element */
|
||||
void *callback_free_data; /* data for free callback */
|
||||
};
|
||||
|
||||
extern struct t_arraylist *arraylist_new (int initial_size,
|
||||
int sorted,
|
||||
int allow_duplicates,
|
||||
t_arraylist_cmp *callback_cmp,
|
||||
void *callback_cmp_data,
|
||||
t_arraylist_free *callback_free,
|
||||
void *callback_free_data);
|
||||
extern int arraylist_size (struct t_arraylist *arraylist);
|
||||
extern void *arraylist_get (struct t_arraylist *arraylist, int index);
|
||||
extern void *arraylist_search (struct t_arraylist *arraylist, void *pointer,
|
||||
int *index, int *index_insert);
|
||||
extern int arraylist_insert (struct t_arraylist *arraylist, int index,
|
||||
void *pointer);
|
||||
extern int arraylist_add (struct t_arraylist *arraylist, void *pointer);
|
||||
extern int arraylist_remove (struct t_arraylist *arraylist, int index);
|
||||
extern int arraylist_clear (struct t_arraylist *arraylist);
|
||||
extern void arraylist_free (struct t_arraylist *arraylist);
|
||||
extern void arraylist_print_log (struct t_arraylist *arraylist,
|
||||
const char *name);
|
||||
|
||||
#endif /* WEECHAT_ARRAYLIST_H */
|
@ -34,6 +34,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "weechat.h"
|
||||
#include "wee-arraylist.h"
|
||||
#include "wee-config.h"
|
||||
#include "wee-hashtable.h"
|
||||
#include "wee-hook.h"
|
||||
@ -625,12 +626,12 @@ completion_list_add_nicks_cb (void *data,
|
||||
(void) completion_item;
|
||||
(void) buffer;
|
||||
|
||||
count_before = weelist_size (completion->completion_list);
|
||||
count_before = completion->list->size;
|
||||
hook_completion_exec (completion->buffer->plugin,
|
||||
"nick",
|
||||
completion->buffer,
|
||||
completion);
|
||||
if (weelist_size (completion->completion_list) == count_before)
|
||||
if (completion->list->size == count_before)
|
||||
{
|
||||
/*
|
||||
* no plugin overrides nick completion => use default nick
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "../core/weechat.h"
|
||||
#include "../core/wee-arraylist.h"
|
||||
#include "../core/wee-config.h"
|
||||
#include "../core/wee-hashtable.h"
|
||||
#include "../core/wee-hdata.h"
|
||||
@ -1484,9 +1485,9 @@ gui_bar_item_default_completion (void *data, struct t_gui_bar_item *item,
|
||||
struct t_gui_buffer *buffer,
|
||||
struct t_hashtable *extra_info)
|
||||
{
|
||||
int length;
|
||||
int length, i;
|
||||
char *buf, str_number[64];
|
||||
struct t_gui_completion_partial *ptr_item;
|
||||
struct t_gui_completion_word *ptr_completion_word;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) data;
|
||||
@ -1495,37 +1496,39 @@ gui_bar_item_default_completion (void *data, struct t_gui_bar_item *item,
|
||||
(void) extra_info;
|
||||
|
||||
if (!buffer || !buffer->completion
|
||||
|| !buffer->completion->partial_completion_list)
|
||||
|| (buffer->completion->partial_list->size == 0))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
length = 1;
|
||||
for (ptr_item = buffer->completion->partial_completion_list;
|
||||
ptr_item; ptr_item = ptr_item->next_item)
|
||||
for (i = 0; i < buffer->completion->partial_list->size; i++)
|
||||
{
|
||||
length += strlen (ptr_item->word) + 32;
|
||||
ptr_completion_word =
|
||||
(struct t_gui_completion_word *)(buffer->completion->partial_list->data[i]);
|
||||
length += strlen (ptr_completion_word->word) + 32;
|
||||
}
|
||||
|
||||
buf = malloc (length);
|
||||
if (buf)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
for (ptr_item = buffer->completion->partial_completion_list;
|
||||
ptr_item; ptr_item = ptr_item->next_item)
|
||||
for (i = 0; i < buffer->completion->partial_list->size; i++)
|
||||
{
|
||||
ptr_completion_word =
|
||||
(struct t_gui_completion_word *)(buffer->completion->partial_list->data[i]);
|
||||
strcat (buf, GUI_COLOR_CUSTOM_BAR_FG);
|
||||
strcat (buf, ptr_item->word);
|
||||
if (ptr_item->count > 0)
|
||||
strcat (buf, ptr_completion_word->word);
|
||||
if (ptr_completion_word->count > 0)
|
||||
{
|
||||
strcat (buf, GUI_COLOR_CUSTOM_BAR_DELIM);
|
||||
strcat (buf, "(");
|
||||
snprintf (str_number, sizeof (str_number),
|
||||
"%d", ptr_item->count);
|
||||
"%d", ptr_completion_word->count);
|
||||
strcat (buf, str_number);
|
||||
strcat (buf, ")");
|
||||
}
|
||||
if (ptr_item->next_item)
|
||||
if (i < buffer->completion->partial_list->size - 1)
|
||||
strcat (buf, " ");
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../core/weechat.h"
|
||||
#include "../core/wee-arraylist.h"
|
||||
#include "../core/wee-completion.h"
|
||||
#include "../core/wee-config.h"
|
||||
#include "../core/wee-hdata.h"
|
||||
@ -50,6 +51,48 @@ int gui_completion_freeze = 0; /* 1 to freeze completions (do not */
|
||||
/* stop partial completion on key) */
|
||||
|
||||
|
||||
/*
|
||||
* Compares two words in completion list.
|
||||
*/
|
||||
|
||||
int
|
||||
gui_completion_word_compare_cb (void *data, struct t_arraylist *arraylist,
|
||||
void *pointer1, void *pointer2)
|
||||
{
|
||||
struct t_gui_completion_word *completion_word1, *completion_word2;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) data;
|
||||
(void) arraylist;
|
||||
|
||||
completion_word1 = (struct t_gui_completion_word *)pointer1;
|
||||
completion_word2 = (struct t_gui_completion_word *)pointer2;
|
||||
|
||||
return string_strcasecmp (completion_word1->word, completion_word2->word);
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees a word in completion list.
|
||||
*/
|
||||
|
||||
void
|
||||
gui_completion_word_free_cb (void *data, struct t_arraylist *arraylist,
|
||||
void *pointer)
|
||||
{
|
||||
struct t_gui_completion_word *completion_word;
|
||||
|
||||
/* make C compiler happy */
|
||||
(void) data;
|
||||
(void) arraylist;
|
||||
|
||||
completion_word = (struct t_gui_completion_word *)pointer;
|
||||
|
||||
if (completion_word->word)
|
||||
free (completion_word->word);
|
||||
|
||||
free (completion_word);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes completion for a buffer.
|
||||
*/
|
||||
@ -70,7 +113,9 @@ gui_completion_buffer_init (struct t_gui_completion *completion,
|
||||
completion->add_space = 1;
|
||||
completion->force_partial_completion = 0;
|
||||
|
||||
completion->completion_list = weelist_new ();
|
||||
completion->list = arraylist_new (32, 1, 0,
|
||||
&gui_completion_word_compare_cb, NULL,
|
||||
&gui_completion_word_free_cb, NULL);
|
||||
|
||||
completion->word_found = NULL;
|
||||
completion->word_found_is_nick = 0;
|
||||
@ -78,8 +123,10 @@ gui_completion_buffer_init (struct t_gui_completion *completion,
|
||||
completion->diff_size = 0;
|
||||
completion->diff_length = 0;
|
||||
|
||||
completion->partial_completion_list = NULL;
|
||||
completion->last_partial_completion = NULL;
|
||||
completion->partial_list = arraylist_new (
|
||||
0, 0, 0,
|
||||
&gui_completion_word_compare_cb, NULL,
|
||||
&gui_completion_word_free_cb, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -88,66 +135,23 @@ gui_completion_buffer_init (struct t_gui_completion *completion,
|
||||
* Returns pointer to new item, NULL if error.
|
||||
*/
|
||||
|
||||
struct t_gui_completion_partial *
|
||||
struct t_gui_completion_word *
|
||||
gui_completion_partial_list_add (struct t_gui_completion *completion,
|
||||
const char *word, int count)
|
||||
{
|
||||
struct t_gui_completion_partial *new_item;
|
||||
struct t_gui_completion_word *new_completion_word;
|
||||
|
||||
new_item = malloc (sizeof (*new_item));
|
||||
if (new_item)
|
||||
new_completion_word = malloc (sizeof (*new_completion_word));
|
||||
if (new_completion_word)
|
||||
{
|
||||
new_item->word = strdup (word);
|
||||
new_item->count = count;
|
||||
new_completion_word->word = strdup (word);
|
||||
new_completion_word->nick_completion = 0;
|
||||
new_completion_word->count = count;
|
||||
|
||||
new_item->prev_item = completion->last_partial_completion;
|
||||
if (completion->partial_completion_list)
|
||||
(completion->last_partial_completion)->next_item = new_item;
|
||||
else
|
||||
completion->partial_completion_list = new_item;
|
||||
completion->last_partial_completion = new_item;
|
||||
new_item->next_item = NULL;
|
||||
arraylist_add (completion->partial_list, new_completion_word);
|
||||
}
|
||||
return new_item;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes an item from partial completion list.
|
||||
*/
|
||||
|
||||
void
|
||||
gui_completion_partial_list_free (struct t_gui_completion *completion,
|
||||
struct t_gui_completion_partial *item)
|
||||
{
|
||||
/* remove partial completion item from list */
|
||||
if (item->prev_item)
|
||||
(item->prev_item)->next_item = item->next_item;
|
||||
if (item->next_item)
|
||||
(item->next_item)->prev_item = item->prev_item;
|
||||
if (completion->partial_completion_list == item)
|
||||
completion->partial_completion_list = item->next_item;
|
||||
if (completion->last_partial_completion == item)
|
||||
completion->last_partial_completion = item->prev_item;
|
||||
|
||||
/* free data */
|
||||
if (item->word)
|
||||
free (item->word);
|
||||
|
||||
free (item);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes partial completion list.
|
||||
*/
|
||||
|
||||
void
|
||||
gui_completion_partial_list_free_all (struct t_gui_completion *completion)
|
||||
{
|
||||
while (completion->partial_completion_list)
|
||||
{
|
||||
gui_completion_partial_list_free (completion,
|
||||
completion->partial_completion_list);
|
||||
}
|
||||
return new_completion_word;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -169,17 +173,17 @@ gui_completion_free_data (struct t_gui_completion *completion)
|
||||
free (completion->args);
|
||||
completion->args = NULL;
|
||||
|
||||
if (completion->completion_list)
|
||||
if (completion->list)
|
||||
{
|
||||
weelist_free (completion->completion_list);
|
||||
completion->completion_list = NULL;
|
||||
arraylist_free (completion->list);
|
||||
completion->list = NULL;
|
||||
}
|
||||
|
||||
if (completion->word_found)
|
||||
free (completion->word_found);
|
||||
completion->word_found = NULL;
|
||||
|
||||
gui_completion_partial_list_free_all (completion);
|
||||
arraylist_clear (completion->partial_list);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -206,9 +210,9 @@ gui_completion_stop (struct t_gui_completion *completion)
|
||||
completion->context = GUI_COMPLETION_NULL;
|
||||
completion->position = -1;
|
||||
|
||||
if (completion->partial_completion_list)
|
||||
if (completion->partial_list->size > 0)
|
||||
{
|
||||
gui_completion_partial_list_free_all (completion);
|
||||
arraylist_clear (completion->partial_list);
|
||||
(void) hook_signal_send ("partial_completion",
|
||||
WEECHAT_HOOK_SIGNAL_STRING, NULL);
|
||||
}
|
||||
@ -369,7 +373,9 @@ void
|
||||
gui_completion_list_add (struct t_gui_completion *completion, const char *word,
|
||||
int nick_completion, const char *where)
|
||||
{
|
||||
struct t_gui_completion_word *completion_word;
|
||||
char buffer[512];
|
||||
int index;
|
||||
|
||||
if (!word || !word[0])
|
||||
return;
|
||||
@ -380,17 +386,37 @@ gui_completion_list_add (struct t_gui_completion *completion, const char *word,
|
||||
|| (!nick_completion && (string_strncasecmp (completion->base_word, word,
|
||||
utf8_strlen (completion->base_word)) == 0)))
|
||||
{
|
||||
if (nick_completion && (completion->base_word_pos == 0))
|
||||
completion_word = malloc (sizeof (*completion_word));
|
||||
if (completion_word)
|
||||
{
|
||||
snprintf (buffer, sizeof (buffer), "%s%s",
|
||||
word, CONFIG_STRING(config_completion_nick_completer));
|
||||
weelist_add (completion->completion_list, buffer, where,
|
||||
(nick_completion) ? (void *)1 : (void *)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
weelist_add (completion->completion_list, word, where,
|
||||
(nick_completion) ? (void *)1 : (void *)0);
|
||||
completion_word->nick_completion = nick_completion;
|
||||
completion_word->count = 0;
|
||||
|
||||
index = -1;
|
||||
if (strcmp (where, WEECHAT_LIST_POS_BEGINNING) == 0)
|
||||
{
|
||||
completion->list->sorted = 0;
|
||||
index = 0;
|
||||
}
|
||||
else if (strcmp (where, WEECHAT_LIST_POS_END) == 0)
|
||||
{
|
||||
completion->list->sorted = 0;
|
||||
index = -1;
|
||||
}
|
||||
|
||||
if (nick_completion && (completion->base_word_pos == 0))
|
||||
{
|
||||
snprintf (buffer, sizeof (buffer), "%s%s",
|
||||
word,
|
||||
CONFIG_STRING(config_completion_nick_completer));
|
||||
completion_word->word = strdup (buffer);
|
||||
arraylist_insert (completion->list, index, completion_word);
|
||||
}
|
||||
else
|
||||
{
|
||||
completion_word->word = strdup (word);
|
||||
arraylist_insert (completion->list, index, completion_word);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -842,28 +868,32 @@ gui_completion_find_context (struct t_gui_completion *completion,
|
||||
*/
|
||||
|
||||
int
|
||||
gui_completion_common_prefix_size (struct t_weelist *list,
|
||||
gui_completion_common_prefix_size (struct t_arraylist *list,
|
||||
const char *utf_char)
|
||||
{
|
||||
struct t_weelist_item *ptr_item;
|
||||
char *ptr_first_item, *ptr_char, *next_char;
|
||||
struct t_gui_completion_word *ptr_completion_word;
|
||||
int i;
|
||||
|
||||
ptr_first_item = list->items->data;
|
||||
ptr_first_item = ((struct t_gui_completion_word *)(list->data[0]))->word;
|
||||
ptr_char = ptr_first_item;
|
||||
|
||||
while (ptr_char && ptr_char[0])
|
||||
{
|
||||
next_char = utf8_next_char (ptr_char);
|
||||
|
||||
for (ptr_item = list->items->next_item; ptr_item;
|
||||
ptr_item = ptr_item->next_item)
|
||||
for (i = 1; i < list->size; i++)
|
||||
{
|
||||
ptr_completion_word =
|
||||
(struct t_gui_completion_word *)(list->data[i]);
|
||||
if (!utf_char
|
||||
|| (utf8_charcasecmp (utf_char, ptr_item->data) == 0))
|
||||
|| (utf8_charcasecmp (utf_char,
|
||||
ptr_completion_word->word) == 0))
|
||||
{
|
||||
if ((ptr_item->data[ptr_char - ptr_first_item] == '\0')
|
||||
|| (utf8_charcasecmp (ptr_char,
|
||||
ptr_item->data + (ptr_char - ptr_first_item)) != 0))
|
||||
if ((ptr_completion_word->word[ptr_char - ptr_first_item] == '\0')
|
||||
|| (utf8_charcasecmp (
|
||||
ptr_char,
|
||||
ptr_completion_word->word + (ptr_char - ptr_first_item)) != 0))
|
||||
{
|
||||
return ptr_char - ptr_first_item;
|
||||
}
|
||||
@ -883,65 +913,78 @@ void
|
||||
gui_completion_partial_build_list (struct t_gui_completion *completion,
|
||||
int common_prefix_size)
|
||||
{
|
||||
int char_size, items_count;
|
||||
int i, char_size, items_count, index;
|
||||
char utf_char[16], *word;
|
||||
struct t_weelist *weelist_temp;
|
||||
struct t_weelist_item *ptr_item, *next_item;
|
||||
struct t_gui_completion_word *ptr_completion_word, *new_completion_word;
|
||||
struct t_arraylist *list_temp;
|
||||
|
||||
gui_completion_partial_list_free_all (completion);
|
||||
arraylist_clear (completion->partial_list);
|
||||
|
||||
if (!completion->completion_list || !completion->completion_list->items)
|
||||
if (!completion->list || (completion->list->size == 0))
|
||||
return;
|
||||
|
||||
weelist_temp = weelist_new ();
|
||||
if (!weelist_temp)
|
||||
list_temp = arraylist_new (completion->list->size, 1, 0,
|
||||
&gui_completion_word_compare_cb, NULL,
|
||||
&gui_completion_word_free_cb, NULL);
|
||||
if (!list_temp)
|
||||
return;
|
||||
|
||||
for (ptr_item = completion->completion_list->items; ptr_item;
|
||||
ptr_item = ptr_item->next_item)
|
||||
for (i = 0; i < completion->list->size; i++)
|
||||
{
|
||||
weelist_add (weelist_temp, ptr_item->data + common_prefix_size,
|
||||
WEECHAT_LIST_POS_END, NULL);
|
||||
ptr_completion_word =
|
||||
(struct t_gui_completion_word *)completion->list->data[i];
|
||||
new_completion_word = malloc (sizeof (*new_completion_word));
|
||||
if (new_completion_word)
|
||||
{
|
||||
new_completion_word->word = strdup (
|
||||
ptr_completion_word->word + common_prefix_size);
|
||||
new_completion_word->nick_completion = 0;
|
||||
new_completion_word->count = 0;
|
||||
arraylist_add (list_temp, new_completion_word);
|
||||
}
|
||||
}
|
||||
|
||||
while (weelist_temp->items)
|
||||
while (list_temp->size > 0)
|
||||
{
|
||||
char_size = utf8_char_size (weelist_temp->items->data);
|
||||
memcpy (utf_char, weelist_temp->items->data, char_size);
|
||||
ptr_completion_word =
|
||||
(struct t_gui_completion_word *)list_temp->data[0];
|
||||
char_size = utf8_char_size (ptr_completion_word->word);
|
||||
memcpy (utf_char, ptr_completion_word->word, char_size);
|
||||
utf_char[char_size] = '\0';
|
||||
word = NULL;
|
||||
common_prefix_size = gui_completion_common_prefix_size (weelist_temp,
|
||||
common_prefix_size = gui_completion_common_prefix_size (list_temp,
|
||||
utf_char);
|
||||
if (common_prefix_size > 0)
|
||||
{
|
||||
word = string_strndup (weelist_temp->items->data,
|
||||
word = string_strndup (ptr_completion_word->word,
|
||||
common_prefix_size);
|
||||
}
|
||||
items_count = 0;
|
||||
ptr_item = weelist_temp->items;
|
||||
while (ptr_item)
|
||||
index = 0;
|
||||
while (index < list_temp->size)
|
||||
{
|
||||
next_item = ptr_item->next_item;
|
||||
|
||||
if (utf8_charcasecmp (utf_char, ptr_item->data) == 0)
|
||||
ptr_completion_word =
|
||||
(struct t_gui_completion_word *)list_temp->data[index];
|
||||
if (utf8_charcasecmp (utf_char, ptr_completion_word->word) == 0)
|
||||
{
|
||||
weelist_remove (weelist_temp, ptr_item);
|
||||
arraylist_remove (list_temp, index);
|
||||
items_count++;
|
||||
}
|
||||
|
||||
ptr_item = next_item;
|
||||
else
|
||||
index++;
|
||||
}
|
||||
if (word)
|
||||
{
|
||||
gui_completion_partial_list_add (completion,
|
||||
word,
|
||||
CONFIG_BOOLEAN(config_completion_partial_completion_count) ?
|
||||
items_count : -1);
|
||||
gui_completion_partial_list_add (
|
||||
completion,
|
||||
word,
|
||||
CONFIG_BOOLEAN(config_completion_partial_completion_count) ?
|
||||
items_count : -1);
|
||||
free (word);
|
||||
}
|
||||
}
|
||||
|
||||
weelist_free (weelist_temp);
|
||||
arraylist_free (list_temp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -952,8 +995,8 @@ void
|
||||
gui_completion_complete (struct t_gui_completion *completion)
|
||||
{
|
||||
int length, word_found_seen, other_completion, partial_completion;
|
||||
int common_prefix_size, item_is_nick;
|
||||
struct t_weelist_item *ptr_item, *ptr_item2;
|
||||
int common_prefix_size, index, index2;
|
||||
struct t_gui_completion_word *ptr_completion_word, *ptr_completion_word2;
|
||||
|
||||
length = utf8_strlen (completion->base_word);
|
||||
word_found_seen = 0;
|
||||
@ -977,21 +1020,12 @@ gui_completion_complete (struct t_gui_completion *completion)
|
||||
|
||||
common_prefix_size = 0;
|
||||
if (partial_completion
|
||||
&& completion->completion_list && completion->completion_list->items)
|
||||
&& completion->list && (completion->list->size > 0))
|
||||
{
|
||||
common_prefix_size = gui_completion_common_prefix_size (completion->completion_list,
|
||||
common_prefix_size = gui_completion_common_prefix_size (completion->list,
|
||||
NULL);
|
||||
}
|
||||
|
||||
ptr_item = NULL;
|
||||
if (completion->completion_list)
|
||||
{
|
||||
if (completion->direction < 0)
|
||||
ptr_item = completion->completion_list->last_item;
|
||||
else
|
||||
ptr_item = completion->completion_list->items;
|
||||
}
|
||||
|
||||
if (partial_completion
|
||||
&& completion->word_found
|
||||
&& (utf8_strlen (completion->word_found) >= common_prefix_size))
|
||||
@ -999,59 +1033,68 @@ gui_completion_complete (struct t_gui_completion *completion)
|
||||
return;
|
||||
}
|
||||
|
||||
while (ptr_item)
|
||||
index = -1;
|
||||
if (completion->list)
|
||||
{
|
||||
item_is_nick = ((long)(ptr_item->user_data) == 1);
|
||||
if ((item_is_nick
|
||||
&& (gui_completion_nickncmp (completion->base_word, ptr_item->data,
|
||||
if (completion->direction < 0)
|
||||
index = completion->list->size - 1;
|
||||
else
|
||||
index = 0;
|
||||
}
|
||||
|
||||
while ((index >= 0) && (index < completion->list->size))
|
||||
{
|
||||
ptr_completion_word =
|
||||
(struct t_gui_completion_word *)(completion->list->data[index]);
|
||||
if ((ptr_completion_word->nick_completion
|
||||
&& (gui_completion_nickncmp (completion->base_word,
|
||||
ptr_completion_word->word,
|
||||
length) == 0))
|
||||
|| ((!item_is_nick)
|
||||
&& (string_strncasecmp (completion->base_word, ptr_item->data,
|
||||
|| (!ptr_completion_word->nick_completion
|
||||
&& (string_strncasecmp (completion->base_word,
|
||||
ptr_completion_word->word,
|
||||
length) == 0)))
|
||||
{
|
||||
if ((!completion->word_found) || word_found_seen)
|
||||
{
|
||||
if (completion->word_found)
|
||||
free (completion->word_found);
|
||||
completion->word_found = strdup (ptr_item->data);
|
||||
completion->word_found_is_nick = item_is_nick;
|
||||
if (item_is_nick
|
||||
completion->word_found = strdup (ptr_completion_word->word);
|
||||
completion->word_found_is_nick =
|
||||
ptr_completion_word->nick_completion;
|
||||
if (ptr_completion_word->nick_completion
|
||||
&& !CONFIG_BOOLEAN(config_completion_nick_add_space))
|
||||
{
|
||||
completion->add_space = 0;
|
||||
}
|
||||
|
||||
/* stop after first nick if user asked that */
|
||||
if (item_is_nick
|
||||
if (ptr_completion_word->nick_completion
|
||||
&& CONFIG_BOOLEAN(config_completion_nick_first_only))
|
||||
{
|
||||
gui_completion_stop (completion);
|
||||
return;
|
||||
}
|
||||
|
||||
if (completion->direction < 0)
|
||||
ptr_item2 = ptr_item->prev_item;
|
||||
else
|
||||
ptr_item2 = ptr_item->next_item;
|
||||
|
||||
while (ptr_item2)
|
||||
index2 = (completion->direction < 0) ? index - 1 : index + 1;
|
||||
while ((index2 >= 0) && (index2 < completion->list->size))
|
||||
{
|
||||
if ((item_is_nick
|
||||
ptr_completion_word2 =
|
||||
(struct t_gui_completion_word *)(completion->list->data[index2]);
|
||||
if ((ptr_completion_word->nick_completion
|
||||
&& (gui_completion_nickncmp (completion->base_word,
|
||||
ptr_item2->data,
|
||||
ptr_completion_word2->word,
|
||||
length) == 0))
|
||||
|| ((!item_is_nick)
|
||||
|| (!ptr_completion_word->nick_completion
|
||||
&& (string_strncasecmp (completion->base_word,
|
||||
ptr_item2->data,
|
||||
ptr_completion_word2->word,
|
||||
length) == 0)))
|
||||
{
|
||||
other_completion++;
|
||||
}
|
||||
|
||||
if (completion->direction < 0)
|
||||
ptr_item2 = ptr_item2->prev_item;
|
||||
else
|
||||
ptr_item2 = ptr_item2->next_item;
|
||||
index2 = (completion->direction < 0) ?
|
||||
index2 - 1 : index2 + 1;
|
||||
}
|
||||
|
||||
if (other_completion == 0)
|
||||
@ -1086,20 +1129,17 @@ gui_completion_complete (struct t_gui_completion *completion)
|
||||
return;
|
||||
}
|
||||
|
||||
gui_completion_partial_list_free_all (completion);
|
||||
arraylist_clear (completion->partial_list);
|
||||
|
||||
return;
|
||||
}
|
||||
other_completion++;
|
||||
}
|
||||
if (completion->word_found &&
|
||||
(strcmp (ptr_item->data, completion->word_found) == 0))
|
||||
(strcmp (ptr_completion_word->word, completion->word_found) == 0))
|
||||
word_found_seen = 1;
|
||||
|
||||
if (completion->direction < 0)
|
||||
ptr_item = ptr_item->prev_item;
|
||||
else
|
||||
ptr_item = ptr_item->next_item;
|
||||
index = (completion->direction < 0) ? index - 1 : index + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1124,7 +1164,7 @@ gui_completion_command (struct t_gui_completion *completion)
|
||||
{
|
||||
struct t_hook *ptr_hook;
|
||||
|
||||
if (!completion->completion_list->items)
|
||||
if (completion->list->size == 0)
|
||||
{
|
||||
for (ptr_hook = weechat_hooks[HOOK_TYPE_COMMAND]; ptr_hook;
|
||||
ptr_hook = ptr_hook->next_hook)
|
||||
@ -1154,18 +1194,19 @@ gui_completion_auto (struct t_gui_completion *completion)
|
||||
if ((completion->base_word[0] == '/')
|
||||
|| (completion->base_word[0] == '~'))
|
||||
{
|
||||
if (!completion->completion_list->items)
|
||||
if (completion->list->size == 0)
|
||||
completion_list_add_filename_cb (NULL, NULL, NULL, completion);
|
||||
gui_completion_complete (completion);
|
||||
return;
|
||||
}
|
||||
|
||||
/* use default template completion */
|
||||
if (!completion->completion_list->items)
|
||||
if (completion->list->size == 0)
|
||||
{
|
||||
gui_completion_build_list_template (completion,
|
||||
CONFIG_STRING(config_completion_default_template),
|
||||
NULL);
|
||||
gui_completion_build_list_template (
|
||||
completion,
|
||||
CONFIG_STRING(config_completion_default_template),
|
||||
NULL);
|
||||
}
|
||||
gui_completion_complete (completion);
|
||||
}
|
||||
@ -1205,7 +1246,7 @@ gui_completion_search (struct t_gui_completion *completion, int direction,
|
||||
gui_completion_command (completion);
|
||||
break;
|
||||
case GUI_COMPLETION_COMMAND_ARG:
|
||||
if (completion->completion_list->items)
|
||||
if (completion->list->size > 0)
|
||||
gui_completion_complete (completion);
|
||||
else
|
||||
{
|
||||
@ -1286,24 +1327,23 @@ gui_completion_hdata_completion_cb (void *data, const char *hdata_name)
|
||||
HDATA_VAR(struct t_gui_completion, direction, INTEGER, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion, add_space, INTEGER, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion, force_partial_completion, INTEGER, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion, completion_list, POINTER, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion, list, POINTER, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion, word_found, STRING, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion, word_found_is_nick, INTEGER, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion, position_replace, INTEGER, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion, diff_size, INTEGER, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion, diff_length, INTEGER, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion, partial_completion_list, POINTER, 0, NULL, "completion_partial");
|
||||
HDATA_VAR(struct t_gui_completion, last_partial_completion, POINTER, 0, NULL, "completion_partial");
|
||||
HDATA_VAR(struct t_gui_completion, partial_list, POINTER, 0, NULL, NULL);
|
||||
}
|
||||
return hdata;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns hdata for partial completion.
|
||||
* Returns hdata for completion word.
|
||||
*/
|
||||
|
||||
struct t_hdata *
|
||||
gui_completion_hdata_completion_partial_cb (void *data, const char *hdata_name)
|
||||
gui_completion_hdata_completion_word_cb (void *data, const char *hdata_name)
|
||||
{
|
||||
struct t_hdata *hdata;
|
||||
|
||||
@ -1314,14 +1354,34 @@ gui_completion_hdata_completion_partial_cb (void *data, const char *hdata_name)
|
||||
0, 0, NULL, NULL);
|
||||
if (hdata)
|
||||
{
|
||||
HDATA_VAR(struct t_gui_completion_partial, word, STRING, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion_partial, count, INTEGER, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion_partial, prev_item, POINTER, 0, NULL, hdata_name);
|
||||
HDATA_VAR(struct t_gui_completion_partial, next_item, POINTER, 0, NULL, hdata_name);
|
||||
HDATA_VAR(struct t_gui_completion_word, word, STRING, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion_word, nick_completion, CHAR, 0, NULL, NULL);
|
||||
HDATA_VAR(struct t_gui_completion_word, count, INTEGER, 0, NULL, NULL);
|
||||
}
|
||||
return hdata;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints list of completion words in WeeChat log file (usually for crash dump).
|
||||
*/
|
||||
|
||||
void
|
||||
gui_completion_list_words_print_log (struct t_arraylist *list,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
struct t_gui_completion_word *ptr_completion_word;
|
||||
|
||||
for (i = 0; i < list->size; i++)
|
||||
{
|
||||
ptr_completion_word = (struct t_gui_completion_word *)(list->data[i]);
|
||||
log_printf ("[%s (addr:0x%lx)]", name, ptr_completion_word);
|
||||
log_printf (" word. . . . . . . . . . : '%s'", ptr_completion_word->word);
|
||||
log_printf (" nicklist_completion . . : %d", ptr_completion_word->nick_completion);
|
||||
log_printf (" count . . . . . . . . . : %d", ptr_completion_word->count);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints completion list in WeeChat log file (usually for crash dump).
|
||||
*/
|
||||
@ -1329,8 +1389,6 @@ gui_completion_hdata_completion_partial_cb (void *data, const char *hdata_name)
|
||||
void
|
||||
gui_completion_print_log (struct t_gui_completion *completion)
|
||||
{
|
||||
struct t_gui_completion_partial *ptr_item;
|
||||
|
||||
log_printf ("[completion (addr:0x%lx)]", completion);
|
||||
log_printf (" buffer. . . . . . . . . : 0x%lx", completion->buffer);
|
||||
log_printf (" context . . . . . . . . : %d", completion->context);
|
||||
@ -1343,29 +1401,22 @@ gui_completion_print_log (struct t_gui_completion *completion)
|
||||
log_printf (" direction . . . . . . . : %d", completion->direction);
|
||||
log_printf (" add_space . . . . . . . : %d", completion->add_space);
|
||||
log_printf (" force_partial_completion: %d", completion->force_partial_completion);
|
||||
log_printf (" completion_list . . . . : 0x%lx", completion->completion_list);
|
||||
log_printf (" list. . . . . . . . . . : 0x%lx", completion->list);
|
||||
log_printf (" word_found. . . . . . . : '%s'", completion->word_found);
|
||||
log_printf (" word_found_is_nick. . . : %d", completion->word_found_is_nick);
|
||||
log_printf (" position_replace. . . . : %d", completion->position_replace);
|
||||
log_printf (" diff_size . . . . . . . : %d", completion->diff_size);
|
||||
log_printf (" diff_length . . . . . . : %d", completion->diff_length);
|
||||
if (completion->completion_list)
|
||||
if (completion->list)
|
||||
{
|
||||
log_printf ("");
|
||||
weelist_print_log (completion->completion_list,
|
||||
"completion list element");
|
||||
gui_completion_list_words_print_log (completion->list,
|
||||
"completion word");
|
||||
}
|
||||
if (completion->partial_completion_list)
|
||||
if (completion->partial_list)
|
||||
{
|
||||
log_printf ("");
|
||||
for (ptr_item = completion->partial_completion_list;
|
||||
ptr_item; ptr_item = ptr_item->next_item)
|
||||
{
|
||||
log_printf ("[partial completion item (addr:0x%lx)]", ptr_item);
|
||||
log_printf (" word. . . . . . . . . . : '%s'", ptr_item->word);
|
||||
log_printf (" count . . . . . . . . . : %d", ptr_item->count);
|
||||
log_printf (" prev_item . . . . . . . : 0x%lx", ptr_item->prev_item);
|
||||
log_printf (" next_item . . . . . . . : 0x%lx", ptr_item->next_item);
|
||||
}
|
||||
arraylist_print_log (completion->partial_list,
|
||||
"partial completion word");
|
||||
}
|
||||
}
|
||||
|
@ -25,12 +25,12 @@
|
||||
#define GUI_COMPLETION_COMMAND_ARG 2
|
||||
#define GUI_COMPLETION_AUTO 3
|
||||
|
||||
struct t_gui_completion_partial
|
||||
struct t_gui_completion_word
|
||||
{
|
||||
char *word; /* (partial) word matching completion */
|
||||
char *word; /* word matching completion */
|
||||
char nick_completion; /* 1 if it is completion of a nick */
|
||||
int count; /* number of matching items with this word */
|
||||
struct t_gui_completion_partial *prev_item;
|
||||
struct t_gui_completion_partial *next_item;
|
||||
/* (for partial completion) */
|
||||
};
|
||||
|
||||
struct t_gui_completion
|
||||
@ -49,7 +49,7 @@ struct t_gui_completion
|
||||
int force_partial_completion; /* force partial completion? */
|
||||
|
||||
/* for command argument completion */
|
||||
struct t_weelist *completion_list; /* data list for completion */
|
||||
struct t_arraylist *list; /* data list for completion */
|
||||
|
||||
/* completion found */
|
||||
char *word_found; /* word found (to replace base word) */
|
||||
@ -59,8 +59,7 @@ struct t_gui_completion
|
||||
int diff_length; /* length difference (<= diff_size) */
|
||||
|
||||
/* partial completion */
|
||||
struct t_gui_completion_partial *partial_completion_list;
|
||||
struct t_gui_completion_partial *last_partial_completion;
|
||||
struct t_arraylist *partial_list;
|
||||
};
|
||||
|
||||
/* completion variables */
|
||||
|
@ -1298,8 +1298,6 @@ plugin_api_init ()
|
||||
&gui_buffer_hdata_buffer_visited_cb, NULL);
|
||||
hook_hdata (NULL, "completion", N_("structure with completion"),
|
||||
&gui_completion_hdata_completion_cb, NULL);
|
||||
hook_hdata (NULL, "completion_partial", N_("structure with partial completion"),
|
||||
&gui_completion_hdata_completion_partial_cb, NULL);
|
||||
hook_hdata (NULL, "config_file", N_("config file"),
|
||||
&config_file_hdata_config_file_cb, NULL);
|
||||
hook_hdata (NULL, "config_section", N_("config section"),
|
||||
|
@ -30,6 +30,7 @@ include_directories(${CPPUTEST_INCLUDE_DIRS} ${PROJECT_BINARY_DIR} ${PROJECT_SOU
|
||||
|
||||
# unit tests
|
||||
set(LIB_WEECHAT_UNIT_TESTS_SRC
|
||||
unit/core/test-arraylist.cpp
|
||||
unit/core/test-eval.cpp
|
||||
unit/core/test-hashtable.cpp
|
||||
unit/core/test-hdata.cpp
|
||||
@ -53,6 +54,8 @@ set(LIBS
|
||||
${PROJECT_BINARY_DIR}/src/gui/curses/libweechat_gui_curses.a
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libweechat_ncurses_fake.a
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libweechat_unit_tests.a
|
||||
# due to circular references, we must link two times with libweechat_core.a
|
||||
${PROJECT_BINARY_DIR}/src/core/libweechat_core.a
|
||||
${EXTRA_LIBS}
|
||||
${CURL_LIBRARIES}
|
||||
${CPPUTEST_LIBRARIES})
|
||||
|
@ -23,7 +23,8 @@ noinst_LIBRARIES = lib_ncurses_fake.a lib_weechat_unit_tests.a
|
||||
|
||||
lib_ncurses_fake_a_SOURCES = ncurses-fake.c
|
||||
|
||||
lib_weechat_unit_tests_a_SOURCES = unit/core/test-eval.cpp \
|
||||
lib_weechat_unit_tests_a_SOURCES = unit/core/test-arraylist.cpp \
|
||||
unit/core/test-eval.cpp \
|
||||
unit/core/test-hashtable.cpp \
|
||||
unit/core/test-hdata.cpp \
|
||||
unit/core/test-infolist.cpp \
|
||||
@ -35,15 +36,15 @@ lib_weechat_unit_tests_a_SOURCES = unit/core/test-eval.cpp \
|
||||
|
||||
noinst_PROGRAMS = tests
|
||||
|
||||
# Because of a linker bug, we have to link 2 times with lib_weechat_core.a
|
||||
# Due to circular references, we must link two times with libweechat_core.a
|
||||
# (and it must be 2 different path/names to be kept by linker)
|
||||
tests_LDADD = ./../src/core/lib_weechat_core.a \
|
||||
../src/plugins/lib_weechat_plugins.a \
|
||||
../src/gui/lib_weechat_gui_common.a \
|
||||
../src/gui/curses/lib_weechat_gui_curses.a \
|
||||
../src/core/lib_weechat_core.a \
|
||||
lib_ncurses_fake.a \
|
||||
lib_weechat_unit_tests.a \
|
||||
../src/core/lib_weechat_core.a \
|
||||
$(PLUGINS_LFLAGS) \
|
||||
$(GCRYPT_LFLAGS) \
|
||||
$(GNUTLS_LFLAGS) \
|
||||
|
@ -47,6 +47,7 @@ extern "C"
|
||||
#include "CppUTest/CommandLineTestRunner.h"
|
||||
|
||||
/* import tests from libs */
|
||||
IMPORT_TEST_GROUP(Arraylist);
|
||||
IMPORT_TEST_GROUP(Eval);
|
||||
IMPORT_TEST_GROUP(Hashtable);
|
||||
IMPORT_TEST_GROUP(Hdata);
|
||||
|
418
tests/unit/core/test-arraylist.cpp
Normal file
418
tests/unit/core/test-arraylist.cpp
Normal file
@ -0,0 +1,418 @@
|
||||
/*
|
||||
* test-arraylist.cpp - test arraylist functions
|
||||
*
|
||||
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CppUTest/TestHarness.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <string.h>
|
||||
#include "src/core/wee-arraylist.h"
|
||||
#include "src/core/wee-string.h"
|
||||
}
|
||||
|
||||
#define TEST_ARRAYLIST_ADD(__result, __value) \
|
||||
LONGS_EQUAL(__result, \
|
||||
arraylist_add (arraylist, (void *)(__value)));
|
||||
|
||||
TEST_GROUP(Arraylist)
|
||||
{
|
||||
};
|
||||
|
||||
/*
|
||||
* Test callback comparing two arraylist elements.
|
||||
*
|
||||
* Returns:
|
||||
* -1: element(pointer1) < element(pointer2)
|
||||
* 0: element(pointer1) == element(pointer2)
|
||||
* 1: element(pointer1) > element(pointer2)
|
||||
*/
|
||||
|
||||
int
|
||||
test_cmp_cb (void *data, struct t_arraylist *arraylist,
|
||||
void *pointer1, void *pointer2)
|
||||
{
|
||||
if (!pointer1 || !pointer2)
|
||||
return (pointer1) ? 1 : ((pointer2) ? -1 : 0);
|
||||
|
||||
return string_strcasecmp ((const char *)pointer1, (const char *)pointer2);
|
||||
}
|
||||
|
||||
void
|
||||
test_arraylist (int initial_size, int sorted, int allow_duplicates)
|
||||
{
|
||||
struct t_arraylist *arraylist;
|
||||
int i, index, index_insert, expected_pos;
|
||||
const char *item_aaa = "aaa";
|
||||
const char *item_abc = "abc";
|
||||
const char *item_DEF = "DEF";
|
||||
const char *item_def = "def";
|
||||
const char *item_xxx = "xxx";
|
||||
|
||||
/* create arraylist */
|
||||
arraylist = arraylist_new (initial_size,
|
||||
sorted,
|
||||
allow_duplicates,
|
||||
&test_cmp_cb, NULL,
|
||||
NULL, NULL);
|
||||
|
||||
/* check values after creation */
|
||||
CHECK(arraylist);
|
||||
LONGS_EQUAL(0, arraylist->size);
|
||||
LONGS_EQUAL(initial_size, arraylist->size_alloc);
|
||||
LONGS_EQUAL(initial_size, arraylist->size_alloc_min);
|
||||
if (initial_size > 0)
|
||||
{
|
||||
CHECK(arraylist->data);
|
||||
for (i = 0; i < initial_size; i++)
|
||||
{
|
||||
POINTERS_EQUAL(NULL, arraylist->data[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
POINTERS_EQUAL(NULL, arraylist->data);
|
||||
}
|
||||
LONGS_EQUAL(sorted, arraylist->sorted);
|
||||
LONGS_EQUAL(allow_duplicates, arraylist->allow_duplicates);
|
||||
|
||||
/* check size */
|
||||
LONGS_EQUAL(0, arraylist_size (arraylist));
|
||||
|
||||
/* get element (this should always fail, the list is empty!) */
|
||||
POINTERS_EQUAL(NULL, arraylist_get (NULL, -1));
|
||||
POINTERS_EQUAL(NULL, arraylist_get (NULL, 0));
|
||||
POINTERS_EQUAL(NULL, arraylist_get (NULL, 1));
|
||||
POINTERS_EQUAL(NULL, arraylist_get (arraylist, -1));
|
||||
POINTERS_EQUAL(NULL, arraylist_get (arraylist, 0));
|
||||
POINTERS_EQUAL(NULL, arraylist_get (arraylist, 1));
|
||||
|
||||
/* search element (this should always fail, the list is empty!) */
|
||||
POINTERS_EQUAL(NULL, arraylist_search (NULL, NULL, NULL, NULL));
|
||||
POINTERS_EQUAL(NULL, arraylist_search (arraylist, NULL, NULL, NULL));
|
||||
POINTERS_EQUAL(NULL,
|
||||
arraylist_search (NULL, (void *)item_abc, NULL, NULL));
|
||||
POINTERS_EQUAL(NULL,
|
||||
arraylist_search (arraylist, (void *)item_abc, NULL, NULL));
|
||||
|
||||
/* invalid add of element */
|
||||
LONGS_EQUAL(-1, arraylist_add (NULL, NULL));
|
||||
|
||||
/* add some elements */
|
||||
if (sorted)
|
||||
{
|
||||
TEST_ARRAYLIST_ADD(0, item_xxx);
|
||||
TEST_ARRAYLIST_ADD(0, NULL);
|
||||
TEST_ARRAYLIST_ADD(1, item_def);
|
||||
TEST_ARRAYLIST_ADD(1, item_DEF);
|
||||
TEST_ARRAYLIST_ADD(1, item_abc);
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_ARRAYLIST_ADD(0, item_xxx);
|
||||
TEST_ARRAYLIST_ADD(1, NULL);
|
||||
TEST_ARRAYLIST_ADD(2, item_def);
|
||||
TEST_ARRAYLIST_ADD((allow_duplicates) ? 3 : 2, item_DEF);
|
||||
TEST_ARRAYLIST_ADD((allow_duplicates) ? 4 : 3, item_abc);
|
||||
}
|
||||
|
||||
/*
|
||||
* arraylist is now:
|
||||
* sorted:
|
||||
* allow dup: [NULL, "abc", "DEF", "def", "xxx", (NULL)]
|
||||
* no dup : [NULL, "abc", "DEF", "xxx"]
|
||||
* not sorted:
|
||||
* allow dup: ["xxx", NULL, "def", "DEF", "abc", (NULL)]
|
||||
* no dup : ["xxx", NULL, "DEF", "abc"]
|
||||
*/
|
||||
|
||||
/* check size after adds */
|
||||
LONGS_EQUAL((allow_duplicates) ? 5 : 4, arraylist->size);
|
||||
LONGS_EQUAL((allow_duplicates) ? 5 : 4, arraylist_size (arraylist));
|
||||
LONGS_EQUAL((allow_duplicates) ? 6 : 4, arraylist->size_alloc);
|
||||
|
||||
/* check content after adds */
|
||||
if (sorted)
|
||||
{
|
||||
POINTERS_EQUAL(NULL, arraylist->data[0]);
|
||||
STRCMP_EQUAL(item_abc, (const char *)arraylist->data[1]);
|
||||
if (allow_duplicates)
|
||||
{
|
||||
STRCMP_EQUAL(item_DEF, (const char *)arraylist->data[2]);
|
||||
STRCMP_EQUAL(item_def, (const char *)arraylist->data[3]);
|
||||
STRCMP_EQUAL(item_xxx, (const char *)arraylist->data[4]);
|
||||
POINTERS_EQUAL(NULL, arraylist->data[5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
STRCMP_EQUAL(item_DEF, (const char *)arraylist->data[2]);
|
||||
STRCMP_EQUAL(item_xxx, (const char *)arraylist->data[3]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
STRCMP_EQUAL(item_xxx, (const char *)arraylist->data[0]);
|
||||
POINTERS_EQUAL(NULL, arraylist->data[1]);
|
||||
if (allow_duplicates)
|
||||
{
|
||||
STRCMP_EQUAL(item_def, (const char *)arraylist->data[2]);
|
||||
STRCMP_EQUAL(item_DEF, (const char *)arraylist->data[3]);
|
||||
STRCMP_EQUAL(item_abc, (const char *)arraylist->data[4]);
|
||||
POINTERS_EQUAL(NULL, arraylist->data[5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
STRCMP_EQUAL(item_DEF, (const char *)arraylist->data[2]);
|
||||
STRCMP_EQUAL(item_abc, (const char *)arraylist->data[3]);
|
||||
}
|
||||
}
|
||||
|
||||
/* search elements */
|
||||
if (sorted)
|
||||
{
|
||||
/* search first element */
|
||||
POINTERS_EQUAL(NULL, arraylist_search (arraylist, NULL,
|
||||
&index, &index_insert));
|
||||
LONGS_EQUAL(0, index);
|
||||
LONGS_EQUAL(0, index_insert);
|
||||
|
||||
/* search second element */
|
||||
POINTERS_EQUAL(item_abc, arraylist_search (arraylist, (void *)item_abc,
|
||||
&index, &index_insert));
|
||||
LONGS_EQUAL(1, index);
|
||||
LONGS_EQUAL(1, index_insert);
|
||||
|
||||
/* search last element */
|
||||
POINTERS_EQUAL(item_xxx,
|
||||
arraylist_search (arraylist, (void *)item_xxx,
|
||||
&index, &index_insert));
|
||||
LONGS_EQUAL((allow_duplicates) ? 4 : 3, index);
|
||||
LONGS_EQUAL(-1, index_insert);
|
||||
|
||||
/* search non-existing element */
|
||||
POINTERS_EQUAL(NULL,
|
||||
arraylist_search (arraylist, (void *)item_aaa,
|
||||
&index, &index_insert));
|
||||
LONGS_EQUAL(-1, index);
|
||||
LONGS_EQUAL(1, index_insert);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* search first element */
|
||||
POINTERS_EQUAL(item_xxx, arraylist_search (arraylist, (void *)item_xxx,
|
||||
&index, &index_insert));
|
||||
LONGS_EQUAL(0, index);
|
||||
LONGS_EQUAL(-1, index_insert);
|
||||
|
||||
/* search second element */
|
||||
POINTERS_EQUAL(NULL, arraylist_search (arraylist, NULL,
|
||||
&index, &index_insert));
|
||||
LONGS_EQUAL(1, index);
|
||||
LONGS_EQUAL(-1, index_insert);
|
||||
|
||||
/* search last element */
|
||||
POINTERS_EQUAL(item_abc,
|
||||
arraylist_search (arraylist, (void *)item_abc,
|
||||
&index, &index_insert));
|
||||
LONGS_EQUAL((allow_duplicates) ? 4 : 3, index);
|
||||
LONGS_EQUAL(-1, index_insert);
|
||||
|
||||
/* search non-existing element */
|
||||
POINTERS_EQUAL(NULL,
|
||||
arraylist_search (arraylist, (void *)item_aaa,
|
||||
&index, &index_insert));
|
||||
LONGS_EQUAL(-1, index);
|
||||
LONGS_EQUAL(-1, index_insert);
|
||||
}
|
||||
|
||||
/* invalid remove of elements */
|
||||
LONGS_EQUAL(-1, arraylist_remove (NULL, -1));
|
||||
LONGS_EQUAL(-1, arraylist_remove (arraylist, -1));
|
||||
LONGS_EQUAL(-1, arraylist_remove (NULL, 0));
|
||||
|
||||
/* remove the 3 first elements and check size after each remove */
|
||||
LONGS_EQUAL(0, arraylist_remove (arraylist, 0));
|
||||
LONGS_EQUAL((allow_duplicates) ? 4 : 3, arraylist->size);
|
||||
LONGS_EQUAL((allow_duplicates) ? 4 : 3, arraylist_size (arraylist));
|
||||
LONGS_EQUAL((allow_duplicates) ? 6 : 4, arraylist->size_alloc);
|
||||
LONGS_EQUAL(0, arraylist_remove (arraylist, 0));
|
||||
LONGS_EQUAL((allow_duplicates) ? 3 : 2, arraylist->size);
|
||||
LONGS_EQUAL((allow_duplicates) ? 3 : 2, arraylist_size (arraylist));
|
||||
LONGS_EQUAL((allow_duplicates) ? 6 : 4, arraylist->size_alloc);
|
||||
LONGS_EQUAL(0, arraylist_remove (arraylist, 0));
|
||||
LONGS_EQUAL((allow_duplicates) ? 2 : 1, arraylist->size);
|
||||
LONGS_EQUAL((allow_duplicates) ? 2 : 1, arraylist_size (arraylist));
|
||||
LONGS_EQUAL((allow_duplicates) ? 3 : 2, arraylist->size_alloc);
|
||||
|
||||
/*
|
||||
* arraylist is now:
|
||||
* sorted:
|
||||
* allow dup: ["def", "xxx", (NULL)]
|
||||
* no dup : ["xxx"]
|
||||
* not sorted:
|
||||
* allow dup: ["DEF", "abc", (NULL)]
|
||||
* no dup : ["abc"]
|
||||
*/
|
||||
|
||||
/* check content after the 3 deletions */
|
||||
if (sorted)
|
||||
{
|
||||
if (allow_duplicates)
|
||||
{
|
||||
STRCMP_EQUAL(item_def, (const char *)arraylist->data[0]);
|
||||
STRCMP_EQUAL(item_xxx, (const char *)arraylist->data[1]);
|
||||
POINTERS_EQUAL(NULL, arraylist->data[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
STRCMP_EQUAL(item_xxx, (const char *)arraylist->data[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (allow_duplicates)
|
||||
{
|
||||
STRCMP_EQUAL(item_DEF, (const char *)arraylist->data[0]);
|
||||
STRCMP_EQUAL(item_abc, (const char *)arraylist->data[1]);
|
||||
POINTERS_EQUAL(NULL, arraylist->data[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
STRCMP_EQUAL(item_abc, (const char *)arraylist->data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/* invalid insert of element */
|
||||
LONGS_EQUAL(-1, arraylist_insert (NULL, 0, NULL));
|
||||
|
||||
/* insert of one element */
|
||||
LONGS_EQUAL(0, arraylist_insert (arraylist, 0, (void *)item_aaa));
|
||||
|
||||
/*
|
||||
* arraylist is now:
|
||||
* sorted:
|
||||
* allow dup: ["aaa", "def", "xxx", (NULL)]
|
||||
* no dup : ["aaa", "xxx"]
|
||||
* not sorted:
|
||||
* allow dup: ["aaa", "DEF", "abc", (NULL)]
|
||||
* no dup : ["aaa", "abc"]
|
||||
*/
|
||||
|
||||
/* check size after insert */
|
||||
LONGS_EQUAL((allow_duplicates) ? 3 : 2, arraylist->size);
|
||||
LONGS_EQUAL((allow_duplicates) ? 3 : 2, arraylist_size (arraylist));
|
||||
LONGS_EQUAL((allow_duplicates) ? 3 : 2, arraylist->size_alloc);
|
||||
|
||||
/* check content after the insert */
|
||||
if (sorted)
|
||||
{
|
||||
if (allow_duplicates)
|
||||
{
|
||||
STRCMP_EQUAL(item_aaa, (const char *)arraylist->data[0]);
|
||||
STRCMP_EQUAL(item_def, (const char *)arraylist->data[1]);
|
||||
STRCMP_EQUAL(item_xxx, (const char *)arraylist->data[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
STRCMP_EQUAL(item_aaa, (const char *)arraylist->data[0]);
|
||||
STRCMP_EQUAL(item_xxx, (const char *)arraylist->data[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (allow_duplicates)
|
||||
{
|
||||
STRCMP_EQUAL(item_aaa, (const char *)arraylist->data[0]);
|
||||
STRCMP_EQUAL(item_DEF, (const char *)arraylist->data[1]);
|
||||
STRCMP_EQUAL(item_abc, (const char *)arraylist->data[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
STRCMP_EQUAL(item_aaa, (const char *)arraylist->data[0]);
|
||||
STRCMP_EQUAL(item_abc, (const char *)arraylist->data[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* clear arraylist */
|
||||
LONGS_EQUAL(0, arraylist_clear (NULL));
|
||||
LONGS_EQUAL(1, arraylist_clear (arraylist));
|
||||
|
||||
/* check size and data after clear */
|
||||
LONGS_EQUAL(0, arraylist->size);
|
||||
LONGS_EQUAL(0, arraylist_size (arraylist));
|
||||
LONGS_EQUAL(initial_size, arraylist->size_alloc);
|
||||
if (initial_size > 0)
|
||||
{
|
||||
CHECK(arraylist->data);
|
||||
for (i = 0; i < initial_size; i++)
|
||||
{
|
||||
POINTERS_EQUAL(NULL, arraylist->data[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
POINTERS_EQUAL(NULL, arraylist->data);
|
||||
}
|
||||
|
||||
/* free arraylist */
|
||||
arraylist_free (arraylist);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* arraylist_new
|
||||
* arraylist_size
|
||||
* arraylist_get
|
||||
* arraylist_search
|
||||
* arraylist_insert
|
||||
* arraylist_add
|
||||
* arraylist_remove
|
||||
* arraylist_clear
|
||||
* arraylist_free
|
||||
*/
|
||||
|
||||
TEST(Arraylist, New)
|
||||
{
|
||||
int initial_size, sorted, allow_duplicates;
|
||||
|
||||
/*
|
||||
* in order to create an arraylist, initial_size must be >= 0 and a
|
||||
* comparison callback must be given
|
||||
*/
|
||||
POINTERS_EQUAL(NULL,
|
||||
arraylist_new (-1, 0, 0, NULL, NULL, NULL, NULL));
|
||||
POINTERS_EQUAL(NULL,
|
||||
arraylist_new (-1, 0, 0, &test_cmp_cb, NULL, NULL, NULL));
|
||||
POINTERS_EQUAL(NULL,
|
||||
arraylist_new (0, 0, 0, NULL, NULL, NULL, NULL));
|
||||
|
||||
/* tests on arraylists */
|
||||
for (initial_size = 0; initial_size < 2; initial_size++)
|
||||
{
|
||||
for (sorted = 0; sorted < 2; sorted++)
|
||||
{
|
||||
for (allow_duplicates = 0; allow_duplicates < 2;
|
||||
allow_duplicates++)
|
||||
{
|
||||
test_arraylist (initial_size, sorted, allow_duplicates);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user