1 /* Copyright (C) 1995,1996,1997 Free Software Foundation, Inc.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
42 /* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
50 #include "scm_validate.h"
55 #define var_start(x, y) va_start(x, y)
58 #define var_start(x, y) va_start(x)
64 /* SCM_P won't help us deal with varargs here. */
67 scm_listify (SCM elt
, ...)
70 scm_listify (elt
, va_alist
)
82 while (elt
!= SCM_UNDEFINED
)
84 *pos
= scm_cons (elt
, SCM_EOL
);
85 pos
= SCM_CDRLOC (*pos
);
86 elt
= va_arg (foo
, SCM
);
92 GUILE_PROC(scm_list
, "list", 0, 0, 1,
95 #define FUNC_NAME s_scm_list
102 GUILE_PROC (scm_list_star
, "list*", 1, 0, 1,
105 #define FUNC_NAME s_scm_list_star
109 SCM prev
= arg
= scm_cons (arg
, rest
);
110 while (SCM_NIMP (SCM_CDR (rest
)))
113 rest
= SCM_CDR (rest
);
115 SCM_SETCDR (prev
, SCM_CAR (rest
));
123 /* general questions about lists --- null?, list?, length, etc. */
125 GUILE_PROC(scm_null_p
, "null?", 1, 0, 0,
128 #define FUNC_NAME s_scm_null_p
130 return SCM_BOOL(SCM_NULLP(x
));
134 GUILE_PROC(scm_list_p
, "list?", 1, 0, 0,
137 #define FUNC_NAME s_scm_list_p
139 return SCM_BOOL(scm_ilength(x
)>=0);
144 /* Return the length of SX, or -1 if it's not a proper list.
145 This uses the "tortoise and hare" algorithm to detect "infinitely
146 long" lists (i.e. lists with cycles in their cdrs), and returns -1
147 if it does find one. */
152 register SCM tortoise
= sx
;
153 register SCM hare
= sx
;
156 if (SCM_IMP(hare
)) return SCM_NULLP(hare
) ? i
: -1;
157 if (SCM_NCONSP(hare
)) return -1;
158 hare
= SCM_CDR(hare
);
160 if (SCM_IMP(hare
)) return SCM_NULLP(hare
) ? i
: -1;
161 if (SCM_NCONSP(hare
)) return -1;
162 hare
= SCM_CDR(hare
);
164 /* For every two steps the hare takes, the tortoise takes one. */
165 tortoise
= SCM_CDR(tortoise
);
167 while (hare
!= tortoise
);
169 /* If the tortoise ever catches the hare, then the list must contain
174 GUILE_PROC(scm_length
, "length", 1, 0, 0,
177 #define FUNC_NAME s_scm_length
180 SCM_VALIDATE_LIST_COPYLEN(1,lst
,i
);
181 return SCM_MAKINUM (i
);
187 /* appending lists */
189 GUILE_PROC (scm_append
, "append", 0, 0, 1,
191 "A destructive version of @code{append} (@pxref{Pairs and Lists,,,r4rs,
192 The Revised^4 Report on Scheme}). The cdr field of each list's final
193 pair is changed to point to the head of the next list, so no consing is
194 performed. Return a pointer to the mutated list.")
195 #define FUNC_NAME s_scm_append
198 SCM
*lloc
= &res
, arg
;
200 SCM_VALIDATE_NULL(SCM_ARGn
, args
);
203 SCM_VALIDATE_CONS(SCM_ARGn
, args
);
206 args
= SCM_CDR(args
);
209 SCM_VALIDATE_NULL(SCM_ARGn
, args
);
212 SCM_VALIDATE_CONS(SCM_ARGn
, args
);
213 for(;SCM_NIMP(arg
);arg
= SCM_CDR(arg
)) {
214 SCM_VALIDATE_CONS(SCM_ARGn
, arg
);
215 *lloc
= scm_cons(SCM_CAR(arg
), SCM_EOL
);
216 lloc
= SCM_CDRLOC(*lloc
);
218 SCM_VALIDATE_NULL(SCM_ARGn
, arg
);
224 GUILE_PROC (scm_append_x
, "append!", 0, 0, 1,
227 #define FUNC_NAME s_scm_append_x
231 if (SCM_NULLP(args
)) return SCM_EOL
;
233 args
= SCM_CDR(args
);
234 if (SCM_NULLP(args
)) return arg
;
235 if (SCM_NULLP(arg
)) goto tail
;
236 SCM_VALIDATE_NIMCONS(SCM_ARG1
,arg
);
237 SCM_SETCDR (scm_last_pair (arg
), scm_append_x (args
));
243 GUILE_PROC(scm_last_pair
, "last-pair", 1, 0, 0,
245 "Return a pointer to the last pair in @var{lst}, signalling an error if
246 @var{lst} is circular.")
247 #define FUNC_NAME s_scm_last_pair
249 register SCM res
= sx
;
255 SCM_VALIDATE_NIMCONS(SCM_ARG1
,res
);
258 if (SCM_IMP(x
) || SCM_NCONSP(x
)) return res
;
261 if (SCM_IMP(x
) || SCM_NCONSP(x
)) return res
;
264 SCM_ASSERT(x
!= sx
, sx
, SCM_ARG1
, FUNC_NAME
);
270 /* reversing lists */
272 GUILE_PROC (scm_reverse
, "reverse", 1, 0, 0,
274 "A destructive version of @code{reverse} (@pxref{Pairs and Lists,,,r4rs,
275 The Revised^4 Report on Scheme}). The cdr of each cell in @var{lst} is
276 modified to point to the previous list element. Return a pointer to the
277 head of the reversed list.
279 Caveat: because the list is modified in place, the tail of the original
280 list now becomes its head, and the head of the original list now becomes
281 the tail. Therefore, the @var{lst} symbol to which the head of the
282 original list was bound now points to the tail. To ensure that the head
283 of the modified list is not lost, it is wise to save the return value of
285 #define FUNC_NAME s_scm_reverse
291 SCM_VALIDATE_CONS(1,ls
);
292 res
= scm_cons (SCM_CAR (p
), res
);
296 SCM_VALIDATE_CONS(1,ls
);
297 res
= scm_cons (SCM_CAR (p
), res
);
301 scm_misc_error (FUNC_NAME
, "Circular structure: %S", SCM_LIST1 (ls
));
304 SCM_VALIDATE_NULL(1,ls
);
309 GUILE_PROC (scm_reverse_x
, "reverse!", 1, 1, 0,
310 (SCM ls
, SCM new_tail
),
312 #define FUNC_NAME s_scm_reverse_x
315 SCM_ASSERT (scm_ilength (ls
) >= 0, ls
, SCM_ARG1
, FUNC_NAME
);
316 if (SCM_UNBNDP (new_tail
))
319 SCM_ASSERT (scm_ilength (new_tail
) >= 0, new_tail
, SCM_ARG2
, FUNC_NAME
);
321 while (SCM_NIMP (ls
))
323 old_tail
= SCM_CDR (ls
);
324 SCM_SETCDR (ls
, new_tail
);
334 /* indexing lists by element number */
336 GUILE_PROC(scm_list_ref
, "list-ref", 2, 0, 0,
339 #define FUNC_NAME s_scm_list_ref
342 SCM_VALIDATE_INT_MIN_COPY(2,k
,0,i
);
344 SCM_ASRTGO(SCM_NIMP(lst
) && SCM_CONSP(lst
), erout
);
348 SCM_ASSERT(SCM_NIMP(lst
) && SCM_CONSP(lst
),
349 SCM_NULLP(lst
)?k
:lst
, SCM_NULLP(lst
)?SCM_OUTOFRANGE
:SCM_ARG1
, FUNC_NAME
);
354 GUILE_PROC(scm_list_set_x
, "list-set!", 3, 0, 0,
355 (SCM lst
, SCM k
, SCM val
),
356 "Set the @var{k}th element of @var{lst} to @var{val}.")
357 #define FUNC_NAME s_scm_list_set_x
360 SCM_VALIDATE_INT_MIN_COPY(2,k
,0,i
);
362 SCM_ASRTGO(SCM_NIMP(lst
) && SCM_CONSP(lst
), erout
);
366 SCM_ASSERT(SCM_NIMP(lst
) && SCM_CONSP(lst
),
367 SCM_NULLP(lst
)?k
:lst
, SCM_NULLP(lst
)?SCM_OUTOFRANGE
:SCM_ARG1
, FUNC_NAME
);
368 SCM_SETCAR (lst
, val
);
374 SCM_REGISTER_PROC(s_list_cdr_ref
, "list-cdr-ref", 2, 0, 0, scm_list_tail
);
376 GUILE_PROC(scm_list_tail
, "list-tail", 2, 0, 0,
378 "Return the \"tail\" of @var{lst} beginning with its @var{k}th element.
379 The first element of the list is considered to be element 0.
381 @code{list-cdr-ref} and @code{list-tail} are identical. It may help to
382 think of @code{list-cdr-ref} as accessing the @var{k}th cdr of the list,
383 or returning the results of cdring @var{k} times down @var{lst}.")
384 #define FUNC_NAME s_scm_list_tail
387 SCM_VALIDATE_INT_MIN_COPY(2,k
,0,i
);
389 SCM_VALIDATE_NIMCONS(1,lst
);
397 GUILE_PROC(scm_list_cdr_set_x
, "list-cdr-set!", 3, 0, 0,
398 (SCM lst
, SCM k
, SCM val
),
399 "Set the @var{k}th cdr of @var{lst} to @var{val}.")
400 #define FUNC_NAME s_scm_list_cdr_set_x
403 SCM_VALIDATE_INT_MIN_COPY(2,k
,0,i
);
405 SCM_ASRTGO(SCM_NIMP(lst
) && SCM_CONSP(lst
), erout
);
409 SCM_ASSERT(SCM_NIMP(lst
) && SCM_CONSP(lst
),
410 SCM_NULLP(lst
)?k
:lst
, SCM_NULLP(lst
)?SCM_OUTOFRANGE
:SCM_ARG1
, FUNC_NAME
);
411 SCM_SETCDR (lst
, val
);
418 /* copying lists, perhaps partially */
420 GUILE_PROC(scm_list_head
, "list-head", 2, 0, 0,
422 "Copy the first @var{k} elements from @var{lst} into a new list, and
424 #define FUNC_NAME s_scm_list_head
430 SCM_VALIDATE_INT_MIN_COPY(2,k
,0,i
);
435 SCM_VALIDATE_NIMCONS(1,lst
);
436 *pos
= scm_cons (SCM_CAR (lst
), SCM_EOL
);
437 pos
= SCM_CDRLOC (*pos
);
445 GUILE_PROC (scm_list_copy
, "list-copy", 1, 0, 0,
447 "Return a (newly-created) copy of @var{lst}.")
448 #define FUNC_NAME s_scm_list_copy
458 while (SCM_NIMP (from_here
) && SCM_CONSP (from_here
))
461 c
= scm_cons (SCM_CAR (from_here
), SCM_CDR (from_here
));
463 fill_here
= SCM_CDRLOC (c
);
464 from_here
= SCM_CDR (from_here
);
471 /* membership tests (memq, memv, etc.) */
473 GUILE_PROC (scm_sloppy_memq
, "sloppy-memq", 2, 0, 0,
475 "@deffnx primitive sloppy-memv
476 @deffnx primitive sloppy-member
477 These procedures behave like @code{memq}, @code{memv} and @code{member}
478 (@pxref{Pairs and Lists,,,r4rs, The Revised^4 Report on Scheme}), but do
479 not perform any type or error checking. Their use is recommended only
480 in writing Guile internals, not for high-level Scheme programs.")
481 #define FUNC_NAME s_scm_sloppy_memq
483 for(; SCM_NIMP(lst
) && SCM_CONSP (lst
); lst
= SCM_CDR(lst
))
493 GUILE_PROC (scm_sloppy_memv
, "sloppy-memv", 2, 0, 0,
496 #define FUNC_NAME s_scm_sloppy_memv
498 for(; SCM_NIMP(lst
) && SCM_CONSP (lst
); lst
= SCM_CDR(lst
))
500 if (SCM_BOOL_F
!= scm_eqv_p (SCM_CAR(lst
), x
))
508 GUILE_PROC (scm_sloppy_member
, "sloppy-member", 2, 0, 0,
511 #define FUNC_NAME s_scm_sloppy_member
513 for(; SCM_NIMP(lst
) && SCM_CONSP (lst
); lst
= SCM_CDR(lst
))
515 if (SCM_BOOL_F
!= scm_equal_p (SCM_CAR(lst
), x
))
524 GUILE_PROC(scm_memq
, "memq", 2, 0, 0,
527 #define FUNC_NAME s_scm_memq
530 SCM_VALIDATE_LIST(2,lst
);
531 answer
= scm_sloppy_memq (x
, lst
);
532 return (answer
== SCM_EOL
) ? SCM_BOOL_F
: answer
;
538 GUILE_PROC(scm_memv
, "memv", 2, 0, 0,
541 #define FUNC_NAME s_scm_memv
544 SCM_VALIDATE_LIST(2,lst
);
545 answer
= scm_sloppy_memv (x
, lst
);
546 return (answer
== SCM_EOL
) ? SCM_BOOL_F
: answer
;
551 GUILE_PROC(scm_member
, "member", 2, 0, 0,
554 #define FUNC_NAME s_scm_member
557 SCM_VALIDATE_LIST(2,lst
);
558 answer
= scm_sloppy_member (x
, lst
);
559 return (answer
== SCM_EOL
) ? SCM_BOOL_F
: answer
;
565 /* deleting elements from a list (delq, etc.) */
567 GUILE_PROC(scm_delq_x
, "delq!", 2, 0, 0,
569 "@deffnx primitive delv! item lst
570 @deffnx primitive delete! item lst
571 These procedures are destructive versions of @code{delq}, @code{delv}
572 and @code{delete}: they modify the pointers in the existing @var{lst}
573 rather than creating a new list. Caveat evaluator: Like other
574 destructive list functions, these functions cannot modify the binding of
575 @var{lst}, and so cannot be used to delete the first element of
576 @var{lst} destructively.")
577 #define FUNC_NAME s_scm_delq_x
582 for (prev
= &lst
, walk
= lst
;
583 SCM_NIMP (walk
) && SCM_CONSP (walk
);
584 walk
= SCM_CDR (walk
))
586 if (SCM_CAR (walk
) == item
)
587 *prev
= SCM_CDR (walk
);
589 prev
= SCM_CDRLOC (walk
);
597 GUILE_PROC(scm_delv_x
, "delv!", 2, 0, 0,
600 #define FUNC_NAME s_scm_delv_x
605 for (prev
= &lst
, walk
= lst
;
606 SCM_NIMP (walk
) && SCM_CONSP (walk
);
607 walk
= SCM_CDR (walk
))
609 if (SCM_BOOL_F
!= scm_eqv_p (SCM_CAR (walk
), item
))
610 *prev
= SCM_CDR (walk
);
612 prev
= SCM_CDRLOC (walk
);
621 GUILE_PROC(scm_delete_x
, "delete!", 2, 0, 0,
624 #define FUNC_NAME s_scm_delete_x
629 for (prev
= &lst
, walk
= lst
;
630 SCM_NIMP (walk
) && SCM_CONSP (walk
);
631 walk
= SCM_CDR (walk
))
633 if (SCM_BOOL_F
!= scm_equal_p (SCM_CAR (walk
), item
))
634 *prev
= SCM_CDR (walk
);
636 prev
= SCM_CDRLOC (walk
);
647 GUILE_PROC (scm_delq
, "delq", 2, 0, 0,
649 "@deffnx primitive delv item lst
650 @deffnx primitive delete item lst
651 Return a newly-created copy of @var{lst} with @var{item} removed. These
652 procedures mirror @code{memq}, @code{memv} and @code{member}:
653 @code{delq} compares elements of @var{lst} against @var{item} with
654 @code{eq?}, @code{delv} uses @code{eqv?} and @code{delete} uses @code{equal?}")
655 #define FUNC_NAME s_scm_delq
657 SCM copy
= scm_list_copy (lst
);
658 return scm_delq_x (item
, copy
);
662 GUILE_PROC (scm_delv
, "delv", 2, 0, 0,
665 #define FUNC_NAME s_scm_delv
667 SCM copy
= scm_list_copy (lst
);
668 return scm_delv_x (item
, copy
);
672 GUILE_PROC (scm_delete
, "delete", 2, 0, 0,
675 #define FUNC_NAME s_scm_delete
677 SCM copy
= scm_list_copy (lst
);
678 return scm_delete_x (item
, copy
);
683 GUILE_PROC(scm_delq1_x
, "delq1!", 2, 0, 0,
686 #define FUNC_NAME s_scm_delq1_x
691 for (prev
= &lst
, walk
= lst
;
692 SCM_NIMP (walk
) && SCM_CONSP (walk
);
693 walk
= SCM_CDR (walk
))
695 if (SCM_CAR (walk
) == item
)
697 *prev
= SCM_CDR (walk
);
701 prev
= SCM_CDRLOC (walk
);
709 GUILE_PROC(scm_delv1_x
, "delv1!", 2, 0, 0,
712 #define FUNC_NAME s_scm_delv1_x
717 for (prev
= &lst
, walk
= lst
;
718 SCM_NIMP (walk
) && SCM_CONSP (walk
);
719 walk
= SCM_CDR (walk
))
721 if (SCM_BOOL_F
!= scm_eqv_p (SCM_CAR (walk
), item
))
723 *prev
= SCM_CDR (walk
);
727 prev
= SCM_CDRLOC (walk
);
735 GUILE_PROC(scm_delete1_x
, "delete1!", 2, 0, 0,
738 #define FUNC_NAME s_scm_delete1_x
743 for (prev
= &lst
, walk
= lst
;
744 SCM_NIMP (walk
) && SCM_CONSP (walk
);
745 walk
= SCM_CDR (walk
))
747 if (SCM_BOOL_F
!= scm_equal_p (SCM_CAR (walk
), item
))
749 *prev
= SCM_CDR (walk
);
753 prev
= SCM_CDRLOC (walk
);