+
+ if (nmemb >= THRESH)
+ quick_sort(bot, nmemb, size, compar);
+ else
+ insertion_sort(bot, nmemb, size, compar);
+}
+
+/*
+ * Swap two areas of size number of bytes. Although qsort(3) permits random
+ * blocks of memory to be sorted, sorting pointers is almost certainly the
+ * common case (and, were it not, could easily be made so). Regardless, it
+ * isn't worth optimizing; the SWAP's get sped up by the cache, and pointer
+ * arithmetic gets lost in the time required for comparison function calls.
+ */
+#define SWAP(a, b) { \
+ cnt = size; \
+ do { \
+ ch = *a; \
+ *a++ = *b; \
+ *b++ = ch; \
+ } while (--cnt); \
+}
+
+/*
+ * Knuth, Vol. 3, page 116, Algorithm Q, step b, argues that a single pass
+ * of straight insertion sort after partitioning is complete is better than
+ * sorting each small partition as it is created. This isn't correct in this
+ * implementation because comparisons require at least one (and often two)
+ * function calls and are likely to be the dominating expense of the sort.
+ * Doing a final insertion sort does more comparisons than are necessary
+ * because it compares the "edges" and medians of the partitions which are
+ * known to be already sorted.
+ *
+ * This is also the reasoning behind selecting a small THRESH value (see
+ * Knuth, page 122, equation 26), since the quicksort algorithm does less
+ * comparisons than the insertion sort.
+ */
+#define SORT(bot, n) { \
+ if (n > 1) \
+ if (n == 2) { \
+ t1 = bot + size; \
+ if (compar(t1, bot) < 0) \
+ SWAP(t1, bot); \
+ } else \
+ insertion_sort(bot, n, size, compar); \
+}
+
+static void
+quick_sort(bot, nmemb, size, compar)
+ register char *bot;
+ register int size;
+ int nmemb, (*compar)();
+{
+ register int cnt;
+ register u_char ch;
+ register char *top, *mid, *t1, *t2;
+ register int n1, n2;
+ char *bsv;
+
+ /* bot and nmemb must already be set. */
+partition:
+
+ /* find mid and top elements */
+ mid = bot + size * (nmemb >> 1);
+ top = bot + (nmemb - 1) * size;
+