(decode_coding_object): Revert part of last change.
[bpt/emacs.git] / src / coding.c
index 20c6c00..d862ed1 100644 (file)
@@ -1,8 +1,8 @@
 /* Coding system handler (conversion, detection, etc).
    Copyright (C) 2001, 2002, 2003, 2004, 2005,
-                 2006, 2007 Free Software Foundation, Inc.
+                 2006, 2007, 2008 Free Software Foundation, Inc.
    Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-     2005, 2006, 2007
+     2005, 2006, 2007, 2008
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H14PRO021
    Copyright (C) 2003
@@ -300,6 +300,8 @@ encode_coding_XXX (coding)
 #include "composite.h"
 #include "coding.h"
 #include "window.h"
+#include "frame.h"
+#include "termhooks.h"
 
 Lisp_Object Vcoding_system_hash_table;
 
@@ -327,6 +329,8 @@ Lisp_Object Qtarget_idx;
 Lisp_Object Qinsufficient_source, Qinconsistent_eol, Qinvalid_source;
 Lisp_Object Qinterrupted, Qinsufficient_memory;
 
+extern Lisp_Object Qcompletion_ignore_case;
+
 /* If a symbol has this property, evaluate the value to define the
    symbol as a coding system.  */
 static Lisp_Object Qcoding_system_define_form;
@@ -381,16 +385,10 @@ int inhibit_iso_escape_detection;
 /* Flag to make buffer-file-coding-system inherit from process-coding.  */
 int inherit_process_coding_system;
 
-/* Coding system to be used to encode text for terminal display.  */
-struct coding_system terminal_coding;
-
 /* Coding system to be used to encode text for terminal display when
    terminal coding system is nil.  */
 struct coding_system safe_terminal_coding;
 
-/* Coding system of what is sent from terminal keyboard.  */
-struct coding_system keyboard_coding;
-
 Lisp_Object Vfile_coding_system_alist;
 Lisp_Object Vprocess_coding_system_alist;
 Lisp_Object Vnetwork_coding_system_alist;
@@ -957,6 +955,11 @@ record_conversion_result (struct coding_system *coding,
   } while (0)
 
 
+/* If there are at least BYTES length of room at dst, allocate memory
+   for coding->destination and update dst and dst_end.  We don't have
+   to take care of coding->source which will be relocated.  It is
+   handled by calling coding_set_source in encode_coding.  */
+
 #define ASSURE_DESTINATION(bytes)                              \
   do {                                                         \
     if (dst + (bytes) >= dst_end)                              \
@@ -969,6 +972,66 @@ record_conversion_result (struct coding_system *coding,
   } while (0)
 
 
+/* Store multibyte form of the character C in P, and advance P to the
+   end of the multibyte form.  This is like CHAR_STRING_ADVANCE but it
+   never calls MAYBE_UNIFY_CHAR.  */
+
+#define CHAR_STRING_ADVANCE_NO_UNIFY(c, p)     \
+  do {                                         \
+    if ((c) <= MAX_1_BYTE_CHAR)                        \
+      *(p)++ = (c);                            \
+    else if ((c) <= MAX_2_BYTE_CHAR)           \
+      *(p)++ = (0xC0 | ((c) >> 6)),            \
+       *(p)++ = (0x80 | ((c) & 0x3F));         \
+    else if ((c) <= MAX_3_BYTE_CHAR)           \
+      *(p)++ = (0xE0 | ((c) >> 12)),           \
+       *(p)++ = (0x80 | (((c) >> 6) & 0x3F)),  \
+       *(p)++ = (0x80 | ((c) & 0x3F));         \
+    else if ((c) <= MAX_4_BYTE_CHAR)           \
+      *(p)++ = (0xF0 | (c >> 18)),             \
+       *(p)++ = (0x80 | ((c >> 12) & 0x3F)),   \
+       *(p)++ = (0x80 | ((c >> 6) & 0x3F)),    \
+       *(p)++ = (0x80 | (c & 0x3F));           \
+    else if ((c) <= MAX_5_BYTE_CHAR)           \
+      *(p)++ = 0xF8,                           \
+       *(p)++ = (0x80 | ((c >> 18) & 0x0F)),   \
+       *(p)++ = (0x80 | ((c >> 12) & 0x3F)),   \
+       *(p)++ = (0x80 | ((c >> 6) & 0x3F)),    \
+       *(p)++ = (0x80 | (c & 0x3F));           \
+    else                                       \
+      (p) += BYTE8_STRING ((c) - 0x3FFF80, p); \
+  } while (0)
+
+
+/* Return the character code of character whose multibyte form is at
+   P, and advance P to the end of the multibyte form.  This is like
+   STRING_CHAR_ADVANCE, but it never calls MAYBE_UNIFY_CHAR.  */
+
+#define STRING_CHAR_ADVANCE_NO_UNIFY(p)                                \
+  (!((p)[0] & 0x80)                                            \
+   ? *(p)++                                                    \
+   : ! ((p)[0] & 0x20)                                         \
+   ? ((p) += 2,                                                        \
+      ((((p)[-2] & 0x1F) << 6)                                 \
+       | ((p)[-1] & 0x3F)                                      \
+       | ((unsigned char) ((p)[-2]) < 0xC2 ? 0x3FFF80 : 0)))   \
+   : ! ((p)[0] & 0x10)                                         \
+   ? ((p) += 3,                                                        \
+      ((((p)[-3] & 0x0F) << 12)                                        \
+       | (((p)[-2] & 0x3F) << 6)                               \
+       | ((p)[-1] & 0x3F)))                                    \
+   : ! ((p)[0] & 0x08)                                         \
+   ? ((p) += 4,                                                        \
+      ((((p)[-4] & 0xF) << 18)                                 \
+       | (((p)[-3] & 0x3F) << 12)                              \
+       | (((p)[-2] & 0x3F) << 6)                               \
+       | ((p)[-1] & 0x3F)))                                    \
+   : ((p) += 5,                                                        \
+      ((((p)[-4] & 0x3F) << 18)                                        \
+       | (((p)[-3] & 0x3F) << 12)                              \
+       | (((p)[-2] & 0x3F) << 6)                               \
+       | ((p)[-1] & 0x3F))))
+
 
 static void
 coding_set_source (coding)
@@ -1001,7 +1064,7 @@ coding_set_destination (coding)
     {
       if (coding->src_pos < 0)
        {
-         coding->destination = BEG_ADDR + coding->dst_pos_byte - 1;
+         coding->destination = BEG_ADDR + coding->dst_pos_byte - BEG_BYTE;
          coding->dst_bytes = (GAP_END_ADDR
                               - (coding->src_bytes - coding->consumed)
                               - coding->destination);
@@ -1011,7 +1074,7 @@ coding_set_destination (coding)
          /* We are sure that coding->dst_pos_byte is before the gap
             of the buffer. */
          coding->destination = (BUF_BEG_ADDR (XBUFFER (coding->dst_object))
-                                + coding->dst_pos_byte - 1);
+                                + coding->dst_pos_byte - BEG_BYTE);
          coding->dst_bytes = (BUF_GAP_END_ADDR (XBUFFER (coding->dst_object))
                               - coding->destination);
        }
@@ -1034,20 +1097,23 @@ coding_alloc_by_realloc (coding, bytes)
 }
 
 static void
