diff --git a/.gitattributes b/.gitattributes
index 9555a0d2ae8d565ef765d9056becd68f7cfaa68c..77e2fb18727174b67eb154e78c5403aeecf295b2 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -621,6 +621,7 @@ testfont binary
 /src/modules/_Charset/Makefile.in foreign_ident
 /src/modules/_Charset/acconfig.h foreign_ident
 /src/modules/_Charset/charsetmod.c foreign_ident
+/src/modules/_Charset/charsetmod.h foreign_ident
 /src/modules/_Charset/configure.in foreign_ident
 /src/modules/_Charset/iso2022.c foreign_ident
 /src/modules/_Charset/iso2022.h foreign_ident
diff --git a/src/modules/_Charset/charsetmod.c b/src/modules/_Charset/charsetmod.c
index 5e30a925d22ce4e790a17a2319005883502c79ae..df9813371b58034195ad5ec5ef4fb747cb30b4ce 100644
--- a/src/modules/_Charset/charsetmod.c
+++ b/src/modules/_Charset/charsetmod.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: charsetmod.c,v 1.66 2008/06/28 23:06:01 nilsson Exp $
+|| $Id: charsetmod.c,v 1.67 2008/06/29 12:52:02 mast Exp $
 */
 
 #ifdef HAVE_CONFIG_H
@@ -16,7 +16,9 @@
 #include "object.h"
 #include "module_support.h"
 #include "pike_error.h"
+#include "builtin_functions.h"
 
+#include "charsetmod.h"
 #include "iso2022.h"
 
 
@@ -31,21 +33,26 @@
 
 p_wchar1 *misc_charset_lookup(const char *name, int *rlo, int *rhi);
 
-static struct program *std_cs_program = NULL, *std_rfc_program = NULL;
+static struct program *std_cs_program = NULL;
 static struct program *utf1_program = NULL, *utf1e_program = NULL;
 static struct program *utf7_program = NULL, *utf8_program = NULL;
 static struct program *utf7e_program = NULL, *utf8e_program = NULL;
 static struct program *utf_ebcdic_program = NULL, *utf_ebcdice_program = NULL;
 static struct program *utf7_5_program = NULL, *utf7_5e_program = NULL;
 static struct program *euc_program = NULL, *sjis_program = NULL;
+static struct program *gbke_program = NULL;
+static struct program *multichar_program = NULL, *gb18030e_program = NULL;
+static struct program *rfc_base_program = NULL;
+/* The following inherit rfc_base_program. */
+static struct program *std_rfc_program = NULL;
 static struct program *euce_program = NULL, *sjise_program = NULL;
 static struct program *std_94_program = NULL, *std_96_program = NULL;
 static struct program *std_9494_program = NULL, *std_9696_program = NULL;
 static struct program *std_big5_program = NULL;
 static struct program *std_8bit_program = NULL, *std_8bite_program = NULL;
 static struct program *std_16bite_program = NULL;
-static struct program *multichar_program = NULL, *gb18030e_program = NULL;
-static struct program *gbke_program = NULL;
+
+static size_t rfc_charset_name_offs = 0;
 
 struct std_cs_stor { 
   struct string_builder strbuild;
@@ -71,12 +78,14 @@ static size_t utf7_stor_offs = 0;
 
 struct euc_stor {
   UNICHAR const *table, *table2, *table3;
+  struct pike_string *name;
 };
 static size_t euc_stor_offs = 0;
 
 struct multichar_stor {
   const struct multichar_table *table;
   int is_gb18030;
+  struct pike_string *name;
 };
 static size_t multichar_stor_offs = 0;
 
@@ -140,16 +149,91 @@ static int call_repcb(struct svalue *repcb, p_wchar2 ch)
   return 0;
 }
 
-#define REPLACE_CHAR(ch, func, ctx, pos) do {				\
+static struct svalue decode_err_prog = SVALUE_INIT_INT (0);
+static struct svalue encode_err_prog = SVALUE_INIT_INT (0);
+static void DECLSPEC(noreturn) transcode_error_va (
+  struct pike_string *str, ptrdiff_t pos, struct pike_string *charset,
+  int encode, const char *reason, va_list args) ATTRIBUTE((noreturn));
+
+static void DECLSPEC(noreturn) transcode_error_va (
+  struct pike_string *str, ptrdiff_t pos, struct pike_string *charset,
+  int encode, const char *reason, va_list args)
+/* Note: Consumes a ref to charset. */
+{
+  struct svalue *err_prog;
+
+  if (encode) {
+    if (encode_err_prog.type == T_INT) {
+      push_text ("Locale.Charset.EncodeError");
+      SAFE_APPLY_MASTER ("resolv", 1);
+      if (sp[-1].type != T_PROGRAM && sp[-1].type != T_FUNCTION)
+	Pike_error ("Failed to resolve Locale.Charset.EncodeError "
+		    "to a program - unable to throw an encode error.\n");
+      move_svalue (&encode_err_prog, --sp);
+    }
+    err_prog = &encode_err_prog;
+  }
+
+  else {
+    if (decode_err_prog.type == T_INT) {
+      push_text ("Locale.Charset.DecodeError");
+      SAFE_APPLY_MASTER ("resolv", 1);
+      if (sp[-1].type != T_PROGRAM && sp[-1].type != T_FUNCTION)
+	Pike_error ("Failed to resolve Locale.Charset.DecodeError "
+		    "to a program - unable to throw an decode error.\n");
+      move_svalue (&decode_err_prog, --sp);
+    }
+    err_prog = &decode_err_prog;
+  }
+
+  ref_push_string (str);
+  push_int (pos);
+  push_string (charset);
+  if (reason) {
+    struct string_builder s;
+    init_string_builder (&s, 0);
+    string_builder_vsprintf (&s, reason, args);
+    push_string (finish_string_builder (&s));
+  }
+  else
+    push_int (0);
+  f_backtrace (0);
+  apply_svalue (err_prog, 5);
+  f_throw (1);
+}
+
+void DECLSPEC(noreturn) transcode_error (
+  struct pike_string *str, ptrdiff_t pos, struct pike_string *charset,
+  int encode, const char *reason, ...)
+{
+  va_list args;
+  va_start (args, reason);
+  transcode_error_va (str, pos, charset, encode, reason, args);
+  va_end (args);
+}
+
+void DECLSPEC(noreturn) transcoder_error (
+  struct pike_string *str, ptrdiff_t pos, int encode, const char *reason, ...)
+{
+  struct svalue charset_str, charset;
+  va_list args;
+  va_start (args, reason);
+  charset_str.subtype = 0;
+  MAKE_CONST_STRING (charset_str.u.string, "charset");
+  charset_str.type = T_STRING;
+  object_index_no_free (&charset, fp->current_object, 0, &charset_str);
+  transcode_error_va (str, pos, charset.u.string, encode, reason, args);
+  va_end (args);
+}
+
+#define REPLACE_CHAR(ch, func, ctx, str, pos) do {			\
     if(repcb != NULL && call_repcb(repcb, ch)) {			\
       func(ctx, sb, sp[-1].u.string, rep, NULL);			\
       pop_stack();							\
     } else if(rep != NULL)						\
       func(ctx, sb, rep, NULL, NULL);					\
     else								\
