|
|
BSD 4.3
#include "../h/rt.h"
/*
* sort(l) - sort list l.
* sort(S) - sort set S.
* sort(t,i) - sort table on reference (i = 1) or value (i = 2) field.
*/
Xsort(nargs, arg2, arg1, arg0)
int nargs;
struct descrip arg2, arg1, arg0;
{
register struct descrip *d1;
register int size, i;
int nelem;
struct b_list *lp, *tp;
union block *bp, *ep;
extern struct b_list *alclist();
extern struct b_lelem *alclstb();
extern anycmp(), trefcmp(), tvalcmp();
DeRef(arg1)
if (arg1.type == D_LIST) {
/*
* Sort the list by copying it into a new list and then using
* qsort to sort the descriptors. (That was easy!)
*/
size = BLKLOC(arg1)->list.cursize;
cplist(&arg1, &arg0, 1, size + 1);
qsort(BLKLOC(BLKLOC(arg0)->list.listhead)->lelem.lslots, size,
sizeof(struct descrip), anycmp);
}
#ifdef SETS
else if (arg1.type == D_SET) {
/*
* Create a list the size of the set (or at least
* LISTBLKSIZE), copy each element into the list, and
* then sort the list using qsort as in list sorting
* and return the sorted list.
*/
nelem = size = BLKLOC(arg1)->set.setsize;
if(nelem < LISTBLKSIZE)
nelem = LISTBLKSIZE;
hneed(sizeof(struct b_list) + sizeof(struct b_lelem) +
nelem * sizeof(struct descrip));
bp = BLKLOC(arg1);
lp = alclist(size);
lp->listhead.type = lp->listtail.type = D_LELEM;
BLKLOC(lp->listtail) = (union block *) alclstb(nelem,0,size);
BLKLOC(lp->listhead) = BLKLOC(lp->listtail);
if (size > 0) { /* only need to sort non-empty sets */
d1 = BLKLOC(lp->listhead)->lelem.lslots;
for(i = 0; i < NBUCKETS; i++) {
ep = BLKLOC(bp->set.sbucks[i]);
while (ep != NULL) {
*d1 = ep->selem.setmem;
d1++;
ep = BLKLOC(ep->selem.sblink);
}
}
qsort(BLKLOC(lp->listhead)->lelem.lslots,size,sizeof(struct descrip),anycmp);
}
arg0.type = D_LIST;
BLKLOC(arg0) = (union block *) lp;
}
#endif SETS
else if (arg1.type == D_TABLE) {
/*
* Default i (the type of sort) to 1, and be sure that it is
* either 1 or 2.
*/
defshort(&arg2, 1);
if (INTVAL(arg2) != 1 && INTVAL(arg2) != 2)
runerr(205, &arg2);
/*
* The list resulting from the sort will have as many elements as
* the table has, so get that value and also make a valid list
* block size out of it.
*/
nelem = size = BLKLOC(arg1)->table.cursize;
if (nelem < LISTBLKSIZE)
nelem = LISTBLKSIZE;
/*
* Ensure space for: the list header block and a list element
* block for the list which is to be returned,
* a list header block and a list element block for each of the two
* element lists the sorted list is to contain. Note that the
* calculation might be better expressed as:
* list_header_size + list_block_size + nelem * descriptor_size +
* nelem * (list_header_size + list_block_size + 2*descriptor_size)
*/
hneed(sizeof(struct b_list) + sizeof(struct b_lelem) +
nelem * (sizeof(struct b_list) + sizeof(struct b_lelem) +
3 * sizeof(struct descrip)));
/*
* Point bp at the table header block of the table to be sorted
* and point lp at a newly allocated list
* that will hold the the result of sorting the table.
*/
bp = BLKLOC(arg1);
lp = alclist(size);
lp->listhead.type = lp->listtail.type = D_LELEM;
BLKLOC(lp->listtail) = (union block *) alclstb(nelem, 0, size);
BLKLOC(lp->listhead) = BLKLOC(lp->listtail);
if (size > 0) { /* No need to sort the elements of an empty table */
/*
* Point d1 at the start of the list elements in the new list
* element block in preparation for use as an index into the list.
*/
d1 = BLKLOC(lp->listhead)->lelem.lslots;
/*
* Traverse the element chain for each table bucket. For each
* element, allocate a two-element list and put the table
* entry value in the first element and the assigned value in
* the second element. The two-element list is assigned to
* the descriptor that d1 points at. When this is done, the
* list of two-element lists is complete, but unsorted.
*/
for (i = 0; i < NBUCKETS; i++) {
ep = BLKLOC(bp->table.buckets[i]);
while (ep != NULL) {
d1->type = D_LIST;
tp = alclist(2);
BLKLOC(*d1) = (union block *) tp;
tp->listhead.type = tp->listtail.type = D_LELEM;
BLKLOC(tp->listtail) = (union block *) alclstb(2, 0, 2);
BLKLOC(tp->listhead) = BLKLOC(tp->listtail);
BLKLOC(tp->listhead)->lelem.lslots[0] = ep->telem.tref;
BLKLOC(tp->listhead)->lelem.lslots[1] = ep->telem.tval;
d1++;
ep = BLKLOC(ep->telem.blink);
}
}
/*
* Sort the resulting two-element list using the sorting function
* determined by i.
*/
if (INTVAL(arg2) == 1)
qsort(BLKLOC(lp->listhead)->lelem.lslots, size,
sizeof(struct descrip), trefcmp);
else
qsort(BLKLOC(lp->listhead)->lelem.lslots, size,
sizeof(struct descrip), tvalcmp);
}
/*
* Make arg0 point at the sorted list.
*/
arg0.type = D_LIST;
BLKLOC(arg0) = (union block *) lp;
}
else /* Tried to sort something that wasn't a list or a table. */
runerr(115, &arg1);
}
Procblock(sort,2)
/*
* trefcmp(d1,d2) - compare two-element lists on first field.
*/
trefcmp(d1,d2)
struct descrip *d1, *d2;
{
extern anycmp();
if (d1->type != D_LIST || d2->type != D_LIST)
syserr("trefcmp: internal consistency check fails.");
return (anycmp(&(BLKLOC(BLKLOC(*d1)->list.listhead)->lelem.lslots[0]),
&(BLKLOC(BLKLOC(*d2)->list.listhead)->lelem.lslots[0])));
}
/*
* tvalcmp(d1,d2) - compare two-element lists on second field.
*/
tvalcmp(d1,d2)
struct descrip *d1, *d2;
{
extern anycmp();
if (d1->type != D_LIST || d2->type != D_LIST)
syserr("tvalcmp: internal consistency check fails.");
return (anycmp(&(BLKLOC(BLKLOC(*d1)->list.listhead)->lelem.lslots[1]),
&(BLKLOC(BLKLOC(*d2)->list.listhead)->lelem.lslots[1])));
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.