-coding_alloc_by_making_gap (coding, offset, bytes)
+coding_alloc_by_making_gap (coding, gap_head_used, bytes)
      struct coding_system *coding;
-     EMACS_INT offset, bytes;
+     EMACS_INT gap_head_used, bytes;
 {
-  if (BUFFERP (coding->dst_object)
-      && EQ (coding->src_object, coding->dst_object))
+  if (EQ (coding->src_object, coding->dst_object))
     {
-      EMACS_INT add = offset + (coding->src_bytes - coding->consumed);
+      /* The gap may contain the produced data at the head and not-yet
+        consumed data at the tail.  To preserve those data, we at
+        first make the gap size to zero, then increase the gap
+        size.  */
+      EMACS_INT add = GAP_SIZE;
 
-      GPT += offset, GPT_BYTE += offset;
-      GAP_SIZE -= add; ZV += add; Z += add; ZV_BYTE += add; Z_BYTE += add;
+      GPT += gap_head_used, GPT_BYTE += gap_head_used;
+      GAP_SIZE = 0; ZV += add; Z += add; ZV_BYTE += add; Z_BYTE += add;
       make_gap (bytes);
       GAP_SIZE += add; ZV -= add; Z -= add; ZV_BYTE -= add; Z_BYTE -= add;
-      GPT -= offset, GPT_BYTE -= offset;
+      GPT -= gap_head_used, GPT_BYTE -= gap_head_used;
     }
   else
     {
@@ -1070,7 +1136,11 @@ alloc_destination (coding, nbytes, dst)
   EMACS_INT offset = dst - coding->destination;
 
   if (BUFFERP (coding->dst_object))
-    coding_alloc_by_making_gap (coding, offset, nbytes);
+    {
+      struct buffer *buf = XBUFFER (coding->dst_object);
+
+      coding_alloc_by_making_gap (coding, dst - BUF_GPT_ADDR (buf), nbytes);
+    }
   else
     coding_alloc_by_realloc (coding, nbytes);
   record_conversion_result (coding, CODING_RESULT_SUCCESS);
@@ -1227,6 +1297,8 @@ decode_coding_utf_8 (coding)
   int consumed_chars = 0, consumed_chars_base;
   int multibytep = coding->src_multibyte;
   Lisp_Object attr, charset_list;
+  int eol_crlf = EQ (CODING_ID_EOL_TYPE (coding->id), Qdos);
+  int byte_after_cr = -1;
 
   CODING_GET_INFO (coding, attr, charset_list);
 
@@ -1240,13 +1312,18 @@ decode_coding_utf_8 (coding)
       if (charbuf >= charbuf_end)
        break;
 
-      ONE_MORE_BYTE (c1);
+      if (byte_after_cr >= 0)
+       c1 = byte_after_cr, byte_after_cr = -1;
+      else
+       ONE_MORE_BYTE (c1);
       if (c1 < 0)
        {
          c = - c1;
        }
       else if (UTF_8_1_OCTET_P(c1))
        {
+         if (eol_crlf && c1 == '\r')
+           ONE_MORE_BYTE (byte_after_cr);
          c = c1;
        }
       else
@@ -1355,7 +1432,7 @@ encode_coding_utf_8 (coding)
            }
          else
            {
-             CHAR_STRING_ADVANCE (c, pend);
+             CHAR_STRING_ADVANCE_NO_UNIFY (c, pend);
              for (p = str; p < pend; p++)
                EMIT_ONE_BYTE (*p);
            }
@@ -1372,7 +1449,7 @@ encode_coding_utf_8 (coding)
          if (CHAR_BYTE8_P (c))
            *dst++ = CHAR_TO_BYTE8 (c);
          else
-           dst += CHAR_STRING (c, dst);
+           CHAR_STRING_ADVANCE_NO_UNIFY (c, dst);
          produced_chars++;
        }
     }