-      Pike_error("Character 0x%x at position %"PRINTPTRDIFFT"d "	\
-		 "unsupported by encoding.\n",				\
-		 ch, (pos));						\
+      transcoder_error (str, pos, 1, "Unsupported character.\n");	\
   } while (0)
 
 #define MKREPCB(c) ((c).type == T_FUNCTION? &(c):NULL)
@@ -264,8 +348,7 @@ static void exit_stor(struct object *o)
   free_string_builder(&s->strbuild);
 }
 
-static void f_std_feed(INT32 args, ptrdiff_t (*func)(const p_wchar0 *,
-						     ptrdiff_t n,
+static void f_std_feed(INT32 args, ptrdiff_t (*func)(struct pike_string *,
 						     struct std_cs_stor *))
 {
   struct std_cs_stor *s = (struct std_cs_stor *)fp->current_storage;
@@ -283,7 +366,7 @@ static void f_std_feed(INT32 args, ptrdiff_t (*func)(const p_wchar0 *,
     args++;
   }
 
-  l = func(STR0(str), str->len, s);
+  l = func(str, s);
 
   if (s->retain) {
     free_string(s->retain);
@@ -297,8 +380,7 @@ static void f_std_feed(INT32 args, ptrdiff_t (*func)(const p_wchar0 *,
 }
 
 
-static ptrdiff_t feed_utf8(const p_wchar0 *p, ptrdiff_t l,
-			   struct std_cs_stor *s)
+static ptrdiff_t feed_utf8(struct pike_string *str, struct std_cs_stor *s)
 {
   static const int utf8cont[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 				  0, 0, 0, 0, 0, 0, 0, 0,
@@ -310,24 +392,26 @@ static ptrdiff_t feed_utf8(const p_wchar0 *p, ptrdiff_t l,
 				  3, 3, 3, 3, 0, 0, 0, 0 };
   static const unsigned int first_char_mask[] = {0x1f, 0x0f, 0x07, 0x03, 0x01};
 
-  const p_wchar0 *start = p;
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   for (; l > 0; l--) {
     unsigned int ch = *p++;
 
     if (ch & 0x80) {
       int cl = utf8cont[(ch>>1) - 64], i;
       if (!cl)
-	Pike_error ("Got invalid byte 0x%x at position %"PRINTPTRDIFFT"d.\n",
-		    ch, p - start - 1 - (s->retain ? s->retain->len : 0));
+	transcoder_error (str, p - STR0(str) - 1, 0, "Invalid byte.\n");
 
       ch &= first_char_mask[cl - 1];
 
       for (i = cl >= l ? l - 1 : cl; i--;) {
 	unsigned int c = *p++;
 	if ((c & 0xc0) != 0x80)
-	  Pike_error ("Got invalid UTF-8 sequence continuation byte 0x%x "
-		      "at position %"PRINTPTRDIFFT"d.\n",
-		      c, p - start - 1 - (s->retain ? s->retain->len : 0));
+	  /* Report the start of the invalid sequence to make things
+	   * easier for code that tries to recover from invalid UTF-8. */
+	  transcoder_error (str, p - STR0(str) -
+			    ((cl >= l ? l - 1 : cl) - i) - 1,
+			    0, "Truncated UTF-8 sequence.\n");
 	ch = (ch << 6) | (c & 0x3f);
       }
 
@@ -339,23 +423,13 @@ static ptrdiff_t feed_utf8(const p_wchar0 *p, ptrdiff_t l,
 	case 1: if (ch >= (1 << 7)) break;
 	case 2: if (ch >= (1 << 11)) break;
 	case 3: if (ch >= (1 << 16)) break;
-	  {
-	    ptrdiff_t errpos =
-	      p - start - cl - 1 - (s->retain ? s->retain->len : 0);
-	    if (errpos < 0) errpos = 0;
-	    Pike_error ("Got non-shortest form of char 0x%x "
-			"at position %"PRINTPTRDIFFT"d.\n",
-			ch, errpos);
-	  }
+	  transcoder_error (str, p - STR0(str) - cl - 1, 0,
+			    "Non-shortest form of character U+%04X.\n", ch);
       }
 
-      if ((ch >= 0xd800 && ch <= 0xdfff) || ch > 0x10ffff) {
-	ptrdiff_t errpos =
-	  p - start - cl - 1 - (s->retain ? s->retain->len : 0);
-	if (errpos < 0) errpos = 0;
-	Pike_error ("Char 0x%x at position %"PRINTPTRDIFFT"d "
-		    "is outside the valid range.\n", ch, errpos);
-      }
+      if ((ch >= 0xd800 && ch <= 0xdfff) || ch > 0x10ffff)
+	transcoder_error (str, p - STR0(str) - cl - 1, 0,
+			  "Character U+%04X is outside the valid range.\n", ch);
     }
 
     string_builder_putchar(&s->strbuild, ch);
@@ -407,7 +481,7 @@ static const unsigned char utf_ebcdic_to_i8_conv[] = {
   0x38, 0x39, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x9f,
 };
 
-static ptrdiff_t feed_utf_ebcdic(const p_wchar0 *p, ptrdiff_t l,
+static ptrdiff_t feed_utf_ebcdic(struct pike_string *str,
 				 struct std_cs_stor *s)
 {
   static const int cont[] = { 0, 0, 0, 0, 0, 0, 0, 0,
@@ -418,7 +492,8 @@ static ptrdiff_t feed_utf_ebcdic(const p_wchar0 *p, ptrdiff_t l,
 			      3, 3, 3, 3, 4, 4, 0, 0, };
   static const unsigned int first_char_mask[] = {0x1f, 0x0f, 0x07, 0x03, 0x01};
 
-  const p_wchar0 *start = p;
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   for (; l > 0; l--) {
     unsigned int ch = utf_ebcdic_to_i8_conv[*p++];
 
@@ -426,17 +501,18 @@ static ptrdiff_t feed_utf_ebcdic(const p_wchar0 *p, ptrdiff_t l,
       int cl = cont[(ch>>1) - 80];
       int i;
       if (!cl)
-	Pike_error ("Got invalid byte 0x%x at position %"PRINTPTRDIFFT"d.\n",
-		    ch, p - start - 1 - (s->retain ? s->retain->len : 0));
+	transcoder_error (str, p - STR0(str) - 1, 0, "Invalid byte.\n");
 
       ch &= first_char_mask[cl - 1];
 
       for (i = cl >= l ? l - 1 : cl; i--;) {
 	unsigned int c = utf_ebcdic_to_i8_conv[*p++];
 	if ((c & 0xe0) != 0xa0)
-	  Pike_error ("Got invalid UTF-EBCDIC I8-sequence continuation "
-		      "byte 0x%x at position %"PRINTPTRDIFFT"d.\n",
-		      c, p - start - 1 - (s->retain ? s->retain->len : 0));
+	  /* Report the start of the invalid sequence to make things
+	   * easier for code that tries to recover from invalid UTF-EBCDIC. */
+	  transcoder_error (str, p - STR0(str) -
+			    ((cl >= l ? l - 1 : cl) - i) - 1,
+			    0, "Truncated UTF-EBCDIC I8-sequence.\n");
 	ch = (ch << 5) | (c & 0x1f);
       }
 
@@ -451,23 +527,13 @@ static ptrdiff_t feed_utf_ebcdic(const p_wchar0 *p, ptrdiff_t l,
 	case 1: if (ch >= (1 << 7)) break;
 	case 2: if (ch >= (1 << 11)) break;
 	case 3: if (ch >= (1 << 16)) break;
-	  {
-	    ptrdiff_t errpos =
-	      p - start - cl - 1 - (s->retain ? s->retain->len : 0);
-	    if (errpos < 0) errpos = 0;
-	    Pike_error ("Got non-shortest form of char 0x%x "
-			"at position %"PRINTPTRDIFFT"d.\n",
-			ch, errpos);
-	  }
+	  transcoder_error (str, p - STR0(str) - cl - 1, 0,
+			    "Non-shortest form of character U+%04X.\n", ch);
       }
 
-      if ((ch >= 0xd800 && ch <= 0xdfff) || ch > 0x10ffff) {
-	ptrdiff_t errpos =
-	  p - start - cl - 1 - (s->retain ? s->retain->len : 0);
-	if (errpos < 0) errpos = 0;
-	Pike_error ("Char 0x%x at position %"PRINTPTRDIFFT"d "
-		    "is outside the valid range.\n", ch, errpos);
-      }
+      if ((ch >= 0xd800 && ch <= 0xdfff) || ch > 0x10ffff)
+	transcoder_error (str, p - STR0(str) - cl - 1, 0,
+			  "Character U+%04X is outside the valid range.\n", ch);
 #endif /* 0 */
     }
 
@@ -482,12 +548,14 @@ static void f_feed_utf_ebcdic(INT32 args)
   f_std_feed(args, feed_utf_ebcdic);
 }
 
-static ptrdiff_t feed_utf7_5(const p_wchar0 *p, ptrdiff_t l,
-			     struct std_cs_stor *s)
+static ptrdiff_t feed_utf7_5(struct pike_string *str, struct std_cs_stor *s)
 {
   static int utf7_5len[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 			    -1,-1, 1, 2,-1,-1,-1,-1, };
   static const unsigned INT32 utf7_5of[] = { 0ul, 0x28c0ul, 0xb30c0ul };
+
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   while(l>0) {
     unsigned INT32 ch = 0;
     int cl = utf7_5len[(*p)>>4];
@@ -514,13 +582,14 @@ static void f_feed_utf7_5(INT32 args)
   f_std_feed(args, feed_utf7_5);
 }
 
-static ptrdiff_t feed_utf7(const p_wchar0 *p, ptrdiff_t l,
-			   struct std_cs_stor *s)
+static ptrdiff_t feed_utf7(struct pike_string *str, struct std_cs_stor *s)
 {
   struct utf7_stor *u7 = (struct utf7_stor *)(((char*)s)+utf7_stor_offs);
   INT32 dat = u7->dat, surro = u7->surro;
   int shift = u7->shift, datbit = u7->datbit;
 
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   if(l<=0)
     return l;
 
@@ -638,10 +707,12 @@ static void f_feed_utf7(INT32 args)
   f_std_feed(args, feed_utf7);
 }
 
-static ptrdiff_t feed_sjis(const p_wchar0 *p, ptrdiff_t l,
-			   struct std_cs_stor *s)
+static ptrdiff_t feed_sjis(struct pike_string *str, struct std_cs_stor *s)
 {
   extern UNICHAR map_JIS_C6226_1983[];
+
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   while(l>0) {
     unsigned INT32 ch = *p++;
     if(ch < 0x80) {
@@ -686,14 +757,15 @@ static void f_feed_sjis(INT32 args)
   f_std_feed(args, feed_sjis);
 }
 
-static ptrdiff_t feed_euc(const p_wchar0 *p, ptrdiff_t l,
-			  struct std_cs_stor *s)
+static ptrdiff_t feed_euc(struct pike_string *str, struct std_cs_stor *s)
 {
   struct euc_stor *euc = (struct euc_stor *)(((char*)s)+euc_stor_offs);
   UNICHAR const *map = euc->table;
   UNICHAR const *map2 = euc->table2;
   UNICHAR const *map3 = euc->table3;
 
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   while(l>0) {
     unsigned INT32 ch = *p++;
     if(ch < 0x80) {
@@ -753,7 +825,7 @@ static void f_create_euc(INT32 args)
   struct pike_string *str;
   int lo=0, hi=num_charset_def-1;
 
-  check_all_args("create()", args, BIT_STRING, 0);
+  check_all_args("create()", args, BIT_STRING, BIT_STRING, 0);
 
   str = sp[-args].u.string;
 
@@ -784,6 +856,8 @@ static void f_create_euc(INT32 args)
     s->table3 = NULL;
   }
 
+  copy_shared_string (s->name, sp[1-args].u.string);
+
   pop_n_elems(args);
   push_int(0);
 }
@@ -808,6 +882,11 @@ static void f_create_multichar(INT32 args)
   s->table = def->table;
   /* NOTE: gb18030 is the first in the multichar map! */
   s->is_gb18030 = (def == multichar_map);
+
+  copy_shared_string (s->name, sp[-args].u.string);
+
+  pop_n_elems(args);
+  push_int(0);
 }
 
 #include "gb18030.h"
@@ -869,12 +948,14 @@ static ptrdiff_t feed_gb18030(const p_wchar0 *p, ptrdiff_t l,
   return -4;
 }
 
-static ptrdiff_t feed_multichar(const p_wchar0 *p, ptrdiff_t l,
+static ptrdiff_t feed_multichar(struct pike_string *str,
 				struct std_cs_stor *s)
 {
   struct multichar_stor *m = (struct multichar_stor *)(fp->current_storage + multichar_stor_offs);
   const struct multichar_table *table = m->table;
 
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   while(l>0) {
     unsigned INT32 ch = *p++;
     if(ch < 0x81) {
@@ -888,7 +969,7 @@ static ptrdiff_t feed_multichar(const p_wchar0 *p, ptrdiff_t l,
       const struct multichar_table page = table[ ch-0x81 ];
       if(l==1) return 1;
       if(ch==0xff) {
-	Pike_error("Illegal character: 0xff.\n");
+	transcoder_error (str, p - STR0(str) - 1, 0, "Illegal character.\n");
       }
       ch = *p++;
       if( ch<page.lo || ch>page.hi ) {
@@ -902,10 +983,11 @@ static ptrdiff_t feed_multichar(const p_wchar0 *p, ptrdiff_t l,
 	    /* More characters needed. */
 	    return delta;
 	  }
-	} 
-	Pike_error("Illegal character pair: 0x%02x 0x%02x "
-		   "(expected 0x%02x 0x%02x..0x%02x).\n",
-		   p[-2], ch, p[-2], page.lo, page.hi);
+	}
+	transcoder_error (str, p - STR0(str) - 2,
+			  0, "Illegal character pair: 0x%02x 0x%02x "
+			  "(expected 0x%02x 0x%02x..0x%02x).\n",
+			  p[-2], ch, p[-2], page.lo, page.hi);
       }
       else
 	string_builder_putchar(&s->strbuild, page.table[ch-page.lo]);
@@ -955,7 +1037,7 @@ static void feed_gb18030e(struct std_cs_stor *cs, struct string_builder *sb,
 	    string_builder_putchar(sb, 0x30 + index);
 	  }
 	} else {
-	  REPLACE_CHAR(c, feed_gb18030e, cs, p - STR0(str) - 1);
+	  REPLACE_CHAR(c, feed_gb18030e, cs, str, p - STR0(str) - 1);
 	}
     }
     break;
@@ -986,7 +1068,7 @@ static void feed_gb18030e(struct std_cs_stor *cs, struct string_builder *sb,
 	    string_builder_putchar(sb, 0x30 + index);
 	  }
 	} else {
-	  REPLACE_CHAR(c, feed_gb18030e, cs, p - STR1(str) - 1);
+	  REPLACE_CHAR(c, feed_gb18030e, cs, str, p - STR1(str) - 1);
 	}
     }
     break;
@@ -1018,7 +1100,7 @@ static void feed_gb18030e(struct std_cs_stor *cs, struct string_builder *sb,
 	    string_builder_putchar(sb, 0x30 + index);
 	  }
 	} else {
-	  REPLACE_CHAR(c, feed_gb18030e, cs, p - STR2(str) - 1);
+	  REPLACE_CHAR(c, feed_gb18030e, cs, str, p - STR2(str) - 1);
 	}
       }
     }
@@ -1064,7 +1146,7 @@ static void feed_gbke(struct std_cs_stor *cs, struct string_builder *sb,
 	  string_builder_putchar(sb, gb18030e_bytes[off]);
 	  string_builder_putchar(sb, gb18030e_bytes[off+1]);
 	} else {
-	  REPLACE_CHAR(c, feed_gbke, cs, p - STR0(str) - 1);
+	  REPLACE_CHAR(c, feed_gbke, cs, str, p - STR0(str) - 1);
 	}
     }
     break;
@@ -1081,7 +1163,7 @@ static void feed_gbke(struct std_cs_stor *cs, struct string_builder *sb,
 	  string_builder_putchar(sb, gb18030e_bytes[off]);
 	  string_builder_putchar(sb, gb18030e_bytes[off+1]);
 	} else {
-	  REPLACE_CHAR(c, feed_gbke, cs, p - STR1(str) - 1);
+	  REPLACE_CHAR(c, feed_gbke, cs, str, p - STR1(str) - 1);
 	}
     }
     break;
@@ -1099,7 +1181,7 @@ static void feed_gbke(struct std_cs_stor *cs, struct string_builder *sb,
 	  string_builder_putchar(sb, gb18030e_bytes[off]);
 	  string_builder_putchar(sb, gb18030e_bytes[off+1]);
 	} else {
-	  REPLACE_CHAR(c, feed_gbke, cs, p - STR2(str) - 1);
+	  REPLACE_CHAR(c, feed_gbke, cs, str, p - STR2(str) - 1);
 	}
       }
     }
@@ -1157,6 +1239,12 @@ static void f_create_sjise(INT32 args)
   s->revtab[0xa5 - s->lo] = 0x5c;
   s->revtab[0x203e - s->lo] = 0x7e;
 
+  /* Could use a program constant in this case, but that'd require a
+   * quirky inherit structure. /mast */
+  REF_MAKE_CONST_STRING (*(struct pike_string **) (fp->current_storage +
+						   rfc_charset_name_offs),
+			 "shiftjis");
+
   f_create(args);
   push_int(0);
 }
@@ -1170,7 +1258,8 @@ static void f_create_euce(INT32 args)
   int i, j, z, lo=0, hi=num_charset_def-1;
   UNICHAR const *table=NULL;
 
-  check_all_args("create()", args, BIT_STRING, BIT_STRING|BIT_VOID|BIT_INT,
+  check_all_args("create()", args, BIT_STRING, BIT_STRING,
+		 BIT_STRING|BIT_VOID|BIT_INT,
 		 BIT_FUNCTION|BIT_VOID|BIT_INT, 0);
 
   str = sp[-args].u.string;
@@ -1236,7 +1325,11 @@ static void f_create_euce(INT32 args)
       }
   }
 
-  f_create(args-1);
+  copy_shared_string (*(struct pike_string **) (fp->current_storage +
+						rfc_charset_name_offs),
+		      sp[1-args].u.string);
+
+  f_create(args-2);
   pop_stack();
   push_int(0);
 }
@@ -1244,13 +1337,13 @@ static void f_create_euce(INT32 args)
 static struct std8e_stor *push_std_8bite(int args, int allargs, int lo, int hi)
 {
   struct std8e_stor *s8;
-  push_object(clone_object(std_8bite_program, args));
-  if((allargs-=args)>0) {
-    struct object *o = sp[-1].u.object;
-    add_ref(o);
-    pop_n_elems(allargs+1);
-    push_object(o);
-  }
+  struct object *o = clone_object(std_8bite_program, args);
+  allargs -= args;
+  copy_shared_string (*(struct pike_string **) (o->storage +
+						rfc_charset_name_offs),
+		      sp[-allargs].u.string);
+  pop_n_elems(allargs);
+  push_object(o);
   s8 = (struct std8e_stor *)(sp[-1].u.object->storage+std8e_stor_offs);
   memset((s8->revtab = (p_wchar0 *)xalloc((hi-lo)*sizeof(p_wchar0))), 0,
 	 (hi-lo)*sizeof(p_wchar0));
@@ -1263,13 +1356,13 @@ static struct std8e_stor *push_std_8bite(int args, int allargs, int lo, int hi)
 static struct std16e_stor *push_std_16bite(int args, int allargs, int lo, int hi)
 {
   struct std16e_stor *s16;
-  push_object(clone_object(std_16bite_program, args));
-  if((allargs-=args)>0) {
-    struct object *o = sp[-1].u.object;
-    add_ref(o);
-    pop_n_elems(allargs+1);
-    push_object(o);
-  }
+  struct object *o = clone_object(std_16bite_program, args);
+  allargs -= args;
+  copy_shared_string (*(struct pike_string **) (o->storage +
+						rfc_charset_name_offs),
+		      sp[-allargs].u.string);
+  pop_n_elems(allargs);
+  push_object(o);
   s16 = (struct std16e_stor *)(sp[-1].u.object->storage+std16e_stor_offs);
   memset((s16->revtab = (p_wchar1 *)xalloc((hi-lo)*sizeof(p_wchar1))), 0,
 	 (hi-lo)*sizeof(p_wchar1));
@@ -1348,7 +1441,6 @@ static void f_rfc1345(INT32 args)
 	return;
       }
 
-      pop_n_elems(args);
       switch(charset_map[mid].mode) {
       case MODE_94: p = std_94_program; break;
       case MODE_96: p = std_96_program; break;
@@ -1358,9 +1450,17 @@ static void f_rfc1345(INT32 args)
       default:
 	Pike_fatal("Internal error in rfc1345\n");
       }
-      push_object(clone_object(p, 0));
-      ((struct std_rfc_stor *)(sp[-1].u.object->storage+std_rfc_stor_offs))
-	->table = charset_map[mid].table;
+
+      {
+	struct object *o = clone_object(p, 0);
+	((struct std_rfc_stor *)(o->storage+std_rfc_stor_offs))
+	  ->table = charset_map[mid].table;
+	copy_shared_string (*(struct pike_string **) (o->storage +
+						      rfc_charset_name_offs),
+			    sp[-args].u.string);
+	pop_n_elems(args);
+	push_object (o);
+      }
       return;
     }
     if(c<0)
@@ -1390,25 +1490,33 @@ static void f_rfc1345(INT32 args)
       return;
     }
 
-    pop_n_elems(args);
-    push_object(clone_object(std_8bit_program, 0));
-    ((struct std_rfc_stor *)(sp[-1].u.object->storage+std_rfc_stor_offs))
-      ->table = (UNICHAR *)tabl;
-    ((struct std_misc_stor *)(sp[-1].u.object->storage+std_misc_stor_offs))
-      ->lo = lo;
-    ((struct std_misc_stor *)(sp[-1].u.object->storage+std_misc_stor_offs))
-      ->hi = hi;
-    return;    
+    {
+      struct object *o = clone_object(std_8bit_program, 0);
+      ((struct std_rfc_stor *)(o->storage+std_rfc_stor_offs))
+	->table = (UNICHAR *)tabl;
+      ((struct std_misc_stor *)(o->storage+std_misc_stor_offs))
+	->lo = lo;
+      ((struct std_misc_stor *)(o->storage+std_misc_stor_offs))
+	->hi = hi;
+      copy_shared_string (*(struct pike_string **) (o->storage +
+						    rfc_charset_name_offs),
+			  sp[-args].u.string);
+      pop_n_elems(args);
+      push_object(o);
+    }
+    return;
   }
 
   pop_n_elems(args);
   push_int(0);
 }
 
-static ptrdiff_t feed_94(const p_wchar0 *p, ptrdiff_t l, struct std_cs_stor *s)
+static ptrdiff_t feed_94(struct pike_string *str, struct std_cs_stor *s)
 {
   UNICHAR const *table =
     ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table;
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   while(l--) {
     p_wchar0 x = *p++;
     if(x<=0x20 || x>=0x7f)
@@ -1424,10 +1532,12 @@ static void f_feed_94(INT32 args)
   f_std_feed(args, feed_94);
 }
 
-static ptrdiff_t feed_96(const p_wchar0 *p, ptrdiff_t l, struct std_cs_stor *s)
+static ptrdiff_t feed_96(struct pike_string *str, struct std_cs_stor *s)
 {
   UNICHAR const *table =
     ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table;
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   while(l--) {
     p_wchar0 x = *p++;
     if(x<0xa0)
@@ -1443,11 +1553,12 @@ static void f_feed_96(INT32 args)
   f_std_feed(args, feed_96);
 }
 
-static ptrdiff_t feed_9494(const p_wchar0 *p, ptrdiff_t l,
-			   struct std_cs_stor *s)
+static ptrdiff_t feed_9494(struct pike_string *str, struct std_cs_stor *s)
 {
   UNICHAR const *table =
     ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table;
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   while(l--) {
     p_wchar0 y, x = (*p++)&0x7f;
     if(x<=0x20 || x>=0x7f)
@@ -1472,11 +1583,12 @@ static void f_feed_9494(INT32 args)
   f_std_feed(args, feed_9494);
 }
 
-static ptrdiff_t feed_9696(const p_wchar0 *p, ptrdiff_t l,
-			   struct std_cs_stor *s)
+static ptrdiff_t feed_9696(struct pike_string *str, struct std_cs_stor *s)
 {
   UNICHAR const *table =
     ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table;
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   while(l--) {
     p_wchar0 y, x = (*p++)&0x7f;
     if(x<0x20)
@@ -1501,10 +1613,12 @@ static void f_feed_9696(INT32 args)
   f_std_feed(args, feed_9696);
 }
 
-static ptrdiff_t feed_big5(const p_wchar0 *p, ptrdiff_t l, struct std_cs_stor *s)
+static ptrdiff_t feed_big5(struct pike_string *str, struct std_cs_stor *s)
 {
   UNICHAR const *table =
     ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table;
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   while(l--) {
     p_wchar0 y, x = (*p++);
     if(x<0xa1 || x>0xf9 )
@@ -1527,8 +1641,7 @@ static void f_feed_big5(INT32 args)
   f_std_feed(args, feed_big5);
 }
 
-static ptrdiff_t feed_8bit(const p_wchar0 *p, ptrdiff_t l,
-			   struct std_cs_stor *s)
+static ptrdiff_t feed_8bit(struct pike_string *str, struct std_cs_stor *s)
 {
   UNICHAR const *table =
     ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table;
@@ -1536,6 +1649,8 @@ static ptrdiff_t feed_8bit(const p_wchar0 *p, ptrdiff_t l,
     ((struct std_misc_stor *)(((char*)s)+std_misc_stor_offs));
   int lo = misc->lo, hi = misc->hi;
 
+  const p_wchar0 *p = STR0(str);
+  ptrdiff_t l = str->len;
   while(l--) {
     p_wchar0 x = *p++;
     if(x<lo || (x>0x7f && hi<=0x7f))
@@ -1587,7 +1702,7 @@ static void feed_utf8e(struct std_cs_stor *cs, struct string_builder *sb,
 	  string_builder_putchar(sb, 0x80|((c>>6)&0x3f));
 	  string_builder_putchar(sb, 0x80|(c&0x3f));	
 	} else
-	  REPLACE_CHAR(c, feed_utf8e, cs, p - STR1(str) - 1);
+	  REPLACE_CHAR(c, feed_utf8e, cs, str, p - STR1(str) - 1);
     }
     break;
   case 2:
@@ -1616,7 +1731,7 @@ static void feed_utf8e(struct std_cs_stor *cs, struct string_builder *sb,
 	  string_builder_putchar(sb, 0x80|(c&0x3f));	
 	  continue;
 	}
-	REPLACE_CHAR(c, feed_utf8e, cs, p - STR2(str) - 1);
+	REPLACE_CHAR(c, feed_utf8e, cs, str, p - STR2(str) - 1);
       }
     }
     break;
@@ -1716,7 +1831,7 @@ static void feed_utf_ebcdice(struct std_cs_stor *cs, struct string_builder *sb,
 	  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|((c>>5)&0x1f)]);
 	  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|(c&0x1f)]);
 	} else
-	  REPLACE_CHAR(c, feed_utf_ebcdice, cs, p - STR1(str) - 1);
+	  REPLACE_CHAR(c, feed_utf_ebcdice, cs, str, p - STR1(str) - 1);
     }
     break;
   case 2:
@@ -1752,7 +1867,7 @@ static void feed_utf_ebcdice(struct std_cs_stor *cs, struct string_builder *sb,
 	  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|(c&0x1f)]);
 	  continue;
 	}
