/* Copyright 1989, 1990 by James Aspnes, David Applegate, and Bennet Yee */
/* See the file COPYING for distribution information */
#include <ctype.h>
#include "set.h"
#include "db.h"
#include "externs.h"
extern alist get_aliases (datum);
int member (set s, datum d)
{
return (!set_empty (s) && assoc (s->list, d, 0));
}
static set new_set (void)
{
set s;
s = (set) malloc (sizeof (struct _set));
s->list = empty_alist ();
s->names = empty_alist ();
return s;
}
set add_member (set s, datum d)
{
datum name;
datum dummy;
alist aliases;
if (d == NOTHING)
return s;
if (set_empty (s))
s = new_set ();
if (!member (s, d)) {
if (!isempty (s->names) && !isempty (aliases = get_aliases (d))) {
FOREACH (aliases, name, dummy) {
s->names = add_assoc (s->names, name, d);
}
END_FOREACH;
}
s->list = add_assoc (s->list, d, NOTHING);
}
return s;
}
set del_member (set s, datum d)
{
datum name;
datum dummy;
alist aliases;
if (member (s, d)) {
if (alist_count (s->list) == 1) {
/* last one */
free_set (s);
return empty_set ();
} else {
if (!isempty (s->names) && !isempty (aliases = get_aliases (d))) {
FOREACH (aliases, name, dummy) {
s->names = del_assoc (s->names, name, d);
}
END_FOREACH;
}
s->list = del_assoc (s->list, d, NOTHING);
}
}
return s;
}
set copy_set (set s)
{
set s1;
if (s) {
s1 = new_set ();
s1->list = copy_alist (s->list);
s1->names = copy_alist (s->names);
return s1;
} else {
return empty_set ();
}
}
void free_set (set s)
{
if (s) {
free_alist (s->list);
free_alist (s->names);
free ((void *) s);
}
}
alist get_aliases (datum obj)
{
datum a;
char buf[MAX_STRLEN + 1];
char *p;
char *end;
char *next;
alist l;
if ((a = lookup (obj, ALIASES_NAME)) == NOTHING) {
/* no aliases */
return empty_alist ();
} else if (isempty (l = get_expansion (a))) {
/* not expanded yet */
/* get a copy we can work on */
strip_whitespace (string (a), buf);
l = empty_alist ();
p = buf;
for (;;) {
/* zip over empty names etc. */
while (*p && (isspace (*p) || *p == ALIAS_SEPARATOR))
p++;
if (!*p)
break; /* nothing left */
/* find the next separator */
for (next = p; *next && *next != ALIAS_SEPARATOR; next++);
/* back over spaces */
/* terminates because p is sitting on a non-space */
for (end = next - 1; isspace (*end); end--);
/* cut it off */
if (*next)
next++; /* get next out of the way */
*++end = '\0';
/* add it to the list */
l = set_assoc (l, intern (p), NOTHING);
/* go on to the next one */
p = next;
}
/* put it in */
set_expansion (a, l);
}
return l;
}
void set_build_name_list (set s)
{
datum obj;
datum name;
datum dummy;
alist a;
if (s != 0) {
if (isempty (s->names) && !isempty (s->list)) {
FOREACH (s->list, obj, dummy) {
if (!isempty (a = get_aliases (obj))) {
FOREACH (a, name, dummy) {
s->names = add_assoc (s->names, name, obj);
}
END_FOREACH;
}
}
END_FOREACH;
}
}
}
void set_clear_name_list (set s)
{
if (s && !isempty (s->names)) {
free_alist (s->names);
s->names = empty_alist ();
}
}
datum set_next (set s, set_iterator * i)
{
if (s) {
return alist_next (s->list, i, 0);
} else {
return NOTHING;
}
}
datum set_first (set s, set_iterator * i)
{
if (s) {
return alist_first (s->list, i, 0);
} else {
return NOTHING;
}
}
datum set_next_match (set s, set_iterator * i)
{
datum value;
/* assume names has been rebuilt */
if (s && alist_next_match (s->names, i, &value)) {
return value;
} else {
return NOTHING;
}
}
datum set_first_match (set s, set_iterator * i, datum key)
{
datum value;
set_build_name_list (s);
if (s && alist_first_match (s->names, i, &value, key)) {
return value;
} else {
return NOTHING;
}
}
set add_members (set victim, set operand)
{
datum next;
if (!set_empty (operand)) {
set_clear_name_list (victim); /* make it fast */
SET_FOREACH (operand, next) {
victim = add_member (victim, next);
}
END_SET_FOREACH;
}
return victim;
}
set del_members (set victim, set operand)
{
datum next;
if (!set_empty (operand)) {
set_clear_name_list (victim); /* make it fast */
SET_FOREACH (operand, next) {
victim = del_member (victim, next);
}
END_SET_FOREACH;
}
return victim;
}