static char rcsid[] = "$Author: djh $ $Date: 1996/05/08 04:19:28 $"; static char rcsident[] = "$Header: /mac/src/cap60/applications/lwsrv/RCS/list.c,v 2.2 1996/05/08 04:19:28 djh Rel djh $"; static char revision[] = "$Revision: 2.2 $"; /* * list.c - general list package-simple and key-value lists * * UNIX AppleTalk spooling program: act as a laserwriter * AppleTalk package for UNIX (4.2 BSD). * */ #include #include #ifdef USESTRINGDOTH #include #else USESTRINGDOTH #include #endif USESTRINGDOTH #include "list.h" #define FALSE 0 #define TRUE 1 static int listcmp(); static void sendKVTree(); static int _AddToKVTree(/* KVTree **ent, void *key, void *val, int (*keycmp)() */); static KVTree *_DupKVTree(/* KVTree *lf */); static void _FreeKVTree(/* KVTree *lp, int (*keyfree)(), int (*valfree)() */); static void _ListKVTree(/* KVTree *kp, List *lp */); static void *_SearchKVTree(/* KVTree *lp, void *key, int (*keycmp)() */); char *malloc(); char *realloc(); void AddToKVTree(ent, key, val, keycmp) KVTree **ent; void *key, *val; int (*keycmp)(); { _AddToKVTree(ent, key, val, keycmp); } /* * Modified from "Algorithms + Data Structures = Programs", Niklaus Wirth, * 1976, section 4.4.7 Balanced Tree Insertion, page 220-221 (AVL). * */ #define L_EQUILIBRATED 2 #define LEFTSLANTED 1 #define L_REBALANCE 0 #define R_EQUILIBRATED 0 #define RIGHTSLANTED 1 #define R_REBALANCE 2 static int _AddToKVTree(ent, key, val, keycmp) register KVTree **ent; void *key, *val; int (*keycmp)(); { register KVTree *ent1, *ent2; register int cmp; char *malloc(); if (*ent == NULL) { /* not in tree, insert it */ if ((*ent = (KVTree *)malloc(sizeof(KVTree))) == NULL) errorexit(1, "_AddToKVTree: Out of memory\n"); (*ent)->left = (*ent)->right = NULL; (*ent)->bal = LEFTSLANTED; (*ent)->key = key; (*ent)->val = val; return(1); } if ((cmp = (*keycmp)(key, (*ent)->key)) == 0) { /* match */ (*ent)->val = val; return(0); } if (cmp < 0) { if (!_AddToKVTree(&(*ent)->left, key, val, keycmp)) return(0); /* left branch has grown higher */ switch((*ent)->bal) { case L_EQUILIBRATED: (*ent)->bal = LEFTSLANTED; return(0); case LEFTSLANTED: (*ent)->bal = L_REBALANCE; return(1); case L_REBALANCE: /* rebalance */ if ((ent1 = (*ent)->left)->bal == L_REBALANCE) { /* single LL rotation */ (*ent)->left = ent1->right; ent1->right = *ent; (*ent)->bal = LEFTSLANTED; *ent = ent1; } else { /* double LR rotation */ ent2 = ent1->right; ent1->right = ent2->left; ent2->left = ent1; (*ent)->left = ent2->right; ent2->right = *ent; (*ent)->bal = (ent2->bal == L_REBALANCE) ? L_EQUILIBRATED : LEFTSLANTED; ent1->bal = (ent2->bal == L_EQUILIBRATED) ? L_REBALANCE : LEFTSLANTED; *ent = ent2; } (*ent)->bal = LEFTSLANTED; return(0); } } if (!_AddToKVTree(&(*ent)->right, key, val, keycmp)) return(0); /* right branch has grown higher */ switch((*ent)->bal) { case R_EQUILIBRATED: (*ent)->bal = RIGHTSLANTED; return(0); case RIGHTSLANTED: (*ent)->bal = R_REBALANCE; return(1); case R_REBALANCE: /* rebalance */ if ((ent1 = (*ent)->right)->bal == R_REBALANCE) { /* single RR rotation */ (*ent)->right = ent1->left; ent1->left = *ent; (*ent)->bal = RIGHTSLANTED; *ent = ent1; } else { /* double RL rotation */ ent2 = ent1->left; ent1->left = ent2->right; ent2->right = ent1; (*ent)->right = ent2->left; ent2->left = *ent; (*ent)->bal = (ent2->bal == R_REBALANCE) ? R_EQUILIBRATED : RIGHTSLANTED; ent1->bal = (ent2->bal == R_EQUILIBRATED) ? R_REBALANCE : RIGHTSLANTED; *ent = ent2; } (*ent)->bal = RIGHTSLANTED; return(0); } } void AddToList(lp, item) register List *lp; void *item; { if (lp->n >= lp->lmax && (lp->list = (void **)realloc((char *)lp->list, (lp->lmax += LISTDELTA) * sizeof(void *))) == NULL) errorexit(1, "AddToList: Out of memory\n"); lp->list[lp->n++] = item; } KVTree ** CreateKVTree() { register KVTree **kp; if ((kp = (KVTree **)malloc(sizeof(KVTree *))) == NULL) errorexit(1, "AddToKVTree: Out of memory\n"); *kp = NULL; return(kp); } void CatList(to, from) register List *to; List *from; { register int n; register void **vp; for (n = from->n, vp = from->list; n > 0; n--) AddToList(to, *vp++); } List * CreateList() { register List *lp; static char errstr[] = "CreateList: Out of memory\n"; if ((lp = (List *)malloc(sizeof(List))) == NULL) errorexit(1, errstr); if ((lp->list = (void **)malloc((lp->lmax = LISTDELTA) * sizeof(void *))) == NULL) errorexit(2, errstr); lp->n = 0; return(lp); } KVTree ** DupKVTree(lf) register KVTree **lf; { register KVTree **kp; if ((kp = (KVTree **)malloc(sizeof(KVTree *))) == NULL) errorexit(1, "DupKVTree: Out of memory\n"); *kp = *lf ? _DupKVTree(*lf) : NULL; return(kp); } static KVTree * _DupKVTree(lf) register KVTree *lf; { register KVTree *lt; if ((lt = (KVTree *)malloc(sizeof(KVTree))) == NULL) errorexit(1, "_DupKVTree: Out of memory\n"); lt->bal = lf->bal; lt->key = lf->key; lt->val = lf->val; lt->left = lf->left ? _DupKVTree(lf->left) : NULL; lt->right = lf->right ? _DupKVTree(lf->right) : NULL; return(lt); } List * DupList(lf) register List *lf; { register List *lt; register void **vp; register int i; lt = CreateList(); for (i = lf->n, vp = lf->list; i > 0; i--) AddToList(lt, *vp++); return(lt); } void FreeKVTree(lp, keyfree, valfree) KVTree **lp; int (*keyfree)(), (*valfree)(); { if (*lp) _FreeKVTree(*lp, keyfree, valfree); free((char *)lp); } static void _FreeKVTree(lp, keyfree, valfree) register KVTree *lp; int (*keyfree)(), (*valfree)(); { if (lp->left) _FreeKVTree(lp->left, keyfree, valfree); if (lp->right) _FreeKVTree(lp->right, keyfree, valfree); if (keyfree) (*keyfree)(lp->key); if (valfree) (*valfree)(lp->val); free((char *)lp); } void FreeList(lp, itemfree) List *lp; int (*itemfree)(); { register void **vp; register int i; if (itemfree) for (i = lp->n, vp = lp->list; i > 0; i--) (*itemfree)(*vp++); free((char *)lp->list); free((char *)lp); } List * ListKVTree(kp) KVTree **kp; { register List *lp; lp = CreateList(); if (*kp) _ListKVTree(*kp, lp); return(lp); } static void _ListKVTree(kp, lp) register KVTree *kp; register List *lp; { if (kp->left) _ListKVTree(kp->left, lp); AddToList(lp, kp); if (kp->right) _ListKVTree(kp->right, lp); } void * SearchKVTree(lp, key, keycmp) KVTree **lp; void *key; int (*keycmp)(); { return(*lp ? _SearchKVTree(*lp, key, keycmp) : NULL); } static void * _SearchKVTree(lp, key, keycmp) KVTree *lp; register void *key; int (*keycmp)(); { register int cmp; if ((cmp = (*keycmp)(key, lp->key)) == 0) return(lp->val); if (cmp > 0) return(lp->right ? _SearchKVTree(lp->right, key, keycmp) : NULL); else return(lp->left ? _SearchKVTree(lp->left, key, keycmp) : NULL); } void * SearchList(lp, item, itemcmp) register List *lp; register void *item; int (*itemcmp)(); { register void **ip = lp->list; register int i, low, high, cmp; low = 0; high = lp->n - 1; while (low <= high) { i = (low + high) / 2; if ((cmp = (*itemcmp)(ip[i], item)) == 0) return(ip[i]); if (cmp > 0) high = i - 1; else low = i + 1; } return(NULL); } void SortList(lp, itemcmp) register List *lp; int (*itemcmp)(); { qsort((char *)lp->list, lp->n, sizeof(void *), itemcmp); } int StringSortItemCmp(a, b) char **a, **b; { return(strcmp(*a, *b)); } errorexit(status, str) int status; char *str; { fputs(str, stderr); exit(status); }