-	REPLACE_CHAR(c, feed_utf_ebcdice, cs, p - STR2(str) - 1);
+	REPLACE_CHAR(c, feed_utf_ebcdice, cs, str, p - STR2(str) - 1);
       }
     }
     break;
@@ -1825,7 +1940,7 @@ static void feed_utf7_5e(struct std_cs_stor *cs, struct string_builder *sb,
 	  string_builder_putchar(sb, 0xc0|((c>>6)&0x3f));
 	  string_builder_putchar(sb, 0xc0|(c&0x3f));	
 	} else
-	  REPLACE_CHAR(c, feed_utf7_5e, cs, p - STR2(str) - 1);
+	  REPLACE_CHAR(c, feed_utf7_5e, cs, str, p - STR2(str) - 1);
       /* FIXME: Encode using surrogates? */
     }
     break;
@@ -1954,7 +2069,7 @@ static void feed_utf7e(struct utf7_stor *u7, struct string_builder *sb,
 	  u7->dat = dat;
 	  u7->shift = shift;
 	  u7->datbit = datbit;
-	  REPLACE_CHAR(c, feed_utf7e, u7, p - STR2(str) - 1);
+	  REPLACE_CHAR(c, feed_utf7e, u7, str, p - STR2(str) - 1);
 	  dat = u7->dat;
 	  shift = u7->shift;
 	  datbit = u7->datbit;
@@ -2067,7 +2182,7 @@ static void feed_std8e(struct std8e_stor *s8, struct string_builder *sb,
 	else if(c>=lo && c<hi && (ch=tab[c-lo])!=0)
 	  string_builder_putchar(sb, ch);
 	else
-	  REPLACE_CHAR(c, feed_std8e, s8, p - STR0(str) - 1);
+	  REPLACE_CHAR(c, feed_std8e, s8, str, p - STR0(str) - 1);
     }
     break;
   case 1:
@@ -2079,7 +2194,7 @@ static void feed_std8e(struct std8e_stor *s8, struct string_builder *sb,
 	else if(c>=lo && c<hi && (ch=tab[c-lo])!=0)
 	  string_builder_putchar(sb, ch);
 	else
-	  REPLACE_CHAR(c, feed_std8e, s8, p - STR1(str) - 1);
+	  REPLACE_CHAR(c, feed_std8e, s8, str, p - STR1(str) - 1);
     }
     break;
   case 2:
@@ -2091,7 +2206,7 @@ static void feed_std8e(struct std8e_stor *s8, struct string_builder *sb,
 	else if(c>=lo && c<hi && (ch=tab[c-lo])!=0)
 	  string_builder_putchar(sb, ch);
 	else
-	  REPLACE_CHAR(c, feed_std8e, s8, p - STR2(str) - 1);
+	  REPLACE_CHAR(c, feed_std8e, s8, str, p - STR2(str) - 1);
     }
     break;
 #ifdef PIKE_DEBUG
@@ -2163,7 +2278,7 @@ static void feed_std16e(struct std16e_stor *s16, struct string_builder *sb,
 	    string_builder_putchar(sb, (ch>>8)&0xff);
 	  string_builder_putchar(sb, ch&0xff);
 	} else
-	  REPLACE_CHAR(c, feed_std16e, s16, p - STR0(str) - 1);
+	  REPLACE_CHAR(c, feed_std16e, s16, str, p - STR0(str) - 1);
     }
     break;
   case 1:
