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); ...@@ -238,7 +238,10 @@ typedef int (*mu_list_mapper_t) (void **_itmv, size_t _itmc, void *_call_data);
238 and until all elements from the array have been visited. 238 and until all elements from the array have been visited.
239 239
240 Mu_list_gmap returns 0 on success and a non-zero error code on failure. 240 Mu_list_gmap returns 0 on success and a non-zero error code on failure.
241 If _map returns non-zero, its return value is propagated to the caller. */ 241 If _map returns non-zero, its return value is propagated to the caller.
242
243 The _map function is not allowed to alter the _list.
244 */
242 245
243 int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem, 246 int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem,
244 void *_data); 247 void *_data);
...@@ -263,11 +266,56 @@ int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem, ...@@ -263,11 +266,56 @@ int mu_list_gmap (mu_list_t _list, mu_list_mapper_t _map, size_t _nelem,
263 MU_LIST_MAP_SKIP bit set, the _itmv[0] element is appended to the new 266 MU_LIST_MAP_SKIP bit set, the _itmv[0] element is appended to the new
264 list. If it has MU_LIST_MAP_STOP bit set, iteration is stopped 267 list. If it has MU_LIST_MAP_STOP bit set, iteration is stopped
265 immediately and any remaining elements in _list are ignored. 268 immediately and any remaining elements in _list are ignored.
269
270 The mapper function (_map) is not allowed to alter the _list.
266 */ 271 */
267 272
268 int mu_list_map (mu_list_t _list, mu_list_mapper_t _map, 273 int mu_list_map (mu_list_t _list, mu_list_mapper_t _map,
269 void *_data, size_t _nelem, 274 void *_data, size_t _nelem,
270 mu_list_t *_res); 275 mu_list_t *_res);
276
277 /* List fold */
278
279 typedef int (*mu_list_folder_t) (void *_item, void *_data,
280 void *_prev, void **_ret);
281
282 /* mu_list_fold iterates over list elements from first to last.
283 For each element it calls _fold with the following arguments:
284
285 _item - the current list element,
286 _data - call-specific data,
287 _prev - on the first call, _init; on subsequent calls,
288 points to the value returned from the previous call
289 to _fold in the _ret varialble,
290 _ret - memory location where to store the result of this
291 call.
292
293 When all elements have been visited, mu_list_fold stores the result
294 of the last _fold invocation (as returned in *_ret) in the memory
295 location pointed to by _return_value.
296
297 If _fold returns a non-zero value, mu_list_fold stops iteration and
298 returns this value. The *_return_value is filled in this case as
299 well.
300
301 Possible return codes:
302
303 0 - success,
304 EINVAL - _list or _fold is NULL,
305 MU_ERR_OUT_PTR_NULL - _return_code is NULL
306 other value - non-zero value returned by _fold.
307
308 The _fold function is not allowed to alter the list it is being applied
309 to.
310
311 The mu_list_rfold acts similarly, except that it iterates over list
312 elements from last to first.
313 */
314 int mu_list_fold (mu_list_t _list, mu_list_folder_t _fold, void *_data,
315 void *_init, void *_return_value);
316 int mu_list_rfold (mu_list_t _list, mu_list_folder_t _fold, void *_data,
317 void *_init, void *_return_value);
318
271 #ifdef __cplusplus 319 #ifdef __cplusplus
272 } 320 }
273 #endif 321 #endif
......
...@@ -25,6 +25,7 @@ liblist_la_SOURCES = \ ...@@ -25,6 +25,7 @@ liblist_la_SOURCES = \
25 create.c\ 25 create.c\
26 destroy.c\ 26 destroy.c\
27 empty.c\ 27 empty.c\
28 fold.c\
28 foreach.c\ 29 foreach.c\
29 get.c\ 30 get.c\
30 getcomp.c\ 31 getcomp.c\
...@@ -39,6 +40,7 @@ liblist_la_SOURCES = \ ...@@ -39,6 +40,7 @@ liblist_la_SOURCES = \
39 prepend.c\ 40 prepend.c\
40 remove.c\ 41 remove.c\
41 replace.c\ 42 replace.c\
43 rfold.c\
42 setcomp.c\ 44 setcomp.c\
43 setdestr.c\ 45 setdestr.c\
44 slice.c\ 46 slice.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <stdlib.h>
22 #include <mailutils/errno.h>
23 #include <mailutils/sys/list.h>
24
25 int
26 mu_list_fold (mu_list_t list, mu_list_folder_t fold, void *data, void *prev,
27 void *return_value)
28 {
29 struct list_data *current;
30 int status = 0;
31
32 if (list == NULL || fold == NULL)
33 return EINVAL;
34 if (return_value == NULL)
35 return MU_ERR_OUT_PTR_NULL;
36
37 for (current = list->head.next; current != &list->head;
38 current = current->next)
39 {
40 status = fold (current->item, data, prev, &prev);
41 if (status)
42 break;
43 }
44 *(void **) return_value = prev;
45 return status;
46 }
...@@ -27,28 +27,21 @@ int ...@@ -27,28 +27,21 @@ int
27 mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data) 27 mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data)
28 { 28 {
29 int rc; 29 int rc;
30 int status; 30 struct list_data *current;
31 mu_iterator_t itr;
32 void **buf; 31 void **buf;
33 size_t i; 32 size_t i;
34 33
35 if (!list || !map || nelem == 0) 34 if (!list || !map || nelem == 0)
36 return EINVAL; 35 return EINVAL;
37 rc = mu_list_get_iterator (list, &itr);
38 if (rc)
39 return status;
40 buf = calloc (nelem, sizeof (buf[0])); 36 buf = calloc (nelem, sizeof (buf[0]));
41 if (!buf) 37 if (!buf)
42 {
43 mu_iterator_destroy (&itr);
44 return ENOMEM; 38 return ENOMEM;
45 } 39
46 for (i = 0, mu_iterator_first (itr); !mu_iterator_is_done (itr); 40 i = 0;
47 mu_iterator_next (itr)) 41 for (current = list->head.next; current != &list->head;
42 current = current->next)
48 { 43 {
49 void *item; 44 buf[i++] = current->item;
50 mu_iterator_current (itr, &item);
51 buf[i++] = item;
52 if (i == nelem) 45 if (i == nelem)
53 { 46 {
54 i = 0; 47 i = 0;
...@@ -59,7 +52,6 @@ mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data) ...@@ -59,7 +52,6 @@ mu_list_gmap (mu_list_t list, mu_list_mapper_t map, size_t nelem, void *data)
59 } 52 }
60 if (rc == 0 && i > 0 && i < nelem) 53 if (rc == 0 && i > 0 && i < nelem)
61 rc = map (buf, i, data); 54 rc = map (buf, i, data);
62 mu_iterator_destroy (&itr);
63 free (buf); 55 free (buf);
64 return rc; 56 return rc;
65 } 57 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <stdlib.h>
22 #include <mailutils/errno.h>
23 #include <mailutils/sys/list.h>
24
25 int
26 mu_list_rfold (mu_list_t list, mu_list_folder_t fold, void *data, void *prev,
27 void *return_value)
28 {
29 struct list_data *current;
30 int status = 0;
31
32 if (list == NULL || fold == NULL)
33 return EINVAL;
34 if (return_value == NULL)
35 return MU_ERR_OUT_PTR_NULL;
36
37 for (current = list->head.prev; current != &list->head;
38 current = current->prev)
39 {
40 status = fold (current->item, data, prev, &prev);
41 if (status)
42 break;
43 }
44 *(void **) return_value = prev;
45 return status;
46 }
...@@ -388,6 +388,62 @@ ti ...@@ -388,6 +388,62 @@ ti
388 ]) 388 ])
389 389
390 m4_popdef([MU_TEST_KEYWORDS]) 390 m4_popdef([MU_TEST_KEYWORDS])
391 # ------------------------------------------------------------
392 # Fold
393 # ------------------------------------------------------------
394
395 m4_define([MU_TEST_GROUP],[Fold])
396 m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ fold])
397
398 TESTLIST([empty list],[],
399 [fold
400 ],
401 [NULL
402 ])
403
404 TESTLIST([one element],[],
405 [add en
406 fold
407 ],
408 [en
409 ])
410
411 TESTLIST([many elements],[],
412 [add en to tre fire fem
413 fold
414 ],
415 [entotrefirefem
416 ])
417
418 m4_popdef([MU_TEST_KEYWORDS])
419 # ------------------------------------------------------------
420 # Reverse Fold
421 # ------------------------------------------------------------
422
423 m4_define([MU_TEST_GROUP],[Reverse Fold])
424 m4_pushdef([MU_TEST_KEYWORDS],MU_TEST_KEYWORDS[ rfold])
425
426 TESTLIST([empty list],[],
427 [rfold
428 ],
429 [NULL
430 ])
431
432 TESTLIST([one element],[],
433 [add en
434 rfold
435 ],
436 [en
437 ])
438
439 TESTLIST([many elements],[],
440 [add en to tre fire fem
441 rfold
442 ],
443 [femfiretretoen
444 ])
445
446 m4_popdef([MU_TEST_KEYWORDS])
391 447
392 dnl ------------------------------------------------------------ 448 dnl ------------------------------------------------------------
393 dnl Cleanup 449 dnl Cleanup
......
...@@ -720,6 +720,60 @@ tail (size_t argc, mu_list_t list) ...@@ -720,6 +720,60 @@ tail (size_t argc, mu_list_t list)
720 printf ("%s\n", text); 720 printf ("%s\n", text);
721 } 721 }
722 722
723 static int
724 fold_concat (void *item, void *data, void *prev, void **ret)
725 {
726 char *s;
727 size_t len = strlen (item);
728 size_t prevlen = 0;
729
730 if (prev)
731 prevlen = strlen (prev);
732
733 s = realloc (prev, len + prevlen + 1);
734 if (!s)
735 abort ();
736 strcpy (s + prevlen, item);
737 *ret = s;
738 return 0;
739 }
740
741 void
742 fold (mu_list_t list)
743 {
744 char *text = NULL;
745 int rc;
746
747 rc = mu_list_fold (list, fold_concat, NULL, NULL, &text);
748 if (rc)
749 mu_diag_funcall (MU_DIAG_ERROR, "mu_list_fold", NULL, rc);
750 else if (text)
751 {
752 printf ("%s\n", text);
753 free (text);
754 }
755 else
756 printf ("NULL\n");
757 }
758
759 void
760 rfold (mu_list_t list)
761 {
762 char *text = NULL;
763 int rc;
764
765 rc = mu_list_rfold (list, fold_concat, NULL, NULL, &text);
766 if (rc)
767 mu_diag_funcall (MU_DIAG_ERROR, "mu_list_fold", NULL, rc);
768 else if (text)
769 {
770 printf ("%s\n", text);
771 free (text);
772 }
773 else
774 printf ("NULL\n");
775 }
776
723 void 777 void
724 help () 778 help ()
725 { 779 {
...@@ -739,6 +793,8 @@ help () ...@@ -739,6 +793,8 @@ help ()
739 printf ("ictl ins item [item*]\n"); 793 printf ("ictl ins item [item*]\n");
740 printf ("ictl dir [backwards|forwards]\n"); 794 printf ("ictl dir [backwards|forwards]\n");
741 printf ("map [-replace] NAME [ARGS]\n"); 795 printf ("map [-replace] NAME [ARGS]\n");
796 printf ("fold\n");
797 printf ("rfold\n");
742 printf ("print\n"); 798 printf ("print\n");
743 printf ("slice [-replace] num [num...]\n"); 799 printf ("slice [-replace] num [num...]\n");
744 printf ("quit\n"); 800 printf ("quit\n");
...@@ -813,6 +869,10 @@ shell (mu_list_t list) ...@@ -813,6 +869,10 @@ shell (mu_list_t list)
813 print (list); 869 print (list);
814 else if (strcmp (ws.ws_wordv[0], "cur") == 0) 870 else if (strcmp (ws.ws_wordv[0], "cur") == 0)
815 cur (num, itr[num]); 871 cur (num, itr[num]);
872 else if (strcmp (ws.ws_wordv[0], "fold") == 0)
873 fold (list);
874 else if (strcmp (ws.ws_wordv[0], "rfold") == 0)
875 rfold (list);
816 else if (strcmp (ws.ws_wordv[0], "map") == 0) 876 else if (strcmp (ws.ws_wordv[0], "map") == 0)
817 { 877 {
818 int i; 878 int i;
......