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