@@ -2181,7 +2296,7 @@ static void feed_std16e(struct std16e_stor *s16, struct string_builder *sb,
 	    string_builder_putchar(sb, (ch>>8)&0xff);
 	  string_builder_putchar(sb, ch&0xff);
 	} else
-	  REPLACE_CHAR(c, feed_std16e, s16, p - STR1(str) - 1);
+	  REPLACE_CHAR(c, feed_std16e, s16, str, p - STR1(str) - 1);
     }
     break;
   case 2:
@@ -2199,7 +2314,7 @@ static void feed_std16e(struct std16e_stor *s16, struct string_builder *sb,
 	    string_builder_putchar(sb, (ch>>8)&0xff);
 	  string_builder_putchar(sb, ch&0xff);
 	} else
-	  REPLACE_CHAR(c, feed_std16e, s16, p - STR2(str) - 1);
+	  REPLACE_CHAR(c, feed_std16e, s16, str, p - STR2(str) - 1);
     }
     break;
 #ifdef PIKE_DEBUG
@@ -2260,6 +2375,7 @@ PIKE_MODULE_INIT
   start_new_program();
   do_inherit(&prog, 0, NULL);
   utf7_stor_offs = ADD_STORAGE(struct utf7_stor);
+  add_string_constant ("charset", "utf7", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_utf7,tFunc(tStr,tObj), 0);
   /* function(:object) */
