*** empty log message ***
[bpt/emacs.git] / src / coding.c
index b62a413..bd7e219 100644 (file)
@@ -212,8 +212,8 @@ decode_coding_XXXX (coding)
      when there's no room in CHARBUF for a decoded character.  */
   unsigned char *src_base;
   /* A buffer to produce decoded characters.  */
-  int *charbuf = coding->charbuf;
-  int *charbuf_end = charbuf + coding->charbuf_size;
+  int *charbuf = coding->charbuf + coding->charbuf_used;
+  int *charbuf_end = coding->charbuf + coding->charbuf_size;
   int multibytep = coding->src_multibyte;
 
   while (1)
@@ -311,13 +311,18 @@ Lisp_Object Qcharset, Qiso_2022, Qutf_8, Qutf_16, Qshift_jis, Qbig5;
 Lisp_Object Qbig, Qlittle;
 Lisp_Object Qcoding_system_history;
 Lisp_Object Qvalid_codes;
-Lisp_Object QCcategory;
+Lisp_Object QCcategory, QCmnemonic, QCdefalut_char;
+Lisp_Object QCdecode_translation_table, QCencode_translation_table;
+Lisp_Object QCpost_read_conversion, QCpre_write_conversion;
 
 extern Lisp_Object Qinsert_file_contents, Qwrite_region;
 Lisp_Object Qcall_process, Qcall_process_region, Qprocess_argument;
 Lisp_Object Qstart_process, Qopen_network_stream;
 Lisp_Object Qtarget_idx;
 
+Lisp_Object Qinsufficient_source, Qinconsistent_eol, Qinvalid_source;
+Lisp_Object Qinterrupted, Qinsufficient_memory;
+
 int coding_system_require_warning;
 
 Lisp_Object Vselect_safe_coding_system_function;
@@ -347,7 +352,8 @@ Lisp_Object Vcoding_system_for_read;
 Lisp_Object Vcoding_system_for_write;
 /* Coding-system actually used in the latest I/O.  */
 Lisp_Object Vlast_coding_system_used;
-
+/* Set to non-nil when an error is detected while code conversion.  */
+Lisp_Object Vlast_code_conversion_error;
 /* A vector of length 256 which contains information about special
    Latin codes (especially for dealing with Microsoft codes).  */
 Lisp_Object Vlatin_extra_code_table;
@@ -405,46 +411,6 @@ Lisp_Object Vtranslation_table_for_input;
 Lisp_Object Vsjis_coding_system;
 Lisp_Object Vbig5_coding_system;
 
-
-static int detect_coding_utf_8 P_ ((struct coding_system *,
-                                   struct coding_detection_info *info));
-static void decode_coding_utf_8 P_ ((struct coding_system *));
-static int encode_coding_utf_8 P_ ((struct coding_system *));
-
-static int detect_coding_utf_16 P_ ((struct coding_system *,
-                                    struct coding_detection_info *info));
-static void decode_coding_utf_16 P_ ((struct coding_system *));
-static int encode_coding_utf_16 P_ ((struct coding_system *));
-
-static int detect_coding_iso_2022 P_ ((struct coding_system *,
-                                      struct coding_detection_info *info));
-static void decode_coding_iso_2022 P_ ((struct coding_system *));
-static int encode_coding_iso_2022 P_ ((struct coding_system *));
-
-static int detect_coding_emacs_mule P_ ((struct coding_system *,
-                                        struct coding_detection_info *info));
-static void decode_coding_emacs_mule P_ ((struct coding_system *));
-static int encode_coding_emacs_mule P_ ((struct coding_system *));
-
-static int detect_coding_sjis P_ ((struct coding_system *,
-                                  struct coding_detection_info *info));
-static void decode_coding_sjis P_ ((struct coding_system *));
-static int encode_coding_sjis P_ ((struct coding_system *));
-
-static int detect_coding_big5 P_ ((struct coding_system *,
-                                  struct coding_detection_info *info));
-static void decode_coding_big5 P_ ((struct coding_system *));
-static int encode_coding_big5 P_ ((struct coding_system *));
-
-static int detect_coding_ccl P_ ((struct coding_system *,
-                                 struct coding_detection_info *info));
-static void decode_coding_ccl P_ ((struct coding_system *));
-static int encode_coding_ccl P_ ((struct coding_system *));
-
-static void decode_coding_raw_text P_ ((struct coding_system *));
-static int encode_coding_raw_text P_ ((struct coding_system *));
-
-
 /* ISO2022 section */
 
 #define CODING_ISO_INITIAL(coding, reg)                        \