@@ -1460,6 +1537,8 @@ decode_coding_utf_16 (coding)
   enum utf_16_endian_type endian = CODING_UTF_16_ENDIAN (coding);
   int surrogate = CODING_UTF_16_SURROGATE (coding);
   Lisp_Object attr, charset_list;
+  int eol_crlf = EQ (CODING_ID_EOL_TYPE (coding->id), Qdos);
+  int byte_after_cr1 = -1, byte_after_cr2 = -1;
 
   CODING_GET_INFO (coding, attr, charset_list);
 
@@ -1499,13 +1578,19 @@ decode_coding_utf_16 (coding)
       if (charbuf + 2 >= charbuf_end)
        break;
 
-      ONE_MORE_BYTE (c1);
+      if (byte_after_cr1 >= 0)
+       c1 = byte_after_cr1, byte_after_cr1 = -1;
+      else
+       ONE_MORE_BYTE (c1);
       if (c1 < 0)
        {
          *charbuf++ = -c1;
          continue;
        }
-      ONE_MORE_BYTE (c2);
+      if (byte_after_cr2 >= 0)
+       c2 = byte_after_cr2, byte_after_cr2 = -1;
+      else
+       ONE_MORE_BYTE (c2);
       if (c2 < 0)
        {
          *charbuf++ = ASCII_BYTE_P (c1) ? c1 : BYTE8_TO_CHAR (c1);
@@ -1514,6 +1599,7 @@ decode_coding_utf_16 (coding)
        }
       c = (endian == utf_16_big_endian
           ? ((c1 << 8) | c2) : ((c2 << 8) | c1));
+
       if (surrogate)
        {
          if (! UTF_16_LOW_SURROGATE_P (c))
@@ -1542,7 +1628,14 @@ decode_coding_utf_16 (coding)
          if (UTF_16_HIGH_SURROGATE_P (c))
            CODING_UTF_16_SURROGATE (coding) = surrogate = c;
          else
-           *charbuf++ = c;
+           {
+             if (eol_crlf && c == '\r')
+               {
+                 ONE_MORE_BYTE (byte_after_cr1);
+                 ONE_MORE_BYTE (byte_after_cr2);
+               }
+             *charbuf++ = c;
+           }
        }
     }
 