@@ -2269,6 +2385,7 @@ PIKE_MODULE_INIT
 
   start_new_program();
   do_inherit(&prog, 0, NULL);
+  add_string_constant ("charset", "utf8", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_utf8,tFunc(tStr,tObj), 0);
   add_program_constant("UTF8dec", utf8_program = end_program(), ID_PROTECTED|ID_FINAL);
@@ -2276,6 +2393,7 @@ PIKE_MODULE_INIT
   prog.u.program = utf7_program;
   start_new_program();
   do_inherit(&prog, 0, NULL);
+  add_string_constant ("charset", "utf7", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_utf7e,tFunc(tStr,tObj), 0);
   /* function(:string) */
@@ -2285,18 +2403,21 @@ PIKE_MODULE_INIT
 
   start_new_program();
   do_inherit(&prog, 0, NULL);
+  add_string_constant ("charset", "utf8", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_utf8e,tFunc(tStr,tObj), 0);
   add_program_constant("UTF8enc", utf8e_program = end_program(), ID_PROTECTED|ID_FINAL);
 
   start_new_program();
   do_inherit(&prog, 0, NULL);
+  add_string_constant ("charset", "utfebcdic", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_utf_ebcdic,tFunc(tStr,tObj), 0);
   add_program_constant("UTF_EBCDICdec", utf_ebcdic_program = end_program(), ID_PROTECTED|ID_FINAL);
 
   start_new_program();
   do_inherit(&prog, 0, NULL);