@@ -718,40 +684,52 @@ static struct coding_system coding_categories[coding_category_max];
 
 /* Safely get one byte from the source text pointed by SRC which ends
    at SRC_END, and set C to that byte.  If there are not enough bytes
-   in the source, it jumps to `no_more_source'.  The caller
-   should declare and set these variables appropriately in advance:
-       src, src_end, multibytep
-*/
+   in the source, it jumps to `no_more_source'.  If multibytep is
+   nonzero, and a multibyte character is found at SRC, set C to the
+   negative value of the character code.  The caller should declare
+   and set these variables appropriately in advance:
+       src, src_end, multibytep */
 
-#define ONE_MORE_BYTE(c)                                       \
-  do {                                                         \
-    if (src == src_end)                                                \
-      {                                                                \
-       if (src_base < src)                                     \
-         coding->result = CODING_RESULT_INSUFFICIENT_SRC;      \
-       goto no_more_source;                                    \
-      }                                                                \
-    c = *src++;                                                        \
-    if (multibytep && (c & 0x80))                              \
-      {                                                                \
-       if ((c & 0xFE) != 0xC0)                                 \
-         error ("Undecodable char found");                     \
-       c = ((c & 1) << 6) | *src++;                            \
-      }                                                                \
-    consumed_chars++;                                          \
+#define ONE_MORE_BYTE(c)                               \
+  do {                                                 \
+    if (src == src_end)                                        \
+      {                                                        \
+       if (src_base < src)                             \
+         record_conversion_result                      \
+           (coding, CODING_RESULT_INSUFFICIENT_SRC);   \
+       goto no_more_source;                            \
+      }                                                        \
+    c = *src++;                                                \
+    if (multibytep && (c & 0x80))                      \
+      {                                                        \
+       if ((c & 0xFE) == 0xC0)                         \
+         c = ((c & 1) << 6) | *src++;                  \
+       else                                            \
+         {                                             \
+           c = - string_char (--src, &src, NULL);      \
+           record_conversion_result                    \
+             (coding, CODING_RESULT_INVALID_SRC);      \
+         }                                             \
+      }                                                        \
+    consumed_chars++;                                  \
   } while (0)
 
 
-#define ONE_MORE_BYTE_NO_CHECK(c)              \
-  do {                                         \
-    c = *src++;                                        \
-    if (multibytep && (c & 0x80))              \
-      {                                                \
-       if ((c & 0xFE) != 0xC0)                 \
-         error ("Undecodable char found");     \
-       c = ((c & 1) << 6) | *src++;            \
-      }                                                \
-    consumed_chars++;                          \
+#define ONE_MORE_BYTE_NO_CHECK(c)                      \
+  do {                                                 \
+    c = *src++;                                                \
+    if (multibytep && (c & 0x80))                      \
+      {                                                        \
+       if ((c & 0xFE) == 0xC0)                         \
+         c = ((c & 1) << 6) | *src++;                  \
+       else                                            \
+         {                                             \
+           c = - string_char (--src, &src, NULL);      \
+           record_conversion_result                    \
+             (coding, CODING_RESULT_INVALID_SRC);      \
+         }                                             \
+      }                                                        \
+    consumed_chars++;                                  \
   } while (0)
 
 
@@ -839,6 +817,110 @@ static struct coding_system coding_categories[coding_category_max];
   } while (0)
 
 
+/* Prototypes for static functions.  */
+static void record_conversion_result P_ ((struct coding_system *coding,
+                                         enum coding_result_code result));
+static int detect_coding_utf_8 P_ ((struct coding_system *,
+                                   struct coding_detection_info *info));
+static void decode_coding_utf_8 P_ ((struct coding_system *));
+static int encode_coding_utf_8 P_ ((struct coding_system *));
+
+static int detect_coding_utf_16 P_ ((struct coding_system *,
+                                    struct coding_detection_info *info));
+static void decode_coding_utf_16 P_ ((struct coding_system *));
+static int encode_coding_utf_16 P_ ((struct coding_system *));
+
+static int detect_coding_iso_2022 P_ ((struct coding_system *,
+                                      struct coding_detection_info *info));
+static void decode_coding_iso_2022 P_ ((struct coding_system *));
+static int encode_coding_iso_2022 P_ ((struct coding_system *));
+
+static int detect_coding_emacs_mule P_ ((struct coding_system *,
+                                        struct coding_detection_info *info));
+static void decode_coding_emacs_mule P_ ((struct coding_system *));
+static int encode_coding_emacs_mule P_ ((struct coding_system *));
+
+static int detect_coding_sjis P_ ((struct coding_system *,
+                                  struct coding_detection_info *info));
+static void decode_coding_sjis P_ ((struct coding_system *));
+static int encode_coding_sjis P_ ((struct coding_system *));
+
+static int detect_coding_big5 P_ ((struct coding_system *,
+                                  struct coding_detection_info *info));
+static void decode_coding_big5 P_ ((struct coding_system *));
+static int encode_coding_big5 P_ ((struct coding_system *));
+
+static int detect_coding_ccl P_ ((struct coding_system *,
+                                 struct coding_detection_info *info));
+static void decode_coding_ccl P_ ((struct coding_system *));
+static int encode_coding_ccl P_ ((struct coding_system *));
+
+static void decode_coding_raw_text P_ ((struct coding_system *));
+static int encode_coding_raw_text P_ ((struct coding_system *));
+
+static void coding_set_source P_ ((struct coding_system *));
+static void coding_set_destination P_ ((struct coding_system *));
+static void coding_alloc_by_realloc P_ ((struct coding_system *, EMACS_INT));
+static void coding_alloc_by_making_gap P_ ((struct coding_system *,
+                                           EMACS_INT));
+static unsigned char *alloc_destination P_ ((struct coding_system *,
+                                            EMACS_INT, unsigned char *));
+static void setup_iso_safe_charsets P_ ((Lisp_Object));
+static unsigned char *encode_designation_at_bol P_ ((struct coding_system *,
+                                                    int *, int *,
+                                                    unsigned char *));
+static int detect_eol P_ ((const unsigned char *,
+                          EMACS_INT, enum coding_category));
+static Lisp_Object adjust_coding_eol_type P_ ((struct coding_system *, int));
+static void decode_eol P_ ((struct coding_system *));
+static Lisp_Object get_translation_table P_ ((Lisp_Object, int, int *));
+static Lisp_Object get_translation P_ ((Lisp_Object, int *, int *,
+                                       int, int *, int *));
+static int produce_chars P_ ((struct coding_system *, Lisp_Object, int));
+static INLINE void produce_composition P_ ((struct coding_system *, int *,
+                                           EMACS_INT));
+static INLINE void produce_charset P_ ((struct coding_system *, int *,
+                                       EMACS_INT));
+static void produce_annotation P_ ((struct coding_system *, EMACS_INT));
+static int decode_coding P_ ((struct coding_system *));
+static INLINE int *handle_composition_annotation P_ ((EMACS_INT, EMACS_INT,
+                                                     struct coding_system *, 
+                                                     int *, EMACS_INT *));
+static INLINE int *handle_charset_annotation P_ ((EMACS_INT, EMACS_INT,
+                                                 struct coding_system *,
+                                                 int *, EMACS_INT *));
+static void consume_chars P_ ((struct coding_system *, Lisp_Object, int));
+static int encode_coding P_ ((struct coding_system *));
+static Lisp_Object make_conversion_work_buffer P_ ((int));
+static Lisp_Object code_conversion_restore P_ ((Lisp_Object));
+static INLINE int char_encodable_p P_ ((int, Lisp_Object));
+static Lisp_Object make_subsidiaries P_ ((Lisp_Object));
+
+static void
+record_conversion_result (struct coding_system *coding,
+                         enum coding_result_code result)
+{
+  coding->result = result;
+  switch (result)
+    {
+    case CODING_RESULT_INSUFFICIENT_SRC:
+      Vlast_code_conversion_error = Qinsufficient_source;
+      break;
+    case CODING_RESULT_INCONSISTENT_EOL:
+      Vlast_code_conversion_error = Qinconsistent_eol;
+      break;
+    case CODING_RESULT_INVALID_SRC:
+      Vlast_code_conversion_error = Qinvalid_source;
+      break;
+    case CODING_RESULT_INTERRUPT:
+      Vlast_code_conversion_error = Qinterrupted;
+      break;
+    case CODING_RESULT_INSUFFICIENT_MEM:
+      Vlast_code_conversion_error = Qinsufficient_memory;
+      break;
+    }
+}
+
 #define CODING_DECODE_CHAR(coding, src, src_base, src_end, charset, code, c) \
   do {                                                                      \
     charset_map_loaded = 0;                                                 \
@@ -971,7 +1053,7 @@ alloc_destination (coding, nbytes, dst)
     coding_alloc_by_making_gap (coding, nbytes);
   else
     coding_alloc_by_realloc (coding, nbytes);
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   coding_set_destination (coding);
   dst = coding->destination + offset;
   return dst;
@@ -981,15 +1063,14 @@ alloc_destination (coding, nbytes, dst)
 
 /* Maximum length of annotation data (sum of annotations for
    composition and charset).  */
-#define MAX_ANNOTATION_LENGTH (5 + (MAX_COMPOSITION_COMPONENTS * 2) - 1 + 5)
+#define MAX_ANNOTATION_LENGTH (4 + (MAX_COMPOSITION_COMPONENTS * 2) - 1 + 4)
 
 /* An annotation data is stored in the array coding->charbuf in this
    format:
-     [ -LENGTH ANNOTATION_MASK FROM TO ... ]
+     [ -LENGTH ANNOTATION_MASK NCHARS ... ]
    LENGTH is the number of elements in the annotation.
    ANNOTATION_MASK is one of CODING_ANNOTATE_XXX_MASK.
-   FROM and TO specify the range of text annotated.  They are relative
-   to coding->src_pos (on encoding) or coding->dst_pos (on decoding).
+   NCHARS is the number of characters in the text annotated.
 
    The format of the following elements depend on ANNOTATION_MASK.
 
@@ -1003,26 +1084,25 @@ alloc_destination (coding, nbytes, dst)
    In the case of CODING_ANNOTATE_CHARSET_MASK, one element CHARSET-ID
    follows.  */
 
-#define ADD_ANNOTATION_DATA(buf, len, mask, from, to)  \
+#define ADD_ANNOTATION_DATA(buf, len, mask, nchars)    \
   do {                                                 \
     *(buf)++ = -(len);                                 \
     *(buf)++ = (mask);                                 \
-    *(buf)++ = (from);                                 \
-    *(buf)++ = (to);                                   \
+    *(buf)++ = (nchars);                               \
     coding->annotated = 1;                             \
   } while (0);
 
-#define ADD_COMPOSITION_DATA(buf, from, to, method)                          \
-  do {                                                                       \
-    ADD_ANNOTATION_DATA (buf, 5, CODING_ANNOTATE_COMPOSITION_MASK, from, to); \
-    *buf++ = method;                                                         \
+#define ADD_COMPOSITION_DATA(buf, nchars, method)                          \
+  do {                                                                     \
+    ADD_ANNOTATION_DATA (buf, 4, CODING_ANNOTATE_COMPOSITION_MASK, nchars); \
+    *buf++ = method;                                                       \
   } while (0)
 
 
-#define ADD_CHARSET_DATA(buf, from, to, id)                              \
-  do {                                                                   \
-    ADD_ANNOTATION_DATA (buf, 5, CODING_ANNOTATE_CHARSET_MASK, from, to); \
-    *buf++ = id;                                                         \
+#define ADD_CHARSET_DATA(buf, nchars, id)                              \
+  do {                                                                 \
+    ADD_ANNOTATION_DATA (buf, 4, CODING_ANNOTATE_CHARSET_MASK, nchars);        \
+    *buf++ = id;                                                       \
   } while (0)
 
 \f
@@ -1049,12 +1129,11 @@ detect_coding_utf_8 (coding, detect_info)
      struct coding_system *coding;
      struct coding_detection_info *detect_info;
 {
-  const unsigned char *src = coding->source, *src_base = src;
+  const unsigned char *src = coding->source, *src_base;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   int multibytep = coding->src_multibyte;
   int consumed_chars = 0;
   int found = 0;
-  int incomplete;
 
   detect_info->checked |= CATEGORY_MASK_UTF_8;
   /* A coding system of this category is always ASCII compatible.  */
@@ -1064,13 +1143,12 @@ detect_coding_utf_8 (coding, detect_info)
     {
       int c, c1, c2, c3, c4;
 
-      incomplete = 0;
+      src_base = src;
       ONE_MORE_BYTE (c);
-      if (UTF_8_1_OCTET_P (c))
+      if (c < 0 || UTF_8_1_OCTET_P (c))
        continue;
-      incomplete = 1;
       ONE_MORE_BYTE (c1);
-      if (! UTF_8_EXTRA_OCTET_P (c1))
+      if (c1 < 0 || ! UTF_8_EXTRA_OCTET_P (c1))
        break;
       if (UTF_8_2_OCTET_LEADING_P (c))
        {
@@ -1078,7 +1156,7 @@ detect_coding_utf_8 (coding, detect_info)
          continue;
        }
       ONE_MORE_BYTE (c2);
-      if (! UTF_8_EXTRA_OCTET_P (c2))
+      if (c2 < 0 || ! UTF_8_EXTRA_OCTET_P (c2))
        break;
       if (UTF_8_3_OCTET_LEADING_P (c))
        {
@@ -1086,7 +1164,7 @@ detect_coding_utf_8 (coding, detect_info)
          continue;
        }
       ONE_MORE_BYTE (c3);
-      if (! UTF_8_EXTRA_OCTET_P (c3))
+      if (c3 < 0 || ! UTF_8_EXTRA_OCTET_P (c3))
        break;
       if (UTF_8_4_OCTET_LEADING_P (c))
        {
@@ -1094,7 +1172,7 @@ detect_coding_utf_8 (coding, detect_info)
          continue;
        }
       ONE_MORE_BYTE (c4);
-      if (! UTF_8_EXTRA_OCTET_P (c4))
+      if (c4 < 0 || ! UTF_8_EXTRA_OCTET_P (c4))
        break;
       if (UTF_8_5_OCTET_LEADING_P (c))
        {
@@ -1107,7 +1185,7 @@ detect_coding_utf_8 (coding, detect_info)
   return 0;
 
  no_more_source:
-  if (incomplete && coding->mode & CODING_MODE_LAST_BLOCK)
+  if (src_base < src && coding->mode & CODING_MODE_LAST_BLOCK)
     {
       detect_info->rejected |= CATEGORY_MASK_UTF_8;
       return 0;
@@ -1124,8 +1202,8 @@ decode_coding_utf_8 (coding)
   const unsigned char *src = coding->source + coding->consumed;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   const unsigned char *src_base;
-  int *charbuf = coding->charbuf;
-  int *charbuf_end = charbuf + coding->charbuf_size;
+  int *charbuf = coding->charbuf + coding->charbuf_used;
+  int *charbuf_end = coding->charbuf + coding->charbuf_size;
   int consumed_chars = 0, consumed_chars_base;
   int multibytep = coding->src_multibyte;
   Lisp_Object attr, charset_list;
@@ -1143,14 +1221,18 @@ decode_coding_utf_8 (coding)
        break;
 
       ONE_MORE_BYTE (c1);
-      if (UTF_8_1_OCTET_P(c1))
+      if (c1 < 0)
+       {
+         c = - c1;
+       }
+      else if (UTF_8_1_OCTET_P(c1))
        {
          c = c1;
        }
       else
        {
          ONE_MORE_BYTE (c2);
-         if (! UTF_8_EXTRA_OCTET_P (c2))
+         if (c2 < 0 || ! UTF_8_EXTRA_OCTET_P (c2))
            goto invalid_code;
          if (UTF_8_2_OCTET_LEADING_P (c1))
            {
@@ -1164,7 +1246,7 @@ decode_coding_utf_8 (coding)
          else
            {
              ONE_MORE_BYTE (c3);
-             if (! UTF_8_EXTRA_OCTET_P (c3))
+             if (c3 < 0 || ! UTF_8_EXTRA_OCTET_P (c3))
                goto invalid_code;
              if (UTF_8_3_OCTET_LEADING_P (c1))
                {
@@ -1177,7 +1259,7 @@ decode_coding_utf_8 (coding)
              else
                {
                  ONE_MORE_BYTE (c4);
-                 if (! UTF_8_EXTRA_OCTET_P (c4))
+                 if (c4 < 0 || ! UTF_8_EXTRA_OCTET_P (c4))
                    goto invalid_code;
                  if (UTF_8_4_OCTET_LEADING_P (c1))
                    {
@@ -1189,7 +1271,7 @@ decode_coding_utf_8 (coding)
                  else
                    {
                      ONE_MORE_BYTE (c5);
-                     if (! UTF_8_EXTRA_OCTET_P (c5))
+                     if (c5 < 0 || ! UTF_8_EXTRA_OCTET_P (c5))
                        goto invalid_code;
                      if (UTF_8_5_OCTET_LEADING_P (c1))
                        {
@@ -1267,11 +1349,14 @@ encode_coding_utf_8 (coding)
        {
          ASSURE_DESTINATION (safe_room);
          c = *charbuf++;
-         dst += CHAR_STRING (c, dst);
+         if (CHAR_BYTE8_P (c))
+           *dst++ = CHAR_TO_BYTE8 (c);
+         else
+           dst += CHAR_STRING (c, dst);
          produced_chars++;
        }
     }
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   coding->produced_char += produced_chars;
   coding->produced = dst - coding->destination;
   return 0;
@@ -1331,25 +1416,8 @@ detect_coding_utf_16 (coding, detect_info)
                                | CATEGORY_MASK_UTF_16_BE_NOSIG
                                | CATEGORY_MASK_UTF_16_LE_NOSIG);
     }
-  else
+  else if (c1 >= 0 && c2 >= 0)
     {
-      unsigned char b1[256], b2[256];
-      int b1_variants = 1, b2_variants = 1;
-      int n;
-
-      bzero (b1, 256), bzero (b2, 256);
-      b1[c1]++, b2[c2]++;
-      for (n = 0; n < 256 && src < src_end; n++)
-       {
-         ONE_MORE_BYTE (c1);
-         ONE_MORE_BYTE (c2);
-         if (! b1[c1++]) b1_variants++;
-         if (! b2[c2++]) b2_variants++;
-       }
-      if (b1_variants < b2_variants)
-       detect_info->found |= CATEGORY_MASK_UTF_16_BE_NOSIG;
-      else
-       detect_info->found |= CATEGORY_MASK_UTF_16_LE_NOSIG;      
       detect_info->rejected
        |= (CATEGORY_MASK_UTF_16_BE | CATEGORY_MASK_UTF_16_LE);
     }
@@ -1364,8 +1432,8 @@ decode_coding_utf_16 (coding)
   const unsigned char *src = coding->source + coding->consumed;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   const unsigned char *src_base;
-  int *charbuf = coding->charbuf;
-  int *charbuf_end = charbuf + coding->charbuf_size;
+  int *charbuf = coding->charbuf + coding->charbuf_used;
+  int *charbuf_end = coding->charbuf + coding->charbuf_size;
   int consumed_chars = 0, consumed_chars_base;
   int multibytep = coding->src_multibyte;
   enum utf_16_bom_type bom = CODING_UTF_16_BOM (coding);
@@ -1412,7 +1480,18 @@ decode_coding_utf_16 (coding)
        break;
 
       ONE_MORE_BYTE (c1);
+      if (c1 < 0)
+       {
+         *charbuf++ = -c1;
+         continue;
+       }
       ONE_MORE_BYTE (c2);
+      if (c2 < 0)
+       {
+         *charbuf++ = ASCII_BYTE_P (c1) ? c1 : BYTE8_TO_CHAR (c1);
+         *charbuf++ = -c2;
+         continue;
+       }
       c = (endian == utf_16_big_endian
           ? ((c1 << 8) | c2) : ((c2 << 8) | c1));
       if (surrogate)
@@ -1435,7 +1514,7 @@ decode_coding_utf_16 (coding)
            {
              c = ((surrogate - 0xD800) << 10) | (c - 0xDC00);
              CODING_UTF_16_SURROGATE (coding) = surrogate = 0;
-             *charbuf++ = c;
+             *charbuf++ = 0x10000 + c;
            }
        }
       else
@@ -1508,7 +1587,7 @@ encode_coding_utf_16 (coding)
            EMIT_FOUR_BYTES (c1 & 0xFF, c1 >> 8, c2 & 0xFF, c2 >> 8);
        }
     }
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   coding->produced = dst - coding->destination;
   coding->produced_char += produced_chars;
   return 0;
@@ -1593,7 +1672,7 @@ char emacs_mule_bytes[256];
 int
 emacs_mule_char (coding, src, nbytes, nchars, id)
      struct coding_system *coding;
-     unsigned char *src;
+     const unsigned char *src;
      int *nbytes, *nchars, *id;
 {
   const unsigned char *src_end = coding->source + coding->src_bytes;
@@ -1605,58 +1684,78 @@ emacs_mule_char (coding, src, nbytes, nchars, id)
   int consumed_chars = 0;
 
   ONE_MORE_BYTE (c);
-  switch (emacs_mule_bytes[c])
+  if (c < 0)
     {
-    case 2:
-      if (! (charset = emacs_mule_charset[c]))
-       goto invalid_code;
-      ONE_MORE_BYTE (c);
-      code = c & 0x7F;
-      break;
-
-    case 3:
-      if (c == EMACS_MULE_LEADING_CODE_PRIVATE_11
-         || c == EMACS_MULE_LEADING_CODE_PRIVATE_12)
+      c = -c;
+      charset = emacs_mule_charset[0];
+    }
+  else
+    {
+      switch (emacs_mule_bytes[c])
        {
-         ONE_MORE_BYTE (c);
+       case 2:
          if (! (charset = emacs_mule_charset[c]))
            goto invalid_code;
          ONE_MORE_BYTE (c);
+         if (c < 0xA0)
+           goto invalid_code;
          code = c & 0x7F;
-       }
-      else
-       {
-         if (! (charset = emacs_mule_charset[c]))
+         break;
+
+       case 3:
+         if (c == EMACS_MULE_LEADING_CODE_PRIVATE_11
+             || c == EMACS_MULE_LEADING_CODE_PRIVATE_12)
+           {
+             ONE_MORE_BYTE (c);
+             if (c < 0xA0 || ! (charset = emacs_mule_charset[c]))
+               goto invalid_code;
+             ONE_MORE_BYTE (c);
+             if (c < 0xA0)
+               goto invalid_code;
+             code = c & 0x7F;
+           }
+         else
+           {
+             if (! (charset = emacs_mule_charset[c]))
+               goto invalid_code;
+             ONE_MORE_BYTE (c);
+             if (c < 0xA0)
+               goto invalid_code;
+             code = (c & 0x7F) << 8;
+             ONE_MORE_BYTE (c);
+             if (c < 0xA0)
+               goto invalid_code;
+             code |= c & 0x7F;
+           }
+         break;
+
+       case 4:
+         ONE_MORE_BYTE (c);
+         if (c < 0 || ! (charset = emacs_mule_charset[c]))
            goto invalid_code;
          ONE_MORE_BYTE (c);
+         if (c < 0xA0)
+           goto invalid_code;
          code = (c & 0x7F) << 8;
          ONE_MORE_BYTE (c);
+         if (c < 0xA0)
+           goto invalid_code;
          code |= c & 0x7F;
-       }
-      break;
-
-    case 4:
-      ONE_MORE_BYTE (c);
-      if (! (charset = emacs_mule_charset[c]))
-       goto invalid_code;
-      ONE_MORE_BYTE (c);
-      code = (c & 0x7F) << 8;
-      ONE_MORE_BYTE (c);
-      code |= c & 0x7F;
-      break;
+         break;
 
-    case 1:
-      code = c;
-      charset = CHARSET_FROM_ID (ASCII_BYTE_P (code)
-                                ? charset_ascii : charset_eight_bit);
-      break;
+       case 1:
+         code = c;
+         charset = CHARSET_FROM_ID (ASCII_BYTE_P (code)
+                                    ? charset_ascii : charset_eight_bit);
+         break;
 
-    default:
-      abort ();
+       default:
+         abort ();
+       }
+      c = DECODE_CHAR (charset, code);
+      if (c < 0)
+       goto invalid_code;
     }
-  c = DECODE_CHAR (charset, code);
-  if (c < 0)
-    goto invalid_code;
   *nbytes = src - src_base;
   *nchars = consumed_chars;
   if (id)
@@ -1680,13 +1779,12 @@ detect_coding_emacs_mule (coding, detect_info)
      struct coding_system *coding;
      struct coding_detection_info *detect_info;
 {
-  const unsigned char *src = coding->source, *src_base = src;
+  const unsigned char *src = coding->source, *src_base;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   int multibytep = coding->src_multibyte;
   int consumed_chars = 0;
   int c;
   int found = 0;
-  int incomplete;
 
   detect_info->checked |= CATEGORY_MASK_EMACS_MULE;
   /* A coding system of this category is always ASCII compatible.  */
@@ -1694,10 +1792,10 @@ detect_coding_emacs_mule (coding, detect_info)
 
   while (1)
     {
-      incomplete = 0;
+      src_base = src;
       ONE_MORE_BYTE (c);
-      incomplete = 1;
-
+      if (c < 0)
+       continue;
       if (c == 0x80)
        {
          /* Perhaps the start of composite character.  We simple skip
@@ -1729,14 +1827,19 @@ detect_coding_emacs_mule (coding, detect_info)
        }
       else
        {
-         const unsigned char *src_base = src - 1;
+         int more_bytes = emacs_mule_bytes[*src_base] - 1;
 
-         do
+         while (more_bytes > 0)
            {
              ONE_MORE_BYTE (c);
+             if (c < 0xA0)
+               {
+                 src--;        /* Unread the last byte.  */
+                 break;
+               }
+             more_bytes--;
            }
-         while (c >= 0xA0);
-         if (src - src_base != emacs_mule_bytes[*src_base])
+         if (more_bytes != 0)
            break;
          found = CATEGORY_MASK_EMACS_MULE;
        }
@@ -1745,7 +1848,7 @@ detect_coding_emacs_mule (coding, detect_info)
   return 0;
 
  no_more_source:
-  if (incomplete && coding->mode & CODING_MODE_LAST_BLOCK)
+  if (src_base < src && coding->mode & CODING_MODE_LAST_BLOCK)
     {
       detect_info->rejected |= CATEGORY_MASK_EMACS_MULE;
       return 0;
@@ -1837,19 +1940,20 @@ detect_coding_emacs_mule (coding, detect_info)
        number of characters composed by this composition.  */          \
     enum composition_method method = c - 0xF2;                         \
     int *charbuf_base = charbuf;                                       \
-    int from, to;                                                      \
     int consumed_chars_limit;                                          \
     int nbytes, nchars;                                                        \
                                                                        \
     ONE_MORE_BYTE (c);                                                 \
+    if (c < 0)                                                         \
+      goto invalid_code;                                               \
     nbytes = c - 0xA0;                                                 \
     if (nbytes < 3)                                                    \
       goto invalid_code;                                               \
     ONE_MORE_BYTE (c);                                                 \
+    if (c < 0)                                                         \
+      goto invalid_code;                                               \
     nchars = c - 0xA0;                                                 \
-    from = coding->produced + char_offset;                             \
-    to = from + nchars;                                                        \
-    ADD_COMPOSITION_DATA (charbuf, from, to, method);                  \
+    ADD_COMPOSITION_DATA (charbuf, nchars, method);                    \
     consumed_chars_limit = consumed_chars_base + nbytes;               \
     if (method != COMPOSITION_RELATIVE)                                        \
       {                                                                        \
@@ -1877,7 +1981,6 @@ detect_coding_emacs_mule (coding, detect_info)
     int components[MAX_COMPOSITION_COMPONENTS * 2 - 1];                \
     int *buf = components;                                     \
     int i, j;                                                  \
-    int from, to;                                              \
                                                                \
     src = src_base;                                            \
     ONE_MORE_BYTE (c);         /* skip 0x80 */                 \
@@ -1885,9 +1988,7 @@ detect_coding_emacs_mule (coding, detect_info)
       DECODE_EMACS_MULE_COMPOSITION_CHAR (buf);                        \
     if (i < 2)                                                 \
       goto invalid_code;                                       \
-    from = coding->produced_char + char_offset;                        \
-    to = from + i;                                             \
-    ADD_COMPOSITION_DATA (charbuf, from, to, method);          \
+    ADD_COMPOSITION_DATA (charbuf, i, method);                 \
     for (j = 0; j < i; j++)                                    \
       *charbuf++ = components[j];                              \
   } while (0)
@@ -1901,7 +2002,6 @@ detect_coding_emacs_mule (coding, detect_info)
     int components[MAX_COMPOSITION_COMPONENTS * 2 - 1];                \
     int *buf = components;                                     \
     int i, j;                                                  \
-    int from, to;                                              \
                                                                \
     DECODE_EMACS_MULE_COMPOSITION_CHAR (buf);                  \
     for (i = 0; i < MAX_COMPOSITION_COMPONENTS; i++)           \
@@ -1913,9 +2013,7 @@ detect_coding_emacs_mule (coding, detect_info)
       goto invalid_code;                                       \
     if (charbuf + i + (i / 2) + 1 < charbuf_end)               \
       goto no_more_source;                                     \
-    from = coding->produced_char + char_offset;                        \
-    to = from + i;                                             \
-    ADD_COMPOSITION_DATA (buf, from, to, method);              \
+    ADD_COMPOSITION_DATA (buf, i, method);                     \
     for (j = 0; j < i; j++)                                    \
       *charbuf++ = components[j];                              \
     for (j = 0; j < i; j += 2)                                 \
@@ -1930,8 +2028,9 @@ decode_coding_emacs_mule (coding)
   const unsigned char *src = coding->source + coding->consumed;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   const unsigned char *src_base;
-  int *charbuf = coding->charbuf;
-  int *charbuf_end = charbuf + coding->charbuf_size - MAX_ANNOTATION_LENGTH;
+  int *charbuf = coding->charbuf + coding->charbuf_used;
+  int *charbuf_end
+    = coding->charbuf + coding->charbuf_size - MAX_ANNOTATION_LENGTH;
   int consumed_chars = 0, consumed_chars_base;
   int multibytep = coding->src_multibyte;
   Lisp_Object attrs, charset_list;
@@ -1952,8 +2051,12 @@ decode_coding_emacs_mule (coding)
        break;
 
       ONE_MORE_BYTE (c);
-
-      if (c < 0x80)
+      if (c < 0)
+       {
+         *charbuf++ = -c;
+         char_offset++;
+       }
+      else if (c < 0x80)
        {
          *charbuf++ = c;
          char_offset++;
@@ -1961,6 +2064,8 @@ decode_coding_emacs_mule (coding)
       else if (c == 0x80)
        {
          ONE_MORE_BYTE (c);
+         if (c < 0)
+           goto invalid_code;
          if (c - 0xF2 >= COMPOSITION_RELATIVE
              && c - 0xF2 <= COMPOSITION_WITH_RULE_ALTCHARS)
            DECODE_EMACS_MULE_21_COMPOSITION (c);
@@ -1988,7 +2093,7 @@ decode_coding_emacs_mule (coding)
          if (last_id != id)
            {
              if (last_id != charset_ascii)
-               ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+               ADD_CHARSET_DATA (charbuf, char_offset - last_offset, last_id);
              last_id = id;
              last_offset = char_offset;
            }
@@ -2010,7 +2115,7 @@ decode_coding_emacs_mule (coding)
 
  no_more_source:
   if (last_id != charset_ascii)
-    ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+    ADD_CHARSET_DATA (charbuf, char_offset - last_offset, last_id);
   coding->consumed_char += consumed_chars_base;
   coding->consumed = src_base - coding->source;
   coding->charbuf_used = charbuf - coding->charbuf;
@@ -2130,7 +2235,7 @@ encode_coding_emacs_mule (coding)
            }
        }
     }
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   coding->produced_char += produced_chars;
   coding->produced = dst - coding->destination;
   return 0;
@@ -2430,6 +2535,7 @@ detect_coding_iso_2022 (coding, detect_info)
 
   while (rejected != CATEGORY_MASK_ISO)
     {
+      src_base = src;
       ONE_MORE_BYTE (c);
       switch (c)
        {
@@ -2526,23 +2632,26 @@ detect_coding_iso_2022 (coding, detect_info)
          found |= CATEGORY_MASK_ISO_8_ELSE;
          goto check_extra_latin;
 
-
        case ISO_CODE_SS2:
        case ISO_CODE_SS3:
          /* Single shift.   */
          if (inhibit_iso_escape_detection)
            break;
-         single_shifting = 1;
+         single_shifting = 0;
          rejected |= CATEGORY_MASK_ISO_7BIT;
          if (CODING_ISO_FLAGS (&coding_categories[coding_category_iso_8_1])
              & CODING_ISO_FLAG_SINGLE_SHIFT)
-           found |= CATEGORY_MASK_ISO_8_1;
+           found |= CATEGORY_MASK_ISO_8_1, single_shifting = 1;
          if (CODING_ISO_FLAGS (&coding_categories[coding_category_iso_8_2])
              & CODING_ISO_FLAG_SINGLE_SHIFT)
-           found |= CATEGORY_MASK_ISO_8_2;
+           found |= CATEGORY_MASK_ISO_8_2, single_shifting = 1;
+         if (single_shifting)
+           break;
          goto check_extra_latin;
 
        default:
+         if (c < 0)
+           continue;
          if (c < 0x80)
            {
              single_shifting = 0;
@@ -2588,11 +2697,7 @@ detect_coding_iso_2022 (coding, detect_info)
            found |= CATEGORY_MASK_ISO_8_1;
          else
            rejected |= CATEGORY_MASK_ISO_8_1;
-         if (CODING_ISO_FLAGS (&coding_categories[coding_category_iso_8_2])
-             & CODING_ISO_FLAG_LATIN_EXTRA)
-           found |= CATEGORY_MASK_ISO_8_2;
-         else
-           rejected |= CATEGORY_MASK_ISO_8_2;
+         rejected |= CATEGORY_MASK_ISO_8_2;
        }
     }
   detect_info->rejected |= CATEGORY_MASK_ISO;
@@ -2605,7 +2710,8 @@ detect_coding_iso_2022 (coding, detect_info)
 }
 
 
-/* Set designation state into CODING.  */
+/* Set designation state into CODING.  Set CHARS_96 to -1 if the
+   escape sequence should be kept.  */
 #define DECODE_DESIGNATION(reg, dim, chars_96, final)                  \
   do {                                                                 \
     int id, prev;                                                      \
@@ -2615,7 +2721,8 @@ detect_coding_iso_2022 (coding, detect_info)
        || !SAFE_CHARSET_P (coding, id))                                \
       {                                                                        \
        CODING_ISO_DESIGNATION (coding, reg) = -2;                      \
-       goto invalid_code;                                              \
+       chars_96 = -1;                                                  \
+       break;                                                          \
       }                                                                        \
     prev = CODING_ISO_DESIGNATION (coding, reg);                       \
     if (id == charset_jisx0201_roman)                                  \
@@ -2633,7 +2740,7 @@ detect_coding_iso_2022 (coding, detect_info)
        designation is ASCII to REG, we should keep this designation    \
        sequence.  */                                                   \
     if (prev == -2 && id == charset_ascii)                             \
-      goto invalid_code;                                               \
+      chars_96 = -1;                                                   \
   } while (0)
 
 
@@ -2716,10 +2823,8 @@ detect_coding_iso_2022 (coding, detect_info)
                  : (component_idx + 1) / 2);                           \
     int i;                                                             \
     int *saved_charbuf = charbuf;                                      \
-    int from = char_offset;                                            \
-    int to = from + nchars;                                            \
                                                                        \
-    ADD_COMPOSITION_DATA (charbuf, from, to, method);                  \
+    ADD_COMPOSITION_DATA (charbuf, nchars, method);                    \
     if (method != COMPOSITION_RELATIVE)                                        \
       {                                                                        \
        if (component_len == 0)                                         \
@@ -2775,14 +2880,15 @@ decode_coding_iso_2022 (coding)
   const unsigned char *src = coding->source + coding->consumed;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   const unsigned char *src_base;
-  int *charbuf = coding->charbuf;
+  int *charbuf = coding->charbuf + coding->charbuf_used;
   int *charbuf_end
-    = charbuf + coding->charbuf_size - 4 - MAX_ANNOTATION_LENGTH;
+    = coding->charbuf + coding->charbuf_size - 4 - MAX_ANNOTATION_LENGTH;
   int consumed_chars = 0, consumed_chars_base;
   int multibytep = coding->src_multibyte;
   /* Charsets invoked to graphic plane 0 and 1 respectively.  */
   int charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
   int charset_id_1 = CODING_ISO_INVOKED_CHARSET (coding, 1);
+  int charset_id_2, charset_id_3;
   struct charset *charset;
   int c;
   /* For handling composition sequence.  */
@@ -2816,6 +2922,8 @@ decode_coding_iso_2022 (coding)
        break;
 
       ONE_MORE_BYTE (c1);
+      if (c1 < 0)
+       goto invalid_code;
 
       /* We produce at most one character.  */
       switch (iso_code_class [c1])
@@ -2852,7 +2960,10 @@ decode_coding_iso_2022 (coding)
                  continue;
                }
            }
-         charset = CHARSET_FROM_ID (charset_id_0);
+         if (charset_id_0 < 0)
+           charset = CHARSET_FROM_ID (charset_ascii);
+         else
+           charset = CHARSET_FROM_ID (charset_id_0);
          break;
 
        case ISO_0xA0_or_0xFF:
@@ -2933,27 +3044,36 @@ decode_coding_iso_2022 (coding)
            case '$':           /* designation of 2-byte character set */
              if (! (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_DESIGNATION))
                goto invalid_code;
-             ONE_MORE_BYTE (c1);
-             if (c1 >= '@' && c1 <= 'B')
-               {       /* designation of JISX0208.1978, GB2312.1980,
+             {
+               int reg, chars96;
+
+               ONE_MORE_BYTE (c1);
+               if (c1 >= '@' && c1 <= 'B')
+                 {     /* designation of JISX0208.1978, GB2312.1980,
                           or JISX0208.1980 */
-                 DECODE_DESIGNATION (0, 2, 0, c1);
-               }
-             else if (c1 >= 0x28 && c1 <= 0x2B)
-               {       /* designation of DIMENSION2_CHARS94 character set */
-                 ONE_MORE_BYTE (c2);
-                 DECODE_DESIGNATION (c1 - 0x28, 2, 0, c2);
-               }
-             else if (c1 >= 0x2C && c1 <= 0x2F)
-               {       /* designation of DIMENSION2_CHARS96 character set */
-                 ONE_MORE_BYTE (c2);
-                 DECODE_DESIGNATION (c1 - 0x2C, 2, 1, c2);
-               }
-             else
-               goto invalid_code;
-             /* We must update these variables now.  */
-             charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
-             charset_id_1 = CODING_ISO_INVOKED_CHARSET (coding, 1);
+                   reg = 0, chars96 = 0;
+                 }
+               else if (c1 >= 0x28 && c1 <= 0x2B)
+                 { /* designation of DIMENSION2_CHARS94 character set */
+                   reg = c1 - 0x28, chars96 = 0;
+                   ONE_MORE_BYTE (c1);
+                 }
+               else if (c1 >= 0x2C && c1 <= 0x2F)
+                 { /* designation of DIMENSION2_CHARS96 character set */
+                   reg = c1 - 0x2C, chars96 = 1;
+                   ONE_MORE_BYTE (c1);
+                 }
+               else
+                 goto invalid_code;
+               DECODE_DESIGNATION (reg, 2, chars96, c1);
+               /* We must update these variables now.  */
+               if (reg == 0)
+                 charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
+               else if (reg == 1)
+                 charset_id_1 = CODING_ISO_INVOKED_CHARSET (coding, 1);
+               if (chars96 < 0)
+                 goto invalid_code;
+             }
              continue;
 
            case 'n':           /* invocation of locking-shift-2 */
@@ -2976,7 +3096,11 @@ decode_coding_iso_2022 (coding)
              if (! (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SINGLE_SHIFT)
                  || CODING_ISO_DESIGNATION (coding, 2) < 0)
                goto invalid_code;
-             charset = CHARSET_FROM_ID (CODING_ISO_DESIGNATION (coding, 2));
+             charset_id_2 = CODING_ISO_DESIGNATION (coding, 2);
+             if (charset_id_2 < 0)
+               charset = CHARSET_FROM_ID (charset_ascii);
+             else
+               charset = CHARSET_FROM_ID (charset_id_2);
              ONE_MORE_BYTE (c1);
              if (c1 < 0x20 || (c1 >= 0x80 && c1 < 0xA0))
                goto invalid_code;
@@ -2986,7 +3110,11 @@ decode_coding_iso_2022 (coding)
              if (! (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SINGLE_SHIFT)
                  || CODING_ISO_DESIGNATION (coding, 3) < 0)
                goto invalid_code;
-             charset = CHARSET_FROM_ID (CODING_ISO_DESIGNATION (coding, 3));
+             charset_id_3 = CODING_ISO_DESIGNATION (coding, 3);
+             if (charset_id_3 < 0)
+               charset = CHARSET_FROM_ID (charset_ascii);
+             else
+               charset = CHARSET_FROM_ID (charset_id_3);
              ONE_MORE_BYTE (c1);
              if (c1 < 0x20 || (c1 >= 0x80 && c1 < 0xA0))
                goto invalid_code;
@@ -3087,7 +3215,10 @@ decode_coding_iso_2022 (coding)
                          && src + 1 < src_end
                          && src[0] == '%'
                          && src[1] == '@')
-                       break;
+                       {
+                         src += 2;
+                         break;
+                       }
                      *p++ = ASCII_BYTE_P (c1) ? c1 : BYTE8_TO_CHAR (c1);
                    }
                  if (p + 3 > charbuf_end)
@@ -3105,21 +3236,30 @@ decode_coding_iso_2022 (coding)
            default:
              if (! (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_DESIGNATION))
                goto invalid_code;
-             if (c1 >= 0x28 && c1 <= 0x2B)
-               {       /* designation of DIMENSION1_CHARS94 character set */
-                 ONE_MORE_BYTE (c2);
-                 DECODE_DESIGNATION (c1 - 0x28, 1, 0, c2);
-               }
-             else if (c1 >= 0x2C && c1 <= 0x2F)
-               {       /* designation of DIMENSION1_CHARS96 character set */
-                 ONE_MORE_BYTE (c2);
-                 DECODE_DESIGNATION (c1 - 0x2C, 1, 1, c2);
-               }
-             else
-               goto invalid_code;
-             /* We must update these variables now.  */
-             charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
-             charset_id_1 = CODING_ISO_INVOKED_CHARSET (coding, 1);
+             {
+               int reg, chars96;
+
+               if (c1 >= 0x28 && c1 <= 0x2B)
+                 { /* designation of DIMENSION1_CHARS94 character set */
+                   reg = c1 - 0x28, chars96 = 0;
+                   ONE_MORE_BYTE (c1);
+                 }
+               else if (c1 >= 0x2C && c1 <= 0x2F)
+                 { /* designation of DIMENSION1_CHARS96 character set */
+                   reg = c1 - 0x2C, chars96 = 1;
+                   ONE_MORE_BYTE (c1);
+                 }
+               else
+                 goto invalid_code;
+               DECODE_DESIGNATION (reg, 1, chars96, c1);
+               /* We must update these variables now.  */
+               if (reg == 0)
+                 charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
+               else if (reg == 1)
+                 charset_id_1 = CODING_ISO_INVOKED_CHARSET (coding, 1);
+               if (chars96 < 0)
+                 goto invalid_code;
+             }
              continue;
            }
        }
@@ -3128,7 +3268,7 @@ decode_coding_iso_2022 (coding)
          && last_id != charset->id)
        {
          if (last_id != charset_ascii)
-           ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+           ADD_CHARSET_DATA (charbuf, char_offset - last_offset, last_id);
          last_id = charset->id;
          last_offset = char_offset;
        }
@@ -3186,7 +3326,7 @@ decode_coding_iso_2022 (coding)
       src = src_base;
       consumed_chars = consumed_chars_base;
       ONE_MORE_BYTE (c);
-      *charbuf++ = ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
+      *charbuf++ = c < 0 ? -c : ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
       char_offset++;
       coding->errors++;
       continue;
@@ -3197,7 +3337,7 @@ decode_coding_iso_2022 (coding)
 
  no_more_source:
   if (last_id != charset_ascii)
-    ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+    ADD_CHARSET_DATA (charbuf, char_offset - last_offset, last_id);
   coding->consumed_char += consumed_chars_base;
   coding->consumed = src_base - coding->source;
   coding->charbuf_used = charbuf - coding->charbuf;
@@ -3745,7 +3885,7 @@ encode_coding_iso_2022 (coding)
       ASSURE_DESTINATION (safe_room);
       ENCODE_RESET_PLANE_AND_REGISTER ();
     }
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   CODING_ISO_BOL (coding) = bol_designation;
   coding->produced_char += produced_chars;
   coding->produced = dst - coding->destination;
@@ -3798,13 +3938,12 @@ detect_coding_sjis (coding, detect_info)
      struct coding_system *coding;
      struct coding_detection_info *detect_info;
 {
-  const unsigned char *src = coding->source, *src_base = src;
+  const unsigned char *src = coding->source, *src_base;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   int multibytep = coding->src_multibyte;
   int consumed_chars = 0;
   int found = 0;
   int c;
-  int incomplete;
 
   detect_info->checked |= CATEGORY_MASK_SJIS;
   /* A coding system of this category is always ASCII compatible.  */
@@ -3812,9 +3951,8 @@ detect_coding_sjis (coding, detect_info)
 
   while (1)
     {
-      incomplete = 0;
+      src_base = src;
       ONE_MORE_BYTE (c);
-      incomplete = 1;
       if (c < 0x80)
        continue;
       if ((c >= 0x81 && c <= 0x9F) || (c >= 0xE0 && c <= 0xEF))
@@ -3833,7 +3971,7 @@ detect_coding_sjis (coding, detect_info)
   return 0;
 
  no_more_source:
-  if (incomplete && coding->mode & CODING_MODE_LAST_BLOCK)
+  if (src_base < src && coding->mode & CODING_MODE_LAST_BLOCK)
     {
       detect_info->rejected |= CATEGORY_MASK_SJIS;
       return 0;
@@ -3851,13 +3989,12 @@ detect_coding_big5 (coding, detect_info)
      struct coding_system *coding;
      struct coding_detection_info *detect_info;
 {
-  const unsigned char *src = coding->source, *src_base = src;
+  const unsigned char *src = coding->source, *src_base;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   int multibytep = coding->src_multibyte;
   int consumed_chars = 0;
   int found = 0;
   int c;
-  int incomplete;
 
   detect_info->checked |= CATEGORY_MASK_BIG5;
   /* A coding system of this category is always ASCII compatible.  */
@@ -3865,9 +4002,8 @@ detect_coding_big5 (coding, detect_info)
 
   while (1)
     {
-      incomplete = 0;
+      src_base = src;
       ONE_MORE_BYTE (c);
-      incomplete = 1;
       if (c < 0x80)
        continue;
       if (c >= 0xA1)
@@ -3884,7 +4020,7 @@ detect_coding_big5 (coding, detect_info)
   return 0;
 
  no_more_source:
-  if (incomplete && coding->mode & CODING_MODE_LAST_BLOCK)
+  if (src_base < src && coding->mode & CODING_MODE_LAST_BLOCK)
     {
       detect_info->rejected |= CATEGORY_MASK_BIG5;
       return 0;
@@ -3903,11 +4039,13 @@ decode_coding_sjis (coding)
   const unsigned char *src = coding->source + coding->consumed;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   const unsigned char *src_base;
-  int *charbuf = coding->charbuf;
-  int *charbuf_end = charbuf + coding->charbuf_size - MAX_ANNOTATION_LENGTH;
+  int *charbuf = coding->charbuf + coding->charbuf_used;
+  int *charbuf_end
+    = coding->charbuf + coding->charbuf_size - MAX_ANNOTATION_LENGTH;
   int consumed_chars = 0, consumed_chars_base;
   int multibytep = coding->src_multibyte;
   struct charset *charset_roman, *charset_kanji, *charset_kana;
+  struct charset *charset_kanji2;
   Lisp_Object attrs, charset_list, val;
   int char_offset = coding->produced_char;
   int last_offset = char_offset;
@@ -3918,7 +4056,8 @@ decode_coding_sjis (coding)
   val = charset_list;
   charset_roman = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
   charset_kana = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
-  charset_kanji = CHARSET_FROM_ID (XINT (XCAR (val)));
+  charset_kanji = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
+  charset_kanji2 = NILP (val) ? NULL : CHARSET_FROM_ID (XINT (XCAR (val)));
 
   while (1)
     {
@@ -3932,37 +4071,45 @@ decode_coding_sjis (coding)
        break;
 
       ONE_MORE_BYTE (c);
-
+      if (c < 0)
+       goto invalid_code;
       if (c < 0x80)
        charset = charset_roman;
-      else
+      else if (c == 0x80 || c == 0xA0)
+       goto invalid_code;
+      else if (c >= 0xA1 && c <= 0xDF)
        {
-         if (c >= 0xF0)
+         /* SJIS -> JISX0201-Kana */
+         c &= 0x7F;
+         charset = charset_kana;
+       }
+      else if (c <= 0xEF)
+       {
+         /* SJIS -> JISX0208 */
+         ONE_MORE_BYTE (c1);
+         if (c1 < 0x40 || c1 == 0x7F || c1 > 0xFC)
            goto invalid_code;
-         if (c < 0xA0 || c >= 0xE0)
-           {
-             /* SJIS -> JISX0208 */
-             ONE_MORE_BYTE (c1);
-             if (c1 < 0x40 || c1 == 0x7F || c1 > 0xFC)
-               goto invalid_code;
-             c = (c << 8) | c1;
-             SJIS_TO_JIS (c);
-             charset = charset_kanji;
-           }
-         else if (c > 0xA0)
-           {
-             /* SJIS -> JISX0201-Kana */
-             c &= 0x7F;
-             charset = charset_kana;
-           }
-         else
+         c = (c << 8) | c1;
+         SJIS_TO_JIS (c);
+         charset = charset_kanji;
+       }
+      else if (c <= 0xFC && charset_kanji2)
+       {
+         /* SJIS -> JISX0213-2 */
+         ONE_MORE_BYTE (c1);
+         if (c1 < 0x40 || c1 == 0x7F || c1 > 0xFC)
            goto invalid_code;
+         c = (c << 8) | c1;
+         SJIS_TO_JIS2 (c);
+         charset = charset_kanji2;
        }
+      else
+       goto invalid_code;
       if (charset->id != charset_ascii
          && last_id != charset->id)
        {
          if (last_id != charset_ascii)
-           ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+           ADD_CHARSET_DATA (charbuf, char_offset - last_offset, last_id);
          last_id = charset->id;
          last_offset = char_offset;
        }
@@ -3975,14 +4122,14 @@ decode_coding_sjis (coding)
       src = src_base;
       consumed_chars = consumed_chars_base;
       ONE_MORE_BYTE (c);
-      *charbuf++ = ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
+      *charbuf++ = c < 0 ? -c : BYTE8_TO_CHAR (c);
       char_offset++;
       coding->errors++;
     }
 
  no_more_source:
   if (last_id != charset_ascii)
-    ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+    ADD_CHARSET_DATA (charbuf, char_offset - last_offset, last_id);
   coding->consumed_char += consumed_chars_base;
   coding->consumed = src_base - coding->source;
   coding->charbuf_used = charbuf - coding->charbuf;
@@ -3995,8 +4142,9 @@ decode_coding_big5 (coding)
   const unsigned char *src = coding->source + coding->consumed;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   const unsigned char *src_base;
-  int *charbuf = coding->charbuf;
-  int *charbuf_end = charbuf + coding->charbuf_size - MAX_ANNOTATION_LENGTH;
+  int *charbuf = coding->charbuf + coding->charbuf_used;
+  int *charbuf_end
+    = coding->charbuf + coding->charbuf_size - MAX_ANNOTATION_LENGTH;
   int consumed_chars = 0, consumed_chars_base;
   int multibytep = coding->src_multibyte;
   struct charset *charset_roman, *charset_big5;
@@ -4023,6 +4171,8 @@ decode_coding_big5 (coding)
 
       ONE_MORE_BYTE (c);
 
+      if (c < 0)
+       goto invalid_code;
       if (c < 0x80)
        charset = charset_roman;
       else
@@ -4040,7 +4190,7 @@ decode_coding_big5 (coding)
          && last_id != charset->id)
        {
          if (last_id != charset_ascii)
-           ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+           ADD_CHARSET_DATA (charbuf, char_offset - last_offset, last_id);
          last_id = charset->id;
          last_offset = char_offset;
        }
@@ -4053,14 +4203,14 @@ decode_coding_big5 (coding)
       src = src_base;
       consumed_chars = consumed_chars_base;
       ONE_MORE_BYTE (c);
-      *charbuf++ = ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
+      *charbuf++ = c < 0 ? -c : BYTE8_TO_CHAR (c);
       char_offset++;
       coding->errors++;
     }
 
  no_more_source:
   if (last_id != charset_ascii)
-    ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+    ADD_CHARSET_DATA (charbuf, char_offset - last_offset, last_id);
   coding->consumed_char += consumed_chars_base;
   coding->consumed = src_base - coding->source;
   coding->charbuf_used = charbuf - coding->charbuf;
@@ -4088,13 +4238,15 @@ encode_coding_sjis (coding)
   Lisp_Object attrs, charset_list, val;
   int ascii_compatible;
   struct charset *charset_roman, *charset_kanji, *charset_kana;
+  struct charset *charset_kanji2;
   int c;
 
   CODING_GET_INFO (coding, attrs, charset_list);
   val = charset_list;
   charset_roman = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
   charset_kana = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
-  charset_kanji = CHARSET_FROM_ID (XINT (XCAR (val)));
+  charset_kanji = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
+  charset_kanji2 = NILP (val) ? NULL : CHARSET_FROM_ID (XINT (XCAR (val)));
 
   ascii_compatible = ! NILP (CODING_ATTR_ASCII_COMPAT (attrs));
 
@@ -4139,11 +4291,26 @@ encode_coding_sjis (coding)
            }
          else if (charset == charset_kana)
            EMIT_ONE_BYTE (code | 0x80);
+         else if (charset_kanji2 && charset == charset_kanji2)
+           {
+             int c1, c2;
+
+             c1 = code >> 8;
+             if (c1 == 0x21 || (c1 >= 0x23 && c1 < 0x25)
+                 || (c1 >= 0x2C && c1 <= 0x2F) || c1 >= 0x6E)
+               {
+                 JIS_TO_SJIS2 (code);
+                 c1 = code >> 8, c2 = code & 0xFF;
+                 EMIT_TWO_BYTES (c1, c2);
+               }
+             else
+               EMIT_ONE_ASCII_BYTE (code & 0x7F);
+           }
          else
            EMIT_ONE_ASCII_BYTE (code & 0x7F);
        }
     }
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   coding->produced_char += produced_chars;
   coding->produced = dst - coding->destination;
   return 0;
@@ -4214,7 +4381,7 @@ encode_coding_big5 (coding)
            EMIT_ONE_ASCII_BYTE (code & 0x7F);
        }
     }
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   coding->produced_char += produced_chars;
   coding->produced = dst - coding->destination;
   return 0;
@@ -4233,18 +4400,19 @@ detect_coding_ccl (coding, detect_info)
      struct coding_system *coding;
      struct coding_detection_info *detect_info;
 {
-  const unsigned char *src = coding->source, *src_base = src;
+  const unsigned char *src = coding->source, *src_base;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   int multibytep = coding->src_multibyte;
   int consumed_chars = 0;
   int found = 0;
-  unsigned char *valids = CODING_CCL_VALIDS (coding);
+  unsigned char *valids;
   int head_ascii = coding->head_ascii;
   Lisp_Object attrs;
 
   detect_info->checked |= CATEGORY_MASK_CCL;
 
   coding = &coding_categories[coding_category_ccl];
+  valids = CODING_CCL_VALIDS (coding);
   attrs = CODING_ID_ATTRS (coding->id);
   if (! NILP (CODING_ATTR_ASCII_COMPAT (attrs)))
     src += head_ascii;
@@ -4252,8 +4420,10 @@ detect_coding_ccl (coding, detect_info)
   while (1)
     {
       int c;
+
+      src_base = src;
       ONE_MORE_BYTE (c);
-      if (! valids[c])
+      if (c < 0 || ! valids[c])
        break;
       if ((valids[c] > 1))
        found = CATEGORY_MASK_CCL;
@@ -4272,8 +4442,8 @@ decode_coding_ccl (coding)
 {
   const unsigned char *src = coding->source + coding->consumed;
   const unsigned char *src_end = coding->source + coding->src_bytes;
-  int *charbuf = coding->charbuf;
-  int *charbuf_end = charbuf + coding->charbuf_size;
+  int *charbuf = coding->charbuf + coding->charbuf_used;
+  int *charbuf_end = coding->charbuf + coding->charbuf_size;
   int consumed_chars = 0;
   int multibytep = coding->src_multibyte;
   struct ccl_program ccl;
@@ -4329,16 +4499,16 @@ decode_coding_ccl (coding)
   switch (ccl.status)
     {
     case CCL_STAT_SUSPEND_BY_SRC:
-      coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+      record_conversion_result (coding, CODING_RESULT_INSUFFICIENT_SRC);
       break;
     case CCL_STAT_SUSPEND_BY_DST:
       break;
     case CCL_STAT_QUIT:
     case CCL_STAT_INVALID_CMD:
-      coding->result = CODING_RESULT_INTERRUPT;
+      record_conversion_result (coding, CODING_RESULT_INTERRUPT);
       break;
     default:
-      coding->result = CODING_RESULT_SUCCESS;
+      record_conversion_result (coding, CODING_RESULT_SUCCESS);
       break;
     }
   coding->consumed_char += consumed_chars;
@@ -4390,17 +4560,17 @@ encode_coding_ccl (coding)
   switch (ccl.status)
     {
     case CCL_STAT_SUSPEND_BY_SRC:
-      coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+      record_conversion_result (coding, CODING_RESULT_INSUFFICIENT_SRC);
       break;
     case CCL_STAT_SUSPEND_BY_DST:
-      coding->result = CODING_RESULT_INSUFFICIENT_DST;
+      record_conversion_result (coding, CODING_RESULT_INSUFFICIENT_DST);
       break;
     case CCL_STAT_QUIT:
     case CCL_STAT_INVALID_CMD:
-      coding->result = CODING_RESULT_INTERRUPT;
+      record_conversion_result (coding, CODING_RESULT_INTERRUPT);
       break;
     default:
-      coding->result = CODING_RESULT_SUCCESS;
+      record_conversion_result (coding, CODING_RESULT_SUCCESS);
       break;
     }
 
@@ -4422,7 +4592,7 @@ decode_coding_raw_text (coding)
   coding->chars_at_source = 1;
   coding->consumed_char = 0;
   coding->consumed = 0;
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
 }
 
 static int
@@ -4500,7 +4670,7 @@ encode_coding_raw_text (coding)
          produced_chars = dst - (coding->destination + coding->dst_bytes);
        }
     }
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   coding->produced_char += produced_chars;
   coding->produced = dst - coding->destination;
   return 0;
@@ -4515,7 +4685,7 @@ detect_coding_charset (coding, detect_info)
      struct coding_system *coding;
      struct coding_detection_info *detect_info;
 {
-  const unsigned char *src = coding->source, *src_base = src;
+  const unsigned char *src = coding->source, *src_base;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   int multibytep = coding->src_multibyte;
   int consumed_chars = 0;
@@ -4535,7 +4705,10 @@ detect_coding_charset (coding, detect_info)
     {
       int c;
 
+      src_base = src;
       ONE_MORE_BYTE (c);
+      if (c < 0)
+       continue;
       if (NILP (AREF (valids, c)))
        break;
       if (c >= 0x80)
@@ -4556,8 +4729,9 @@ decode_coding_charset (coding)
   const unsigned char *src = coding->source + coding->consumed;
   const unsigned char *src_end = coding->source + coding->src_bytes;
   const unsigned char *src_base;
-  int *charbuf = coding->charbuf;
-  int *charbuf_end = charbuf + coding->charbuf_size - MAX_ANNOTATION_LENGTH;
+  int *charbuf = coding->charbuf + coding->charbuf_used;
+  int *charbuf_end
+    = coding->charbuf + coding->charbuf_size - MAX_ANNOTATION_LENGTH;
   int consumed_chars = 0, consumed_chars_base;
   int multibytep = coding->src_multibyte;
   Lisp_Object attrs, charset_list, valids;
@@ -4584,6 +4758,8 @@ decode_coding_charset (coding)
        break;
 
       ONE_MORE_BYTE (c);
+      if (c < 0)
+       goto invalid_code;
       code = c;
 
       val = AREF (valids, c);
@@ -4630,7 +4806,7 @@ decode_coding_charset (coding)
          && last_id != charset->id)
        {
          if (last_id != charset_ascii)
-           ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+           ADD_CHARSET_DATA (charbuf, char_offset - last_offset, last_id);
          last_id = charset->id;
          last_offset = char_offset;
        }
@@ -4643,14 +4819,14 @@ decode_coding_charset (coding)
       src = src_base;
       consumed_chars = consumed_chars_base;
       ONE_MORE_BYTE (c);
-      *charbuf++ = ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
+      *charbuf++ = c < 0 ? -c : ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
       char_offset++;
       coding->errors++;
     }
 
  no_more_source:
   if (last_id != charset_ascii)
-    ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+    ADD_CHARSET_DATA (charbuf, char_offset - last_offset, last_id);
   coding->consumed_char += consumed_chars_base;
   coding->consumed = src_base - coding->source;
   coding->charbuf_used = charbuf - coding->charbuf;
@@ -4714,7 +4890,7 @@ encode_coding_charset (coding)
        }
     }
 
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   coding->produced_char += produced_chars;
   coding->produced = dst - coding->destination;
   return 0;
@@ -4897,6 +5073,13 @@ setup_coding_system (coding_system, coding)
       coding->detector = NULL;
       coding->decoder = decode_coding_raw_text;
       coding->encoder = encode_coding_raw_text;
+      if (! EQ (eol_type, Qunix))
+       {
+         coding->common_flags |= CODING_REQUIRE_DECODING_MASK;
+         if (! VECTORP (eol_type))
+           coding->common_flags |= CODING_REQUIRE_ENCODING_MASK;
+       }
+
     }
 
   return;
@@ -5034,7 +5217,7 @@ coding_inherit_eol_type (coding_system, parent)
    o coding-category-utf-8
 
        The category for a coding system which has the same code range
-       as UTF-8 (cf. RFC2279).  Assigned the coding-system (Lisp
+       as UTF-8 (cf. RFC3629).  Assigned the coding-system (Lisp
        symbol) `utf-8' by default.
 
    o coding-category-utf-16-be
