Commit 827a4ba2 827a4ba256a0d3cfc6b3caab546cea0c1ee96263 by Sergey Poznyakoff

Implement list folding functions.

* include/mailutils/list.h (mu_list_folder_t): New typedef.
(mu_list_fold, mu_list_rfold): New functions.
* libmailutils/list/fold.c: New file.
* libmailutils/list/rfold.c: New file.
* libmailutils/list/Makefile.am (liblist_la_SOURCES): Add fold.c and
rfold.c
* libmailutils/list/gmap.c (mu_list_gmap): Access list elements directly,
instead of using iterators.
* libmailutils/tests/list.at: Add test cases for list folding.
* libmailutils/tests/listop.c: Add fold and rfold commands.
1 parent de237686
......@@ -238,7 +238,10 @@ typedef int (*mu_list_mapper_t) (void **_itmv, size_t _itmc, void *_call_data);
and until all elements from the array have been visited.
Mu_list_gmap returns 0 on success and a non-zero error code on failure.
If _map returns non-zero, its return value is propagated to the caller. */
If _map returns non-zero, its return value is propagated to the caller.
The _map function is not allowed to alter the _list.
*/
int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem,
void *_data);
......@@ -263,11 +266,56 @@ int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem,
MU_LIST_MAP_SKIP bit set, the _itmv[0] element is appended to the new
list. If it has MU_LIST_MAP_STOP bit set, iteration is stopped
immediately and any remaining elements in _list are ignored.
The mapper function (_map) is not allowed to alter the _list.
*/
int mu_list_map (mu_list_t _list, mu_list_mapper_t _map,
void *_data, size_t _nelem,
mu_list_t *_res);
/* List fold */
typedef int (*mu_list_folder_t) (void *_item, void *_data,
void *_prev, void **_ret);
/* mu_list_fold iterates over list elements from first to last.
For each element it calls _fold with the following arguments:
_item - the current list element,
_data - call-specific data,
_prev - on the first call, _init; on subsequent calls,
points to the value returned from the previous call
to _fold in the _ret varialble,
_ret - memory location where to store the result of this
call.
When all elements have been visited, mu_list_fold stores the result
of the last _fold invocation (as returned in *_ret) in the memory
location pointed to by _return_value.
If _fold returns a non-zero value, mu_list_fold stops iteration and
returns this value. The *_return_value is filled in this case as
well.
Possible return codes:
0 - success,
EINVAL - _list or _fold is NULL,
MU_ERR_OUT_PTR_NULL - _return_code is NULL
other value - non-zero value returned by _fold.
The _fold function is not allowed to alter the list it is being applied
to.
The mu_list_rfold acts similarly, except that it iterates over list
elements from last to first.
*/
int mu_list_fold (mu_list_t _list, mu_list_folder_t _fold, void *_data,
void *_init, void *_return_value);
int mu_list_rfold (mu_list_t _list, mu_list_folder_t _fold, void *_data,
void *_init, void *_return_value);
#ifdef __cplusplus
}
#endif
......
......@@ -25,6 +25,7 @@ liblist_la_SOURCES = \
create.c\
destroy.c\
empty.c\
fold.c\
foreach.c\
get.c\
getcomp.c\
......@@ -39,6 +40,7 @@ liblist_la_SOURCES = \
prepend.c\
remove.c\
replace.c\
rfold.c\
setcomp.c\
setdestr.c\
slice.c\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2011 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, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <mailutils/errno.h>
#include <mailutils/sys/list.h>
int
mu_list_fold (mu_list_t list, mu_list_folder_t fold, void *data, void *prev,
void *return_value)
{
struct list_data *current;
int status = 0;
if (list == NULL || fold == NULL)
return EINVAL;
if (return_value == NULL)
return MU_ERR_OUT_PTR_NULL;
for (current = list->head.next; current != &list->head;
current = current->next)
{
status = fold (current->item, data, prev, &prev);
if (status)
break;
}
*(void **) return_value = prev;
return status;
}
......@@ -27,28 +27,21 @@ int
mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data)
{
int rc;
int status;
mu_iterator_t itr;
struct list_data *current;
void **buf;
size_t i;
if (!list || !map || nelem == 0)
return EINVAL;
rc = mu_list_get_iterator (list, &itr);
if (rc)
return status;
buf = calloc (nelem, sizeof (buf[0]));
if (!buf)
{
mu_iterator_destroy (&itr);
return ENOMEM;
}
for (i = 0, mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
i = 0;
for (current = list->head.next; current != &list->head;
current = current->next)
{
void *item;
mu_iterator_current (itr, &item);
buf[i++] = item;
buf[i++] = current->item;
if (i == nelem)
{
i = 0;
......@@ -59,7 +52,6 @@ mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data)
}
if (rc == 0 && i > 0 && i < nelem)
rc = map (buf, i, data);
mu_iterator_destroy (&itr);
free (buf);
return rc;
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2011 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, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <mailutils/errno.h>
#include <mailutils/sys/list.h>
int
mu_list_rfold (mu_list_t list, mu_list_folder_t fold, void *data, void *prev,
void *return_value)
{
struct list_data *current;
int status = 0;
if (list == NULL || fold == NULL)
return EINVAL;
if (return_value == NULL)
return MU_ERR_OUT_PTR_NULL;
for (current = list->head.prev; current != &list->head;
current = current->prev)
{
status = fold (current->item, data, prev, &prev);
if (status)
break;
}
*(void **) return_value = prev;
return status;
}
......@@ -388,6 +388,62 @@ ti
])
m4_popdef([MU_TEST_KEYWORDS])
# ------------------------------------------------------------
# Fold
# ------------------------------------------------------------
m4_define([MU_TEST_GROUP],[Fold])
m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ fold])
TESTLIST([empty list],[],
[fold
],
[NULL
])
TESTLIST([one element],[],
[add en
fold
],
[en
])
TESTLIST([many elements],[],
[add en to tre fire fem
fold
],
[entotrefirefem
])
m4_popdef([MU_TEST_KEYWORDS])
# ------------------------------------------------------------
# Reverse Fold
# ------------------------------------------------------------
m4_define([MU_TEST_GROUP],[Reverse Fold])
m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ rfold])
TESTLIST([empty list],[],
[rfold
],
[NULL
])
TESTLIST([one element],[],
[add en
rfold
],
[en
])
TESTLIST([many elements],[],
[add en to tre fire fem
rfold
],
[femfiretretoen
])
m4_popdef([MU_TEST_KEYWORDS])
dnl ------------------------------------------------------------
dnl Cleanup
......
......@@ -720,6 +720,60 @@ tail (size_t argc, mu_list_t list)
printf ("%s\n", text);
}
static int
fold_concat (void *item, void *data, void *prev, void **ret)
{
char *s;
size_t len = strlen (item);
size_t prevlen = 0;
if (prev)
prevlen = strlen (prev);
s = realloc (prev, len + prevlen + 1);
if (!s)
abort ();
strcpy (s + prevlen, item);
*ret = s;
return 0;
}
void
fold (mu_list_t list)
{
char *text = NULL;
int rc;
rc = mu_list_fold (list, fold_concat, NULL, NULL, &text);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_list_fold", NULL, rc);
else if (text)
{
printf ("%s\n", text);
free (text);
}
else
printf ("NULL\n");
}
void
rfold (mu_list_t list)
{
char *text = NULL;
int rc;
rc = mu_list_rfold (list, fold_concat, NULL, NULL, &text);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_list_fold", NULL, rc);
else if (text)
{
printf ("%s\n", text);
free (text);
}
else
printf ("NULL\n");
}
void
help ()
{
......@@ -739,6 +793,8 @@ help ()
printf ("ictl ins item [item*]\n");
printf ("ictl dir [backwards|forwards]\n");
printf ("map [-replace] NAME [ARGS]\n");
printf ("fold\n");
printf ("rfold\n");
printf ("print\n");
printf ("slice [-replace] num [num...]\n");
printf ("quit\n");
......@@ -813,6 +869,10 @@ shell (mu_list_t list)
print (list);
else if (strcmp (ws.ws_wordv[0], "cur") == 0)
cur (num, itr[num]);
else if (strcmp (ws.ws_wordv[0], "fold") == 0)
fold (list);
else if (strcmp (ws.ws_wordv[0], "rfold") == 0)
rfold (list);
else if (strcmp (ws.ws_wordv[0], "map") == 0)
{
int i;
......