listobject.c: added optional cmp function to list.sort().
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 6992a0f..996c289 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -26,6 +26,8 @@
#include "allobjects.h"
#include "modsupport.h"
+#include "compile.h" /* Needed by ceval.h */
+#include "ceval.h" /* For call_object() */
object *
newlistobject(size)
@@ -471,11 +473,46 @@
return ins(self, (int) self->ob_size, args);
}
+static object *cmpfunc;
+
static int
cmp(v, w)
char *v, *w;
{
- return cmpobject(* (object **) v, * (object **) w);
+ object *t, *res;
+ long i;
+
+ if (err_occurred())
+ return 0;
+
+ if (cmpfunc == NULL)
+ return cmpobject(* (object **) v, * (object **) w);
+
+ /* Call the user-supplied comparison function */
+ t = newtupleobject(2);
+ if (t == NULL)
+ return 0;
+ INCREF(* (object **) v);
+ settupleitem(t, 0, * (object **) v);
+ INCREF(* (object **) w);
+ settupleitem(t, 1, * (object **) w);
+ res = call_object(cmpfunc, t);
+ DECREF(t);
+ if (res == NULL)
+ return 0;
+ if (!is_intobject(res)) {
+ err_setstr(TypeError, "comparison function should return int");
+ i = 0;
+ }
+ else {
+ i = getintvalue(res);
+ if (i < 0)
+ i = -1;
+ else if (i > 0)
+ i = 1;
+ }
+ DECREF(res);
+ return (int) i;
}
static object *
@@ -483,14 +520,24 @@
listobject *self;
object *args;
{
- if (args != NULL) {
- err_badarg();
- return NULL;
+ object *save_cmpfunc;
+ if (self->ob_size <= 1) {
+ INCREF(None);
+ return None;
}
- err_clear();
- if (self->ob_size > 1)
- qsort((char *)self->ob_item,
+ save_cmpfunc = cmpfunc;
+ cmpfunc = args;
+ if (cmpfunc != NULL) {
+ /* Test the comparison function for obvious errors */
+ (void) cmp(&self->ob_item[0], &self->ob_item[1]);
+ if (err_occurred()) {
+ cmpfunc = save_cmpfunc;
+ return NULL;
+ }
+ }
+ qsort((char *)self->ob_item,
(int) self->ob_size, sizeof(object *), cmp);
+ cmpfunc = save_cmpfunc;
if (err_occurred())
return NULL;
INCREF(None);