@@ -5089,11 +5272,11 @@ coding_inherit_eol_type (coding_system, parent)
 
 static int
 detect_eol (source, src_bytes, category)
-     unsigned char *source;
+     const unsigned char *source;
      EMACS_INT src_bytes;
      enum coding_category category;
 {
-  unsigned char *src = source, *src_end = src + src_bytes;
+  const unsigned char *src = source, *src_end = src + src_bytes;
   unsigned char c;
   int total  = 0;
   int eol_seen = EOL_SEEN_NONE;
@@ -5206,7 +5389,6 @@ detect_coding (coding)
      struct coding_system *coding;
 {
   const unsigned char *src, *src_end;
-  Lisp_Object attrs, coding_type;
 
   coding->consumed = coding->consumed_char = 0;
   coding->produced = coding->produced_char = 0;
@@ -5219,57 +5401,78 @@ detect_coding (coding)
   if (EQ (CODING_ATTR_TYPE (CODING_ID_ATTRS (coding->id)), Qundecided))
     {
       int c, i;
+      struct coding_detection_info detect_info;
 
+      detect_info.checked = detect_info.found = detect_info.rejected = 0;
       for (i = 0, src = coding->source; src < src_end; i++, src++)
        {
          c = *src;
-         if (c & 0x80 || (c < 0x20 && (c == 0
-                                       || c == ISO_CODE_ESC
-                                       || c == ISO_CODE_SI
-                                       || c == ISO_CODE_SO)))
+         if (c & 0x80)
            break;
+         if (c < 0x20
+             && (c == ISO_CODE_ESC || c == ISO_CODE_SI || c == ISO_CODE_SO)
+             && ! inhibit_iso_escape_detection
+             && ! detect_info.checked)
+           {
+             coding->head_ascii = src - (coding->source + coding->consumed);
+             if (detect_coding_iso_2022 (coding, &detect_info))
+               {
+                 /* We have scanned the whole data.  */
+                 if (! (detect_info.rejected & CATEGORY_MASK_ISO_7_ELSE))
+                   /* We didn't find an 8-bit code.  */
+                   src = src_end;
+                 break;
+               }
+           }
        }
-      /* Skipped bytes must be even for utf-16 detector.  */
-      if (i % 2)
-       src--;
       coding->head_ascii = src - (coding->source + coding->consumed);
 
-      if (coding->head_ascii < coding->src_bytes)
+      if (coding->head_ascii < coding->src_bytes
+         || detect_info.found)
        {
-         struct coding_detection_info detect_info;
          enum coding_category category;
          struct coding_system *this;
 
-         detect_info.checked = detect_info.found = detect_info.rejected = 0;
-         for (i = 0; i < coding_category_raw_text; i++)
-           {
-             category = coding_priorities[i];
-             this = coding_categories + category;
-             if (this->id < 0)
-               {
-                 /* No coding system of this category is defined.  */
-                 detect_info.rejected |= (1 << category);
-               }
-             else if (category >= coding_category_raw_text)
-               continue;
-             else if (detect_info.checked & (1 << category))
-               {
-                 if (detect_info.found & (1 << category))
-                   break;
-               }
-             else if ((*(this->detector)) (coding, &detect_info)
-                      && detect_info.found & (1 << category))
-               {
-                 if (category == coding_category_utf_16_auto)
-                   {
-                     if (detect_info.found & CATEGORY_MASK_UTF_16_LE)
-                       category = coding_category_utf_16_le;
-                     else
-                       category = coding_category_utf_16_be;
-                   }
+         if (coding->head_ascii == coding->src_bytes)
+           /* As all bytes are 7-bit, we can ignore non-ISO-2022 codings.  */
+           for (i = 0; i < coding_category_raw_text; i++)
+             {
+               category = coding_priorities[i];
+               this = coding_categories + category;
+               if (detect_info.found & (1 << category))
                  break;
-               }
-           }
+             }
+         else
+           for (i = 0; i < coding_category_raw_text; i++)
+             {
+               category = coding_priorities[i];
+               this = coding_categories + category;
+               if (this->id < 0)
+                 {
+                   /* No coding system of this category is defined.  */
+                   detect_info.rejected |= (1 << category);
+                 }
+               else if (category >= coding_category_raw_text)
+                 continue;
+               else if (detect_info.checked & (1 << category))
+                 {
+                   if (detect_info.found & (1 << category))
+                     break;
+                 }
+               else if ((*(this->detector)) (coding, &detect_info)
+                        && detect_info.found & (1 << category))
+                 {
+                   if (category == coding_category_utf_16_auto)
+                     {
+                       if (detect_info.found & CATEGORY_MASK_UTF_16_LE)
+                         category = coding_category_utf_16_le;
+                       else
+                         category = coding_category_utf_16_be;
+                     }
+                   break;
+                 }
+             }
+         
          if (i < coding_category_raw_text)
            setup_coding_system (CODING_ID_NAME (this->id), coding);
          else if (detect_info.rejected == CATEGORY_MASK_ANY)
@@ -5386,75 +5589,220 @@ decode_eol (coding)
     }
 }
 
-static void
-translate_chars (coding, table)
-     struct coding_system *coding;
-     Lisp_Object table;
+
+/* Return a translation table (or list of them) from coding system
+   attribute vector ATTRS for encoding (ENCODEP is nonzero) or
+   decoding (ENCODEP is zero). */
+
+static Lisp_Object
+get_translation_table (attrs, encodep, max_lookup)
+     Lisp_Object attrs;
+     int encodep, *max_lookup;
 {
-  int *charbuf = coding->charbuf;
-  int *charbuf_end = charbuf + coding->charbuf_used;
-  int c;
+  Lisp_Object standard, translation_table;
+  Lisp_Object val;
 
-  if (coding->chars_at_source)
-    return;
+  if (encodep)
+    translation_table = CODING_ATTR_ENCODE_TBL (attrs),
+      standard = Vstandard_translation_table_for_encode;
+  else
+    translation_table = CODING_ATTR_DECODE_TBL (attrs),
+      standard = Vstandard_translation_table_for_decode;
+  if (NILP (translation_table))
+    translation_table = standard;
+  else
+    {
+      if (SYMBOLP (translation_table))
+       translation_table = Fget (translation_table, Qtranslation_table);
+      else if (CONSP (translation_table))
+       {
+         translation_table = Fcopy_sequence (translation_table);
+         for (val = translation_table; CONSP (val); val = XCDR (val))
+           if (SYMBOLP (XCAR (val)))
+             XSETCAR (val, Fget (XCAR (val), Qtranslation_table));
+       }
+      if (CHAR_TABLE_P (standard))
+       {
+         if (CONSP (translation_table))
+           translation_table = nconc2 (translation_table,
+                                       Fcons (standard, Qnil));
+         else
+           translation_table = Fcons (translation_table,
+                                      Fcons (standard, Qnil));
+       }
+    }
 
-  while (charbuf < charbuf_end)
+  if (max_lookup)
     {
-      c = *charbuf;
-      if (c < 0)
-       charbuf += c;
-      else
-       *charbuf++ = translate_char (table, c);
+      *max_lookup = 1;
+      if (CHAR_TABLE_P (translation_table)
+         && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (translation_table)) > 1)
+       {
+         val = XCHAR_TABLE (translation_table)->extras[1];
+         if (NATNUMP (val) && *max_lookup < XFASTINT (val))
+           *max_lookup = XFASTINT (val);
+       }
+      else if (CONSP (translation_table))
+       {
+         Lisp_Object tail, val;
+
+         for (tail = translation_table; CONSP (tail); tail = XCDR (tail))
+           if (CHAR_TABLE_P (XCAR (tail))
+               && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (XCAR (tail))) > 1)
+             {
+               val = XCHAR_TABLE (XCAR (tail))->extras[1];
+               if (NATNUMP (val) && *max_lookup < XFASTINT (val))
+                 *max_lookup = XFASTINT (val);
+             }
+       }
+    }
+  return translation_table;
+}
+
+#define LOOKUP_TRANSLATION_TABLE(table, c, trans)              \
+  do {                                                         \
+    trans = Qnil;                                              \
+    if (CHAR_TABLE_P (table))                                  \
+      {                                                                \
+       trans = CHAR_TABLE_REF (table, c);                      \
+       if (CHARACTERP (trans))                                 \
+         c = XFASTINT (trans), trans = Qnil;                   \
+      }                                                                \
+    else if (CONSP (table))                                    \
+      {                                                                \
+       Lisp_Object tail;                                       \
+                                                               \
+       for (tail = table; CONSP (tail); tail = XCDR (tail))    \
+         if (CHAR_TABLE_P (XCAR (tail)))                       \
+           {                                                   \
+             trans = CHAR_TABLE_REF (XCAR (tail), c);          \
+             if (CHARACTERP (trans))                           \
+               c = XFASTINT (trans), trans = Qnil;             \
+             else if (! NILP (trans))                          \
+               break;                                          \
+           }                                                   \
+      }                                                                \
+  } while (0)
+
+
+static Lisp_Object
+get_translation (val, buf, buf_end, last_block, from_nchars, to_nchars)
+     Lisp_Object val;
+     int *buf, *buf_end;
+     int last_block;
+     int *from_nchars, *to_nchars;
+{
+  /* VAL is TO or (([FROM-CHAR ...] .  TO) ...) where TO is TO-CHAR or
+     [TO-CHAR ...].  */
+  if (CONSP (val))
+    {
+      Lisp_Object from, tail;
+      int i, len;
+
+      for (tail = val; CONSP (tail); tail = XCDR (tail))
+       {
+         val = XCAR (tail);
+         from = XCAR (val);
+         len = ASIZE (from);
+         for (i = 0; i < len; i++)
+           {
+             if (buf + i == buf_end)
+               {
+                 if (! last_block)
+                   return Qt;
+                 break;
+               }
+             if (XINT (AREF (from, i)) != buf[i])
+               break;
+           }
+         if (i == len)
+           {
+             val = XCDR (val);
+             *from_nchars = len;
+             break;
+           }
+       }
+      if (! CONSP (tail))
+       return Qnil;
     }
+  if (VECTORP (val))
+    *buf = XINT (AREF (val, 0)), *to_nchars = ASIZE (val);
+  else
+    *buf = XINT (val);
+  return val;
 }
 