+  add_string_constant ("charset", "utfebcdic", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_utf_ebcdice,tFunc(tStr,tObj), 0);
   add_program_constant("UTF_EBCDICenc", utf_ebcdice_program = end_program(), ID_PROTECTED|ID_FINAL);
@@ -2304,11 +2425,13 @@ PIKE_MODULE_INIT
   start_new_program();
   do_inherit(&prog, 0, NULL);
   /* function(string:object) */
+  add_string_constant ("charset", "utf75", 0);
   ADD_FUNCTION("feed", f_feed_utf7_5,tFunc(tStr,tObj), 0);
   add_program_constant("UTF7_5dec", utf7_5_program = end_program(), ID_PROTECTED|ID_FINAL);
 
   start_new_program();
   do_inherit(&prog, 0, NULL);
+  add_string_constant ("charset", "utf75", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_utf7_5e,tFunc(tStr,tObj), 0);
   add_program_constant("UTF7_5enc", utf7_5e_program = end_program(), ID_PROTECTED|ID_FINAL);
@@ -2316,37 +2439,53 @@ PIKE_MODULE_INIT
   start_new_program();
   do_inherit(&prog, 0, NULL);
   euc_stor_offs = ADD_STORAGE(struct euc_stor);
+  PIKE_MAP_VARIABLE ("charset", euc_stor_offs + OFFSETOF (euc_stor, name),
+		     tStr, T_STRING, 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_euc,tFunc(tStr,tObj), 0);
-  /* function(string:) */
-  ADD_FUNCTION("create", f_create_euc,tFunc(tStr,tVoid), ID_PROTECTED);
+  /* function(string,string:) */
+  ADD_FUNCTION("create", f_create_euc,tFunc(tStr tStr,tVoid), ID_PROTECTED);
   add_program_constant("EUCDec", euc_program = end_program(), ID_PROTECTED|ID_FINAL);
 
   start_new_program();
   do_inherit(&prog, 0, NULL);
   multichar_stor_offs = ADD_STORAGE(struct multichar_stor);
