Commit 5781e1f6 5781e1f68d451a0930060f166a376ba38a88fad2 by Sergey Poznyakoff

Implement new list functions.

* include/mailutils/list.h (_mu_list_ptr_comparator)
(mu_list_insert_list, mu_list_append_list)
(mu_list_prepend_list): New prototypes.
* libproto/include/list0.h (_mu_list_insert_sublist): New prototype.
* mailbox/listlist.c: New function.
* mailbox/Makefile.am (libmailutils_la_SOURCES): Add listlist.c.
* mailbox/list.c: Remove unnecessary parentheses.
(def_comp): Rename to _mu_list_ptr_comparator.
Remove static qualifier. All uses updated.
(_insert_item): Remove.
(mu_list_insert): Use _mu_list_insert_sublist instead of _insert_item.
* examples/listop.c (print): Print number of elements.
(count): New function.
(ins): Use mu_list_insert if only one new element was given,
mu_list_insert_list otherwise.
(help): Update.
(main)<count>: New keyword.
* mailbox/testsuite/mailbox/list.exp: Update. Add new tests.
1 parent 2cb1d357
......@@ -44,13 +44,20 @@ void
print (mu_list_t list)
{
mu_iterator_t itr;
size_t count;
int rc;
rc = mu_list_get_iterator (list, &itr);
if (rc)
lperror ("mu_list_get_iterator", rc);
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
rc = mu_list_count (list, &count);
if (rc)
lperror ("mu_iterator_current", rc);
printf ("# items: %lu\n", (unsigned long) count);
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
char *text;
......@@ -63,6 +70,19 @@ print (mu_list_t list)
}
void
count (mu_list_t list)
{
size_t n;
int rc;
rc = mu_list_count (list, &n);
if (rc)
lperror ("mu_iterator_current", rc);
else
printf ("%lu\n", (unsigned long) n);
}
void
next (mu_iterator_t itr, char *arg)
{
int skip = arg ? strtoul (arg, NULL, 0) : 1;
......@@ -130,41 +150,75 @@ prep (mu_list_t list, int argc, char **argv)
}
}
static int
read_list (mu_list_t list, int argc, char **argv)
{
int rc;
for (; argc; argc--, argv++)
{
rc = mu_list_append (list, strdup (*argv));
if (rc)
break;
}
return rc;
}
void
ins (mu_list_t list, int argc, char **argv)
{
int an;
int rc;
char *item;
char *new_item;
int insert_before = 0;
if (argc < 3 || argc > 4)
if (argc < 3)
{
fprintf (stderr, "ins [before] item new_item?\n");
fprintf (stderr, "ins [before] item new_item [new_item*]?\n");
return;
}
if (argc == 4)
an = 1;
if (strcmp (argv[1], "before") == 0)
{
if (strcmp (argv[1], "before"))
{
fprintf (stderr, "ins before item new_item?\n");
return;
}
item = argv[2];
new_item = argv[3];
an++;
insert_before = 1;
}
else
else if (strcmp (argv[1], "after") == 0)
{
item = argv[1];
new_item = argv[2];
an++;
insert_before = 0;
}
item = argv[an++];
rc = mu_list_insert (list, item, strdup (new_item), argc == 4);
if (an + 1 == argc)
rc = mu_list_insert (list, item, strdup (argv[an]), insert_before);
else
{
mu_list_t tmp;
rc = mu_list_create (&tmp);
if (rc)
{
fprintf (stderr, "creating temp list: %s\n", mu_strerror (rc));
return;
}
rc = read_list (tmp, argc - an, argv + an);
if (rc)
{
fprintf (stderr, "reading temp list: %s\n", mu_strerror (rc));
return;
}
rc = mu_list_insert_list (list, item, tmp, insert_before);
mu_list_destroy (&tmp);
}
if (rc)
fprintf (stderr, "mu_list_insert: %s\n", mu_strerror (rc));
lperror ("mu_list_insert", rc);
}
void
repl (mu_list_t list, int argc, char **argv)
......@@ -232,14 +286,15 @@ find (mu_iterator_t itr, char *arg)
void
help ()
{
printf ("count\n");
printf ("next [count]\n");
printf ("first\n");
printf ("find item\n");
printf ("del item [item...]\n");
printf ("add item [item...]\n");
printf ("prep item [item...]\n");
printf ("del item [item*]\n");
printf ("add item [item*]\n");
printf ("prep item [item*]\n");
printf ("repl old_item new_item\n");
printf ("ins [before] item new_item\n");
printf ("ins [before|after] item new_item [new_item*]\n");
printf ("print\n");
printf ("quit\n");
printf ("iter num\n");
......@@ -285,7 +340,9 @@ shell (mu_list_t list)
if (argc > 0)
{
if (strcmp (argv[0], "next") == 0)
if (strcmp (argv[0], "count") == 0)
count (list);
else if (strcmp (argv[0], "next") == 0)
next (itr[num], argv[1]);
else if (strcmp (argv[0], "first") == 0)
mu_iterator_first (itr[num]);
......
......@@ -41,12 +41,14 @@ extern int mu_list_to_array (mu_list_t list, void **array, size_t count, size_t
extern int mu_list_locate (mu_list_t list, void *item, void **ret_item);
extern int mu_list_get_iterator (mu_list_t, mu_iterator_t *);
typedef int mu_list_action_t (void* item, void* cbdata);
extern int mu_list_do (mu_list_t list, mu_list_action_t * action, void *cbdata);
typedef int mu_list_action_t (void *item, void *cbdata);
extern int mu_list_do (mu_list_t list, mu_list_action_t *action, void *cbdata);
typedef int (*mu_list_comparator_t) (const void*, const void*);
extern int _mu_list_ptr_comparator (const void*, const void*);
extern mu_list_comparator_t mu_list_set_comparator (mu_list_t,
mu_list_comparator_t);
extern int mu_list_get_comparator (mu_list_t, mu_list_comparator_t *);
......@@ -59,6 +61,11 @@ extern int mu_list_intersect_dup (mu_list_t *, mu_list_t, mu_list_t,
int (*dup_item) (void **, void *, void *),
void *);
extern int mu_list_intersect (mu_list_t *, mu_list_t, mu_list_t);
extern int mu_list_insert_list (mu_list_t list, void *item, mu_list_t new_list,
int insert_before);
extern void mu_list_append_list (mu_list_t list, mu_list_t new_list);
extern void mu_list_prepend_list (mu_list_t list, mu_list_t new_list);
#ifdef __cplusplus
}
......
......@@ -51,6 +51,12 @@ struct _mu_list
struct _mu_iterator *itr;
};
extern void _mu_list_insert_sublist (mu_list_t list,
struct list_data *current,
struct list_data *head,
struct list_data *tail,
size_t count,
int insert_before);
#ifdef __cplusplus
}
......
......@@ -86,6 +86,7 @@ libmailutils_la_SOURCES = \
ipsrv.c\
kwd.c\
list.c\
listlist.c\
locale.c\
locker.c\
mailbox.c\
......
......@@ -40,14 +40,14 @@ mu_list_create (mu_list_t *plist)
list = calloc (sizeof (*list), 1);
if (list == NULL)
return ENOMEM;
status = mu_monitor_create (&(list->monitor), 0, list);
status = mu_monitor_create (&list->monitor, 0, list);
if (status != 0)
{
free (list);
return status;
}
list->head.next = &(list->head);
list->head.prev = &(list->head);
list->head.next = &list->head;
list->head.prev = &list->head;
*plist = list;
return 0;
}
......@@ -62,7 +62,7 @@ mu_list_destroy (mu_list_t *plist)
struct list_data *previous;
mu_monitor_wrlock (list->monitor);
for (current = list->head.next; current != &(list->head);)
for (current = list->head.next; current != &list->head;)
{
previous = current;
current = current->next;
......@@ -71,7 +71,7 @@ mu_list_destroy (mu_list_t *plist)
free (previous);
}
mu_monitor_unlock (list->monitor);
mu_monitor_destroy (&(list->monitor), list);
mu_monitor_destroy (&list->monitor, list);
free (list);
*plist = NULL;
}
......@@ -91,7 +91,7 @@ mu_list_append (mu_list_t list, void *item)
return ENOMEM;
ldata->item = item;
mu_monitor_wrlock (list->monitor);
ldata->next = &(list->head);
ldata->next = &list->head;
ldata->prev = list->head.prev;
last->next = ldata;
list->head.prev = ldata;
......@@ -114,7 +114,7 @@ mu_list_prepend (mu_list_t list, void *item)
return ENOMEM;
ldata->item = item;
mu_monitor_wrlock (list->monitor);
ldata->prev = &(list->head);
ldata->prev = &list->head;
ldata->next = list->head.next;
first->prev = ldata;
list->head.next = ldata;
......@@ -164,8 +164,8 @@ mu_list_get_comparator (mu_list_t list, mu_list_comparator_t *comp)
return 0;
}
static int
def_comp (const void *item, const void *value)
int
_mu_list_ptr_comparator (const void *item, const void *value)
{
return item != value;
}
......@@ -179,10 +179,10 @@ mu_list_locate (mu_list_t list, void *item, void **ret_item)
if (list == NULL)
return EINVAL;
comp = list->comp ? list->comp : def_comp;
comp = list->comp ? list->comp : _mu_list_ptr_comparator;
mu_monitor_wrlock (list->monitor);
for (previous = &(list->head), current = list->head.next;
current != &(list->head); previous = current, current = current->next)
for (previous = &list->head, current = list->head.next;
current != &list->head; previous = current, current = current->next)
{
if (comp (current->item, item) == 0)
{
......@@ -196,43 +196,6 @@ mu_list_locate (mu_list_t list, void *item, void **ret_item)
return status;
}
static int
_insert_item(mu_list_t list, struct list_data *current, void *new_item,
int insert_before)
{
struct list_data *ldata = calloc (sizeof (*ldata), 1);
if (ldata == NULL)
return ENOMEM;
ldata->item = new_item;
if (insert_before)
{
ldata->prev = current->prev;
ldata->next = current;
if (current->prev != &list->head)
current->prev->next = ldata;
else
list->head.next = ldata;
current->prev = ldata;
}
else
{
ldata->next = current->next;
ldata->prev = current;
if (current->next != &list->head)
current->next->prev = ldata;
else
list->head.prev = ldata;
current->next = ldata;
}
list->count++;
return 0;
}
int
mu_list_insert (mu_list_t list, void *item, void *new_item, int insert_before)
{
......@@ -242,16 +205,27 @@ mu_list_insert (mu_list_t list, void *item, void *new_item, int insert_before)
if (list == NULL)
return EINVAL;
comp = list->comp ? list->comp : def_comp;
comp = list->comp ? list->comp : _mu_list_ptr_comparator;
mu_monitor_wrlock (list->monitor);
for (current = list->head.next;
current != &(list->head);
current != &list->head;
current = current->next)
{
if (comp (current->item, item) == 0)
{
status = _insert_item (list, current, new_item, insert_before);
struct list_data *ldata = calloc (sizeof (*ldata), 1);
if (ldata == NULL)
status = ENOMEM;
else
{
ldata->item = new_item;
_mu_list_insert_sublist (list, current,
ldata, ldata,
1,
insert_before);
status = 0;
}
break;
}
}
......@@ -268,10 +242,10 @@ mu_list_remove (mu_list_t list, void *item)
if (list == NULL)
return EINVAL;
comp = list->comp ? list->comp : def_comp;
comp = list->comp ? list->comp : _mu_list_ptr_comparator;
mu_monitor_wrlock (list->monitor);
for (previous = &(list->head), current = list->head.next;
current != &(list->head); previous = current, current = current->next)
for (previous = &list->head, current = list->head.next;
current != &list->head; previous = current, current = current->next)
{
if (comp (current->item, item) == 0)
{
......@@ -297,10 +271,10 @@ mu_list_replace (mu_list_t list, void *old_item, void *new_item)
if (list == NULL)
return EINVAL;
comp = list->comp ? list->comp : def_comp;
comp = list->comp ? list->comp : _mu_list_ptr_comparator;
mu_monitor_wrlock (list->monitor);
for (previous = &(list->head), current = list->head.next;
current != &(list->head); previous = current, current = current->next)
for (previous = &list->head, current = list->head.next;
current != &list->head; previous = current, current = current->next)
{
if (comp (current->item, old_item) == 0)
{
......@@ -325,7 +299,7 @@ mu_list_get (mu_list_t list, size_t indx, void **pitem)
if (pitem == NULL)
return MU_ERR_OUT_PTR_NULL;
mu_monitor_rdlock (list->monitor);
for (current = list->head.next, count = 0; current != &(list->head);
for (current = list->head.next, count = 0; current != &list->head;
current = current->next, count++)
{
if (count == indx)
......@@ -340,7 +314,7 @@ mu_list_get (mu_list_t list, size_t indx, void **pitem)
}
int
mu_list_do (mu_list_t list, mu_list_action_t * action, void *cbdata)
mu_list_do (mu_list_t list, mu_list_action_t *action, void *cbdata)
{
mu_iterator_t itr;
int status = 0;
......@@ -350,7 +324,8 @@ mu_list_do (mu_list_t list, mu_list_action_t * action, void *cbdata)
status = mu_list_get_iterator(list, &itr);
if (status)
return status;
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
void *item;
mu_iterator_current (itr, &item);
......@@ -386,7 +361,7 @@ mu_list_to_array (mu_list_t list, void **array, size_t count, size_t *pcount)
struct list_data *current;
for (i = 0, current = list->head.next;
i < total && current != &(list->head); current = current->next)
i < total && current != &list->head; current = current->next)
array[i++] = current->item;
}
if (pcount)
......@@ -394,15 +369,15 @@ mu_list_to_array (mu_list_t list, void **array, size_t count, size_t *pcount)
return 0;
}
/* Computes an intersection of the two lists. The resulting list,
stored into PDEST, contains elements from the list A that are
also encountered in the list B, using the comparison function of
the latter.
/* Computes an intersection of two lists and returns it in PDEST.
The resulting list contains elements from A that are
also encountered in B (as per comparison function of
the latter).
If DUP_ITEM is not NULL, it is used to create copies of the
If DUP_ITEM is not NULL, it is used to create copies of
items to be stored in PDEST. In this case, the destroy_item
function of B is also attached to PDEST. Otherwise, if
DUP_ITEM is NULL, the pointers to the elements are stored and
DUP_ITEM is NULL, pointers to elements are stored and
no destroy_item function is assigned. */
int
mu_list_intersect_dup (mu_list_t *pdest, mu_list_t a, mu_list_t b,
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2004, 2005, 2007, 2008, 2010 Free
Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <list0.h>
#include <iterator0.h>
#include <mailutils/errno.h>
void
_mu_list_insert_sublist (mu_list_t list,
struct list_data *current,
struct list_data *head,
struct list_data *tail,
size_t count,
int insert_before)
{
if (insert_before)
{
head->prev = current->prev;
tail->next = current;
if (current->prev != &list->head)
current->prev->next = head;
else
list->head.next = head;
current->prev = tail;
}
else
{
tail->next = current->next;
head->prev = current;
if (current->next != &list->head)
current->next->prev = tail;
else
list->head.prev = tail;
current->next = head;
}
list->count += count;
}
static void
clear_list (mu_list_t list)
{
list->head.next = list->head.prev = &list->head;
list->count = 0;
}
int
mu_list_insert_list (mu_list_t list, void *item, mu_list_t new_list,
int insert_before)
{
struct list_data *current;
mu_list_comparator_t comp;
int status = MU_ERR_NOENT;
if (list == NULL)
return EINVAL;
comp = list->comp ? list->comp : _mu_list_ptr_comparator;
mu_monitor_wrlock (list->monitor);
for (current = list->head.next;
current != &list->head;
current = current->next)
{
if (comp (current->item, item) == 0)
{
_mu_list_insert_sublist (list, current,
new_list->head.next, new_list->head.prev,
new_list->count,
insert_before);
clear_list (new_list);
status = 0;
break;
}
}
mu_monitor_unlock (list->monitor);
return status;
}
void
mu_list_append_list (mu_list_t list, mu_list_t new_list)
{
if (list->count == 0)
{
list->head = new_list->head;
list->count = new_list->count;
}
else
_mu_list_insert_sublist (list, list->head.prev,
new_list->head.next, new_list->head.prev,
new_list->count,
0);
clear_list (new_list);
}
void
mu_list_prepend_list (mu_list_t list, mu_list_t new_list)
{
if (list->count == 0)
{
list->head = new_list->head;
list->count = new_list->count;
}
else
_mu_list_insert_sublist (list, list->head.next,
new_list->head.next, new_list->head.prev,
new_list->count,
1);
clear_list (new_list);
}
......@@ -50,6 +50,7 @@ mailbox_prog_start "${top_builddir}/examples/listop"
mailbox_prog_command "add en to tre fire fem"
mailbox_prog_test "print" \
"# items: 5" \
"en" \
"to" \
"tre" \
......@@ -78,6 +79,7 @@ prompt_iterator 0
prompt_text "fem"
mailbox_prog_test "iter 0"
mailbox_prog_test "print" \
"# items: 3" \
"en" \
"to" \
"fem"
......@@ -85,6 +87,7 @@ mailbox_prog_test "print" \
mailbox_prog_command "prep jeden dwa trzy cztery"
mailbox_prog_test "print" \
"# items: 7" \
"cztery" \
"trzy" \
"dwa" \
......@@ -110,6 +113,7 @@ mailbox_prog_test "next 2"
mailbox_prog_command "ins jeden un"
mailbox_prog_test "print" \
"# items: 7" \
"3" \
"dwa" \
"jeden" \
......@@ -120,6 +124,7 @@ mailbox_prog_test "print" \
mailbox_prog_command "ins before jeden zero"
mailbox_prog_test "print" \
"# items: 8" \
"3" \
"dwa" \
"zero" \
......@@ -136,6 +141,7 @@ mailbox_prog_command "ins before un cero"
mailbox_prog_command "ins un dos"
mailbox_prog_test "print" \
"# items: 10" \
"3" \
"dwa" \
"zero" \
......@@ -149,6 +155,7 @@ mailbox_prog_test "print" \
mailbox_prog_command "ins before 3 1"
mailbox_prog_test "print" \
"# items: 11" \
"1" \
"3" \
"dwa" \
......@@ -163,6 +170,7 @@ mailbox_prog_test "print" \
mailbox_prog_command "ins before 3 2"
mailbox_prog_test "print" \
"# items: 12" \
"1" \
"2" \
"3" \
......@@ -173,9 +181,48 @@ mailbox_prog_test "print" \
"un" \
"dos" \
"en" \
"to" \
"to" \
"fem"
mailbox_prog_command "ins 3 4 5 6"
mailbox_prog_test "print" \
"# items: 15" \
"1" \
"2" \
"3" \
"4" \
"5" \
"6" \
"dwa" \
"zero" \
"jeden" \
"cero" \
"un" \
"dos" \
"en" \
"to" \
"fem"
mailbox_prog_command "ins before dwa zero jeden"
mailbox_prog_test "print" \
"# items: 17" \
"1" \
"2" \
"3" \
"4" \
"5" \
"6" \
"zero" \
"jeden" \
"dwa" \
"zero" \
"jeden" \
"cero" \
"un" \
"dos" \
"en" \
"to" \
"fem"
mailbox_prog_send "quit"
mailbox_prog_stop
......