+
 static int
-produce_chars (coding)
+produce_chars (coding, translation_table, last_block)
      struct coding_system *coding;
+     Lisp_Object translation_table;
+     int last_block;
 {
   unsigned char *dst = coding->destination + coding->produced;
   unsigned char *dst_end = coding->destination + coding->dst_bytes;
   int produced;
   int produced_chars = 0;
+  int carryover = 0;
 
   if (! coding->chars_at_source)
     {
       /* Characters are in coding->charbuf.  */
       int *buf = coding->charbuf;
       int *buf_end = buf + coding->charbuf_used;
-      unsigned char *adjusted_dst_end;
 
       if (BUFFERP (coding->src_object)
          && EQ (coding->src_object, coding->dst_object))
        dst_end = ((unsigned char *) coding->source) + coding->consumed;
-      adjusted_dst_end = dst_end - MAX_MULTIBYTE_LENGTH;
 
       while (buf < buf_end)
        {
-         int c = *buf++;
+         int c = *buf, i;
 
-         if (dst >= adjusted_dst_end)
-           {
-             dst = alloc_destination (coding,
-                                      buf_end - buf + MAX_MULTIBYTE_LENGTH,
-                                      dst);
-             dst_end = coding->destination + coding->dst_bytes;
-             adjusted_dst_end = dst_end - MAX_MULTIBYTE_LENGTH;
-           }
          if (c >= 0)
            {
-             if (coding->dst_multibyte
-                 || ! CHAR_BYTE8_P (c))
-               CHAR_STRING_ADVANCE (c, dst);
-             else
-               *dst++ = CHAR_TO_BYTE8 (c);
-             produced_chars++;
+             int from_nchars = 1, to_nchars = 1;
+             Lisp_Object trans = Qnil;
+
+             LOOKUP_TRANSLATION_TABLE (translation_table, c, trans);
+             if (! NILP (trans))
+               {
+                 trans = get_translation (trans, buf, buf_end, last_block,
+                                          &from_nchars, &to_nchars);
+                 if (EQ (trans, Qt))
+                   break;
+                 c = *buf;
+               }
+
+             if (dst + MAX_MULTIBYTE_LENGTH * to_nchars > dst_end)
+               {
+                 dst = alloc_destination (coding,
+                                          buf_end - buf
+                                          + MAX_MULTIBYTE_LENGTH * to_nchars,
+                                          dst);
+                 dst_end = coding->destination + coding->dst_bytes;
+               }
+
+             for (i = 0; i < to_nchars; i++)
+               {
+                 if (i > 0)
+                   c = XINT (AREF (trans, i));
+                 if (coding->dst_multibyte
+                     || ! CHAR_BYTE8_P (c))
+                   CHAR_STRING_ADVANCE (c, dst);
+                 else
+                   *dst++ = CHAR_TO_BYTE8 (c);
+               }
+             produced_chars += to_nchars;
+             *buf++ = to_nchars;
+             while (--from_nchars > 0)
+               *buf++ = 0;
            }
          else
-           /* This is an annotation datum.  (-C) is the length of
-              it.  */
-           buf += -c - 1;
+           /* This is an annotation datum.  (-C) is the length.  */
+           buf += -c;
        }
+      carryover = buf_end - buf;
     }
   else
     {
@@ -5483,7 +5831,8 @@ produce_chars (coding)
                        {
                          if (src == src_end)
                            {
-                             coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+                             record_conversion_result
+                               (coding, CODING_RESULT_INSUFFICIENT_SRC);
                              goto no_more_source;
                            }
                          if (*src == '\n')
@@ -5595,7 +5944,7 @@ produce_chars (coding)
     insert_from_gap (produced_chars, produced);
   coding->produced += produced;
   coding->produced_char += produced_chars;
-  return produced_chars;
+  return carryover;
 }
 
 /* Compose text in CODING->object according to the annotation data at
@@ -5604,53 +5953,62 @@ produce_chars (coding)
  */
 
 static INLINE void
-produce_composition (coding, charbuf)
+produce_composition (coding, charbuf, pos)
      struct coding_system *coding;
      int *charbuf;
+     EMACS_INT pos;
 {
   int len;
-  EMACS_INT from, to;
+  EMACS_INT to;
   enum composition_method method;
   Lisp_Object components;
 
   len = -charbuf[0];
-  from = coding->dst_pos + charbuf[2];
-  to = coding->dst_pos + charbuf[3];
-  method = (enum composition_method) (charbuf[4]);
+  to = pos + charbuf[2];
+  if (to <= pos)
+    return;
+  method = (enum composition_method) (charbuf[3]);
 
   if (method == COMPOSITION_RELATIVE)
     components = Qnil;
-  else
+  else if (method >= COMPOSITION_WITH_RULE
+          && method <= COMPOSITION_WITH_RULE_ALTCHARS)
     {
       Lisp_Object args[MAX_COMPOSITION_COMPONENTS * 2 - 1];
       int i;
 
-      len -= 5;
-      charbuf += 5;
+      len -= 4;
+      charbuf += 4;
       for (i = 0; i < len; i++)
-       args[i] = make_number (charbuf[i]);
+       {
+         args[i] = make_number (charbuf[i]);
+         if (args[i] < 0)
+           return;
+       }
       components = (method == COMPOSITION_WITH_ALTCHARS
                    ? Fstring (len, args) : Fvector (len, args));
     }
-  compose_text (from, to, components, Qnil, coding->dst_object);
+  else
+    return;
+  compose_text (pos, to, components, Qnil, coding->dst_object);
 }
 
 
 /* Put `charset' property on text in CODING->object according to
    the annotation data at CHARBUF.  CHARBUF is an array:
-     [ -LENGTH ANNOTATION_MASK FROM TO CHARSET-ID ]
+     [ -LENGTH ANNOTATION_MASK NCHARS CHARSET-ID ]
  */
 
 static INLINE void
-produce_charset (coding, charbuf)
+produce_charset (coding, charbuf, pos)
      struct coding_system *coding;
      int *charbuf;
+     EMACS_INT pos;
 {
-  EMACS_INT from = coding->dst_pos + charbuf[2];
-  EMACS_INT to = coding->dst_pos + charbuf[3];
-  struct charset *charset = CHARSET_FROM_ID (charbuf[4]);
+  EMACS_INT from = pos - charbuf[2];
+  struct charset *charset = CHARSET_FROM_ID (charbuf[3]);
 
-  Fput_text_property (make_number (from), make_number (to),
+  Fput_text_property (make_number (from), make_number (pos),
                      Qcharset, CHARSET_NAME (charset),
                      coding->dst_object);
 }
@@ -5672,7 +6030,7 @@ produce_charset (coding, charbuf)
       }                                                                        \
     if (! coding->charbuf)                                             \
       {                                                                        \
-       coding->result = CODING_RESULT_INSUFFICIENT_MEM;                \
+       record_conversion_result (coding, CODING_RESULT_INSUFFICIENT_MEM); \
        return coding->result;                                          \
       }                                                                        \
     coding->charbuf_size = size;                                       \
@@ -5680,8 +6038,9 @@ produce_charset (coding, charbuf)
 
 
 static void
-produce_annotation (coding)
+produce_annotation (coding, pos)
      struct coding_system *coding;
+     EMACS_INT pos;
 {
   int *charbuf = coding->charbuf;
   int *charbuf_end = charbuf + coding->charbuf_used;
@@ -5692,17 +6051,17 @@ produce_annotation (coding)
   while (charbuf < charbuf_end)
     {
       if (*charbuf >= 0)
-       charbuf++;
+       pos += *charbuf++;
       else
        {
          int len = -*charbuf;
          switch (charbuf[1])
            {
            case CODING_ANNOTATE_COMPOSITION_MASK:
-             produce_composition (coding, charbuf);
+             produce_composition (coding, charbuf, pos);
              break;
            case CODING_ANNOTATE_CHARSET_MASK:
-             produce_charset (coding, charbuf);
+             produce_charset (coding, charbuf, pos);
              break;
            default:
              abort ();
@@ -5741,6 +6100,9 @@ decode_coding (coding)
 {
   Lisp_Object attrs;
   Lisp_Object undo_list;
+  Lisp_Object translation_table;
+  int carryover;
+  int i;
 
   if (BUFFERP (coding->src_object)
       && coding->src_pos > 0
@@ -5762,30 +6124,41 @@ decode_coding (coding)
   coding->consumed = coding->consumed_char = 0;
   coding->produced = coding->produced_char = 0;
   coding->chars_at_source = 0;
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   coding->errors = 0;
 
   ALLOC_CONVERSION_WORK_AREA (coding);
 
   attrs = CODING_ID_ATTRS (coding->id);
+  translation_table = get_translation_table (attrs, 0, NULL);
 
+  carryover = 0;
   do
     {
+      EMACS_INT pos = coding->dst_pos + coding->produced_char;
+
       coding_set_source (coding);
       coding->annotated = 0;
+      coding->charbuf_used = carryover;
       (*(coding->decoder)) (coding);
-      if (!NILP (CODING_ATTR_DECODE_TBL (attrs)))
-       translate_chars (coding, CODING_ATTR_DECODE_TBL (attrs));
-      else if (!NILP (Vstandard_translation_table_for_decode))
-       translate_chars (coding, Vstandard_translation_table_for_decode);
       coding_set_destination (coding);
-      produce_chars (coding);
+      carryover = produce_chars (coding, translation_table, 0);
       if (coding->annotated)
-       produce_annotation (coding);
+       produce_annotation (coding, pos);
+      for (i = 0; i < carryover; i++)
+       coding->charbuf[i]
+         = coding->charbuf[coding->charbuf_used - carryover + i];
     }
   while (coding->consumed < coding->src_bytes
         && ! coding->result);
 
+  if (carryover > 0)
+    {
+      coding_set_destination (coding);
+      coding->charbuf_used = carryover;
+      produce_chars (coding, translation_table, 1);
+    }
+
   coding->carryover_bytes = 0;
   if (coding->consumed < coding->src_bytes)
     {
@@ -5801,13 +6174,14 @@ decode_coding (coding)
          /* Flush out unprocessed data as binary chars.  We are sure
             that the number of data is less than the size of
             coding->charbuf.  */
+         coding->charbuf_used = 0;
          while (nbytes-- > 0)
            {
              int c = *src++;
 
              coding->charbuf[coding->charbuf_used++] = (c & 0x80 ? - c : c);
            }
-         produce_chars (coding);
+         produce_chars (coding, Qnil, 1);
        }
       else
        {
@@ -5869,7 +6243,7 @@ handle_composition_annotation (pos, limit, coding, buf, stop)
          enum composition_method method = COMPOSITION_METHOD (prop);
          int nchars = COMPOSITION_LENGTH (prop);
 
-         ADD_COMPOSITION_DATA (buf, 0, nchars, method);
+         ADD_COMPOSITION_DATA (buf, nchars, method);
          if (method != COMPOSITION_RELATIVE)
            {
              Lisp_Object components;
@@ -5944,7 +6318,7 @@ handle_charset_annotation (pos, limit, coding, buf, stop)
     id = XINT (CHARSET_SYMBOL_ID (val));
   else
     id = -1;
-  ADD_CHARSET_DATA (buf, 0, 0, id);
+  ADD_CHARSET_DATA (buf, 0, id);
   next = Fnext_single_property_change (make_number (pos), Qcharset,
                                       coding->src_object,
                                       make_number (limit));
@@ -5954,8 +6328,10 @@ handle_charset_annotation (pos, limit, coding, buf, stop)
 
 
 static void
-consume_chars (coding)
+consume_chars (coding, translation_table, max_lookup)
      struct coding_system *coding;
+     Lisp_Object translation_table;
+     int max_lookup;
 {
   int *buf = coding->charbuf;
   int *buf_end = coding->charbuf + coding->charbuf_size;
@@ -5967,6 +6343,10 @@ consume_chars (coding)
   Lisp_Object eol_type;
   int c;
   EMACS_INT stop, stop_composition, stop_charset;
+  int *lookup_buf = NULL;
+
+  if (! NILP (translation_table))
+    lookup_buf = alloca (sizeof (int) * max_lookup);
 
   eol_type = CODING_ID_EOL_TYPE (coding->id);
   if (VECTORP (eol_type))
@@ -5993,6 +6373,8 @@ consume_chars (coding)
   buf_end -= 1 + MAX_ANNOTATION_LENGTH;
   while (buf < buf_end)
     {
+      Lisp_Object trans;
+
       if (pos == stop)
        {
          if (pos == end_pos)
@@ -6011,11 +6393,12 @@ consume_chars (coding)
        {
          EMACS_INT bytes;
 
-         if (! CODING_FOR_UNIBYTE (coding)
-             && (bytes = MULTIBYTE_LENGTH (src, src_end)) > 0)
+         if (coding->encoder == encode_coding_raw_text)
+           c = *src++, pos++;
+         else if ((bytes = MULTIBYTE_LENGTH (src, src_end)) > 0)
            c = STRING_CHAR_ADVANCE (src), pos += bytes;
          else
-           c = *src++, pos++;
+           c = BYTE8_TO_CHAR (*src), src++, pos++;
        }
       else
        c = STRING_CHAR_ADVANCE (src), pos++;
@@ -6031,7 +6414,33 @@ consume_chars (coding)
                c = '\r';
            }
        }
-      *buf++ = c;
+
+      trans = Qnil;
+      LOOKUP_TRANSLATION_TABLE (translation_table, c, trans);
+      if (NILP (trans))
+       *buf++ = c;
+      else
+       {
+         int from_nchars = 1, to_nchars = 1;
+         int *lookup_buf_end;
+         const unsigned char *p = src;
+         int i;
+
+         lookup_buf[0] = c;
+         for (i = 1; i < max_lookup && p < src_end; i++)
+           lookup_buf[i] = STRING_CHAR_ADVANCE (p);
+         lookup_buf_end = lookup_buf + i;
+         trans = get_translation (trans, lookup_buf, lookup_buf_end, 1,
+                                  &from_nchars, &to_nchars);
+         if (EQ (trans, Qt)
+             || buf + to_nchars > buf_end)
+           break;
+         *buf++ = *lookup_buf;
+         for (i = 1; i < to_nchars; i++)
+           *buf++ = XINT (AREF (trans, i));
+         for (i = 1; i < from_nchars; i++, pos++)
+           src += MULTIBYTE_LENGTH_NO_CHECK (src);
+       }
     }
 
   coding->consumed = src - coding->source;
@@ -6067,8 +6476,14 @@ encode_coding (coding)
      struct coding_system *coding;
 {
   Lisp_Object attrs;
+  Lisp_Object translation_table;
+  int max_lookup;
 
   attrs = CODING_ID_ATTRS (coding->id);
+  if (coding->encoder == encode_coding_raw_text)
+    translation_table = Qnil, max_lookup = 0;
+  else
+    translation_table = get_translation_table (attrs, 1, &max_lookup);
 
   if (BUFFERP (coding->dst_object))
     {
@@ -6079,20 +6494,14 @@ encode_coding (coding)
 
   coding->consumed = coding->consumed_char = 0;
   coding->produced = coding->produced_char = 0;
-  coding->result = CODING_RESULT_SUCCESS;
+  record_conversion_result (coding, CODING_RESULT_SUCCESS);
   coding->errors = 0;
 
   ALLOC_CONVERSION_WORK_AREA (coding);
 
   do {
     coding_set_source (coding);
-    consume_chars (coding);
-
-    if (!NILP (CODING_ATTR_ENCODE_TBL (attrs)))
-      translate_chars (coding, CODING_ATTR_ENCODE_TBL (attrs));
-    else if (!NILP (Vstandard_translation_table_for_encode))
-      translate_chars (coding, Vstandard_translation_table_for_encode);
-
+    consume_chars (coding, translation_table, max_lookup);
     coding_set_destination (coding);
     (*(coding->encoder)) (coding);
   } while (coding->consumed_char < coding->src_chars);
@@ -6121,17 +6530,25 @@ static int reused_workbuf_in_use;
 /* Return a working buffer of code convesion.  MULTIBYTE specifies the
    multibyteness of returning buffer.  */
 
-Lisp_Object
+static Lisp_Object
 make_conversion_work_buffer (multibyte)
+     int multibyte;
 {
   Lisp_Object name, workbuf;
   struct buffer *current;
 
   if (reused_workbuf_in_use++)
-    name = Fgenerate_new_buffer_name (Vcode_conversion_workbuf_name, Qnil);
+    {
+      name = Fgenerate_new_buffer_name (Vcode_conversion_workbuf_name, Qnil);
+      workbuf = Fget_buffer_create (name);
+    }
   else
-    name = Vcode_conversion_workbuf_name;
-  workbuf = Fget_buffer_create (name);
+    {
+      name = Vcode_conversion_workbuf_name;
+      workbuf = Fget_buffer_create (name);
+      if (NILP (Vcode_conversion_reused_workbuf))
+       Vcode_conversion_reused_workbuf = workbuf;
+    }
   current = current_buffer;
   set_buffer_internal (XBUFFER (workbuf));
   Ferase_buffer ();      
@@ -6392,7 +6809,8 @@ decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
            = (unsigned char *) xrealloc (destination, coding->produced);
          if (! destination)
            {
-             coding->result = CODING_RESULT_INSUFFICIENT_DST;
+             record_conversion_result (coding,
+                                       CODING_RESULT_INSUFFICIENT_DST);
              unbind_to (count, Qnil);
              return;
            }
@@ -6422,7 +6840,7 @@ decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
                          saved_pt_byte + (coding->produced - bytes));
     }
 
-  unbind_to (count, Qnil);
+  unbind_to (count, coding->dst_object);
 }
 
 
@@ -6633,7 +7051,9 @@ If the user enters null input, return second argument DEFAULT-CODING-SYSTEM.  */
 DEFUN ("check-coding-system", Fcheck_coding_system, Scheck_coding_system,
        1, 1, 0,
        doc: /* Check validity of CODING-SYSTEM.
-If valid, return CODING-SYSTEM, else signal a `coding-system-error' error.  */)
+If valid, return CODING-SYSTEM, else signal a `coding-system-error' error.
+It is valid if it is nil or a symbol defined as a coding system by the
+function `define-coding-system'.  */)
   (coding_system)
      Lisp_Object coding_system;
 {
@@ -6705,53 +7125,73 @@ detect_coding_system (src, src_chars, src_bytes, highest, multibytep,
       for (i = 0; src < src_end; i++, src++)
        {
          c = *src;
-         if (c & 0x80 || (c < 0x20 && (c == 0
-                                       || c == ISO_CODE_ESC
-                                       || c == ISO_CODE_SI
-                                       || c == ISO_CODE_SO)))
+         if (c & 0x80)
            break;
+         if (c < 0x20
+             && (c == ISO_CODE_ESC || c == ISO_CODE_SI || c == ISO_CODE_SO)
+             && inhibit_iso_escape_detection)
+           {
+             coding.head_ascii = src - coding.source;
+             if (detect_coding_iso_2022 (&coding, &detect_info))
+               {
+                 /* We have scanned the whole data.  */
+                 if (! (detect_info.rejected & CATEGORY_MASK_ISO_7_ELSE))
+                   /* We didn't find an 8-bit code.  */
+                   src = src_end;
+                 break;
+               }
+           }
        }
-      /* Skipped bytes must be even for utf-16 detecor.  */
-      if (i % 2)
-       src--;
       coding.head_ascii = src - coding.source;
 
-      if (src < src_end)
-       for (i = 0; i < coding_category_raw_text; i++)
-         {
-           category = coding_priorities[i];
-           this = coding_categories + category;
-
-           if (this->id < 0)
-             {
-               /* No coding system of this category is defined.  */
-               detect_info.rejected |= (1 << category);
-             }
-           else if (category >= coding_category_raw_text)
-             continue;
-           else if (detect_info.checked & (1 << category))
+      if (src < src_end
+         || detect_info.found)
+       {
+         if (src == src_end)
+           /* As all bytes are 7-bit, we can ignore non-ISO-2022 codings.  */
+           for (i = 0; i < coding_category_raw_text; i++)
              {
-               if (highest
-                   && (detect_info.found & (1 << category)))
+               category = coding_priorities[i];
+               if (detect_info.found & (1 << category))
                  break;
              }
-           else
+         else
+           for (i = 0; i < coding_category_raw_text; i++)
              {
-               if ((*(this->detector)) (&coding, &detect_info)
-                   && highest
-                   && (detect_info.found & (1 << category)))
+               category = coding_priorities[i];
+               this = coding_categories + category;
+
+               if (this->id < 0)
                  {
-                   if (category == coding_category_utf_16_auto)
+                   /* No coding system of this category is defined.  */
+                   detect_info.rejected |= (1 << category);
+                 }
+               else if (category >= coding_category_raw_text)
+                 continue;
+               else if (detect_info.checked & (1 << category))
+                 {
+                   if (highest
+                       && (detect_info.found & (1 << category)))
+                     break;
+                 }
+               else
+                 {
+                   if ((*(this->detector)) (&coding, &detect_info)
+                       && highest
+                       && (detect_info.found & (1 << category)))
                      {
-                       if (detect_info.found & CATEGORY_MASK_UTF_16_LE)
-                         category = coding_category_utf_16_le;
-                       else
-                         category = coding_category_utf_16_be;
+                       if (category == coding_category_utf_16_auto)
+                         {
+                           if (detect_info.found & CATEGORY_MASK_UTF_16_LE)
+                             category = coding_category_utf_16_le;
+                           else
+                             category = coding_category_utf_16_be;
+                         }
+                       break;
                      }
-                   break;
                  }
              }
-         }
+       }
 
       if (detect_info.rejected == CATEGORY_MASK_ANY)
        {
@@ -6814,7 +7254,6 @@ detect_coding_system (src, src_chars, src_bytes, highest, multibytep,
     {
       if (detect_coding_utf_16 (&coding, &detect_info))
        {
-         enum coding_category category;
          struct coding_system *this;
 
          if (detect_info.found & CATEGORY_MASK_UTF_16_LE)
@@ -6967,7 +7406,11 @@ char_encodable_p (c, attrs)
 {
   Lisp_Object tail;
   struct charset *charset;
+  Lisp_Object translation_table;
 
+  translation_table = CODING_ATTR_TRANS_TBL (attrs);
+  if (! NILP (translation_table))
+    c = translate_char (translation_table, c);
   for (tail = CODING_ATTR_CHARSET_LIST (attrs);
        CONSP (tail); tail = XCDR (tail))
     {
@@ -7038,7 +7481,11 @@ DEFUN ("find-coding-systems-region-internal",
        attrs = AREF (CODING_SYSTEM_SPEC (XCAR (tail)), 0);
        if (EQ (XCAR (tail), CODING_ATTR_BASE_NAME (attrs))
            && ! EQ (CODING_ATTR_TYPE (attrs), Qundecided))
-         coding_attrs_list = Fcons (attrs, coding_attrs_list);
+         {
+           ASET (attrs, coding_attr_trans_tbl,
+                 get_translation_table (attrs, 1, NULL));
+           coding_attrs_list = Fcons (attrs, coding_attrs_list);
+         }
       }
 
   if (STRINGP (start))
@@ -7091,7 +7538,7 @@ DEFUN ("find-coding-systems-region-internal",
        }
     }
 
-  safe_codings = Qnil;
+  safe_codings = list2 (Qraw_text, Qno_conversion);
   for (tail = coding_attrs_list; CONSP (tail); tail = XCDR (tail))
     if (! NILP (XCAR (tail)))
       safe_codings = Fcons (CODING_ATTR_BASE_NAME (XCAR (tail)), safe_codings);
@@ -7119,7 +7566,7 @@ to the string.  */)
 {
   int n;
   struct coding_system coding;
-  Lisp_Object attrs, charset_list;
+  Lisp_Object attrs, charset_list, translation_table;
   Lisp_Object positions;
   int from, to;
   const unsigned char *p, *stop, *pend;
@@ -7131,6 +7578,7 @@ to the string.  */)
     return Qnil;
   ascii_compatible = ! NILP (CODING_ATTR_ASCII_COMPAT (attrs));
   charset_list = CODING_ATTR_CHARSET_LIST (attrs);
+  translation_table = get_translation_table (attrs, 1, NULL);
 
   if (NILP (string))
     {
@@ -7192,7 +7640,8 @@ to the string.  */)
 
       c = STRING_CHAR_ADVANCE (p);
       if (! (ASCII_CHAR_P (c) && ascii_compatible)
-         && ! char_charset (c, charset_list, NULL))
+         && ! char_charset (translate_char (translation_table, c),
+                            charset_list, NULL))
        {
          positions = Fcons (make_number (from), positions);
          n--;
@@ -7233,7 +7682,7 @@ buffer positions.  END is ignored.  */)
   int pos;
   const unsigned char *p, *pbeg, *pend;
   int c;
-  Lisp_Object tail, elt;
+  Lisp_Object tail, elt, attrs;
 
   if (STRINGP (start))
     {
@@ -7271,9 +7720,10 @@ buffer positions.  END is ignored.  */)
   for (tail = coding_system_list; CONSP (tail); tail = XCDR (tail))
     {
       elt = XCAR (tail);
-      list = Fcons (Fcons (elt, Fcons (AREF (CODING_SYSTEM_SPEC (elt), 0),
-                                      Qnil)),
-                   list);
+      attrs = AREF (CODING_SYSTEM_SPEC (elt), 0);
+      ASET (attrs, coding_attr_trans_tbl,
+           get_translation_table (attrs, 1, NULL));
+      list = Fcons (Fcons (elt, Fcons (attrs, Qnil)), list);
     }
 
   if (STRINGP (start))
@@ -7329,7 +7779,6 @@ buffer positions.  END is ignored.  */)
 }
 
 
-
 Lisp_Object
 code_convert_region (start, end, coding_system, dst_object, encodep, norecord)
      Lisp_Object start, end, coding_system, dst_object;
@@ -7369,9 +7818,6 @@ code_convert_region (start, end, coding_system, dst_object, encodep, norecord)
   if (! norecord)
     Vlast_coding_system_used = CODING_ID_NAME (coding.id);
 
-  if (coding.result != CODING_RESULT_SUCCESS)
-    error ("Code conversion error: %d", coding.result);
-
   return (BUFFERP (dst_object)
          ? make_number (coding.produced_char)
          : coding.dst_object);
@@ -7459,9 +7905,6 @@ code_convert_string (string, coding_system, dst_object,
   if (! norecord)
     Vlast_coding_system_used = CODING_ID_NAME (coding.id);
 
-  if (coding.result != CODING_RESULT_SUCCESS)
-    error ("Code conversion error: %d", coding.result);
-
   return (BUFFERP (dst_object)
          ? make_number (coding.produced_char)
          : coding.dst_object);
@@ -8034,13 +8477,13 @@ usage: (define-coding-system-internal ...)  */)
   CODING_ATTR_ASCII_COMPAT (attrs) = args[coding_arg_ascii_compatible_p];
 
   val = args[coding_arg_decode_translation_table];
-  if (! NILP (val))
-    CHECK_CHAR_TABLE (val);
+  if (! CHAR_TABLE_P (val) && ! CONSP (val))
+    CHECK_SYMBOL (val);
   CODING_ATTR_DECODE_TBL (attrs) = val;
 
   val = args[coding_arg_encode_translation_table];
-  if (! NILP (val))
-    CHECK_CHAR_TABLE (val);
+  if (! CHAR_TABLE_P (val) && ! CONSP (val))
+    CHECK_SYMBOL (val);
   CODING_ATTR_ENCODE_TBL (attrs) = val;
 
   val = args[coding_arg_post_read_conversion];
@@ -8316,8 +8759,9 @@ usage: (define-coding-system-internal ...)  */)
 
       struct charset *charset;
 
-      if (XINT (Flength (charset_list)) != 3)
-       error ("There should be just three charsets");
+      if (XINT (Flength (charset_list)) != 3
+         && XINT (Flength (charset_list)) != 4)
+       error ("There should be three or four charsets");
 
       charset = CHARSET_FROM_ID (XINT (XCAR (charset_list)));
       if (CHARSET_DIMENSION (charset) != 1)
@@ -8338,6 +8782,15 @@ usage: (define-coding-system-internal ...)  */)
        error ("Dimension of charset %s is not two",
               SDATA (SYMBOL_NAME (CHARSET_NAME (charset))));
 
+      charset_list = XCDR (charset_list);
+      if (! NILP (charset_list))
+       {
+         charset = CHARSET_FROM_ID (XINT (XCAR (charset_list)));
+         if (CHARSET_DIMENSION (charset) != 2)
+           error ("Dimension of charset %s is not two",
+                  SDATA (SYMBOL_NAME (CHARSET_NAME (charset))));
+       }
+
       category = coding_category_sjis;
       Vsjis_coding_system = name;
     }
@@ -8439,6 +8892,59 @@ usage: (define-coding-system-internal ...)  */)
 }
 
 
+DEFUN ("coding-system-put", Fcoding_system_put, Scoding_system_put,
+       3, 3, 0,
+       doc: /* Change value in CODING-SYSTEM's property list PROP to VAL.  */)
+  (coding_system, prop, val)
+     Lisp_Object coding_system, prop, val;
+{
+  Lisp_Object spec, attrs;
+
+  CHECK_CODING_SYSTEM_GET_SPEC (coding_system, spec);
+  attrs = AREF (spec, 0);
+  if (EQ (prop, QCmnemonic))
+    {
+      if (! STRINGP (val))
+       CHECK_CHARACTER (val);
+      CODING_ATTR_MNEMONIC (attrs) = val;
+    }
+  else if (EQ (prop, QCdefalut_char))
+    {
+      if (NILP (val))
+       val = make_number (' ');
+      else
+       CHECK_CHARACTER (val);
+      CODING_ATTR_DEFAULT_CHAR (attrs) = val;
+    }
+  else if (EQ (prop, QCdecode_translation_table))
+    {
+      if (! CHAR_TABLE_P (val) && ! CONSP (val))
+       CHECK_SYMBOL (val);
+      CODING_ATTR_DECODE_TBL (attrs) = val;
+    }
+  else if (EQ (prop, QCencode_translation_table))
+    {
+      if (! CHAR_TABLE_P (val) && ! CONSP (val))
+       CHECK_SYMBOL (val);
+      CODING_ATTR_ENCODE_TBL (attrs) = val;
+    }
+  else if (EQ (prop, QCpost_read_conversion))
+    {
+      CHECK_SYMBOL (val);
+      CODING_ATTR_POST_READ (attrs) = val;
+    }
+  else if (EQ (prop, QCpre_write_conversion))
+    {
+      CHECK_SYMBOL (val);
+      CODING_ATTR_PRE_WRITE (attrs) = val;
+    }
+
+  CODING_ATTR_PLIST (attrs)
+    = Fplist_put (CODING_ATTR_PLIST (attrs), prop, val);
+  return val;
+}
+
+
 DEFUN ("define-coding-system-alias", Fdefine_coding_system_alias,
        Sdefine_coding_system_alias, 2, 2, 0,
        doc: /* Define ALIAS as an alias for CODING-SYSTEM.  */)
@@ -8691,7 +9197,7 @@ syms_of_coding ()
   Qchar_table_extra_slots = intern ("char-table-extra-slots");
 
   DEFSYM (Qtranslation_table, "translation-table");
-  Fput (Qtranslation_table, Qchar_table_extra_slots, make_number (1));
+  Fput (Qtranslation_table, Qchar_table_extra_slots, make_number (2));
   DEFSYM (Qtranslation_table_id, "translation-table-id");
   DEFSYM (Qtranslation_table_for_decode, "translation-table-for-decode");
   DEFSYM (Qtranslation_table_for_encode, "translation-table-for-encode");
@@ -8701,6 +9207,12 @@ syms_of_coding ()
   DEFSYM (Qemacs_mule, "emacs-mule");
 
   DEFSYM (QCcategory, ":category");
+  DEFSYM (QCmnemonic, ":mnemonic");
+  DEFSYM (QCdefalut_char, ":default-char");
+  DEFSYM (QCdecode_translation_table, ":decode-translation-table");
+  DEFSYM (QCencode_translation_table, ":encode-translation-table");
+  DEFSYM (QCpost_read_conversion, ":post-read-conversion");
+  DEFSYM (QCpre_write_conversion, ":pre-write-conversion");
 
   Vcoding_category_table
     = Fmake_vector (make_number (coding_category_max), Qnil);
@@ -8746,6 +9258,12 @@ syms_of_coding ()
   ASET (Vcoding_category_table, coding_category_undecided,
        intern ("coding-category-undecided"));
 
+  DEFSYM (Qinsufficient_source, "insufficient-source");
+  DEFSYM (Qinconsistent_eol, "inconsistent-eol");
+  DEFSYM (Qinvalid_source, "invalid-source");
+  DEFSYM (Qinterrupted, "interrupted");
+  DEFSYM (Qinsufficient_memory, "insufficient-memory");
+
   defsubr (&Scoding_system_p);
   defsubr (&Sread_coding_system);
   defsubr (&Sread_non_nil_coding_system);
@@ -8772,6 +9290,7 @@ syms_of_coding ()
   defsubr (&Sset_coding_system_priority);
   defsubr (&Sdefine_coding_system_internal);
   defsubr (&Sdefine_coding_system_alias);
+  defsubr (&Scoding_system_put);
   defsubr (&Scoding_system_base);
   defsubr (&Scoding_system_plist);
   defsubr (&Scoding_system_aliases);
@@ -8841,6 +9360,23 @@ the value of `buffer-file-coding-system' is used.  */);
 Coding system used in the latest file or process I/O.  */);
   Vlast_coding_system_used = Qnil;
 
+  DEFVAR_LISP ("last-code-conversion-error", &Vlast_code_conversion_error,
+              doc: /*
+Error status of the last code conversion.
+
+When an error was detected in the last code conversion, this variable
+is set to one of the following symbols.
+  `insufficient-source'
+  `inconsistent-eol'
+  `invalid-source'
+  `interrupted'
+  `insufficient-memory'
+When no error was detected, the value doesn't change.  So, to check
+the error status of a code conversion by this variable, you must
+explicitly set this variable to nil before performing code
+conversion.  */);
+  Vlast_code_conversion_error = Qnil;
+
   DEFVAR_BOOL ("inhibit-eol-conversion", &inhibit_eol_conversion,
               doc: /*
 *Non-nil means always inhibit code conversion of end-of-line format.
@@ -9093,3 +9629,6 @@ emacs_strerror (error_number)
 }
 
 #endif /* emacs */
+
+/* arch-tag: 3a3a2b01-5ff6-4071-9afe-f5b808d9229d
+   (do not change this comment) */