Generic_Window_Manager/wl_list.c

688 lines
17 KiB
C

/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
* Copyright 1989 Massachusetts Institute of Technology
*/
/*********************\
* *
* WOOL_OBJECT List *
* BODY *
* *
\*********************/
#include "EXTERN.h"
#include <stdio.h>
#include "wool.h"
#include "wl_number.h"
#include "wl_atom.h"
#include "wl_name.h"
#include "wl_coll.h"
#include "wl_func.h"
#include "INTERN.h"
#include "wl_list.h"
/*
* Constructor:
* used mainly in parser, called by WLList_make
*/
WOOL_List
WLList_make(col)
WOOL_Collection col;
{
if (col -> size) {
WOOL_List object = (WOOL_List)
Malloc(sizeof(struct _WOOL_List) +
((col -> size -1) * sizeof(WOOL_OBJECT)));
zrt_put(object);
object -> type = WLList;
copy_n_objects(col -> list, object -> list, col -> size);
object -> size = col -> size;
return object;
} else { /* a list of size 0 is just NIL */
return (WOOL_List) NIL;
}
}
/* makes a list with size slots, to be filled by the C programmer */
WOOL_List
wool_list_make(size)
int size;
{
WOOL_List wl_list;
wl_list = (WOOL_List) Malloc(sizeof(struct _WOOL_List) +
(size -1) * sizeof(WOOL_OBJECT));
zrt_put(wl_list);
wl_list -> type = WLList;
wl_list -> size = size;
return wl_list;
}
/* makes a list of argc, argv WOOL_OBJECTS */
WOOL_List
wool_list_make_from_evaluated_array(argc, argv)
int argc;
WOOL_OBJECT argv[];
{
WOOL_List wl_list;
int i;
wl_list = (WOOL_List) Malloc(sizeof(struct _WOOL_List) +
(argc - 1) * sizeof(WOOL_OBJECT));
zrt_put(wl_list);
wl_list -> type = WLList;
wl_list -> size = argc;
for (i = 0; i < argc; i++)
increase_reference(wl_list -> list[i] =
WOOL_send(WOOL_eval, argv[i], (argv[i])));
return wl_list;
}
/* externally callable list-make:
* (list-make n elements...)
*/
WOOL_OBJECT
wool_list_make_from_wool(argc, argv)
int argc;
WOOL_OBJECT argv[];
{
WOOL_List wl_list;
int i;
if (argc < 1)
wool_error(BAD_NUMBER_OF_ARGS, argc);
must_be_number(argv[0], 0);
if (((WOOL_Number) argv[0]) -> number) {
wl_list = wool_list_make(((WOOL_Number) argv[0]) -> number);
if (argc == 1)
for (i = 0; i < wl_list -> size; i++)
increase_reference(wl_list -> list[i] = NIL);
else
for (i = 0; i < wl_list -> size; i++)
increase_reference(wl_list -> list[i] =
argv[(i % (argc - 1)) + 1]);
return (WOOL_OBJECT) wl_list;
} else {
return NIL;
}
}
/*
* WLList_eval:
* the heart of the interpreter:
* evaluating a list is calling the function associated with car by
* sending WOOL_execute to the CAR, with the list of parameters.
*/
WOOL_OBJECT
WLList_eval(obj)
WOOL_List obj;
{
WOOL_OBJECT result;
calling_function_push(obj);
#ifdef USER_DEBUG
if (wool_tracing_on) {
wool_tracing_level++;
wool_put_spaces(wool_tracing_level);
wool_puts("-> ");
wool_print(obj);
wool_puts("\n");
if (wool_tracing_on_EXPR) {
wool_tracing_on = 0;
eval(wool_tracing_on_EXPR);
wool_tracing_on = 1;
}
result = WOOL_send(WOOL_execute, (*(obj -> list)),
(*(obj -> list), obj));
if (wool_tracing_on_EXPR) {
wool_tracing_on = 0;
eval(wool_tracing_on_EXPR);
if (wool_still_tracing)
wool_tracing_on = 1;
else
wool_still_tracing = 1;
}
wool_put_spaces(wool_tracing_level);
wool_puts("<- ");
wool_print(result);
wool_puts("\n");
wool_tracing_level--;
} else
#endif /* USER_DEBUG */
{
#ifdef DEBUG /* stack overflow check */
if ((calling_function_current - calling_function_stack) >= 10000) {
printf("Stack size is %d!\n", (calling_function_current
- calling_function_stack));
stop_if_in_dbx();
}
#endif /* DEBUG */
result = WOOL_send(WOOL_execute, (*(obj -> list)),
(*(obj -> list), obj));
}
calling_function_pop();
return result;
}
/*
* WLList_print:
* classical: "(a b c d)"
*/
WOOL_OBJECT
WLList_print(obj)
WOOL_List obj;
{
int i;
WOOL_OBJECT *p = obj -> list;
wool_putchar('(');
if(++wool_print_level <= wool_max_print_level) {
for (i = 0; i < obj -> size; i++, p++) {
if (i)
wool_putchar(' ');
WOOL_send(WOOL_print, *p, (*p));
}
}else{
wool_puts("...");
}
wool_print_level--;
wool_putchar(')');
return (WOOL_OBJECT) obj;
}
/*
* freeing a list decreases the reference count of all the elements before
* freeing itself!
*/
WOOL_OBJECT
WLList_free(obj)
WOOL_List obj;
{
WOOL_OBJECT *last = obj -> list + obj -> size, *list = obj -> list;
while (list < last) {
decrease_reference(*list);
list++;
}
Free(obj);
return NULL;
}
/*
* executing a list is evaluating it and sending execute to the result
*/
WOOL_OBJECT
WLList_execute(obj, list)
WOOL_List obj;
WOOL_List list;
{
WOOL_OBJECT eval = WLList_eval(obj);
if (eval -> type != WLList) {
return WOOL_send(WOOL_execute, eval, (eval, list));
} else {
return (wool_error(UNDEFINED_FUNCTION, obj));
}
}
/*
* equality of two lists is equality of their elements
*/
WOOL_OBJECT
WLList_equal(l1, l2)
WOOL_List l1,l2;
{
int i;
if ((l2 -> type != l1 -> type)
|| (l2 -> size != l1 -> size))
return NIL;
for (i = 0; i < l1 -> size; i++) {
if (WOOL_send(WOOL_equal, l1 -> list[i],
(l1 -> list[i], l2 -> list[i])) == NIL)
return NIL;
}
return (WOOL_OBJECT) l1;
}
WOOL_OBJECT *
wool_flatten_pairlist(argc, argv)
int argc;
WOOL_List *argv;
{
WOOL_OBJECT *list =
(WOOL_OBJECT *) Malloc(sizeof(WOOL_OBJECT) * 2 * argc);
int i;
for (i = 0; i < argc; i++) {
if ((argv[i] -> type != WLList) || (argv[i] -> size != 2))
return (WOOL_OBJECT *) wool_error(BAD_LOCAL_SYNTAX, "");
list[i * 2] = argv[i] -> list[0];
list[i * 2 + 1] = argv[i] -> list[1];
}
return list;
}
/*****************************\
* *
* List manipulation routines *
* *
\*****************************/
/*
* returns sublist ifrom... ito
* (sublist from to list)
* from included, to excluded
*/
WOOL_OBJECT
WLList_sub(argc, argv)
int argc;
WOOL_List argv[];
{
WOOL_List newlist;
int from, to, i;
if (argc != 3)
wool_error(BAD_NUMBER_OF_ARGS, argc);
must_be_number(argv[0], 0);
must_be_number(argv[1], 1);
must_be_or_nil(WLList, argv[2], 2);
from = ((WOOL_Number) argv[0]) -> number;
to = ((WOOL_Number) argv[1]) -> number;
if (from >= to)
return NIL;
newlist = wool_list_make(to - from);
for (i = 0; i < newlist -> size; i++)
if (i + from < argv[2] -> size) {
increase_reference(newlist -> list[i] =
argv[2] -> list[i + from]);
} else {
increase_reference(newlist -> list[i] = NIL);
}
return (WOOL_OBJECT) newlist;
}
WOOL_OBJECT
WLList_concat(argc,argv)
int argc;
WOOL_List argv[];
{
WOOL_List newlist;
int i, newsize = 0, size;
for (i = 0; i < argc; i++) {
must_be_or_nil(WLList, argv[i], i);
newsize += ((argv[i] == (WOOL_List) NIL) ? 0 : argv[i] -> size);
}
if (!newsize)
return NIL;
newlist = wool_list_make(newsize);
newsize = 0;
for (i = 0; i < argc; i++) {
if (size = ((argv[i] == (WOOL_List) NIL) ? 0 : argv[i] -> size))
copy_n_objects(argv[i] -> list, &(newlist -> list)[newsize],
size);
newsize += size;
}
return (WOOL_OBJECT) newlist;
}
WOOL_List
WLList_physically_append(list, key, value)
WOOL_List list;
WOOL_OBJECT key;
WOOL_OBJECT value;
{
WOOL_List old_list = list;
if (key -> type == WLNumber) {
list = (WOOL_List) Realloc(list, sizeof(struct _WOOL_List) +
list -> size * sizeof(WOOL_OBJECT));
} else {
list = (WOOL_List) Realloc(list, sizeof(struct _WOOL_List) +
(list -> size + 1) * sizeof(WOOL_OBJECT));
increase_reference(list -> list[list -> size] = key);
list -> size ++;
}
increase_reference(list -> list[list -> size] = value);
list -> size ++;
if (list != old_list && !(REF(list) & 1)) { /* old list was in zrt! */
zrt_replace_element(old_list, list);
}
return list;
}
int
WLList_length(list)
WOOL_List list;
{
if (list == (WOOL_List) NIL)
return 0;
else
return list -> size;
}
/*
* (# n list) gives n-th element (nil if out bounds) returns obj
* (# n list obj) sets n-th element (increasing size if needed) returns
* newlist
* referencing via an atom is like giving the n tof the position after atom
* list can also be an atom or a wob
*/
#ifdef GWM
#include "EXTERN.h"
#include "gwm.h" /* TO_DO remove and treat as method */
#endif /* GWM */
WOOL_OBJECT
WLList_nth(argc, argv)
int argc;
WOOL_List argv[];
{
WOOL_List newlist, list;
int size, newsize, i;
int position, symbolic = 0;
if (argc < 2 || argc > 3)
return wool_error(BAD_NUMBER_OF_ARGS, argc);
if (argv[1] -> type == WLList || argv[1] == (WOOL_List) NIL) {
list = argv[1];
#ifdef GWM
} else if (argv[1] -> type == WLNumber) { /* WOB */
if (!WobIsValid(((WOOL_Number) argv[1]) -> number)
|| !((Wob) ((WOOL_Number) argv[1])->number) -> property)
return NIL;
list = (WOOL_List)
((Wob) ((WOOL_Number) argv[1]) -> number) -> property;
#endif /* GWM */
} else if (argv[1] -> type == WLAtom || argv[1] -> type == WLName) {
list = (WOOL_List) WOOL_send(WOOL_eval, argv[1], (argv[1]));
must_be_or_nil(WLList, list, 1);
} else {
bad_argument(argv[1], 1, "list or pointer to list");
}
size = (list == (WOOL_List) NIL ? 0 : list -> size);
if (argv[0] -> type == WLNumber)
position = ((WOOL_Number) argv[0]) -> number;
else {
symbolic = 1;
position = size + 1;
for (i = 0; i < size; i++) {
if (argv[0] == (WOOL_List) list -> list[i]) {
position = i + 1;
break;
}
}
}
if (argc == 2) { /* GET */
if (position < 0 || position >= size)
return NIL;
else
return (list) -> list[position];
} else { /* SET */
newsize = Max(size, position + 1);
newlist = wool_list_make(newsize);
if (size)
copy_n_objects(&(list -> list)[0], newlist -> list, size);
if (newsize > size) {
for (i = size; i < newsize - symbolic; i++)
increase_reference(newlist -> list[i] = NIL);
} else {
decrease_reference(newlist -> list[position]);
}
if (symbolic) {
if (size < position)
increase_reference(newlist -> list[position - 1] =
(WOOL_OBJECT) argv[0]);
increase_reference(newlist -> list[position] =
(WOOL_OBJECT) argv[2]);
} else {
increase_reference(newlist -> list[position] =
(WOOL_OBJECT) argv[2]);
}
return (WOOL_OBJECT) newlist;
}
}
/* physical replacement of an element of a list
* succeeds only if there is room, else returns ()
* returns list
*/
WOOL_OBJECT
WLList_replace_nth(argc, argv)
int argc;
WOOL_List argv[];
{
int size, i;
int position = 0;
WOOL_List list, *list_ptr;
if (argc != 3)
return wool_error(BAD_NUMBER_OF_ARGS, argc);
if (argv[1] -> type == WLList || argv[1] == (WOOL_List) NIL) {
list = argv[1];
list_ptr = NULL;
#ifdef GWM
} else if (argv[1] -> type == WLNumber) {/* WOB */
if (!WobIsValid(((WOOL_Number) argv[1]) -> number)
|| !((Wob) ((WOOL_Number) argv[1])->number) -> property)
return NIL;
list_ptr = (WOOL_List*)&
((Wob) ((WOOL_Number) argv[1])->number) -> property;
list = *list_ptr;
must_be_or_nil(WLList, list, 1);
#endif /* GWM */
} else if (argv[1] -> type == WLAtom) {
list_ptr = (WOOL_List*)& ((WOOL_Atom) argv[1])->c_val;
list = *list_ptr;
must_be_or_nil(WLList, list, 1);
} else if (argv[1] -> type == WLName) {
list_ptr = (WOOL_List *) WLName_slot(argv[1]);
list = *list_ptr;
must_be_or_nil(WLList, list, 1);
} else {
bad_argument(argv[1], 1, "list or pointer to list");
}
size = (list == (WOOL_List) NIL ? 0 : list -> size);
if (argv[0] -> type == WLNumber)
position = Max(0, ((WOOL_Number) argv[0]) -> number);
else {
position = size + 1;
for (i = 0; i < size; i++) {
if (argv[0] == (WOOL_List) list -> list[i]) {
position = i + 1;
break;
}
}
}
if (position >= size) { /* increase size */
if (list_ptr) {
if (REF(list) >= 4) {/* 2 or more objs point to it */
decrease_reference(list);
increase_reference(*list_ptr = list =
(WOOL_List) WLList_nth(argc, argv));
} else { /* pointed by one object */
*list_ptr = list =
WLList_physically_append(list, argv[0], argv[2]);
}
} else { /* cannot resize a non-pointed to list */
wool_error("Could not modify %s\n", "list");
}
} else { /* replace an existing element */
if (list_ptr && REF(list) >= 4) { /* duplicate first */
decrease_reference(list);
increase_reference(*list_ptr = list =
(WOOL_List) WLList_nth(argc, argv));
} else { /* physical modif */
decrease_reference(list -> list[position]);
increase_reference(list -> list[position]
= (WOOL_OBJECT) argv[2]);
}
}
return (WOOL_OBJECT) list;
}
/* physical deletion of an element of a list
* succeeds only if there is room, else returns ()
* returns list
*/
WOOL_OBJECT
WLList_delete_nth(key, wl_list)
WOOL_OBJECT key;
WOOL_List wl_list;
{
int size, i;
int position = 0;
WOOL_List list, *list_ptr;
if (wl_list -> type == WLList || wl_list == (WOOL_List) NIL) {
list = wl_list;
list_ptr = NULL;
#ifdef GWM
} else if (wl_list -> type == WLNumber) {/* WOB */
if (!WobIsValid(((WOOL_Number) wl_list) -> number)
|| !((Wob) ((WOOL_Number) wl_list)->number) -> property)
return NIL;
list_ptr = (WOOL_List*)&
((Wob) ((WOOL_Number) wl_list) -> number) -> property;
list = *list_ptr;
must_be_or_nil(WLList, list, 1);
#endif /* GWM */
} else if (wl_list -> type == WLAtom) {
list_ptr = (WOOL_List*) & ((WOOL_Atom) wl_list) -> c_val;
list = *list_ptr;
must_be_or_nil(WLList, list, 1);
} else if (wl_list -> type == WLName) {
list_ptr = (WOOL_List *) WLName_slot(wl_list);
list = *list_ptr;
must_be_or_nil(WLList, list, 1);
} else {
bad_argument(wl_list, 1, "list or pointer to list");
}
size = (list == (WOOL_List) NIL ? 0 : list -> size);
if (key -> type == WLNumber)
position = Max(0, ((WOOL_Number) key) -> number);
else {
position = size + 1;
for (i = 0; i < size; i++) {
if (key == list -> list[i]) {
position = i + 1;
break;
}
}
}
if (position < size) { /* increase size */
if (list_ptr && REF(list) >= 4) { /* duplicate first */
decrease_reference(list);
increase_reference(*list_ptr = list =
(WOOL_List) WLList_copy(list));
}
/* delete elements */
{
int i;
int number = (key -> type == WLNumber ? 1 : 2);
decrease_reference(list -> list[position - number + 1]);
list -> size -= number;
for (i = position - number + 1; i < list -> size; i++)
list -> list[i] = list -> list[i + number];
}
}
if (list -> size)
return (WOOL_OBJECT) list;
else
return NIL;
}
/* the quicksort of a list
*/
static WOOL_List WLList_qsort_compare_call;
#ifdef PROTOTYPES
/* correct typing for the actual call to qsort */
typedef int (*WLListQsortCompareFuncType) (const void *, const void *);
#endif
int
WLList_qsort_compare_func(o1, o2)
WOOL_OBJECT *o1, *o2;
{
WOOL_Number wl_num;
WLList_qsort_compare_call -> list[1] = *o1;
WLList_qsort_compare_call -> list[2] = *o2;
wl_num = (WOOL_Number) WOOL_send(WOOL_execute,
(WLList_qsort_compare_call -> list[0]),
(WLList_qsort_compare_call -> list[0], WLList_qsort_compare_call));
if (wl_num -> type != WLNumber)
wool_error("sort compare function must return a number, not a %s",
((WOOL_Atom) wl_num -> type[0]) -> p_name);
return wl_num -> number;
}
WOOL_OBJECT
WLList_qsort(list, compare_func)
WOOL_List list;
WOOL_OBJECT compare_func; /* any function */
{
if (list->type != WLList)
return NIL;
if (!WLList_qsort_compare_call) {
increase_reference(WLList_qsort_compare_call = wool_list_make(3));
}
WLList_qsort_compare_call -> list[0] = compare_func;
qsort((char *) list -> list, list ->size, sizeof(WOOL_OBJECT),
#ifdef PROTOTYPES
(WLListQsortCompareFuncType)
#endif
WLList_qsort_compare_func);
return (WOOL_OBJECT) list;
}
/* copy of a list (but not of its elements)
*/
WOOL_OBJECT
WLList_copy(list)
WOOL_List list;
{
if (list -> type != WLList) /* copy of () = () */
return (WOOL_OBJECT) list;
else { /* normal case */
WOOL_List wl_list;
int i;
wl_list = (WOOL_List) Malloc(sizeof(struct _WOOL_List) +
(list -> size - 1) * sizeof(WOOL_OBJECT));
zrt_put(wl_list);
wl_list -> type = WLList;
wl_list -> size = list -> size;
for (i = 0; i < list -> size; i++)
increase_reference(wl_list -> list[i] = list -> list[i]);
return (WOOL_OBJECT) wl_list;
}
}