Index: include/bu.h
===================================================================
--- include/bu.h	(Revision 58930)
+++ include/bu.h	(Arbeitskopie)
@@ -6304,6 +6304,20 @@
  */
 BU_EXPORT extern int bu_gethostname(char *hostname, size_t len);
 
+
+/** @addtogroup file */
+/** @ingroup io */
+/** @{ */
+/** @file libbu/sort.c
+ * platform-independent re-entrant version of qsort, where the first argument
+ * is the array to sort, the second the number of elements inside the array, the
+ * third the size of one element, the fourth the comparison-function and the
+ * fifth a variable which is handed as a third argument to the comparison-function.
+ */
+BU_EXPORT extern void bu_sort(genptr_t base, size_t nel, size_t width,
+            int (*compar)(const_genptr_t a1, const_genptr_t a2, genptr_t aarg), void *arg);
+/** @} */
+
 __END_DECLS
 
 #endif  /* __BU_H__ */
Index: src/libbu/CMakeLists.txt
===================================================================
--- src/libbu/CMakeLists.txt	(Revision 58930)
+++ src/libbu/CMakeLists.txt	(Arbeitskopie)
@@ -78,6 +78,7 @@
   realpath.c
   semaphore.c
   simd.c
+  sort.c
   sscanf.c
   str.c
   tcl.c
Index: src/libbu/sort.c
===================================================================
--- src/libbu/sort.c	(Revision 0)
+++ src/libbu/sort.c	(Arbeitskopie)
@@ -0,0 +1,158 @@
+/*                        S O R T . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2013 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+
+#include "stdlib.h"
+#include "bu.h"
+
+#define min(a, b)	(a) < (b) ? a : b
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) { 	\
+    long i = (n) / sizeof (TYPE); 		\
+    TYPE *pi = (TYPE *) (parmi); 		\
+    TYPE *pj = (TYPE *) (parmj); 		\
+    do { 					\
+	TYPE	t = *pi;			\
+	*pi++ = *pj;				\
+	*pj++ = t;				\
+    } while (--i > 0);				\
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+    es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+
+void
+swapfunc(a, b, n, swaptype)
+    char *a, *b;
+    int n, swaptype;
+{
+    if(swaptype <= 1)
+	swapcode(long, a, b, n)
+    else
+	swapcode(char, a, b, n)
+}
+
+
+#define swap(a, b)				\
+    if (swaptype == 0) {			\
+	long t = *(long *)(a);			\
+	*(long *)(a) = *(long *)(b);		\
+	*(long *)(b) = t;			\
+    } else					\
+	swapfunc(a, b, sizememb, swaptype)
+
+#define vecswap(a, b, n) 	if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+#define	CMP(t, x, y) (compare((t), (x), (y)))
+
+
+char *
+med3(char *a, char *b, char *c, int (*compare)(const void *, const void *, void *), void *thunk)
+{
+    return CMP(a, b, thunk) < 0 ?
+	   (CMP(b, c, thunk) < 0 ? b : (CMP(a, c, thunk) < 0 ? c : a ))
+	  :(CMP(b, c, thunk) > 0 ? b : (CMP(a, c, thunk) < 0 ? a : c ));
+}
+
+
+void
+bu_sort(void *array, size_t nunmemb, size_t sizememb, int (*compare)(const void *, const void *, void *), void *context)
+{
+    char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+    size_t d, r;
+    int cmp_result;
+    int swaptype, swap_cnt;
+
+loop:	SWAPINIT(array, sizememb);
+    swap_cnt = 0;
+    if (nunmemb < 7) {
+	for (pm = (char *)array + sizememb; pm < (char *)array + nunmemb * sizememb; pm += sizememb)
+	    for (pl = pm;
+	         pl > (char *)array && CMP(pl - sizememb, pl, context) > 0;
+	         pl -= sizememb)
+		swap(pl, pl - sizememb);
+	return;
+    }
+    pm = (char *)array + (nunmemb / 2) * sizememb;
+    if (nunmemb > 7) {
+	pl = array;
+	pn = (char *)array + (nunmemb - 1) * sizememb;
+	if (nunmemb > 40) {
+	    d = (nunmemb / 8) * sizememb;
+	    pl = med3(pl, pl + d, pl + 2 * d, compare, context);
+	    pm = med3(pm - d, pm, pm + d, compare, context);
+	    pn = med3(pn - 2 * d, pn - d, pn, compare, context);
+	}
+	pm = med3(pl, pm, pn, compare, context);
+    }
+    swap(array, pm);
+    pa = pb = (char *)array + sizememb;
+
+    pc = pd = (char *)array + (nunmemb - 1) * sizememb;
+    for (;;) {
+	while (pb <= pc && (cmp_result = CMP(pb, array, context)) <= 0) {
+	    if (cmp_result == 0) {
+		swap_cnt = 1;
+		swap(pa, pb);
+		pa += sizememb;
+	    }
+	    pb += sizememb;
+	}
+	while (pb <= pc && (cmp_result = CMP(pc, array, context)) >= 0) {
+	    if (cmp_result == 0) {
+		swap_cnt = 1;
+		swap(pc, pd);
+		pd -= sizememb;
+	    }
+	    pc -= sizememb;
+	}
+	if (pb > pc)
+		break;
+	swap(pb, pc);
+	swap_cnt = 1;
+	pb += sizememb;
+	pc -= sizememb;
+    }
+    if (swap_cnt == 0) {  /* Switch to insertion sort */
+	for (pm = (char *)array + sizememb; pm < (char *)array + nunmemb * sizememb; pm += sizememb)
+	    for (pl = pm;
+		 pl > (char *)array && CMP(pl - sizememb, pl, context) > 0;
+		 pl -= sizememb)
+		swap(pl, pl - sizememb);
+	return;
+    }
+
+    pn = (char *)array + nunmemb * sizememb;
+    r = min(pa - (char *)array, pb - pa);
+    vecswap(array, pb - r, r);
+    r = min(pd - pc, (signed) (pn - pd - sizememb));
+    vecswap(pb, pn - r, r);
+    if ((r = pb - pa) > sizememb)
+	bu_sort(array, r / sizememb, sizememb, compare, context);
+    if ((r = pd - pc) > sizememb) {
+	/* Iterate rather than recurse to save stack space */
+	array = pn - r;
+	nunmemb = r / sizememb;
+	goto loop;
+    }
+}
