/*TITLE pqsort.c - quicksort algorithm 1/10/85 10:04:32 */

static char *version = "@(#)pqsort.c    1.1 1/10/85 10:04:32";

/*
** void pqsort(vec, nel, esize, compptr)
**
**  Quick Sort routine.
**  Based on Knuth's ART OF COMPUTER PROGRAMMING, VOL III, pp 114-117.
**  For some unknown reason, this works faster than the library's qsort.
**
** Parameters:
**  vec = points to beginning of structure to sort.
**  nel = number of elements.
**  esize = size of an element.
**  compptr = points to the routine for comparing two elements.
**
** Returns:
**  Nothing.
*/

static int elsize;              /* Element size */
static int (*comp)();           /* Address of comparison routing */

static void memexch(), mysort();

void pqsort(vec, nel, esize, compptr)

unsigned char *vec;
int nel;
int esize;
int (*compptr)();

{
  /* If less than 2 items, done */
  if (nel < 2)
    return;

  elsize = esize;
  comp = compptr;

  /* Call the real worker */
  mysort(vec, nel);
}
/*PAGE*/
/*
** void mysort(vec, nel)
**
**  The real quick sort routine.
**
** Parameters:
**  vec = points to beginning of structure to sort.
**  nel = number of elements.
**
**  esize = size of an element.
**  compptr = points to the routine for comparing two elements.
**
** Returns:
**  Nothing.
*/

static void mysort(vec, nel)

unsigned char *vec;
int nel;

{
  register short i, j;
  register unsigned char *iptr, *jptr, *kptr;

  /*
  ** If 2 items, check them by hand.
  */

begin:
  if (nel == 2) {
    if ((*comp)(vec, vec + elsize) > 0)
      memexch(vec, vec + elsize, elsize);
    return;
  }

  /*
  ** Initialize for this round.
  */

  j = nel;
  i = 0;
  kptr = vec;
  iptr = vec;
  jptr = vec + elsize * nel;
/*PAGE*/
  while (--j > i) {

    /*
    ** From the righthand side, find the first value that should be
    ** to the left of k.
    */

    jptr -= elsize;
    if ((*comp)(jptr, kptr) > 0)
      continue;

    /*
    ** Now from the lefthand side, find the first value that should be
    ** to the right of k.
    */

    iptr += elsize;
    while(++i < j && (*comp)(iptr, kptr) <= 0)
      iptr += elsize;

    if (i >= j)
      break;

    /*
    ** Exchange the two items.
    ** k will eventually end up between them.
    */

    memexch(jptr, iptr, elsize);
  }

  /*
  ** Move item 0 into position.
  */

  memexch(vec, iptr, elsize);

  /*
  ** Now sort the two partitions.
  */

  if ((nel -= (i + 1)) > 1)
    mysort(iptr + elsize, nel);

  /*
  ** To save a little time, just start the routine over by hand.
  */

  if (i > 1) {
    nel = i;
    goto begin;
  }
}
/*PAGE*/
/*
** memexch(s1, s2, n)
**
**  Exchange the contents of two vectors.
**
** Parameters:
**  s1 = points to one vector.
**  s2 = points to another vector.
**  n = size of the vectors in bytes.
**
** Returns:
**  Nothing.
*/

static void memexch(s1, s2, n)

register unsigned char *s1;
register unsigned char *s2;
register int n;

{
  register unsigned char c;

  while (n--) {
    c = *s1;
    *s1++ = *s2;
    *s2++ = c;
  }
}
