Commit a192c111 a192c1115ffc99fe631826cd6f17ce00f4d22820 by Sergey Poznyakoff

Implement `iterator_ctl' function.

* include/mailutils/iterator.h (mu_itrctl_req): New enum.
(mu_iterator_skip, mu_iterator_ctl)
(mu_iterator_set_itrctl): New prototypes.
* include/mailutils/list.h (mu_list_free_item): New prototype.
* libproto/include/iterator0.h (struct _mu_iterator)<itrctl>: New method.
* libproto/include/list0.h (_mu_list_clear): New proto.
* mailbox/iterator.c (mu_iterator_set_itrctl): New function.
(mu_iterator_skip, mu_iterator_ctl): New functions.
* mailbox/list.c (_insert_item): Re-implement function.
(mu_list_insert): Use _insert_item again.
(mu_list_remove): Don't keep track of the previous item.
(list_itrctl): New function.
(mu_list_get_iterator): Set itrctl method.
* mailbox/listlist.c (clear_list): Rename to _mu_list_clear,
remove static qualifier. All uses updated.

* mailbox/freeitem.c: New file.
* mailbox/Makefile.am (libmailutils_la_SOURCES): Add freeitem.c.

* examples/listop.c (read_list): Rewrite to simplify
calling convention. All callers updated.
(inctl_tell,ictl_del,ictl_repl)
(ictl_ins,ictl): New functions.
(help): Add new commands.
(shell): Handle "inctl" command.
(delete): Fix memory leak.
(main): Set mu_list_free_item as a destroy_item function.

* mailbox/testsuite/mailbox/listop.c: Add ictl tests.

* libmu_cfg/sieve.c (_add_path): Set mu_list_free_item as
a destroy_item function.
* mailbox/gocs.c (mu_gocs_store): Likewise.
* maidag/lmtp.c (cfun_rcpt_to): Likewise.
* imap4d/namespace.c (namespace_init): Likewise.
* libmu_sieve/conf.c (_path_append): Likewise.
1 parent 5781e1f6
......@@ -106,7 +106,7 @@ delete (mu_list_t list, int argc, char **argv)
while (--argc)
{
rc = mu_list_remove (list, strdup (*++argv));
rc = mu_list_remove (list, *++argv);
if (rc)
fprintf (stderr, "mu_list_remove(%s): %s\n", *argv, mu_strerror (rc));
}
......@@ -150,18 +150,30 @@ prep (mu_list_t list, int argc, char **argv)
}
}
static int
read_list (mu_list_t list, int argc, char **argv)
static mu_list_t
read_list (int argc, char **argv)
{
int rc;
mu_list_t list;
rc = mu_list_create (&list);
if (rc)
{
fprintf (stderr, "creating temp list: %s\n", mu_strerror (rc));
return NULL;
}
mu_list_set_destroy_item (list, mu_list_free_item);
for (; argc; argc--, argv++)
{
rc = mu_list_append (list, strdup (*argv));
if (rc)
break;
{
mu_list_destroy (&list);
fprintf (stderr, "adding to temp list: %s\n", mu_strerror (rc));
break;
}
}
return rc;
return list;
}
void
......@@ -196,21 +208,9 @@ ins (mu_list_t list, int argc, char **argv)
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;
}
mu_list_t tmp = read_list (argc - an, argv + an);
if (!tmp)
return;
rc = mu_list_insert_list (list, item, tmp, insert_before);
mu_list_destroy (&tmp);
}
......@@ -219,7 +219,6 @@ ins (mu_list_t list, int argc, char **argv)
lperror ("mu_list_insert", rc);
}
void
repl (mu_list_t list, int argc, char **argv)
{
......@@ -236,6 +235,99 @@ repl (mu_list_t list, int argc, char **argv)
fprintf (stderr, "mu_list_replace: %s\n", mu_strerror (rc));
}
void
ictl_tell (mu_iterator_t itr, int argc)
{
size_t pos;
int rc;
if (argc)
{
fprintf (stderr, "ictl tell?\n");
return;
}
rc = mu_iterator_ctl (itr, mu_itrctl_tell, &pos);
if (rc)
lperror ("mu_iterator_ctl", rc);
printf ("%lu\n", (unsigned long) pos);
}
void
ictl_del (mu_iterator_t itr, int argc)
{
int rc;
if (argc)
{
fprintf (stderr, "ictl del?\n");
return;
}
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
if (rc)
lperror ("mu_iterator_ctl", rc);
}
void
ictl_repl (mu_iterator_t itr, int argc, char **argv)
{
int rc;
if (argc != 1)
{
fprintf (stderr, "ictl repl item?\n");
return;
}
rc = mu_iterator_ctl (itr, mu_itrctl_replace, strdup (argv[0]));
if (rc)
lperror ("mu_iterator_ctl", rc);
}
void
ictl_ins (mu_iterator_t itr, int argc, char **argv)
{
int rc;
if (argc < 1)
{
fprintf (stderr, "ictl ins item [item*]?\n");
return;
}
if (argc == 1)
rc = mu_iterator_ctl (itr, mu_itrctl_insert, strdup (argv[0]));
else
{
mu_list_t tmp = read_list (argc, argv);
if (!tmp)
return;
rc = mu_iterator_ctl (itr, mu_itrctl_insert_list, tmp);
mu_list_destroy (&tmp);
}
}
void
ictl (mu_iterator_t itr, int argc, char **argv)
{
if (argc == 1)
{
fprintf (stderr, "ictl tell|del|repl|ins?\n");
return;
}
if (strcmp (argv[1], "tell") == 0)
ictl_tell (itr, argc - 2);
else if (strcmp (argv[1], "del") == 0)
ictl_del (itr, argc - 2);
else if (strcmp (argv[1], "repl") == 0)
ictl_repl (itr, argc - 2, argv + 2);
else if (strcmp (argv[1], "ins") == 0)
ictl_ins (itr, argc - 2, argv + 2);
else
fprintf (stderr, "unknown subcommand\n");
}
#define NITR 4
int
......@@ -295,6 +387,10 @@ help ()
printf ("prep item [item*]\n");
printf ("repl old_item new_item\n");
printf ("ins [before|after] item new_item [new_item*]\n");
printf ("ictl tell\n");
printf ("ictl del\n");
printf ("ictl repl item\n");
printf ("ictl ins item [item*]\n");
printf ("print\n");
printf ("quit\n");
printf ("iter num\n");
......@@ -356,6 +452,8 @@ shell (mu_list_t list)
ins (list, argc, argv);
else if (strcmp (argv[0], "repl") == 0)
repl (list, argc, argv);
else if (strcmp (argv[0], "ictl") == 0)
ictl (itr[num], argc, argv);
else if (strcmp (argv[0], "print") == 0)
print (list);
else if (strcmp (argv[0], "quit") == 0)
......@@ -437,7 +535,8 @@ main (int argc, char **argv)
if (rc)
lperror ("mu_list_create", rc);
mu_list_set_comparator (list, string_comp);
mu_list_set_destroy_item (list, mu_list_free_item);
while (argc--)
{
rc = mu_list_append (list, *argv++);
......
......@@ -261,12 +261,6 @@ normalize_fun (void *item, void *data)
mu_strdup (mu_normalize_path (name)));
}
static void
free_item (void *item)
{
free (item);
}
void
namespace_init ()
{
......@@ -278,9 +272,9 @@ namespace_init ()
{
mu_list_t list;
mu_list_create (&list);
mu_list_set_destroy_item (list, free_item);
mu_list_set_destroy_item (list, mu_list_free_item);
mu_list_do (namespace[i], normalize_fun, list);
mu_list_set_destroy_item (namespace[i], free_item);
mu_list_set_destroy_item (namespace[i], mu_list_free_item);
mu_list_destroy (&namespace[i]);
namespace[i] = list;
}
......
......@@ -26,16 +26,28 @@
extern "C" {
#endif
enum mu_itrctl_req
{
mu_itrctl_tell, /* Return current position in the object */
mu_itrctl_delete, /* Delete current element */
mu_itrctl_replace,/* Replace current element */
mu_itrctl_insert, /* Insert new element in the current position */
mu_itrctl_insert_list, /* Insert a list of elements */
};
extern int mu_iterator_create (mu_iterator_t *, void *);
extern int mu_iterator_dup (mu_iterator_t *piterator, mu_iterator_t orig);
extern void mu_iterator_destroy (mu_iterator_t *);
extern int mu_iterator_first (mu_iterator_t);
extern int mu_iterator_next (mu_iterator_t);
extern int mu_iterator_skip (mu_iterator_t iterator, ssize_t count);
extern int mu_iterator_current (mu_iterator_t, void **pitem);
extern int mu_iterator_current_kv (mu_iterator_t,
const void **key, void **pitem);
extern int mu_iterator_is_done (mu_iterator_t);
extern int mu_iterator_ctl (mu_iterator_t, enum mu_itrctl_req, void *);
extern int mu_iterator_attach (mu_iterator_t *root, mu_iterator_t iterator);
extern int mu_iterator_detach (mu_iterator_t *root, mu_iterator_t iterator);
extern void mu_iterator_advance (mu_iterator_t iterator, void *e);
......@@ -53,7 +65,10 @@ extern int mu_iterator_set_destroy (mu_iterator_t itr,
int (*destroy) (mu_iterator_t, void *data));
extern int mu_iterator_set_curitem_p (mu_iterator_t itr,
int (*curitem_p) (void *, void *));
extern int mu_iterator_set_itrctl (mu_iterator_t itr,
int (*itrctl) (void *,
enum mu_itrctl_req,
void *));
#ifdef __cplusplus
}
#endif
......
......@@ -53,6 +53,8 @@ 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 *);
extern void mu_list_free_item (void *item);
extern int mu_list_set_destroy_item (mu_list_t list,
void (*destroy_item) (void *));
......
......@@ -58,12 +58,6 @@ cb_clear_include_path (mu_debug_t debug, void *data, mu_config_value_t *val)
return 0;
}
static void
destroy_string (void *str)
{
free (str);
}
static int
_add_path (mu_debug_t debug, const char *arg, void *data)
{
......@@ -79,7 +73,7 @@ _add_path (mu_debug_t debug, const char *arg, void *data)
_("cannot create list: %s"), mu_strerror (rc));
exit (1);
}
mu_list_set_destroy_item (*plist, destroy_string);
mu_list_set_destroy_item (*plist, mu_list_free_item);
}
/* FIXME: Use mu_argcv */
tmp = strdup (arg);
......
......@@ -26,12 +26,6 @@
mu_list_t mu_sieve_include_path = NULL;
mu_list_t mu_sieve_library_path = NULL;
static void
destroy_string (void *str)
{
free (str);
}
static int
_path_append (void *item, void *data)
{
......@@ -44,7 +38,7 @@ _path_append (void *item, void *data)
mu_error (_("cannot create list: %s"), mu_strerror (rc));
exit (1);
}
mu_list_set_destroy_item (*plist, destroy_string);
mu_list_set_destroy_item (*plist, mu_list_free_item);
}
return mu_list_append (*plist, strdup (item));
}
......
......@@ -43,6 +43,7 @@ struct _mu_iterator
int (*getitem) (void *owner, void **pret, const void **pkey);
int (*curitem_p) (void *owner, void *item);
int (*finished_p) (void *owner);
int (*itrctl) (void *owner, enum mu_itrctl_req req, void *arg);
};
#ifdef __cplusplus
......
......@@ -51,6 +51,7 @@ struct _mu_list
struct _mu_iterator *itr;
};
extern void _mu_list_clear (mu_list_t list);
extern void _mu_list_insert_sublist (mu_list_t list,
struct list_data *current,
struct list_data *head,
......
......@@ -155,12 +155,6 @@ mu_list_t rcpt_list; /* Recipient addresses */
struct mail_tmp *mtmp; /* Temporary mail storage */
mu_mailbox_t mbox; /* Collected mail body */
static void
rcpt_to_destroy_item (void *ptr)
{
free (ptr);
}
int
cfun_unknown (FILE *out, char *arg)
......@@ -295,7 +289,7 @@ cfun_rcpt_to (FILE *out, char *arg)
if (!rcpt_list)
{
mu_list_create (&rcpt_list);
mu_list_set_destroy_item (rcpt_list, rcpt_to_destroy_item);
mu_list_set_destroy_item (rcpt_list, mu_list_free_item);
}
mu_list_append (rcpt_list, user);
lmtp_reply (out, "250", "2.1.5", "Go ahead");
......
......@@ -78,6 +78,7 @@ libmailutils_la_SOURCES = \
filter_rfc822.c\
filter_trans.c\
folder.c\
freeitem.c\
gdebug.c\
gocs.c\
hdritr.c\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 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
/* Default destroy_item function. */
void
mu_list_free_item (void *item)
{
free (item);
}
......@@ -333,12 +333,6 @@ struct mu_gocs_data
static mu_list_t /* of struct mu_gocs_data */ data_list;
static void
_destroy_data (void *item)
{
free (item);
}
static int
_gocs_comp (const void *a, const void *b)
{
......@@ -353,7 +347,7 @@ mu_gocs_store (char *capa, void *data)
if (!data_list)
{
mu_list_create (&data_list);
mu_list_set_destroy_item (data_list, _destroy_data);
mu_list_set_destroy_item (data_list, mu_list_free_item);
mu_list_set_comparator (data_list, _gocs_comp);
}
s = malloc (sizeof *s);
......
......@@ -92,6 +92,18 @@ mu_iterator_set_curitem_p (mu_iterator_t itr,
}
int
mu_iterator_set_itrctl (mu_iterator_t itr,
int (*itrctl) (void *,
enum mu_itrctl_req,
void *))
{
if (!itr)
return EINVAL;
itr->itrctl = itrctl;
return 0;
}
int
mu_iterator_set_destroy (mu_iterator_t itr, int (*destroy) (mu_iterator_t, void *))
{
if (!itr)
......@@ -176,6 +188,18 @@ mu_iterator_next (mu_iterator_t iterator)
}
int
mu_iterator_skip (mu_iterator_t iterator, ssize_t count)
{
int status;
if (count < 0)
return ENOSYS; /* Need prev method */
while (count--)
if ((status = mu_iterator_next (iterator)))
break;
return status;
}
int
mu_iterator_current (mu_iterator_t iterator, void **pitem)
{
return iterator->getitem (iterator->owner, pitem, NULL);
......@@ -247,3 +271,13 @@ mu_iterator_detach (mu_iterator_t *root, mu_iterator_t iterator)
return 0;
}
int
mu_iterator_ctl (mu_iterator_t iterator, enum mu_itrctl_req req, void *arg)
{
if (!iterator)
return EINVAL;
if (!iterator->itrctl)
return ENOSYS;
return iterator->itrctl (iterator->owner, req, arg);
}
......
......@@ -196,6 +196,26 @@ 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)
{
int status;
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;
}
return status;
}
int
mu_list_insert (mu_list_t list, void *item, void *new_item, int insert_before)
{
......@@ -214,18 +234,7 @@ mu_list_insert (mu_list_t list, void *item, void *new_item, int insert_before)
{
if (comp (current->item, item) == 0)
{
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;
}
status = _insert_item (list, current, new_item, insert_before);
break;
}
}
......@@ -236,7 +245,7 @@ mu_list_insert (mu_list_t list, void *item, void *new_item, int insert_before)
int
mu_list_remove (mu_list_t list, void *item)
{
struct list_data *current, *previous;
struct list_data *current;
mu_list_comparator_t comp;
int status = MU_ERR_NOENT;
......@@ -244,14 +253,17 @@ mu_list_remove (mu_list_t list, void *item)
return EINVAL;
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 (current = list->head.next;
current != &list->head; current = current->next)
{
if (comp (current->item, item) == 0)
{
struct list_data *previous = current->prev;
mu_iterator_advance (list->itr, current);
previous->next = current->next;
current->next->prev = previous;
/* FIXME: Call destroy_item */
free (current);
list->count--;
status = 0;
......@@ -278,6 +290,7 @@ mu_list_replace (mu_list_t list, void *old_item, void *new_item)
{
if (comp (current->item, old_item) == 0)
{
/* FIXME: Call destroy_item. Perhaps optionally? */
current->item = new_item;
status = 0;
break;
......@@ -503,6 +516,87 @@ list_data_dup (void **ptr, void *owner)
return 0;
}
static int
list_itrctl (void *owner, enum mu_itrctl_req req, void *arg)
{
struct list_iterator *itr = owner;
mu_list_t list = itr->list;
struct list_data *ptr;
if (itr->cur == NULL)
return MU_ERR_NOENT;
switch (req)
{
case mu_itrctl_tell:
/* Return current position in the object */
{
size_t count;
for (count = 0, ptr = list->head.next; ptr != &list->head;
ptr = ptr->next, count++)
{
if (ptr == itr->cur)
{
*(size_t*)arg = count;
return 0;
}
}
return MU_ERR_NOENT;
}
case mu_itrctl_delete:
/* Delete current element */
{
struct list_data *prev;
ptr = itr->cur;
prev = ptr->prev;
mu_iterator_advance (list->itr, ptr);
prev->next = ptr->next;
ptr->next->prev = prev;
/* FIXME: Call destroy_item */
free (ptr);
list->count--;
}
break;
case mu_itrctl_replace:
/* Replace current element */
if (!arg)
return EINVAL;
/* FIXME: Call destroy_item. Perhaps optionally? */
ptr = itr->cur;
ptr->item = arg;
break;
case mu_itrctl_insert:
/* Insert new element in the current position */
if (!arg)
return EINVAL;
return _insert_item (list, itr->cur, arg, 0);
case mu_itrctl_insert_list:
/* Insert a list of elements */
if (!arg)
return EINVAL;
else
{
mu_list_t new_list = arg;
_mu_list_insert_sublist (list, itr->cur,
new_list->head.next, new_list->head.prev,
new_list->count,
0);
_mu_list_clear (new_list);
}
break;
default:
return ENOSYS;
}
return 0;
}
int
mu_list_get_iterator (mu_list_t list, mu_iterator_t *piterator)
{
......@@ -533,7 +627,8 @@ mu_list_get_iterator (mu_list_t list, mu_iterator_t *piterator)
mu_iterator_set_curitem_p (iterator, curitem_p);
mu_iterator_set_destroy (iterator, destroy);
mu_iterator_set_dup (iterator, list_data_dup);
mu_iterator_set_itrctl (iterator, list_itrctl);
mu_iterator_attach (&list->itr, iterator);
*piterator = iterator;
......
......@@ -62,8 +62,8 @@ _mu_list_insert_sublist (mu_list_t list,
list->count += count;
}
static void
clear_list (mu_list_t list)
void
_mu_list_clear (mu_list_t list)
{
list->head.next = list->head.prev = &list->head;
list->count = 0;
......@@ -92,7 +92,7 @@ mu_list_insert_list (mu_list_t list, void *item, mu_list_t new_list,
new_list->head.next, new_list->head.prev,
new_list->count,
insert_before);
clear_list (new_list);
_mu_list_clear (new_list);
status = 0;
break;
}
......@@ -114,7 +114,7 @@ mu_list_append_list (mu_list_t list, mu_list_t new_list)
new_list->head.next, new_list->head.prev,
new_list->count,
0);
clear_list (new_list);
_mu_list_clear (new_list);
}
void
......@@ -130,7 +130,7 @@ mu_list_prepend_list (mu_list_t list, mu_list_t new_list)
new_list->head.next, new_list->head.prev,
new_list->count,
1);
clear_list (new_list);
_mu_list_clear (new_list);
}
......
......@@ -681,12 +681,6 @@ mu_mailbox_unlock (mu_mailbox_t mbox)
return mu_locker_unlock (lock);
}
static void
free_uidl (void *item)
{
free (item);
}
int
mu_mailbox_get_uidls (mu_mailbox_t mbox, mu_list_t *plist)
{
......@@ -700,7 +694,7 @@ mu_mailbox_get_uidls (mu_mailbox_t mbox, mu_list_t *plist)
status = mu_list_create (&list);
if (status)
return status;
mu_list_set_destroy_item (list, free_uidl);
mu_list_set_destroy_item (list, mu_list_free_item);
if (mbox->_get_uidls)
status = mbox->_get_uidls (mbox, list);
else
......@@ -734,7 +728,7 @@ mu_mailbox_get_uidls (mu_mailbox_t mbox, mu_list_t *plist)
status = mu_list_append (list, uidl);
if (status)
{
free_uidl (uidl);
free (uidl);
break;
}
}
......
......@@ -224,6 +224,83 @@ mailbox_prog_test "print" \
"to" \
"fem"
mailbox_prog_test "ictl tell" "12"
prompt_text "dos"
mailbox_prog_test "ictl del"
prompt_text "dos"
mailbox_prog_test "next"
mailbox_prog_test "print" \
"# items: 16" \
"1" \
"2" \
"3" \
"4" \
"5" \
"6" \
"zero" \
"jeden" \
"dwa" \
"zero" \
"jeden" \
"cero" \
"dos" \
"en" \
"to" \
"fem"
mailbox_prog_test "ictl ins seis"
mailbox_prog_test "print" \
"# items: 17" \
"1" \
"2" \
"3" \
"4" \
"5" \
"6" \
"zero" \
"jeden" \
"dwa" \
"zero" \
"jeden" \
"cero" \
"dos" \
"seis" \
"en" \
"to" \
"fem"
mailbox_prog_test "ictl ins tres quatro cinco"
mailbox_prog_test "print" \
"# items: 20" \
"1" \
"2" \
"3" \
"4" \
"5" \
"6" \
"zero" \
"jeden" \
"dwa" \
"zero" \
"jeden" \
"cero" \
"dos" \
"tres" \
"quatro" \
"cinco" \
"seis" \
"en" \
"to" \
"fem"
prompt_text "tres"
mailbox_prog_test "next"
mailbox_prog_send "quit"
mailbox_prog_stop
......