/* 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; }