+  PIKE_MAP_VARIABLE ("charset",
+		     multichar_stor_offs + OFFSETOF (multichar_stor, name),
+		     tStr, T_STRING, 0);
   ADD_FUNCTION("create", f_create_multichar,tFunc(tStr,tVoid), ID_PROTECTED);
   ADD_FUNCTION("feed", f_feed_multichar,tFunc(tStr,tObj), 0);
   add_program_constant("MulticharDec", multichar_program = end_program(), ID_PROTECTED|ID_FINAL);
 
   start_new_program();
   do_inherit(&prog, 0, NULL);
+  add_string_constant ("charset", "gb18030", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_gb18030e,tFunc(tStr,tObj), 0);
   add_program_constant("GB18030Enc", gb18030e_program = end_program(), ID_PROTECTED|ID_FINAL);
 
   start_new_program();
   do_inherit(&prog, 0, NULL);
+  add_string_constant ("charset", "gbk", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_gbke,tFunc(tStr,tObj), 0);
   add_program_constant("GBKenc", gbke_program = end_program(), ID_PROTECTED|ID_FINAL);
 
   start_new_program();
   do_inherit(&prog, 0, NULL);
+  add_string_constant ("charset", "shiftjis", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed_sjis,tFunc(tStr,tObj), 0);
   add_program_constant("ShiftJisDec", sjis_program = end_program(), ID_PROTECTED|ID_FINAL);
 
+  start_new_program();
+  do_inherit (&prog, 0, NULL);
+  rfc_charset_name_offs = ADD_STORAGE (struct pike_string *);
+  PIKE_MAP_VARIABLE ("charset", rfc_charset_name_offs, tStr, T_STRING, 0);
+  rfc_base_program = end_program();
+
+  prog.u.program = rfc_base_program;
+
   start_new_program();
   do_inherit(&prog, 0, NULL);
   std8e_stor_offs = ADD_STORAGE(struct std8e_stor);
@@ -2375,8 +2514,8 @@ PIKE_MODULE_INIT
 
   start_new_program();
   do_inherit(&prog, 0, NULL);
-  /* function(string,string|void,function(string:string)|void:void) */
-  ADD_FUNCTION("create", f_create_euce,tFunc(tStr tOr(tStr,tVoid) tOr(tFunc(tStr,tStr),tVoid),tVoid), 0);
+  /* function(string,string,string|void,function(string:string)|void:void) */
+  ADD_FUNCTION("create", f_create_euce,tFunc(tStr tStr tOr(tStr,tVoid) tOr(tFunc(tStr,tStr),tVoid),tVoid), 0);
   add_program_constant("EUCEnc", euce_program = end_program(), ID_PROTECTED|ID_FINAL);
 
   start_new_program();
@@ -2427,6 +2566,8 @@ PIKE_MODULE_INIT
   add_function_constant("rfc1345", f_rfc1345,
 			"function(string,int|void,string|void,"
 			"function(string:string)|void:object)", 0);
+
+  PIKE_MODULE_EXPORT (_Charset, transcode_error_va);
 }
 
 PIKE_MODULE_EXIT
@@ -2493,6 +2634,9 @@ PIKE_MODULE_EXIT
   if(std_16bite_program != NULL)
     free_program(std_16bite_program);
 
+  if(rfc_base_program != NULL)
+    free_program(rfc_base_program);
+
   if(std_rfc_program != NULL)
     free_program(std_rfc_program);
 
@@ -2509,4 +2653,7 @@ PIKE_MODULE_EXIT
     free_program(multichar_program);
 
   iso2022_exit();
+
+  if (encode_err_prog.type != T_INT) free_svalue (&encode_err_prog);
+  if (decode_err_prog.type != T_INT) free_svalue (&decode_err_prog);
 }
