/* hacked version of the one from dlibs: * removed size restriction by using alloca * fixed alignment problems * ints <-> longs fixed in accordance with ansi proto * note: changing longs to size_t in _[w,l,n]qsort for args/indices * breaks this code (not sure why!). * * (duh, duh!)now i understand, its due to (hi > lo) condition. * * ++jrb */ #ifdef minix #include #include "lib.h" #else #include #include #endif #include typedef unsigned short ushort; typedef unsigned long ulong; typedef unsigned char uchar; uchar *_qbuf; /* pointer to storage for qsort() */ #define PIVOT ((i+j)>>1) #define moveitem(dst,src,size) if(dst != src) bcopy(src, dst, size) #ifdef __GNUC__ #ifdef minix void *alloca(unsigned long); #else #define alloca __builtin_alloca #endif #endif #if (defined(atarist) || defined(minix)) #define SHORT_ALIGN_DESIRABLE /* SHORT_ALIGN_DESIRABLE def'ed for machines on which short alignment on a two word boundary is desirable */ #endif #ifdef SHORT_ALIGN_DESIRABLE static void _wqsort(base, lo, hi, cmp) register ushort *base; register long lo; register long hi; register int (*cmp)(); { ushort k; register long i, j, t; register ushort *p = &k; while(hi > lo) { i = lo; j = hi; t = PIVOT; *p = base[t]; base[t] = base[i]; base[i] = *p; while(i < j) { while(((*cmp)((base+j), p)) > 0) --j; base[i] = base[j]; while((i < j) && (((*cmp)((base+i), p)) <= 0)) ++i; base[j] = base[i]; } base[i] = *p; if((i - lo) < (hi - i)) { _wqsort(base, lo, (i - 1), cmp); lo = i + 1; } else { _wqsort(base, (i + 1), hi, cmp); hi = i - 1; } } } #endif /* SHORT_ALIGN_DESIRABLE */ static void _lqsort(base, lo, hi, cmp) register ulong *base; register long lo; register long hi; register int (*cmp)(); { ulong k; register long i, j, t; register ulong *p = &k; while(hi > lo) { i = lo; j = hi; t = PIVOT; *p = base[t]; base[t] = base[i]; base[i] = *p; while(i < j) { while(((*cmp)((base+j), p)) > 0) --j; base[i] = base[j]; while((i < j) && (((*cmp)((base+i), p)) <= 0)) ++i; base[j] = base[i]; } base[i] = *p; if((i - lo) < (hi - i)) { _lqsort(base, lo, (i - 1), cmp); lo = i + 1; } else { _lqsort(base, (i + 1), hi, cmp); hi = i - 1; } } } static void _nqsort(base, lo, hi, size, cmp) register uchar *base; register long lo; register long hi; register long size; register int (*cmp)(); { register long i, j; register uchar *p = _qbuf; while(hi > lo) { i = lo; j = hi; p = (base+size*PIVOT); moveitem(_qbuf, p, size); moveitem(p, (base+size*i), size); moveitem((base+size*i), _qbuf, size); p = _qbuf; while(i < j) { while(((*cmp)((base+size*j), p)) > 0) --j; moveitem((base+size*i), (base+size*j), size); while((i < j) && (((*cmp)((base+size*i), p)) <= 0)) ++i; moveitem((base+size*j), (base+size*i), size); } moveitem((base+size*i), p, size); if((i - lo) < (hi - i)) { _nqsort(base, lo, (i - 1), size, cmp); lo = i + 1; } else { _nqsort(base, (i + 1), hi, size, cmp); hi = i - 1; } } } #define LONG_ALIGNED(X) ((((unsigned long)(X)) & 3) == 0) #ifdef SHORT_ALIGN_DESIRABLE #define SHORT_ALIGNED(X) ((((unsigned long)(X)) & 1) == 0) #endif void qsort(base, num, size, cmp) void *base; size_t num; size_t size; int (*cmp)(); { if(num < 2) return; /* nothing to do */ #if 0 /* later put in thresh stuff and kick in this code */ else if(num == 2) /* at some point replace if n < THRESH do insert sort */ { /* degenerate case */ if(((*cmp)( base, ((uchar *)base)+size )) > 0) { if((_qbuf = alloca(size)) == (void *)0) return; bcopy(base, _qbuf, size); bcopy(((uchar *)base)+size, base, size); bcopy(_qbuf, ((uchar *)base)+size, size); } return; } #endif #ifdef SHORT_ALIGN_DESIRABLE /* assumption: if short align desired, then its ok to align a long at a short boundary too. */ if(SHORT_ALIGNED(base)) { if(size == 2) _wqsort((ushort *)base, 0L, num-1, cmp); else if(size == 4) _lqsort((ulong *)base, 0L, num-1, cmp); } #else if((size == 4) && LONG_ALIGNED(base)) _lqsort((ulong *)base, 0L, num-1, cmp); #endif else { #ifdef minix /* we have to check, otherwise ... */ if((_qbuf = alloca(size)) == (void *)0) return; #else _qbuf = alloca(size); /* stack better be large enough */ #endif _nqsort((uchar *)base, 0L, num-1, size, cmp); } }