@@ -1713,7 +1806,7 @@ emacs_mule_char (coding, src, nbytes, nchars, id)
     {
       if (c >= 0xA0)
        {
-         /* Old style component character of a compostion.  */
+         /* Old style component character of a composition.  */
          if (c == 0xA0)
            {
              ONE_MORE_BYTE (c);
@@ -1900,7 +1993,7 @@ detect_coding_emacs_mule (coding, detect_info)
    value 0.  */
 
 #define DECODE_EMACS_MULE_COMPOSITION_CHAR(buf)                        \
-  if (1)                                                       \
+  do                                                           \
     {                                                          \
       int c;                                                   \
       int nbytes, nchars;                                      \
@@ -1918,7 +2011,7 @@ detect_coding_emacs_mule (coding, detect_info)
       src += nbytes;                                           \
       consumed_chars += nchars;                                        \
     }                                                          \
-  else
+  while (0)
 
 
 /* Decode a composition rule represented as a component of composition
@@ -2074,6 +2167,8 @@ decode_coding_emacs_mule (coding)
   int char_offset = coding->produced_char;
   int last_offset = char_offset;
   int last_id = charset_ascii;
+  int eol_crlf = EQ (CODING_ID_EOL_TYPE (coding->id), Qdos);
+  int byte_after_cr = -1;
 
   CODING_GET_INFO (coding, attrs, charset_list);
 
@@ -2087,7 +2182,10 @@ decode_coding_emacs_mule (coding)
       if (charbuf >= charbuf_end)
        break;
 
-      ONE_MORE_BYTE (c);
+      if (byte_after_cr >= 0)
+       c = byte_after_cr, byte_after_cr = -1;
+      else
+       ONE_MORE_BYTE (c);
       if (c < 0)
        {
          *charbuf++ = -c;
@@ -2095,6 +2193,8 @@ decode_coding_emacs_mule (coding)
        }
       else if (c < 0x80)
        {
+         if (eol_crlf && c == '\r')
+           ONE_MORE_BYTE (byte_after_cr);
          *charbuf++ = c;
          char_offset++;
        }
@@ -2947,6 +3047,8 @@ decode_coding_iso_2022 (coding)
   int char_offset = coding->produced_char;
   int last_offset = char_offset;
   int last_id = charset_ascii;
+  int eol_crlf = EQ (CODING_ID_EOL_TYPE (coding->id), Qdos);
+  int byte_after_cr = -1;
 
   CODING_GET_INFO (coding, attrs, charset_list);
   setup_iso_safe_charsets (attrs);
@@ -2964,7 +3066,10 @@ decode_coding_iso_2022 (coding)
       if (charbuf >= charbuf_end)
        break;
 
-      ONE_MORE_BYTE (c1);
+      if (byte_after_cr >= 0)
+       c1 = byte_after_cr, byte_after_cr = -1;
+      else
+       ONE_MORE_BYTE (c1);
       if (c1 < 0)
        goto invalid_code;
 
@@ -3023,6 +3128,8 @@ decode_coding_iso_2022 (coding)
          break;
 
        case ISO_control_0:
+         if (eol_crlf && c1 == '\r')
+           ONE_MORE_BYTE (byte_after_cr);
          MAYBE_FINISH_COMPOSITION ();
          charset = CHARSET_FROM_ID (charset_ascii);
          break;
@@ -4093,6 +4200,8 @@ decode_coding_sjis (coding)
   int char_offset = coding->produced_char;
   int last_offset = char_offset;
   int last_id = charset_ascii;
+  int eol_crlf = EQ (CODING_ID_EOL_TYPE (coding->id), Qdos);
+  int byte_after_cr = -1;
 
   CODING_GET_INFO (coding, attrs, charset_list);
 
@@ -4113,11 +4222,18 @@ decode_coding_sjis (coding)
       if (charbuf >= charbuf_end)
        break;
 
-      ONE_MORE_BYTE (c);
+      if (byte_after_cr >= 0)
+       c = byte_after_cr, byte_after_cr = -1;
+      else
+       ONE_MORE_BYTE (c);
       if (c < 0)
        goto invalid_code;
       if (c < 0x80)
-       charset = charset_roman;
+       {
+         if (eol_crlf && c == '\r')
+           ONE_MORE_BYTE (byte_after_cr);
+         charset = charset_roman;
+       }
       else if (c == 0x80 || c == 0xA0)
        goto invalid_code;
       else if (c >= 0xA1 && c <= 0xDF)
@@ -4195,6 +4311,8 @@ decode_coding_big5 (coding)
   int char_offset = coding->produced_char;
   int last_offset = char_offset;
   int last_id = charset_ascii;
+  int eol_crlf = EQ (CODING_ID_EOL_TYPE (coding->id), Qdos);
+  int byte_after_cr = -1;
 
   CODING_GET_INFO (coding, attrs, charset_list);
   val = charset_list;
@@ -4212,12 +4330,19 @@ decode_coding_big5 (coding)
       if (charbuf >= charbuf_end)
        break;
 
-      ONE_MORE_BYTE (c);
+      if (byte_after_cr >= 0)
+       c = byte_after_cr, byte_after_cr = -1;
+      else
+       ONE_MORE_BYTE (c);
 
       if (c < 0)
        goto invalid_code;
       if (c < 0x80)
-       charset = charset_roman;
+       {
+         if (eol_crlf && c == '\r')
+           ONE_MORE_BYTE (byte_after_cr);
+         charset = charset_roman;
+       }
       else
        {
          /* BIG5 -> Big5 */
@@ -4634,10 +4759,19 @@ static void
 decode_coding_raw_text (coding)
      struct coding_system *coding;
 {
+  int eol_crlf = EQ (CODING_ID_EOL_TYPE (coding->id), Qdos);
+
   coding->chars_at_source = 1;
-  coding->consumed_char = 0;
-  coding->consumed = 0;
-  record_conversion_result (coding, CODING_RESULT_SUCCESS);
+  coding->consumed_char = coding->src_chars;
+  coding->consumed = coding->src_bytes;
+  if (eol_crlf && coding->source[coding->src_bytes - 1] == '\r')
+    {
+      coding->consumed_char--;
+      coding->consumed--;
+      record_conversion_result (coding, CODING_RESULT_INSUFFICIENT_SRC);
+    }
+  else
+    record_conversion_result (coding, CODING_RESULT_SUCCESS);
 }
 
 static int
@@ -4831,6 +4965,8 @@ decode_coding_charset (coding)
   int char_offset = coding->produced_char;
   int last_offset = char_offset;
   int last_id = charset_ascii;
+  int eol_crlf = EQ (CODING_ID_EOL_TYPE (coding->id), Qdos);
+  int byte_after_cr = -1;
 
   CODING_GET_INFO (coding, attrs, charset_list);
   valids = AREF (attrs, coding_attr_charset_valids);
@@ -4850,7 +4986,17 @@ decode_coding_charset (coding)
       if (charbuf >= charbuf_end)
        break;
 
-      ONE_MORE_BYTE (c);
+      if (byte_after_cr >= 0)
+       {
+         c = byte_after_cr;
+         byte_after_cr = -1;
+       }
+      else
+       {
+         ONE_MORE_BYTE (c);
+         if (eol_crlf && c == '\r')
+           ONE_MORE_BYTE (byte_after_cr);
+       }
       if (c < 0)
        goto invalid_code;
       code = c;
@@ -5719,7 +5865,10 @@ decode_eol (coding)
                  pos_end--;
                }
              pos++;
-             pos_byte += BYTES_BY_CHAR_HEAD (*p);
+             if (coding->dst_multibyte)
+               pos_byte += BYTES_BY_CHAR_HEAD (*p);
+             else
+               pos_byte++;
            }
        }
       coding->produced -= n;
@@ -5879,19 +6028,21 @@ produce_chars (coding, translation_table, last_block)
 {
   unsigned char *dst = coding->destination + coding->produced;
   unsigned char *dst_end = coding->destination + coding->dst_bytes;
-  int produced;
-  int produced_chars = 0;
+  EMACS_INT produced;
+  EMACS_INT produced_chars = 0;
   int carryover = 0;
 
   if (! coding->chars_at_source)
     {
-      /* Characters are in coding->charbuf.  */
+      /* Source characters are in coding->charbuf.  */
       int *buf = coding->charbuf;
       int *buf_end = buf + coding->charbuf_used;
 
-      if (BUFFERP (coding->src_object)
-         && EQ (coding->src_object, coding->dst_object))
-       dst_end = ((unsigned char *) coding->source) + coding->consumed;
+      if (EQ (coding->src_object, coding->dst_object))
+       {
+         coding_set_source (coding);
+         dst_end = ((unsigned char *) coding->source) + coding->consumed;
+       }
 
       while (buf < buf_end)
        {
@@ -5918,7 +6069,13 @@ produce_chars (coding, translation_table, last_block)
                                           buf_end - buf
                                           + MAX_MULTIBYTE_LENGTH * to_nchars,
                                           dst);
-                 dst_end = coding->destination + coding->dst_bytes;
+                 if (EQ (coding->src_object, coding->dst_object))
+                   {
+                     coding_set_source (coding);
+                     dst_end = ((unsigned char *) coding->source) + coding->consumed;
+                   }
+                 else
+                   dst_end = coding->destination + coding->dst_bytes;
                }
 
              for (i = 0; i < to_nchars; i++)
@@ -5927,7 +6084,7 @@ produce_chars (coding, translation_table, last_block)
                    c = XINT (AREF (trans, i));
                  if (coding->dst_multibyte
                      || ! CHAR_BYTE8_P (c))
-                   CHAR_STRING_ADVANCE (c, dst);
+                   CHAR_STRING_ADVANCE_NO_UNIFY (c, dst);
                  else
                    *dst++ = CHAR_TO_BYTE8 (c);
                }
