diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index a6938b205b6470669e2122f0c22177c34f5c0730..211def40ca9c6dce7d92f6bf21be390d81a5cb92 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: builtin_functions.c,v 1.246 2000/03/24 01:24:49 hubbe Exp $");
+RCSID("$Id: builtin_functions.c,v 1.247 2000/03/26 01:55:11 mast Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "pike_macros.h"
@@ -5981,6 +5981,10 @@ void init_builtin_efuns(void)
   ADD_EFUN("encode_value", f_encode_value,
 	   tFunc(tMix tOr(tVoid,tObj),tStr), OPT_TRY_OPTIMIZE);
 
+  /* function(mixed,void|object:string) */
+  ADD_EFUN("encode_value_canonic", f_encode_value_canonic,
+	   tFunc(tMix tOr(tVoid,tObj),tStr), OPT_TRY_OPTIMIZE);
+
 /* function(string,void|object:mixed) */
   ADD_EFUN("decode_value", f_decode_value,
 	   tFunc(tStr tOr(tVoid,tObj),tMix), OPT_TRY_OPTIMIZE);
diff --git a/src/encode.c b/src/encode.c
index 9608efbc2ff64851d27d437efc8884bcaa119e48..301ddcdecccf49f3699012e0cb0c97d9b3aef0b1 100644
--- a/src/encode.c
+++ b/src/encode.c
@@ -25,7 +25,7 @@
 #include "version.h"
 #include "bignum.h"
 
-RCSID("$Id: encode.c,v 1.54 2000/02/16 03:58:16 per Exp $");
+RCSID("$Id: encode.c,v 1.55 2000/03/26 01:55:11 mast Exp $");
 
 /* #define ENCODE_DEBUG */
 
@@ -103,6 +103,7 @@ double LDEXP(double x, int exp)
 
 struct encode_data
 {
+  int canonic;
   struct object *codec;
   struct svalue counter;
   struct mapping *encoded;
@@ -360,7 +361,9 @@ static void encode_value2(struct svalue *val, struct encode_data *data)
       break;
 
     case T_TYPE:
-      error("Encoding of the type type not supported yet!");
+      if (data->canonic)
+	error("Canonical encoding of the type type not supported.\n");
+      error("Encoding of the type type not supported yet!\n");
       break;
 
     case T_FLOAT:
@@ -404,6 +407,22 @@ static void encode_value2(struct svalue *val, struct encode_data *data)
       ref_push_mapping(val->u.mapping);
       f_values(1);
 
+      if (data->canonic) {
+	INT32 *order;
+	if (val->u.mapping->data->ind_types & ~(BIT_BASIC & ~BIT_TYPE)) {
+	  mapping_fix_type_field(val->u.mapping);
+	  if (val->u.mapping->data->ind_types & ~(BIT_BASIC & ~BIT_TYPE))
+	    /* This doesn't let bignums through. That's necessary as
+	     * long as they aren't handled deterministically by the
+	     * sort function. */
+	    error("Canonical encoding requires basic types in indices.\n");
+	}
+	order = get_switch_order(sp[-2].u.array);
+	order_array(sp[-2].u.array, order);
+	order_array(sp[-1].u.array, order);
+	free((char *) order);
+      }
+
       code_entry(TAG_MAPPING, sp[-2].u.array->size,data);
       for(i=0; i<sp[-2].u.array->size; i++)
       {
@@ -415,8 +434,28 @@ static void encode_value2(struct svalue *val, struct encode_data *data)
 
     case T_MULTISET:
       code_entry(TAG_MULTISET, val->u.multiset->ind->size,data);
-      for(i=0; i<val->u.multiset->ind->size; i++)
-	encode_value2(ITEM(val->u.multiset->ind)+i, data);
+      if (data->canonic) {
+	INT32 *order;
+	if (val->u.multiset->ind->type_field & ~(BIT_BASIC & ~BIT_TYPE)) {
+	  array_fix_type_field(val->u.multiset->ind);
+	  if (val->u.multiset->ind->type_field & ~(BIT_BASIC & ~BIT_TYPE))
+	    /* This doesn't let bignums through. That's necessary as
+	     * long as they aren't handled deterministically by the
+	     * sort function. */
+	    error("Canonical encoding requires basic types in indices.\n");
+	}
+	check_stack(1);
+	ref_push_array(val->u.multiset->ind);
+	order = get_switch_order(sp[-1].u.array);
+	order_array(sp[-1].u.array, order);
+	free((char *) order);
+	for (i = 0; i < sp[-1].u.array->size; i++)
+	  encode_value2(ITEM(sp[-1].u.array)+i, data);
+	pop_stack();
+      }
+      else
+	for(i=0; i<val->u.multiset->ind->size; i++)
+	  encode_value2(ITEM(val->u.multiset->ind)+i, data);
       break;
 
     case T_OBJECT:
@@ -442,6 +481,8 @@ static void encode_value2(struct svalue *val, struct encode_data *data)
       }
 #endif
 
+      if (data->canonic)
+	error("Canonical encoding of objects not supported.\n");
       push_svalue(val);
       apply(data->codec, "nameof", 1);
       switch(sp[-1].type)
@@ -472,6 +513,8 @@ static void encode_value2(struct svalue *val, struct encode_data *data)
       break;
 
     case T_FUNCTION:
+      if (data->canonic)
+	error("Canonical encoding of functions not supported.\n");
       check_stack(1);
       push_svalue(val);
       apply(data->codec,"nameof", 1);
@@ -518,6 +561,8 @@ static void encode_value2(struct svalue *val, struct encode_data *data)
     case T_PROGRAM:
     {
       int d;
+      if (data->canonic)
+	error("Canonical encoding of programs not supported.\n");
       check_stack(1);
       push_svalue(val);
       apply(data->codec,"nameof", 1);
@@ -627,6 +672,38 @@ void f_encode_value(INT32 args)
   check_all_args("encode_value", args, BIT_MIXED, BIT_VOID | BIT_OBJECT, 0);
 
   initialize_buf(&data->buf);
+  data->canonic = 0;
+  data->encoded=allocate_mapping(128);
+  data->counter.type=T_INT;
+  data->counter.u.integer=COUNTER_START;
+  if(args > 1)
+  {
+    data->codec=sp[1-args].u.object;
+  }else{
+    data->codec=get_master();
+  }
+
+  SET_ONERROR(tmp, free_encode_data, data);
+  addstr("\266ke0", 4);
+  encode_value2(sp-args, data);
+  UNSET_ONERROR(tmp);
+
+  free_mapping(data->encoded);
+
+  pop_n_elems(args);
+  push_string(low_free_buf(&data->buf));
+}
+
+void f_encode_value_canonic(INT32 args)
+{
+  ONERROR tmp;
+  struct encode_data d, *data;
+  data=&d;
+  
+  check_all_args("encode_value_canonic", args, BIT_MIXED, BIT_VOID | BIT_OBJECT, 0);
+
+  initialize_buf(&data->buf);
+  data->canonic = 1;
   data->encoded=allocate_mapping(128);
   data->counter.type=T_INT;
   data->counter.u.integer=COUNTER_START;
diff --git a/src/encode.h b/src/encode.h
index 77e4f42a65796354cb8defd349d43ef7b6bb44b3..4b3d489d9b4ea5de3401c0f882812070b156ec8c 100644
--- a/src/encode.h
+++ b/src/encode.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: encode.h,v 1.2 1998/03/28 15:31:23 grubba Exp $
+ * $Id: encode.h,v 1.3 2000/03/26 01:55:11 mast Exp $
  */
 #ifndef ENCODE_H
 #define ENCODE_H
@@ -13,6 +13,7 @@
 /* Prototypes begin here */
 struct encode_data;
 void f_encode_value(INT32 args);
+void f_encode_value_canonic(INT32 args);
 struct decode_data;
 void f_decode_value(INT32 args);
 /* Prototypes end here */