diff --git a/src/modules/_Charset/charsetmod.h b/src/modules/_Charset/charsetmod.h
new file mode 100644
index 0000000000000000000000000000000000000000..9aa339e1e5600751a8f41716af3f448a77aa3d5e
--- /dev/null
+++ b/src/modules/_Charset/charsetmod.h
@@ -0,0 +1,24 @@
+/*
+|| This file is part of Pike. For copyright information see COPYRIGHT.
+|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
+|| for more information.
+|| $Id: charsetmod.h,v 1.1 2008/06/29 12:52:03 mast Exp $
+*/
+
+#ifndef CHARSETMOD_H
+#define CHARSETMOD_H
+
+static void DECLSPEC(noreturn) transcode_error_va (
+  struct pike_string *str, ptrdiff_t pos, struct pike_string *charset,
+  int encode, const char *reason, va_list args) ATTRIBUTE((noreturn));
+
+void DECLSPEC(noreturn) transcode_error (
+  struct pike_string *str, ptrdiff_t pos, struct pike_string *charset,
+  int encode, const char *reason, ...);
+
+/* This picks out the charset by indexing Pike_fp->current_object with
+ * "charset". */
+void DECLSPEC(noreturn) transcoder_error (
+  struct pike_string *str, ptrdiff_t pos, int encode, const char *reason, ...);
+
+#endif	/* !CHARSETMOD_H */
diff --git a/src/modules/_Charset/iso2022.c b/src/modules/_Charset/iso2022.c
index 455de21fed46683e08634bb96cab327d23045182..d0966e566043c45aea51e6ec5cf722b1f3ee98f7 100644
--- a/src/modules/_Charset/iso2022.c
+++ b/src/modules/_Charset/iso2022.c
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: iso2022.c,v 1.48 2008/06/28 23:06:02 nilsson Exp $
+|| $Id: iso2022.c,v 1.49 2008/06/29 12:52:03 mast Exp $
 */
 
 #ifdef HAVE_CONFIG_H
@@ -17,6 +17,7 @@
 #include "module_support.h"
 #include "pike_error.h"
 
+#include "charsetmod.h"
 #include "iso2022.h"
 
 
@@ -52,6 +53,7 @@ struct iso2022enc_stor {
   struct pike_string *replace;
   struct string_builder strbuild;
   struct svalue repcb;
+  struct pike_string *name;
 };
 
 #define EMIT(X) string_builder_putchar(&s->strbuild,(X))
@@ -359,16 +361,14 @@ static int call_repcb(struct svalue *repcb, p_wchar2 ch)
   return 0;
 }
 
-#define REPLACE_CHAR(ch, pos)			       \
+#define REPLACE_CHAR(ch, str, pos)		       \
           if(repcb != NULL && call_repcb(repcb, ch)) { \
 	    eat_enc_string(sp[-1].u.string, s, rep, NULL); \
             pop_stack(); \
 	  } else if(rep != NULL) \
             eat_enc_string(rep, s, NULL, NULL); \
 	  else \
-	    Pike_error("Character %lu at position %"PRINTPTRDIFFT"d "	\
-		       "unsupported by encoding.\n",			\
-		       (unsigned long) ch, (pos));
+	    transcoder_error (str, pos, 1, "Unsupported character.\n");
 
 static const unsigned INT32 jp2_tab[] = {
   0x000003c0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
@@ -857,7 +857,7 @@ static void eat_enc_string(struct pike_string *str, struct iso2022enc_stor *s,
 	  string_builder_putchar(&s->strbuild,c);
 	} else if(c==0xfffd) {
 	  /* Substitution character... */
-	  REPLACE_CHAR(0xfffd,
+	  REPLACE_CHAR(0xfffd, str,
 		       s1 ? (p_wchar1 *) p - STR1(str) - 1 :
 		       (p_wchar2 *) p - STR2(str) - 1);
 	} else if(s->r[0].map != NULL && c >= s->r[0].lo && c < s->r[0].hi &&
@@ -1193,7 +1193,7 @@ static void eat_enc_string(struct pike_string *str, struct iso2022enc_stor *s,
 	  if(ttab == NULL) {
 	    if(rmap != NULL)
 	      free(rmap);
-	    REPLACE_CHAR(c,
+	    REPLACE_CHAR(c, str,
 			 s1 ? (p_wchar1 *) p - STR1(str) - 1 :
 			 (p_wchar2 *) p - STR2(str) - 1);
 	  }
@@ -1375,16 +1375,26 @@ static void select_encoding_parameters(struct iso2022enc_stor *s,
   if(str == NULL || str->size_shift)
     Pike_error("Invalid ISO2022 encoding variant\n");
   var = (char *)STR0(str);
-  if(!*var)
+  if(!*var) {
     s->variant = 0;
-  else if(!strcmp(var, "jp"))
+    REF_MAKE_CONST_STRING (s->name, "iso2022");
+  }
+  else if(!strcmp(var, "jp")) {
     s->variant = VARIANT_JP;
-  else if(!strcmp(var, "cn") || !strcmp(var, "cnext"))
+    REF_MAKE_CONST_STRING (s->name, "iso2022jp");
+  }
+  else if(!strcmp(var, "cn") || !strcmp(var, "cnext")) {
     s->variant = VARIANT_CN;
-  else if(!strcmp(var, "kr"))
+    REF_MAKE_CONST_STRING (s->name, "iso2022cn");
+  }
+  else if(!strcmp(var, "kr")) {
     s->variant = VARIANT_KR;
-  else if(!strcmp(var, "jp2"))
+    REF_MAKE_CONST_STRING (s->name, "iso2022kr");
+  }
+  else if(!strcmp(var, "jp2")) {
     s->variant = VARIANT_JP2;
+    REF_MAKE_CONST_STRING (s->name, "iso2022jp2");
+  }
   else
     Pike_error("Invalid ISO2022 encoding variant\n");
 }
@@ -1485,6 +1495,7 @@ void iso2022_init(void)
 {
   start_new_program();
   ADD_STORAGE(struct iso2022_stor);
+  add_string_constant ("charset", "iso2022", 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_feed,tFunc(tStr,tObj), 0);
   /* function(:string) */
@@ -1498,13 +1509,15 @@ void iso2022_init(void)
 
   start_new_program();
   ADD_STORAGE(struct iso2022enc_stor);
+  PIKE_MAP_VARIABLE ("charset", OFFSETOF (iso2022enc_stor, name),
+		     tStr, T_STRING, 0);
   /* function(string:object) */
   ADD_FUNCTION("feed", f_enc_feed,tFunc(tStr,tObj), 0);
   /* function(:string) */
   ADD_FUNCTION("drain", f_enc_drain,tFunc(tNone,tStr), 0);
   /* function(:object) */
   ADD_FUNCTION("clear", f_enc_clear,tFunc(tNone,tObj), 0);
-  /* function(string|void,function(string:string)|void:void) */
+  /* function(string,string|void,function(string:string)|void:void) */
   ADD_FUNCTION("create", f_create,tFunc(tStr tOr(tStr,tVoid) tOr(tFunc(tStr,tStr),tVoid),tVoid), 0);
   /* function(function(string:string):void) */
   ADD_FUNCTION("set_replacement_callback", f_set_repcb,tFunc(tFunc(tStr,tStr),tVoid), 0);