@@ -5944,18 +6101,18 @@ produce_chars (coding, translation_table, last_block)
     }
   else
     {
+      /* Source characters are at coding->source.  */
       const unsigned char *src = coding->source;
-      const unsigned char *src_end = src + coding->src_bytes;
-      Lisp_Object eol_type;
-
-      eol_type = CODING_ID_EOL_TYPE (coding->id);
+      const unsigned char *src_end = src + coding->consumed;
 
+      if (EQ (coding->dst_object, coding->src_object))
+       dst_end = (unsigned char *) src;
       if (coding->src_multibyte != coding->dst_multibyte)
        {
          if (coding->src_multibyte)
            {
              int multibytep = 1;
-             int consumed_chars;
+             EMACS_INT consumed_chars;
 
              while (1)
                {
@@ -5963,37 +6120,23 @@ produce_chars (coding, translation_table, last_block)
                  int c;
 
                  ONE_MORE_BYTE (c);
-                 if (c == '\r')
+                 if (dst == dst_end)
                    {
-                     if (EQ (eol_type, Qdos))
+                     if (EQ (coding->src_object, coding->dst_object))
+                       dst_end = (unsigned char *) src;
+                     if (dst == dst_end)
                        {
-                         if (src == src_end)
-                           {
-                             record_conversion_result
-                               (coding, CODING_RESULT_INSUFFICIENT_SRC);
-                             goto no_more_source;
-                           }
-                         if (*src == '\n')
-                           c = *src++;
+                         EMACS_INT offset = src - coding->source;
+
+                         dst = alloc_destination (coding, src_end - src + 1,
+                                                  dst);
+                         dst_end = coding->destination + coding->dst_bytes;
+                         coding_set_source (coding);
+                         src = coding->source + offset;
+                         src_end = coding->source + coding->src_bytes;
+                         if (EQ (coding->src_object, coding->dst_object))
+                           dst_end = (unsigned char *) src;
                        }
-                     else if (EQ (eol_type, Qmac))
-                       c = '\n';
-                   }
-                 if (dst == dst_end)
-                   {
-                     coding->consumed = src - coding->source;
-
-                   if (EQ (coding->src_object, coding->dst_object))
-                     dst_end = (unsigned char *) src;
-                   if (dst == dst_end)
-                     {
-                       dst = alloc_destination (coding, src_end - src + 1,
-                                                dst);
-                       dst_end = coding->destination + coding->dst_bytes;
-                       coding_set_source (coding);
-                       src = coding->source + coding->consumed;
-                       src_end = coding->source + coding->src_bytes;
-                     }
                    }
                  *dst++ = c;
                  produced_chars++;
@@ -6007,31 +6150,26 @@ produce_chars (coding, translation_table, last_block)
                int multibytep = 1;
                int c = *src++;
 
-               if (c == '\r')
-                 {
-                   if (EQ (eol_type, Qdos))
-                     {
-                       if (src < src_end
-                           && *src == '\n')
-                         c = *src++;
-                     }
-                   else if (EQ (eol_type, Qmac))
-                     c = '\n';
-                 }
                if (dst >= dst_end - 1)
                  {
-                   coding->consumed = src - coding->source;
-
                    if (EQ (coding->src_object, coding->dst_object))
                      dst_end = (unsigned char *) src;
                    if (dst >= dst_end - 1)
                      {
-                       dst = alloc_destination (coding, src_end - src + 2,
-                                                dst);
+                       EMACS_INT offset = src - coding->source;
+                       EMACS_INT more_bytes;
+
+                       if (EQ (coding->src_object, coding->dst_object))
+                         more_bytes = ((src_end - src) / 2) + 2;
+                       else
+                         more_bytes = src_end - src + 2;
+                       dst = alloc_destination (coding, more_bytes, dst);
                        dst_end = coding->destination + coding->dst_bytes;
                        coding_set_source (coding);
-                       src = coding->source + coding->consumed;
+                       src = coding->source + offset;
                        src_end = coding->source + coding->src_bytes;
+                       if (EQ (coding->src_object, coding->dst_object))
+                         dst_end = (unsigned char *) src;
                      }
                  }
                EMIT_ONE_BYTE (c);
@@ -6041,7 +6179,7 @@ produce_chars (coding, translation_table, last_block)
        {
          if (!EQ (coding->src_object, coding->dst_object))
            {
-             int require = coding->src_bytes - coding->dst_bytes;
+             EMACS_INT require = coding->src_bytes - coding->dst_bytes;
 
              if (require > 0)
                {
@@ -6053,28 +6191,10 @@ produce_chars (coding, translation_table, last_block)
                  src_end = coding->source + coding->src_bytes;
                }
            }
-         produced_chars = coding->src_chars;
+         produced_chars = coding->consumed_char;
          while (src < src_end)
-           {
-             int c = *src++;
-
-             if (c == '\r')
-               {
-                 if (EQ (eol_type, Qdos))
-                   {
-                     if (src < src_end
-                         && *src == '\n')
-                       c = *src++;
-                     produced_chars--;
-                   }
-                 else if (EQ (eol_type, Qmac))
-                   c = '\n';
-               }
-             *dst++ = c;
-           }
+           *dst++ = *src++;
        }
-      coding->consumed = coding->src_bytes;
-      coding->consumed_char = coding->src_chars;
     }
 
   produced = dst - (coding->destination + coding->produced);
@@ -6537,12 +6657,12 @@ consume_chars (coding, translation_table, max_lookup)
          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;
+           c = STRING_CHAR_ADVANCE_NO_UNIFY (src), pos += bytes;
          else
            c = BYTE8_TO_CHAR (*src), src++, pos++;
        }
       else
-       c = STRING_CHAR_ADVANCE (src), pos++;
+       c = STRING_CHAR_ADVANCE_NO_UNIFY (src), pos++;
       if ((c == '\r') && (coding->mode & CODING_MODE_SELECTIVE_DISPLAY))
        c = '\n';
       if (! EQ (eol_type, Qunix))
@@ -6851,10 +6971,11 @@ decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
   EMACS_INT chars = to - from;
   EMACS_INT bytes = to_byte - from_byte;
   Lisp_Object attrs;
-  Lisp_Object buffer;
   int saved_pt = -1, saved_pt_byte;
+  int need_marker_adjustment = 0;
+  Lisp_Object old_deactivate_mark;
 
-  buffer = Fcurrent_buffer ();
+  old_deactivate_mark = Vdeactivate_mark;
 
   if (NILP (dst_object))
     {
@@ -6879,8 +7000,17 @@ decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
        move_gap_both (from, from_byte);
       if (EQ (src_object, dst_object))
        {
+         struct Lisp_Marker *tail;
+
+         for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
+           {
+             tail->need_adjustment
+               = tail->charpos == (tail->insertion_type ? from : to);
+             need_marker_adjustment |= tail->need_adjustment;
+           }
          saved_pt = PT, saved_pt_byte = PT_BYTE;
          TEMP_SET_PT_BOTH (from, from_byte);
+         current_buffer->text->inhibit_shrinking = 1;
          del_range_both (from, from_byte, to, to_byte, 1);
          coding->src_pos = -chars;
          coding->src_pos_byte = -bytes;
@@ -6900,10 +7030,10 @@ decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
       || (! NILP (CODING_ATTR_POST_READ (attrs))
          && NILP (dst_object)))
     {
-      coding->dst_object = code_conversion_save (1, 1);
+      coding->dst_multibyte = !CODING_FOR_UNIBYTE (coding);
+      coding->dst_object = code_conversion_save (1, coding->dst_multibyte);
       coding->dst_pos = BEG;
       coding->dst_pos_byte = BEG_BYTE;
-      coding->dst_multibyte = 1;
     }
   else if (BUFFERP (dst_object))
     {
@@ -6918,7 +7048,10 @@ decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
     {
       code_conversion_save (0, 0);
       coding->dst_object = Qnil;
-      coding->dst_multibyte = 1;
+      /* Most callers presume this will return a multibyte result, and they
+        won't use `binary' or `raw-text' anyway, so let's not worry about
+        CODING_FOR_UNIBYTE.  */
+      coding->dst_multibyte = Qt;
     }
 
   decode_coding (coding);
@@ -6928,12 +7061,13 @@ decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
 
   if (! NILP (CODING_ATTR_POST_READ (attrs)))
     {
-      struct gcpro gcpro1, gcpro2;
+      struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
       EMACS_INT prev_Z = Z, prev_Z_BYTE = Z_BYTE;
       Lisp_Object val;
 
       TEMP_SET_PT_BOTH (coding->dst_pos, coding->dst_pos_byte);
-      GCPRO2 (coding->src_object, coding->dst_object);
+      GCPRO5 (coding->src_object, coding->dst_object, src_object, dst_object,
+             old_deactivate_mark);
       val = safe_call1 (CODING_ATTR_POST_READ (attrs),
                        make_number (coding->produced_char));
       UNGCPRO;
@@ -6951,8 +7085,7 @@ decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
       set_buffer_internal (XBUFFER (coding->dst_object));
       if (dst_bytes < coding->produced)
        {
-         destination
-           = (unsigned char *) xrealloc (destination, coding->produced);
+         destination = xrealloc (destination, coding->produced);
          if (! destination)
            {
              record_conversion_result (coding,
@@ -6974,6 +7107,7 @@ decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
         As we have moved PT while replacing the original buffer
         contents, we must recover it now.  */
       set_buffer_internal (XBUFFER (src_object));
+      current_buffer->text->inhibit_shrinking = 0;
       if (saved_pt < from)
        TEMP_SET_PT_BOTH (saved_pt, saved_pt_byte);
       else if (saved_pt < from + chars)
@@ -6984,8 +7118,32 @@ decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
       else
        TEMP_SET_PT_BOTH (saved_pt + (coding->produced - bytes),
                          saved_pt_byte + (coding->produced - bytes));
+
+      if (need_marker_adjustment)
+       {
+         struct Lisp_Marker *tail;
+
+         for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
+           if (tail->need_adjustment)
+             {
+               tail->need_adjustment = 0;
+               if (tail->insertion_type)
+                 {
+                   tail->bytepos = from_byte;
+                   tail->charpos = from;
+                 }
+               else
+                 {
+                   tail->bytepos = from_byte + coding->produced;
+                   tail->charpos
+                     = (NILP (current_buffer->enable_multibyte_characters)
+                        ? tail->bytepos : from + coding->produced_char);
+                 }
+             }
+       }
     }
 
+  Vdeactivate_mark = old_deactivate_mark;
   unbind_to (count, coding->dst_object);
 }
 
@@ -7002,11 +7160,12 @@ encode_coding_object (coding, src_object, from, from_byte, to, to_byte,
   EMACS_INT chars = to - from;
   EMACS_INT bytes = to_byte - from_byte;
   Lisp_Object attrs;
-  Lisp_Object buffer;
   int saved_pt = -1, saved_pt_byte;
+  int need_marker_adjustment = 0;
   int kill_src_buffer = 0;
+  Lisp_Object old_deactivate_mark;
 
-  buffer = Fcurrent_buffer ();
+  old_deactivate_mark = Vdeactivate_mark;
 
   coding->src_object = src_object;
   coding->src_chars = chars;
@@ -7015,6 +7174,18 @@ encode_coding_object (coding, src_object, from, from_byte, to, to_byte,
 
   attrs = CODING_ID_ATTRS (coding->id);
 
+  if (EQ (src_object, dst_object))
+    {
+      struct Lisp_Marker *tail;
+
+      for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
+       {
+         tail->need_adjustment
+           = tail->charpos == (tail->insertion_type ? from : to);
+         need_marker_adjustment |= tail->need_adjustment;
+       }
+    }
+
   if (! NILP (CODING_ATTR_PRE_WRITE (attrs)))
     {
       coding->src_object = code_conversion_save (1, coding->src_multibyte);
@@ -7036,11 +7207,15 @@ encode_coding_object (coding, src_object, from, from_byte, to, to_byte,
 
       {
        Lisp_Object args[3];
+       struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
 
+       GCPRO5 (coding->src_object, coding->dst_object, src_object, dst_object,
+               old_deactivate_mark);
        args[0] = CODING_ATTR_PRE_WRITE (attrs);
        args[1] = make_number (BEG);
        args[2] = make_number (Z);
        safe_call (3, args);
+       UNGCPRO;
       }
       if (XBUFFER (coding->src_object) != current_buffer)
        kill_src_buffer = 1;
@@ -7144,10 +7319,35 @@ encode_coding_object (coding, src_object, from, from_byte, to, to_byte,
       else
        TEMP_SET_PT_BOTH (saved_pt + (coding->produced - bytes),
                          saved_pt_byte + (coding->produced - bytes));
+
+      if (need_marker_adjustment)
+       {
+         struct Lisp_Marker *tail;
+
+         for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
+           if (tail->need_adjustment)
+             {
+               tail->need_adjustment = 0;
+               if (tail->insertion_type)
+                 {
+                   tail->bytepos = from_byte;
+                   tail->charpos = from;
+                 }
+               else
+                 {
+                   tail->bytepos = from_byte + coding->produced;
+                   tail->charpos
+                     = (NILP (current_buffer->enable_multibyte_characters)
+                        ? tail->bytepos : from + coding->produced_char);
+                 }
+             }
+       }
     }
 
   if (kill_src_buffer)
     Fkill_buffer (coding->src_object);
+
+  Vdeactivate_mark = old_deactivate_mark;
   unbind_to (count, Qnil);
 }
 
@@ -7198,16 +7398,22 @@ DEFUN ("read-non-nil-coding-system", Fread_non_nil_coding_system,
 
 DEFUN ("read-coding-system", Fread_coding_system, Sread_coding_system, 1, 2, 0,
        doc: /* Read a coding system from the minibuffer, prompting with string PROMPT.
-If the user enters null input, return second argument DEFAULT-CODING-SYSTEM.  */)
+If the user enters null input, return second argument DEFAULT-CODING-SYSTEM.
+Ignores case when completing coding systems (all Emacs coding systems
+are lower-case).  */)
      (prompt, default_coding_system)
      Lisp_Object prompt, default_coding_system;
 {
   Lisp_Object val;
+  int count = SPECPDL_INDEX ();
+
   if (SYMBOLP (default_coding_system))
-    XSETSTRING (default_coding_system, XPNTR (SYMBOL_NAME (default_coding_system)));
+    default_coding_system = SYMBOL_NAME (default_coding_system);
+  specbind (Qcompletion_ignore_case, Qt);
   val = Fcompleting_read (prompt, Vcoding_system_alist, Qnil,
                          Qt, Qnil, Qcoding_system_history,
                          default_coding_system, Qnil);
+  unbind_to (count, Qnil);
   return (SCHARS (val) == 0 ? Qnil : Fintern (val, Qnil));
 }
 
@@ -7254,7 +7460,8 @@ Lisp_Object
 detect_coding_system (src, src_chars, src_bytes, highest, multibytep,
                      coding_system)
      const unsigned char *src;
-     int src_chars, src_bytes, highest;
+     EMACS_INT src_chars, src_bytes;
+     int highest;
      int multibytep;
      Lisp_Object coding_system;
 {
@@ -8005,7 +8212,7 @@ When called from a program, takes four arguments:
 START and END are buffer positions.
 
 Optional 4th arguments DESTINATION specifies where the decoded text goes.
-If nil, the region between START and END is replace by the decoded text.
+If nil, the region between START and END is replaced by the decoded text.
 If buffer, the decoded text is inserted in the buffer.
 If t, the decoded text is returned.
 
@@ -8286,23 +8493,22 @@ Return the corresponding character code in Big5.  */)
 }
 
 \f
-DEFUN ("set-terminal-coding-system-internal",
-       Fset_terminal_coding_system_internal,
-       Sset_terminal_coding_system_internal, 1, 1, 0,
+DEFUN ("set-terminal-coding-system-internal", Fset_terminal_coding_system_internal,
+       Sset_terminal_coding_system_internal, 1, 2, 0,
        doc: /* Internal use only.  */)
-     (coding_system)
+     (coding_system, terminal)
      Lisp_Object coding_system;
+     Lisp_Object terminal;
 {
+  struct coding_system *terminal_coding = TERMINAL_TERMINAL_CODING (get_terminal (terminal, 1));
   CHECK_SYMBOL (coding_system);
-  setup_coding_system (Fcheck_coding_system (coding_system),
-                       &terminal_coding);
-
+  setup_coding_system (Fcheck_coding_system (coding_system), terminal_coding);
   /* We had better not send unsafe characters to terminal.  */
-  terminal_coding.mode |= CODING_MODE_SAFE_ENCODING;
+  terminal_coding->mode |= CODING_MODE_SAFE_ENCODING;
   /* Characer composition should be disabled.  */
-  terminal_coding.common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK;
-  terminal_coding.src_multibyte = 1;
-  terminal_coding.dst_multibyte = 0;
+  terminal_coding->common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK;
+  terminal_coding->src_multibyte = 1;
+  terminal_coding->dst_multibyte = 0;
   return Qnil;
 }
 
@@ -8323,39 +8529,47 @@ DEFUN ("set-safe-terminal-coding-system-internal",
   return Qnil;
 }
 
-DEFUN ("terminal-coding-system",
-       Fterminal_coding_system, Sterminal_coding_system, 0, 0, 0,
-       doc: /* Return coding system specified for terminal output.  */)
-     ()
+DEFUN ("terminal-coding-system", Fterminal_coding_system,
+       Sterminal_coding_system, 0, 1, 0,
+       doc: /* Return coding system specified for terminal output on the given terminal.
+TERMINAL may be a terminal id, a frame, or nil for the selected
+frame's terminal device.  */)
+     (terminal)
+     Lisp_Object terminal;
 {
-  Lisp_Object coding_system;
+  struct coding_system *terminal_coding
+    = TERMINAL_TERMINAL_CODING (get_terminal (terminal, 1));
+  Lisp_Object coding_system = CODING_ID_NAME (terminal_coding->id);
 
-  coding_system = CODING_ID_NAME (terminal_coding.id);
   /* For backward compatibility, return nil if it is `undecided'. */
   return (! EQ (coding_system, Qundecided) ? coding_system : Qnil);
 }
 
-DEFUN ("set-keyboard-coding-system-internal",
-       Fset_keyboard_coding_system_internal,
-       Sset_keyboard_coding_system_internal, 1, 1, 0,
+DEFUN ("set-keyboard-coding-system-internal", Fset_keyboard_coding_system_internal,
+       Sset_keyboard_coding_system_internal, 1, 2, 0,
        doc: /* Internal use only.  */)
-     (coding_system)
+     (coding_system, terminal)
      Lisp_Object coding_system;
+     Lisp_Object terminal;
 {
+  struct terminal *t = get_terminal (terminal, 1);
   CHECK_SYMBOL (coding_system);
   setup_coding_system (Fcheck_coding_system (coding_system),
-                      &keyboard_coding);
+                      TERMINAL_KEYBOARD_CODING (t));
   /* Characer composition should be disabled.  */
-  keyboard_coding.common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK;
+  TERMINAL_KEYBOARD_CODING (t)->common_flags
+    &= ~CODING_ANNOTATE_COMPOSITION_MASK;
   return Qnil;
 }
 
 DEFUN ("keyboard-coding-system",
-       Fkeyboard_coding_system, Skeyboard_coding_system, 0, 0, 0,
+       Fkeyboard_coding_system, Skeyboard_coding_system, 0, 1, 0,
        doc: /* Return coding system specified for decoding keyboard input.  */)
-     ()
+     (terminal)
+     Lisp_Object terminal;
 {
-  return CODING_ID_NAME (keyboard_coding.id);
+  return CODING_ID_NAME (TERMINAL_KEYBOARD_CODING
+                        (get_terminal (terminal, 1))->id);
 }
 
 \f
@@ -8640,11 +8854,11 @@ usage: (define-coding-system-internal ...)  */)
   else
     {
       charset_list = Fcopy_sequence (charset_list);
-      for (tail = charset_list; !NILP (tail); tail = Fcdr (tail))
+      for (tail = charset_list; CONSP (tail); tail = XCDR (tail))
        {
          struct charset *charset;
 
-         val = Fcar (tail);
+         val = XCAR (tail);
          CHECK_CHARSET_GET_CHARSET (val, charset);
          if (EQ (coding_type, Qiso_2022)
              ? CHARSET_ISO_FINAL (charset) < 0
@@ -9731,7 +9945,9 @@ Function to call to select safe coding system for encoding a text.
 
 If set, this function is called to force a user to select a proper
 coding system which can encode the text in the case that a default
-coding system used in each operation can't encode the text.
+coding system used in each operation can't encode the text.  The
+function should take care that the buffer is not modified while
+the coding system is being selected.
 
 The default value is `select-safe-coding-system' (which see).  */);
   Vselect_safe_coding_system_function = Qnil;
@@ -9824,8 +10040,6 @@ character.");
     Fdefine_coding_system_internal (coding_arg_max, args);
   }
 
-  setup_coding_system (Qno_conversion, &keyboard_coding);
-  setup_coding_system (Qundecided, &terminal_coding);
   setup_coding_system (Qno_conversion, &safe_terminal_coding);
 
   {