]> code.delx.au - gnu-emacs/blobdiff - src/coding.c
*** empty log message ***
[gnu-emacs] / src / coding.c
index b06bf79a4bf9a44938ab63f486a672b507b0cb60..c3804630d729eb371242827e7fe2e1acdc7d5a20 100644 (file)
@@ -1,7 +1,10 @@
-/* Coding system handler (conversion, detection, and etc).
-   Copyright (C) 1995,97,1998,2002,2003  Electrotechnical Laboratory, JAPAN.
-   Licensed to the Free Software Foundation.
-   Copyright (C) 2001,2002,2003  Free Software Foundation, Inc.
+/* Coding system handler (conversion, detection, etc).
+   Copyright (C) 1995, 1997, 1998 Electrotechnical Laboratory, JAPAN.
+     Licensed to the Free Software Foundation.
+   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 2003
+     National Institute of Advanced Industrial Science and Technology (AIST)
+     Registration Number H13PRO009
 
 This file is part of GNU Emacs.
 
@@ -24,374 +27,309 @@ Boston, MA 02111-1307, USA.  */
 
   0. General comments
   1. Preamble
-  2. Emacs' internal format (emacs-mule) handlers
-  3. ISO2022 handlers
-  4. Shift-JIS and BIG5 handlers
-  5. CCL handlers
-  6. End-of-line handlers
-  7. C library functions
-  8. Emacs Lisp library functions
-  9. Post-amble
+  2. Emacs' internal format (emacs-utf-8) handlers
+  3. UTF-8 handlers
+  4. UTF-16 handlers
+  5. Charset-base coding systems handlers
+  6. emacs-mule (old Emacs' internal format) handlers
+  7. ISO2022 handlers
+  8. Shift-JIS and BIG5 handlers
+  9. CCL handlers
+  10. C library functions
+  11. Emacs Lisp library functions
+  12. Postamble
 
 */
 
-/*** 0. General comments ***/
+/*** 0. General comments ***
 
 
-/*** GENERAL NOTE on CODING SYSTEMS ***
+CODING SYSTEM
 
-  A coding system is an encoding mechanism for one or more character
-  sets.  Here's a list of coding systems which Emacs can handle.  When
-  we say "decode", it means converting some other coding system to
-  Emacs' internal format (emacs-mule), and when we say "encode",
-  it means converting the coding system emacs-mule to some other
+  A coding system is an object for an encoding mechanism that contains
+  information about how to convert byte sequences to character
+  sequences and vice versa.  When we say "decode", it means converting
+  a byte sequence of a specific coding system into a character
+  sequence that is represented by Emacs' internal coding system
+  `emacs-utf-8', and when we say "encode", it means converting a
+  character sequence of emacs-utf-8 to a byte sequence of a specific
   coding system.
 
-  0. Emacs' internal format (emacs-mule)
+  In Emacs Lisp, a coding system is represented by a Lisp symbol.  In
+  C level, a coding system is represented by a vector of attributes
+  stored in the hash table Vcharset_hash_table.  The conversion from
+  coding system symbol to attributes vector is done by looking up
+  Vcharset_hash_table by the symbol.
 
-  Emacs itself holds a multi-lingual character in buffers and strings
-  in a special format.  Details are described in section 2.
+  Coding systems are classified into the following types depending on
+  the encoding mechanism.  Here's a brief description of the types.
 
-  1. ISO2022
+  o UTF-8
+
+  o UTF-16
+
+  o Charset-base coding system
+
+  A coding system defined by one or more (coded) character sets.
+  Decoding and encoding are done by a code converter defined for each
+  character set.
+
+  o Old Emacs internal format (emacs-mule)
+
+  The coding system adopted by old versions of Emacs (20 and 21).
+
+  o ISO2022-base coding system
 
   The most famous coding system for multiple character sets.  X's
-  Compound Text, various EUCs (Extended Unix Code), and coding
-  systems used in Internet communication such as ISO-2022-JP are
-  all variants of ISO2022.  Details are described in section 3.
+  Compound Text, various EUCs (Extended Unix Code), and coding systems
+  used in the Internet communication such as ISO-2022-JP are all
+  variants of ISO2022.
 
-  2. SJIS (or Shift-JIS or MS-Kanji-Code)
+  o SJIS (or Shift-JIS or MS-Kanji-Code)
 
   A coding system to encode character sets: ASCII, JISX0201, and
   JISX0208.  Widely used for PC's in Japan.  Details are described in
-  section 4.
+  section 8.
 
-  3. BIG5
+  o BIG5
 
-  A coding system to encode the character sets ASCII and Big5.  Widely
+  A coding system to encode character sets: ASCII and Big5.  Widely
   used for Chinese (mainly in Taiwan and Hong Kong).  Details are
-  described in section 4.  In this file, when we write "BIG5"
-  (all uppercase), we mean the coding system, and when we write
-  "Big5" (capitalized), we mean the character set.
+  described in section 8.  In this file, when we write "big5" (all
+  lowercase), we mean the coding system, and when we write "Big5"
+  (capitalized), we mean the character set.
 
-  4. Raw text
+  o CCL
 
-  A coding system for text containing random 8-bit code.  Emacs does
-  no code conversion on such text except for end-of-line format.
+  If a user wants to decode/encode text encoded in a coding system
+  not listed above, he can supply a decoder and an encoder for it in
+  CCL (Code Conversion Language) programs.  Emacs executes the CCL
+  program while decoding/encoding.
 
-  5. Other
+  o Raw-text
 
-  If a user wants to read/write text encoded in a coding system not
-  listed above, he can supply a decoder and an encoder for it as CCL
-  (Code Conversion Language) programs.  Emacs executes the CCL program
-  while reading/writing.
+  A coding system for text containing raw eight-bit data.  Emacs
+  treats each byte of source text as a character (except for
+  end-of-line conversion).
 
-  Emacs represents a coding system by a Lisp symbol that has a property
-  `coding-system'.  But, before actually using the coding system, the
-  information about it is set in a structure of type `struct
-  coding_system' for rapid processing.  See section 6 for more details.
+  o No-conversion
+
+  Like raw text, but don't do end-of-line conversion.
 
-*/
 
-/*** GENERAL NOTES on END-OF-LINE FORMAT ***
+END-OF-LINE FORMAT
 
-  How end-of-line of text is encoded depends on the operating system.
-  For instance, Unix's format is just one byte of `line-feed' code,
+  How text end-of-line is encoded depends on operating system.  For
+  instance, Unix's format is just one byte of LF (line-feed) code,
   whereas DOS's format is two-byte sequence of `carriage-return' and
   `line-feed' codes.  MacOS's format is usually one byte of
   `carriage-return'.
 
   Since text character encoding and end-of-line encoding are
-  independent, any coding system described above can have any
-  end-of-line format.  So Emacs has information about end-of-line
-  format in each coding-system.  See section 6 for more details.
+  independent, any coding system described above can take any format
+  of end-of-line (except for no-conversion).
+
+STRUCT CODING_SYSTEM
+
+  Before using a coding system for code conversion (i.e. decoding and
+  encoding), we setup a structure of type `struct coding_system'.
+  This structure keeps various information about a specific code
+  conversion (e.g. the location of source and destination data).
 
 */
 
+/* COMMON MACROS */
+
+
 /*** GENERAL NOTES on `detect_coding_XXX ()' functions ***
 
-  These functions check if a text between SRC and SRC_END is encoded
-  in the coding system category XXX.  Each returns an integer value in
-  which appropriate flag bits for the category XXX are set.  The flag
-  bits are defined in macros CODING_CATEGORY_MASK_XXX.  Below is the
-  template for these functions.  If MULTIBYTEP is nonzero, 8-bit codes
-  of the range 0x80..0x9F are in multibyte form.  */
+  These functions check if a byte sequence specified as a source in
+  CODING conforms to the format of XXX, and update the members of
+  DETECT_INFO.
+
+  Return 1 if the byte sequence conforms to XXX, otherwise return 0.
+
+  Below is the template of these functions.  */
+
 #if 0
-int
-detect_coding_emacs_mule (src, src_end, multibytep)
-     unsigned char *src, *src_end;
-     int multibytep;
+static int
+detect_coding_XXX (coding, detect_info)
+     struct coding_system *coding;
+     struct coding_detection_info *detect_info;
 {
-  ...
+  unsigned char *src = coding->source;
+  unsigned char *src_end = coding->source + coding->src_bytes;
+  int multibytep = coding->src_multibyte;
+  int consumed_chars = 0;
+  int found = 0;
+  ...;
+
+  while (1)
+    {
+      /* Get one byte from the source.  If the souce is exausted, jump
+        to no_more_source:.  */
+      ONE_MORE_BYTE (c);
+
+      if (! __C_conforms_to_XXX___ (c))
+       break;
+      if (! __C_strongly_suggests_XXX__ (c))
+       found = CATEGORY_MASK_XXX;
+    }
+  /* The byte sequence is invalid for XXX.  */
+  detect_info->rejected |= CATEGORY_MASK_XXX;
+  return 0;
+
+ no_more_source:
+  /* The source exausted successfully.  */
+  detect_info->found |= found;
+  return 1;
 }
 #endif
 
 /*** GENERAL NOTES on `decode_coding_XXX ()' functions ***
 
-  These functions decode SRC_BYTES length of unibyte text at SOURCE
-  encoded in CODING to Emacs' internal format.  The resulting
-  multibyte text goes to a place pointed to by DESTINATION, the length
-  of which should not exceed DST_BYTES.
+  These functions decode a byte sequence specified as a source by
+  CODING.  The resulting multibyte text goes to a place pointed to by
+  CODING->charbuf, the length of which should not exceed
+  CODING->charbuf_size;
 
-  These functions set the information about original and decoded texts
-  in the members `produced', `produced_char', `consumed', and
-  `consumed_char' of the structure *CODING.  They also set the member
-  `result' to one of CODING_FINISH_XXX indicating how the decoding
-  finished.
+  These functions set the information of original and decoded texts in
+  CODING->consumed, CODING->consumed_char, and CODING->charbuf_used.
+  They also set CODING->result to one of CODING_RESULT_XXX indicating
+  how the decoding is finished.
 
-  DST_BYTES zero means that the source area and destination area are
-  overlapped, which means that we can produce a decoded text until it
-  reaches the head of the not-yet-decoded source text.
+  Below is the template of these functions.  */
 
-  Below is a template for these functions.  */
 #if 0
 static void
-decode_coding_XXX (coding, source, destination, src_bytes, dst_bytes)
+decode_coding_XXXX (coding)
      struct coding_system *coding;
-     unsigned char *source, *destination;
-     int src_bytes, dst_bytes;
 {
-  ...
+  unsigned char *src = coding->source + coding->consumed;
+  unsigned char *src_end = coding->source + coding->src_bytes;
+  /* SRC_BASE remembers the start position in source in each loop.
+     The loop will be exited when there's not enough source code, or
+     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 multibytep = coding->src_multibyte;
+
+  while (1)
+    {
+      src_base = src;
+      if (charbuf < charbuf_end)
+       /* No more room to produce a decoded character.  */
+       break;
+      ONE_MORE_BYTE (c);
+      /* Decode it. */
+    }
+
+ no_more_source:
+  if (src_base < src_end
+      && coding->mode & CODING_MODE_LAST_BLOCK)
+    /* If the source ends by partial bytes to construct a character,
+       treat them as eight-bit raw data.  */
+    while (src_base < src_end && charbuf < charbuf_end)
+      *charbuf++ = *src_base++;
+  /* Remember how many bytes and characters we consumed.  If the
+     source is multibyte, the bytes and chars are not identical.  */
+  coding->consumed = coding->consumed_char = src_base - coding->source;
+  /* Remember how many characters we produced.  */
+  coding->charbuf_used = charbuf - coding->charbuf;
 }
 #endif
 
 /*** GENERAL NOTES on `encode_coding_XXX ()' functions ***
 
-  These functions encode SRC_BYTES length text at SOURCE from Emacs'
-  internal multibyte format to CODING.  The resulting unibyte text
+  These functions encode SRC_BYTES length text at SOURCE of Emacs'
+  internal multibyte format by CODING.  The resulting byte sequence
   goes to a place pointed to by DESTINATION, the length of which
   should not exceed DST_BYTES.
 
-  These functions set the information about original and encoded texts
-  in the members `produced', `produced_char', `consumed', and
-  `consumed_char' of the structure *CODING.  They also set the member
-  `result' to one of CODING_FINISH_XXX indicating how the encoding
-  finished.
+  These functions set the information of original and encoded texts in
+  the members produced, produced_char, consumed, and consumed_char of
+  the structure *CODING.  They also set the member result to one of
+  CODING_RESULT_XXX indicating how the encoding finished.
 
-  DST_BYTES zero means that the source area and destination area are
-  overlapped, which means that we can produce encoded text until it
-  reaches at the head of the not-yet-encoded source text.
+  DST_BYTES zero means that source area and destination area are
+  overlapped, which means that we can produce encoded text until it
+  reaches at the head of not-yet-encoded source text.
 
-  Below is a template for these functions.  */
+  Below is a template of these functions.  */
 #if 0
 static void
-encode_coding_XXX (coding, source, destination, src_bytes, dst_bytes)
+encode_coding_XXX (coding)
      struct coding_system *coding;
-     unsigned char *source, *destination;
-     int src_bytes, dst_bytes;
 {
-  ...
+  int multibytep = coding->dst_multibyte;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf->charbuf + coding->charbuf_used;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  unsigned char *adjusted_dst_end = dst_end - _MAX_BYTES_PRODUCED_IN_LOOP_;
+  int produced_chars = 0;
+
+  for (; charbuf < charbuf_end && dst < adjusted_dst_end; charbuf++)
+    {
+      int c = *charbuf;
+      /* Encode C into DST, and increment DST.  */
+    }
+ label_no_more_destination:
+  /* How many chars and bytes we produced.  */
+  coding->produced_char += produced_chars;
+  coding->produced = dst - coding->destination;
 }
 #endif
 
-/*** COMMONLY USED MACROS ***/
-
-/* The following two macros ONE_MORE_BYTE and TWO_MORE_BYTES safely
-   get one, two, and three bytes from the source text respectively.
-   If there are not enough bytes in the source, they jump to
-   `label_end_of_loop'.  The caller should set variables `coding',
-   `src' and `src_end' to appropriate pointer in advance.  These
-   macros are called from decoding routines `decode_coding_XXX', thus
-   it is assumed that the source text is unibyte.  */
-
-#define ONE_MORE_BYTE(c1)                                      \
-  do {                                                         \
-    if (src >= src_end)                                                \
-      {                                                                \
-       coding->result = CODING_FINISH_INSUFFICIENT_SRC;        \
-       goto label_end_of_loop;                                 \
-      }                                                                \
-    c1 = *src++;                                               \
-  } while (0)
-
-#define TWO_MORE_BYTES(c1, c2)                                 \
-  do {                                                         \
-    if (src + 1 >= src_end)                                    \
-      {                                                                \
-       coding->result = CODING_FINISH_INSUFFICIENT_SRC;        \
-       goto label_end_of_loop;                                 \
-      }                                                                \
-    c1 = *src++;                                               \
-    c2 = *src++;                                               \
-  } while (0)
-
-
-/* Like ONE_MORE_BYTE, but 8-bit bytes of data at SRC are in multibyte
-   form if MULTIBYTEP is nonzero.  */
-
-#define ONE_MORE_BYTE_CHECK_MULTIBYTE(c1, multibytep)          \
-  do {                                                         \
-    if (src >= src_end)                                                \
-      {                                                                \
-       coding->result = CODING_FINISH_INSUFFICIENT_SRC;        \
-       goto label_end_of_loop;                                 \
-      }                                                                \
-    c1 = *src++;                                               \
-    if (multibytep && c1 == LEADING_CODE_8_BIT_CONTROL)                \
-      c1 = *src++ - 0x20;                                      \
-  } while (0)
-
-/* Set C to the next character at the source text pointed by `src'.
-   If there are not enough characters in the source, jump to
-   `label_end_of_loop'.  The caller should set variables `coding'
-   `src', `src_end', and `translation_table' to appropriate pointers
-   in advance.  This macro is used in encoding routines
-   `encode_coding_XXX', thus it assumes that the source text is in
-   multibyte form except for 8-bit characters.  8-bit characters are
-   in multibyte form if coding->src_multibyte is nonzero, else they
-   are represented by a single byte.  */
-
-#define ONE_MORE_CHAR(c)                                       \
-  do {                                                         \
-    int len = src_end - src;                                   \
-    int bytes;                                                 \
-    if (len <= 0)                                              \
-      {                                                                \
-       coding->result = CODING_FINISH_INSUFFICIENT_SRC;        \
-       goto label_end_of_loop;                                 \
-      }                                                                \
-    if (coding->src_multibyte                                  \
-       || UNIBYTE_STR_AS_MULTIBYTE_P (src, len, bytes))        \
-      c = STRING_CHAR_AND_LENGTH (src, len, bytes);            \
-    else                                                       \
-      c = *src, bytes = 1;                                     \
-    if (!NILP (translation_table))                             \
-      c = translate_char (translation_table, c, -1, 0, 0);     \
-    src += bytes;                                              \
-  } while (0)
-
-
-/* Produce a multibyte form of character C to `dst'.  Jump to
-   `label_end_of_loop' if there's not enough space at `dst'.
-
-   If we are now in the middle of a composition sequence, the decoded
-   character may be ALTCHAR (for the current composition).  In that
-   case, the character goes to coding->cmp_data->data instead of
-   `dst'.
-
-   This macro is used in decoding routines.  */
-
-#define EMIT_CHAR(c)                                                   \
-  do {                                                                 \
-    if (! COMPOSING_P (coding)                                         \
-       || coding->composing == COMPOSITION_RELATIVE                    \
-       || coding->composing == COMPOSITION_WITH_RULE)                  \
-      {                                                                        \
-       int bytes = CHAR_BYTES (c);                                     \
-       if ((dst + bytes) > (dst_bytes ? dst_end : src))                \
-         {                                                             \
-           coding->result = CODING_FINISH_INSUFFICIENT_DST;            \
-           goto label_end_of_loop;                                     \
-         }                                                             \
-       dst += CHAR_STRING (c, dst);                                    \
-       coding->produced_char++;                                        \
-      }                                                                        \
-                                                                       \
-    if (COMPOSING_P (coding)                                           \
-       && coding->composing != COMPOSITION_RELATIVE)                   \
-      {                                                                        \
-       CODING_ADD_COMPOSITION_COMPONENT (coding, c);                   \
-       coding->composition_rule_follows                                \
-         = coding->composing != COMPOSITION_WITH_ALTCHARS;             \
-      }                                                                        \
-  } while (0)
-
-
-#define EMIT_ONE_BYTE(c)                                       \
-  do {                                                         \
-    if (dst >= (dst_bytes ? dst_end : src))                    \
-      {                                                                \
-       coding->result = CODING_FINISH_INSUFFICIENT_DST;        \
-       goto label_end_of_loop;                                 \
-      }                                                                \
-    *dst++ = c;                                                        \
-  } while (0)
-
-#define EMIT_TWO_BYTES(c1, c2)                                 \
-  do {                                                         \
-    if (dst + 2 > (dst_bytes ? dst_end : src))                 \
-      {                                                                \
-       coding->result = CODING_FINISH_INSUFFICIENT_DST;        \
-       goto label_end_of_loop;                                 \
-      }                                                                \
-    *dst++ = c1, *dst++ = c2;                                  \
-  } while (0)
-
-#define EMIT_BYTES(from, to)                                   \
-  do {                                                         \
-    if (dst + (to - from) > (dst_bytes ? dst_end : src))       \
-      {                                                                \
-       coding->result = CODING_FINISH_INSUFFICIENT_DST;        \
-       goto label_end_of_loop;                                 \
-      }                                                                \
-    while (from < to)                                          \
-      *dst++ = *from++;                                                \
-  } while (0)
-
 \f
 /*** 1. Preamble ***/
 
-#ifdef emacs
 #include <config.h>
-#endif
-
 #include <stdio.h>
 
-#ifdef emacs
-
 #include "lisp.h"
 #include "buffer.h"
+#include "character.h"
 #include "charset.h"
-#include "composite.h"
 #include "ccl.h"
+#include "composite.h"
 #include "coding.h"
 #include "window.h"
-#include "intervals.h"
-
-#else  /* not emacs */
 
-#include "mulelib.h"
+Lisp_Object Vcoding_system_hash_table;
 
-#endif /* not emacs */
-
-Lisp_Object Qcoding_system, Qeol_type;
+Lisp_Object Qcoding_system, Qcoding_aliases, Qeol_type;
+Lisp_Object Qunix, Qdos;
+extern Lisp_Object Qmac;       /* frame.c */
 Lisp_Object Qbuffer_file_coding_system;
 Lisp_Object Qpost_read_conversion, Qpre_write_conversion;
+Lisp_Object Qdefault_char;
 Lisp_Object Qno_conversion, Qundecided;
+Lisp_Object Qcharset, Qiso_2022, Qutf_8, Qutf_16, Qshift_jis, Qbig5;
+Lisp_Object Qbig, Qlittle;
 Lisp_Object Qcoding_system_history;
-Lisp_Object Qsafe_chars;
 Lisp_Object Qvalid_codes;
+Lisp_Object QCcategory;
 
 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 Vselect_safe_coding_system_function;
-
 int coding_system_require_warning;
 
+Lisp_Object Vselect_safe_coding_system_function;
+
 /* Mnemonic string for each format of end-of-line.  */
 Lisp_Object eol_mnemonic_unix, eol_mnemonic_dos, eol_mnemonic_mac;
 /* Mnemonic string to indicate format of end-of-line is not yet
    decided.  */
 Lisp_Object eol_mnemonic_undecided;
 
-/* Format of end-of-line decided by system.  This is CODING_EOL_LF on
-   Unix, CODING_EOL_CRLF on DOS/Windows, and CODING_EOL_CR on Mac.  */
-int system_eol_type;
-
 #ifdef emacs
 
-/* Information about which coding system is safe for which chars.
-   The value has the form (GENERIC-LIST . NON-GENERIC-ALIST).
-
-   GENERIC-LIST is a list of generic coding systems which can encode
-   any characters.
-
-   NON-GENERIC-ALIST is an alist of non generic coding systems vs the
-   corresponding char table that contains safe chars.  */
-Lisp_Object Vcoding_system_safe_chars;
-
 Lisp_Object Vcoding_system_list, Vcoding_system_alist;
 
 Lisp_Object Qcoding_system_p, Qcoding_system_error;
@@ -399,8 +337,7 @@ Lisp_Object Qcoding_system_p, Qcoding_system_error;
 /* Coding system emacs-mule and raw-text are for converting only
    end-of-line format.  */
 Lisp_Object Qemacs_mule, Qraw_text;
-
-Lisp_Object Qutf_8;
+Lisp_Object Qutf_8_emacs;
 
 /* Coding-systems are handed between Emacs Lisp programs and C internal
    routines by the following three variables.  */
@@ -434,9 +371,6 @@ struct coding_system safe_terminal_coding;
 /* Coding system of what is sent from terminal keyboard.  */
 struct coding_system keyboard_coding;
 
-/* Default coding system to be used to write a file.  */
-struct coding_system default_buffer_file_coding;
-
 Lisp_Object Vfile_coding_system_alist;
 Lisp_Object Vprocess_coding_system_alist;
 Lisp_Object Vnetwork_coding_system_alist;
@@ -445,42 +379,6 @@ Lisp_Object Vlocale_coding_system;
 
 #endif /* emacs */
 
-Lisp_Object Qcoding_category, Qcoding_category_index;
-
-/* List of symbols `coding-category-xxx' ordered by priority.  */
-Lisp_Object Vcoding_category_list;
-
-/* Table of coding categories (Lisp symbols).  */
-Lisp_Object Vcoding_category_table;
-
-/* Table of names of symbol for each coding-category.  */
-char *coding_category_name[CODING_CATEGORY_IDX_MAX] = {
-  "coding-category-emacs-mule",
-  "coding-category-sjis",
-  "coding-category-iso-7",
-  "coding-category-iso-7-tight",
-  "coding-category-iso-8-1",
-  "coding-category-iso-8-2",
-  "coding-category-iso-7-else",
-  "coding-category-iso-8-else",
-  "coding-category-ccl",
-  "coding-category-big5",
-  "coding-category-utf-8",
-  "coding-category-utf-16-be",
-  "coding-category-utf-16-le",
-  "coding-category-raw-text",
-  "coding-category-binary"
-};
-
-/* Table of pointers to coding systems corresponding to each coding
-   categories.  */
-struct coding_system *coding_system_table[CODING_CATEGORY_IDX_MAX];
-
-/* Table of coding category masks.  Nth element is a mask for a coding
-   category of which priority is Nth.  */
-static
-int coding_priorities[CODING_CATEGORY_IDX_MAX];
-
 /* Flag to tell if we look up translation table on character code
    conversion.  */
 Lisp_Object Venable_character_translation;
@@ -495,7 +393,7 @@ Lisp_Object Qtranslation_table_for_decode;
 Lisp_Object Qtranslation_table_for_encode;
 
 /* Alist of charsets vs revision number.  */
-Lisp_Object Vcharset_revision_alist;
+static Lisp_Object Vcharset_revision_table;
 
 /* Default coding systems used for process I/O.  */
 Lisp_Object Vdefault_process_coding_system;
@@ -509,675 +407,1752 @@ Lisp_Object Vtranslation_table_for_input;
    to avoid infinite recursive call.  */
 static int inhibit_pre_post_conversion;
 
-Lisp_Object Qchar_coding_system;
+/* Two special coding systems.  */
+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)                        \
+  (XINT (AREF (AREF (CODING_ID_ATTRS ((coding)->id),   \
+                    coding_attr_iso_initial),          \
+              reg)))
+
+
+#define CODING_ISO_REQUEST(coding, charset_id) \
+  ((charset_id <= (coding)->max_charset_id     \
+    ? (coding)->safe_charsets[charset_id]      \
+    : -1))
+
+
+#define CODING_ISO_FLAGS(coding)       \
+  ((coding)->spec.iso_2022.flags)
+#define CODING_ISO_DESIGNATION(coding, reg)    \
+  ((coding)->spec.iso_2022.current_designation[reg])
+#define CODING_ISO_INVOCATION(coding, plane)   \
+  ((coding)->spec.iso_2022.current_invocation[plane])
+#define CODING_ISO_SINGLE_SHIFTING(coding)     \
+  ((coding)->spec.iso_2022.single_shifting)
+#define CODING_ISO_BOL(coding) \
+  ((coding)->spec.iso_2022.bol)
+#define CODING_ISO_INVOKED_CHARSET(coding, plane)      \
+  CODING_ISO_DESIGNATION ((coding), CODING_ISO_INVOCATION ((coding), (plane)))
+
+/* Control characters of ISO2022.  */
+                       /* code */      /* function */
+#define ISO_CODE_LF    0x0A            /* line-feed */
+#define ISO_CODE_CR    0x0D            /* carriage-return */
+#define ISO_CODE_SO    0x0E            /* shift-out */
+#define ISO_CODE_SI    0x0F            /* shift-in */
+#define ISO_CODE_SS2_7 0x19            /* single-shift-2 for 7-bit code */
+#define ISO_CODE_ESC   0x1B            /* escape */
+#define ISO_CODE_SS2   0x8E            /* single-shift-2 */
+#define ISO_CODE_SS3   0x8F            /* single-shift-3 */
+#define ISO_CODE_CSI   0x9B            /* control-sequence-introducer */
+
+/* All code (1-byte) of ISO2022 is classified into one of the
+   followings.  */
+enum iso_code_class_type
+  {
+    ISO_control_0,             /* Control codes in the range
+                                  0x00..0x1F and 0x7F, except for the
+                                  following 5 codes.  */
+    ISO_carriage_return,       /* ISO_CODE_CR (0x0D) */
+    ISO_shift_out,             /* ISO_CODE_SO (0x0E) */
+    ISO_shift_in,              /* ISO_CODE_SI (0x0F) */
+    ISO_single_shift_2_7,      /* ISO_CODE_SS2_7 (0x19) */
+    ISO_escape,                        /* ISO_CODE_SO (0x1B) */
+    ISO_control_1,             /* Control codes in the range
+                                  0x80..0x9F, except for the
+                                  following 3 codes.  */
+    ISO_single_shift_2,                /* ISO_CODE_SS2 (0x8E) */
+    ISO_single_shift_3,                /* ISO_CODE_SS3 (0x8F) */
+    ISO_control_sequence_introducer, /* ISO_CODE_CSI (0x9B) */
+    ISO_0x20_or_0x7F,          /* Codes of the values 0x20 or 0x7F.  */
+    ISO_graphic_plane_0,       /* Graphic codes in the range 0x21..0x7E.  */
+    ISO_0xA0_or_0xFF,          /* Codes of the values 0xA0 or 0xFF.  */
+    ISO_graphic_plane_1                /* Graphic codes in the range 0xA1..0xFE.  */
+  };
 
-/* Return `safe-chars' property of CODING_SYSTEM (symbol).  Don't check
-   its validity.  */
+/** The macros CODING_ISO_FLAG_XXX defines a flag bit of the
+    `iso-flags' attribute of an iso2022 coding system.  */
 
-Lisp_Object
-coding_safe_chars (coding_system)
-     Lisp_Object coding_system;
-{
-  Lisp_Object coding_spec, plist, safe_chars;
+/* If set, produce long-form designation sequence (e.g. ESC $ ( A)
+   instead of the correct short-form sequence (e.g. ESC $ A).  */
+#define CODING_ISO_FLAG_LONG_FORM      0x0001
 
-  coding_spec = Fget (coding_system, Qcoding_system);
-  plist = XVECTOR (coding_spec)->contents[3];
-  safe_chars = Fplist_get (XVECTOR (coding_spec)->contents[3], Qsafe_chars);
-  return (CHAR_TABLE_P (safe_chars) ? safe_chars : Qt);
-}
+/* If set, reset graphic planes and registers at end-of-line to the
+   initial state.  */
+#define CODING_ISO_FLAG_RESET_AT_EOL   0x0002
 
-#define CODING_SAFE_CHAR_P(safe_chars, c) \
-  (EQ (safe_chars, Qt) || !NILP (CHAR_TABLE_REF (safe_chars, c)))
+/* If set, reset graphic planes and registers before any control
+   characters to the initial state.  */
+#define CODING_ISO_FLAG_RESET_AT_CNTL  0x0004
 
-\f
-/*** 2. Emacs internal format (emacs-mule) handlers ***/
+/* If set, encode by 7-bit environment.  */
+#define CODING_ISO_FLAG_SEVEN_BITS     0x0008
 
-/* Emacs' internal format for representation of multiple character
-   sets is a kind of multi-byte encoding, i.e. characters are
-   represented by variable-length sequences of one-byte codes.
+/* If set, use locking-shift function.  */
+#define CODING_ISO_FLAG_LOCKING_SHIFT  0x0010
 
-   ASCII characters and control characters (e.g. `tab', `newline') are
-   represented by one-byte sequences which are their ASCII codes, in
-   the range 0x00 through 0x7F.
+/* If set, use single-shift function.  Overwrite
+   CODING_ISO_FLAG_LOCKING_SHIFT.  */
+#define CODING_ISO_FLAG_SINGLE_SHIFT   0x0020
 
-   8-bit characters of the range 0x80..0x9F are represented by
-   two-byte sequences of LEADING_CODE_8_BIT_CONTROL and (their 8-bit
-   code + 0x20).
+/* If set, use designation escape sequence.  */
+#define CODING_ISO_FLAG_DESIGNATION    0x0040
 
-   8-bit characters of the range 0xA0..0xFF are represented by
-   one-byte sequences which are their 8-bit code.
+/* If set, produce revision number sequence.  */
+#define CODING_ISO_FLAG_REVISION       0x0080
 
-   The other characters are represented by a sequence of `base
-   leading-code', optional `extended leading-code', and one or two
-   `position-code's.  The length of the sequence is determined by the
-   base leading-code.  Leading-code takes the range 0x81 through 0x9D,
-   whereas extended leading-code and position-code take the range 0xA0
-   through 0xFF.  See `charset.h' for more details about leading-code
-   and position-code.
+/* If set, produce ISO6429's direction specifying sequence.  */
+#define CODING_ISO_FLAG_DIRECTION      0x0100
 
-   --- CODE RANGE of Emacs' internal format ---
-   character set       range
-   -------------       -----
-   ascii               0x00..0x7F
-   eight-bit-control   LEADING_CODE_8_BIT_CONTROL + 0xA0..0xBF
-   eight-bit-graphic   0xA0..0xBF
-   ELSE                        0x81..0x9D + [0xA0..0xFF]+
-   ---------------------------------------------
+/* If set, assume designation states are reset at beginning of line on
+   output.  */
+#define CODING_ISO_FLAG_INIT_AT_BOL    0x0200
 
-   As this is the internal character representation, the format is
-   usually not used externally (i.e. in a file or in a data sent to a
-   process).  But, it is possible to have a text externally in this
-   format (i.e. by encoding by the coding system `emacs-mule').
+/* If set, designation sequence should be placed at beginning of line
+   on output.  */
+#define CODING_ISO_FLAG_DESIGNATE_AT_BOL 0x0400
 
-   In that case, a sequence of one-byte codes has a slightly different
-   form.
+/* If set, do not encode unsafe charactes on output.  */
+#define CODING_ISO_FLAG_SAFE           0x0800
 
-   Firstly, all characters in eight-bit-control are represented by
-   one-byte sequences which are their 8-bit code.
+/* If set, extra latin codes (128..159) are accepted as a valid code
+   on input.  */
+#define CODING_ISO_FLAG_LATIN_EXTRA    0x1000
 
-   Next, character composition data are represented by the byte
-   sequence of the form: 0x80 METHOD BYTES CHARS COMPONENT ...,
-   where,
-       METHOD is 0xF0 plus one of composition method (enum
-       composition_method),
+#define CODING_ISO_FLAG_COMPOSITION    0x2000
 
-       BYTES is 0xA0 plus the byte length of these composition data,
+#define CODING_ISO_FLAG_EUC_TW_SHIFT   0x4000
 
-       CHARS is 0xA0 plus the number of characters composed by these
-       data,
+#define CODING_ISO_FLAG_USE_ROMAN      0x8000
 
-       COMPONENTs are characters of multibyte form or composition
-       rules encoded by two-byte of ASCII codes.
+#define CODING_ISO_FLAG_USE_OLDJIS     0x10000
 
-   In addition, for backward compatibility, the following formats are
-   also recognized as composition data on decoding.
+#define CODING_ISO_FLAG_FULL_SUPPORT   0x100000
 
-   0x80 MSEQ ...
-   0x80 0xFF MSEQ RULE MSEQ RULE ... MSEQ
+/* A character to be produced on output if encoding of the original
+   character is prohibited by CODING_ISO_FLAG_SAFE.  */
+#define CODING_INHIBIT_CHARACTER_SUBSTITUTION  '?'
 
-   Here,
-       MSEQ is a multibyte form but in these special format:
-         ASCII: 0xA0 ASCII_CODE+0x80,
-         other: LEADING_CODE+0x20 FOLLOWING-BYTE ...,
-       RULE is a one byte code of the range 0xA0..0xF0 that
-       represents a composition rule.
-  */
 
-enum emacs_code_class_type emacs_code_class[256];
+/* UTF-16 section */
+#define CODING_UTF_16_BOM(coding)      \
+  ((coding)->spec.utf_16.bom)
 
-/* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
-   Check if a text is encoded in Emacs' internal format.  If it is,
-   return CODING_CATEGORY_MASK_EMACS_MULE, else return 0.  */
+#define CODING_UTF_16_ENDIAN(coding)   \
+  ((coding)->spec.utf_16.endian)
 
-static int
-detect_coding_emacs_mule (src, src_end, multibytep)
-      unsigned char *src, *src_end;
-      int multibytep;
-{
-  unsigned char c;
-  int composing = 0;
-  /* Dummy for ONE_MORE_BYTE.  */
-  struct coding_system dummy_coding;
-  struct coding_system *coding = &dummy_coding;
+#define CODING_UTF_16_SURROGATE(coding)        \
+  ((coding)->spec.utf_16.surrogate)
 
-  while (1)
-    {
-      ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
 
-      if (composing)
-       {
-         if (c < 0xA0)
-           composing = 0;
-         else if (c == 0xA0)
-           {
-             ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
-             c &= 0x7F;
-           }
-         else
-           c -= 0x20;
-       }
+/* CCL section */
+#define CODING_CCL_DECODER(coding)     \
+  AREF (CODING_ID_ATTRS ((coding)->id), coding_attr_ccl_decoder)
+#define CODING_CCL_ENCODER(coding)     \
+  AREF (CODING_ID_ATTRS ((coding)->id), coding_attr_ccl_encoder)
+#define CODING_CCL_VALIDS(coding)                                         \
+  (SDATA (AREF (CODING_ID_ATTRS ((coding)->id), coding_attr_ccl_valids)))
 
-      if (c < 0x20)
-       {
-         if (c == ISO_CODE_ESC || c == ISO_CODE_SI || c == ISO_CODE_SO)
-           return 0;
-       }
-      else if (c >= 0x80 && c < 0xA0)
-       {
-         if (c == 0x80)
-           /* Old leading code for a composite character.  */
-           composing = 1;
-         else
-           {
-             unsigned char *src_base = src - 1;
-             int bytes;
+/* Index for each coding category in `coding_categories' */
 
-             if (!UNIBYTE_STR_AS_MULTIBYTE_P (src_base, src_end - src_base,
-                                              bytes))
-               return 0;
-             src = src_base + bytes;
-           }
-       }
-    }
- label_end_of_loop:
-  return CODING_CATEGORY_MASK_EMACS_MULE;
-}
+enum coding_category
+  {
+    coding_category_iso_7,
+    coding_category_iso_7_tight,
+    coding_category_iso_8_1,
+    coding_category_iso_8_2,
+    coding_category_iso_7_else,
+    coding_category_iso_8_else,
+    coding_category_utf_8,
+    coding_category_utf_16_auto,
+    coding_category_utf_16_be,
+    coding_category_utf_16_le,
+    coding_category_utf_16_be_nosig,
+    coding_category_utf_16_le_nosig,
+    coding_category_charset,
+    coding_category_sjis,
+    coding_category_big5,
+    coding_category_ccl,
+    coding_category_emacs_mule,
+    /* All above are targets of code detection.  */
+    coding_category_raw_text,
+    coding_category_undecided,
+    coding_category_max
+  };
+
+/* Definitions of flag bits used in detect_coding_XXXX.  */
+#define CATEGORY_MASK_ISO_7            (1 << coding_category_iso_7)
+#define CATEGORY_MASK_ISO_7_TIGHT      (1 << coding_category_iso_7_tight)
+#define CATEGORY_MASK_ISO_8_1          (1 << coding_category_iso_8_1)
+#define CATEGORY_MASK_ISO_8_2          (1 << coding_category_iso_8_2)
+#define CATEGORY_MASK_ISO_7_ELSE       (1 << coding_category_iso_7_else)
+#define CATEGORY_MASK_ISO_8_ELSE       (1 << coding_category_iso_8_else)
+#define CATEGORY_MASK_UTF_8            (1 << coding_category_utf_8)
+#define CATEGORY_MASK_UTF_16_AUTO      (1 << coding_category_utf_16_auto)
+#define CATEGORY_MASK_UTF_16_BE                (1 << coding_category_utf_16_be)
+#define CATEGORY_MASK_UTF_16_LE                (1 << coding_category_utf_16_le)
+#define CATEGORY_MASK_UTF_16_BE_NOSIG  (1 << coding_category_utf_16_be_nosig)
+#define CATEGORY_MASK_UTF_16_LE_NOSIG  (1 << coding_category_utf_16_le_nosig)
+#define CATEGORY_MASK_CHARSET          (1 << coding_category_charset)
+#define CATEGORY_MASK_SJIS             (1 << coding_category_sjis)
+#define CATEGORY_MASK_BIG5             (1 << coding_category_big5)
+#define CATEGORY_MASK_CCL              (1 << coding_category_ccl)
+#define CATEGORY_MASK_EMACS_MULE       (1 << coding_category_emacs_mule)
+#define CATEGORY_MASK_RAW_TEXT         (1 << coding_category_raw_text)
+
+/* This value is returned if detect_coding_mask () find nothing other
+   than ASCII characters.  */
+#define CATEGORY_MASK_ANY              \
+  (CATEGORY_MASK_ISO_7                 \
+   | CATEGORY_MASK_ISO_7_TIGHT         \
+   | CATEGORY_MASK_ISO_8_1             \
+   | CATEGORY_MASK_ISO_8_2             \
+   | CATEGORY_MASK_ISO_7_ELSE          \
+   | CATEGORY_MASK_ISO_8_ELSE          \
+   | CATEGORY_MASK_UTF_8               \
+   | CATEGORY_MASK_UTF_16_BE           \
+   | CATEGORY_MASK_UTF_16_LE           \
+   | CATEGORY_MASK_UTF_16_BE_NOSIG     \
+   | CATEGORY_MASK_UTF_16_LE_NOSIG     \
+   | CATEGORY_MASK_CHARSET             \
+   | CATEGORY_MASK_SJIS                        \
+   | CATEGORY_MASK_BIG5                        \
+   | CATEGORY_MASK_CCL                 \
+   | CATEGORY_MASK_EMACS_MULE)
+
+
+#define CATEGORY_MASK_ISO_7BIT \
+  (CATEGORY_MASK_ISO_7 | CATEGORY_MASK_ISO_7_TIGHT)
+
+#define CATEGORY_MASK_ISO_8BIT \
+  (CATEGORY_MASK_ISO_8_1 | CATEGORY_MASK_ISO_8_2)
+
+#define CATEGORY_MASK_ISO_ELSE \
+  (CATEGORY_MASK_ISO_7_ELSE | CATEGORY_MASK_ISO_8_ELSE)
+
+#define CATEGORY_MASK_ISO_ESCAPE       \
+  (CATEGORY_MASK_ISO_7                 \
+   | CATEGORY_MASK_ISO_7_TIGHT         \
+   | CATEGORY_MASK_ISO_7_ELSE          \
+   | CATEGORY_MASK_ISO_8_ELSE)
+
+#define CATEGORY_MASK_ISO      \
+  (  CATEGORY_MASK_ISO_7BIT    \
+     | CATEGORY_MASK_ISO_8BIT  \
+     | CATEGORY_MASK_ISO_ELSE)
+
+#define CATEGORY_MASK_UTF_16           \
+  (CATEGORY_MASK_UTF_16_BE             \
+   | CATEGORY_MASK_UTF_16_LE           \
+   | CATEGORY_MASK_UTF_16_BE_NOSIG     \
+   | CATEGORY_MASK_UTF_16_LE_NOSIG)
+
+
+/* List of symbols `coding-category-xxx' ordered by priority.  This
+   variable is exposed to Emacs Lisp.  */
+static Lisp_Object Vcoding_category_list;
+
+/* Table of coding categories (Lisp symbols).  This variable is for
+   internal use oly.  */
+static Lisp_Object Vcoding_category_table;
+
+/* Table of coding-categories ordered by priority.  */
+static enum coding_category coding_priorities[coding_category_max];
+
+/* Nth element is a coding context for the coding system bound to the
+   Nth coding category.  */
+static struct coding_system coding_categories[coding_category_max];
+
+/*** Commonly used macros and functions ***/
+
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define CODING_GET_INFO(coding, attrs, eol_type, charset_list) \
+  do {                                                         \
+    attrs = CODING_ID_ATTRS (coding->id);                      \
+    eol_type = CODING_ID_EOL_TYPE (coding->id);                        \
+    if (VECTORP (eol_type))                                    \
+      eol_type = Qunix;                                                \
+    charset_list = CODING_ATTR_CHARSET_LIST (attrs);           \
+  } while (0)
 
 
-/* Record the starting position START and METHOD of one composition.  */
+/* 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
+*/
 
-#define CODING_ADD_COMPOSITION_START(coding, start, method)    \
+#define ONE_MORE_BYTE(c)                                       \
   do {                                                         \
-    struct composition_data *cmp_data = coding->cmp_data;      \
-    int *data = cmp_data->data + cmp_data->used;               \
-    coding->cmp_data_start = cmp_data->used;                   \
-    data[0] = -1;                                              \
-    data[1] = cmp_data->char_offset + start;                   \
-    data[3] = (int) method;                                    \
-    cmp_data->used += 4;                                       \
+    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++;                                          \
   } while (0)
 
-/* Record the ending position END of the current composition.  */
 
-#define CODING_ADD_COMPOSITION_END(coding, end)                        \
-  do {                                                         \
-    struct composition_data *cmp_data = coding->cmp_data;      \
-    int *data = cmp_data->data + coding->cmp_data_start;       \
-    data[0] = cmp_data->used - coding->cmp_data_start;         \
-    data[2] = cmp_data->char_offset + end;                     \
+#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++;                          \
   } while (0)
 
-/* Record one COMPONENT (alternate character or composition rule).  */
 
-#define CODING_ADD_COMPOSITION_COMPONENT(coding, component)            \
-  do {                                                                 \
-    coding->cmp_data->data[coding->cmp_data->used++] = component;      \
-    if (coding->cmp_data->used - coding->cmp_data_start                        \
-       == COMPOSITION_DATA_MAX_BUNCH_LENGTH)                           \
-      {                                                                        \
-       CODING_ADD_COMPOSITION_END (coding, coding->produced_char);     \
-       coding->composing = COMPOSITION_NO;                             \
-      }                                                                        \
+/* Store a byte C in the place pointed by DST and increment DST to the
+   next free point, and increment PRODUCED_CHARS.  The caller should
+   assure that C is 0..127, and declare and set the variable `dst'
+   appropriately in advance.
+*/
+
+
+#define EMIT_ONE_ASCII_BYTE(c) \
+  do {                         \
+    produced_chars++;          \
+    *dst++ = (c);              \
   } while (0)
 
 
-/* Get one byte from a data pointed by SRC and increment SRC.  If SRC
-   is not less than SRC_END, return -1 without incrementing Src.  */
+/* Like EMIT_ONE_ASCII_BYTE byt store two bytes; C1 and C2.  */
 
-#define SAFE_ONE_MORE_BYTE() (src >= src_end ? -1 : *src++)
+#define EMIT_TWO_ASCII_BYTES(c1, c2)   \
+  do {                                 \
+    produced_chars += 2;               \
+    *dst++ = (c1), *dst++ = (c2);      \
+  } while (0)
 
 
-/* Decode a character represented as a component of composition
-   sequence of Emacs 20 style at SRC.  Set C to that character, store
-   its multibyte form sequence at P, and set P to the end of that
-   sequence.  If no valid character is found, set C to -1.  */
+/* Store a byte C in the place pointed by DST and increment DST to the
+   next free point, and increment PRODUCED_CHARS.  If MULTIBYTEP is
+   nonzero, store in an appropriate multibyte from.  The caller should
+   declare and set the variables `dst' and `multibytep' appropriately
+   in advance.  */
+
+#define EMIT_ONE_BYTE(c)               \
+  do {                                 \
+    produced_chars++;                  \
+    if (multibytep)                    \
+      {                                        \
+       int ch = (c);                   \
+       if (ch >= 0x80)                 \
+         ch = BYTE8_TO_CHAR (ch);      \
+       CHAR_STRING_ADVANCE (ch, dst);  \
+      }                                        \
+    else                               \
+      *dst++ = (c);                    \
+  } while (0)
 
-#define DECODE_EMACS_MULE_COMPOSITION_CHAR(c, p)               \
-  do {                                                         \
-    int bytes;                                                 \
-                                                               \
-    c = SAFE_ONE_MORE_BYTE ();                                 \
-    if (c < 0)                                                 \
-      break;                                                   \
-    if (CHAR_HEAD_P (c))                                       \
-      c = -1;                                                  \
-    else if (c == 0xA0)                                                \
-      {                                                                \
-       c = SAFE_ONE_MORE_BYTE ();                              \
-       if (c < 0xA0)                                           \
-         c = -1;                                               \
-       else                                                    \
-         {                                                     \
-           c -= 0xA0;                                          \
-           *p++ = c;                                           \
-         }                                                     \
-      }                                                                \
-    else if (BASE_LEADING_CODE_P (c - 0x20))                   \
-      {                                                                \
-       unsigned char *p0 = p;                                  \
-                                                               \
-       c -= 0x20;                                              \
-       *p++ = c;                                               \
-       bytes = BYTES_BY_CHAR_HEAD (c);                         \
-       while (--bytes)                                         \
-         {                                                     \
-           c = SAFE_ONE_MORE_BYTE ();                          \
-           if (c < 0)                                          \
-             break;                                            \
-           *p++ = c;                                           \
-         }                                                     \
-       if (UNIBYTE_STR_AS_MULTIBYTE_P (p0, p - p0, bytes)      \
-           || (coding->flags /* We are recovering a file.  */  \
-               && p0[0] == LEADING_CODE_8_BIT_CONTROL          \
-               && ! CHAR_HEAD_P (p0[1])))                      \
-         c = STRING_CHAR (p0, bytes);                          \
-       else                                                    \
-         c = -1;                                               \
-      }                                                                \
-    else                                                       \
-      c = -1;                                                  \
+
+/* Like EMIT_ONE_BYTE, but emit two bytes; C1 and C2.  */
+
+#define EMIT_TWO_BYTES(c1, c2)         \
+  do {                                 \
+    produced_chars += 2;               \
+    if (multibytep)                    \
+      {                                        \
+       int ch;                         \
+                                       \
+       ch = (c1);                      \
+       if (ch >= 0x80)                 \
+         ch = BYTE8_TO_CHAR (ch);      \
+       CHAR_STRING_ADVANCE (ch, dst);  \
+       ch = (c2);                      \
+       if (ch >= 0x80)                 \
+         ch = BYTE8_TO_CHAR (ch);      \
+       CHAR_STRING_ADVANCE (ch, dst);  \
+      }                                        \
+    else                               \
+      {                                        \
+       *dst++ = (c1);                  \
+       *dst++ = (c2);                  \
+      }                                        \
   } while (0)
 
 
-/* Decode a composition rule represented as a component of composition
-   sequence of Emacs 20 style at SRC.  Set C to the rule.  If not
-   valid rule is found, set C to -1.  */
+#define EMIT_THREE_BYTES(c1, c2, c3)   \
+  do {                                 \
+    EMIT_ONE_BYTE (c1);                        \
+    EMIT_TWO_BYTES (c2, c3);           \
+  } while (0)
 
-#define DECODE_EMACS_MULE_COMPOSITION_RULE(c)          \
-  do {                                                 \
-    c = SAFE_ONE_MORE_BYTE ();                         \
-    c -= 0xA0;                                         \
-    if (c < 0 || c >= 81)                              \
-      c = -1;                                          \
-    else                                               \
-      {                                                        \
-       gref = c / 9, nref = c % 9;                     \
-       c = COMPOSITION_ENCODE_RULE (gref, nref);       \
-      }                                                        \
+
+#define EMIT_FOUR_BYTES(c1, c2, c3, c4)                \
+  do {                                         \
+    EMIT_TWO_BYTES (c1, c2);                   \
+    EMIT_TWO_BYTES (c3, c4);                   \
+  } while (0)
+
+
+#define CODING_DECODE_CHAR(coding, src, src_base, src_end, charset, code, c) \
+  do {                                                                      \
+    charset_map_loaded = 0;                                                 \
+    c = DECODE_CHAR (charset, code);                                        \
+    if (charset_map_loaded)                                                 \
+      {                                                                             \
+       const unsigned char *orig = coding->source;                          \
+       EMACS_INT offset;                                                    \
+                                                                            \
+       coding_set_source (coding);                                          \
+       offset = coding->source - orig;                                      \
+       src += offset;                                                       \
+       src_base += offset;                                                  \
+       src_end += offset;                                                   \
+      }                                                                             \
   } while (0)
 
 
-/* Decode composition sequence encoded by `emacs-mule' at the source
-   pointed by SRC.  SRC_END is the end of source.  Store information
-   of the composition in CODING->cmp_data.
+#define ASSURE_DESTINATION(bytes)                              \
+  do {                                                         \
+    if (dst + (bytes) >= dst_end)                              \
+      {                                                                \
+       int more_bytes = charbuf_end - charbuf + (bytes);       \
+                                                               \
+       dst = alloc_destination (coding, more_bytes, dst);      \
+       dst_end = coding->destination + coding->dst_bytes;      \
+      }                                                                \
+  } while (0)
 
-   For backward compatibility, decode also a composition sequence of
-   Emacs 20 style.  In that case, the composition sequence contains
-   characters that should be extracted into a buffer or string.  Store
-   those characters at *DESTINATION in multibyte form.
 
-   If we encounter an invalid byte sequence, return 0.
-   If we encounter an insufficient source or destination, or
-   insufficient space in CODING->cmp_data, return 1.
-   Otherwise, return consumed bytes in the source.
 
-*/
-static INLINE int
-decode_composition_emacs_mule (coding, src, src_end,
-                              destination, dst_end, dst_bytes)
+static void
+coding_set_source (coding)
      struct coding_system *coding;
-     unsigned char *src, *src_end, **destination, *dst_end;
-     int dst_bytes;
 {
-  unsigned char *dst = *destination;
-  int method, data_len, nchars;
-  unsigned char *src_base = src++;
-  /* Store components of composition.  */
-  int component[COMPOSITION_DATA_MAX_BUNCH_LENGTH];
-  int ncomponent;
-  /* Store multibyte form of characters to be composed.  This is for
-     Emacs 20 style composition sequence.  */
-  unsigned char buf[MAX_COMPOSITION_COMPONENTS * MAX_MULTIBYTE_LENGTH];
-  unsigned char *bufp = buf;
-  int c, i, gref, nref;
+  if (BUFFERP (coding->src_object))
+    {
+      struct buffer *buf = XBUFFER (coding->src_object);
 
-  if (coding->cmp_data->used + COMPOSITION_DATA_MAX_BUNCH_LENGTH
-      >= COMPOSITION_DATA_SIZE)
+      if (coding->src_pos < 0)
+       coding->source = BUF_GAP_END_ADDR (buf) + coding->src_pos_byte;
+      else
+       coding->source = BUF_BYTE_ADDRESS (buf, coding->src_pos_byte);
+    }
+  else if (STRINGP (coding->src_object))
     {
-      coding->result = CODING_FINISH_INSUFFICIENT_CMP;
-      return -1;
+      coding->source = SDATA (coding->src_object) + coding->src_pos_byte;
     }
+  else
+    /* Otherwise, the source is C string and is never relocated
+       automatically.  Thus we don't have to update anything.  */
+    ;
+}
 
-  ONE_MORE_BYTE (c);
-  if (c - 0xF0 >= COMPOSITION_RELATIVE
-          && c - 0xF0 <= COMPOSITION_WITH_RULE_ALTCHARS)
+static void
+coding_set_destination (coding)
+     struct coding_system *coding;
+{
+  if (BUFFERP (coding->dst_object))
     {
-      int with_rule;
-
-      method = c - 0xF0;
-      with_rule = (method == COMPOSITION_WITH_RULE
-                  || method == COMPOSITION_WITH_RULE_ALTCHARS);
-      ONE_MORE_BYTE (c);
-      data_len = c - 0xA0;
-      if (data_len < 4
-         || src_base + data_len > src_end)
-       return 0;
-      ONE_MORE_BYTE (c);
-      nchars = c - 0xA0;
-      if (c < 1)
-       return 0;
-      for (ncomponent = 0; src < src_base + data_len; ncomponent++)
+      if (coding->src_pos < 0)
        {
-         /* If it is longer than this, it can't be valid.  */
-         if (ncomponent >= COMPOSITION_DATA_MAX_BUNCH_LENGTH)
-           return 0;
-
-         if (ncomponent % 2 && with_rule)
-           {
-             ONE_MORE_BYTE (gref);
-             gref -= 32;
-             ONE_MORE_BYTE (nref);
-             nref -= 32;
-             c = COMPOSITION_ENCODE_RULE (gref, nref);
-           }
-         else
-           {
-             int bytes;
-             if (UNIBYTE_STR_AS_MULTIBYTE_P (src, src_end - src, bytes)
-                 || (coding->flags /* We are recovering a file.  */
-                     && src[0] == LEADING_CODE_8_BIT_CONTROL
-                     && ! CHAR_HEAD_P (src[1])))
-               c = STRING_CHAR (src, bytes);
-             else
-               c = *src, bytes = 1;
-             src += bytes;
-           }
-         component[ncomponent] = c;
+         coding->destination = BEG_ADDR + coding->dst_pos_byte - 1;
+         coding->dst_bytes = (GAP_END_ADDR
+                              - (coding->src_bytes - coding->consumed)
+                              - coding->destination);
        }
+      else
+       {
+         /* 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_bytes = (BUF_GAP_END_ADDR (XBUFFER (coding->dst_object))
+                              - coding->destination);
+       }
+    }
+  else
+    /* Otherwise, the destination is C string and is never relocated
+       automatically.  Thus we don't have to update anything.  */
+    ;
+}
+
+
+static void
+coding_alloc_by_realloc (coding, bytes)
+     struct coding_system *coding;
+     EMACS_INT bytes;
+{
+  coding->destination = (unsigned char *) xrealloc (coding->destination,
+                                                   coding->dst_bytes + bytes);
+  coding->dst_bytes += bytes;
+}
+
+static void
+coding_alloc_by_making_gap (coding, bytes)
+     struct coding_system *coding;
+     EMACS_INT bytes;
+{
+  if (BUFFERP (coding->dst_object)
+      && EQ (coding->src_object, coding->dst_object))
+    {
+      EMACS_INT add = coding->src_bytes - coding->consumed;
+
+      GAP_SIZE -= add; 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;
+    }
+  else
+    {
+      Lisp_Object this_buffer;
+
+      this_buffer = Fcurrent_buffer ();
+      set_buffer_internal (XBUFFER (coding->dst_object));
+      make_gap (bytes);
+      set_buffer_internal (XBUFFER (this_buffer));
     }
+}
+
+
+static unsigned char *
+alloc_destination (coding, nbytes, dst)
+     struct coding_system *coding;
+     int nbytes;
+     unsigned char *dst;
+{
+  EMACS_INT offset = dst - coding->destination;
+
+  if (BUFFERP (coding->dst_object))
+    coding_alloc_by_making_gap (coding, nbytes);
   else
+    coding_alloc_by_realloc (coding, nbytes);
+  coding->result = CODING_RESULT_SUCCESS;
+  coding_set_destination (coding);
+  dst = coding->destination + offset;
+  return dst;
+}
+
+/** Macros for annotations.  */
+
+/* Maximum length of annotation data (sum of annotations for
+   composition and charset).  */
+#define MAX_ANNOTATION_LENGTH (5 + (MAX_COMPOSITION_COMPONENTS * 2) - 1 + 5)
+
+/* An annotation data is stored in the array coding->charbuf in this
+   format:
+     [ -LENGTH ANNOTATION_MASK FROM TO ... ]
+   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).
+
+   The format of the following elements depend on ANNOTATION_MASK.
+
+   In the case of CODING_ANNOTATE_COMPOSITION_MASK, these elements
+   follows:
+     ... METHOD [ COMPOSITION-COMPONENTS ... ]
+   METHOD is one of enum composition_method.
+   Optionnal COMPOSITION-COMPONENTS are characters and composition
+   rules.
+
+   In the case of CODING_ANNOTATE_CHARSET_MASK, one element CHARSET-ID
+   follows.  */
+
+#define ADD_ANNOTATION_DATA(buf, len, mask, from, to)  \
+  do {                                                 \
+    *(buf)++ = -(len);                                 \
+    *(buf)++ = (mask);                                 \
+    *(buf)++ = (from);                                 \
+    *(buf)++ = (to);                                   \
+    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;                                                         \
+  } while (0)
+
+
+#define ADD_CHARSET_DATA(buf, from, to, id)                              \
+  do {                                                                   \
+    ADD_ANNOTATION_DATA (buf, 5, CODING_ANNOTATE_CHARSET_MASK, from, to); \
+    *buf++ = id;                                                         \
+  } while (0)
+
+\f
+/*** 2. Emacs' internal format (emacs-utf-8) ***/
+
+
+
+\f
+/*** 3. UTF-8 ***/
+
+/* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
+   Check if a text is encoded in UTF-8.  If it is, return 1, else
+   return 0.  */
+
+#define UTF_8_1_OCTET_P(c)         ((c) < 0x80)
+#define UTF_8_EXTRA_OCTET_P(c)     (((c) & 0xC0) == 0x80)
+#define UTF_8_2_OCTET_LEADING_P(c) (((c) & 0xE0) == 0xC0)
+#define UTF_8_3_OCTET_LEADING_P(c) (((c) & 0xF0) == 0xE0)
+#define UTF_8_4_OCTET_LEADING_P(c) (((c) & 0xF8) == 0xF0)
+#define UTF_8_5_OCTET_LEADING_P(c) (((c) & 0xFC) == 0xF8)
+
+static int
+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_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.  */
+  src += coding->head_ascii;
+
+  while (1)
     {
-      /* This may be an old Emacs 20 style format.  See the comment at
-        the section 2 of this file.  */
-      while (src < src_end && !CHAR_HEAD_P (*src)) src++;
-      if (src == src_end
-         && !(coding->mode & CODING_MODE_LAST_BLOCK))
-       goto label_end_of_loop;
+      int c, c1, c2, c3, c4;
 
-      src_end = src;
-      src = src_base + 1;
-      if (c < 0xC0)
+      incomplete = 0;
+      ONE_MORE_BYTE (c);
+      if (UTF_8_1_OCTET_P (c))
+       continue;
+      incomplete = 1;
+      ONE_MORE_BYTE (c1);
+      if (! UTF_8_EXTRA_OCTET_P (c1))
+       break;
+      if (UTF_8_2_OCTET_LEADING_P (c))
        {
-         method = COMPOSITION_RELATIVE;
-         for (ncomponent = 0; ncomponent < MAX_COMPOSITION_COMPONENTS;)
-           {
-             DECODE_EMACS_MULE_COMPOSITION_CHAR (c, bufp);
-             if (c < 0)
-               break;
-             component[ncomponent++] = c;
-           }
-         if (ncomponent < 2)
-           return 0;
-         nchars = ncomponent;
+         found = CATEGORY_MASK_UTF_8;
+         continue;
        }
-      else if (c == 0xFF)
+      ONE_MORE_BYTE (c2);
+      if (! UTF_8_EXTRA_OCTET_P (c2))
+       break;
+      if (UTF_8_3_OCTET_LEADING_P (c))
        {
-         method = COMPOSITION_WITH_RULE;
-         src++;
-         DECODE_EMACS_MULE_COMPOSITION_CHAR (c, bufp);
-         if (c < 0)
-           return 0;
-         component[0] = c;
-         for (ncomponent = 1;
-              ncomponent < MAX_COMPOSITION_COMPONENTS * 2 - 1;)
-           {
-             DECODE_EMACS_MULE_COMPOSITION_RULE (c);
-             if (c < 0)
-               break;
-             component[ncomponent++] = c;
-             DECODE_EMACS_MULE_COMPOSITION_CHAR (c, bufp);
-             if (c < 0)
-               break;
-             component[ncomponent++] = c;
-           }
-         if (ncomponent < 3)
-           return 0;
-         nchars = (ncomponent + 1) / 2;
+         found = CATEGORY_MASK_UTF_8;
+         continue;
        }
-      else
-       return 0;
+      ONE_MORE_BYTE (c3);
+      if (! UTF_8_EXTRA_OCTET_P (c3))
+       break;
+      if (UTF_8_4_OCTET_LEADING_P (c))
+       {
+         found = CATEGORY_MASK_UTF_8;
+         continue;
+       }
+      ONE_MORE_BYTE (c4);
+      if (! UTF_8_EXTRA_OCTET_P (c4))
+       break;
+      if (UTF_8_5_OCTET_LEADING_P (c))
+       {
+         found = CATEGORY_MASK_UTF_8;
+         continue;
+       }
+      break;
     }
+  detect_info->rejected |= CATEGORY_MASK_UTF_8;
+  return 0;
 
-  if (buf == bufp || dst + (bufp - buf) <= (dst_bytes ? dst_end : src))
+ no_more_source:
+  if (incomplete && coding->mode & CODING_MODE_LAST_BLOCK)
     {
-      CODING_ADD_COMPOSITION_START (coding, coding->produced_char, method);
-      for (i = 0; i < ncomponent; i++)
-       CODING_ADD_COMPOSITION_COMPONENT (coding, component[i]);
-      CODING_ADD_COMPOSITION_END (coding, coding->produced_char + nchars);
-      if (buf < bufp)
-       {
-         unsigned char *p = buf;
-         EMIT_BYTES (p, bufp);
-         *destination += bufp - buf;
-         coding->produced_char += nchars;
-       }
-      return (src - src_base);
+      detect_info->rejected |= CATEGORY_MASK_UTF_8;
+      return 0;
     }
- label_end_of_loop:
-  return -1;
+  detect_info->found |= found;
+  return 1;
 }
 
-/* See the above "GENERAL NOTES on `decode_coding_XXX ()' functions".  */
 
 static void
-decode_coding_emacs_mule (coding, source, destination, src_bytes, dst_bytes)
+decode_coding_utf_8 (coding)
      struct coding_system *coding;
-     unsigned char *source, *destination;
-     int src_bytes, dst_bytes;
 {
-  unsigned char *src = source;
-  unsigned char *src_end = source + src_bytes;
-  unsigned char *dst = destination;
-  unsigned char *dst_end = destination + dst_bytes;
-  /* SRC_BASE remembers the start position in source in each loop.
-     The loop will be exited when there's not enough source code, or
-     when there's not enough destination area to produce a
-     character.  */
-  unsigned char *src_base;
+  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 consumed_chars = 0, consumed_chars_base;
+  int multibytep = coding->src_multibyte;
+  Lisp_Object attr, eol_type, charset_list;
 
-  coding->produced_char = 0;
-  while ((src_base = src) < src_end)
+  CODING_GET_INFO (coding, attr, eol_type, charset_list);
+
+  while (1)
     {
-      unsigned char tmp[MAX_MULTIBYTE_LENGTH], *p;
-      int bytes;
+      int c, c1, c2, c3, c4, c5;
 
-      if (*src == '\r')
-       {
-         int c = *src++;
+      src_base = src;
+      consumed_chars_base = consumed_chars;
 
-         if (coding->eol_type == CODING_EOL_CR)
-           c = '\n';
-         else if (coding->eol_type == CODING_EOL_CRLF)
+      if (charbuf >= charbuf_end)
+       break;
+
+      ONE_MORE_BYTE (c1);
+      if (UTF_8_1_OCTET_P(c1))
+       {
+         c = c1;
+         if (c == '\r')
            {
-             ONE_MORE_BYTE (c);
-             if (c != '\n')
+             if (EQ (eol_type, Qdos))
                {
-                 src--;
-                 c = '\r';
+                 if (src == src_end)
+                   {
+                     coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+                     goto no_more_source;
+                   }
+                 if (*src == '\n')
+                   ONE_MORE_BYTE (c);
                }
+             else if (EQ (eol_type, Qmac))
+               c = '\n';
            }
-         *dst++ = c;
-         coding->produced_char++;
-         continue;
        }
-      else if (*src == '\n')
+      else
        {
-         if ((coding->eol_type == CODING_EOL_CR
-              || coding->eol_type == CODING_EOL_CRLF)
-             && coding->mode & CODING_MODE_INHIBIT_INCONSISTENT_EOL)
+         ONE_MORE_BYTE (c2);
+         if (! UTF_8_EXTRA_OCTET_P (c2))
+           goto invalid_code;
+         if (UTF_8_2_OCTET_LEADING_P (c1))
            {
-             coding->result = CODING_FINISH_INCONSISTENT_EOL;
-             goto label_end_of_loop;
+             c = ((c1 & 0x1F) << 6) | (c2 & 0x3F);
+             /* Reject overlong sequences here and below.  Encoders
+                producing them are incorrect, they can be misleading,
+                and they mess up read/write invariance.  */
+             if (c < 128)
+               goto invalid_code;
            }
-         *dst++ = *src++;
-         coding->produced_char++;
-         continue;
-       }
-      else if (*src == 0x80 && coding->cmp_data)
-       {
-         /* Start of composition data.  */
-         int consumed  = decode_composition_emacs_mule (coding, src, src_end,
-                                                        &dst, dst_end,
-                                                        dst_bytes);
-         if (consumed < 0)
-           goto label_end_of_loop;
-         else if (consumed > 0)
+         else
            {
-             src += consumed;
-             continue;
+             ONE_MORE_BYTE (c3);
+             if (! UTF_8_EXTRA_OCTET_P (c3))
+               goto invalid_code;
+             if (UTF_8_3_OCTET_LEADING_P (c1))
+               {
+                 c = (((c1 & 0xF) << 12)
+                      | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+                 if (c < 0x800
+                     || (c >= 0xd800 && c < 0xe000)) /* surrogates (invalid) */
+                   goto invalid_code;
+               }
+             else
+               {
+                 ONE_MORE_BYTE (c4);
+                 if (! UTF_8_EXTRA_OCTET_P (c4))
+                   goto invalid_code;
+                 if (UTF_8_4_OCTET_LEADING_P (c1))
+                   {
+                   c = (((c1 & 0x7) << 18) | ((c2 & 0x3F) << 12)
+                        | ((c3 & 0x3F) << 6) | (c4 & 0x3F));
+                   if (c < 0x10000)
+                     goto invalid_code;
+                   }
+                 else
+                   {
+                     ONE_MORE_BYTE (c5);
+                     if (! UTF_8_EXTRA_OCTET_P (c5))
+                       goto invalid_code;
+                     if (UTF_8_5_OCTET_LEADING_P (c1))
+                       {
+                         c = (((c1 & 0x3) << 24) | ((c2 & 0x3F) << 18)
+                              | ((c3 & 0x3F) << 12) | ((c4 & 0x3F) << 6)
+                              | (c5 & 0x3F));
+                         if ((c > MAX_CHAR) || (c < 0x200000))
+                           goto invalid_code;
+                       }
+                     else
+                       goto invalid_code;
+                   }
+               }
            }
-         bytes = CHAR_STRING (*src, tmp);
-         p = tmp;
-         src++;
-       }
-      else if (UNIBYTE_STR_AS_MULTIBYTE_P (src, src_end - src, bytes)
-              || (coding->flags /* We are recovering a file.  */
-                  && src[0] == LEADING_CODE_8_BIT_CONTROL
-                  && ! CHAR_HEAD_P (src[1])))
-       {
-         p = src;
-         src += bytes;
        }
-      else
+
+      *charbuf++ = c;
+      continue;
+
+    invalid_code:
+      src = src_base;
+      consumed_chars = consumed_chars_base;
+      ONE_MORE_BYTE (c);
+      *charbuf++ = ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
+      coding->errors++;
+    }
+
+ no_more_source:
+  coding->consumed_char += consumed_chars_base;
+  coding->consumed = src_base - coding->source;
+  coding->charbuf_used = charbuf - coding->charbuf;
+}
+
+
+static int
+encode_coding_utf_8 (coding)
+     struct coding_system *coding;
+{
+  int multibytep = coding->dst_multibyte;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf + coding->charbuf_used;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  int produced_chars = 0;
+  int c;
+
+  if (multibytep)
+    {
+      int safe_room = MAX_MULTIBYTE_LENGTH * 2;
+
+      while (charbuf < charbuf_end)
        {
-         bytes = CHAR_STRING (*src, tmp);
-         p = tmp;
-         src++;
+         unsigned char str[MAX_MULTIBYTE_LENGTH], *p, *pend = str;
+
+         ASSURE_DESTINATION (safe_room);
+         c = *charbuf++;
+         if (CHAR_BYTE8_P (c))
+           {
+             c = CHAR_TO_BYTE8 (c);
+             EMIT_ONE_BYTE (c);
+           }
+         else
+           {
+             CHAR_STRING_ADVANCE (c, pend);
+             for (p = str; p < pend; p++)
+               EMIT_ONE_BYTE (*p);
+           }
        }
-      if (dst + bytes >= (dst_bytes ? dst_end : src))
+    }
+  else
+    {
+      int safe_room = MAX_MULTIBYTE_LENGTH;
+
+      while (charbuf < charbuf_end)
        {
-         coding->result = CODING_FINISH_INSUFFICIENT_DST;
-         break;
+         ASSURE_DESTINATION (safe_room);
+         c = *charbuf++;
+         dst += CHAR_STRING (c, dst);
+         produced_chars++;
        }
-      while (bytes--) *dst++ = *p++;
-      coding->produced_char++;
     }
- label_end_of_loop:
-  coding->consumed = coding->consumed_char = src_base - source;
-  coding->produced = dst - destination;
+  coding->result = CODING_RESULT_SUCCESS;
+  coding->produced_char += produced_chars;
+  coding->produced = dst - coding->destination;
+  return 0;
 }
 
 
-/* Encode composition data stored at DATA into a special byte sequence
-   starting by 0x80.  Update CODING->cmp_data_start and maybe
-   CODING->cmp_data for the next call.  */
+/* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
+   Check if a text is encoded in one of UTF-16 based coding systems.
+   If it is, return 1, else return 0.  */
 
-#define ENCODE_COMPOSITION_EMACS_MULE(coding, data)                    \
-  do {                                                                 \
-    unsigned char buf[1024], *p0 = buf, *p;                            \
-    int len = data[0];                                                 \
-    int i;                                                             \
-                                                                       \
-    buf[0] = 0x80;                                                     \
-    buf[1] = 0xF0 + data[3];   /* METHOD */                            \
-    buf[3] = 0xA0 + (data[2] - data[1]); /* COMPOSED-CHARS */          \
-    p = buf + 4;                                                       \
-    if (data[3] == COMPOSITION_WITH_RULE                               \
-       || data[3] == COMPOSITION_WITH_RULE_ALTCHARS)                   \
-      {                                                                        \
-       p += CHAR_STRING (data[4], p);                                  \
-       for (i = 5; i < len; i += 2)                                    \
-         {                                                             \
-           int gref, nref;                                             \
-            COMPOSITION_DECODE_RULE (data[i], gref, nref);             \
-           *p++ = 0x20 + gref;                                         \
-           *p++ = 0x20 + nref;                                         \
-           p += CHAR_STRING (data[i + 1], p);                          \
-         }                                                             \
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-       for (i = 4; i < len; i++)                                       \
-         p += CHAR_STRING (data[i], p);                                \
-      }                                                                        \
-    buf[2] = 0xA0 + (p - buf); /* COMPONENTS-BYTES */                  \
-                                                                       \
-    if (dst + (p - buf) + 4 > (dst_bytes ? dst_end : src))             \
-      {                                                                        \
-       coding->result = CODING_FINISH_INSUFFICIENT_DST;                \
-       goto label_end_of_loop;                                         \
-      }                                                                        \
-    while (p0 < p)                                                     \
-      *dst++ = *p0++;                                                  \
-    coding->cmp_data_start += data[0];                                 \
-    if (coding->cmp_data_start == coding->cmp_data->used               \
-       && coding->cmp_data->next)                                      \
-      {                                                                        \
-       coding->cmp_data = coding->cmp_data->next;                      \
-       coding->cmp_data_start = 0;                                     \
-      }                                                                        \
-  } while (0)
+#define UTF_16_HIGH_SURROGATE_P(val) \
+  (((val) & 0xFC00) == 0xD800)
+
+#define UTF_16_LOW_SURROGATE_P(val) \
+  (((val) & 0xFC00) == 0xDC00)
 
+#define UTF_16_INVALID_P(val)  \
+  (((val) == 0xFFFE)           \
+   || ((val) == 0xFFFF)                \
+   || UTF_16_LOW_SURROGATE_P (val))
 
-static void encode_eol P_ ((struct coding_system *, const unsigned char *,
-                           unsigned char *, int, int));
 
-static void
-encode_coding_emacs_mule (coding, source, destination, src_bytes, dst_bytes)
+static int
+detect_coding_utf_16 (coding, detect_info)
      struct coding_system *coding;
-     unsigned char *source, *destination;
-     int src_bytes, dst_bytes;
+     struct coding_detection_info *detect_info;
 {
-  unsigned char *src = source;
-  unsigned char *src_end = source + src_bytes;
-  unsigned char *dst = destination;
-  unsigned char *dst_end = destination + dst_bytes;
-  unsigned char *src_base;
-  int c;
-  int char_offset;
-  int *data;
+  const unsigned char *src = coding->source, *src_base = src;
+  const unsigned char *src_end = coding->source + coding->src_bytes;
+  int multibytep = coding->src_multibyte;
+  int consumed_chars = 0;
+  int c1, c2;
 
-  Lisp_Object translation_table;
+  detect_info->checked |= CATEGORY_MASK_UTF_16;
 
-  translation_table = Qnil;
+  if (coding->mode & CODING_MODE_LAST_BLOCK
+      && (coding->src_bytes & 1))
+    {
+      detect_info->rejected |= CATEGORY_MASK_UTF_16;
+      return 0;
+    }
+  ONE_MORE_BYTE (c1);
+  ONE_MORE_BYTE (c2);
 
-  /* Optimization for the case that there's no composition.  */
-  if (!coding->cmp_data || coding->cmp_data->used == 0)
+  if ((c1 == 0xFF) && (c2 == 0xFE))
     {
-      encode_eol (coding, source, destination, src_bytes, dst_bytes);
-      return;
+      detect_info->found |= (CATEGORY_MASK_UTF_16_LE
+                            | CATEGORY_MASK_UTF_16_AUTO);
+      detect_info->rejected |= CATEGORY_MASK_UTF_16_BE;
     }
+  else if ((c1 == 0xFE) && (c2 == 0xFF))
+    {
+      detect_info->found |= (CATEGORY_MASK_UTF_16_BE
+                            | CATEGORY_MASK_UTF_16_AUTO);
+      detect_info->rejected |= CATEGORY_MASK_UTF_16_LE;
+    }
+ no_more_source:
+  return 1;
+}
 
-  char_offset = coding->cmp_data->char_offset;
-  data = coding->cmp_data->data + coding->cmp_data_start;
-  while (1)
+static void
+decode_coding_utf_16 (coding)
+     struct coding_system *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 consumed_chars = 0, consumed_chars_base;
+  int multibytep = coding->src_multibyte;
+  enum utf_16_bom_type bom = CODING_UTF_16_BOM (coding);
+  enum utf_16_endian_type endian = CODING_UTF_16_ENDIAN (coding);
+  int surrogate = CODING_UTF_16_SURROGATE (coding);
+  Lisp_Object attr, eol_type, charset_list;
+
+  CODING_GET_INFO (coding, attr, eol_type, charset_list);
+
+  if (bom == utf_16_with_bom)
     {
+      int c, c1, c2;
+
       src_base = src;
+      ONE_MORE_BYTE (c1);
+      ONE_MORE_BYTE (c2);
+      c = (c1 << 8) | c2;
 
-      /* If SRC starts a composition, encode the information about the
-        composition in advance.  */
-      if (coding->cmp_data_start < coding->cmp_data->used
-         && char_offset + coding->consumed_char == data[1])
+      if (endian == utf_16_big_endian
+         ? c != 0xFEFF : c != 0xFFFE)
        {
-         ENCODE_COMPOSITION_EMACS_MULE (coding, data);
-         char_offset = coding->cmp_data->char_offset;
-         data = coding->cmp_data->data + coding->cmp_data_start;
+         /* The first two bytes are not BOM.  Treat them as bytes
+            for a normal character.  */
+         src = src_base;
+         coding->errors++;
        }
+      CODING_UTF_16_BOM (coding) = utf_16_without_bom;
+    }
+  else if (bom == utf_16_detect_bom)
+    {
+      /* We have already tried to detect BOM and failed in
+        detect_coding.  */
+      CODING_UTF_16_BOM (coding) = utf_16_without_bom;
+    }
 
-      ONE_MORE_CHAR (c);
-      if (c == '\n' && (coding->eol_type == CODING_EOL_CRLF
-                       || coding->eol_type == CODING_EOL_CR))
-       {
-         if (coding->eol_type == CODING_EOL_CRLF)
-           EMIT_TWO_BYTES ('\r', c);
-         else
-           EMIT_ONE_BYTE ('\r');
-       }
-      else if (SINGLE_BYTE_CHAR_P (c))
+  while (1)
+    {
+      int c, c1, c2;
+
+      src_base = src;
+      consumed_chars_base = consumed_chars;
+
+      if (charbuf + 2 >= charbuf_end)
+       break;
+
+      ONE_MORE_BYTE (c1);
+      ONE_MORE_BYTE (c2);
+      c = (endian == utf_16_big_endian
+          ? ((c1 << 8) | c2) : ((c2 << 8) | c1));
+      if (surrogate)
        {
-         if (coding->flags && ! ASCII_BYTE_P (c))
+         if (! UTF_16_LOW_SURROGATE_P (c))
            {
-             /* As we are auto saving, retain the multibyte form for
-                8-bit chars.  */
-             unsigned char buf[MAX_MULTIBYTE_LENGTH];
-             int bytes = CHAR_STRING (c, buf);
-
-             if (bytes == 1)
-               EMIT_ONE_BYTE (buf[0]);
+             if (endian == utf_16_big_endian)
+               c1 = surrogate >> 8, c2 = surrogate & 0xFF;
+             else
+               c1 = surrogate & 0xFF, c2 = surrogate >> 8;
+             *charbuf++ = c1;
+             *charbuf++ = c2;
+             coding->errors++;
+             if (UTF_16_HIGH_SURROGATE_P (c))
+               CODING_UTF_16_SURROGATE (coding) = surrogate = c;
              else
-               EMIT_TWO_BYTES (buf[0], buf[1]);
+               *charbuf++ = c;
            }
          else
-           EMIT_ONE_BYTE (c);
+           {
+             c = ((surrogate - 0xD800) << 10) | (c - 0xDC00);
+             CODING_UTF_16_SURROGATE (coding) = surrogate = 0;
+             *charbuf++ = c;
+           }
        }
       else
-       EMIT_BYTES (src_base, src);
-      coding->consumed_char++;
+       {
+         if (UTF_16_HIGH_SURROGATE_P (c))
+           CODING_UTF_16_SURROGATE (coding) = surrogate = c;
+         else
+           *charbuf++ = c;
+       }
     }
- label_end_of_loop:
-  coding->consumed = src_base - source;
-  coding->produced = coding->produced_char = dst - destination;
-  return;
+
+ no_more_source:
+  coding->consumed_char += consumed_chars_base;
+  coding->consumed = src_base - coding->source;
+  coding->charbuf_used = charbuf - coding->charbuf;
 }
 
-\f
-/*** 3. ISO2022 handlers ***/
+static int
+encode_coding_utf_16 (coding)
+     struct coding_system *coding;
+{
+  int multibytep = coding->dst_multibyte;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf + coding->charbuf_used;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  int safe_room = 8;
+  enum utf_16_bom_type bom = CODING_UTF_16_BOM (coding);
+  int big_endian = CODING_UTF_16_ENDIAN (coding) == utf_16_big_endian;
+  int produced_chars = 0;
+  Lisp_Object attrs, eol_type, charset_list;
+  int c;
 
-/* The following note describes the coding system ISO2022 briefly.
-   Since the intention of this note is to help understand the
-   functions in this file, some parts are NOT ACCURATE or are OVERLY
-   SIMPLIFIED.  For thorough understanding, please refer to the
-   original document of ISO2022.  This is equivalent to the standard
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+
+  if (bom != utf_16_without_bom)
+    {
+      ASSURE_DESTINATION (safe_room);
+      if (big_endian)
+       EMIT_TWO_BYTES (0xFE, 0xFF);
+      else
+       EMIT_TWO_BYTES (0xFF, 0xFE);
+      CODING_UTF_16_BOM (coding) = utf_16_without_bom;
+    }
+
+  while (charbuf < charbuf_end)
+    {
+      ASSURE_DESTINATION (safe_room);
+      c = *charbuf++;
+      if (c >= MAX_UNICODE_CHAR)
+       c = coding->default_char;
+
+      if (c < 0x10000)
+       {
+         if (big_endian)
+           EMIT_TWO_BYTES (c >> 8, c & 0xFF);
+         else
+           EMIT_TWO_BYTES (c & 0xFF, c >> 8);
+       }
+      else
+       {
+         int c1, c2;
+
+         c -= 0x10000;
+         c1 = (c >> 10) + 0xD800;
+         c2 = (c & 0x3FF) + 0xDC00;
+         if (big_endian)
+           EMIT_FOUR_BYTES (c1 >> 8, c1 & 0xFF, c2 >> 8, c2 & 0xFF);
+         else
+           EMIT_FOUR_BYTES (c1 & 0xFF, c1 >> 8, c2 & 0xFF, c2 >> 8);
+       }
+    }
+  coding->result = CODING_RESULT_SUCCESS;
+  coding->produced = dst - coding->destination;
+  coding->produced_char += produced_chars;
+  return 0;
+}
+
+\f
+/*** 6. Old Emacs' internal format (emacs-mule) ***/
+
+/* Emacs' internal format for representation of multiple character
+   sets is a kind of multi-byte encoding, i.e. characters are
+   represented by variable-length sequences of one-byte codes.
+
+   ASCII characters and control characters (e.g. `tab', `newline') are
+   represented by one-byte sequences which are their ASCII codes, in
+   the range 0x00 through 0x7F.
+
+   8-bit characters of the range 0x80..0x9F are represented by
+   two-byte sequences of LEADING_CODE_8_BIT_CONTROL and (their 8-bit
+   code + 0x20).
+
+   8-bit characters of the range 0xA0..0xFF are represented by
+   one-byte sequences which are their 8-bit code.
+
+   The other characters are represented by a sequence of `base
+   leading-code', optional `extended leading-code', and one or two
+   `position-code's.  The length of the sequence is determined by the
+   base leading-code.  Leading-code takes the range 0x81 through 0x9D,
+   whereas extended leading-code and position-code take the range 0xA0
+   through 0xFF.  See `charset.h' for more details about leading-code
+   and position-code.
+
+   --- CODE RANGE of Emacs' internal format ---
+   character set       range
+   -------------       -----
+   ascii               0x00..0x7F
+   eight-bit-control   LEADING_CODE_8_BIT_CONTROL + 0xA0..0xBF
+   eight-bit-graphic   0xA0..0xBF
+   ELSE                        0x81..0x9D + [0xA0..0xFF]+
+   ---------------------------------------------
+
+   As this is the internal character representation, the format is
+   usually not used externally (i.e. in a file or in a data sent to a
+   process).  But, it is possible to have a text externally in this
+   format (i.e. by encoding by the coding system `emacs-mule').
+
+   In that case, a sequence of one-byte codes has a slightly different
+   form.
+
+   At first, all characters in eight-bit-control are represented by
+   one-byte sequences which are their 8-bit code.
+
+   Next, character composition data are represented by the byte
+   sequence of the form: 0x80 METHOD BYTES CHARS COMPONENT ...,
+   where,
+       METHOD is 0xF0 plus one of composition method (enum
+       composition_method),
+
+       BYTES is 0xA0 plus a byte length of this composition data,
+
+       CHARS is 0x20 plus a number of characters composed by this
+       data,
+
+       COMPONENTs are characters of multibye form or composition
+       rules encoded by two-byte of ASCII codes.
+
+   In addition, for backward compatibility, the following formats are
+   also recognized as composition data on decoding.
+
+   0x80 MSEQ ...
+   0x80 0xFF MSEQ RULE MSEQ RULE ... MSEQ
+
+   Here,
+       MSEQ is a multibyte form but in these special format:
+         ASCII: 0xA0 ASCII_CODE+0x80,
+         other: LEADING_CODE+0x20 FOLLOWING-BYTE ...,
+       RULE is a one byte code of the range 0xA0..0xF0 that
+       represents a composition rule.
+  */
+
+char emacs_mule_bytes[256];
+
+int
+emacs_mule_char (coding, src, nbytes, nchars, id)
+     struct coding_system *coding;
+     unsigned char *src;
+     int *nbytes, *nchars, *id;
+{
+  const unsigned char *src_end = coding->source + coding->src_bytes;
+  const unsigned char *src_base = src;
+  int multibytep = coding->src_multibyte;
+  struct charset *charset;
+  unsigned code;
+  int c;
+  int consumed_chars = 0;
+
+  ONE_MORE_BYTE (c);
+  switch (emacs_mule_bytes[c])
+    {
+    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)
+       {
+         ONE_MORE_BYTE (c);
+         if (! (charset = emacs_mule_charset[c]))
+           goto invalid_code;
+         ONE_MORE_BYTE (c);
+         code = c & 0x7F;
+       }
+      else
+       {
+         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;
+
+    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;
+
+    case 1:
+      code = c;
+      charset = CHARSET_FROM_ID (ASCII_BYTE_P (code)
+                                ? charset_ascii : charset_eight_bit);
+      break;
+
+    default:
+      abort ();
+    }
+  c = DECODE_CHAR (charset, code);
+  if (c < 0)
+    goto invalid_code;
+  *nbytes = src - src_base;
+  *nchars = consumed_chars;
+  if (id)
+    *id = charset->id;
+  return c;
+
+ no_more_source:
+  return -2;
+
+ invalid_code:
+  return -1;
+}
+
+
+/* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
+   Check if a text is encoded in `emacs-mule'.  If it is, return 1,
+   else return 0.  */
+
+static int
+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_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.  */
+  src += coding->head_ascii;
+
+  while (1)
+    {
+      incomplete = 0;
+      ONE_MORE_BYTE (c);
+      incomplete = 1;
+
+      if (c == 0x80)
+       {
+         /* Perhaps the start of composite character.  We simple skip
+            it because analyzing it is too heavy for detecting.  But,
+            at least, we check that the composite character
+            constitues of more than 4 bytes.  */
+         const unsigned char *src_base;
+
+       repeat:
+         src_base = src;
+         do
+           {
+             ONE_MORE_BYTE (c);
+           }
+         while (c >= 0xA0);
+
+         if (src - src_base <= 4)
+           break;
+         found = CATEGORY_MASK_EMACS_MULE;
+         if (c == 0x80)
+           goto repeat;
+       }
+
+      if (c < 0x80)
+       {
+         if (c < 0x20
+             && (c == ISO_CODE_ESC || c == ISO_CODE_SI || c == ISO_CODE_SO))
+           break;
+       }
+      else
+       {
+         const unsigned char *src_base = src - 1;
+
+         do
+           {
+             ONE_MORE_BYTE (c);
+           }
+         while (c >= 0xA0);
+         if (src - src_base != emacs_mule_bytes[*src_base])
+           break;
+         found = CATEGORY_MASK_EMACS_MULE;
+       }
+    }
+  detect_info->rejected |= CATEGORY_MASK_EMACS_MULE;
+  return 0;
+
+ no_more_source:
+  if (incomplete && coding->mode & CODING_MODE_LAST_BLOCK)
+    {
+      detect_info->rejected |= CATEGORY_MASK_EMACS_MULE;
+      return 0;
+    }
+  detect_info->found |= found;
+  return 1;
+}
+
+
+/* See the above "GENERAL NOTES on `decode_coding_XXX ()' functions".  */
+
+/* Decode a character represented as a component of composition
+   sequence of Emacs 20/21 style at SRC.  Set C to that character and
+   update SRC to the head of next character (or an encoded composition
+   rule).  If SRC doesn't points a composition component, set C to -1.
+   If SRC points an invalid byte sequence, global exit by a return
+   value 0.  */
+
+#define DECODE_EMACS_MULE_COMPOSITION_CHAR(buf)                        \
+  if (1)                                                       \
+    {                                                          \
+      int c;                                                   \
+      int nbytes, nchars;                                      \
+                                                               \
+      if (src == src_end)                                      \
+       break;                                                  \
+      c = emacs_mule_char (coding, src, &nbytes, &nchars, NULL);\
+      if (c < 0)                                               \
+       {                                                       \
+         if (c == -2)                                          \
+           break;                                              \
+         goto invalid_code;                                    \
+       }                                                       \
+      *buf++ = c;                                              \
+      src += nbytes;                                           \
+      consumed_chars += nchars;                                        \
+    }                                                          \
+  else
+
+
+/* Decode a composition rule represented as a component of composition
+   sequence of Emacs 20 style at SRC.  Store the decoded rule in *BUF,
+   and increment BUF.  If SRC points an invalid byte sequence, set C
+   to -1.  */
+
+#define DECODE_EMACS_MULE_COMPOSITION_RULE_20(buf)     \
+  do {                                                 \
+    int c, gref, nref;                                 \
+                                                       \
+    if (src >= src_end)                                        \
+      goto invalid_code;                               \
+    ONE_MORE_BYTE_NO_CHECK (c);                                \
+    c -= 0x20;                                         \
+    if (c < 0 || c >= 81)                              \
+      goto invalid_code;                               \
+                                                       \
+    gref = c / 9, nref = c % 9;                                \
+    *buf++ = COMPOSITION_ENCODE_RULE (gref, nref);     \
+  } while (0)
+
+
+/* Decode a composition rule represented as a component of composition
+   sequence of Emacs 21 style at SRC.  Store the decoded rule in *BUF,
+   and increment BUF.  If SRC points an invalid byte sequence, set C
+   to -1.  */
+
+#define DECODE_EMACS_MULE_COMPOSITION_RULE_21(buf)     \
+  do {                                                 \
+    int gref, nref;                                    \
+                                                       \
+    if (src + 1>= src_end)                             \
+      goto invalid_code;                               \
+    ONE_MORE_BYTE_NO_CHECK (gref);                     \
+    gref -= 0x20;                                      \
+    ONE_MORE_BYTE_NO_CHECK (nref);                     \
+    nref -= 0x20;                                      \
+    if (gref < 0 || gref >= 81                         \
+       || nref < 0 || nref >= 81)                      \
+      goto invalid_code;                               \
+    *buf++ = COMPOSITION_ENCODE_RULE (gref, nref);     \
+  } while (0)
+
+
+#define DECODE_EMACS_MULE_21_COMPOSITION(c)                            \
+  do {                                                                 \
+    /* Emacs 21 style format.  The first three bytes at SRC are                \
+       (METHOD - 0xF2), (BYTES - 0xA0), (CHARS - 0xA0), where BYTES is \
+       the byte length of this composition information, CHARS is the   \
+       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);                                                 \
+    nbytes = c - 0xA0;                                                 \
+    if (nbytes < 3)                                                    \
+      goto invalid_code;                                               \
+    ONE_MORE_BYTE (c);                                                 \
+    nchars = c - 0xA0;                                                 \
+    from = coding->produced + char_offset;                             \
+    to = from + nchars;                                                        \
+    ADD_COMPOSITION_DATA (charbuf, from, to, method);                  \
+    consumed_chars_limit = consumed_chars_base + nbytes;               \
+    if (method != COMPOSITION_RELATIVE)                                        \
+      {                                                                        \
+       int i = 0;                                                      \
+       while (consumed_chars < consumed_chars_limit)                   \
+         {                                                             \
+           if (i % 2 && method != COMPOSITION_WITH_ALTCHARS)           \
+             DECODE_EMACS_MULE_COMPOSITION_RULE_21 (charbuf);          \
+           else                                                        \
+             DECODE_EMACS_MULE_COMPOSITION_CHAR (charbuf);             \
+           i++;                                                        \
+         }                                                             \
+       if (consumed_chars < consumed_chars_limit)                      \
+         goto invalid_code;                                            \
+       charbuf_base[0] -= i;                                           \
+      }                                                                        \
+  } while (0)
+
+
+#define DECODE_EMACS_MULE_20_RELATIVE_COMPOSITION(c)           \
+  do {                                                         \
+    /* Emacs 20 style format for relative composition.  */     \
+    /* Store multibyte form of characters to be composed.  */  \
+    enum composition_method method = COMPOSITION_RELATIVE;     \
+    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 */                 \
+    for (i = 0; i < MAX_COMPOSITION_COMPONENTS; i++)           \
+      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);          \
+    for (j = 0; j < i; j++)                                    \
+      *charbuf++ = components[j];                              \
+  } while (0)
+
+
+#define DECODE_EMACS_MULE_20_RULEBASE_COMPOSITION(c)           \
+  do {                                                         \
+    /* Emacs 20 style format for rule-base composition.  */    \
+    /* Store multibyte form of characters to be composed.  */  \
+    enum composition_method method = COMPOSITION_WITH_RULE;    \
+    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++)           \
+      {                                                                \
+       DECODE_EMACS_MULE_COMPOSITION_RULE_20 (buf);            \
+       DECODE_EMACS_MULE_COMPOSITION_CHAR (buf);               \
+      }                                                                \
+    if (i < 1 || (buf - components) % 2 == 0)                  \
+      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);              \
+    for (j = 0; j < i; j++)                                    \
+      *charbuf++ = components[j];                              \
+    for (j = 0; j < i; j += 2)                                 \
+      *charbuf++ = components[j];                              \
+  } while (0)
+
+
+static void
+decode_coding_emacs_mule (coding)
+     struct coding_system *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 consumed_chars = 0, consumed_chars_base;
+  int multibytep = coding->src_multibyte;
+  Lisp_Object attrs, eol_type, charset_list;
+  int char_offset = coding->produced_char;
+  int last_offset = char_offset;
+  int last_id = charset_ascii;
+
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+
+  while (1)
+    {
+      int c;
+
+      src_base = src;
+      consumed_chars_base = consumed_chars;
+
+      if (charbuf >= charbuf_end)
+       break;
+
+      ONE_MORE_BYTE (c);
+
+      if (c < 0x80)
+       {
+         if (c == '\r')
+           {
+             if (EQ (eol_type, Qdos))
+               {
+                 if (src == src_end)
+                   {
+                     coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+                     goto no_more_source;
+                   }
+                 if (*src == '\n')
+                   ONE_MORE_BYTE (c);
+               }
+             else if (EQ (eol_type, Qmac))
+               c = '\n';
+           }
+         *charbuf++ = c;
+         char_offset++;
+       }
+      else if (c == 0x80)
+       {
+         ONE_MORE_BYTE (c);
+         if (c - 0xF2 >= COMPOSITION_RELATIVE
+             && c - 0xF2 <= COMPOSITION_WITH_RULE_ALTCHARS)
+           DECODE_EMACS_MULE_21_COMPOSITION (c);
+         else if (c < 0xC0)
+           DECODE_EMACS_MULE_20_RELATIVE_COMPOSITION (c);
+         else if (c == 0xFF)
+           DECODE_EMACS_MULE_20_RULEBASE_COMPOSITION (c);
+         else
+           goto invalid_code;
+       }
+      else if (c < 0xA0 && emacs_mule_bytes[c] > 1)
+       {
+         int nbytes, nchars;
+         int id;
+
+         src = src_base;
+         consumed_chars = consumed_chars_base;
+         c = emacs_mule_char (coding, src, &nbytes, &nchars, &id);
+         if (c < 0)
+           {
+             if (c == -2)
+               break;
+             goto invalid_code;
+           }
+         if (last_id != id)
+           {
+             if (last_id != charset_ascii)
+               ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+             last_id = id;
+             last_offset = char_offset;
+           }
+         *charbuf++ = c;
+         src += nbytes;
+         consumed_chars += nchars;
+         char_offset++;
+       }
+      continue;
+
+    invalid_code:
+      src = src_base;
+      consumed_chars = consumed_chars_base;
+      ONE_MORE_BYTE (c);
+      *charbuf++ = 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);
+  coding->consumed_char += consumed_chars_base;
+  coding->consumed = src_base - coding->source;
+  coding->charbuf_used = charbuf - coding->charbuf;
+}
+
+
+#define EMACS_MULE_LEADING_CODES(id, codes)    \
+  do {                                         \
+    if (id < 0xA0)                             \
+      codes[0] = id, codes[1] = 0;             \
+    else if (id < 0xE0)                                \
+      codes[0] = 0x9A, codes[1] = id;          \
+    else if (id < 0xF0)                                \
+      codes[0] = 0x9B, codes[1] = id;          \
+    else if (id < 0xF5)                                \
+      codes[0] = 0x9C, codes[1] = id;          \
+    else                                       \
+      codes[0] = 0x9D, codes[1] = id;          \
+  } while (0);
+
+
+static int
+encode_coding_emacs_mule (coding)
+     struct coding_system *coding;
+{
+  int multibytep = coding->dst_multibyte;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf + coding->charbuf_used;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  int safe_room = 8;
+  int produced_chars = 0;
+  Lisp_Object attrs, eol_type, charset_list;
+  int c;
+  int preferred_charset_id = -1;
+
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+
+  while (charbuf < charbuf_end)
+    {
+      ASSURE_DESTINATION (safe_room);
+      c = *charbuf++;
+
+      if (c < 0)
+       {
+         /* Handle an annotation.  */
+         switch (*charbuf)
+           {
+           case CODING_ANNOTATE_COMPOSITION_MASK:
+             /* Not yet implemented.  */
+             break;
+           case CODING_ANNOTATE_CHARSET_MASK:
+             preferred_charset_id = charbuf[3];
+             if (preferred_charset_id >= 0
+                 && NILP (Fmemq (make_number (preferred_charset_id),
+                                 charset_list)))
+               preferred_charset_id = -1;
+             break;
+           default:
+             abort ();
+           }
+         charbuf += -c - 1;
+         continue;
+       }
+
+      if (ASCII_CHAR_P (c))
+       EMIT_ONE_ASCII_BYTE (c);
+      else if (CHAR_BYTE8_P (c))
+       {
+         c = CHAR_TO_BYTE8 (c);
+         EMIT_ONE_BYTE (c);
+       }
+      else
+       {
+         struct charset *charset;
+         unsigned code;
+         int dimension;
+         int emacs_mule_id;
+         unsigned char leading_codes[2];
+
+         if (preferred_charset_id >= 0)
+           {
+             charset = CHARSET_FROM_ID (preferred_charset_id);
+             if (! CHAR_CHARSET_P (c, charset))
+               charset = char_charset (c, charset_list, NULL);
+           }
+         else
+           charset = char_charset (c, charset_list, &code);
+         if (! charset)
+           {
+             c = coding->default_char;
+             if (ASCII_CHAR_P (c))
+               {
+                 EMIT_ONE_ASCII_BYTE (c);
+                 continue;
+               }
+             charset = char_charset (c, charset_list, &code);
+           }
+         dimension = CHARSET_DIMENSION (charset);
+         emacs_mule_id = CHARSET_EMACS_MULE_ID (charset);
+         EMACS_MULE_LEADING_CODES (emacs_mule_id, leading_codes);
+         EMIT_ONE_BYTE (leading_codes[0]);
+         if (leading_codes[1])
+           EMIT_ONE_BYTE (leading_codes[1]);
+         if (dimension == 1)
+           EMIT_ONE_BYTE (code);
+         else
+           {
+             EMIT_ONE_BYTE (code >> 8);
+             EMIT_ONE_BYTE (code & 0xFF);
+           }
+       }
+    }
+  coding->result = CODING_RESULT_SUCCESS;
+  coding->produced_char += produced_chars;
+  coding->produced = dst - coding->destination;
+  return 0;
+}
+
+\f
+/*** 7. ISO2022 handlers ***/
+
+/* The following note describes the coding system ISO2022 briefly.
+   Since the intention of this note is to help understand the
+   functions in this file, some parts are NOT ACCURATE or are OVERLY
+   SIMPLIFIED.  For thorough understanding, please refer to the
+   original document of ISO2022.  This is equivalent to the standard
    ECMA-35, obtainable from <URL:http://www.ecma.ch/> (*).
 
    ISO2022 provides many mechanisms to encode several character sets
@@ -1301,7 +2276,7 @@ encode_coding_emacs_mule (coding, source, destination, src_bytes, dst_bytes)
    7-bit environment, non-locking-shift, and non-single-shift.
 
    Note (**): If <F> is '@', 'A', or 'B', the intermediate character
-   '(' can be omitted.  We refer to this as "short-form" hereafter.
+   '(' must be omitted.  We refer to this as "short-form" hereafter.
 
    Now you may notice that there are a lot of ways of encoding the
    same multilingual text in ISO2022.  Actually, there exist many
@@ -1331,10 +2306,10 @@ encode_coding_emacs_mule (coding, source, destination, src_bytes, dst_bytes)
   Since these are not standard escape sequences of any ISO standard,
   the use of them with these meanings is restricted to Emacs only.
 
-  (*) This form is used only in Emacs 20.5 and older versions,
-  but the newer versions can safely decode it.
+  (*) This form is used only in Emacs 20.7 and older versions,
+  but newer versions can safely decode it.
   (**) This form is used only in Emacs 21.1 and newer versions,
-  and the older versions can't decode it.
+  and older versions can't decode it.
 
   Here's a list of example usages of these composition escape
   sequences (categorized by `enum composition_method').
@@ -1350,209 +2325,231 @@ encode_coding_emacs_mule (coding, source, destination, src_bytes, dst_bytes)
 
 enum iso_code_class_type iso_code_class[256];
 
-#define CHARSET_OK(idx, charset, c)                                    \
-  (coding_system_table[idx]                                            \
-   && (charset == CHARSET_ASCII                                                \
-       || (safe_chars = coding_safe_chars (coding_system_table[idx]->symbol), \
-          CODING_SAFE_CHAR_P (safe_chars, c)))                         \
-   && (CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding_system_table[idx],        \
-                                             charset)                  \
-       != CODING_SPEC_ISO_NO_REQUESTED_DESIGNATION))
+#define SAFE_CHARSET_P(coding, id)     \
+  ((id) <= (coding)->max_charset_id    \
+   && (coding)->safe_charsets[id] >= 0)
+
+
+#define SHIFT_OUT_OK(category) \
+  (CODING_ISO_INITIAL (&coding_categories[category], 1) >= 0)
+
+static void
+setup_iso_safe_charsets (attrs)
+     Lisp_Object attrs;
+{
+  Lisp_Object charset_list, safe_charsets;
+  Lisp_Object request;
+  Lisp_Object reg_usage;
+  Lisp_Object tail;
+  int reg94, reg96;
+  int flags = XINT (AREF (attrs, coding_attr_iso_flags));
+  int max_charset_id;
+
+  charset_list = CODING_ATTR_CHARSET_LIST (attrs);
+  if ((flags & CODING_ISO_FLAG_FULL_SUPPORT)
+      && ! EQ (charset_list, Viso_2022_charset_list))
+    {
+      CODING_ATTR_CHARSET_LIST (attrs)
+       = charset_list = Viso_2022_charset_list;
+      ASET (attrs, coding_attr_safe_charsets, Qnil);
+    }
+
+  if (STRINGP (AREF (attrs, coding_attr_safe_charsets)))
+    return;
+
+  max_charset_id = 0;
+  for (tail = charset_list; CONSP (tail); tail = XCDR (tail))
+    {
+      int id = XINT (XCAR (tail));
+      if (max_charset_id < id)
+       max_charset_id = id;
+    }
 
-#define SHIFT_OUT_OK(idx) \
-  (CODING_SPEC_ISO_INITIAL_DESIGNATION (coding_system_table[idx], 1) >= 0)
+  safe_charsets = Fmake_string (make_number (max_charset_id + 1),
+                               make_number (255));
+  request = AREF (attrs, coding_attr_iso_request);
+  reg_usage = AREF (attrs, coding_attr_iso_usage);
+  reg94 = XINT (XCAR (reg_usage));
+  reg96 = XINT (XCDR (reg_usage));
+
+  for (tail = charset_list; CONSP (tail); tail = XCDR (tail))
+    {
+      Lisp_Object id;
+      Lisp_Object reg;
+      struct charset *charset;
+
+      id = XCAR (tail);
+      charset = CHARSET_FROM_ID (XINT (id));
+      reg = Fcdr (Fassq (id, request));
+      if (! NILP (reg))
+       SSET (safe_charsets, XINT (id), XINT (reg));
+      else if (charset->iso_chars_96)
+       {
+         if (reg96 < 4)
+           SSET (safe_charsets, XINT (id), reg96);
+       }
+      else
+       {
+         if (reg94 < 4)
+           SSET (safe_charsets, XINT (id), reg94);
+       }
+    }
+  ASET (attrs, coding_attr_safe_charsets, safe_charsets);
+}
 
-#define COMPOSITION_OK(idx)    \
-  (coding_system_table[idx]->composing != COMPOSITION_DISABLED)
 
 /* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
-   Check if a text is encoded in ISO2022.  If it is, return an
-   integer in which appropriate flag bits any of:
-       CODING_CATEGORY_MASK_ISO_7
-       CODING_CATEGORY_MASK_ISO_7_TIGHT
-       CODING_CATEGORY_MASK_ISO_8_1
-       CODING_CATEGORY_MASK_ISO_8_2
-       CODING_CATEGORY_MASK_ISO_7_ELSE
-       CODING_CATEGORY_MASK_ISO_8_ELSE
-   are set.  If a code which should never appear in ISO2022 is found,
-   returns 0.  */
+   Check if a text is encoded in one of ISO-2022 based codig systems.
+   If it is, return 1, else return 0.  */
 
 static int
-detect_coding_iso2022 (src, src_end, multibytep)
-     unsigned char *src, *src_end;
-     int multibytep;
+detect_coding_iso_2022 (coding, detect_info)
+     struct coding_system *coding;
+     struct coding_detection_info *detect_info;
 {
-  int mask = CODING_CATEGORY_MASK_ISO;
-  int mask_found = 0;
-  int reg[4], shift_out = 0, single_shifting = 0;
-  int c, c1, charset;
-  /* Dummy for ONE_MORE_BYTE.  */
-  struct coding_system dummy_coding;
-  struct coding_system *coding = &dummy_coding;
-  Lisp_Object safe_chars;
-
-  reg[0] = CHARSET_ASCII, reg[1] = reg[2] = reg[3] = -1;
-  while (mask && src < src_end)
-    {
-      ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
-    retry:
+  const unsigned char *src = coding->source, *src_base = src;
+  const unsigned char *src_end = coding->source + coding->src_bytes;
+  int multibytep = coding->src_multibyte;
+  int single_shifting = 0;
+  int id;
+  int c, c1;
+  int consumed_chars = 0;
+  int i;
+  int rejected = 0;
+  int found = 0;
+
+  detect_info->checked |= CATEGORY_MASK_ISO;
+
+  for (i = coding_category_iso_7; i <= coding_category_iso_8_else; i++)
+    {
+      struct coding_system *this = &(coding_categories[i]);
+      Lisp_Object attrs, val;
+
+      attrs = CODING_ID_ATTRS (this->id);
+      if (CODING_ISO_FLAGS (this) & CODING_ISO_FLAG_FULL_SUPPORT
+         && ! EQ (CODING_ATTR_SAFE_CHARSETS (attrs), Viso_2022_charset_list))
+       setup_iso_safe_charsets (attrs);
+      val = CODING_ATTR_SAFE_CHARSETS (attrs);
+      this->max_charset_id = SCHARS (val) - 1;
+      this->safe_charsets = (char *) SDATA (val);
+    }
+
+  /* A coding system of this category is always ASCII compatible.  */
+  src += coding->head_ascii;
+
+  while (rejected != CATEGORY_MASK_ISO)
+    {
+      ONE_MORE_BYTE (c);
       switch (c)
        {
        case ISO_CODE_ESC:
          if (inhibit_iso_escape_detection)
            break;
          single_shifting = 0;
-         ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
+         ONE_MORE_BYTE (c);
          if (c >= '(' && c <= '/')
            {
              /* Designation sequence for a charset of dimension 1.  */
-             ONE_MORE_BYTE_CHECK_MULTIBYTE (c1, multibytep);
+             ONE_MORE_BYTE (c1);
              if (c1 < ' ' || c1 >= 0x80
-                 || (charset = iso_charset_table[0][c >= ','][c1]) < 0)
+                 || (id = iso_charset_table[0][c >= ','][c1]) < 0)
                /* Invalid designation sequence.  Just ignore.  */
                break;
-             reg[(c - '(') % 4] = charset;
            }
          else if (c == '$')
            {
              /* Designation sequence for a charset of dimension 2.  */
-             ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
+             ONE_MORE_BYTE (c);
              if (c >= '@' && c <= 'B')
                /* Designation for JISX0208.1978, GB2312, or JISX0208.  */
-               reg[0] = charset = iso_charset_table[1][0][c];
+               id = iso_charset_table[1][0][c];
              else if (c >= '(' && c <= '/')
                {
-                 ONE_MORE_BYTE_CHECK_MULTIBYTE (c1, multibytep);
+                 ONE_MORE_BYTE (c1);
                  if (c1 < ' ' || c1 >= 0x80
-                     || (charset = iso_charset_table[1][c >= ','][c1]) < 0)
+                     || (id = iso_charset_table[1][c >= ','][c1]) < 0)
                    /* Invalid designation sequence.  Just ignore.  */
                    break;
-                 reg[(c - '(') % 4] = charset;
                }
              else
-               /* Invalid designation sequence.  Just ignore.  */
+               /* Invalid designation sequence.  Just ignore it.  */
                break;
            }
          else if (c == 'N' || c == 'O')
            {
              /* ESC <Fe> for SS2 or SS3.  */
-             mask &= CODING_CATEGORY_MASK_ISO_7_ELSE;
+             single_shifting = 1;
+             rejected |= CATEGORY_MASK_ISO_7BIT | CATEGORY_MASK_ISO_8BIT;
              break;
            }
          else if (c >= '0' && c <= '4')
            {
              /* ESC <Fp> for start/end composition.  */
-             if (COMPOSITION_OK (CODING_CATEGORY_IDX_ISO_7))
-               mask_found |= CODING_CATEGORY_MASK_ISO_7;
-             else
-               mask &= ~CODING_CATEGORY_MASK_ISO_7;
-             if (COMPOSITION_OK (CODING_CATEGORY_IDX_ISO_7_TIGHT))
-               mask_found |= CODING_CATEGORY_MASK_ISO_7_TIGHT;
-             else
-               mask &= ~CODING_CATEGORY_MASK_ISO_7_TIGHT;
-             if (COMPOSITION_OK (CODING_CATEGORY_IDX_ISO_8_1))
-               mask_found |= CODING_CATEGORY_MASK_ISO_8_1;
-             else
-               mask &= ~CODING_CATEGORY_MASK_ISO_8_1;
-             if (COMPOSITION_OK (CODING_CATEGORY_IDX_ISO_8_2))
-               mask_found |= CODING_CATEGORY_MASK_ISO_8_2;
-             else
-               mask &= ~CODING_CATEGORY_MASK_ISO_8_2;
-             if (COMPOSITION_OK (CODING_CATEGORY_IDX_ISO_7_ELSE))
-               mask_found |= CODING_CATEGORY_MASK_ISO_7_ELSE;
-             else
-               mask &= ~CODING_CATEGORY_MASK_ISO_7_ELSE;
-             if (COMPOSITION_OK (CODING_CATEGORY_IDX_ISO_8_ELSE))
-               mask_found |= CODING_CATEGORY_MASK_ISO_8_ELSE;
-             else
-               mask &= ~CODING_CATEGORY_MASK_ISO_8_ELSE;
+             found |= CATEGORY_MASK_ISO;
              break;
            }
          else
-           /* Invalid escape sequence.  Just ignore.  */
-           break;
+           {
+             /* Invalid escape sequence.  Just ignore it.  */
+             break;
+           }
 
          /* We found a valid designation sequence for CHARSET.  */
-         mask &= ~CODING_CATEGORY_MASK_ISO_8BIT;
-         c = MAKE_CHAR (charset, 0, 0);
-         if (CHARSET_OK (CODING_CATEGORY_IDX_ISO_7, charset, c))
-           mask_found |= CODING_CATEGORY_MASK_ISO_7;
+         rejected |= CATEGORY_MASK_ISO_8BIT;
+         if (SAFE_CHARSET_P (&coding_categories[coding_category_iso_7],
+                             id))
+           found |= CATEGORY_MASK_ISO_7;
          else
-           mask &= ~CODING_CATEGORY_MASK_ISO_7;
-         if (CHARSET_OK (CODING_CATEGORY_IDX_ISO_7_TIGHT, charset, c))
-           mask_found |= CODING_CATEGORY_MASK_ISO_7_TIGHT;
+           rejected |= CATEGORY_MASK_ISO_7;
+         if (SAFE_CHARSET_P (&coding_categories[coding_category_iso_7_tight],
+                             id))
+           found |= CATEGORY_MASK_ISO_7_TIGHT;
          else
-           mask &= ~CODING_CATEGORY_MASK_ISO_7_TIGHT;
-         if (CHARSET_OK (CODING_CATEGORY_IDX_ISO_7_ELSE, charset, c))
-           mask_found |= CODING_CATEGORY_MASK_ISO_7_ELSE;
+           rejected |= CATEGORY_MASK_ISO_7_TIGHT;
+         if (SAFE_CHARSET_P (&coding_categories[coding_category_iso_7_else],
+                             id))
+           found |= CATEGORY_MASK_ISO_7_ELSE;
          else
-           mask &= ~CODING_CATEGORY_MASK_ISO_7_ELSE;
-         if (CHARSET_OK (CODING_CATEGORY_IDX_ISO_8_ELSE, charset, c))
-           mask_found |= CODING_CATEGORY_MASK_ISO_8_ELSE;
+           rejected |= CATEGORY_MASK_ISO_7_ELSE;
+         if (SAFE_CHARSET_P (&coding_categories[coding_category_iso_8_else],
+                             id))
+           found |= CATEGORY_MASK_ISO_8_ELSE;
          else
-           mask &= ~CODING_CATEGORY_MASK_ISO_8_ELSE;
+           rejected |= CATEGORY_MASK_ISO_8_ELSE;
          break;
 
        case ISO_CODE_SO:
-         if (inhibit_iso_escape_detection)
-           break;
-         single_shifting = 0;
-         if (shift_out == 0
-             && (reg[1] >= 0
-                 || SHIFT_OUT_OK (CODING_CATEGORY_IDX_ISO_7_ELSE)
-                 || SHIFT_OUT_OK (CODING_CATEGORY_IDX_ISO_8_ELSE)))
-           {
-             /* Locking shift out.  */
-             mask &= ~CODING_CATEGORY_MASK_ISO_7BIT;
-             mask_found |= CODING_CATEGORY_MASK_ISO_SHIFT;
-           }
-         break;
-
        case ISO_CODE_SI:
+         /* Locking shift out/in.  */
          if (inhibit_iso_escape_detection)
            break;
          single_shifting = 0;
-         if (shift_out == 1)
-           {
-             /* Locking shift in.  */
-             mask &= ~CODING_CATEGORY_MASK_ISO_7BIT;
-             mask_found |= CODING_CATEGORY_MASK_ISO_SHIFT;
-           }
+         rejected |= CATEGORY_MASK_ISO_7BIT | CATEGORY_MASK_ISO_8BIT;
+         found |= CATEGORY_MASK_ISO_ELSE;
          break;
 
        case ISO_CODE_CSI:
+         /* Control sequence introducer.  */
          single_shifting = 0;
+         rejected |= CATEGORY_MASK_ISO_7BIT | CATEGORY_MASK_ISO_7_ELSE;
+         found |= CATEGORY_MASK_ISO_8_ELSE;
+         goto check_extra_latin;
+
+
        case ISO_CODE_SS2:
        case ISO_CODE_SS3:
-         {
-           int newmask = CODING_CATEGORY_MASK_ISO_8_ELSE;
-
-           if (inhibit_iso_escape_detection)
-             break;
-           if (c != ISO_CODE_CSI)
-             {
-               if (coding_system_table[CODING_CATEGORY_IDX_ISO_8_1]->flags
-                   & CODING_FLAG_ISO_SINGLE_SHIFT)
-                 newmask |= CODING_CATEGORY_MASK_ISO_8_1;
-               if (coding_system_table[CODING_CATEGORY_IDX_ISO_8_2]->flags
-                   & CODING_FLAG_ISO_SINGLE_SHIFT)
-                 newmask |= CODING_CATEGORY_MASK_ISO_8_2;
-               single_shifting = 1;
-             }
-           if (VECTORP (Vlatin_extra_code_table)
-               && !NILP (XVECTOR (Vlatin_extra_code_table)->contents[c]))
-             {
-               if (coding_system_table[CODING_CATEGORY_IDX_ISO_8_1]->flags
-                   & CODING_FLAG_ISO_LATIN_EXTRA)
-                 newmask |= CODING_CATEGORY_MASK_ISO_8_1;
-               if (coding_system_table[CODING_CATEGORY_IDX_ISO_8_2]->flags
-                   & CODING_FLAG_ISO_LATIN_EXTRA)
-                 newmask |= CODING_CATEGORY_MASK_ISO_8_2;
-             }
-           mask &= newmask;
-           mask_found |= newmask;
-         }
-         break;
+         /* Single shift.   */
+         if (inhibit_iso_escape_detection)
+           break;
+         single_shifting = 1;
+         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;
+         if (CODING_ISO_FLAGS (&coding_categories[coding_category_iso_8_2])
+             & CODING_ISO_FLAG_SINGLE_SHIFT)
+           found |= CATEGORY_MASK_ISO_8_2;
+         goto check_extra_latin;
 
        default:
          if (c < 0x80)
@@ -1560,210 +2557,205 @@ detect_coding_iso2022 (src, src_end, multibytep)
              single_shifting = 0;
              break;
            }
-         else if (c < 0xA0)
+         if (c >= 0xA0)
            {
-             single_shifting = 0;
-             if (VECTORP (Vlatin_extra_code_table)
-                 && !NILP (XVECTOR (Vlatin_extra_code_table)->contents[c]))
-               {
-                 int newmask = 0;
-
-                 if (coding_system_table[CODING_CATEGORY_IDX_ISO_8_1]->flags
-                     & CODING_FLAG_ISO_LATIN_EXTRA)
-                   newmask |= CODING_CATEGORY_MASK_ISO_8_1;
-                 if (coding_system_table[CODING_CATEGORY_IDX_ISO_8_2]->flags
-                     & CODING_FLAG_ISO_LATIN_EXTRA)
-                   newmask |= CODING_CATEGORY_MASK_ISO_8_2;
-                 mask &= newmask;
-                 mask_found |= newmask;
-               }
-             else
-               return 0;
-           }
-         else
-           {
-             mask &= ~(CODING_CATEGORY_MASK_ISO_7BIT
-                       | CODING_CATEGORY_MASK_ISO_7_ELSE);
-             mask_found |= CODING_CATEGORY_MASK_ISO_8_1;
+             rejected |= CATEGORY_MASK_ISO_7BIT | CATEGORY_MASK_ISO_7_ELSE;
+             found |= CATEGORY_MASK_ISO_8_1;
              /* Check the length of succeeding codes of the range
-                 0xA0..0FF.  If the byte length is odd, we exclude
-                 CODING_CATEGORY_MASK_ISO_8_2.  We can check this only
-                 when we are not single shifting.  */
-             if (!single_shifting
-                 && mask & CODING_CATEGORY_MASK_ISO_8_2)
+                 0xA0..0FF.  If the byte length is even, we include
+                 CATEGORY_MASK_ISO_8_2 in `found'.  We can check this
+                 only when we are not single shifting.  */
+             if (! single_shifting
+                 && ! (rejected & CATEGORY_MASK_ISO_8_2))
                {
                  int i = 1;
-
-                 c = -1;
                  while (src < src_end)
                    {
-                     ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
+                     ONE_MORE_BYTE (c);
                      if (c < 0xA0)
                        break;
                      i++;
                    }
 
                  if (i & 1 && src < src_end)
-                   mask &= ~CODING_CATEGORY_MASK_ISO_8_2;
+                   rejected |= CATEGORY_MASK_ISO_8_2;
                  else
-                   mask_found |= CODING_CATEGORY_MASK_ISO_8_2;
-                 if (c >= 0)
-                   /* This means that we have read one extra byte.  */
-                   goto retry;
+                   found |= CATEGORY_MASK_ISO_8_2;
                }
+             break;
            }
-         break;
+       check_extra_latin:
+         single_shifting = 0;
+         if (! VECTORP (Vlatin_extra_code_table)
+             || NILP (XVECTOR (Vlatin_extra_code_table)->contents[c]))
+           {
+             rejected = CATEGORY_MASK_ISO;
+             break;
+           }
+         if (CODING_ISO_FLAGS (&coding_categories[coding_category_iso_8_1])
+             & CODING_ISO_FLAG_LATIN_EXTRA)
+           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;
        }
     }
- label_end_of_loop:
-  return (mask & mask_found);
-}
+  detect_info->rejected |= CATEGORY_MASK_ISO;
+  return 0;
 
-/* Decode a character of which charset is CHARSET, the 1st position
-   code is C1, the 2nd position code is C2, and return the decoded
-   character code.  If the variable `translation_table' is non-nil,
-   returned the translated code.  */
+ no_more_source:
+  detect_info->rejected |= rejected;
+  detect_info->found |= (found & ~rejected);
+  return 1;
+}
 
-#define DECODE_ISO_CHARACTER(charset, c1, c2)  \
-  (NILP (translation_table)                    \
-   ? MAKE_CHAR (charset, c1, c2)               \
-   : translate_char (translation_table, -1, charset, c1, c2))
 
 /* Set designation state into CODING.  */
-#define DECODE_DESIGNATION(reg, dimension, chars, final_char)             \
-  do {                                                                    \
-    int charset, c;                                                       \
-                                                                          \
-    if (final_char < '0' || final_char >= 128)                            \
-      goto label_invalid_code;                                            \
-    charset = ISO_CHARSET_TABLE (make_number (dimension),                 \
-                                make_number (chars),                      \
-                                make_number (final_char));                \
-    c = MAKE_CHAR (charset, 0, 0);                                        \
-    if (charset >= 0                                                      \
-       && (CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding, charset) == reg \
-           || CODING_SAFE_CHAR_P (safe_chars, c)))                        \
-      {                                                                           \
-       if (coding->spec.iso2022.last_invalid_designation_register == 0    \
-           && reg == 0                                                    \
-           && charset == CHARSET_ASCII)                                   \
-         {                                                                \
-           /* We should insert this designation sequence as is so         \
-               that it is surely written back to a file.  */              \
-           coding->spec.iso2022.last_invalid_designation_register = -1;   \
-           goto label_invalid_code;                                       \
-         }                                                                \
-       coding->spec.iso2022.last_invalid_designation_register = -1;       \
-        if ((coding->mode & CODING_MODE_DIRECTION)                        \
-           && CHARSET_REVERSE_CHARSET (charset) >= 0)                     \
-          charset = CHARSET_REVERSE_CHARSET (charset);                    \
-        CODING_SPEC_ISO_DESIGNATION (coding, reg) = charset;              \
-      }                                                                           \
-    else                                                                  \
-      {                                                                           \
-       coding->spec.iso2022.last_invalid_designation_register = reg;      \
-       goto label_invalid_code;                                           \
-      }                                                                           \
+#define DECODE_DESIGNATION(reg, dim, chars_96, final)                  \
+  do {                                                                 \
+    int id, prev;                                                      \
+                                                                       \
+    if (final < '0' || final >= 128                                    \
+       || ((id = ISO_CHARSET_TABLE (dim, chars_96, final)) < 0)        \
+       || !SAFE_CHARSET_P (coding, id))                                \
+      {                                                                        \
+       CODING_ISO_DESIGNATION (coding, reg) = -2;                      \
+       goto invalid_code;                                              \
+      }                                                                        \
+    prev = CODING_ISO_DESIGNATION (coding, reg);                       \
+    if (id == charset_jisx0201_roman)                                  \
+      {                                                                        \
+       if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_USE_ROMAN)      \
+         id = charset_ascii;                                           \
+      }                                                                        \
+    else if (id == charset_jisx0208_1978)                              \
+      {                                                                        \
+       if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_USE_OLDJIS)     \
+         id = charset_jisx0208;                                        \
+      }                                                                        \
+    CODING_ISO_DESIGNATION (coding, reg) = id;                         \
+    /* If there was an invalid designation to REG previously, and this \
+       designation is ASCII to REG, we should keep this designation    \
+       sequence.  */                                                   \
+    if (prev == -2 && id == charset_ascii)                             \
+      goto invalid_code;                                               \
   } while (0)
 
-/* Allocate a memory block for storing information about compositions.
-   The block is chained to the already allocated blocks.  */
 
-void
-coding_allocate_composition_data (coding, char_offset)
-     struct coding_system *coding;
-     int char_offset;
-{
-  struct composition_data *cmp_data
-    = (struct composition_data *) xmalloc (sizeof *cmp_data);
-
-  cmp_data->char_offset = char_offset;
-  cmp_data->used = 0;
-  cmp_data->prev = coding->cmp_data;
-  cmp_data->next = NULL;
-  if (coding->cmp_data)
-    coding->cmp_data->next = cmp_data;
-  coding->cmp_data = cmp_data;
-  coding->cmp_data_start = 0;
-}
+#define MAYBE_FINISH_COMPOSITION()                             \
+  do {                                                         \
+    int i;                                                     \
+    if (composition_state == COMPOSING_NO)                     \
+      break;                                                   \
+    /* It is assured that we have enough room for producing    \
+       characters stored in the table `components'.  */                \
+    if (charbuf + component_idx > charbuf_end)                 \
+      goto no_more_source;                                     \
+    composition_state = COMPOSING_NO;                          \
+    if (method == COMPOSITION_RELATIVE                         \
+       || method == COMPOSITION_WITH_ALTCHARS)                 \
+      {                                                                \
+       for (i = 0; i < component_idx; i++)                     \
+         *charbuf++ = components[i];                           \
+       char_offset += component_idx;                           \
+      }                                                                \
+    else                                                       \
+      {                                                                \
+       for (i = 0; i < component_idx; i += 2)                  \
+         *charbuf++ = components[i];                           \
+       char_offset += (component_idx / 2) + 1;                 \
+      }                                                                \
+  } while (0)
+
 
 /* Handle composition start sequence ESC 0, ESC 2, ESC 3, or ESC 4.
    ESC 0 : relative composition : ESC 0 CHAR ... ESC 1
    ESC 2 : rulebase composition : ESC 2 CHAR RULE CHAR RULE ... CHAR ESC 1
-   ESC 3 : altchar composition :  ESC 3 ALT ... ESC 0 CHAR ... ESC 1
-   ESC 4 : alt&rule composition : ESC 4 ALT RULE .. ALT ESC 0 CHAR ... ESC 1
+   ESC 3 : altchar composition :  ESC 3 CHAR ... ESC 0 CHAR ... ESC 1
+   ESC 4 : alt&rule composition : ESC 4 CHAR RULE ... CHAR ESC 0 CHAR ... ESC 1
   */
 
-#define DECODE_COMPOSITION_START(c1)                                      \
-  do {                                                                    \
-    if (coding->composing == COMPOSITION_DISABLED)                        \
-      {                                                                           \
-       *dst++ = ISO_CODE_ESC;                                             \
-       *dst++ = c1 & 0x7f;                                                \
-       coding->produced_char += 2;                                        \
-      }                                                                           \
-    else if (!COMPOSING_P (coding))                                       \
-      {                                                                           \
-       /* This is surely the start of a composition.  We must be sure     \
-           that coding->cmp_data has enough space to store the            \
-           information about the composition.  If not, terminate the      \
-           current decoding loop, allocate one more memory block for      \
-           coding->cmp_data in the caller, then start the decoding        \
-           loop again.  We can't allocate memory here directly because    \
-           it may cause buffer/string relocation.  */                     \
-       if (!coding->cmp_data                                              \
-           || (coding->cmp_data->used + COMPOSITION_DATA_MAX_BUNCH_LENGTH \
-               >= COMPOSITION_DATA_SIZE))                                 \
-         {                                                                \
-           coding->result = CODING_FINISH_INSUFFICIENT_CMP;               \
-           goto label_end_of_loop;                                        \
-         }                                                                \
-       coding->composing = (c1 == '0' ? COMPOSITION_RELATIVE              \
-                            : c1 == '2' ? COMPOSITION_WITH_RULE           \
-                            : c1 == '3' ? COMPOSITION_WITH_ALTCHARS       \
-                            : COMPOSITION_WITH_RULE_ALTCHARS);            \
-       CODING_ADD_COMPOSITION_START (coding, coding->produced_char,       \
-                                     coding->composing);                  \
-       coding->composition_rule_follows = 0;                              \
-      }                                                                           \
-    else                                                                  \
-      {                                                                           \
-       /* We are already handling a composition.  If the method is        \
-           the following two, the codes following the current escape      \
-           sequence are actual characters stored in a buffer.  */         \
-       if (coding->composing == COMPOSITION_WITH_ALTCHARS                 \
-           || coding->composing == COMPOSITION_WITH_RULE_ALTCHARS)        \
-         {                                                                \
-           coding->composing = COMPOSITION_RELATIVE;                      \
-           coding->composition_rule_follows = 0;                          \
-         }                                                                \
-      }                                                                           \
+#define DECODE_COMPOSITION_START(c1)                                   \
+  do {                                                                 \
+    if (c1 == '0'                                                      \
+       && composition_state == COMPOSING_COMPONENT_RULE)               \
+      {                                                                        \
+       component_len = component_idx;                                  \
+       composition_state = COMPOSING_CHAR;                             \
+      }                                                                        \
+    else                                                               \
+      {                                                                        \
+       const unsigned char *p;                                         \
+                                                                       \
+       MAYBE_FINISH_COMPOSITION ();                                    \
+       if (charbuf + MAX_COMPOSITION_COMPONENTS > charbuf_end)         \
+         goto no_more_source;                                          \
+       for (p = src; p < src_end - 1; p++)                             \
+         if (*p == ISO_CODE_ESC && p[1] == '1')                        \
+           break;                                                      \
+       if (p == src_end - 1)                                           \
+         {                                                             \
+           if (coding->mode & CODING_MODE_LAST_BLOCK)                  \
+             goto invalid_code;                                        \
+           goto no_more_source;                                        \
+         }                                                             \
+                                                                       \
+       /* This is surely the start of a composition.  */               \
+       method = (c1 == '0' ? COMPOSITION_RELATIVE                      \
+                 : c1 == '2' ? COMPOSITION_WITH_RULE                   \
+                 : c1 == '3' ? COMPOSITION_WITH_ALTCHARS               \
+                 : COMPOSITION_WITH_RULE_ALTCHARS);                    \
+       composition_state = (c1 <= '2' ? COMPOSING_CHAR                 \
+                            : COMPOSING_COMPONENT_CHAR);               \
+       component_idx = component_len = 0;                              \
+      }                                                                        \
   } while (0)
 
-/* Handle composition end sequence ESC 1.  */
 
-#define DECODE_COMPOSITION_END(c1)                                     \
+/* Handle compositoin end sequence ESC 1.  */
+
+#define DECODE_COMPOSITION_END()                                       \
   do {                                                                 \
-    if (! COMPOSING_P (coding))                                                \
+    int nchars = (component_len > 0 ? component_idx - component_len    \
+                 : method == COMPOSITION_RELATIVE ? component_idx      \
+                 : (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);                  \
+    if (method != COMPOSITION_RELATIVE)                                        \
       {                                                                        \
-       *dst++ = ISO_CODE_ESC;                                          \
-       *dst++ = c1;                                                    \
-       coding->produced_char += 2;                                     \
+       if (component_len == 0)                                         \
+         for (i = 0; i < component_idx; i++)                           \
+           *charbuf++ = components[i];                                 \
+       else                                                            \
+         for (i = 0; i < component_len; i++)                           \
+           *charbuf++ = components[i];                                 \
+       *saved_charbuf = saved_charbuf - charbuf;                       \
       }                                                                        \
+    if (method == COMPOSITION_WITH_RULE)                               \
+      for (i = 0; i < component_idx; i += 2, char_offset++)            \
+       *charbuf++ = components[i];                                     \
     else                                                               \
-      {                                                                        \
-       CODING_ADD_COMPOSITION_END (coding, coding->produced_char);     \
-       coding->composing = COMPOSITION_NO;                             \
-      }                                                                        \
+      for (i = component_len; i < component_idx; i++, char_offset++)   \
+       *charbuf++ = components[i];                                     \
+    coding->annotated = 1;                                             \
+    composition_state = COMPOSING_NO;                                  \
   } while (0)
 
+
 /* Decode a composition rule from the byte C1 (and maybe one more byte
    from SRC) and store one encoded composition rule in
    coding->cmp_data.  */
 
 #define DECODE_COMPOSITION_RULE(c1)                                    \
   do {                                                                 \
-    int rule = 0;                                                      \
     (c1) -= 32;                                                                \
     if (c1 < 81)               /* old format (before ver.21) */        \
       {                                                                        \
@@ -1771,167 +2763,173 @@ coding_allocate_composition_data (coding, char_offset)
        int nref = (c1) % 9;                                            \
        if (gref == 4) gref = 10;                                       \
        if (nref == 4) nref = 10;                                       \
-       rule = COMPOSITION_ENCODE_RULE (gref, nref);                    \
+       c1 = COMPOSITION_ENCODE_RULE (gref, nref);                      \
       }                                                                        \
     else if (c1 < 93)          /* new format (after ver.21) */         \
       {                                                                        \
        ONE_MORE_BYTE (c2);                                             \
-       rule = COMPOSITION_ENCODE_RULE (c1 - 81, c2 - 32);              \
+       c1 = COMPOSITION_ENCODE_RULE (c1 - 81, c2 - 32);                \
       }                                                                        \
-    CODING_ADD_COMPOSITION_COMPONENT (coding, rule);                   \
-    coding->composition_rule_follows = 0;                              \
+    else                                                               \
+      c1 = 0;                                                          \
   } while (0)
 
 
 /* See the above "GENERAL NOTES on `decode_coding_XXX ()' functions".  */
 
 static void
-decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
+decode_coding_iso_2022 (coding)
      struct coding_system *coding;
-     unsigned char *source, *destination;
-     int src_bytes, dst_bytes;
 {
-  unsigned char *src = source;
-  unsigned char *src_end = source + src_bytes;
-  unsigned char *dst = destination;
-  unsigned char *dst_end = destination + dst_bytes;
+  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 - 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 charset0 = CODING_SPEC_ISO_PLANE_CHARSET (coding, 0);
-  int charset1 = CODING_SPEC_ISO_PLANE_CHARSET (coding, 1);
-  /* SRC_BASE remembers the start position in source in each loop.
-     The loop will be exited when there's not enough source code
-     (within macro ONE_MORE_BYTE), or when there's not enough
-     destination area to produce a character (within macro
-     EMIT_CHAR).  */
-  unsigned char *src_base;
-  int c, charset;
-  Lisp_Object translation_table;
-  Lisp_Object safe_chars;
-
-  safe_chars = coding_safe_chars (coding->symbol);
-
-  if (NILP (Venable_character_translation))
-    translation_table = Qnil;
-  else
-    {
-      translation_table = coding->translation_table_for_decode;
-      if (NILP (translation_table))
-       translation_table = Vstandard_translation_table_for_decode;
-    }
-
-  coding->result = CODING_FINISH_NORMAL;
+  int charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
+  int charset_id_1 = CODING_ISO_INVOKED_CHARSET (coding, 1);
+  struct charset *charset;
+  int c;
+  /* For handling composition sequence.  */
+#define COMPOSING_NO                   0
+#define COMPOSING_CHAR                 1
+#define COMPOSING_RULE                 2
+#define COMPOSING_COMPONENT_CHAR       3
+#define COMPOSING_COMPONENT_RULE       4
+
+  int composition_state = COMPOSING_NO;
+  enum composition_method method;
+  int components[MAX_COMPOSITION_COMPONENTS * 2 + 1];
+  int component_idx;
+  int component_len;
+  Lisp_Object attrs, eol_type, charset_list;
+  int char_offset = coding->produced_char;
+  int last_offset = char_offset;
+  int last_id = charset_ascii;
+
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+  setup_iso_safe_charsets (attrs);
 
   while (1)
     {
       int c1, c2;
 
       src_base = src;
+      consumed_chars_base = consumed_chars;
+
+      if (charbuf >= charbuf_end)
+       break;
+
       ONE_MORE_BYTE (c1);
 
-      /* We produce no character or one character.  */
+      /* We produce at most one character.  */
       switch (iso_code_class [c1])
        {
        case ISO_0x20_or_0x7F:
-         if (COMPOSING_P (coding) && coding->composition_rule_follows)
+         if (composition_state != COMPOSING_NO)
            {
-             DECODE_COMPOSITION_RULE (c1);
-             continue;
-           }
-         if (charset0 < 0 || CHARSET_CHARS (charset0) == 94)
-           {
-             /* This is SPACE or DEL.  */
-             charset = CHARSET_ASCII;
-             break;
+             if (composition_state == COMPOSING_RULE
+                 || composition_state == COMPOSING_COMPONENT_RULE)
+               {
+                 DECODE_COMPOSITION_RULE (c1);
+                 components[component_idx++] = c1;
+                 composition_state--;
+                 continue;
+               }
            }
-         /* This is a graphic character, we fall down ...  */
+         if (charset_id_0 < 0
+             || ! CHARSET_ISO_CHARS_96 (CHARSET_FROM_ID (charset_id_0)))
+           /* This is SPACE or DEL.  */
+           charset = CHARSET_FROM_ID (charset_ascii);
+         else
+           charset = CHARSET_FROM_ID (charset_id_0);
+         break;
 
        case ISO_graphic_plane_0:
-         if (COMPOSING_P (coding) && coding->composition_rule_follows)
+         if (composition_state != COMPOSING_NO)
            {
-             DECODE_COMPOSITION_RULE (c1);
-             continue;
+             if (composition_state == COMPOSING_RULE
+                 || composition_state == COMPOSING_COMPONENT_RULE)
+               {
+                 DECODE_COMPOSITION_RULE (c1);
+                 components[component_idx++] = c1;
+                 composition_state--;
+                 continue;
+               }
            }
-         charset = charset0;
+         charset = CHARSET_FROM_ID (charset_id_0);
          break;
 
        case ISO_0xA0_or_0xFF:
-         if (charset1 < 0 || CHARSET_CHARS (charset1) == 94
-             || coding->flags & CODING_FLAG_ISO_SEVEN_BITS)
-           goto label_invalid_code;
+         if (charset_id_1 < 0
+             || ! CHARSET_ISO_CHARS_96 (CHARSET_FROM_ID (charset_id_1))
+             || CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SEVEN_BITS)
+           goto invalid_code;
          /* This is a graphic character, we fall down ... */
 
        case ISO_graphic_plane_1:
-         if (charset1 < 0)
-           goto label_invalid_code;
-         charset = charset1;
-         break;
-
-       case ISO_control_0:
-         if (COMPOSING_P (coding))
-           DECODE_COMPOSITION_END ('1');
-
-         /* All ISO2022 control characters in this class have the
-             same representation in Emacs internal format.  */
-         if (c1 == '\n'
-             && (coding->mode & CODING_MODE_INHIBIT_INCONSISTENT_EOL)
-             && (coding->eol_type == CODING_EOL_CR
-                 || coding->eol_type == CODING_EOL_CRLF))
-           {
-             coding->result = CODING_FINISH_INCONSISTENT_EOL;
-             goto label_end_of_loop;
-           }
-         charset = CHARSET_ASCII;
+         if (charset_id_1 < 0)
+           goto invalid_code;
+         charset = CHARSET_FROM_ID (charset_id_1);
          break;
 
-       case ISO_control_1:
-         if (COMPOSING_P (coding))
-           DECODE_COMPOSITION_END ('1');
-         goto label_invalid_code;
-
        case ISO_carriage_return:
-         if (COMPOSING_P (coding))
-           DECODE_COMPOSITION_END ('1');
-
-         if (coding->eol_type == CODING_EOL_CR)
-           c1 = '\n';
-         else if (coding->eol_type == CODING_EOL_CRLF)
+         if (c1 == '\r')
            {
-             ONE_MORE_BYTE (c1);
-             if (c1 != ISO_CODE_LF)
+             if (EQ (eol_type, Qdos))
                {
-                 src--;
-                 c1 = '\r';
+                 if (src == src_end)
+                   {
+                     coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+                     goto no_more_source;
+                   }
+                 if (*src == '\n')
+                   ONE_MORE_BYTE (c1);
                }
+             else if (EQ (eol_type, Qmac))
+               c1 = '\n';
            }
-         charset = CHARSET_ASCII;
+         /* fall through */
+
+       case ISO_control_0:
+         MAYBE_FINISH_COMPOSITION ();
+         charset = CHARSET_FROM_ID (charset_ascii);
          break;
 
+       case ISO_control_1:
+         MAYBE_FINISH_COMPOSITION ();
+         goto invalid_code;
+
        case ISO_shift_out:
-         if (! (coding->flags & CODING_FLAG_ISO_LOCKING_SHIFT)
-             || CODING_SPEC_ISO_DESIGNATION (coding, 1) < 0)
-           goto label_invalid_code;
-         CODING_SPEC_ISO_INVOCATION (coding, 0) = 1;
-         charset0 = CODING_SPEC_ISO_PLANE_CHARSET (coding, 0);
+         if (! (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_LOCKING_SHIFT)
+             || CODING_ISO_DESIGNATION (coding, 1) < 0)
+           goto invalid_code;
+         CODING_ISO_INVOCATION (coding, 0) = 1;
+         charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
          continue;
 
        case ISO_shift_in:
-         if (! (coding->flags & CODING_FLAG_ISO_LOCKING_SHIFT))
-           goto label_invalid_code;
-         CODING_SPEC_ISO_INVOCATION (coding, 0) = 0;
-         charset0 = CODING_SPEC_ISO_PLANE_CHARSET (coding, 0);
+         if (! (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_LOCKING_SHIFT))
+           goto invalid_code;
+         CODING_ISO_INVOCATION (coding, 0) = 0;
+         charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
          continue;
 
        case ISO_single_shift_2_7:
        case ISO_single_shift_2:
-         if (! (coding->flags & CODING_FLAG_ISO_SINGLE_SHIFT))
-           goto label_invalid_code;
+         if (! (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SINGLE_SHIFT))
+           goto invalid_code;
          /* SS2 is handled as an escape sequence of ESC 'N' */
          c1 = 'N';
          goto label_escape_sequence;
 
        case ISO_single_shift_3:
-         if (! (coding->flags & CODING_FLAG_ISO_SINGLE_SHIFT))
-           goto label_invalid_code;
+         if (! (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SINGLE_SHIFT))
+           goto invalid_code;
          /* SS2 is handled as an escape sequence of ESC 'O' */
          c1 = 'O';
          goto label_escape_sequence;
@@ -1944,7 +2942,7 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
        case ISO_escape:
          ONE_MORE_BYTE (c1);
        label_escape_sequence:
-         /* Escape sequences handled by Emacs are invocation,
+         /* Escape sequences handled here are invocation,
             designation, direction specification, and character
             composition specification.  */
          switch (c1)
@@ -1952,89 +2950,93 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
            case '&':           /* revision of following character set */
              ONE_MORE_BYTE (c1);
              if (!(c1 >= '@' && c1 <= '~'))
-               goto label_invalid_code;
+               goto invalid_code;
              ONE_MORE_BYTE (c1);
              if (c1 != ISO_CODE_ESC)
-               goto label_invalid_code;
+               goto invalid_code;
              ONE_MORE_BYTE (c1);
              goto label_escape_sequence;
 
            case '$':           /* designation of 2-byte character set */
-             if (! (coding->flags & CODING_FLAG_ISO_DESIGNATION))
-               goto label_invalid_code;
+             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,
                           or JISX0208.1980 */
-                 DECODE_DESIGNATION (0, 2, 94, c1);
+                 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, 94, 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, 96, c2);
+                 DECODE_DESIGNATION (c1 - 0x2C, 2, 1, c2);
                }
              else
-               goto label_invalid_code;
+               goto invalid_code;
              /* We must update these variables now.  */
-             charset0 = CODING_SPEC_ISO_PLANE_CHARSET (coding, 0);
-             charset1 = CODING_SPEC_ISO_PLANE_CHARSET (coding, 1);
+             charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
+             charset_id_1 = CODING_ISO_INVOKED_CHARSET (coding, 1);
              continue;
 
            case 'n':           /* invocation of locking-shift-2 */
-             if (! (coding->flags & CODING_FLAG_ISO_LOCKING_SHIFT)
-                 || CODING_SPEC_ISO_DESIGNATION (coding, 2) < 0)
-               goto label_invalid_code;
-             CODING_SPEC_ISO_INVOCATION (coding, 0) = 2;
-             charset0 = CODING_SPEC_ISO_PLANE_CHARSET (coding, 0);
+             if (! (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_LOCKING_SHIFT)
+                 || CODING_ISO_DESIGNATION (coding, 2) < 0)
+               goto invalid_code;
+             CODING_ISO_INVOCATION (coding, 0) = 2;
+             charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
              continue;
 
            case 'o':           /* invocation of locking-shift-3 */
-             if (! (coding->flags & CODING_FLAG_ISO_LOCKING_SHIFT)
-                 || CODING_SPEC_ISO_DESIGNATION (coding, 3) < 0)
-               goto label_invalid_code;
-             CODING_SPEC_ISO_INVOCATION (coding, 0) = 3;
-             charset0 = CODING_SPEC_ISO_PLANE_CHARSET (coding, 0);
+             if (! (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_LOCKING_SHIFT)
+                 || CODING_ISO_DESIGNATION (coding, 3) < 0)
+               goto invalid_code;
+             CODING_ISO_INVOCATION (coding, 0) = 3;
+             charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
              continue;
 
            case 'N':           /* invocation of single-shift-2 */
-             if (! (coding->flags & CODING_FLAG_ISO_SINGLE_SHIFT)
-                 || CODING_SPEC_ISO_DESIGNATION (coding, 2) < 0)
-               goto label_invalid_code;
-             charset = CODING_SPEC_ISO_DESIGNATION (coding, 2);
+             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));
              ONE_MORE_BYTE (c1);
              if (c1 < 0x20 || (c1 >= 0x80 && c1 < 0xA0))
-               goto label_invalid_code;
+               goto invalid_code;
              break;
 
            case 'O':           /* invocation of single-shift-3 */
-             if (! (coding->flags & CODING_FLAG_ISO_SINGLE_SHIFT)
-                 || CODING_SPEC_ISO_DESIGNATION (coding, 3) < 0)
-               goto label_invalid_code;
-             charset = CODING_SPEC_ISO_DESIGNATION (coding, 3);
+             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));
              ONE_MORE_BYTE (c1);
              if (c1 < 0x20 || (c1 >= 0x80 && c1 < 0xA0))
-               goto label_invalid_code;
+               goto invalid_code;
              break;
 
            case '0': case '2': case '3': case '4': /* start composition */
+             if (! (coding->common_flags & CODING_ANNOTATE_COMPOSITION_MASK))
+               goto invalid_code;
              DECODE_COMPOSITION_START (c1);
              continue;
 
            case '1':           /* end composition */
-             DECODE_COMPOSITION_END (c1);
+             if (composition_state == COMPOSING_NO)
+               goto invalid_code;
+             DECODE_COMPOSITION_END ();
              continue;
 
            case '[':           /* specification of direction */
-             if (coding->flags & CODING_FLAG_ISO_NO_DIRECTION)
-               goto label_invalid_code;
+             if (! CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_DIRECTION)
+               goto invalid_code;
              /* For the moment, nested direction is not supported.
                 So, `coding->mode & CODING_MODE_DIRECTION' zero means
-                left-to-right, and nonzero means right-to-left.  */
+                left-to-right, and nozero means right-to-left.  */
              ONE_MORE_BYTE (c1);
              switch (c1)
                {
@@ -2047,7 +3049,7 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
                  if (c1 == ']')
                    coding->mode &= ~CODING_MODE_DIRECTION;
                  else
-                   goto label_invalid_code;
+                   goto invalid_code;
                  break;
 
                case '2':       /* start of right-to-left direction */
@@ -2055,17 +3057,15 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
                  if (c1 == ']')
                    coding->mode |= CODING_MODE_DIRECTION;
                  else
-                   goto label_invalid_code;
+                   goto invalid_code;
                  break;
 
                default:
-                 goto label_invalid_code;
+                 goto invalid_code;
                }
              continue;
 
            case '%':
-             if (COMPOSING_P (coding))
-               DECODE_COMPOSITION_END ('1');
              ONE_MORE_BYTE (c1);
              if (c1 == '/')
                {
@@ -2074,46 +3074,40 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
                     We keep these bytes as is for the moment.
                     They may be decoded by post-read-conversion.  */
                  int dim, M, L;
-                 int size, required;
-                 int produced_chars;
-                 
+                 int size;
+
                  ONE_MORE_BYTE (dim);
                  ONE_MORE_BYTE (M);
                  ONE_MORE_BYTE (L);
                  size = ((M - 128) * 128) + (L - 128);
-                 required = 8 + size * 2;
-                 if (dst + required > (dst_bytes ? dst_end : src))
-                   goto label_end_of_loop;
-                 *dst++ = ISO_CODE_ESC;
-                 *dst++ = '%';
-                 *dst++ = '/';
-                 *dst++ = dim;
-                 produced_chars = 4;
-                 dst += CHAR_STRING (M, dst), produced_chars++;
-                 dst += CHAR_STRING (L, dst), produced_chars++;
+                 if (charbuf + 8 + size > charbuf_end)
+                   goto break_loop;
+                 *charbuf++ = ISO_CODE_ESC;
+                 *charbuf++ = '%';
+                 *charbuf++ = '/';
+                 *charbuf++ = dim;
+                 *charbuf++ = BYTE8_TO_CHAR (M);
+                 *charbuf++ = BYTE8_TO_CHAR (L);
                  while (size-- > 0)
                    {
                      ONE_MORE_BYTE (c1);
-                     dst += CHAR_STRING (c1, dst), produced_chars++;
+                     *charbuf++ = ASCII_BYTE_P (c1) ? c1 : BYTE8_TO_CHAR (c1);
                    }
-                 coding->produced_char += produced_chars;
                }
              else if (c1 == 'G')
                {
-                 unsigned char *d = dst;
-                 int produced_chars;
-
                  /* XFree86 extension for embedding UTF-8 in CTEXT:
                     ESC % G --UTF-8-BYTES-- ESC % @
                     We keep these bytes as is for the moment.
                     They may be decoded by post-read-conversion.  */
-                 if (d + 6 > (dst_bytes ? dst_end : src))
-                   goto label_end_of_loop;
-                 *d++ = ISO_CODE_ESC;
-                 *d++ = '%';
-                 *d++ = 'G';
-                 produced_chars = 3;
-                 while (d + 1 < (dst_bytes ? dst_end : src))
+                 int *p = charbuf;
+
+                 if (p + 6 > charbuf_end)
+                   goto break_loop;
+                 *p++ = ISO_CODE_ESC;
+                 *p++ = '%';
+                 *p++ = 'G';
+                 while (p < charbuf_end)
                    {
                      ONE_MORE_BYTE (c1);
                      if (c1 == ISO_CODE_ESC
@@ -2121,69 +3115,119 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
                          && src[0] == '%'
                          && src[1] == '@')
                        break;
-                     d += CHAR_STRING (c1, d), produced_chars++;
+                     *p++ = ASCII_BYTE_P (c1) ? c1 : BYTE8_TO_CHAR (c1);
                    }
-                 if (d + 3 > (dst_bytes ? dst_end : src))
-                   goto label_end_of_loop;
-                 *d++ = ISO_CODE_ESC;
-                 *d++ = '%';
-                 *d++ = '@';
-                 dst = d;
-                 coding->produced_char += produced_chars + 3;
+                 if (p + 3 > charbuf_end)
+                   goto break_loop;
+                 *p++ = ISO_CODE_ESC;
+                 *p++ = '%';
+                 *p++ = '@';
+                 charbuf = p;
                }
              else
-               goto label_invalid_code;
+               goto invalid_code;
              continue;
+             break;
 
            default:
-             if (! (coding->flags & CODING_FLAG_ISO_DESIGNATION))
-               goto label_invalid_code;
+             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, 94, 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, 96, c2);
+                 DECODE_DESIGNATION (c1 - 0x2C, 1, 1, c2);
                }
              else
-               goto label_invalid_code;
+               goto invalid_code;
              /* We must update these variables now.  */
-             charset0 = CODING_SPEC_ISO_PLANE_CHARSET (coding, 0);
-             charset1 = CODING_SPEC_ISO_PLANE_CHARSET (coding, 1);
+             charset_id_0 = CODING_ISO_INVOKED_CHARSET (coding, 0);
+             charset_id_1 = CODING_ISO_INVOKED_CHARSET (coding, 1);
              continue;
            }
        }
 
+      if (charset->id != charset_ascii
+         && last_id != charset->id)
+       {
+         if (last_id != charset_ascii)
+           ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+         last_id = charset->id;
+         last_offset = char_offset;
+       }
+
       /* Now we know CHARSET and 1st position code C1 of a character.
-         Produce a multibyte sequence for that character while getting
-         2nd position code C2 if necessary.  */
-      if (CHARSET_DIMENSION (charset) == 2)
+         Produce a decoded character while getting 2nd position code
+         C2 if necessary.  */
+      c1 &= 0x7F;
+      if (CHARSET_DIMENSION (charset) > 1)
        {
          ONE_MORE_BYTE (c2);
-         if (c1 < 0x80 ? c2 < 0x20 || c2 >= 0x80 : c2 < 0xA0)
+         if (c2 < 0x20 || (c2 >= 0x80 && c2 < 0xA0))
            /* C2 is not in a valid range.  */
-           goto label_invalid_code;
+           goto invalid_code;
+         c1 = (c1 << 8) | (c2 & 0x7F);
+         if (CHARSET_DIMENSION (charset) > 2)
+           {
+             ONE_MORE_BYTE (c2);
+             if (c2 < 0x20 || (c2 >= 0x80 && c2 < 0xA0))
+               /* C2 is not in a valid range.  */
+               goto invalid_code;
+             c1 = (c1 << 8) | (c2 & 0x7F);
+           }
+       }
+
+      CODING_DECODE_CHAR (coding, src, src_base, src_end, charset, c1, c);
+      if (c < 0)
+       {
+         MAYBE_FINISH_COMPOSITION ();
+         for (; src_base < src; src_base++, char_offset++)
+           {
+             if (ASCII_BYTE_P (*src_base))
+               *charbuf++ = *src_base;
+             else
+               *charbuf++ = BYTE8_TO_CHAR (*src_base);
+           }
+       }
+      else if (composition_state == COMPOSING_NO)
+       {
+         *charbuf++ = c;
+         char_offset++;
+       }
+      else
+       {
+         components[component_idx++] = c;
+         if (method == COMPOSITION_WITH_RULE
+             || (method == COMPOSITION_WITH_RULE_ALTCHARS
+                 && composition_state == COMPOSING_COMPONENT_CHAR))
+           composition_state++;
        }
-      c = DECODE_ISO_CHARACTER (charset, c1, c2);
-      EMIT_CHAR (c);
       continue;
 
-    label_invalid_code:
-      coding->errors++;
-      if (COMPOSING_P (coding))
-       DECODE_COMPOSITION_END ('1');
+    invalid_code:
+      MAYBE_FINISH_COMPOSITION ();
       src = src_base;
-      c = *src++;
-      EMIT_CHAR (c);
+      consumed_chars = consumed_chars_base;
+      ONE_MORE_BYTE (c);
+      *charbuf++ = ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
+      char_offset++;
+      coding->errors++;
+      continue;
+
+    break_loop:
+      break;
     }
 
- label_end_of_loop:
-  coding->consumed = coding->consumed_char = src_base - source;
-  coding->produced = dst - destination;
-  return;
+ no_more_source:
+  if (last_id != charset_ascii)
+    ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+  coding->consumed_char += consumed_chars_base;
+  coding->consumed = src_base - coding->source;
+  coding->charbuf_used = charbuf - coding->charbuf;
 }
 
 
@@ -2191,9 +3235,9 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
 
 /*
    It is not enough to say just "ISO2022" on encoding, we have to
-   specify more details.  In Emacs, each ISO2022 coding system
+   specify more details.  In Emacs, each coding system of ISO2022
    variant has the following specifications:
-       1. Initial designation to G0 through G3.
+       1. Initial designation to G0 thru G3.
        2. Allows short-form designation?
        3. ASCII should be designated to G0 before control characters?
        4. ASCII should be designated to G0 at end of line?
@@ -2203,8 +3247,8 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
    And the following two are only for Japanese:
        8. Use ASCII in place of JIS0201-1976-Roman?
        9. Use JISX0208-1983 in place of JISX0208-1978?
-   These specifications are encoded in `coding->flags' as flag bits
-   defined by macros CODING_FLAG_ISO_XXX.  See `coding.h' for more
+   These specifications are encoded in CODING_ISO_FLAGS (coding) as flag bits
+   defined by macros CODING_ISO_FLAG_XXX.  See `coding.h' for more
    details.
 */
 
@@ -2215,115 +3259,136 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
 
 #define ENCODE_DESIGNATION(charset, reg, coding)                       \
   do {                                                                 \
-    unsigned char final_char = CHARSET_ISO_FINAL_CHAR (charset);       \
+    unsigned char final_char = CHARSET_ISO_FINAL (charset);            \
     char *intermediate_char_94 = "()*+";                               \
     char *intermediate_char_96 = ",-./";                               \
-    int revision = CODING_SPEC_ISO_REVISION_NUMBER(coding, charset);   \
-                                                                       \
-    if (revision < 255)                                                        \
+    int revision = -1;                                                 \
+    int c;                                                             \
+                                                                       \
+    if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_REVISION)          \
+      revision = CHARSET_ISO_REVISION (charset);                       \
+                                                                       \
+    if (revision >= 0)                                                 \
       {                                                                        \
-       *dst++ = ISO_CODE_ESC;                                          \
-       *dst++ = '&';                                                   \
-       *dst++ = '@' + revision;                                        \
+       EMIT_TWO_ASCII_BYTES (ISO_CODE_ESC, '&');                       \
+       EMIT_ONE_BYTE ('@' + revision);                                 \
       }                                                                        \
-    *dst++ = ISO_CODE_ESC;                                             \
+    EMIT_ONE_ASCII_BYTE (ISO_CODE_ESC);                                        \
     if (CHARSET_DIMENSION (charset) == 1)                              \
       {                                                                        \
-       if (CHARSET_CHARS (charset) == 94)                              \
-         *dst++ = (unsigned char) (intermediate_char_94[reg]);         \
+       if (! CHARSET_ISO_CHARS_96 (charset))                           \
+         c = intermediate_char_94[reg];                                \
        else                                                            \
-         *dst++ = (unsigned char) (intermediate_char_96[reg]);         \
+         c = intermediate_char_96[reg];                                \
+       EMIT_ONE_ASCII_BYTE (c);                                        \
       }                                                                        \
     else                                                               \
       {                                                                        \
-       *dst++ = '$';                                                   \
-       if (CHARSET_CHARS (charset) == 94)                              \
+       EMIT_ONE_ASCII_BYTE ('$');                                      \
+       if (! CHARSET_ISO_CHARS_96 (charset))                           \
          {                                                             \
-           if (! (coding->flags & CODING_FLAG_ISO_SHORT_FORM)          \
+           if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_LONG_FORM   \
                || reg != 0                                             \
                || final_char < '@' || final_char > 'B')                \
-             *dst++ = (unsigned char) (intermediate_char_94[reg]);     \
+             EMIT_ONE_ASCII_BYTE (intermediate_char_94[reg]);          \
          }                                                             \
        else                                                            \
-         *dst++ = (unsigned char) (intermediate_char_96[reg]);         \
+         EMIT_ONE_ASCII_BYTE (intermediate_char_96[reg]);              \
       }                                                                        \
-    *dst++ = final_char;                                               \
-    CODING_SPEC_ISO_DESIGNATION (coding, reg) = charset;               \
+    EMIT_ONE_ASCII_BYTE (final_char);                                  \
+                                                                       \
+    CODING_ISO_DESIGNATION (coding, reg) = CHARSET_ID (charset);       \
   } while (0)
 
+
 /* The following two macros produce codes (control character or escape
    sequence) for ISO2022 single-shift functions (single-shift-2 and
    single-shift-3).  */
 
-#define ENCODE_SINGLE_SHIFT_2                          \
-  do {                                                 \
-    if (coding->flags & CODING_FLAG_ISO_SEVEN_BITS)    \
-      *dst++ = ISO_CODE_ESC, *dst++ = 'N';             \
-    else                                               \
-      *dst++ = ISO_CODE_SS2;                           \
-    CODING_SPEC_ISO_SINGLE_SHIFTING (coding) = 1;      \
+#define ENCODE_SINGLE_SHIFT_2                                          \
+  do {                                                                 \
+    if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SEVEN_BITS)                \
+      EMIT_TWO_ASCII_BYTES (ISO_CODE_ESC, 'N');                                \
+    else                                                               \
+      EMIT_ONE_BYTE (ISO_CODE_SS2);                                    \
+    CODING_ISO_SINGLE_SHIFTING (coding) = 1;                           \
   } while (0)
 
-#define ENCODE_SINGLE_SHIFT_3                          \
-  do {                                                 \
-    if (coding->flags & CODING_FLAG_ISO_SEVEN_BITS)    \
-      *dst++ = ISO_CODE_ESC, *dst++ = 'O';             \
-    else                                               \
-      *dst++ = ISO_CODE_SS3;                           \
-    CODING_SPEC_ISO_SINGLE_SHIFTING (coding) = 1;      \
+
+#define ENCODE_SINGLE_SHIFT_3                                          \
+  do {                                                                 \
+    if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SEVEN_BITS)                \
+      EMIT_TWO_ASCII_BYTES (ISO_CODE_ESC, 'O');                                \
+    else                                                               \
+      EMIT_ONE_BYTE (ISO_CODE_SS3);                                    \
+    CODING_ISO_SINGLE_SHIFTING (coding) = 1;                           \
   } while (0)
 
+
 /* The following four macros produce codes (control character or
    escape sequence) for ISO2022 locking-shift functions (shift-in,
    shift-out, locking-shift-2, and locking-shift-3).  */
 
-#define ENCODE_SHIFT_IN                                \
-  do {                                         \
-    *dst++ = ISO_CODE_SI;                      \
-    CODING_SPEC_ISO_INVOCATION (coding, 0) = 0;        \
+#define ENCODE_SHIFT_IN                                        \
+  do {                                                 \
+    EMIT_ONE_ASCII_BYTE (ISO_CODE_SI);                 \
+    CODING_ISO_INVOCATION (coding, 0) = 0;             \
   } while (0)
 
-#define ENCODE_SHIFT_OUT                       \
-  do {                                         \
-    *dst++ = ISO_CODE_SO;                      \
-    CODING_SPEC_ISO_INVOCATION (coding, 0) = 1;        \
+
+#define ENCODE_SHIFT_OUT                               \
+  do {                                                 \
+    EMIT_ONE_ASCII_BYTE (ISO_CODE_SO);                 \
+    CODING_ISO_INVOCATION (coding, 0) = 1;             \
   } while (0)
 
-#define ENCODE_LOCKING_SHIFT_2                 \
-  do {                                         \
-    *dst++ = ISO_CODE_ESC, *dst++ = 'n';       \
-    CODING_SPEC_ISO_INVOCATION (coding, 0) = 2;        \
+
+#define ENCODE_LOCKING_SHIFT_2                         \
+  do {                                                 \
+    EMIT_TWO_ASCII_BYTES (ISO_CODE_ESC, 'n');          \
+    CODING_ISO_INVOCATION (coding, 0) = 2;             \
   } while (0)
 
-#define ENCODE_LOCKING_SHIFT_3                 \
-  do {                                         \
-    *dst++ = ISO_CODE_ESC, *dst++ = 'o';       \
-    CODING_SPEC_ISO_INVOCATION (coding, 0) = 3;        \
+
+#define ENCODE_LOCKING_SHIFT_3                         \
+  do {                                                 \
+    EMIT_TWO_ASCII_BYTES (ISO_CODE_ESC, 'n');          \
+    CODING_ISO_INVOCATION (coding, 0) = 3;             \
   } while (0)
 
+
 /* Produce codes for a DIMENSION1 character whose character set is
    CHARSET and whose position-code is C1.  Designation and invocation
    sequences are also produced in advance if necessary.  */
 
 #define ENCODE_ISO_CHARACTER_DIMENSION1(charset, c1)                   \
   do {                                                                 \
-    if (CODING_SPEC_ISO_SINGLE_SHIFTING (coding))                      \
+    int id = CHARSET_ID (charset);                                     \
+                                                                       \
+    if ((CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_USE_ROMAN)                \
+       && id == charset_ascii)                                         \
+      {                                                                        \
+       id = charset_jisx0201_roman;                                    \
+       charset = CHARSET_FROM_ID (id);                                 \
+      }                                                                        \
+                                                                       \
+    if (CODING_ISO_SINGLE_SHIFTING (coding))                           \
       {                                                                        \
-       if (coding->flags & CODING_FLAG_ISO_SEVEN_BITS)                 \
-         *dst++ = c1 & 0x7F;                                           \
+       if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SEVEN_BITS)     \
+         EMIT_ONE_ASCII_BYTE (c1 & 0x7F);                              \
        else                                                            \
-         *dst++ = c1 | 0x80;                                           \
-       CODING_SPEC_ISO_SINGLE_SHIFTING (coding) = 0;                   \
+         EMIT_ONE_BYTE (c1 | 0x80);                                    \
+       CODING_ISO_SINGLE_SHIFTING (coding) = 0;                        \
        break;                                                          \
       }                                                                        \
-    else if (charset == CODING_SPEC_ISO_PLANE_CHARSET (coding, 0))     \
+    else if (id == CODING_ISO_INVOKED_CHARSET (coding, 0))             \
       {                                                                        \
-       *dst++ = c1 & 0x7F;                                             \
+       EMIT_ONE_ASCII_BYTE (c1 & 0x7F);                                \
        break;                                                          \
       }                                                                        \
-    else if (charset == CODING_SPEC_ISO_PLANE_CHARSET (coding, 1))     \
+    else if (id == CODING_ISO_INVOKED_CHARSET (coding, 1))             \
       {                                                                        \
-       *dst++ = c1 | 0x80;                                             \
+       EMIT_ONE_BYTE (c1 | 0x80);                                      \
        break;                                                          \
       }                                                                        \
     else                                                               \
@@ -2331,32 +3396,43 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
         must invoke it, or, at first, designate it to some graphic     \
         register.  Then repeat the loop to actually produce the        \
         character.  */                                                 \
-      dst = encode_invocation_designation (charset, coding, dst);      \
+      dst = encode_invocation_designation (charset, coding, dst,       \
+                                          &produced_chars);            \
   } while (1)
 
+
 /* Produce codes for a DIMENSION2 character whose character set is
    CHARSET and whose position-codes are C1 and C2.  Designation and
    invocation codes are also produced in advance if necessary.  */
 
 #define ENCODE_ISO_CHARACTER_DIMENSION2(charset, c1, c2)               \
   do {                                                                 \
-    if (CODING_SPEC_ISO_SINGLE_SHIFTING (coding))                      \
+    int id = CHARSET_ID (charset);                                     \
+                                                                       \
+    if ((CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_USE_OLDJIS)       \
+       && id == charset_jisx0208)                                      \
+      {                                                                        \
+       id = charset_jisx0208_1978;                                     \
+       charset = CHARSET_FROM_ID (id);                                 \
+      }                                                                        \
+                                                                       \
+    if (CODING_ISO_SINGLE_SHIFTING (coding))                           \
       {                                                                        \
-       if (coding->flags & CODING_FLAG_ISO_SEVEN_BITS)                 \
-         *dst++ = c1 & 0x7F, *dst++ = c2 & 0x7F;                       \
+       if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SEVEN_BITS)     \
+         EMIT_TWO_ASCII_BYTES ((c1) & 0x7F, (c2) & 0x7F);              \
        else                                                            \
-         *dst++ = c1 | 0x80, *dst++ = c2 | 0x80;                       \
-       CODING_SPEC_ISO_SINGLE_SHIFTING (coding) = 0;                   \
+         EMIT_TWO_BYTES ((c1) | 0x80, (c2) | 0x80);                    \
+       CODING_ISO_SINGLE_SHIFTING (coding) = 0;                        \
        break;                                                          \
       }                                                                        \
-    else if (charset == CODING_SPEC_ISO_PLANE_CHARSET (coding, 0))     \
+    else if (id == CODING_ISO_INVOKED_CHARSET (coding, 0))             \
       {                                                                        \
-       *dst++ = c1 & 0x7F, *dst++= c2 & 0x7F;                          \
+       EMIT_TWO_ASCII_BYTES ((c1) & 0x7F, (c2) & 0x7F);                \
        break;                                                          \
       }                                                                        \
-    else if (charset == CODING_SPEC_ISO_PLANE_CHARSET (coding, 1))     \
+    else if (id == CODING_ISO_INVOKED_CHARSET (coding, 1))             \
       {                                                                        \
-       *dst++ = c1 | 0x80, *dst++= c2 | 0x80;                          \
+       EMIT_TWO_BYTES ((c1) | 0x80, (c2) | 0x80);                      \
        break;                                                          \
       }                                                                        \
     else                                                               \
@@ -2364,73 +3440,49 @@ decode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
         must invoke it, or, at first, designate it to some graphic     \
         register.  Then repeat the loop to actually produce the        \
         character.  */                                                 \
-      dst = encode_invocation_designation (charset, coding, dst);      \
+      dst = encode_invocation_designation (charset, coding, dst,       \
+                                          &produced_chars);            \
   } while (1)
 
-#define ENCODE_ISO_CHARACTER(c)                                        \
-  do {                                                         \
-    int charset, c1, c2;                                       \
-                                                               \
-    SPLIT_CHAR (c, charset, c1, c2);                           \
-    if (CHARSET_DEFINED_P (charset))                           \
-      {                                                                \
-       if (CHARSET_DIMENSION (charset) == 1)                   \
-         {                                                     \
-           if (charset == CHARSET_ASCII                        \
-               && coding->flags & CODING_FLAG_ISO_USE_ROMAN)   \
-             charset = charset_latin_jisx0201;                 \
-           ENCODE_ISO_CHARACTER_DIMENSION1 (charset, c1);      \
-         }                                                     \
-       else                                                    \
-         {                                                     \
-           if (charset == charset_jisx0208                     \
-               && coding->flags & CODING_FLAG_ISO_USE_OLDJIS)  \
-             charset = charset_jisx0208_1978;                  \
-           ENCODE_ISO_CHARACTER_DIMENSION2 (charset, c1, c2);  \
-         }                                                     \
-      }                                                                \
-    else                                                       \
-      {                                                                \
-       *dst++ = c1;                                            \
-       if (c2 >= 0)                                            \
-         *dst++ = c2;                                          \
-      }                                                                \
-  } while (0)
-
-
-/* Instead of encoding character C, produce one or two `?'s.  */
 
-#define ENCODE_UNSAFE_CHARACTER(c)                             \
-  do {                                                         \
-    ENCODE_ISO_CHARACTER (CODING_REPLACEMENT_CHARACTER);       \
-    if (CHARSET_WIDTH (CHAR_CHARSET (c)) > 1)                  \
-      ENCODE_ISO_CHARACTER (CODING_REPLACEMENT_CHARACTER);     \
+#define ENCODE_ISO_CHARACTER(charset, c)                                  \
+  do {                                                                    \
+    int code = ENCODE_CHAR ((charset),(c));                               \
+                                                                          \
+    if (CHARSET_DIMENSION (charset) == 1)                                 \
+      ENCODE_ISO_CHARACTER_DIMENSION1 ((charset), code);                  \
+    else                                                                  \
+      ENCODE_ISO_CHARACTER_DIMENSION2 ((charset), code >> 8, code & 0xFF); \
   } while (0)
 
 
 /* Produce designation and invocation codes at a place pointed by DST
-   to use CHARSET.  The element `spec.iso2022' of *CODING is updated.
+   to use CHARSET.  The element `spec.iso_2022' of *CODING is updated.
    Return new DST.  */
 
 unsigned char *
-encode_invocation_designation (charset, coding, dst)
-     int charset;
+encode_invocation_designation (charset, coding, dst, p_nchars)
+     struct charset *charset;
      struct coding_system *coding;
      unsigned char *dst;
+     int *p_nchars;
 {
+  int multibytep = coding->dst_multibyte;
+  int produced_chars = *p_nchars;
   int reg;                     /* graphic register number */
+  int id = CHARSET_ID (charset);
 
   /* At first, check designations.  */
   for (reg = 0; reg < 4; reg++)
-    if (charset == CODING_SPEC_ISO_DESIGNATION (coding, reg))
+    if (id == CODING_ISO_DESIGNATION (coding, reg))
       break;
 
   if (reg >= 4)
     {
       /* CHARSET is not yet designated to any graphic registers.  */
       /* At first check the requested designation.  */
-      reg = CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding, charset);
-      if (reg == CODING_SPEC_ISO_NO_REQUESTED_DESIGNATION)
+      reg = CODING_ISO_REQUEST (coding, id);
+      if (reg < 0)
        /* Since CHARSET requests no special designation, designate it
           to graphic register 0.  */
        reg = 0;
@@ -2438,8 +3490,8 @@ encode_invocation_designation (charset, coding, dst)
       ENCODE_DESIGNATION (charset, reg, coding);
     }
 
-  if (CODING_SPEC_ISO_INVOCATION (coding, 0) != reg
-      && CODING_SPEC_ISO_INVOCATION (coding, 1) != reg)
+  if (CODING_ISO_INVOCATION (coding, 0) != reg
+      && CODING_ISO_INVOCATION (coding, 1) != reg)
     {
       /* Since the graphic register REG is not invoked to any graphic
         planes, invoke it to graphic plane 0.  */
@@ -2454,14 +3506,14 @@ encode_invocation_designation (charset, coding, dst)
          break;
 
        case 2:                 /* graphic register 2 */
-         if (coding->flags & CODING_FLAG_ISO_SINGLE_SHIFT)
+         if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SINGLE_SHIFT)
            ENCODE_SINGLE_SHIFT_2;
          else
            ENCODE_LOCKING_SHIFT_2;
          break;
 
        case 3:                 /* graphic register 3 */
-         if (coding->flags & CODING_FLAG_ISO_SINGLE_SHIFT)
+         if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_SINGLE_SHIFT)
            ENCODE_SINGLE_SHIFT_3;
          else
            ENCODE_LOCKING_SHIFT_3;
@@ -2469,98 +3521,55 @@ encode_invocation_designation (charset, coding, dst)
        }
     }
 
+  *p_nchars = produced_chars;
   return dst;
 }
 
-/* Produce 2-byte codes for encoded composition rule RULE.  */
-
-#define ENCODE_COMPOSITION_RULE(rule)          \
-  do {                                         \
-    int gref, nref;                            \
-    COMPOSITION_DECODE_RULE (rule, gref, nref);        \
-    *dst++ = 32 + 81 + gref;                   \
-    *dst++ = 32 + nref;                                \
-  } while (0)
-
-/* Produce codes for indicating the start of a composition sequence
-   (ESC 0, ESC 3, or ESC 4).  DATA points to an array of integers
-   which specify information about the composition.  See the comment
-   in coding.h for the format of DATA.  */
-
-#define ENCODE_COMPOSITION_START(coding, data)                         \
+/* The following three macros produce codes for indicating direction
+   of text.  */
+#define ENCODE_CONTROL_SEQUENCE_INTRODUCER                             \
   do {                                                                 \
-    coding->composing = data[3];                                       \
-    *dst++ = ISO_CODE_ESC;                                             \
-    if (coding->composing == COMPOSITION_RELATIVE)                     \
-      *dst++ = '0';                                                    \
+    if (CODING_ISO_FLAGS (coding) == CODING_ISO_FLAG_SEVEN_BITS)       \
+      EMIT_TWO_ASCII_BYTES (ISO_CODE_ESC, '[');                                \
     else                                                               \
-      {                                                                        \
-       *dst++ = (coding->composing == COMPOSITION_WITH_ALTCHARS        \
-                 ? '3' : '4');                                         \
-       coding->cmp_data_index = coding->cmp_data_start + 4;            \
-       coding->composition_rule_follows = 0;                           \
-      }                                                                        \
+      EMIT_ONE_BYTE (ISO_CODE_CSI);                                    \
   } while (0)
 
-/* Produce codes for indicating the end of the current composition.  */
 
-#define ENCODE_COMPOSITION_END(coding, data)                   \
-  do {                                                         \
-    *dst++ = ISO_CODE_ESC;                                     \
-    *dst++ = '1';                                              \
-    coding->cmp_data_start += data[0];                         \
-    coding->composing = COMPOSITION_NO;                                \
-    if (coding->cmp_data_start == coding->cmp_data->used       \
-       && coding->cmp_data->next)                              \
-      {                                                                \
-       coding->cmp_data = coding->cmp_data->next;              \
-       coding->cmp_data_start = 0;                             \
-      }                                                                \
+#define ENCODE_DIRECTION_R2L()                 \
+  do {                                         \
+    ENCODE_CONTROL_SEQUENCE_INTRODUCER (dst);  \
+    EMIT_TWO_ASCII_BYTES ('2', ']');           \
   } while (0)
 
-/* Produce composition start sequence ESC 0.  Here, this sequence
-   doesn't mean the start of a new composition but means that we have
-   just produced components (alternate chars and composition rules) of
-   the composition and the actual text follows in SRC.  */
 
-#define ENCODE_COMPOSITION_FAKE_START(coding)  \
+#define ENCODE_DIRECTION_L2R()                 \
   do {                                         \
-    *dst++ = ISO_CODE_ESC;                     \
-    *dst++ = '0';                              \
-    coding->composing = COMPOSITION_RELATIVE;  \
+    ENCODE_CONTROL_SEQUENCE_INTRODUCER (dst);  \
+    EMIT_TWO_ASCII_BYTES ('0', ']');           \
   } while (0)
 
-/* The following three macros produce codes for indicating direction
-   of text.  */
-#define ENCODE_CONTROL_SEQUENCE_INTRODUCER             \
-  do {                                                 \
-    if (coding->flags == CODING_FLAG_ISO_SEVEN_BITS)   \
-      *dst++ = ISO_CODE_ESC, *dst++ = '[';             \
-    else                                               \
-      *dst++ = ISO_CODE_CSI;                           \
-  } while (0)
-
-#define ENCODE_DIRECTION_R2L   \
-  ENCODE_CONTROL_SEQUENCE_INTRODUCER (dst), *dst++ = '2', *dst++ = ']'
-
-#define ENCODE_DIRECTION_L2R   \
-  ENCODE_CONTROL_SEQUENCE_INTRODUCER (dst), *dst++ = '0', *dst++ = ']'
 
 /* Produce codes for designation and invocation to reset the graphic
    planes and registers to initial state.  */
-#define ENCODE_RESET_PLANE_AND_REGISTER                                            \
-  do {                                                                     \
-    int reg;                                                               \
-    if (CODING_SPEC_ISO_INVOCATION (coding, 0) != 0)                       \
-      ENCODE_SHIFT_IN;                                                     \
-    for (reg = 0; reg < 4; reg++)                                          \
-      if (CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, reg) >= 0           \
-         && (CODING_SPEC_ISO_DESIGNATION (coding, reg)                     \
-             != CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, reg)))        \
-       ENCODE_DESIGNATION                                                  \
-         (CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, reg), reg, coding); \
+#define ENCODE_RESET_PLANE_AND_REGISTER()                              \
+  do {                                                                 \
+    int reg;                                                           \
+    struct charset *charset;                                           \
+                                                                       \
+    if (CODING_ISO_INVOCATION (coding, 0) != 0)                                \
+      ENCODE_SHIFT_IN;                                                 \
+    for (reg = 0; reg < 4; reg++)                                      \
+      if (CODING_ISO_INITIAL (coding, reg) >= 0                                \
+         && (CODING_ISO_DESIGNATION (coding, reg)                      \
+             != CODING_ISO_INITIAL (coding, reg)))                     \
+       {                                                               \
+         charset = CHARSET_FROM_ID (CODING_ISO_INITIAL (coding, reg)); \
+         ENCODE_DESIGNATION (charset, reg, coding);                    \
+       }                                                               \
   } while (0)
 
+
 /* Produce designation sequences of charsets in the line started from
    SRC to a place pointed by DST, and return updated DST.
 
@@ -2568,40 +3577,51 @@ encode_invocation_designation (charset, coding, dst)
    find all the necessary designations.  */
 
 static unsigned char *
-encode_designation_at_bol (coding, translation_table, src, src_end, dst)
+encode_designation_at_bol (coding, charbuf, charbuf_end, dst)
      struct coding_system *coding;
-     Lisp_Object translation_table;
-     unsigned char *src, *src_end, *dst;
+     int *charbuf, *charbuf_end;
+     unsigned char *dst;
 {
-  int charset, c, found = 0, reg;
+  struct charset *charset;
   /* Table of charsets to be designated to each graphic register.  */
   int r[4];
+  int c, found = 0, reg;
+  int produced_chars = 0;
+  int multibytep = coding->dst_multibyte;
+  Lisp_Object attrs;
+  Lisp_Object charset_list;
+
+  attrs = CODING_ID_ATTRS (coding->id);
+  charset_list = CODING_ATTR_CHARSET_LIST (attrs);
+  if (EQ (charset_list, Qiso_2022))
+    charset_list = Viso_2022_charset_list;
 
   for (reg = 0; reg < 4; reg++)
     r[reg] = -1;
 
   while (found < 4)
     {
-      ONE_MORE_CHAR (c);
+      int id;
+
+      c = *charbuf++;
       if (c == '\n')
        break;
-
-      charset = CHAR_CHARSET (c);
-      reg = CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding, charset);
-      if (reg != CODING_SPEC_ISO_NO_REQUESTED_DESIGNATION && r[reg] < 0)
+      charset = char_charset (c, charset_list, NULL);
+      id = CHARSET_ID (charset);
+      reg = CODING_ISO_REQUEST (coding, id);
+      if (reg >= 0 && r[reg] < 0)
        {
          found++;
-         r[reg] = charset;
+         r[reg] = id;
        }
     }
 
- label_end_of_loop:
   if (found)
     {
       for (reg = 0; reg < 4; reg++)
        if (r[reg] >= 0
-           && CODING_SPEC_ISO_DESIGNATION (coding, reg) != r[reg])
-         ENCODE_DESIGNATION (r[reg], reg, coding);
+           && CODING_ISO_DESIGNATION (coding, reg) != r[reg])
+         ENCODE_DESIGNATION (CHARSET_FROM_ID (r[reg]), reg, coding);
     }
 
   return dst;
@@ -2609,187 +3629,156 @@ encode_designation_at_bol (coding, translation_table, src, src_end, dst)
 
 /* See the above "GENERAL NOTES on `encode_coding_XXX ()' functions".  */
 
-static void
-encode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
+static int
+encode_coding_iso_2022 (coding)
      struct coding_system *coding;
-     unsigned char *source, *destination;
-     int src_bytes, dst_bytes;
 {
-  unsigned char *src = source;
-  unsigned char *src_end = source + src_bytes;
-  unsigned char *dst = destination;
-  unsigned char *dst_end = destination + dst_bytes;
-  /* Since the maximum bytes produced by each loop is 20, we subtract 19
-     from DST_END to assure overflow checking is necessary only at the
-     head of loop.  */
-  unsigned char *adjusted_dst_end = dst_end - 19;
-  /* SRC_BASE remembers the start position in source in each loop.
-     The loop will be exited when there's not enough source text to
-     analyze multi-byte codes (within macro ONE_MORE_CHAR), or when
-     there's not enough destination area to produce encoded codes
-     (within macro EMIT_BYTES).  */
-  unsigned char *src_base;
+  int multibytep = coding->dst_multibyte;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf + coding->charbuf_used;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  int safe_room = 16;
+  int bol_designation
+    = (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_DESIGNATE_AT_BOL
+       && CODING_ISO_BOL (coding));
+  int produced_chars = 0;
+  Lisp_Object attrs, eol_type, charset_list;
+  int ascii_compatible;
   int c;
-  Lisp_Object translation_table;
-  Lisp_Object safe_chars;
+  int preferred_charset_id = -1;
 
-  if (coding->flags & CODING_FLAG_ISO_SAFE)
-    coding->mode |= CODING_MODE_INHIBIT_UNENCODABLE_CHAR;
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+  setup_iso_safe_charsets (attrs);
+  /* Charset list may have been changed.  */
+  charset_list = CODING_ATTR_CHARSET_LIST (attrs);             \
+  coding->safe_charsets = (char *) SDATA (CODING_ATTR_SAFE_CHARSETS(attrs));
 
-  safe_chars = coding_safe_chars (coding->symbol);
+  ascii_compatible = ! NILP (CODING_ATTR_ASCII_COMPAT (attrs));
 
-  if (NILP (Venable_character_translation))
-    translation_table = Qnil;
-  else
-    {
-      translation_table = coding->translation_table_for_encode;
-      if (NILP (translation_table))
-       translation_table = Vstandard_translation_table_for_encode;
-    }
-
-  coding->consumed_char = 0;
-  coding->errors = 0;
-  while (1)
+  while (charbuf < charbuf_end)
     {
-      src_base = src;
+      ASSURE_DESTINATION (safe_room);
 
-      if (dst >= (dst_bytes ? adjusted_dst_end : (src - 19)))
+      if (bol_designation)
        {
-         coding->result = CODING_FINISH_INSUFFICIENT_DST;
-         break;
-       }
+         unsigned char *dst_prev = dst;
 
-      if (coding->flags & CODING_FLAG_ISO_DESIGNATE_AT_BOL
-         && CODING_SPEC_ISO_BOL (coding))
-       {
          /* We have to produce designation sequences if any now.  */
-         dst = encode_designation_at_bol (coding, translation_table,
-                                          src, src_end, dst);
-         CODING_SPEC_ISO_BOL (coding) = 0;
+         dst = encode_designation_at_bol (coding, charbuf, charbuf_end, dst);
+         bol_designation = 0;
+         /* We are sure that designation sequences are all ASCII bytes.  */
+         produced_chars += dst - dst_prev;
        }
 
-      /* Check composition start and end.  */
-      if (coding->composing != COMPOSITION_DISABLED
-         && coding->cmp_data_start < coding->cmp_data->used)
-       {
-         struct composition_data *cmp_data = coding->cmp_data;
-         int *data = cmp_data->data + coding->cmp_data_start;
-         int this_pos = cmp_data->char_offset + coding->consumed_char;
+      c = *charbuf++;
 
-         if (coding->composing == COMPOSITION_RELATIVE)
-           {
-             if (this_pos == data[2])
-               {
-                 ENCODE_COMPOSITION_END (coding, data);
-                 cmp_data = coding->cmp_data;
-                 data = cmp_data->data + coding->cmp_data_start;
-               }
-           }
-         else if (COMPOSING_P (coding))
-           {
-             /* COMPOSITION_WITH_ALTCHARS or COMPOSITION_WITH_RULE_ALTCHAR  */
-             if (coding->cmp_data_index == coding->cmp_data_start + data[0])
-               /* We have consumed components of the composition.
-                   What follows in SRC is the composition's base
-                   text.  */
-               ENCODE_COMPOSITION_FAKE_START (coding);
-             else
-               {
-                 int c = cmp_data->data[coding->cmp_data_index++];
-                 if (coding->composition_rule_follows)
-                   {
-                     ENCODE_COMPOSITION_RULE (c);
-                     coding->composition_rule_follows = 0;
-                   }
-                 else
-                   {
-                     if (coding->mode & CODING_MODE_INHIBIT_UNENCODABLE_CHAR
-                         && ! CODING_SAFE_CHAR_P (safe_chars, c))
-                       ENCODE_UNSAFE_CHARACTER (c);
-                     else
-                       ENCODE_ISO_CHARACTER (c);
-                     if (coding->composing == COMPOSITION_WITH_RULE_ALTCHARS)
-                       coding->composition_rule_follows = 1;
-                   }
-                 continue;
-               }
-           }
-         if (!COMPOSING_P (coding))
+      if (c < 0)
+       {
+         /* Handle an annotation.  */
+         switch (*charbuf)
            {
-             if (this_pos == data[1])
-               {
-                 ENCODE_COMPOSITION_START (coding, data);
-                 continue;
-               }
+           case CODING_ANNOTATE_COMPOSITION_MASK:
+             /* Not yet implemented.  */
+             break;
+           case CODING_ANNOTATE_CHARSET_MASK:
+             preferred_charset_id = charbuf[3];
+             if (preferred_charset_id >= 0
+                 && NILP (Fmemq (make_number (preferred_charset_id),
+                                 charset_list)))
+               preferred_charset_id = -1;
+             break;
+           default:
+             abort ();
            }
+         charbuf += -c - 1;
+         continue;
        }
 
-      ONE_MORE_CHAR (c);
-
       /* Now encode the character C.  */
       if (c < 0x20 || c == 0x7F)
        {
-         if (c == '\r')
+         if (c == '\n'
+             || (c == '\r' && EQ (eol_type, Qmac)))
            {
-             if (! (coding->mode & CODING_MODE_SELECTIVE_DISPLAY))
+             if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_RESET_AT_EOL)
+               ENCODE_RESET_PLANE_AND_REGISTER ();
+             if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_INIT_AT_BOL)
                {
-                 if (coding->flags & CODING_FLAG_ISO_RESET_AT_CNTL)
-                   ENCODE_RESET_PLANE_AND_REGISTER;
-                 *dst++ = c;
-                 continue;
+                 int i;
+
+                 for (i = 0; i < 4; i++)
+                   CODING_ISO_DESIGNATION (coding, i)
+                     = CODING_ISO_INITIAL (coding, i);
                }
-             /* fall down to treat '\r' as '\n' ...  */
-             c = '\n';
-           }
-         if (c == '\n')
-           {
-             if (coding->flags & CODING_FLAG_ISO_RESET_AT_EOL)
-               ENCODE_RESET_PLANE_AND_REGISTER;
-             if (coding->flags & CODING_FLAG_ISO_INIT_AT_BOL)
-               bcopy (coding->spec.iso2022.initial_designation,
-                      coding->spec.iso2022.current_designation,
-                      sizeof coding->spec.iso2022.initial_designation);
-             if (coding->eol_type == CODING_EOL_LF
-                 || coding->eol_type == CODING_EOL_UNDECIDED)
-               *dst++ = ISO_CODE_LF;
-             else if (coding->eol_type == CODING_EOL_CRLF)
-               *dst++ = ISO_CODE_CR, *dst++ = ISO_CODE_LF;
-             else
-               *dst++ = ISO_CODE_CR;
-             CODING_SPEC_ISO_BOL (coding) = 1;
+             bol_designation
+               = CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_DESIGNATE_AT_BOL;
            }
+         else if (CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_RESET_AT_CNTL)
+           ENCODE_RESET_PLANE_AND_REGISTER ();
+         EMIT_ONE_ASCII_BYTE (c);
+       }
+      else if (ASCII_CHAR_P (c))
+       {
+         if (ascii_compatible)
+           EMIT_ONE_ASCII_BYTE (c);
          else
            {
-             if (coding->flags & CODING_FLAG_ISO_RESET_AT_CNTL)
-               ENCODE_RESET_PLANE_AND_REGISTER;
-             *dst++ = c;
+             struct charset *charset = CHARSET_FROM_ID (charset_ascii);
+             ENCODE_ISO_CHARACTER (charset, c);
            }
        }
-      else if (ASCII_BYTE_P (c))
-       ENCODE_ISO_CHARACTER (c);
-      else if (SINGLE_BYTE_CHAR_P (c))
+      else if (CHAR_BYTE8_P (c))
        {
-         *dst++ = c;
-         coding->errors++;
+         c = CHAR_TO_BYTE8 (c);
+         EMIT_ONE_BYTE (c);
        }
-      else if (coding->mode & CODING_MODE_INHIBIT_UNENCODABLE_CHAR
-              && ! CODING_SAFE_CHAR_P (safe_chars, c))
-       ENCODE_UNSAFE_CHARACTER (c);
       else
-       ENCODE_ISO_CHARACTER (c);
+       {
+         struct charset *charset;
 
-      coding->consumed_char++;
+         if (preferred_charset_id >= 0)
+           {
+             charset = CHARSET_FROM_ID (preferred_charset_id);
+             if (! CHAR_CHARSET_P (c, charset))
+               charset = char_charset (c, charset_list, NULL);
+           }
+         else
+           charset = char_charset (c, charset_list, NULL);
+         if (!charset)
+           {
+             if (coding->mode & CODING_MODE_SAFE_ENCODING)
+               {
+                 c = CODING_INHIBIT_CHARACTER_SUBSTITUTION;
+                 charset = CHARSET_FROM_ID (charset_ascii);
+               }
+             else
+               {
+                 c = coding->default_char;
+                 charset = char_charset (c, charset_list, NULL);
+               }
+           }
+         ENCODE_ISO_CHARACTER (charset, c);
+       }
     }
 
- label_end_of_loop:
-  coding->consumed = src_base - source;
-  coding->produced = coding->produced_char = dst - destination;
+  if (coding->mode & CODING_MODE_LAST_BLOCK
+      && CODING_ISO_FLAGS (coding) & CODING_ISO_FLAG_RESET_AT_EOL)
+    {
+      ASSURE_DESTINATION (safe_room);
+      ENCODE_RESET_PLANE_AND_REGISTER ();
+    }
+  coding->result = CODING_RESULT_SUCCESS;
+  CODING_ISO_BOL (coding) = bol_designation;
+  coding->produced_char += produced_chars;
+  coding->produced = dst - coding->destination;
+  return 0;
 }
 
 \f
-/*** 4. SJIS and BIG5 handlers ***/
+/*** 8,9. SJIS and BIG5 handlers ***/
 
-/* Although SJIS and BIG5 are not ISO coding systems, they are used
+/* Although SJIS and BIG5 are not ISO's coding system, they are used
    quite widely.  So, for the moment, Emacs supports them in the bare
    C code.  But, in the future, they may be supported only by CCL.  */
 
@@ -2798,12 +3787,12 @@ encode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
    as is.  A character of charset katakana-jisx0201 is encoded by
    "position-code + 0x80".  A character of charset japanese-jisx0208
    is encoded in 2-byte but two position-codes are divided and shifted
-   so that it fits in the range below.
+   so that it fit in the range below.
 
    --- CODE RANGE of SJIS ---
    (character set)     (range)
    ASCII               0x00 .. 0x7F
-   KATAKANA-JISX0201   0xA1 .. 0xDF
+   KATAKANA-JISX0201   0xA0 .. 0xDF
    JISX0208 (1st byte) 0x81 .. 0x9F and 0xE0 .. 0xEF
            (2nd byte)  0x40 .. 0x7E and 0x80 .. 0xFC
    -------------------------------
@@ -2812,7 +3801,7 @@ encode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
 
 /* BIG5 is a coding system encoding two character sets: ASCII and
    Big5.  An ASCII character is encoded as is.  Big5 is a two-byte
-   character set and is encoded in two bytes.
+   character set and is encoded in two-byte.
 
    --- CODE RANGE of BIG5 ---
    (character set)     (range)
@@ -2821,315 +3810,321 @@ encode_coding_iso2022 (coding, source, destination, src_bytes, dst_bytes)
        (2nd byte)      0x40 .. 0x7E and 0xA1 .. 0xFE
    --------------------------
 
-   Since the number of characters in Big5 is larger than maximum
-   characters in Emacs' charset (96x96), it can't be handled as one
-   charset.  So, in Emacs, Big5 is divided into two: `charset-big5-1'
-   and `charset-big5-2'.  Both are DIMENSION2 and CHARS94.  The former
-   contains frequently used characters and the latter contains less
-   frequently used characters.  */
-
-/* Macros to decode or encode a character of Big5 in BIG5.  B1 and B2
-   are the 1st and 2nd position-codes of Big5 in BIG5 coding system.
-   C1 and C2 are the 1st and 2nd position-codes of Emacs' internal
-   format.  CHARSET is `charset_big5_1' or `charset_big5_2'.  */
-
-/* Number of Big5 characters which have the same code in 1st byte.  */
-#define BIG5_SAME_ROW (0xFF - 0xA1 + 0x7F - 0x40)
-
-#define DECODE_BIG5(b1, b2, charset, c1, c2)                           \
-  do {                                                                 \
-    unsigned int temp                                                  \
-      = (b1 - 0xA1) * BIG5_SAME_ROW + b2 - (b2 < 0x7F ? 0x40 : 0x62);  \
-    if (b1 < 0xC9)                                                     \
-      charset = charset_big5_1;                                                \
-    else                                                               \
-      {                                                                        \
-       charset = charset_big5_2;                                       \
-       temp -= (0xC9 - 0xA1) * BIG5_SAME_ROW;                          \
-      }                                                                        \
-    c1 = temp / (0xFF - 0xA1) + 0x21;                                  \
-    c2 = temp % (0xFF - 0xA1) + 0x21;                                  \
-  } while (0)
-
-#define ENCODE_BIG5(charset, c1, c2, b1, b2)                           \
-  do {                                                                 \
-    unsigned int temp = (c1 - 0x21) * (0xFF - 0xA1) + (c2 - 0x21);     \
-    if (charset == charset_big5_2)                                     \
-      temp += BIG5_SAME_ROW * (0xC9 - 0xA1);                           \
-    b1 = temp / BIG5_SAME_ROW + 0xA1;                                  \
-    b2 = temp % BIG5_SAME_ROW;                                         \
-    b2 += b2 < 0x3F ? 0x40 : 0x62;                                     \
-  } while (0)
+  */
 
 /* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
    Check if a text is encoded in SJIS.  If it is, return
-   CODING_CATEGORY_MASK_SJIS, else return 0.  */
+   CATEGORY_MASK_SJIS, else return 0.  */
 
 static int
-detect_coding_sjis (src, src_end, multibytep)
-     unsigned char *src, *src_end;
-     int multibytep;
+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_end = coding->source + coding->src_bytes;
+  int multibytep = coding->src_multibyte;
+  int consumed_chars = 0;
+  int found = 0;
   int c;
-  /* Dummy for ONE_MORE_BYTE.  */
-  struct coding_system dummy_coding;
-  struct coding_system *coding = &dummy_coding;
+  int incomplete;
+
+  detect_info->checked |= CATEGORY_MASK_SJIS;
+  /* A coding system of this category is always ASCII compatible.  */
+  src += coding->head_ascii;
 
   while (1)
     {
-      ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
+      incomplete = 0;
+      ONE_MORE_BYTE (c);
+      incomplete = 1;
       if (c < 0x80)
        continue;
-      if (c == 0x80 || c == 0xA0 || c > 0xEF)
-       return 0;
-      if (c <= 0x9F || c >= 0xE0)
+      if ((c >= 0x81 && c <= 0x9F) || (c >= 0xE0 && c <= 0xEF))
        {
-         ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
+         ONE_MORE_BYTE (c);
          if (c < 0x40 || c == 0x7F || c > 0xFC)
-           return 0;
+           break;
+         found = CATEGORY_MASK_SJIS;
        }
+      else if (c >= 0xA0 && c < 0xE0)
+       found = CATEGORY_MASK_SJIS;
+      else
+       break;
+    }
+  detect_info->rejected |= CATEGORY_MASK_SJIS;
+  return 0;
+
+ no_more_source:
+  if (incomplete && coding->mode & CODING_MODE_LAST_BLOCK)
+    {
+      detect_info->rejected |= CATEGORY_MASK_SJIS;
+      return 0;
     }
- label_end_of_loop:
-  return CODING_CATEGORY_MASK_SJIS;
+  detect_info->found |= found;
+  return 1;
 }
 
 /* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
    Check if a text is encoded in BIG5.  If it is, return
-   CODING_CATEGORY_MASK_BIG5, else return 0.  */
+   CATEGORY_MASK_BIG5, else return 0.  */
 
 static int
-detect_coding_big5 (src, src_end, multibytep)
-     unsigned char *src, *src_end;
-     int multibytep;
+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_end = coding->source + coding->src_bytes;
+  int multibytep = coding->src_multibyte;
+  int consumed_chars = 0;
+  int found = 0;
   int c;
-  /* Dummy for ONE_MORE_BYTE.  */
-  struct coding_system dummy_coding;
-  struct coding_system *coding = &dummy_coding;
-
-  while (1)
-    {
-      ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
-      if (c < 0x80)
-       continue;
-      if (c < 0xA1 || c > 0xFE)
-       return 0;
-      ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
-      if (c < 0x40 || (c > 0x7F && c < 0xA1) || c > 0xFE)
-       return 0;
-    }
- label_end_of_loop:
-  return CODING_CATEGORY_MASK_BIG5;
-}
-
-/* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
-   Check if a text is encoded in UTF-8.  If it is, return
-   CODING_CATEGORY_MASK_UTF_8, else return 0.  */
-
-#define UTF_8_1_OCTET_P(c)         ((c) < 0x80)
-#define UTF_8_EXTRA_OCTET_P(c)     (((c) & 0xC0) == 0x80)
-#define UTF_8_2_OCTET_LEADING_P(c) (((c) & 0xE0) == 0xC0)
-#define UTF_8_3_OCTET_LEADING_P(c) (((c) & 0xF0) == 0xE0)
-#define UTF_8_4_OCTET_LEADING_P(c) (((c) & 0xF8) == 0xF0)
-#define UTF_8_5_OCTET_LEADING_P(c) (((c) & 0xFC) == 0xF8)
-#define UTF_8_6_OCTET_LEADING_P(c) (((c) & 0xFE) == 0xFC)
+  int incomplete;
 
-static int
-detect_coding_utf_8 (src, src_end, multibytep)
-     unsigned char *src, *src_end;
-     int multibytep;
-{
-  unsigned char c;
-  int seq_maybe_bytes;
-  /* Dummy for ONE_MORE_BYTE.  */
-  struct coding_system dummy_coding;
-  struct coding_system *coding = &dummy_coding;
+  detect_info->checked |= CATEGORY_MASK_BIG5;
+  /* A coding system of this category is always ASCII compatible.  */
+  src += coding->head_ascii;
 
   while (1)
     {
-      ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
-      if (UTF_8_1_OCTET_P (c))
+      incomplete = 0;
+      ONE_MORE_BYTE (c);
+      incomplete = 1;
+      if (c < 0x80)
        continue;
-      else if (UTF_8_2_OCTET_LEADING_P (c))
-       seq_maybe_bytes = 1;
-      else if (UTF_8_3_OCTET_LEADING_P (c))
-       seq_maybe_bytes = 2;
-      else if (UTF_8_4_OCTET_LEADING_P (c))
-       seq_maybe_bytes = 3;
-      else if (UTF_8_5_OCTET_LEADING_P (c))
-       seq_maybe_bytes = 4;
-      else if (UTF_8_6_OCTET_LEADING_P (c))
-       seq_maybe_bytes = 5;
-      else
-       return 0;
-
-      do
+      if (c >= 0xA1)
        {
-         ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
-         if (!UTF_8_EXTRA_OCTET_P (c))
+         ONE_MORE_BYTE (c);
+         if (c < 0x40 || (c >= 0x7F && c <= 0xA0))
            return 0;
-         seq_maybe_bytes--;
+         found = CATEGORY_MASK_BIG5;
        }
-      while (seq_maybe_bytes > 0);
+      else
+       break;
     }
+  detect_info->rejected |= CATEGORY_MASK_BIG5;
+  return 0;
 
- label_end_of_loop:
-  return CODING_CATEGORY_MASK_UTF_8;
+ no_more_source:
+  if (incomplete && coding->mode & CODING_MODE_LAST_BLOCK)
+    {
+      detect_info->rejected |= CATEGORY_MASK_BIG5;
+      return 0;
+    }
+  detect_info->found |= found;
+  return 1;
 }
 
-/* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
-   Check if a text is encoded in UTF-16 Big Endian (endian == 1) or
-   Little Endian (otherwise).  If it is, return
-   CODING_CATEGORY_MASK_UTF_16_BE or CODING_CATEGORY_MASK_UTF_16_LE,
-   else return 0.  */
+/* See the above "GENERAL NOTES on `decode_coding_XXX ()' functions".
+   If SJIS_P is 1, decode SJIS text, else decode BIG5 test.  */
 
-#define UTF_16_INVALID_P(val)  \
-  (((val) == 0xFFFE)           \
-   || ((val) == 0xFFFF))
+static void
+decode_coding_sjis (coding)
+     struct coding_system *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 consumed_chars = 0, consumed_chars_base;
+  int multibytep = coding->src_multibyte;
+  struct charset *charset_roman, *charset_kanji, *charset_kana;
+  Lisp_Object attrs, eol_type, charset_list, val;
+  int char_offset = coding->produced_char;
+  int last_offset = char_offset;
+  int last_id = charset_ascii;
+
+  CODING_GET_INFO (coding, attrs, eol_type, 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)));
 
-#define UTF_16_HIGH_SURROGATE_P(val) \
-  (((val) & 0xD800) == 0xD800)
+  while (1)
+    {
+      int c, c1;
 
-#define UTF_16_LOW_SURROGATE_P(val) \
-  (((val) & 0xDC00) == 0xDC00)
+      src_base = src;
+      consumed_chars_base = consumed_chars;
 
-static int
-detect_coding_utf_16 (src, src_end, multibytep)
-     unsigned char *src, *src_end;
-     int multibytep;
-{
-  unsigned char c1, c2;
-  /* Dummy for ONE_MORE_BYTE_CHECK_MULTIBYTE.  */
-  struct coding_system dummy_coding;
-  struct coding_system *coding = &dummy_coding;
+      if (charbuf >= charbuf_end)
+       break;
+
+      ONE_MORE_BYTE (c);
+
+      if (c == '\r')
+       {
+         if (EQ (eol_type, Qdos))
+           {
+             if (src == src_end)
+               {
+                 coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+                 goto no_more_source;
+               }
+             if (*src == '\n')
+               ONE_MORE_BYTE (c);
+           }
+         else if (EQ (eol_type, Qmac))
+           c = '\n';
+       }
+      else
+       {
+         struct charset *charset;
 
-  ONE_MORE_BYTE_CHECK_MULTIBYTE (c1, multibytep);
-  ONE_MORE_BYTE_CHECK_MULTIBYTE (c2, multibytep);
+         if (c < 0x80)
+           charset = charset_roman;
+         else
+           {
+             if (c >= 0xF0)
+               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
+               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);
+             last_id = charset->id;
+             last_offset = char_offset;
+           }
+         CODING_DECODE_CHAR (coding, src, src_base, src_end, charset, c, c);
+       }
+      *charbuf++ = c;
+      char_offset++;
+      continue;
 
-  if ((c1 == 0xFF) && (c2 == 0xFE))
-    return CODING_CATEGORY_MASK_UTF_16_LE;
-  else if ((c1 == 0xFE) && (c2 == 0xFF))
-    return CODING_CATEGORY_MASK_UTF_16_BE;
+    invalid_code:
+      src = src_base;
+      consumed_chars = consumed_chars_base;
+      ONE_MORE_BYTE (c);
+      *charbuf++ = ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
+      char_offset++;
+      coding->errors++;
+    }
 
- label_end_of_loop:
-  return 0;
+ no_more_source:
+  if (last_id != charset_ascii)
+    ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+  coding->consumed_char += consumed_chars_base;
+  coding->consumed = src_base - coding->source;
+  coding->charbuf_used = charbuf - coding->charbuf;
 }
 
-/* See the above "GENERAL NOTES on `decode_coding_XXX ()' functions".
-   If SJIS_P is 1, decode SJIS text, else decode BIG5 test.  */
-
 static void
-decode_coding_sjis_big5 (coding, source, destination,
-                        src_bytes, dst_bytes, sjis_p)
+decode_coding_big5 (coding)
      struct coding_system *coding;
-     unsigned char *source, *destination;
-     int src_bytes, dst_bytes;
-     int sjis_p;
 {
-  unsigned char *src = source;
-  unsigned char *src_end = source + src_bytes;
-  unsigned char *dst = destination;
-  unsigned char *dst_end = destination + dst_bytes;
-  /* SRC_BASE remembers the start position in source in each loop.
-     The loop will be exited when there's not enough source code
-     (within macro ONE_MORE_BYTE), or when there's not enough
-     destination area to produce a character (within macro
-     EMIT_CHAR).  */
-  unsigned char *src_base;
-  Lisp_Object translation_table;
-
-  if (NILP (Venable_character_translation))
-    translation_table = Qnil;
-  else
-    {
-      translation_table = coding->translation_table_for_decode;
-      if (NILP (translation_table))
-       translation_table = Vstandard_translation_table_for_decode;
-    }
+  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 consumed_chars = 0, consumed_chars_base;
+  int multibytep = coding->src_multibyte;
+  struct charset *charset_roman, *charset_big5;
+  Lisp_Object attrs, eol_type, charset_list, val;
+  int char_offset = coding->produced_char;
+  int last_offset = char_offset;
+  int last_id = charset_ascii;
+
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+  val = charset_list;
+  charset_roman = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
+  charset_big5 = CHARSET_FROM_ID (XINT (XCAR (val)));
 
-  coding->produced_char = 0;
   while (1)
     {
-      int c, charset, c1, c2;
+      int c, c1;
 
       src_base = src;
-      ONE_MORE_BYTE (c1);
+      consumed_chars_base = consumed_chars;
+
+      if (charbuf >= charbuf_end)
+       break;
+
+      ONE_MORE_BYTE (c);
 
-      if (c1 < 0x80)
+      if (c == '\r')
        {
-         charset = CHARSET_ASCII;
-         if (c1 < 0x20)
+         if (EQ (eol_type, Qdos))
            {
-             if (c1 == '\r')
-               {
-                 if (coding->eol_type == CODING_EOL_CRLF)
-                   {
-                     ONE_MORE_BYTE (c2);
-                     if (c2 == '\n')
-                       c1 = c2;
-                     else
-                       /* To process C2 again, SRC is subtracted by 1.  */
-                       src--;
-                   }
-                 else if (coding->eol_type == CODING_EOL_CR)
-                   c1 = '\n';
-               }
-             else if (c1 == '\n'
-                      && (coding->mode & CODING_MODE_INHIBIT_INCONSISTENT_EOL)
-                      && (coding->eol_type == CODING_EOL_CR
-                          || coding->eol_type == CODING_EOL_CRLF))
+             if (src == src_end)
                {
-                 coding->result = CODING_FINISH_INCONSISTENT_EOL;
-                 goto label_end_of_loop;
+                 coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+                 goto no_more_source;
                }
+             if (*src == '\n')
+               ONE_MORE_BYTE (c);
            }
+         else if (EQ (eol_type, Qmac))
+           c = '\n';
        }
       else
-        {
-         if (sjis_p)
-           {
-             if (c1 == 0x80 || c1 == 0xA0 || c1 > 0xEF)
-               goto label_invalid_code;
-             if (c1 <= 0x9F || c1 >= 0xE0)
-               {
-                 /* SJIS -> JISX0208 */
-                 ONE_MORE_BYTE (c2);
-                 if (c2 < 0x40 || c2 == 0x7F || c2 > 0xFC)
-                   goto label_invalid_code;
-                 DECODE_SJIS (c1, c2, c1, c2);
-                 charset = charset_jisx0208;
-               }
-             else
-               /* SJIS -> JISX0201-Kana */
-               charset = charset_katakana_jisx0201;
-           }
+       {
+         struct charset *charset;
+         if (c < 0x80)
+           charset = charset_roman;
          else
            {
              /* BIG5 -> Big5 */
-             if (c1 < 0xA0 || c1 > 0xFE)
-               goto label_invalid_code;
-             ONE_MORE_BYTE (c2);
-             if (c2 < 0x40 || (c2 > 0x7E && c2 < 0xA1) || c2 > 0xFE)
-               goto label_invalid_code;
-             DECODE_BIG5 (c1, c2, charset, c1, c2);
+             if (c < 0xA1 || c > 0xFE)
+               goto invalid_code;
+             ONE_MORE_BYTE (c1);
+             if (c1 < 0x40 || (c1 > 0x7E && c1 < 0xA1) || c1 > 0xFE)
+               goto invalid_code;
+             c = c << 8 | c1;
+             charset = charset_big5;
+           }
+         if (charset->id != charset_ascii
+             && last_id != charset->id)
+           {
+             if (last_id != charset_ascii)
+               ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+             last_id = charset->id;
+             last_offset = char_offset;
            }
+         CODING_DECODE_CHAR (coding, src, src_base, src_end, charset, c, c);
        }
 
-      c = DECODE_ISO_CHARACTER (charset, c1, c2);
-      EMIT_CHAR (c);
+      *charbuf++ = c;
+      char_offset++;
       continue;
 
-    label_invalid_code:
-      coding->errors++;
+    invalid_code:
       src = src_base;
-      c = *src++;
-      EMIT_CHAR (c);
+      consumed_chars = consumed_chars_base;
+      ONE_MORE_BYTE (c);
+      *charbuf++ = ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
+      char_offset++;
+      coding->errors++;
     }
 
- label_end_of_loop:
-  coding->consumed = coding->consumed_char = src_base - source;
-  coding->produced = dst - destination;
-  return;
+ no_more_source:
+  if (last_id != charset_ascii)
+    ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+  coding->consumed_char += consumed_chars_base;
+  coding->consumed = src_base - coding->source;
+  coding->charbuf_used = charbuf - coding->charbuf;
 }
 
 /* See the above "GENERAL NOTES on `encode_coding_XXX ()' functions".
@@ -3140,815 +4135,913 @@ decode_coding_sjis_big5 (coding, source, destination,
    charsets are produced without any encoding.  If SJIS_P is 1, encode
    SJIS text, else encode BIG5 text.  */
 
-static void
-encode_coding_sjis_big5 (coding, source, destination,
-                        src_bytes, dst_bytes, sjis_p)
+static int
+encode_coding_sjis (coding)
      struct coding_system *coding;
-     unsigned char *source, *destination;
-     int src_bytes, dst_bytes;
-     int sjis_p;
 {
-  unsigned char *src = source;
-  unsigned char *src_end = source + src_bytes;
-  unsigned char *dst = destination;
-  unsigned char *dst_end = destination + dst_bytes;
-  /* SRC_BASE remembers the start position in source in each loop.
-     The loop will be exited when there's not enough source text to
-     analyze multi-byte codes (within macro ONE_MORE_CHAR), or when
-     there's not enough destination area to produce encoded codes
-     (within macro EMIT_BYTES).  */
-  unsigned char *src_base;
-  Lisp_Object translation_table;
-
-  if (NILP (Venable_character_translation))
-    translation_table = Qnil;
-  else
-    {
-      translation_table = coding->translation_table_for_encode;
-      if (NILP (translation_table))
-       translation_table = Vstandard_translation_table_for_encode;
-    }
+  int multibytep = coding->dst_multibyte;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf + coding->charbuf_used;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  int safe_room = 4;
+  int produced_chars = 0;
+  Lisp_Object attrs, eol_type, charset_list, val;
+  int ascii_compatible;
+  struct charset *charset_roman, *charset_kanji, *charset_kana;
+  int c;
 
-  while (1)
-    {
-      int c, charset, c1, c2;
+  CODING_GET_INFO (coding, attrs, eol_type, 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)));
 
-      src_base = src;
-      ONE_MORE_CHAR (c);
+  ascii_compatible = ! NILP (CODING_ATTR_ASCII_COMPAT (attrs));
 
+  while (charbuf < charbuf_end)
+    {
+      ASSURE_DESTINATION (safe_room);
+      c = *charbuf++;
       /* Now encode the character C.  */
-      if (SINGLE_BYTE_CHAR_P (c))
+      if (ASCII_CHAR_P (c) && ascii_compatible)
+       EMIT_ONE_ASCII_BYTE (c);
+      else if (CHAR_BYTE8_P (c))
+       {
+         c = CHAR_TO_BYTE8 (c);
+         EMIT_ONE_BYTE (c);
+       }
+      else
        {
-         switch (c)
+         unsigned code;
+         struct charset *charset = char_charset (c, charset_list, &code);
+
+         if (!charset)
            {
-           case '\r':
-             if (!(coding->mode & CODING_MODE_SELECTIVE_DISPLAY))
+             if (coding->mode & CODING_MODE_SAFE_ENCODING)
                {
-                 EMIT_ONE_BYTE (c);
-                 break;
+                 code = CODING_INHIBIT_CHARACTER_SUBSTITUTION;
+                 charset = CHARSET_FROM_ID (charset_ascii);
                }
-             c = '\n';
-           case '\n':
-             if (coding->eol_type == CODING_EOL_CRLF)
+             else
                {
-                 EMIT_TWO_BYTES ('\r', c);
-                 break;
+                 c = coding->default_char;
+                 charset = char_charset (c, charset_list, &code);
                }
-             else if (coding->eol_type == CODING_EOL_CR)
-               c = '\r';
-           default:
-             EMIT_ONE_BYTE (c);
            }
+         if (code == CHARSET_INVALID_CODE (charset))
+           abort ();
+         if (charset == charset_kanji)
+           {
+             int c1, c2;
+             JIS_TO_SJIS (code);
+             c1 = code >> 8, c2 = code & 0xFF;
+             EMIT_TWO_BYTES (c1, c2);
+           }
+         else if (charset == charset_kana)
+           EMIT_ONE_BYTE (code | 0x80);
+         else
+           EMIT_ONE_ASCII_BYTE (code & 0x7F);
+       }
+    }
+  coding->result = CODING_RESULT_SUCCESS;
+  coding->produced_char += produced_chars;
+  coding->produced = dst - coding->destination;
+  return 0;
+}
+
+static int
+encode_coding_big5 (coding)
+     struct coding_system *coding;
+{
+  int multibytep = coding->dst_multibyte;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf + coding->charbuf_used;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  int safe_room = 4;
+  int produced_chars = 0;
+  Lisp_Object attrs, eol_type, charset_list, val;
+  int ascii_compatible;
+  struct charset *charset_roman, *charset_big5;
+  int c;
+
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+  val = charset_list;
+  charset_roman = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
+  charset_big5 = CHARSET_FROM_ID (XINT (XCAR (val)));
+  ascii_compatible = ! NILP (CODING_ATTR_ASCII_COMPAT (attrs));
+
+  while (charbuf < charbuf_end)
+    {
+      ASSURE_DESTINATION (safe_room);
+      c = *charbuf++;
+      /* Now encode the character C.  */
+      if (ASCII_CHAR_P (c) && ascii_compatible)
+       EMIT_ONE_ASCII_BYTE (c);
+      else if (CHAR_BYTE8_P (c))
+       {
+         c = CHAR_TO_BYTE8 (c);
+         EMIT_ONE_BYTE (c);
        }
       else
        {
-         SPLIT_CHAR (c, charset, c1, c2);
-         if (sjis_p)
+         unsigned code;
+         struct charset *charset = char_charset (c, charset_list, &code);
+
+         if (! charset)
            {
-             if (charset == charset_jisx0208
-                 || charset == charset_jisx0208_1978)
+             if (coding->mode & CODING_MODE_SAFE_ENCODING)
                {
-                 ENCODE_SJIS (c1, c2, c1, c2);
-                 EMIT_TWO_BYTES (c1, c2);
+                 code = CODING_INHIBIT_CHARACTER_SUBSTITUTION;
+                 charset = CHARSET_FROM_ID (charset_ascii);
                }
-             else if (charset == charset_katakana_jisx0201)
-               EMIT_ONE_BYTE (c1 | 0x80);
-             else if (charset == charset_latin_jisx0201)
-               EMIT_ONE_BYTE (c1);
-             else if (coding->mode & CODING_MODE_INHIBIT_UNENCODABLE_CHAR)
+             else
                {
-                 EMIT_ONE_BYTE (CODING_REPLACEMENT_CHARACTER);
-                 if (CHARSET_WIDTH (charset) > 1)
-                   EMIT_ONE_BYTE (CODING_REPLACEMENT_CHARACTER);
+                 c = coding->default_char;
+                 charset = char_charset (c, charset_list, &code);
                }
-             else
-               /* There's no way other than producing the internal
-                  codes as is.  */
-               EMIT_BYTES (src_base, src);
            }
-         else
+         if (code == CHARSET_INVALID_CODE (charset))
+           abort ();
+         if (charset == charset_big5)
            {
-             if (charset == charset_big5_1 || charset == charset_big5_2)
-               {
-                 ENCODE_BIG5 (charset, c1, c2, c1, c2);
-                 EMIT_TWO_BYTES (c1, c2);
-               }
-             else if (coding->mode & CODING_MODE_INHIBIT_UNENCODABLE_CHAR)
-               {
-                 EMIT_ONE_BYTE (CODING_REPLACEMENT_CHARACTER);
-                 if (CHARSET_WIDTH (charset) > 1)
-                   EMIT_ONE_BYTE (CODING_REPLACEMENT_CHARACTER);
-               }
-             else
-               /* There's no way other than producing the internal
-                  codes as is.  */
-               EMIT_BYTES (src_base, src);
+             int c1, c2;
+
+             c1 = code >> 8, c2 = code & 0xFF;
+             EMIT_TWO_BYTES (c1, c2);
            }
+         else
+           EMIT_ONE_ASCII_BYTE (code & 0x7F);
        }
-      coding->consumed_char++;
     }
-
- label_end_of_loop:
-  coding->consumed = src_base - source;
-  coding->produced = coding->produced_char = dst - destination;
+  coding->result = CODING_RESULT_SUCCESS;
+  coding->produced_char += produced_chars;
+  coding->produced = dst - coding->destination;
+  return 0;
 }
 
 \f
-/*** 5. CCL handlers ***/
+/*** 10. CCL handlers ***/
 
 /* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
    Check if a text is encoded in a coding system of which
    encoder/decoder are written in CCL program.  If it is, return
-   CODING_CATEGORY_MASK_CCL, else return 0.  */
+   CATEGORY_MASK_CCL, else return 0.  */
 
 static int
-detect_coding_ccl (src, src_end, multibytep)
-     unsigned char *src, *src_end;
-     int multibytep;
+detect_coding_ccl (coding, detect_info)
+     struct coding_system *coding;
+     struct coding_detection_info *detect_info;
 {
-  unsigned char *valid;
-  int c;
-  /* Dummy for ONE_MORE_BYTE.  */
-  struct coding_system dummy_coding;
-  struct coding_system *coding = &dummy_coding;
+  const unsigned char *src = coding->source, *src_base = src;
+  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);
+  int head_ascii = coding->head_ascii;
+  Lisp_Object attrs;
+
+  detect_info->checked |= CATEGORY_MASK_CCL;
+
+  coding = &coding_categories[coding_category_ccl];
+  attrs = CODING_ID_ATTRS (coding->id);
+  if (! NILP (CODING_ATTR_ASCII_COMPAT (attrs)))
+    src += head_ascii;
 
-  /* No coding system is assigned to coding-category-ccl.  */
-  if (!coding_system_table[CODING_CATEGORY_IDX_CCL])
-    return 0;
-
-  valid = coding_system_table[CODING_CATEGORY_IDX_CCL]->spec.ccl.valid_codes;
   while (1)
     {
-      ONE_MORE_BYTE_CHECK_MULTIBYTE (c, multibytep);
-      if (! valid[c])
-       return 0;
+      int c;
+      ONE_MORE_BYTE (c);
+      if (! valids[c])
+       break;
+      if ((valids[c] > 1))
+       found = CATEGORY_MASK_CCL;
+    }
+  detect_info->rejected |= CATEGORY_MASK_CCL;
+  return 0;
+
+ no_more_source:
+  detect_info->found |= found;
+  return 1;
+}
+
+static void
+decode_coding_ccl (coding)
+     struct coding_system *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 consumed_chars = 0;
+  int multibytep = coding->src_multibyte;
+  struct ccl_program ccl;
+  int source_charbuf[1024];
+  int source_byteidx[1024];
+  Lisp_Object attrs, eol_type, charset_list;
+
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+  setup_ccl_program (&ccl, CODING_CCL_DECODER (coding));
+
+  while (src < src_end)
+    {
+      const unsigned char *p = src;
+      int *source, *source_end;
+      int i = 0;
+
+      if (multibytep)
+       while (i < 1024 && p < src_end)
+         {
+           source_byteidx[i] = p - src;
+           source_charbuf[i++] = STRING_CHAR_ADVANCE (p);
+         }
+      else
+       while (i < 1024 && p < src_end)
+         source_charbuf[i++] = *p++;
+
+      if (p == src_end && coding->mode & CODING_MODE_LAST_BLOCK)
+       ccl.last_block = 1;
+
+      source = source_charbuf;
+      source_end = source + i;
+      while (source < source_end)
+       {
+         ccl_driver (&ccl, source, charbuf,
+                     source_end - source, charbuf_end - charbuf,
+                     charset_list);
+         source += ccl.consumed;
+         charbuf += ccl.produced;
+         if (ccl.status != CCL_STAT_SUSPEND_BY_DST)
+           break;
+       }
+      if (source < source_end)
+       src += source_byteidx[source - source_charbuf];
+      else
+       src = p;
+      consumed_chars += source - source_charbuf;
+
+      if (ccl.status != CCL_STAT_SUSPEND_BY_SRC
+         && ccl.status != CODING_RESULT_INSUFFICIENT_SRC)
+       break;
+    }
+
+  switch (ccl.status)
+    {
+    case CCL_STAT_SUSPEND_BY_SRC:
+      coding->result = 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;
+      break;
+    default:
+      coding->result = CODING_RESULT_SUCCESS;
+      break;
+    }
+  coding->consumed_char += consumed_chars;
+  coding->consumed = src - coding->source;
+  coding->charbuf_used = charbuf - coding->charbuf;
+}
+
+static int
+encode_coding_ccl (coding)
+     struct coding_system *coding;
+{
+  struct ccl_program ccl;
+  int multibytep = coding->dst_multibyte;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf + coding->charbuf_used;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  unsigned char *adjusted_dst_end = dst_end - 1;
+  int destination_charbuf[1024];
+  int i, produced_chars = 0;
+  Lisp_Object attrs, eol_type, charset_list;
+
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+  setup_ccl_program (&ccl, CODING_CCL_ENCODER (coding));
+
+  ccl.last_block = coding->mode & CODING_MODE_LAST_BLOCK;
+  ccl.dst_multibyte = coding->dst_multibyte;
+
+  while (charbuf < charbuf_end && dst < adjusted_dst_end)
+    {
+      int dst_bytes = dst_end - dst;
+      if (dst_bytes > 1024)
+       dst_bytes = 1024;
+
+      ccl_driver (&ccl, charbuf, destination_charbuf,
+                 charbuf_end - charbuf, dst_bytes, charset_list);
+      charbuf += ccl.consumed;
+      if (multibytep)
+       for (i = 0; i < ccl.produced; i++)
+         EMIT_ONE_BYTE (destination_charbuf[i] & 0xFF);
+      else
+       {
+         for (i = 0; i < ccl.produced; i++)    
+           *dst++ = destination_charbuf[i] & 0xFF;
+         produced_chars += ccl.produced;
+       }
+    }
+
+  switch (ccl.status)
+    {
+    case CCL_STAT_SUSPEND_BY_SRC:
+      coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+      break;
+    case CCL_STAT_SUSPEND_BY_DST:
+      coding->result = CODING_RESULT_INSUFFICIENT_DST;
+      break;
+    case CCL_STAT_QUIT:
+    case CCL_STAT_INVALID_CMD:
+      coding->result = CODING_RESULT_INTERRUPT;
+      break;
+    default:
+      coding->result = CODING_RESULT_SUCCESS;
+      break;
     }
- label_end_of_loop:
-  return CODING_CATEGORY_MASK_CCL;
+
+  coding->produced_char += produced_chars;
+  coding->produced = dst - coding->destination;
+  return 0;
 }
 
+
 \f
-/*** 6. End-of-line handlers ***/
+/*** 10, 11. no-conversion handlers ***/
 
 /* See the above "GENERAL NOTES on `decode_coding_XXX ()' functions".  */
 
 static void
-decode_eol (coding, source, destination, src_bytes, dst_bytes)
+decode_coding_raw_text (coding)
      struct coding_system *coding;
-     unsigned char *source, *destination;
-     int src_bytes, dst_bytes;
 {
-  unsigned char *src = source;
-  unsigned char *dst = destination;
-  unsigned char *src_end = src + src_bytes;
-  unsigned char *dst_end = dst + dst_bytes;
-  Lisp_Object translation_table;
-  /* SRC_BASE remembers the start position in source in each loop.
-     The loop will be exited when there's not enough source code
-     (within macro ONE_MORE_BYTE), or when there's not enough
-     destination area to produce a character (within macro
-     EMIT_CHAR).  */
-  unsigned char *src_base;
+  coding->chars_at_source = 1;
+  coding->consumed_char = 0;
+  coding->consumed = 0;
+  coding->result = CODING_RESULT_SUCCESS;
+}
+
+static int
+encode_coding_raw_text (coding)
+     struct coding_system *coding;
+{
+  int multibytep = coding->dst_multibyte;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = coding->charbuf + coding->charbuf_used;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  int produced_chars = 0;
   int c;
 
-  translation_table = Qnil;
-  switch (coding->eol_type)
+  if (multibytep)
+    {
+      int safe_room = MAX_MULTIBYTE_LENGTH * 2;
+
+      if (coding->src_multibyte)
+       while (charbuf < charbuf_end)
+         {
+           ASSURE_DESTINATION (safe_room);
+           c = *charbuf++;
+           if (ASCII_CHAR_P (c))
+             EMIT_ONE_ASCII_BYTE (c);
+           else if (CHAR_BYTE8_P (c))
+             {
+               c = CHAR_TO_BYTE8 (c);
+               EMIT_ONE_BYTE (c);
+             }
+           else
+             {
+               unsigned char str[MAX_MULTIBYTE_LENGTH], *p0 = str, *p1 = str;
+
+               CHAR_STRING_ADVANCE (c, p1);
+               while (p0 < p1)
+                 {
+                   EMIT_ONE_BYTE (*p0);
+                   p0++;
+                 }
+             }
+         }
+      else
+       while (charbuf < charbuf_end)
+         {
+           ASSURE_DESTINATION (safe_room);
+           c = *charbuf++;
+           EMIT_ONE_BYTE (c);
+         }
+    }
+  else
     {
-    case CODING_EOL_CRLF:
-      while (1)
+      if (coding->src_multibyte)
        {
-         src_base = src;
-         ONE_MORE_BYTE (c);
-         if (c == '\r')
-           {
-             ONE_MORE_BYTE (c);
-             if (c != '\n')
-               {
-                 src--;
-                 c = '\r';
-               }
-           }
-         else if (c == '\n'
-                  && (coding->mode & CODING_MODE_INHIBIT_INCONSISTENT_EOL))
+         int safe_room = MAX_MULTIBYTE_LENGTH;
+
+         while (charbuf < charbuf_end)
            {
-             coding->result = CODING_FINISH_INCONSISTENT_EOL;
-             goto label_end_of_loop;
+             ASSURE_DESTINATION (safe_room);
+             c = *charbuf++;
+             if (ASCII_CHAR_P (c))
+               *dst++ = c;
+             else if (CHAR_BYTE8_P (c))
+               *dst++ = CHAR_TO_BYTE8 (c);
+             else
+               CHAR_STRING_ADVANCE (c, dst);
+             produced_chars++;
            }
-         EMIT_CHAR (c);
        }
-      break;
+      else
+       {
+         ASSURE_DESTINATION (charbuf_end - charbuf);
+         while (charbuf < charbuf_end && dst < dst_end)
+           *dst++ = *charbuf++;
+         produced_chars = dst - (coding->destination + coding->dst_bytes);
+       }
+    }
+  coding->result = CODING_RESULT_SUCCESS;
+  coding->produced_char += produced_chars;
+  coding->produced = dst - coding->destination;
+  return 0;
+}
+
+/* See the above "GENERAL NOTES on `detect_coding_XXX ()' functions".
+   Check if a text is encoded in a charset-based coding system.  If it
+   is, return 1, else return 0.  */
+
+static int
+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_end = coding->source + coding->src_bytes;
+  int multibytep = coding->src_multibyte;
+  int consumed_chars = 0;
+  Lisp_Object attrs, valids;
+  int found = 0;
+
+  detect_info->checked |= CATEGORY_MASK_CHARSET;
+
+  coding = &coding_categories[coding_category_charset];
+  attrs = CODING_ID_ATTRS (coding->id);
+  valids = AREF (attrs, coding_attr_charset_valids);
+
+  if (! NILP (CODING_ATTR_ASCII_COMPAT (attrs)))
+    src += coding->head_ascii;
+
+  while (1)
+    {
+      int c;
+
+      ONE_MORE_BYTE (c);
+      if (NILP (AREF (valids, c)))
+       break;
+      if (c >= 0x80)
+       found = CATEGORY_MASK_CHARSET;
+    }
+  detect_info->rejected |= CATEGORY_MASK_CHARSET;
+  return 0;
+
+ no_more_source:
+  detect_info->found |= found;
+  return 1;
+}
 
-    case CODING_EOL_CR:
-      while (1)
+static void
+decode_coding_charset (coding)
+     struct coding_system *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 consumed_chars = 0, consumed_chars_base;
+  int multibytep = coding->src_multibyte;
+  Lisp_Object attrs, eol_type, charset_list, valids;
+  int char_offset = coding->produced_char;
+  int last_offset = char_offset;
+  int last_id = charset_ascii;
+
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+  valids = AREF (attrs, coding_attr_charset_valids);
+
+  while (1)
+    {
+      int c;
+
+      src_base = src;
+      consumed_chars_base = consumed_chars;
+
+      if (charbuf >= charbuf_end)
+       break;
+
+      ONE_MORE_BYTE (c);
+      if (c == '\r')
        {
-         src_base = src;
-         ONE_MORE_BYTE (c);
-         if (c == '\n')
+         /* Here we assume that no charset maps '\r' to something
+            else.  */
+         if (EQ (eol_type, Qdos))
            {
-             if (coding->mode & CODING_MODE_INHIBIT_INCONSISTENT_EOL)
+             if (src == src_end)
                {
-                 coding->result = CODING_FINISH_INCONSISTENT_EOL;
-                 goto label_end_of_loop;
+                 coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+                 goto no_more_source;
                }
+             if (*src == '\n')
+               ONE_MORE_BYTE (c);
            }
-         else if (c == '\r')
+         else if (EQ (eol_type, Qmac))
            c = '\n';
-         EMIT_CHAR (c);
        }
-      break;
-
-    default:                   /* no need for EOL handling */
-      while (1)
+      else
        {
-         src_base = src;
-         ONE_MORE_BYTE (c);
-         EMIT_CHAR (c);
+         Lisp_Object val;
+         struct charset *charset;
+         int dim;
+         int len = 1;
+         unsigned code = c;
+
+         val = AREF (valids, c);
+         if (NILP (val))
+           goto invalid_code;
+         if (INTEGERP (val))
+           {
+             charset = CHARSET_FROM_ID (XFASTINT (val));
+             dim = CHARSET_DIMENSION (charset);
+             while (len < dim)
+               {
+                 ONE_MORE_BYTE (c);
+                 code = (code << 8) | c;
+                 len++;
+               }
+             CODING_DECODE_CHAR (coding, src, src_base, src_end,
+                                 charset, code, c);
+           }
+         else
+           {
+             /* VAL is a list of charset IDs.  It is assured that the
+                list is sorted by charset dimensions (smaller one
+                comes first).  */
+             while (CONSP (val))
+               {
+                 charset = CHARSET_FROM_ID (XFASTINT (XCAR (val)));
+                 dim = CHARSET_DIMENSION (charset);
+                 while (len < dim)
+                   {
+                     ONE_MORE_BYTE (c);
+                     code = (code << 8) | c;
+                     len++;
+                   }
+                 CODING_DECODE_CHAR (coding, src, src_base,
+                                     src_end, charset, code, c);
+                 if (c >= 0)
+                   break;
+                 val = XCDR (val);
+               }
+           }
+         if (c < 0)
+           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);
+             last_id = charset->id;
+             last_offset = char_offset;
+           }
        }
+      *charbuf++ = c;
+      char_offset++;
+      continue;
+
+    invalid_code:
+      src = src_base;
+      consumed_chars = consumed_chars_base;
+      ONE_MORE_BYTE (c);
+      *charbuf++ = ASCII_BYTE_P (c) ? c : BYTE8_TO_CHAR (c);
+      char_offset++;
+      coding->errors++;
     }
 
- label_end_of_loop:
-  coding->consumed = coding->consumed_char = src_base - source;
-  coding->produced = dst - destination;
-  return;
+ no_more_source:
+  if (last_id != charset_ascii)
+    ADD_CHARSET_DATA (charbuf, last_offset, char_offset, last_id);
+  coding->consumed_char += consumed_chars_base;
+  coding->consumed = src_base - coding->source;
+  coding->charbuf_used = charbuf - coding->charbuf;
 }
 
-/* See "GENERAL NOTES about `encode_coding_XXX ()' functions".  Encode
-   format of end-of-line according to `coding->eol_type'.  It also
-   convert multibyte form 8-bit characters to unibyte if
-   CODING->src_multibyte is nonzero.  If `coding->mode &
-   CODING_MODE_SELECTIVE_DISPLAY' is nonzero, code '\r' in source text
-   also means end-of-line.  */
-
-static void
-encode_eol (coding, source, destination, src_bytes, dst_bytes)
+static int
+encode_coding_charset (coding)
      struct coding_system *coding;
-     const unsigned char *source;
-     unsigned char *destination;
-     int src_bytes, dst_bytes;
 {
-  const unsigned char *src = source;
-  unsigned char *dst = destination;
-  const unsigned char *src_end = src + src_bytes;
-  unsigned char *dst_end = dst + dst_bytes;
-  Lisp_Object translation_table;
-  /* SRC_BASE remembers the start position in source in each loop.
-     The loop will be exited when there's not enough source text to
-     analyze multi-byte codes (within macro ONE_MORE_CHAR), or when
-     there's not enough destination area to produce encoded codes
-     (within macro EMIT_BYTES).  */
-  const unsigned char *src_base;
-  unsigned char *tmp;
+  int multibytep = coding->dst_multibyte;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf + coding->charbuf_used;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  int safe_room = MAX_MULTIBYTE_LENGTH;
+  int produced_chars = 0;
+  Lisp_Object attrs, eol_type, charset_list;
+  int ascii_compatible;
   int c;
-  int selective_display = coding->mode & CODING_MODE_SELECTIVE_DISPLAY;
 
-  translation_table = Qnil;
-  if (coding->src_multibyte
-      && *(src_end - 1) == LEADING_CODE_8_BIT_CONTROL)
-    {
-      src_end--;
-      src_bytes--;
-      coding->result = CODING_FINISH_INSUFFICIENT_SRC;
-    }
+  CODING_GET_INFO (coding, attrs, eol_type, charset_list);
+  ascii_compatible = ! NILP (CODING_ATTR_ASCII_COMPAT (attrs));
 
-  if (coding->eol_type == CODING_EOL_CRLF)
-    {
-      while (src < src_end)
-       {
-         src_base = src;
-         c = *src++;
-         if (c >= 0x20)
-           EMIT_ONE_BYTE (c);
-         else if (c == '\n' || (c == '\r' && selective_display))
-           EMIT_TWO_BYTES ('\r', '\n');
-         else
-           EMIT_ONE_BYTE (c);
-       }
-      src_base = src;
-    label_end_of_loop:
-      ;
-    }
-  else
+  while (charbuf < charbuf_end)
     {
-      if (!dst_bytes || src_bytes <= dst_bytes)
+      struct charset *charset;
+      unsigned code;
+
+      ASSURE_DESTINATION (safe_room);
+      c = *charbuf++;
+      if (ascii_compatible && ASCII_CHAR_P (c))
+       EMIT_ONE_ASCII_BYTE (c);
+      else if (CHAR_BYTE8_P (c))
        {
-         safe_bcopy (src, dst, src_bytes);
-         src_base = src_end;
-         dst += src_bytes;
+         c = CHAR_TO_BYTE8 (c);
+         EMIT_ONE_BYTE (c);
        }
       else
        {
-         if (coding->src_multibyte
-             && *(src + dst_bytes - 1) == LEADING_CODE_8_BIT_CONTROL)
-           dst_bytes--;
-         safe_bcopy (src, dst, dst_bytes);
-         src_base = src + dst_bytes;
-         dst = destination + dst_bytes;
-         coding->result = CODING_FINISH_INSUFFICIENT_DST;
-       }
-      if (coding->eol_type == CODING_EOL_CR)
-       {
-         for (tmp = destination; tmp < dst; tmp++)
-           if (*tmp == '\n') *tmp = '\r';
-       }
-      else if (selective_display)
-       {
-         for (tmp = destination; tmp < dst; tmp++)
-           if (*tmp == '\r') *tmp = '\n';
+         charset = char_charset (c, charset_list, &code);
+         if (charset)
+           {
+             if (CHARSET_DIMENSION (charset) == 1)
+               EMIT_ONE_BYTE (code);
+             else if (CHARSET_DIMENSION (charset) == 2)
+               EMIT_TWO_BYTES (code >> 8, code & 0xFF);
+             else if (CHARSET_DIMENSION (charset) == 3)
+               EMIT_THREE_BYTES (code >> 16, (code >> 8) & 0xFF, code & 0xFF);
+             else
+               EMIT_FOUR_BYTES (code >> 24, (code >> 16) & 0xFF,
+                                (code >> 8) & 0xFF, code & 0xFF);
+           }
+         else
+           {
+             if (coding->mode & CODING_MODE_SAFE_ENCODING)
+               c = CODING_INHIBIT_CHARACTER_SUBSTITUTION;
+             else
+               c = coding->default_char;
+             EMIT_ONE_BYTE (c);
+           }
        }
     }
-  if (coding->src_multibyte)
-    dst = destination + str_as_unibyte (destination, dst - destination);
 
-  coding->consumed = src_base - source;
-  coding->produced = dst - destination;
-  coding->produced_char = coding->produced;
+  coding->result = CODING_RESULT_SUCCESS;
+  coding->produced_char += produced_chars;
+  coding->produced = dst - coding->destination;
+  return 0;
 }
 
 \f
 /*** 7. C library functions ***/
 
-/* In Emacs Lisp, a coding system is represented by a Lisp symbol which
-   has a property `coding-system'.  The value of this property is a
-   vector of length 5 (called the coding-vector).  Among elements of
-   this vector, the first (element[0]) and the fifth (element[4])
-   carry important information for decoding/encoding.  Before
-   decoding/encoding, this information should be set in fields of a
-   structure of type `coding_system'.
-
-   The value of the property `coding-system' can be a symbol of another
-   subsidiary coding-system.  In that case, Emacs gets coding-vector
-   from that symbol.
-
-   `element[0]' contains information to be set in `coding->type'.  The
-   value and its meaning is as follows:
-
-   0 -- coding_type_emacs_mule
-   1 -- coding_type_sjis
-   2 -- coding_type_iso2022
-   3 -- coding_type_big5
-   4 -- coding_type_ccl encoder/decoder written in CCL
-   nil -- coding_type_no_conversion
-   t -- coding_type_undecided (automatic conversion on decoding,
-                              no-conversion on encoding)
-
-   `element[4]' contains information to be set in `coding->flags' and
-   `coding->spec'.  The meaning varies by `coding->type'.
-
-   If `coding->type' is `coding_type_iso2022', element[4] is a vector
-   of length 32 (of which the first 13 sub-elements are used now).
-   Meanings of these sub-elements are:
-
-   sub-element[N] where N is 0 through 3: to be set in `coding->spec.iso2022'
-       If the value is an integer of valid charset, the charset is
-       assumed to be designated to graphic register N initially.
-
-       If the value is minus, it is a minus value of charset which
-       reserves graphic register N, which means that the charset is
-       not designated initially but should be designated to graphic
-       register N just before encoding a character in that charset.
-
-       If the value is nil, graphic register N is never used on
-       encoding.
-
-   sub-element[N] where N is 4 through 11: to be set in `coding->flags'
-       Each value takes t or nil.  See the section ISO2022 of
-       `coding.h' for more information.
-
-   If `coding->type' is `coding_type_big5', element[4] is t to denote
-   BIG5-ETen or nil to denote BIG5-HKU.
-
-   If `coding->type' takes the other value, element[4] is ignored.
-
-   Emacs Lisp's coding systems also carry information about format of
-   end-of-line in a value of property `eol-type'.  If the value is
-   integer, 0 means CODING_EOL_LF, 1 means CODING_EOL_CRLF, and 2
-   means CODING_EOL_CR.  If it is not integer, it should be a vector
-   of subsidiary coding systems of which property `eol-type' has one
-   of the above values.
-
-*/
-
-/* Extract information for decoding/encoding from CODING_SYSTEM_SYMBOL
-   and set it in CODING.  If CODING_SYSTEM_SYMBOL is invalid, CODING
-   is setup so that no conversion is necessary and return -1, else
-   return 0.  */
+/* Setup coding context CODING from information about CODING_SYSTEM.
+   If CODING_SYSTEM is nil, `no-conversion' is assumed.  If
+   CODING_SYSTEM is invalid, signal an error.  */
 
-int
+void
 setup_coding_system (coding_system, coding)
      Lisp_Object coding_system;
      struct coding_system *coding;
 {
-  Lisp_Object coding_spec, coding_type, eol_type, plist;
+  Lisp_Object attrs;
+  Lisp_Object eol_type;
+  Lisp_Object coding_type;
   Lisp_Object val;
 
-  /* At first, zero clear all members.  */
-  bzero (coding, sizeof (struct coding_system));
+  if (NILP (coding_system))
+    coding_system = Qno_conversion;
 
-  /* Initialize some fields required for all kinds of coding systems.  */
-  coding->symbol = coding_system;
-  coding->heading_ascii = -1;
-  coding->post_read_conversion = coding->pre_write_conversion = Qnil;
-  coding->composing = COMPOSITION_DISABLED;
-  coding->cmp_data = NULL;
+  CHECK_CODING_SYSTEM_GET_ID (coding_system, coding->id);
 
-  if (NILP (coding_system))
-    goto label_invalid_coding_system;
+  attrs = CODING_ID_ATTRS (coding->id);
+  eol_type = CODING_ID_EOL_TYPE (coding->id);
 
-  coding_spec = Fget (coding_system, Qcoding_system);
+  coding->mode = 0;
+  coding->head_ascii = -1;
+  coding->common_flags
+    = (VECTORP (eol_type) ? CODING_REQUIRE_DETECTION_MASK : 0);
+  if (! NILP (CODING_ATTR_POST_READ (attrs)))
+    coding->common_flags |= CODING_REQUIRE_DECODING_MASK;
+  if (! NILP (CODING_ATTR_PRE_WRITE (attrs)))
+    coding->common_flags |= CODING_REQUIRE_ENCODING_MASK;
+  if (! NILP (CODING_ATTR_FOR_UNIBYTE (attrs)))
+    coding->common_flags |= CODING_FOR_UNIBYTE_MASK;
 
-  if (!VECTORP (coding_spec)
-      || XVECTOR (coding_spec)->size != 5
-      || !CONSP (XVECTOR (coding_spec)->contents[3]))
-    goto label_invalid_coding_system;
+  val = CODING_ATTR_SAFE_CHARSETS (attrs);
+  coding->max_charset_id = SCHARS (val) - 1;
+  coding->safe_charsets = (char *) SDATA (val);
+  coding->default_char = XINT (CODING_ATTR_DEFAULT_CHAR (attrs));
 
-  eol_type = inhibit_eol_conversion ? Qnil : Fget (coding_system, Qeol_type);
-  if (VECTORP (eol_type))
+  coding_type = CODING_ATTR_TYPE (attrs);
+  if (EQ (coding_type, Qundecided))
     {
-      coding->eol_type = CODING_EOL_UNDECIDED;
-      coding->common_flags = CODING_REQUIRE_DETECTION_MASK;
+      coding->detector = NULL;
+      coding->decoder = decode_coding_raw_text;
+      coding->encoder = encode_coding_raw_text;
+      coding->common_flags |= CODING_REQUIRE_DETECTION_MASK;
     }
-  else if (XFASTINT (eol_type) == 1)
+  else if (EQ (coding_type, Qiso_2022))
     {
-      coding->eol_type = CODING_EOL_CRLF;
+      int i;
+      int flags = XINT (AREF (attrs, coding_attr_iso_flags));
+
+      /* Invoke graphic register 0 to plane 0.  */
+      CODING_ISO_INVOCATION (coding, 0) = 0;
+      /* Invoke graphic register 1 to plane 1 if we can use 8-bit.  */
+      CODING_ISO_INVOCATION (coding, 1)
+       = (flags & CODING_ISO_FLAG_SEVEN_BITS ? -1 : 1);
+      /* Setup the initial status of designation.  */
+      for (i = 0; i < 4; i++)
+       CODING_ISO_DESIGNATION (coding, i) = CODING_ISO_INITIAL (coding, i);
+      /* Not single shifting initially.  */
+      CODING_ISO_SINGLE_SHIFTING (coding) = 0;
+      /* Beginning of buffer should also be regarded as bol. */
+      CODING_ISO_BOL (coding) = 1;
+      coding->detector = detect_coding_iso_2022;
+      coding->decoder = decode_coding_iso_2022;
+      coding->encoder = encode_coding_iso_2022;
+      if (flags & CODING_ISO_FLAG_SAFE)
+       coding->mode |= CODING_MODE_SAFE_ENCODING;
       coding->common_flags
-       = CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK;
+       |= (CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK
+           | CODING_REQUIRE_FLUSHING_MASK);
+      if (flags & CODING_ISO_FLAG_COMPOSITION)
+       coding->common_flags |= CODING_ANNOTATE_COMPOSITION_MASK;
+      if (flags & CODING_ISO_FLAG_DESIGNATION)
+       coding->common_flags |= CODING_ANNOTATE_CHARSET_MASK;
+      if (flags & CODING_ISO_FLAG_FULL_SUPPORT)
+       {
+         setup_iso_safe_charsets (attrs);
+         val = CODING_ATTR_SAFE_CHARSETS (attrs);
+         coding->max_charset_id = SCHARS (val) - 1;
+         coding->safe_charsets = (char *) SDATA (val);
+       }
+      CODING_ISO_FLAGS (coding) = flags;
     }
-  else if (XFASTINT (eol_type) == 2)
+  else if (EQ (coding_type, Qcharset))
     {
-      coding->eol_type = CODING_EOL_CR;
+      coding->detector = detect_coding_charset;
+      coding->decoder = decode_coding_charset;
+      coding->encoder = encode_coding_charset;
       coding->common_flags
-       = CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK;
+       |= (CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK);
     }
-  else
-    coding->eol_type = CODING_EOL_LF;
-
-  coding_type = XVECTOR (coding_spec)->contents[0];
-  /* Try short cut.  */
-  if (SYMBOLP (coding_type))
+  else if (EQ (coding_type, Qutf_8))
     {
-      if (EQ (coding_type, Qt))
-       {
-         coding->type = coding_type_undecided;
-         coding->common_flags |= CODING_REQUIRE_DETECTION_MASK;
-       }
-      else
-       coding->type = coding_type_no_conversion;
-      /* Initialize this member.  Any thing other than
-        CODING_CATEGORY_IDX_UTF_16_BE and
-        CODING_CATEGORY_IDX_UTF_16_LE are ok because they have
-        special treatment in detect_eol.  */
-      coding->category_idx = CODING_CATEGORY_IDX_EMACS_MULE;
-
-      return 0;
-    }
-
-  /* Get values of coding system properties:
-     `post-read-conversion', `pre-write-conversion',
-     `translation-table-for-decode', `translation-table-for-encode'.  */
-  plist = XVECTOR (coding_spec)->contents[3];
-  /* Pre & post conversion functions should be disabled if
-     inhibit_eol_conversion is nonzero.  This is the case that a code
-     conversion function is called while those functions are running.  */
-  if (! inhibit_pre_post_conversion)
-    {
-      coding->post_read_conversion = Fplist_get (plist, Qpost_read_conversion);
-      coding->pre_write_conversion = Fplist_get (plist, Qpre_write_conversion);
-    }
-  val = Fplist_get (plist, Qtranslation_table_for_decode);
-  if (SYMBOLP (val))
-    val = Fget (val, Qtranslation_table_for_decode);
-  coding->translation_table_for_decode = CHAR_TABLE_P (val) ? val : Qnil;
-  val = Fplist_get (plist, Qtranslation_table_for_encode);
-  if (SYMBOLP (val))
-    val = Fget (val, Qtranslation_table_for_encode);
-  coding->translation_table_for_encode = CHAR_TABLE_P (val) ? val : Qnil;
-  val = Fplist_get (plist, Qcoding_category);
-  if (!NILP (val))
-    {
-      val = Fget (val, Qcoding_category_index);
-      if (INTEGERP (val))
-       coding->category_idx = XINT (val);
-      else
-       goto label_invalid_coding_system;
+      coding->detector = detect_coding_utf_8;
+      coding->decoder = decode_coding_utf_8;
+      coding->encoder = encode_coding_utf_8;
+      coding->common_flags
+       |= (CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK);
+    }
+  else if (EQ (coding_type, Qutf_16))
+    {
+      val = AREF (attrs, coding_attr_utf_16_bom);
+      CODING_UTF_16_BOM (coding) = (CONSP (val) ? utf_16_detect_bom
+                                   : EQ (val, Qt) ? utf_16_with_bom
+                                   : utf_16_without_bom);
+      val = AREF (attrs, coding_attr_utf_16_endian);
+      CODING_UTF_16_ENDIAN (coding) = (EQ (val, Qbig) ? utf_16_big_endian
+                                      : utf_16_little_endian);
+      CODING_UTF_16_SURROGATE (coding) = 0;
+      coding->detector = detect_coding_utf_16;
+      coding->decoder = decode_coding_utf_16;
+      coding->encoder = encode_coding_utf_16;
+      coding->common_flags
+       |= (CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK);
+      if (CODING_UTF_16_BOM (coding) == utf_16_detect_bom)
+       coding->common_flags |= CODING_REQUIRE_DETECTION_MASK;
     }
-  else
-    goto label_invalid_coding_system;
-
-  /* If the coding system has non-nil `composition' property, enable
-     composition handling.  */
-  val = Fplist_get (plist, Qcomposition);
-  if (!NILP (val))
-    coding->composing = COMPOSITION_NO;
-
-  switch (XFASTINT (coding_type))
+  else if (EQ (coding_type, Qccl))
     {
-    case 0:
-      coding->type = coding_type_emacs_mule;
-      coding->common_flags
-       |= CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK;
-      if (!NILP (coding->post_read_conversion))
-       coding->common_flags |= CODING_REQUIRE_DECODING_MASK;
-      if (!NILP (coding->pre_write_conversion))
-       coding->common_flags |= CODING_REQUIRE_ENCODING_MASK;
-      break;
-
-    case 1:
-      coding->type = coding_type_sjis;
+      coding->detector = detect_coding_ccl;
+      coding->decoder = decode_coding_ccl;
+      coding->encoder = encode_coding_ccl;
       coding->common_flags
-       |= CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK;
-      break;
-
-    case 2:
-      coding->type = coding_type_iso2022;
+       |= (CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK
+           | CODING_REQUIRE_FLUSHING_MASK);
+    }
+  else if (EQ (coding_type, Qemacs_mule))
+    {
+      coding->detector = detect_coding_emacs_mule;
+      coding->decoder = decode_coding_emacs_mule;
+      coding->encoder = encode_coding_emacs_mule;
       coding->common_flags
-       |= CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK;
-      {
-       Lisp_Object val, temp;
-       Lisp_Object *flags;
-       int i, charset, reg_bits = 0;
-
-       val = XVECTOR (coding_spec)->contents[4];
-
-       if (!VECTORP (val) || XVECTOR (val)->size != 32)
-         goto label_invalid_coding_system;
-
-       flags = XVECTOR (val)->contents;
-       coding->flags
-         = ((NILP (flags[4]) ? 0 : CODING_FLAG_ISO_SHORT_FORM)
-            | (NILP (flags[5]) ? 0 : CODING_FLAG_ISO_RESET_AT_EOL)
-            | (NILP (flags[6]) ? 0 : CODING_FLAG_ISO_RESET_AT_CNTL)
-            | (NILP (flags[7]) ? 0 : CODING_FLAG_ISO_SEVEN_BITS)
-            | (NILP (flags[8]) ? 0 : CODING_FLAG_ISO_LOCKING_SHIFT)
-            | (NILP (flags[9]) ? 0 : CODING_FLAG_ISO_SINGLE_SHIFT)
-            | (NILP (flags[10]) ? 0 : CODING_FLAG_ISO_USE_ROMAN)
-            | (NILP (flags[11]) ? 0 : CODING_FLAG_ISO_USE_OLDJIS)
-            | (NILP (flags[12]) ? 0 : CODING_FLAG_ISO_NO_DIRECTION)
-            | (NILP (flags[13]) ? 0 : CODING_FLAG_ISO_INIT_AT_BOL)
-            | (NILP (flags[14]) ? 0 : CODING_FLAG_ISO_DESIGNATE_AT_BOL)
-            | (NILP (flags[15]) ? 0 : CODING_FLAG_ISO_SAFE)
-            | (NILP (flags[16]) ? 0 : CODING_FLAG_ISO_LATIN_EXTRA)
-            );
-
-       /* Invoke graphic register 0 to plane 0.  */
-       CODING_SPEC_ISO_INVOCATION (coding, 0) = 0;
-       /* Invoke graphic register 1 to plane 1 if we can use full 8-bit.  */
-       CODING_SPEC_ISO_INVOCATION (coding, 1)
-         = (coding->flags & CODING_FLAG_ISO_SEVEN_BITS ? -1 : 1);
-       /* Not single shifting at first.  */
-       CODING_SPEC_ISO_SINGLE_SHIFTING (coding) = 0;
-       /* Beginning of buffer should also be regarded as bol. */
-       CODING_SPEC_ISO_BOL (coding) = 1;
-
-       for (charset = 0; charset <= MAX_CHARSET; charset++)
-         CODING_SPEC_ISO_REVISION_NUMBER (coding, charset) = 255;
-       val = Vcharset_revision_alist;
-       while (CONSP (val))
-         {
-           charset = get_charset_id (Fcar_safe (XCAR (val)));
-           if (charset >= 0
-               && (temp = Fcdr_safe (XCAR (val)), INTEGERP (temp))
-               && (i = XINT (temp), (i >= 0 && (i + '@') < 128)))
-             CODING_SPEC_ISO_REVISION_NUMBER (coding, charset) = i;
-           val = XCDR (val);
-         }
-
-       /* Checks FLAGS[REG] (REG = 0, 1, 2 3) and decide designations.
-          FLAGS[REG] can be one of below:
-               integer CHARSET: CHARSET occupies register I,
-               t: designate nothing to REG initially, but can be used
-                 by any charsets,
-               list of integer, nil, or t: designate the first
-                 element (if integer) to REG initially, the remaining
-                 elements (if integer) is designated to REG on request,
-                 if an element is t, REG can be used by any charsets,
-               nil: REG is never used.  */
-       for (charset = 0; charset <= MAX_CHARSET; charset++)
-         CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding, charset)
-           = CODING_SPEC_ISO_NO_REQUESTED_DESIGNATION;
-       for (i = 0; i < 4; i++)
-         {
-           if ((INTEGERP (flags[i])
-                && (charset = XINT (flags[i]), CHARSET_VALID_P (charset)))
-               || (charset = get_charset_id (flags[i])) >= 0)
-             {
-               CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, i) = charset;
-               CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding, charset) = i;
-             }
-           else if (EQ (flags[i], Qt))
-             {
-               CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, i) = -1;
-               reg_bits |= 1 << i;
-               coding->flags |= CODING_FLAG_ISO_DESIGNATION;
-             }
-           else if (CONSP (flags[i]))
-             {
-               Lisp_Object tail;
-               tail = flags[i];
-
-               coding->flags |= CODING_FLAG_ISO_DESIGNATION;
-               if ((INTEGERP (XCAR (tail))
-                    && (charset = XINT (XCAR (tail)),
-                        CHARSET_VALID_P (charset)))
-                   || (charset = get_charset_id (XCAR (tail))) >= 0)
-                 {
-                   CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, i) = charset;
-                   CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding, charset) =i;
-                 }
-               else
-                 CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, i) = -1;
-               tail = XCDR (tail);
-               while (CONSP (tail))
-                 {
-                   if ((INTEGERP (XCAR (tail))
-                        && (charset = XINT (XCAR (tail)),
-                            CHARSET_VALID_P (charset)))
-                       || (charset = get_charset_id (XCAR (tail))) >= 0)
-                     CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding, charset)
-                       = i;
-                   else if (EQ (XCAR (tail), Qt))
-                     reg_bits |= 1 << i;
-                   tail = XCDR (tail);
-                 }
-             }
-           else
-             CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, i) = -1;
-
-           CODING_SPEC_ISO_DESIGNATION (coding, i)
-             = CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, i);
-         }
-
-       if (reg_bits && ! (coding->flags & CODING_FLAG_ISO_LOCKING_SHIFT))
-         {
-           /* REG 1 can be used only by locking shift in 7-bit env.  */
-           if (coding->flags & CODING_FLAG_ISO_SEVEN_BITS)
-             reg_bits &= ~2;
-           if (! (coding->flags & CODING_FLAG_ISO_SINGLE_SHIFT))
-             /* Without any shifting, only REG 0 and 1 can be used.  */
-             reg_bits &= 3;
-         }
-
-       if (reg_bits)
-         for (charset = 0; charset <= MAX_CHARSET; charset++)
-           {
-             if (CHARSET_DEFINED_P (charset)
-                 && (CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding, charset)
-                     == CODING_SPEC_ISO_NO_REQUESTED_DESIGNATION))
-               {
-                 /* There exist some default graphic registers to be
-                    used by CHARSET.  */
-
-                 /* We had better avoid designating a charset of
-                    CHARS96 to REG 0 as far as possible.  */
-                 if (CHARSET_CHARS (charset) == 96)
-                   CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding, charset)
-                     = (reg_bits & 2
-                        ? 1 : (reg_bits & 4 ? 2 : (reg_bits & 8 ? 3 : 0)));
-                 else
-                   CODING_SPEC_ISO_REQUESTED_DESIGNATION (coding, charset)
-                     = (reg_bits & 1
-                        ? 0 : (reg_bits & 2 ? 1 : (reg_bits & 4 ? 2 : 3)));
-               }
-           }
-      }
-      coding->common_flags |= CODING_REQUIRE_FLUSHING_MASK;
-      coding->spec.iso2022.last_invalid_designation_register = -1;
-      break;
-
-    case 3:
-      coding->type = coding_type_big5;
+       |= (CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK);
+      if (! NILP (AREF (attrs, coding_attr_emacs_mule_full))
+         && ! EQ (CODING_ATTR_CHARSET_LIST (attrs), Vemacs_mule_charset_list))
+       {
+         Lisp_Object tail, safe_charsets;
+         int max_charset_id = 0;
+
+         for (tail = Vemacs_mule_charset_list; CONSP (tail);
+              tail = XCDR (tail))
+           if (max_charset_id < XFASTINT (XCAR (tail)))
+             max_charset_id = XFASTINT (XCAR (tail));
+         safe_charsets = Fmake_string (make_number (max_charset_id + 1),
+                                       make_number (255));
+         for (tail = Vemacs_mule_charset_list; CONSP (tail);
+              tail = XCDR (tail))
+           SSET (safe_charsets, XFASTINT (XCAR (tail)), 0);
+         coding->max_charset_id = max_charset_id;
+         coding->safe_charsets = (char *) SDATA (safe_charsets);
+       }
+    }
+  else if (EQ (coding_type, Qshift_jis))
+    {
+      coding->detector = detect_coding_sjis;
+      coding->decoder = decode_coding_sjis;
+      coding->encoder = encode_coding_sjis;
       coding->common_flags
-       |= CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK;
-      coding->flags
-       = (NILP (XVECTOR (coding_spec)->contents[4])
-          ? CODING_FLAG_BIG5_HKU
-          : CODING_FLAG_BIG5_ETEN);
-      break;
-
-    case 4:
-      coding->type = coding_type_ccl;
+       |= (CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK);
+    }
+  else if (EQ (coding_type, Qbig5))
+    {
+      coding->detector = detect_coding_big5;
+      coding->decoder = decode_coding_big5;
+      coding->encoder = encode_coding_big5;
       coding->common_flags
-       |= CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK;
-      {
-       val = XVECTOR (coding_spec)->contents[4];
-       if (! CONSP (val)
-           || setup_ccl_program (&(coding->spec.ccl.decoder),
-                                 XCAR (val)) < 0
-           || setup_ccl_program (&(coding->spec.ccl.encoder),
-                                 XCDR (val)) < 0)
-         goto label_invalid_coding_system;
-
-       bzero (coding->spec.ccl.valid_codes, 256);
-       val = Fplist_get (plist, Qvalid_codes);
-       if (CONSP (val))
-         {
-           Lisp_Object this;
-
-           for (; CONSP (val); val = XCDR (val))
-             {
-               this = XCAR (val);
-               if (INTEGERP (this)
-                   && XINT (this) >= 0 && XINT (this) < 256)
-                 coding->spec.ccl.valid_codes[XINT (this)] = 1;
-               else if (CONSP (this)
-                        && INTEGERP (XCAR (this))
-                        && INTEGERP (XCDR (this)))
-                 {
-                   int start = XINT (XCAR (this));
-                   int end = XINT (XCDR (this));
-
-                   if (start >= 0 && start <= end && end < 256)
-                     while (start <= end)
-                       coding->spec.ccl.valid_codes[start++] = 1;
-                 }
-             }
-         }
-      }
-      coding->common_flags |= CODING_REQUIRE_FLUSHING_MASK;
-      coding->spec.ccl.cr_carryover = 0;
-      coding->spec.ccl.eight_bit_carryover[0] = 0;
-      break;
-
-    case 5:
-      coding->type = coding_type_raw_text;
-      break;
-
-    default:
-      goto label_invalid_coding_system;
+       |= (CODING_REQUIRE_DECODING_MASK | CODING_REQUIRE_ENCODING_MASK);
+    }
+  else                         /* EQ (coding_type, Qraw_text) */
+    {
+      coding->detector = NULL;
+      coding->decoder = decode_coding_raw_text;
+      coding->encoder = encode_coding_raw_text;
     }
-  return 0;
 
- label_invalid_coding_system:
-  coding->type = coding_type_no_conversion;
-  coding->category_idx = CODING_CATEGORY_IDX_BINARY;
-  coding->common_flags = 0;
-  coding->eol_type = CODING_EOL_LF;
-  coding->pre_write_conversion = coding->post_read_conversion = Qnil;
-  return -1;
+  return;
 }
 
-/* Free memory blocks allocated for storing composition information.  */
+/* Return raw-text or one of its subsidiaries that has the same
+   eol_type as CODING-SYSTEM.  */
 
-void
-coding_free_composition_data (coding)
-     struct coding_system *coding;
+Lisp_Object
+raw_text_coding_system (coding_system)
+     Lisp_Object coding_system;
 {
-  struct composition_data *cmp_data = coding->cmp_data, *next;
-
-  if (!cmp_data)
-    return;
-  /* Memory blocks are chained.  At first, rewind to the first, then,
-     free blocks one by one.  */
-  while (cmp_data->prev)
-    cmp_data = cmp_data->prev;
-  while (cmp_data)
-    {
-      next = cmp_data->next;
-      xfree (cmp_data);
-      cmp_data = next;
-    }
-  coding->cmp_data = NULL;
-}
+  Lisp_Object spec, attrs;
+  Lisp_Object eol_type, raw_text_eol_type;
 
-/* Set `char_offset' member of all memory blocks pointed by
-   coding->cmp_data to POS.  */
+  if (NILP (coding_system))
+    return Qraw_text;
+  spec = CODING_SYSTEM_SPEC (coding_system);
+  attrs = AREF (spec, 0);
 
-void
-coding_adjust_composition_offset (coding, pos)
-     struct coding_system *coding;
-     int pos;
-{
-  struct composition_data *cmp_data;
+  if (EQ (CODING_ATTR_TYPE (attrs), Qraw_text))
+    return coding_system;
 
-  for (cmp_data = coding->cmp_data; cmp_data; cmp_data = cmp_data->next)
-    cmp_data->char_offset = pos;
+  eol_type = AREF (spec, 2);
+  if (VECTORP (eol_type))
+    return Qraw_text;
+  spec = CODING_SYSTEM_SPEC (Qraw_text);
+  raw_text_eol_type = AREF (spec, 2);
+  return (EQ (eol_type, Qunix) ? AREF (raw_text_eol_type, 0)
+         : EQ (eol_type, Qdos) ? AREF (raw_text_eol_type, 1)
+         : AREF (raw_text_eol_type, 2));
 }
 
-/* Setup raw-text or one of its subsidiaries in the structure
-   coding_system CODING according to the already setup value eol_type
-   in CODING.  CODING should be setup for some coding system in
-   advance.  */
 
-void
-setup_raw_text_coding_system (coding)
-     struct coding_system *coding;
+/* If CODING_SYSTEM doesn't specify end-of-line format but PARENT
+   does, return one of the subsidiary that has the same eol-spec as
+   PARENT.  Otherwise, return CODING_SYSTEM.  */
+
+Lisp_Object
+coding_inherit_eol_type (coding_system, parent)
+     Lisp_Object coding_system, parent;
 {
-  if (coding->type != coding_type_raw_text)
-    {
-      coding->symbol = Qraw_text;
-      coding->type = coding_type_raw_text;
-      if (coding->eol_type != CODING_EOL_UNDECIDED)
-       {
-         Lisp_Object subsidiaries;
-         subsidiaries = Fget (Qraw_text, Qeol_type);
+  Lisp_Object spec, attrs, eol_type;
 
-         if (VECTORP (subsidiaries)
-             && XVECTOR (subsidiaries)->size == 3)
-           coding->symbol
-             = XVECTOR (subsidiaries)->contents[coding->eol_type];
-       }
-      setup_coding_system (coding->symbol, coding);
-    }
-  return;
+  if (NILP (coding_system))
+    coding_system = Qraw_text;
+  spec = CODING_SYSTEM_SPEC (coding_system);
+  attrs = AREF (spec, 0);
+  eol_type = AREF (spec, 2);
+  if (VECTORP (eol_type)
+      && ! NILP (parent))
+    {
+      Lisp_Object parent_spec;
+      Lisp_Object parent_eol_type;
+
+      parent_spec
+       = CODING_SYSTEM_SPEC (buffer_defaults.buffer_file_coding_system);
+      parent_eol_type = AREF (parent_spec, 2);
+      if (EQ (parent_eol_type, Qunix))
+       coding_system = AREF (eol_type, 0);
+      else if (EQ (parent_eol_type, Qdos))
+       coding_system = AREF (eol_type, 1);
+      else if (EQ (parent_eol_type, Qmac))
+       coding_system = AREF (eol_type, 2);
+    }
+  return coding_system;
 }
 
 /* Emacs has a mechanism to automatically detect a coding system if it
@@ -4001,14 +5094,14 @@ setup_raw_text_coding_system (coding)
    o coding-category-iso-7-else
 
        The category for a coding system which has the same code range
-       as ISO2022 of 7-bit environment but uses locking shift or
+       as ISO2022 of 7-bit environemnt but uses locking shift or
        single shift functions.  Assigned the coding-system (Lisp
        symbol) `iso-2022-7bit-lock' by default.
 
    o coding-category-iso-8-else
 
        The category for a coding system which has the same code range
-       as ISO2022 of 8-bit environment but uses locking shift or
+       as ISO2022 of 8-bit environemnt but uses locking shift or
        single shift functions.  Assigned the coding-system (Lisp
        symbol) `iso-2022-8bit-ss2' by default.
 
@@ -4051,3354 +5144,3459 @@ setup_raw_text_coding_system (coding)
        `no-conversion' by default.
 
    Each of them is a Lisp symbol and the value is an actual
-   `coding-system' (this is also a Lisp symbol) assigned by a user.
+   `coding-system's (this is also a Lisp symbol) assigned by a user.
    What Emacs does actually is to detect a category of coding system.
    Then, it uses a `coding-system' assigned to it.  If Emacs can't
-   decide a single possible category, it selects a category of the
+   decide only one possible category, it selects a category of the
    highest priority.  Priorities of categories are also specified by a
    user in a Lisp variable `coding-category-list'.
 
 */
 
-static
-int ascii_skip_code[256];
+#define EOL_SEEN_NONE  0
+#define EOL_SEEN_LF    1
+#define EOL_SEEN_CR    2
+#define EOL_SEEN_CRLF  4
 
-/* Detect how a text of length SRC_BYTES pointed by SOURCE is encoded.
-   If it detects possible coding systems, return an integer in which
-   appropriate flag bits are set.  Flag bits are defined by macros
-   CODING_CATEGORY_MASK_XXX in `coding.h'.  If PRIORITIES is non-NULL,
-   it should point the table `coding_priorities'.  In that case, only
-   the flag bit for a coding system of the highest priority is set in
-   the returned value.  If MULTIBYTEP is nonzero, 8-bit codes of the
-   range 0x80..0x9F are in multibyte form.
+/* Detect how end-of-line of a text of length SRC_BYTES pointed by
+   SOURCE is encoded.  If CATEGORY is one of
+   coding_category_utf_16_XXXX, assume that CR and LF are encoded by
+   two-byte, else they are encoded by one-byte.
+
+   Return one of EOL_SEEN_XXX.  */
 
-   How many ASCII characters are at the head is returned as *SKIP.  */
+#define MAX_EOL_CHECK_COUNT 3
 
 static int
-detect_coding_mask (source, src_bytes, priorities, skip, multibytep)
+detect_eol (source, src_bytes, category)
      unsigned char *source;
-     int src_bytes, *priorities, *skip;
-     int multibytep;
+     EMACS_INT src_bytes;
+     enum coding_category category;
 {
-  register unsigned char c;
-  unsigned char *src = source, *src_end = source + src_bytes;
-  unsigned int mask, utf16_examined_p, iso2022_examined_p;
-  int i;
+  unsigned char *src = source, *src_end = src + src_bytes;
+  unsigned char c;
+  int total  = 0;
+  int eol_seen = EOL_SEEN_NONE;
 
-  /* At first, skip all ASCII characters and control characters except
-     for three ISO2022 specific control characters.  */
-  ascii_skip_code[ISO_CODE_SO] = 0;
-  ascii_skip_code[ISO_CODE_SI] = 0;
-  ascii_skip_code[ISO_CODE_ESC] = 0;
-
- label_loop_detect_coding:
-  while (src < src_end && ascii_skip_code[*src]) src++;
-  *skip = src - source;
-
-  if (src >= src_end)
-    /* We found nothing other than ASCII.  There's nothing to do.  */
-    return 0;
-
-  c = *src;
-  /* The text seems to be encoded in some multilingual coding system.
-     Now, try to find in which coding system the text is encoded.  */
-  if (c < 0x80)
-    {
-      /* i.e. (c == ISO_CODE_ESC || c == ISO_CODE_SI || c == ISO_CODE_SO) */
-      /* C is an ISO2022 specific control code of C0.  */
-      mask = detect_coding_iso2022 (src, src_end, multibytep);
-      if (mask == 0)
-       {
-         /* No valid ISO2022 code follows C.  Try again.  */
-         src++;
-         if (c == ISO_CODE_ESC)
-           ascii_skip_code[ISO_CODE_ESC] = 1;
-         else
-           ascii_skip_code[ISO_CODE_SO] = ascii_skip_code[ISO_CODE_SI] = 1;
-         goto label_loop_detect_coding;
-       }
-      if (priorities)
+  if ((1 << category) & CATEGORY_MASK_UTF_16)
+    {
+      int msb, lsb;
+
+      msb = category == (coding_category_utf_16_le
+                        | coding_category_utf_16_le_nosig);
+      lsb = 1 - msb;
+
+      while (src + 1 < src_end)
        {
-         for (i = 0; i < CODING_CATEGORY_IDX_MAX; i++)
+         c = src[lsb];
+         if (src[msb] == 0 && (c == '\n' || c == '\r'))
            {
-             if (mask & priorities[i])
-               return priorities[i];
+             int this_eol;
+
+             if (c == '\n')
+               this_eol = EOL_SEEN_LF;
+             else if (src + 3 >= src_end
+                      || src[msb + 2] != 0
+                      || src[lsb + 2] != '\n')
+               this_eol = EOL_SEEN_CR;
+             else
+               this_eol = EOL_SEEN_CRLF;
+
+             if (eol_seen == EOL_SEEN_NONE)
+               /* This is the first end-of-line.  */
+               eol_seen = this_eol;
+             else if (eol_seen != this_eol)
+               {
+                 /* The found type is different from what found before.  */
+                 eol_seen = EOL_SEEN_LF;
+                 break;
+               }
+             if (++total == MAX_EOL_CHECK_COUNT)
+               break;
            }
-         return CODING_CATEGORY_MASK_RAW_TEXT;
+         src += 2;
        }
     }
   else
     {
-      int try;
+      while (src < src_end)
+       {
+         c = *src++;
+         if (c == '\n' || c == '\r')
+           {
+             int this_eol;
+
+             if (c == '\n')
+               this_eol = EOL_SEEN_LF;
+             else if (src >= src_end || *src != '\n')
+               this_eol = EOL_SEEN_CR;
+             else
+               this_eol = EOL_SEEN_CRLF, src++;
+
+             if (eol_seen == EOL_SEEN_NONE)
+               /* This is the first end-of-line.  */
+               eol_seen = this_eol;
+             else if (eol_seen != this_eol)
+               {
+                 /* The found type is different from what found before.  */
+                 eol_seen = EOL_SEEN_LF;
+                 break;
+               }
+             if (++total == MAX_EOL_CHECK_COUNT)
+               break;
+           }
+       }
+    }
+  return eol_seen;
+}
+
+
+static void
+adjust_coding_eol_type (coding, eol_seen)
+     struct coding_system *coding;
+     int eol_seen;
+{
+  Lisp_Object eol_type;
+
+  eol_type = CODING_ID_EOL_TYPE (coding->id);
+  if (eol_seen & EOL_SEEN_LF)
+    coding->id = CODING_SYSTEM_ID (AREF (eol_type, 0));
+  else if (eol_seen & EOL_SEEN_CRLF)
+    coding->id = CODING_SYSTEM_ID (AREF (eol_type, 1));
+  else if (eol_seen & EOL_SEEN_CR)
+    coding->id = CODING_SYSTEM_ID (AREF (eol_type, 2));
+}
 
-      if (multibytep && c == LEADING_CODE_8_BIT_CONTROL)
-       c = src[1] - 0x20;
+/* Detect how a text specified in CODING is encoded.  If a coding
+   system is detected, update fields of CODING by the detected coding
+   system.  */
 
-      if (c < 0xA0)
+void
+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;
+  coding_set_source (coding);
+
+  src_end = coding->source + coding->src_bytes;
+
+  /* If we have not yet decided the text encoding type, detect it
+     now.  */
+  if (EQ (CODING_ATTR_TYPE (CODING_ID_ATTRS (coding->id)), Qundecided))
+    {
+      int c, i;
+
+      for (src = coding->source; src < src_end; src++)
        {
-         /* C is the first byte of SJIS character code,
-            or a leading-code of Emacs' internal format (emacs-mule),
-            or the first byte of UTF-16.  */
-         try = (CODING_CATEGORY_MASK_SJIS
-                 | CODING_CATEGORY_MASK_EMACS_MULE
-                 | CODING_CATEGORY_MASK_UTF_16_BE
-                 | CODING_CATEGORY_MASK_UTF_16_LE);
-
-         /* Or, if C is a special latin extra code,
-            or is an ISO2022 specific control code of C1 (SS2 or SS3),
-            or is an ISO2022 control-sequence-introducer (CSI),
-            we should also consider the possibility of ISO2022 codings.  */
-         if ((VECTORP (Vlatin_extra_code_table)
-              && !NILP (XVECTOR (Vlatin_extra_code_table)->contents[c]))
-             || (c == ISO_CODE_SS2 || c == ISO_CODE_SS3)
-             || (c == ISO_CODE_CSI
-                 && (src < src_end
-                     && (*src == ']'
-                         || ((*src == '0' || *src == '1' || *src == '2')
-                             && src + 1 < src_end
-                             && src[1] == ']')))))
-           try |= (CODING_CATEGORY_MASK_ISO_8_ELSE
-                    | CODING_CATEGORY_MASK_ISO_8BIT);
+         c = *src;
+         if (c & 0x80 || (c < 0x20 && (c == ISO_CODE_ESC
+                                       || c == ISO_CODE_SI
+                                       || c == ISO_CODE_SO)))
+           break;
        }
-      else
-       /* C is a character of ISO2022 in graphic plane right,
-          or a SJIS's 1-byte character code (i.e. JISX0201),
-          or the first byte of BIG5's 2-byte code,
-          or the first byte of UTF-8/16.  */
-       try = (CODING_CATEGORY_MASK_ISO_8_ELSE
-               | CODING_CATEGORY_MASK_ISO_8BIT
-               | CODING_CATEGORY_MASK_SJIS
-               | CODING_CATEGORY_MASK_BIG5
-               | CODING_CATEGORY_MASK_UTF_8
-               | CODING_CATEGORY_MASK_UTF_16_BE
-               | CODING_CATEGORY_MASK_UTF_16_LE);
-
-      /* Or, we may have to consider the possibility of CCL.  */
-      if (coding_system_table[CODING_CATEGORY_IDX_CCL]
-         && (coding_system_table[CODING_CATEGORY_IDX_CCL]
-             ->spec.ccl.valid_codes)[c])
-       try |= CODING_CATEGORY_MASK_CCL;
-
-      mask = 0;
-      utf16_examined_p = iso2022_examined_p = 0;
-      if (priorities)
+      coding->head_ascii = src - (coding->source + coding->consumed);
+
+      if (coding->head_ascii < coding->src_bytes)
        {
-         for (i = 0; i < CODING_CATEGORY_IDX_MAX; i++)
+         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++)
            {
-             if (!iso2022_examined_p
-                 && (priorities[i] & try & CODING_CATEGORY_MASK_ISO))
+             category = coding_priorities[i];
+             this = coding_categories + category;
+             if (this->id < 0)
                {
-                 mask |= detect_coding_iso2022 (src, src_end, multibytep);
-                 iso2022_examined_p = 1;
+                 /* No coding system of this category is defined.  */
+                 detect_info.rejected |= (1 << category);
                }
-             else if (priorities[i] & try & CODING_CATEGORY_MASK_SJIS)
-               mask |= detect_coding_sjis (src, src_end, multibytep);
-             else if (priorities[i] & try & CODING_CATEGORY_MASK_UTF_8)
-               mask |= detect_coding_utf_8 (src, src_end, multibytep);
-             else if (!utf16_examined_p
-                      && (priorities[i] & try &
-                          CODING_CATEGORY_MASK_UTF_16_BE_LE))
+             else if (category >= coding_category_raw_text)
+               continue;
+             else if (detect_info.checked & (1 << category))
                {
-                 mask |= detect_coding_utf_16 (src, src_end, multibytep);
-                 utf16_examined_p = 1;
+                 if (detect_info.found & (1 << category))
+                   break;
                }
-             else if (priorities[i] & try & CODING_CATEGORY_MASK_BIG5)
-               mask |= detect_coding_big5 (src, src_end, multibytep);
-             else if (priorities[i] & try & CODING_CATEGORY_MASK_EMACS_MULE)
-               mask |= detect_coding_emacs_mule (src, src_end, multibytep);
-             else if (priorities[i] & try & CODING_CATEGORY_MASK_CCL)
-               mask |= detect_coding_ccl (src, src_end, multibytep);
-             else if (priorities[i] & CODING_CATEGORY_MASK_RAW_TEXT)
-               mask |= CODING_CATEGORY_MASK_RAW_TEXT;
-             else if (priorities[i] & CODING_CATEGORY_MASK_BINARY)
-               mask |= CODING_CATEGORY_MASK_BINARY;
-             if (mask & priorities[i])
-               return priorities[i];
+             else if ((*(this->detector)) (coding, &detect_info)
+                      && detect_info.found & (1 << category))
+               break;
            }
-         return CODING_CATEGORY_MASK_RAW_TEXT;
+         if (i < coding_category_raw_text)
+           setup_coding_system (CODING_ID_NAME (this->id), coding);
+         else if (detect_info.rejected == CATEGORY_MASK_ANY)
+           setup_coding_system (Qraw_text, coding);
+         else if (detect_info.rejected)
+           for (i = 0; i < coding_category_raw_text; i++)
+             if (! (detect_info.rejected & (1 << coding_priorities[i])))
+               {
+                 this = coding_categories + coding_priorities[i];
+                 setup_coding_system (CODING_ID_NAME (this->id), coding);
+                 break;
+               }
        }
-      if (try & CODING_CATEGORY_MASK_ISO)
-       mask |= detect_coding_iso2022 (src, src_end, multibytep);
-      if (try & CODING_CATEGORY_MASK_SJIS)
-       mask |= detect_coding_sjis (src, src_end, multibytep);
-      if (try & CODING_CATEGORY_MASK_BIG5)
-       mask |= detect_coding_big5 (src, src_end, multibytep);
-      if (try & CODING_CATEGORY_MASK_UTF_8)
-       mask |= detect_coding_utf_8 (src, src_end, multibytep);
-      if (try & CODING_CATEGORY_MASK_UTF_16_BE_LE)
-       mask |= detect_coding_utf_16 (src, src_end, multibytep);
-      if (try & CODING_CATEGORY_MASK_EMACS_MULE)
-       mask |= detect_coding_emacs_mule (src, src_end, multibytep);
-      if (try & CODING_CATEGORY_MASK_CCL)
-       mask |= detect_coding_ccl (src, src_end, multibytep);
-    }
-  return (mask | CODING_CATEGORY_MASK_RAW_TEXT | CODING_CATEGORY_MASK_BINARY);
-}
+    }
+  else if (EQ (CODING_ATTR_TYPE (CODING_ID_ATTRS (coding->id)), Qutf_16))
+    {
+      Lisp_Object coding_systems;
+      struct coding_detection_info detect_info;
+
+      coding_systems
+       = AREF (CODING_ID_ATTRS (coding->id), coding_attr_utf_16_bom);
+      detect_info.found = detect_info.rejected = 0;
+      if (CONSP (coding_systems)
+         && detect_coding_utf_16 (coding, &detect_info)
+         && (detect_info.found & (CATEGORY_MASK_UTF_16_LE
+                                  | CATEGORY_MASK_UTF_16_BE)))
+       {
+         if (detect_info.found & CATEGORY_MASK_UTF_16_LE)
+           setup_coding_system (XCAR (coding_systems), coding);
+         else
+           setup_coding_system (XCDR (coding_systems), coding);
+       }
+    }
 
-/* Detect how a text of length SRC_BYTES pointed by SRC is encoded.
-   The information of the detected coding system is set in CODING.  */
+  attrs = CODING_ID_ATTRS (coding->id);
+  coding_type = CODING_ATTR_TYPE (attrs);
 
-void
-detect_coding (coding, src, src_bytes)
-     struct coding_system *coding;
-     const unsigned char *src;
-     int src_bytes;
-{
-  unsigned int idx;
-  int skip, mask;
-  Lisp_Object val;
+  /* If we have not yet decided the EOL type, detect it now.  But, the
+     detection is impossible for a CCL based coding system, in which
+     case, we detct the EOL type after decoding.  */
+  if (VECTORP (CODING_ID_EOL_TYPE (coding->id))
+      && ! EQ (coding_type, Qccl))
+    {
+      int eol_seen = detect_eol (coding->source, coding->src_bytes,
+                                XINT (CODING_ATTR_CATEGORY (attrs)));
 
-  val = Vcoding_category_list;
-  mask = detect_coding_mask (src, src_bytes, coding_priorities, &skip,
-                            coding->src_multibyte);
-  coding->heading_ascii = skip;
+      if (eol_seen != EOL_SEEN_NONE)
+       adjust_coding_eol_type (coding, eol_seen);
+    }
+}
 
-  if (!mask) return;
 
-  /* We found a single coding system of the highest priority in MASK.  */
-  idx = 0;
-  while (mask && ! (mask & 1)) mask >>= 1, idx++;
-  if (! mask)
-    idx = CODING_CATEGORY_IDX_RAW_TEXT;
+static void
+decode_eol (coding)
+     struct coding_system *coding;
+{
+  if (VECTORP (CODING_ID_EOL_TYPE (coding->id)))
+    {
+      unsigned char *p = CHAR_POS_ADDR (coding->dst_pos);
+      unsigned char *pend = p + coding->produced;
+      int eol_seen = EOL_SEEN_NONE;
 
-  val = SYMBOL_VALUE (XVECTOR (Vcoding_category_table)->contents[idx]);
+      for (; p < pend; p++)
+       {
+         if (*p == '\n')
+           eol_seen |= EOL_SEEN_LF;
+         else if (*p == '\r')
+           {
+             if (p + 1 < pend && *(p + 1) == '\n')
+               {
+                 eol_seen |= EOL_SEEN_CRLF;
+                 p++;
+               }
+             else
+               eol_seen |= EOL_SEEN_CR;
+           }
+       }
+      if (eol_seen != EOL_SEEN_NONE)
+       adjust_coding_eol_type (coding, eol_seen);
+    }
 
-  if (coding->eol_type != CODING_EOL_UNDECIDED)
+  if (EQ (CODING_ID_EOL_TYPE (coding->id), Qmac))
     {
-      Lisp_Object tmp;
+      unsigned char *p = CHAR_POS_ADDR (coding->dst_pos);
+      unsigned char *pend = p + coding->produced;
 
-      tmp = Fget (val, Qeol_type);
-      if (VECTORP (tmp))
-       val = XVECTOR (tmp)->contents[coding->eol_type];
+      for (; p < pend; p++)
+       if (*p == '\r')
+         *p = '\n';
     }
+  else if (EQ (CODING_ID_EOL_TYPE (coding->id), Qdos))
+    {
+      unsigned char *p, *pbeg, *pend;
+      Lisp_Object undo_list;
 
-  /* Setup this new coding system while preserving some slots.  */
-  {
-    int src_multibyte = coding->src_multibyte;
-    int dst_multibyte = coding->dst_multibyte;
+      move_gap_both (coding->dst_pos + coding->produced_char,
+                    coding->dst_pos_byte + coding->produced);
+      undo_list = current_buffer->undo_list;
+      current_buffer->undo_list = Qt;
+      del_range_2 (coding->dst_pos, coding->dst_pos_byte, GPT, GPT_BYTE, 0);
+      current_buffer->undo_list = undo_list;
+      pbeg = GPT_ADDR;
+      pend = pbeg + coding->produced;
 
-    setup_coding_system (val, coding);
-    coding->src_multibyte = src_multibyte;
-    coding->dst_multibyte = dst_multibyte;
-    coding->heading_ascii = skip;
-  }
+      for (p = pend - 1; p >= pbeg; p--)
+       if (*p == '\r')
+         {
+           safe_bcopy ((char *) (p + 1), (char *) p, pend - p - 1);
+           pend--;
+         }
+      coding->produced_char -= coding->produced - (pend - pbeg);
+      coding->produced = pend - pbeg;
+      insert_from_gap (coding->produced_char, coding->produced);
+    }
 }
 
-/* Detect how end-of-line of a text of length SRC_BYTES pointed by
-   SOURCE is encoded.  Return one of CODING_EOL_LF, CODING_EOL_CRLF,
-   CODING_EOL_CR, and CODING_EOL_UNDECIDED.
+static void
+translate_chars (coding, table)
+     struct coding_system *coding;
+     Lisp_Object table;
+{
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf + coding->charbuf_used;
+  int c;
 
-   How many non-eol characters are at the head is returned as *SKIP.  */
+  if (coding->chars_at_source)
+    return;
 
-#define MAX_EOL_CHECK_COUNT 3
+  while (charbuf < charbuf_end)
+    {
+      c = *charbuf;
+      if (c < 0)
+       charbuf += c;
+      else
+       *charbuf++ = translate_char (table, c);
+    }
+}
 
 static int
-detect_eol_type (source, src_bytes, skip)
-     unsigned char *source;
-     int src_bytes, *skip;
+produce_chars (coding)
+     struct coding_system *coding;
 {
-  unsigned char *src = source, *src_end = src + src_bytes;
-  unsigned char c;
-  int total = 0;               /* How many end-of-lines are found so far.  */
-  int eol_type = CODING_EOL_UNDECIDED;
-  int this_eol_type;
+  unsigned char *dst = coding->destination + coding->produced;
+  unsigned char *dst_end = coding->destination + coding->dst_bytes;
+  int produced;
+  int produced_chars = 0;
 
-  *skip = 0;
-
-  while (src < src_end && total < MAX_EOL_CHECK_COUNT)
+  if (! coding->chars_at_source)
     {
-      c = *src++;
-      if (c == '\n' || c == '\r')
+      /* 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)
        {
-         if (*skip == 0)
-           *skip = src - 1 - source;
-         total++;
-         if (c == '\n')
-           this_eol_type = CODING_EOL_LF;
-         else if (src >= src_end || *src != '\n')
-           this_eol_type = CODING_EOL_CR;
-         else
-           this_eol_type = CODING_EOL_CRLF, src++;
+         int c = *buf++;
 
-         if (eol_type == CODING_EOL_UNDECIDED)
-           /* This is the first end-of-line.  */
-           eol_type = this_eol_type;
-         else if (eol_type != this_eol_type)
+         if (dst >= adjusted_dst_end)
            {
-             /* The found type is different from what found before.  */
-             eol_type = CODING_EOL_INCONSISTENT;
-             break;
+             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++;
            }
+         else
+           /* This is an annotation datum.  (-C) is the length of
+              it.  */
+           buf += -c - 1;
        }
     }
-
-  if (*skip == 0)
-    *skip = src_end - source;
-  return eol_type;
-}
-
-/* Like detect_eol_type, but detect EOL type in 2-octet
-   big-endian/little-endian format for coding systems utf-16-be and
-   utf-16-le.  */
-
-static int
-detect_eol_type_in_2_octet_form (source, src_bytes, skip, big_endian_p)
-     unsigned char *source;
-     int src_bytes, *skip, big_endian_p;
-{
-  unsigned char *src = source, *src_end = src + src_bytes;
-  unsigned int c1, c2;
-  int total = 0;               /* How many end-of-lines are found so far.  */
-  int eol_type = CODING_EOL_UNDECIDED;
-  int this_eol_type;
-  int msb, lsb;
-
-  if (big_endian_p)
-    msb = 0, lsb = 1;
   else
-    msb = 1, lsb = 0;
-
-  *skip = 0;
-
-  while ((src + 1) < src_end && total < MAX_EOL_CHECK_COUNT)
     {
-      c1 = (src[msb] << 8) | (src[lsb]);
-      src += 2;
+      const unsigned char *src = coding->source;
+      const unsigned char *src_end = src + coding->src_bytes;
+      Lisp_Object eol_type;
 
-      if (c1 == '\n' || c1 == '\r')
+      eol_type = CODING_ID_EOL_TYPE (coding->id);
+
+      if (coding->src_multibyte != coding->dst_multibyte)
        {
-         if (*skip == 0)
-           *skip = src - 2 - source;
-         total++;
-         if (c1 == '\n')
+         if (coding->src_multibyte)
            {
-             this_eol_type = CODING_EOL_LF;
+             int multibytep = 1;
+             int consumed_chars;
+
+             while (1)
+               {
+                 const unsigned char *src_base = src;
+                 int c;
+
+                 ONE_MORE_BYTE (c);
+                 if (c == '\r')
+                   {
+                     if (EQ (eol_type, Qdos))
+                       {
+                         if (src == src_end)
+                           {
+                             coding->result = CODING_RESULT_INSUFFICIENT_SRC;
+                             goto no_more_source;
+                           }
+                         if (*src == '\n')
+                           c = *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++;
+               }
+           no_more_source:
+             ;
            }
          else
+           while (src < src_end)
+             {
+               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);
+                       dst_end = coding->destination + coding->dst_bytes;
+                       coding_set_source (coding);
+                       src = coding->source + coding->consumed;
+                       src_end = coding->source + coding->src_bytes;
+                     }
+                 }
+               EMIT_ONE_BYTE (c);
+             }
+       }
+      else
+       {
+         if (!EQ (coding->src_object, coding->dst_object))
            {
-             if ((src + 1) >= src_end)
-               {
-                 this_eol_type = CODING_EOL_CR;
-               }
-             else
+             int require = coding->src_bytes - coding->dst_bytes;
+
+             if (require > 0)
                {
-                 c2 = (src[msb] << 8) | (src[lsb]);
-                 if (c2 == '\n')
-                   this_eol_type = CODING_EOL_CRLF, src += 2;
-                 else
-                   this_eol_type = CODING_EOL_CR;
+                 EMACS_INT offset = src - coding->source;
+
+                 dst = alloc_destination (coding, require, dst);
+                 coding_set_source (coding);
+                 src = coding->source + offset;
+                 src_end = coding->source + coding->src_bytes;
                }
            }
-
-         if (eol_type == CODING_EOL_UNDECIDED)
-           /* This is the first end-of-line.  */
-           eol_type = this_eol_type;
-         else if (eol_type != this_eol_type)
+         produced_chars = coding->src_chars;
+         while (src < src_end)
            {
-             /* The found type is different from what found before.  */
-             eol_type = CODING_EOL_INCONSISTENT;
-             break;
+             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;
            }
        }
+      coding->consumed = coding->src_bytes;
+      coding->consumed_char = coding->src_chars;
     }
 
-  if (*skip == 0)
-    *skip = src_end - source;
-  return eol_type;
+  produced = dst - (coding->destination + coding->produced);
+  if (BUFFERP (coding->dst_object))
+    insert_from_gap (produced_chars, produced);
+  coding->produced += produced;
+  coding->produced_char += produced_chars;
+  return produced_chars;
 }
 
-/* Detect how end-of-line of a text of length SRC_BYTES pointed by SRC
-   is encoded.  If it detects an appropriate format of end-of-line, it
-   sets the information in *CODING.  */
+/* Compose text in CODING->object according to the annotation data at
+   CHARBUF.  CHARBUF is an array:
+     [ -LENGTH ANNOTATION_MASK FROM TO METHOD COMP_LEN [ COMPONENTS... ] ]
+ */
 
-void
-detect_eol (coding, src, src_bytes)
+static INLINE void
+produce_composition (coding, charbuf)
      struct coding_system *coding;
-     const unsigned char *src;
-     int src_bytes;
+     int *charbuf;
 {
-  Lisp_Object val;
-  int skip;
-  int eol_type;
+  int len;
+  EMACS_INT from, to;
+  enum composition_method method;
+  Lisp_Object components;
 
-  switch (coding->category_idx)
-    {
-    case CODING_CATEGORY_IDX_UTF_16_BE:
-      eol_type = detect_eol_type_in_2_octet_form (src, src_bytes, &skip, 1);
-      break;
-    case CODING_CATEGORY_IDX_UTF_16_LE:
-      eol_type = detect_eol_type_in_2_octet_form (src, src_bytes, &skip, 0);
-      break;
-    default:
-      eol_type = detect_eol_type (src, src_bytes, &skip);
-      break;
-    }
+  len = -charbuf[0];
+  from = coding->dst_pos + charbuf[2];
+  to = coding->dst_pos + charbuf[3];
+  method = (enum composition_method) (charbuf[4]);
 
-  if (coding->heading_ascii > skip)
-    coding->heading_ascii = skip;
+  if (method == COMPOSITION_RELATIVE)
+    components = Qnil;
   else
-    skip = coding->heading_ascii;
-
-  if (eol_type == CODING_EOL_UNDECIDED)
-    return;
-  if (eol_type == CODING_EOL_INCONSISTENT)
-    {
-#if 0
-      /* This code is suppressed until we find a better way to
-        distinguish raw text file and binary file.  */
-
-      /* If we have already detected that the coding is raw-text, the
-        coding should actually be no-conversion.  */
-      if (coding->type == coding_type_raw_text)
-       {
-         setup_coding_system (Qno_conversion, coding);
-         return;
-       }
-      /* Else, let's decode only text code anyway.  */
-#endif /* 0 */
-      eol_type = CODING_EOL_LF;
-    }
-
-  val = Fget (coding->symbol, Qeol_type);
-  if (VECTORP (val) && XVECTOR (val)->size == 3)
     {
-      int src_multibyte = coding->src_multibyte;
-      int dst_multibyte = coding->dst_multibyte;
-      struct composition_data *cmp_data = coding->cmp_data;
+      Lisp_Object args[MAX_COMPOSITION_COMPONENTS * 2 - 1];
+      int i;
 
-      setup_coding_system (XVECTOR (val)->contents[eol_type], coding);
-      coding->src_multibyte = src_multibyte;
-      coding->dst_multibyte = dst_multibyte;
-      coding->heading_ascii = skip;
-      coding->cmp_data = cmp_data;
+      len -= 5;
+      charbuf += 5;
+      for (i = 0; i < len; i++)
+       args[i] = make_number (charbuf[i]);
+      components = (method == COMPOSITION_WITH_ALTCHARS
+                   ? Fstring (len, args) : Fvector (len, args));
     }
+  compose_text (from, to, components, Qnil, coding->dst_object);
 }
 
-#define CONVERSION_BUFFER_EXTRA_ROOM 256
-
-#define DECODING_BUFFER_MAG(coding)                    \
-  (coding->type == coding_type_iso2022                 \
-   ? 3                                                 \
-   : (coding->type == coding_type_ccl                  \
-      ? coding->spec.ccl.decoder.buf_magnification     \
-      : 2))
 
-/* Return maximum size (bytes) of a buffer enough for decoding
-   SRC_BYTES of text encoded in CODING.  */
+/* 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 ]
+ */
 
-int
-decoding_buffer_size (coding, src_bytes)
+static INLINE void
+produce_charset (coding, charbuf)
      struct coding_system *coding;
-     int src_bytes;
+     int *charbuf;
 {
-  return (src_bytes * DECODING_BUFFER_MAG (coding)
-         + CONVERSION_BUFFER_EXTRA_ROOM);
+  EMACS_INT from = coding->dst_pos + charbuf[2];
+  EMACS_INT to = coding->dst_pos + charbuf[3];
+  struct charset *charset = CHARSET_FROM_ID (charbuf[4]);
+
+  Fput_text_property (make_number (from), make_number (to),
+                     Qcharset, CHARSET_NAME (charset),
+                     coding->dst_object);
 }
 
-/* Return maximum size (bytes) of a buffer enough for encoding
-   SRC_BYTES of text to CODING.  */
 
-int
-encoding_buffer_size (coding, src_bytes)
+#define CHARBUF_SIZE 0x4000
+
+#define ALLOC_CONVERSION_WORK_AREA(coding)                             \
+  do {                                                                 \
+    int size = CHARBUF_SIZE;;                                          \
+                                                                       \
+    coding->charbuf = NULL;                                            \
+    while (size > 1024)                                                        \
+      {                                                                        \
+       coding->charbuf = (int *) alloca (sizeof (int) * size);         \
+       if (coding->charbuf)                                            \
+         break;                                                        \
+       size >>= 1;                                                     \
+      }                                                                        \
+    if (! coding->charbuf)                                             \
+      {                                                                        \
+       coding->result = CODING_RESULT_INSUFFICIENT_MEM;                \
+       return coding->result;                                          \
+      }                                                                        \
+    coding->charbuf_size = size;                                       \
+  } while (0)
+
+
+static void
+produce_annotation (coding)
      struct coding_system *coding;
-     int src_bytes;
 {
-  int magnification;
+  int *charbuf = coding->charbuf;
+  int *charbuf_end = charbuf + coding->charbuf_used;
+
+  if (NILP (coding->dst_object))
+    return;
 
-  if (coding->type == coding_type_ccl)
+  while (charbuf < charbuf_end)
     {
-      magnification = coding->spec.ccl.encoder.buf_magnification;
-      if (coding->eol_type == CODING_EOL_CRLF)
-       magnification *= 2;
+      if (*charbuf >= 0)
+       charbuf++;
+      else
+       {
+         int len = -*charbuf;
+         switch (charbuf[1])
+           {
+           case CODING_ANNOTATE_COMPOSITION_MASK:
+             produce_composition (coding, charbuf);
+             break;
+           case CODING_ANNOTATE_CHARSET_MASK:
+             produce_charset (coding, charbuf);
+             break;
+           default:
+             abort ();
+           }
+         charbuf += len;
+       }
     }
-  else if (CODING_REQUIRE_ENCODING (coding))
-    magnification = 3;
-  else
-    magnification = 1;
-
-  return (src_bytes * magnification + CONVERSION_BUFFER_EXTRA_ROOM);
 }
 
-/* Working buffer for code conversion.  */
-struct conversion_buffer
-{
-  int size;                    /* size of data.  */
-  int on_stack;                        /* 1 if allocated by alloca.  */
-  unsigned char *data;
-};
+/* Decode the data at CODING->src_object into CODING->dst_object.
+   CODING->src_object is a buffer, a string, or nil.
+   CODING->dst_object is a buffer.
 
-/* Don't use alloca for allocating memory space larger than this, lest
-   we overflow their stack.  */
-#define MAX_ALLOCA 16*1024
+   If CODING->src_object is a buffer, it must be the current buffer.
+   In this case, if CODING->src_pos is positive, it is a position of
+   the source text in the buffer, otherwise, the source text is in the
+   gap area of the buffer, and CODING->src_pos specifies the offset of
+   the text from GPT (which must be the same as PT).  If this is the
+   same buffer as CODING->dst_object, CODING->src_pos must be
+   negative.
 
-/* Allocate LEN bytes of memory for BUF (struct conversion_buffer).  */
-#define allocate_conversion_buffer(buf, len)           \
-  do {                                                 \
-    if (len < MAX_ALLOCA)                              \
-      {                                                        \
-       buf.data = (unsigned char *) alloca (len);      \
-       buf.on_stack = 1;                               \
-      }                                                        \
-    else                                               \
-      {                                                        \
-       buf.data = (unsigned char *) xmalloc (len);     \
-       buf.on_stack = 0;                               \
-      }                                                        \
-    buf.size = len;                                    \
-  } while (0)
+   If CODING->src_object is a string, CODING->src_pos in an index to
+   that string.
 
-/* Double the allocated memory for *BUF.  */
-static void
-extend_conversion_buffer (buf)
-     struct conversion_buffer *buf;
-{
-  if (buf->on_stack)
-    {
-      unsigned char *save = buf->data;
-      buf->data = (unsigned char *) xmalloc (buf->size * 2);
-      bcopy (save, buf->data, buf->size);
-      buf->on_stack = 0;
-    }
-  else
-    {
-      buf->data = (unsigned char *) xrealloc (buf->data, buf->size * 2);
-    }
-  buf->size *= 2;
-}
+   If CODING->src_object is nil, CODING->source must already point to
+   the non-relocatable memory area.  In this case, CODING->src_pos is
+   an offset from CODING->source.
 
-/* Free the allocated memory for BUF if it is not on stack.  */
-static void
-free_conversion_buffer (buf)
-     struct conversion_buffer *buf;
-{
-  if (!buf->on_stack)
-    xfree (buf->data);
-}
+   The decoded data is inserted at the current point of the buffer
+   CODING->dst_object.
+*/
 
-int
-ccl_coding_driver (coding, source, destination, src_bytes, dst_bytes, encodep)
+static int
+decode_coding (coding)
      struct coding_system *coding;
-     unsigned char *source, *destination;
-     int src_bytes, dst_bytes, encodep;
 {
-  struct ccl_program *ccl
-    = encodep ? &coding->spec.ccl.encoder : &coding->spec.ccl.decoder;
-  unsigned char *dst = destination;
+  Lisp_Object attrs;
 
-  ccl->suppress_error = coding->suppress_error;
-  ccl->last_block = coding->mode & CODING_MODE_LAST_BLOCK;
-  if (encodep)
-    {
-      /* On encoding, EOL format is converted within ccl_driver.  For
-        that, setup proper information in the structure CCL.  */
-      ccl->eol_type = coding->eol_type;
-      if (ccl->eol_type ==CODING_EOL_UNDECIDED)
-       ccl->eol_type = CODING_EOL_LF;
-      ccl->cr_consumed = coding->spec.ccl.cr_carryover;
-      ccl->eight_bit_control = coding->dst_multibyte;
-    }
-  else
-    ccl->eight_bit_control = 1;
-  ccl->multibyte = coding->src_multibyte;
-  if (coding->spec.ccl.eight_bit_carryover[0] != 0)
+  if (BUFFERP (coding->src_object)
+      && coding->src_pos > 0
+      && coding->src_pos < GPT
+      && coding->src_pos + coding->src_chars > GPT)
+    move_gap_both (coding->src_pos, coding->src_pos_byte);
+
+  if (BUFFERP (coding->dst_object))
     {
-      /* Move carryover bytes to DESTINATION.  */
-      unsigned char *p = coding->spec.ccl.eight_bit_carryover;
-      while (*p)
-       *dst++ = *p++;
-      coding->spec.ccl.eight_bit_carryover[0] = 0;
-      if (dst_bytes)
-       dst_bytes -= dst - destination;
+      if (current_buffer != XBUFFER (coding->dst_object))
+       set_buffer_internal (XBUFFER (coding->dst_object));
+      if (GPT != PT)
+       move_gap_both (PT, PT_BYTE);
     }
 
-  coding->produced = (ccl_driver (ccl, source, dst, src_bytes, dst_bytes,
-                                 &(coding->consumed))
-                     + dst - destination);
+  coding->consumed = coding->consumed_char = 0;
+  coding->produced = coding->produced_char = 0;
+  coding->chars_at_source = 0;
+  coding->result = CODING_RESULT_SUCCESS;
+  coding->errors = 0;
 
-  if (encodep)
-    {
-      coding->produced_char = coding->produced;
-      coding->spec.ccl.cr_carryover = ccl->cr_consumed;
-    }
-  else if (!ccl->eight_bit_control)
-    {
-      /* The produced bytes forms a valid multibyte sequence. */
-      coding->produced_char
-       = multibyte_chars_in_text (destination, coding->produced);
-      coding->spec.ccl.eight_bit_carryover[0] = 0;
-    }
-  else
+  ALLOC_CONVERSION_WORK_AREA (coding);
+
+  attrs = CODING_ID_ATTRS (coding->id);
+
+  do
     {
-      /* On decoding, the destination should always multibyte.  But,
-        CCL program might have been generated an invalid multibyte
-        sequence.  Here we make such a sequence valid as
-        multibyte.  */
-      int bytes
-       = dst_bytes ? dst_bytes : source + coding->consumed - destination;
-
-      if ((coding->consumed < src_bytes
-          || !ccl->last_block)
-         && coding->produced >= 1
-         && destination[coding->produced - 1] >= 0x80)
+      coding_set_source (coding);
+      coding->annotated = 0;
+      (*(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);
+      if (coding->annotated)
+       produce_annotation (coding);
+    }
+  while (coding->consumed < coding->src_bytes
+        && ! coding->result);
+
+  if (EQ (CODING_ATTR_TYPE (CODING_ID_ATTRS (coding->id)), Qccl)
+      && SYMBOLP (CODING_ID_EOL_TYPE (coding->id))
+      && ! EQ (CODING_ID_EOL_TYPE (coding->id), Qunix))
+    decode_eol (coding);
+
+  coding->carryover_bytes = 0;
+  if (coding->consumed < coding->src_bytes)
+    {
+      int nbytes = coding->src_bytes - coding->consumed;
+      const unsigned char *src;
+
+      coding_set_source (coding);
+      coding_set_destination (coding);
+      src = coding->source + coding->consumed;
+
+      if (coding->mode & CODING_MODE_LAST_BLOCK)
        {
-         /* We should not convert the tailing 8-bit codes to
-            multibyte form even if they doesn't form a valid
-            multibyte sequence.  They may form a valid sequence in
-            the next call.  */
-         int carryover = 0;
-
-         if (destination[coding->produced - 1] < 0xA0)
-           carryover = 1;
-         else if (coding->produced >= 2)
-           {
-             if (destination[coding->produced - 2] >= 0x80)
-               {
-                 if (destination[coding->produced - 2] < 0xA0)
-                   carryover = 2;
-                 else if (coding->produced >= 3
-                          && destination[coding->produced - 3] >= 0x80
-                          && destination[coding->produced - 3] < 0xA0)
-                   carryover = 3;
-               }
-           }
-         if (carryover > 0)
+         /* Flush out unprocessed data as binary chars.  We are sure
+            that the number of data is less than the size of
+            coding->charbuf.  */
+         while (nbytes-- > 0)
            {
-             BCOPY_SHORT (destination + coding->produced - carryover,
-                          coding->spec.ccl.eight_bit_carryover,
-                          carryover);
-             coding->spec.ccl.eight_bit_carryover[carryover] = 0;
-             coding->produced -= carryover;
+             int c = *src++;
+
+             coding->charbuf[coding->charbuf_used++] = (c & 0x80 ? - c : c);
            }
+         produce_chars (coding);
+       }
+      else
+       {
+         /* Record unprocessed bytes in coding->carryover.  We are
+            sure that the number of data is less than the size of
+            coding->carryover.  */
+         unsigned char *p = coding->carryover;
+
+         coding->carryover_bytes = nbytes;
+         while (nbytes-- > 0)
+           *p++ = *src++;
        }
-      coding->produced = str_as_multibyte (destination, bytes,
-                                          coding->produced,
-                                          &(coding->produced_char));
+      coding->consumed = coding->src_bytes;
     }
 
-  switch (ccl->status)
-    {
-    case CCL_STAT_SUSPEND_BY_SRC:
-      coding->result = CODING_FINISH_INSUFFICIENT_SRC;
-      break;
-    case CCL_STAT_SUSPEND_BY_DST:
-      coding->result = CODING_FINISH_INSUFFICIENT_DST;
-      break;
-    case CCL_STAT_QUIT:
-    case CCL_STAT_INVALID_CMD:
-      coding->result = CODING_FINISH_INTERRUPT;
-      break;
-    default:
-      coding->result = CODING_FINISH_NORMAL;
-      break;
-    }
   return coding->result;
 }
 
-/* Decode EOL format of the text at PTR of BYTES length destructively
-   according to CODING->eol_type.  This is called after the CCL
-   program produced a decoded text at PTR.  If we do CRLF->LF
-   conversion, update CODING->produced and CODING->produced_char.  */
 
-static void
-decode_eol_post_ccl (coding, ptr, bytes)
+/* Extract an annotation datum from a composition starting at POS and
+   ending before LIMIT of CODING->src_object (buffer or string), store
+   the data in BUF, set *STOP to a starting position of the next
+   composition (if any) or to LIMIT, and return the address of the
+   next element of BUF.
+
+   If such an annotation is not found, set *STOP to a starting
+   position of a composition after POS (if any) or to LIMIT, and
+   return BUF.  */
+
+static INLINE int *
+handle_composition_annotation (pos, limit, coding, buf, stop)
+     EMACS_INT pos, limit;
      struct coding_system *coding;
-     unsigned char *ptr;
-     int bytes;
+     int *buf;
+     EMACS_INT *stop;
 {
-  Lisp_Object val, saved_coding_symbol;
-  unsigned char *pend = ptr + bytes;
-  int dummy;
-
-  /* Remember the current coding system symbol.  We set it back when
-     an inconsistent EOL is found so that `last-coding-system-used' is
-     set to the coding system that doesn't specify EOL conversion.  */
-  saved_coding_symbol = coding->symbol;
-
-  coding->spec.ccl.cr_carryover = 0;
-  if (coding->eol_type == CODING_EOL_UNDECIDED)
-    {
-      /* Here, to avoid the call of setup_coding_system, we directly
-        call detect_eol_type.  */
-      coding->eol_type = detect_eol_type (ptr, bytes, &dummy);
-      if (coding->eol_type == CODING_EOL_INCONSISTENT)
-       coding->eol_type = CODING_EOL_LF;
-      if (coding->eol_type != CODING_EOL_UNDECIDED)
-       {
-         val = Fget (coding->symbol, Qeol_type);
-         if (VECTORP (val) && XVECTOR (val)->size == 3)
-           coding->symbol = XVECTOR (val)->contents[coding->eol_type];
-       }
-      coding->mode |= CODING_MODE_INHIBIT_INCONSISTENT_EOL;
-    }
+  EMACS_INT start, end;
+  Lisp_Object prop;
 
-  if (coding->eol_type == CODING_EOL_LF
-      || coding->eol_type == CODING_EOL_UNDECIDED)
-    {
-      /* We have nothing to do.  */
-      ptr = pend;
-    }
-  else if (coding->eol_type == CODING_EOL_CRLF)
+  if (! find_composition (pos, limit, &start, &end, &prop, coding->src_object)
+      || end > limit)
+    *stop = limit;
+  else if (start > pos)
+    *stop = start;
+  else
     {
-      unsigned char *pstart = ptr, *p = ptr;
-
-      if (! (coding->mode & CODING_MODE_LAST_BLOCK)
-         && *(pend - 1) == '\r')
-       {
-         /* If the last character is CR, we can't handle it here
-            because LF will be in the not-yet-decoded source text.
-            Record that the CR is not yet processed.  */
-         coding->spec.ccl.cr_carryover = 1;
-         coding->produced--;
-         coding->produced_char--;
-         pend--;
-       }
-      while (ptr < pend)
+      if (start == pos)
        {
-         if (*ptr == '\r')
+         /* We found a composition.  Store the corresponding
+            annotation data in BUF.  */
+         int *head = buf;
+         enum composition_method method = COMPOSITION_METHOD (prop);
+         int nchars = COMPOSITION_LENGTH (prop);
+
+         ADD_COMPOSITION_DATA (buf, 0, nchars, method);
+         if (method != COMPOSITION_RELATIVE)
            {
-             if (ptr + 1 < pend && *(ptr + 1) == '\n')
+             Lisp_Object components;
+             int len, i, i_byte;
+
+             components = COMPOSITION_COMPONENTS (prop);
+             if (VECTORP (components))
                {
-                 *p++ = '\n';
-                 ptr += 2;
+                 len = XVECTOR (components)->size;
+                 for (i = 0; i < len; i++)
+                   *buf++ = XINT (AREF (components, i));
                }
-             else
+             else if (STRINGP (components))
                {
-                 if (coding->mode & CODING_MODE_INHIBIT_INCONSISTENT_EOL)
-                   goto undo_eol_conversion;
-                 *p++ = *ptr++;
+                 len = SCHARS (components);
+                 i = i_byte = 0;
+                 while (i < len)
+                   {
+                     FETCH_STRING_CHAR_ADVANCE (*buf, components, i, i_byte);
+                     buf++;
+                   }
+               }
+             else if (INTEGERP (components))
+               {
+                 len = 1;
+                 *buf++ = XINT (components);
+               }
+             else if (CONSP (components))
+               {
+                 for (len = 0; CONSP (components);
+                      len++, components = XCDR (components))
+                   *buf++ = XINT (XCAR (components));
                }
-           }
-         else if (*ptr == '\n'
-                  && coding->mode & CODING_MODE_INHIBIT_INCONSISTENT_EOL)
-           goto undo_eol_conversion;
-         else
-           *p++ = *ptr++;
-         continue;
-
-       undo_eol_conversion:
-         /* We have faced with inconsistent EOL format at PTR.
-            Convert all LFs before PTR back to CRLFs.  */
-         for (p--, ptr--; p >= pstart; p--)
-           {
-             if (*p == '\n')
-               *ptr-- = '\n', *ptr-- = '\r';
              else
-               *ptr-- = *p;
-           }
-         /*  If carryover is recorded, cancel it because we don't
-             convert CRLF anymore.  */
-         if (coding->spec.ccl.cr_carryover)
-           {
-             coding->spec.ccl.cr_carryover = 0;
-             coding->produced++;
-             coding->produced_char++;
-             pend++;
+               abort ();
+             *head -= len;
            }
-         p = ptr = pend;
-         coding->eol_type = CODING_EOL_LF;
-         coding->symbol = saved_coding_symbol;
-       }
-      if (p < pend)
-       {
-         /* As each two-byte sequence CRLF was converted to LF, (PEND
-            - P) is the number of deleted characters.  */
-         coding->produced -= pend - p;
-         coding->produced_char -= pend - p;
        }
+
+      if (find_composition (end, limit, &start, &end, &prop,
+                           coding->src_object)
+         && end <= limit)
+       *stop = start;
+      else
+       *stop = limit;
     }
-  else                 /* i.e. coding->eol_type == CODING_EOL_CR */
+  return buf;
+}
+
+
+/* Extract an annotation datum from a text property `charset' at POS of
+   CODING->src_object (buffer of string), store the data in BUF, set
+   *STOP to the position where the value of `charset' property changes
+   (limiting by LIMIT), and return the address of the next element of
+   BUF.
+
+   If the property value is nil, set *STOP to the position where the
+   property value is non-nil (limiting by LIMIT), and return BUF.  */
+
+static INLINE int *
+handle_charset_annotation (pos, limit, coding, buf, stop)
+     EMACS_INT pos, limit;
+     struct coding_system *coding;
+     int *buf;
+     EMACS_INT *stop;
+{
+  Lisp_Object val, next;
+  int id;
+
+  val = Fget_text_property (make_number (pos), Qcharset, coding->src_object);
+  if (! NILP (val) && CHARSETP (val))
+    id = XINT (CHARSET_SYMBOL_ID (val));
+  else
+    id = -1;
+  ADD_CHARSET_DATA (buf, 0, 0, id);
+  next = Fnext_single_property_change (make_number (pos), Qcharset,
+                                      coding->src_object,
+                                      make_number (limit));
+  *stop = XINT (next);
+  return buf;
+}
+
+
+static void
+consume_chars (coding)
+     struct coding_system *coding;
+{
+  int *buf = coding->charbuf;
+  int *buf_end = coding->charbuf + coding->charbuf_size;
+  const unsigned char *src = coding->source + coding->consumed;
+  const unsigned char *src_end = coding->source + coding->src_bytes;
+  EMACS_INT pos = coding->src_pos + coding->consumed_char;
+  EMACS_INT end_pos = coding->src_pos + coding->src_chars;
+  int multibytep = coding->src_multibyte;
+  Lisp_Object eol_type;
+  int c;
+  EMACS_INT stop, stop_composition, stop_charset;
+
+  eol_type = CODING_ID_EOL_TYPE (coding->id);
+  if (VECTORP (eol_type))
+    eol_type = Qunix;
+
+  /* Note: composition handling is not yet implemented.  */
+  coding->common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK;
+
+  if (coding->common_flags & CODING_ANNOTATE_COMPOSITION_MASK)
+    stop = stop_composition = pos;
+  else
+    stop = stop_composition = end_pos;
+  if (coding->common_flags & CODING_ANNOTATE_CHARSET_MASK)
+    stop = stop_charset = pos;
+  else
+    stop_charset = end_pos;
+
+  /* Compensate for CRLF and annotation.  */
+  buf_end -= 1 + MAX_ANNOTATION_LENGTH;
+  while (buf < buf_end)
     {
-      unsigned char *p = ptr;
+      if (pos == stop)
+       {
+         if (pos == end_pos)
+           break;
+         if (pos == stop_composition)
+           buf = handle_composition_annotation (pos, end_pos, coding,
+                                                buf, &stop_composition);
+         if (pos == stop_charset)
+           buf = handle_charset_annotation (pos, end_pos, coding,
+                                            buf, &stop_charset);
+         stop = (stop_composition < stop_charset
+                 ? stop_composition : stop_charset);
+       }
+
+      if (! multibytep)
+       {
+         EMACS_INT bytes;
 
-      for (; ptr < pend; ptr++)
+         if (! CODING_FOR_UNIBYTE (coding)
+             && (bytes = MULTIBYTE_LENGTH (src, src_end)) > 0)
+           c = STRING_CHAR_ADVANCE (src), pos += bytes;
+         else
+           c = *src++, pos++;
+       }
+      else
+       c = STRING_CHAR_ADVANCE (src), pos++;
+      if ((c == '\r') && (coding->mode & CODING_MODE_SELECTIVE_DISPLAY))
+       c = '\n';
+      if (! EQ (eol_type, Qunix))
        {
-         if (*ptr == '\r')
-           *ptr = '\n';
-         else if (*ptr == '\n'
-                  && coding->mode & CODING_MODE_INHIBIT_INCONSISTENT_EOL)
+         if (c == '\n')
            {
-             for (; p < ptr; p++)
-               {
-                 if (*p == '\n')
-                   *p = '\r';
-               }
-             ptr = pend;
-             coding->eol_type = CODING_EOL_LF;
-             coding->symbol = saved_coding_symbol;
+             if (EQ (eol_type, Qdos))
+               *buf++ = '\r';
+             else
+               c = '\r';
            }
        }
+      *buf++ = c;
     }
+
+  coding->consumed = src - coding->source;
+  coding->consumed_char = pos - coding->src_pos;
+  coding->charbuf_used = buf - coding->charbuf;
+  coding->chars_at_source = 0;
 }
 
-/* See "GENERAL NOTES about `decode_coding_XXX ()' functions".  Before
-   decoding, it may detect coding system and format of end-of-line if
-   those are not yet decided.  The source should be unibyte, the
-   result is multibyte if CODING->dst_multibyte is nonzero, else
-   unibyte.  */
 
-int
-decode_coding (coding, source, destination, src_bytes, dst_bytes)
+/* Encode the text at CODING->src_object into CODING->dst_object.
+   CODING->src_object is a buffer or a string.
+   CODING->dst_object is a buffer or nil.
+
+   If CODING->src_object is a buffer, it must be the current buffer.
+   In this case, if CODING->src_pos is positive, it is a position of
+   the source text in the buffer, otherwise. the source text is in the
+   gap area of the buffer, and coding->src_pos specifies the offset of
+   the text from GPT (which must be the same as PT).  If this is the
+   same buffer as CODING->dst_object, CODING->src_pos must be
+   negative and CODING should not have `pre-write-conversion'.
+
+   If CODING->src_object is a string, CODING should not have
+   `pre-write-conversion'.
+
+   If CODING->dst_object is a buffer, the encoded data is inserted at
+   the current point of that buffer.
+
+   If CODING->dst_object is nil, the encoded data is placed at the
+   memory area specified by CODING->destination.  */
+
+static int
+encode_coding (coding)
      struct coding_system *coding;
-     const unsigned char *source;
-     unsigned char *destination;
-     int src_bytes, dst_bytes;
 {
-  int extra = 0;
+  Lisp_Object attrs;
 
-  if (coding->type == coding_type_undecided)
-    detect_coding (coding, source, src_bytes);
+  attrs = CODING_ID_ATTRS (coding->id);
 
-  if (coding->eol_type == CODING_EOL_UNDECIDED
-      && coding->type != coding_type_ccl)
+  if (BUFFERP (coding->dst_object))
     {
-      detect_eol (coding, source, src_bytes);
-      /* We had better recover the original eol format if we
-        encounter an inconsistent eol format while decoding.  */
-      coding->mode |= CODING_MODE_INHIBIT_INCONSISTENT_EOL;
+      set_buffer_internal (XBUFFER (coding->dst_object));
+      coding->dst_multibyte
+       = ! NILP (current_buffer->enable_multibyte_characters);
     }
 
-  coding->produced = coding->produced_char = 0;
   coding->consumed = coding->consumed_char = 0;
+  coding->produced = coding->produced_char = 0;
+  coding->result = CODING_RESULT_SUCCESS;
   coding->errors = 0;
-  coding->result = CODING_FINISH_NORMAL;
 
-  switch (coding->type)
-    {
-    case coding_type_sjis:
-      decode_coding_sjis_big5 (coding, source, destination,
-                              src_bytes, dst_bytes, 1);
-      break;
+  ALLOC_CONVERSION_WORK_AREA (coding);
 
-    case coding_type_iso2022:
-      decode_coding_iso2022 (coding, source, destination,
-                            src_bytes, dst_bytes);
-      break;
+  do {
+    coding_set_source (coding);
+    consume_chars (coding);
 
-    case coding_type_big5:
-      decode_coding_sjis_big5 (coding, source, destination,
-                              src_bytes, dst_bytes, 0);
-      break;
+    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);
 
-    case coding_type_emacs_mule:
-      decode_coding_emacs_mule (coding, source, destination,
-                               src_bytes, dst_bytes);
-      break;
+    coding_set_destination (coding);
+    (*(coding->encoder)) (coding);
+  } while (coding->consumed_char < coding->src_chars);
+
+  if (BUFFERP (coding->dst_object))
+    insert_from_gap (coding->produced_char, coding->produced);
+
+  return (coding->result);
+}
+
+
+/* Stack of working buffers used in code conversion.  An nil element
+   means that the code conversion of that level is not using a working
+   buffer.  */
+Lisp_Object Vcode_conversion_work_buf_list;
+
+/* A working buffer used by the top level conversion.  */
+Lisp_Object Vcode_conversion_reused_work_buf;
+
+
+/* Return a working buffer that can be freely used by the following
+   code conversion.  MULTIBYTEP specifies the multibyteness of the
+   buffer.  */
+
+Lisp_Object
+make_conversion_work_buffer (multibytep, depth)
+     int multibytep, depth;
+{
+  struct buffer *current = current_buffer;
+  Lisp_Object buf, name;
 
-    case coding_type_ccl:
-      if (coding->spec.ccl.cr_carryover)
+  if (depth == 0)
+    {
+      if (NILP (Vcode_conversion_reused_work_buf))
+       Vcode_conversion_reused_work_buf
+         = Fget_buffer_create (build_string (" *code-converting-work<0>*"));
+      buf = Vcode_conversion_reused_work_buf;
+    }
+  else
+    {
+      if (depth < 0)
        {
-         /* Put the CR which was not processed by the previous call
-            of decode_eol_post_ccl in DESTINATION.  It will be
-            decoded together with the following LF by the call to
-            decode_eol_post_ccl below.  */
-         *destination = '\r';
-         coding->produced++;
-         coding->produced_char++;
-         dst_bytes--;
-         extra = coding->spec.ccl.cr_carryover;
+         name = build_string (" *code-converting-work*");
+         name = Fgenerate_new_buffer_name (name, Qnil);
        }
-      ccl_coding_driver (coding, source, destination + extra,
-                        src_bytes, dst_bytes, 0);
-      if (coding->eol_type != CODING_EOL_LF)
+      else
        {
-         coding->produced += extra;
-         coding->produced_char += extra;
-         decode_eol_post_ccl (coding, destination, coding->produced);
-       }
-      break;
+         char str[128];
 
-    default:
-      decode_eol (coding, source, destination, src_bytes, dst_bytes);
+         sprintf (str, " *code-converting-work*<%d>", depth);
+         name = build_string (str);
+       }
+      buf = Fget_buffer_create (name);
     }
+  set_buffer_internal (XBUFFER (buf));
+  current_buffer->undo_list = Qt;
+  Ferase_buffer ();
+  Fset_buffer_multibyte (multibytep ? Qt : Qnil);
+  set_buffer_internal (current);
+  return buf;
+}
+
+static Lisp_Object
+code_conversion_restore (buffer)
+     Lisp_Object buffer;
+{
+  Lisp_Object workbuf;
+
+  workbuf = XCAR (Vcode_conversion_work_buf_list);
+  if (! NILP (workbuf)
+      && ! EQ (workbuf, Vcode_conversion_reused_work_buf)
+      && ! NILP (Fbuffer_live_p (workbuf)))
+    Fkill_buffer (workbuf);
+  Vcode_conversion_work_buf_list = XCDR (Vcode_conversion_work_buf_list);
+  set_buffer_internal (XBUFFER (buffer));
+  return Qnil;
+}
 
-  if (coding->result == CODING_FINISH_INSUFFICIENT_SRC
-      && coding->mode & CODING_MODE_LAST_BLOCK
-      && coding->consumed == src_bytes)
-    coding->result = CODING_FINISH_NORMAL;
+static Lisp_Object
+code_conversion_save (buffer, with_work_buf, multibyte)
+     Lisp_Object buffer;
+     int with_work_buf, multibyte;
+{
+  Lisp_Object workbuf;
 
-  if (coding->mode & CODING_MODE_LAST_BLOCK
-      && coding->result == CODING_FINISH_INSUFFICIENT_SRC)
+  if (with_work_buf)
     {
-      const unsigned char *src = source + coding->consumed;
-      unsigned char *dst = destination + coding->produced;
+      int depth = XINT (Flength (Vcode_conversion_work_buf_list));
 
-      src_bytes -= coding->consumed;
-      coding->errors++;
-      if (COMPOSING_P (coding))
-       DECODE_COMPOSITION_END ('1');
-      while (src_bytes--)
-       {
-         int c = *src++;
-         dst += CHAR_STRING (c, dst);
-         coding->produced_char++;
-       }
-      coding->consumed = coding->consumed_char = src - source;
-      coding->produced = dst - destination;
-      coding->result = CODING_FINISH_NORMAL;
+      workbuf = make_conversion_work_buffer (multibyte, depth);
     }
+  else
+    workbuf = Qnil;
+  Vcode_conversion_work_buf_list
+    = Fcons (workbuf, Vcode_conversion_work_buf_list);
+  record_unwind_protect (code_conversion_restore, buffer);
+  return workbuf;
+}
+
+int
+decode_coding_gap (coding, chars, bytes)
+     struct coding_system *coding;
+     EMACS_INT chars, bytes;
+{
+  int count = specpdl_ptr - specpdl;
+  Lisp_Object attrs;
+  Lisp_Object buffer;
+
+  buffer = Fcurrent_buffer ();
+  code_conversion_save (buffer, 0, 0);
+
+  coding->src_object = buffer;
+  coding->src_chars = chars;
+  coding->src_bytes = bytes;
+  coding->src_pos = -chars;
+  coding->src_pos_byte = -bytes;
+  coding->src_multibyte = chars < bytes;
+  coding->dst_object = buffer;
+  coding->dst_pos = PT;
+  coding->dst_pos_byte = PT_BYTE;
+  coding->dst_multibyte = ! NILP (current_buffer->enable_multibyte_characters);
+  coding->mode |= CODING_MODE_LAST_BLOCK;
 
-  if (!coding->dst_multibyte)
+  if (CODING_REQUIRE_DETECTION (coding))
+    detect_coding (coding);
+
+  decode_coding (coding);
+
+  attrs = CODING_ID_ATTRS (coding->id);
+  if (! NILP (CODING_ATTR_POST_READ (attrs)))
     {
-      coding->produced = str_as_unibyte (destination, coding->produced);
-      coding->produced_char = coding->produced;
+      EMACS_INT prev_Z = Z, prev_Z_BYTE = Z_BYTE;
+      Lisp_Object val;
+
+      TEMP_SET_PT_BOTH (coding->dst_pos, coding->dst_pos_byte);
+      val = call1 (CODING_ATTR_POST_READ (attrs),
+                  make_number (coding->produced_char));
+      CHECK_NATNUM (val);
+      coding->produced_char += Z - prev_Z;
+      coding->produced += Z_BYTE - prev_Z_BYTE;
     }
 
+  unbind_to (count, Qnil);
   return coding->result;
 }
 
-/* See "GENERAL NOTES about `encode_coding_XXX ()' functions".  The
-   multibyteness of the source is CODING->src_multibyte, the
-   multibyteness of the result is always unibyte.  */
-
 int
-encode_coding (coding, source, destination, src_bytes, dst_bytes)
+encode_coding_gap (coding, chars, bytes)
      struct coding_system *coding;
-     const unsigned char *source;
-     unsigned char *destination;
-     int src_bytes, dst_bytes;
+     EMACS_INT chars, bytes;
 {
-  coding->produced = coding->produced_char = 0;
-  coding->consumed = coding->consumed_char = 0;
-  coding->errors = 0;
-  coding->result = CODING_FINISH_NORMAL;
+  int count = specpdl_ptr - specpdl;
+  Lisp_Object buffer;
 
-  switch (coding->type)
-    {
-    case coding_type_sjis:
-      encode_coding_sjis_big5 (coding, source, destination,
-                              src_bytes, dst_bytes, 1);
-      break;
+  buffer = Fcurrent_buffer ();
+  code_conversion_save (buffer, 0, 0);
 
-    case coding_type_iso2022:
-      encode_coding_iso2022 (coding, source, destination,
-                            src_bytes, dst_bytes);
-      break;
+  coding->src_object = buffer;
+  coding->src_chars = chars;
+  coding->src_bytes = bytes;
+  coding->src_pos = -chars;
+  coding->src_pos_byte = -bytes;
+  coding->src_multibyte = chars < bytes;
+  coding->dst_object = coding->src_object;
+  coding->dst_pos = PT;
+  coding->dst_pos_byte = PT_BYTE;
 
-    case coding_type_big5:
-      encode_coding_sjis_big5 (coding, source, destination,
-                              src_bytes, dst_bytes, 0);
-      break;
+  encode_coding (coding);
 
-    case coding_type_emacs_mule:
-      encode_coding_emacs_mule (coding, source, destination,
-                               src_bytes, dst_bytes);
-      break;
+  unbind_to (count, Qnil);
+  return coding->result;
+}
 
-    case coding_type_ccl:
-      ccl_coding_driver (coding, source, destination,
-                        src_bytes, dst_bytes, 1);
-      break;
 
-    default:
-      encode_eol (coding, source, destination, src_bytes, dst_bytes);
-    }
+/* Decode the text in the range FROM/FROM_BYTE and TO/TO_BYTE in
+   SRC_OBJECT into DST_OBJECT by coding context CODING.
 
-  if (coding->mode & CODING_MODE_LAST_BLOCK
-      && coding->result == CODING_FINISH_INSUFFICIENT_SRC)
-    {
-      const unsigned char *src = source + coding->consumed;
-      unsigned char *dst = destination + coding->produced;
+   SRC_OBJECT is a buffer, a string, or Qnil.
 
-      if (coding->type == coding_type_iso2022)
-       ENCODE_RESET_PLANE_AND_REGISTER;
-      if (COMPOSING_P (coding))
-       *dst++ = ISO_CODE_ESC, *dst++ = '1';
-      if (coding->consumed < src_bytes)
-       {
-         int len = src_bytes - coding->consumed;
+   If it is a buffer, the text is at point of the buffer.  FROM and TO
+   are positions in the buffer.
 
-         BCOPY_SHORT (src, dst, len);
-         if (coding->src_multibyte)
-           len = str_as_unibyte (dst, len);
-         dst += len;
-         coding->consumed = src_bytes;
-       }
-      coding->produced = coding->produced_char = dst - destination;
-      coding->result = CODING_FINISH_NORMAL;
-    }
+   If it is a string, the text is at the beginning of the string.
+   FROM and TO are indices to the string.
 
-  if (coding->result == CODING_FINISH_INSUFFICIENT_SRC
-      && coding->consumed == src_bytes)
-    coding->result = CODING_FINISH_NORMAL;
+   If it is nil, the text is at coding->source.  FROM and TO are
+   indices to coding->source.
 
-  return coding->result;
-}
+   DST_OBJECT is a buffer, Qt, or Qnil.
 
-/* Scan text in the region between *BEG and *END (byte positions),
-   skip characters which we don't have to decode by coding system
-   CODING at the head and tail, then set *BEG and *END to the region
-   of the text we actually have to convert.  The caller should move
-   the gap out of the region in advance if the region is from a
-   buffer.
+   If it is a buffer, the decoded text is inserted at point of the
+   buffer.  If the buffer is the same as SRC_OBJECT, the source text
+   is deleted.
 
-   If STR is not NULL, *BEG and *END are indices into STR.  */
+   If it is Qt, a string is made from the decoded text, and
+   set in CODING->dst_object.
 
-static void
-shrink_decoding_region (beg, end, coding, str)
-     int *beg, *end;
+   If it is Qnil, the decoded text is stored at CODING->destination.
+   The caller must allocate CODING->dst_bytes bytes at
+   CODING->destination by xmalloc.  If the decoded text is longer than
+   CODING->dst_bytes, CODING->destination is relocated by xrealloc.
+ */
+
+void
+decode_coding_object (coding, src_object, from, from_byte, to, to_byte,
+                     dst_object)
      struct coding_system *coding;
-     unsigned char *str;
+     Lisp_Object src_object;
+     EMACS_INT from, from_byte, to, to_byte;
+     Lisp_Object dst_object;
 {
-  unsigned char *begp_orig, *begp, *endp_orig, *endp, c;
-  int eol_conversion;
-  Lisp_Object translation_table;
+  int count = specpdl_ptr - specpdl;
+  unsigned char *destination;
+  EMACS_INT dst_bytes;
+  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;
 
-  if (coding->type == coding_type_ccl
-      || coding->type == coding_type_undecided
-      || coding->eol_type != CODING_EOL_LF
-      || !NILP (coding->post_read_conversion)
-      || coding->composing != COMPOSITION_DISABLED)
+  buffer = Fcurrent_buffer ();
+
+  if (NILP (dst_object))
     {
-      /* We can't skip any data.  */
-      return;
+      destination = coding->destination;
+      dst_bytes = coding->dst_bytes;
     }
-  if (coding->type == coding_type_no_conversion
-      || coding->type == coding_type_raw_text
-      || coding->type == coding_type_emacs_mule)
+
+  coding->src_object = src_object;
+  coding->src_chars = chars;
+  coding->src_bytes = bytes;
+  coding->src_multibyte = chars < bytes;
+
+  if (STRINGP (src_object))
     {
-      /* We need no conversion, but don't have to skip any data here.
-         Decoding routine handles them effectively anyway.  */
-      return;
+      coding->src_pos = from;
+      coding->src_pos_byte = from_byte;
     }
-
-  translation_table = coding->translation_table_for_decode;
-  if (NILP (translation_table) && !NILP (Venable_character_translation))
-    translation_table = Vstandard_translation_table_for_decode;
-  if (CHAR_TABLE_P (translation_table))
+  else if (BUFFERP (src_object))
     {
-      int i;
-      for (i = 0; i < 128; i++)
-       if (!NILP (CHAR_TABLE_REF (translation_table, i)))
-         break;
-      if (i < 128)
-       /* Some ASCII character should be translated.  We give up
-          shrinking.  */
-       return;
+      set_buffer_internal (XBUFFER (src_object));
+      if (from != GPT)
+       move_gap_both (from, from_byte);
+      if (EQ (src_object, dst_object))
+       {
+         saved_pt = PT, saved_pt_byte = PT_BYTE;
+         TEMP_SET_PT_BOTH (from, from_byte);
+         del_range_both (from, from_byte, to, to_byte, 1);
+         coding->src_pos = -chars;
+         coding->src_pos_byte = -bytes;
+       }
+      else
+       {
+         coding->src_pos = from;
+         coding->src_pos_byte = from_byte;
+       }
     }
 
-  if (coding->heading_ascii >= 0)
-    /* Detection routine has already found how much we can skip at the
-       head.  */
-    *beg += coding->heading_ascii;
+  if (CODING_REQUIRE_DETECTION (coding))
+    detect_coding (coding);
+  attrs = CODING_ID_ATTRS (coding->id);
 
-  if (str)
+  if (EQ (dst_object, Qt)
+      || (! NILP (CODING_ATTR_POST_READ (attrs))
+         && NILP (dst_object)))
+    {
+      coding->dst_object = code_conversion_save (buffer, 1, 1);
+      coding->dst_pos = BEG;
+      coding->dst_pos_byte = BEG_BYTE;
+      coding->dst_multibyte = 1;
+    }
+  else if (BUFFERP (dst_object))
     {
-      begp_orig = begp = str + *beg;
-      endp_orig = endp = str + *end;
+      code_conversion_save (buffer, 0, 0);
+      coding->dst_object = dst_object;
+      coding->dst_pos = BUF_PT (XBUFFER (dst_object));
+      coding->dst_pos_byte = BUF_PT_BYTE (XBUFFER (dst_object));
+      coding->dst_multibyte
+       = ! NILP (XBUFFER (dst_object)->enable_multibyte_characters);
     }
   else
     {
-      begp_orig = begp = BYTE_POS_ADDR (*beg);
-      endp_orig = endp = begp + *end - *beg;
+      code_conversion_save (buffer, 0, 0);
+      coding->dst_object = Qnil;
+      coding->dst_multibyte = 1;
     }
 
-  eol_conversion = (coding->eol_type == CODING_EOL_CR
-                   || coding->eol_type == CODING_EOL_CRLF);
+  decode_coding (coding);
 
-  switch (coding->type)
-    {
-    case coding_type_sjis:
-    case coding_type_big5:
-      /* We can skip all ASCII characters at the head.  */
-      if (coding->heading_ascii < 0)
-       {
-         if (eol_conversion)
-           while (begp < endp && *begp < 0x80 && *begp != '\r') begp++;
-         else
-           while (begp < endp && *begp < 0x80) begp++;
-       }
-      /* We can skip all ASCII characters at the tail except for the
-        second byte of SJIS or BIG5 code.  */
-      if (eol_conversion)
-       while (begp < endp && endp[-1] < 0x80 && endp[-1] != '\r') endp--;
-      else
-       while (begp < endp && endp[-1] < 0x80) endp--;
-      /* Do not consider LF as ascii if preceded by CR, since that
-        confuses eol decoding. */
-      if (begp < endp && endp < endp_orig && endp[-1] == '\r' && endp[0] == '\n')
-       endp++;
-      if (begp < endp && endp < endp_orig && endp[-1] >= 0x80)
-       endp++;
-      break;
+  if (BUFFERP (coding->dst_object))
+    set_buffer_internal (XBUFFER (coding->dst_object));
 
-    case coding_type_iso2022:
-      if (CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, 0) != CHARSET_ASCII)
-       /* We can't skip any data.  */
-       break;
-      if (coding->heading_ascii < 0)
-       {
-         /* We can skip all ASCII characters at the head except for a
-            few control codes.  */
-         while (begp < endp && (c = *begp) < 0x80
-                && c != ISO_CODE_CR && c != ISO_CODE_SO
-                && c != ISO_CODE_SI && c != ISO_CODE_ESC
-                && (!eol_conversion || c != ISO_CODE_LF))
-           begp++;
-       }
-      switch (coding->category_idx)
-       {
-       case CODING_CATEGORY_IDX_ISO_8_1:
-       case CODING_CATEGORY_IDX_ISO_8_2:
-         /* We can skip all ASCII characters at the tail.  */
-         if (eol_conversion)
-           while (begp < endp && (c = endp[-1]) < 0x80 && c != '\r') endp--;
-         else
-           while (begp < endp && endp[-1] < 0x80) endp--;
-         /* Do not consider LF as ascii if preceded by CR, since that
-             confuses eol decoding. */
-         if (begp < endp && endp < endp_orig && endp[-1] == '\r' && endp[0] == '\n')
-           endp++;
-         break;
+  if (! NILP (CODING_ATTR_POST_READ (attrs)))
+    {
+      struct gcpro gcpro1, gcpro2;
+      EMACS_INT prev_Z = Z, prev_Z_BYTE = Z_BYTE;
+      Lisp_Object val;
 
-       case CODING_CATEGORY_IDX_ISO_7:
-       case CODING_CATEGORY_IDX_ISO_7_TIGHT:
-         {
-           /* We can skip all characters at the tail except for 8-bit
-              codes and ESC and the following 2-byte at the tail.  */
-           unsigned char *eight_bit = NULL;
+      TEMP_SET_PT_BOTH (coding->dst_pos, coding->dst_pos_byte);
+      GCPRO2 (coding->src_object, coding->dst_object);
+      val = call1 (CODING_ATTR_POST_READ (attrs),
+                  make_number (coding->produced_char));
+      UNGCPRO;
+      CHECK_NATNUM (val);
+      coding->produced_char += Z - prev_Z;
+      coding->produced += Z_BYTE - prev_Z_BYTE;
+    }
 
-           if (eol_conversion)
-             while (begp < endp
-                    && (c = endp[-1]) != ISO_CODE_ESC && c != '\r')
-               {
-                 if (!eight_bit && c & 0x80) eight_bit = endp;
-                 endp--;
-               }
-           else
-             while (begp < endp
-                    && (c = endp[-1]) != ISO_CODE_ESC)
-               {
-                 if (!eight_bit && c & 0x80) eight_bit = endp;
-                 endp--;
-               }
-           /* Do not consider LF as ascii if preceded by CR, since that
-              confuses eol decoding. */
-           if (begp < endp && endp < endp_orig
-               && endp[-1] == '\r' && endp[0] == '\n')
-             endp++;
-           if (begp < endp && endp[-1] == ISO_CODE_ESC)
-             {
-               if (endp + 1 < endp_orig && end[0] == '(' && end[1] == 'B')
-                 /* This is an ASCII designation sequence.  We can
-                    surely skip the tail.  But, if we have
-                    encountered an 8-bit code, skip only the codes
-                    after that.  */
-                 endp = eight_bit ? eight_bit : endp + 2;
-               else
-                 /* Hmmm, we can't skip the tail.  */
-                 endp = endp_orig;
-             }
-           else if (eight_bit)
-             endp = eight_bit;
-         }
+  if (EQ (dst_object, Qt))
+    {
+      coding->dst_object = Fbuffer_string ();
+    }
+  else if (NILP (dst_object) && BUFFERP (coding->dst_object))
+    {
+      set_buffer_internal (XBUFFER (coding->dst_object));
+      if (dst_bytes < coding->produced)
+       {
+         destination
+           = (unsigned char *) xrealloc (destination, coding->produced);
+         if (! destination)
+           {
+             coding->result = CODING_RESULT_INSUFFICIENT_DST;
+             unbind_to (count, Qnil);
+             return;
+           }
+         if (BEGV < GPT && GPT < BEGV + coding->produced_char)
+           move_gap_both (BEGV, BEGV_BYTE);
+         bcopy (BEGV_ADDR, destination, coding->produced);
+         coding->destination = destination;
        }
-      break;
+    }
 
-    default:
-      abort ();
+  if (saved_pt >= 0)
+    {
+      /* This is the case of:
+        (BUFFERP (src_object) && EQ (src_object, dst_object))
+        As we have moved PT while replacing the original buffer
+        contents, we must recover it now.  */
+      set_buffer_internal (XBUFFER (src_object));
+      if (saved_pt < from)
+       TEMP_SET_PT_BOTH (saved_pt, saved_pt_byte);
+      else if (saved_pt < from + chars)
+       TEMP_SET_PT_BOTH (from, from_byte);
+      else if (! NILP (current_buffer->enable_multibyte_characters))
+       TEMP_SET_PT_BOTH (saved_pt + (coding->produced_char - chars),
+                         saved_pt_byte + (coding->produced - bytes));
+      else
+       TEMP_SET_PT_BOTH (saved_pt + (coding->produced - bytes),
+                         saved_pt_byte + (coding->produced - bytes));
     }
-  *beg += begp - begp_orig;
-  *end += endp - endp_orig;
-  return;
+
+  unbind_to (count, Qnil);
 }
 
-/* Like shrink_decoding_region but for encoding.  */
 
-static void
-shrink_encoding_region (beg, end, coding, str)
-     int *beg, *end;
+void
+encode_coding_object (coding, src_object, from, from_byte, to, to_byte,
+                     dst_object)
      struct coding_system *coding;
-     unsigned char *str;
+     Lisp_Object src_object;
+     EMACS_INT from, from_byte, to, to_byte;
+     Lisp_Object dst_object;
 {
-  unsigned char *begp_orig, *begp, *endp_orig, *endp;
-  int eol_conversion;
-  Lisp_Object translation_table;
+  int count = specpdl_ptr - specpdl;
+  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;
+
+  buffer = Fcurrent_buffer ();
+
+  coding->src_object = src_object;
+  coding->src_chars = chars;
+  coding->src_bytes = bytes;
+  coding->src_multibyte = chars < bytes;
+
+  attrs = CODING_ID_ATTRS (coding->id);
+
+  if (! NILP (CODING_ATTR_PRE_WRITE (attrs)))
+    {
+      coding->src_object = code_conversion_save (buffer, 1,
+                                                coding->src_multibyte);
+      set_buffer_internal (XBUFFER (coding->src_object));
+      if (STRINGP (src_object))
+       insert_from_string (src_object, from, from_byte, chars, bytes, 0);
+      else if (BUFFERP (src_object))
+       insert_from_buffer (XBUFFER (src_object), from, chars, 0);
+      else
+       insert_1_both (coding->source + from, chars, bytes, 0, 0, 0);
 
-  if (coding->type == coding_type_ccl
-      || coding->eol_type == CODING_EOL_CRLF
-      || coding->eol_type == CODING_EOL_CR
-      || (coding->cmp_data && coding->cmp_data->used > 0))
+      if (EQ (src_object, dst_object))
+       {
+         set_buffer_internal (XBUFFER (src_object));
+         saved_pt = PT, saved_pt_byte = PT_BYTE;
+         del_range_both (from, from_byte, to, to_byte, 1);
+         set_buffer_internal (XBUFFER (coding->src_object));
+       }
+
+      call2 (CODING_ATTR_PRE_WRITE (attrs),
+            make_number (BEG), make_number (Z));
+      coding->src_object = Fcurrent_buffer ();
+      if (BEG != GPT)
+       move_gap_both (BEG, BEG_BYTE);
+      coding->src_chars = Z - BEG;
+      coding->src_bytes = Z_BYTE - BEG_BYTE;
+      coding->src_pos = BEG;
+      coding->src_pos_byte = BEG_BYTE;
+      coding->src_multibyte = Z < Z_BYTE;
+    }
+  else if (STRINGP (src_object))
     {
-      /* We can't skip any data.  */
-      return;
+      code_conversion_save (buffer, 0, 0);
+      coding->src_pos = from;
+      coding->src_pos_byte = from_byte;
     }
-  if (coding->type == coding_type_no_conversion
-      || coding->type == coding_type_raw_text
-      || coding->type == coding_type_emacs_mule
-      || coding->type == coding_type_undecided)
+  else if (BUFFERP (src_object))
     {
-      /* We need no conversion, but don't have to skip any data here.
-         Encoding routine handles them effectively anyway.  */
-      return;
+      code_conversion_save (buffer, 0, 0);
+      set_buffer_internal (XBUFFER (src_object));
+      if (EQ (src_object, dst_object))
+       {
+         saved_pt = PT, saved_pt_byte = PT_BYTE;
+         coding->src_object = del_range_1 (from, to, 1, 1);
+         coding->src_pos = 0;
+         coding->src_pos_byte = 0;
+       }
+      else
+       {
+         if (from < GPT && to >= GPT)
+           move_gap_both (from, from_byte);
+         coding->src_pos = from;
+         coding->src_pos_byte = from_byte;
+       }
     }
+  else
+    code_conversion_save (buffer, 0, 0);
 
-  translation_table = coding->translation_table_for_encode;
-  if (NILP (translation_table) && !NILP (Venable_character_translation))
-    translation_table = Vstandard_translation_table_for_encode;
-  if (CHAR_TABLE_P (translation_table))
+  if (BUFFERP (dst_object))
     {
-      int i;
-      for (i = 0; i < 128; i++)
-       if (!NILP (CHAR_TABLE_REF (translation_table, i)))
-         break;
-      if (i < 128)
-       /* Some ASCII character should be translated.  We give up
-          shrinking.  */
-       return;
+      coding->dst_object = dst_object;
+      if (EQ (src_object, dst_object))
+       {
+         coding->dst_pos = from;
+         coding->dst_pos_byte = from_byte;
+       }
+      else
+       {
+         coding->dst_pos = BUF_PT (XBUFFER (dst_object));
+         coding->dst_pos_byte = BUF_PT_BYTE (XBUFFER (dst_object));
+       }
+      coding->dst_multibyte
+       = ! NILP (XBUFFER (dst_object)->enable_multibyte_characters);
     }
-
-  if (str)
+  else if (EQ (dst_object, Qt))
     {
-      begp_orig = begp = str + *beg;
-      endp_orig = endp = str + *end;
+      coding->dst_object = Qnil;
+      coding->dst_bytes = coding->src_chars;
+      if (coding->dst_bytes == 0)
+       coding->dst_bytes = 1;
+      coding->destination = (unsigned char *) xmalloc (coding->dst_bytes);
+      coding->dst_multibyte = 0;
     }
   else
     {
-      begp_orig = begp = BYTE_POS_ADDR (*beg);
-      endp_orig = endp = begp + *end - *beg;
+      coding->dst_object = Qnil;
+      coding->dst_multibyte = 0;
     }
 
-  eol_conversion = (coding->eol_type == CODING_EOL_CR
-                   || coding->eol_type == CODING_EOL_CRLF);
+  encode_coding (coding);
 
-  /* Here, we don't have to check coding->pre_write_conversion because
-     the caller is expected to have handled it already.  */
-  switch (coding->type)
+  if (EQ (dst_object, Qt))
     {
-    case coding_type_iso2022:
-      if (CODING_SPEC_ISO_INITIAL_DESIGNATION (coding, 0) != CHARSET_ASCII)
-       /* We can't skip any data.  */
-       break;
-      if (coding->flags & CODING_FLAG_ISO_DESIGNATE_AT_BOL)
+      if (BUFFERP (coding->dst_object))
+       coding->dst_object = Fbuffer_string ();
+      else
        {
-         unsigned char *bol = begp;
-         while (begp < endp && *begp < 0x80)
-           {
-             begp++;
-             if (begp[-1] == '\n')
-               bol = begp;
-           }
-         begp = bol;
-         goto label_skip_tail;
+         coding->dst_object
+           = make_unibyte_string ((char *) coding->destination,
+                                  coding->produced);
+         xfree (coding->destination);
        }
-      /* fall down ... */
+    }
 
-    case coding_type_sjis:
-    case coding_type_big5:
-      /* We can skip all ASCII characters at the head and tail.  */
-      if (eol_conversion)
-       while (begp < endp && *begp < 0x80 && *begp != '\n') begp++;
-      else
-       while (begp < endp && *begp < 0x80) begp++;
-    label_skip_tail:
-      if (eol_conversion)
-       while (begp < endp && endp[-1] < 0x80 && endp[-1] != '\n') endp--;
+  if (saved_pt >= 0)
+    {
+      /* This is the case of:
+        (BUFFERP (src_object) && EQ (src_object, dst_object))
+        As we have moved PT while replacing the original buffer
+        contents, we must recover it now.  */
+      set_buffer_internal (XBUFFER (src_object));
+      if (saved_pt < from)
+       TEMP_SET_PT_BOTH (saved_pt, saved_pt_byte);
+      else if (saved_pt < from + chars)
+       TEMP_SET_PT_BOTH (from, from_byte);
+      else if (! NILP (current_buffer->enable_multibyte_characters))
+       TEMP_SET_PT_BOTH (saved_pt + (coding->produced_char - chars),
+                         saved_pt_byte + (coding->produced - bytes));
       else
-       while (begp < endp && *(endp - 1) < 0x80) endp--;
-      break;
+       TEMP_SET_PT_BOTH (saved_pt + (coding->produced - bytes),
+                         saved_pt_byte + (coding->produced - bytes));
+    }
+
+  unbind_to (count, Qnil);
+}
+
+
+Lisp_Object
+preferred_coding_system ()
+{
+  int id = coding_categories[coding_priorities[0]].id;
+
+  return CODING_ID_NAME (id);
+}
+
+\f
+#ifdef emacs
+/*** 8. Emacs Lisp library functions ***/
+
+DEFUN ("coding-system-p", Fcoding_system_p, Scoding_system_p, 1, 1, 0,
+       doc: /* Return t if OBJECT is nil or a coding-system.
+See the documentation of `define-coding-system' for information
+about coding-system objects.  */)
+     (obj)
+     Lisp_Object obj;
+{
+  return ((NILP (obj) || CODING_SYSTEM_P (obj)) ? Qt : Qnil);
+}
+
+DEFUN ("read-non-nil-coding-system", Fread_non_nil_coding_system,
+       Sread_non_nil_coding_system, 1, 1, 0,
+       doc: /* Read a coding system from the minibuffer, prompting with string PROMPT.  */)
+     (prompt)
+     Lisp_Object prompt;
+{
+  Lisp_Object val;
+  do
+    {
+      val = Fcompleting_read (prompt, Vcoding_system_alist, Qnil,
+                             Qt, Qnil, Qcoding_system_history, Qnil, Qnil);
+    }
+  while (SCHARS (val) == 0);
+  return (Fintern (val, Qnil));
+}
+
+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.  */)
+     (prompt, default_coding_system)
+     Lisp_Object prompt, default_coding_system;
+{
+  Lisp_Object val;
+  if (SYMBOLP (default_coding_system))
+    XSETSTRING (default_coding_system, SYMBOL_NAME (default_coding_system));
+  val = Fcompleting_read (prompt, Vcoding_system_alist, Qnil,
+                         Qt, Qnil, Qcoding_system_history,
+                         default_coding_system, Qnil);
+  return (SCHARS (val) == 0 ? Qnil : Fintern (val, Qnil));
+}
+
+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.  */)
+  (coding_system)
+     Lisp_Object coding_system;
+{
+  CHECK_SYMBOL (coding_system);
+  if (!NILP (Fcoding_system_p (coding_system)))
+    return coding_system;
+  while (1)
+    Fsignal (Qcoding_system_error, Fcons (coding_system, Qnil));
+}
+
+\f
+/* Detect how the bytes at SRC of length SRC_BYTES are encoded.  If
+   HIGHEST is nonzero, return the coding system of the highest
+   priority among the detected coding systems.  Otherwize return a
+   list of detected coding systems sorted by their priorities.  If
+   MULTIBYTEP is nonzero, it is assumed that the bytes are in correct
+   multibyte form but contains only ASCII and eight-bit chars.
+   Otherwise, the bytes are raw bytes.
+
+   CODING-SYSTEM controls the detection as below:
+
+   If it is nil, detect both text-format and eol-format.  If the
+   text-format part of CODING-SYSTEM is already specified
+   (e.g. `iso-latin-1'), detect only eol-format.  If the eol-format
+   part of CODING-SYSTEM is already specified (e.g. `undecided-unix'),
+   detect only text-format.  */
+
+Lisp_Object
+detect_coding_system (src, src_bytes, highest, multibytep, coding_system)
+     const unsigned char *src;
+     int src_bytes, highest;
+     int multibytep;
+     Lisp_Object coding_system;
+{
+  const unsigned char *src_end = src + src_bytes;
+  Lisp_Object attrs, eol_type;
+  Lisp_Object val;
+  struct coding_system coding;
+  int id;
+  struct coding_detection_info detect_info;
 
-    default:
-      abort ();
-    }
+  if (NILP (coding_system))
+    coding_system = Qundecided;
+  setup_coding_system (coding_system, &coding);
+  attrs = CODING_ID_ATTRS (coding.id);
+  eol_type = CODING_ID_EOL_TYPE (coding.id);
+  coding_system = CODING_ATTR_BASE_NAME (attrs);
+
+  coding.source = src;
+  coding.src_bytes = src_bytes;
+  coding.src_multibyte = multibytep;
+  coding.consumed = 0;
+  coding.mode |= CODING_MODE_LAST_BLOCK;
 
-  *beg += begp - begp_orig;
-  *end += endp - endp_orig;
-  return;
-}
+  detect_info.checked = detect_info.found = detect_info.rejected = 0;
 
-/* As shrinking conversion region requires some overhead, we don't try
-   shrinking if the length of conversion region is less than this
-   value.  */
-static int shrink_conversion_region_threshhold = 1024;
+  /* At first, detect text-format if necessary.  */
+  if (XINT (CODING_ATTR_CATEGORY (attrs)) == coding_category_undecided)
+    {
+      enum coding_category category;
+      struct coding_system *this;
+      int c, i;
 
-#define SHRINK_CONVERSION_REGION(beg, end, coding, str, encodep)       \
-  do {                                                                 \
-    if (*(end) - *(beg) > shrink_conversion_region_threshhold)         \
-      {                                                                        \
-        if (encodep) shrink_encoding_region (beg, end, coding, str);   \
-        else shrink_decoding_region (beg, end, coding, str);           \
-      }                                                                        \
-  } while (0)
+      for (; src < src_end; src++)
+       {
+         c = *src;
+         if (c & 0x80
+             || (c < 0x20 && (c == ISO_CODE_ESC
+                              || c == ISO_CODE_SI
+                              || c == ISO_CODE_SO)))
+           break;
+       }
+      coding.head_ascii = src - coding.source;
 
-static Lisp_Object
-code_convert_region_unwind (arg)
-     Lisp_Object arg;
-{
-  inhibit_pre_post_conversion = 0;
-  Vlast_coding_system_used = arg;
-  return Qnil;
-}
+      if (src < src_end)
+       for (i = 0; i < coding_category_raw_text; i++)
+         {
+           category = coding_priorities[i];
+           this = coding_categories + category;
 
-/* Store information about all compositions in the range FROM and TO
-   of OBJ in memory blocks pointed by CODING->cmp_data.  OBJ is a
-   buffer or a string, defaults to the current buffer.  */
+           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 (highest
+                   && (detect_info.found & (1 << category)))
+                 break;
+             }
+           else
+             {
+               if ((*(this->detector)) (&coding, &detect_info)
+                   && highest
+                   && (detect_info.found & (1 << category)))
+                 break;
+             }
+         }
 
-void
-coding_save_composition (coding, from, to, obj)
-     struct coding_system *coding;
-     int from, to;
-     Lisp_Object obj;
-{
-  Lisp_Object prop;
-  int start, end;
 
-  if (coding->composing == COMPOSITION_DISABLED)
-    return;
-  if (!coding->cmp_data)
-    coding_allocate_composition_data (coding, from);
-  if (!find_composition (from, to, &start, &end, &prop, obj)
-      || end > to)
-    return;
-  if (start < from
-      && (!find_composition (end, to, &start, &end, &prop, obj)
-         || end > to))
-    return;
-  coding->composing = COMPOSITION_NO;
-  do
-    {
-      if (COMPOSITION_VALID_P (start, end, prop))
+      if (detect_info.rejected == CATEGORY_MASK_ANY)
        {
-         enum composition_method method = COMPOSITION_METHOD (prop);
-         if (coding->cmp_data->used + COMPOSITION_DATA_MAX_BUNCH_LENGTH
-             >= COMPOSITION_DATA_SIZE)
-           coding_allocate_composition_data (coding, from);
-         /* For relative composition, we remember start and end
-             positions, for the other compositions, we also remember
-             components.  */
-         CODING_ADD_COMPOSITION_START (coding, start - from, method);
-         if (method != COMPOSITION_RELATIVE)
+         detect_info.found = CATEGORY_MASK_RAW_TEXT;
+         id = coding_categories[coding_category_raw_text].id;
+         val = Fcons (make_number (id), Qnil);
+       }
+      else if (! detect_info.rejected && ! detect_info.found)
+       {
+         detect_info.found = CATEGORY_MASK_ANY;
+         id = coding_categories[coding_category_undecided].id;
+         val = Fcons (make_number (id), Qnil);
+       }
+      else if (highest)
+       {
+         if (detect_info.found)
            {
-             /* We must store a*/
-             Lisp_Object val, ch;
+             detect_info.found = 1 << category;
+             val = Fcons (make_number (this->id), Qnil);
+           }
+         else
+           for (i = 0; i < coding_category_raw_text; i++)
+             if (! (detect_info.rejected & (1 << coding_priorities[i])))
+               {
+                 detect_info.found = 1 << coding_priorities[i];
+                 id = coding_categories[coding_priorities[i]].id;
+                 val = Fcons (make_number (id), Qnil);
+                 break;
+               }
+       }
+      else
+       {
+         int mask = detect_info.rejected | detect_info.found;
+         int found = 0;
+         val = Qnil;
 
-             val = COMPOSITION_COMPONENTS (prop);
-             if (CONSP (val))
-               while (CONSP (val))
-                 {
-                   ch = XCAR (val), val = XCDR (val);
-                   CODING_ADD_COMPOSITION_COMPONENT (coding, XINT (ch));
-                 }
-             else if (VECTORP (val) || STRINGP (val))
+         for (i = coding_category_raw_text - 1; i >= 0; i--)
+           {
+             category = coding_priorities[i];
+             if (! (mask & (1 << category)))
                {
-                 int len = (VECTORP (val)
-                            ? XVECTOR (val)->size : SCHARS (val));
-                 int i;
-                 for (i = 0; i < len; i++)
-                   {
-                     ch = (STRINGP (val)
-                           ? Faref (val, make_number (i))
-                           : XVECTOR (val)->contents[i]);
-                     CODING_ADD_COMPOSITION_COMPONENT (coding, XINT (ch));
-                   }
+                 found |= 1 << category;
+                 id = coding_categories[category].id;
+                 val = Fcons (make_number (id), val);
+               }
+           }
+         for (i = coding_category_raw_text - 1; i >= 0; i--)
+           {
+             category = coding_priorities[i];
+             if (detect_info.found & (1 << category))
+               {
+                 id = coding_categories[category].id;
+                 val = Fcons (make_number (id), val);
                }
-             else              /* INTEGERP (val) */
-               CODING_ADD_COMPOSITION_COMPONENT (coding, XINT (val));
            }
-         CODING_ADD_COMPOSITION_END (coding, end - from);
+         detect_info.found |= found;
        }
-      start = end;
     }
-  while (start < to
-        && find_composition (start, to, &start, &end, &prop, obj)
-        && end <= to);
+  else
+    {
+      detect_info.found = 1 << XINT (CODING_ATTR_CATEGORY (attrs));
+      val = Fcons (make_number (coding.id), Qnil);
+    }
+
+  /* Then, detect eol-format if necessary.  */
+  {
+    int normal_eol = -1, utf_16_be_eol = -1, utf_16_le_eol;
+    Lisp_Object tail;
+
+    if (VECTORP (eol_type))
+      {
+       if (detect_info.found & ~CATEGORY_MASK_UTF_16)
+         normal_eol = detect_eol (coding.source, src_bytes,
+                                  coding_category_raw_text);
+       if (detect_info.found & (CATEGORY_MASK_UTF_16_BE
+                                | CATEGORY_MASK_UTF_16_BE_NOSIG))
+         utf_16_be_eol = detect_eol (coding.source, src_bytes,
+                                     coding_category_utf_16_be);
+       if (detect_info.found & (CATEGORY_MASK_UTF_16_LE
+                                | CATEGORY_MASK_UTF_16_LE_NOSIG))
+         utf_16_le_eol = detect_eol (coding.source, src_bytes,
+                                     coding_category_utf_16_le);
+      }
+    else
+      {
+       if (EQ (eol_type, Qunix))
+         normal_eol = utf_16_be_eol = utf_16_le_eol = EOL_SEEN_LF;
+       else if (EQ (eol_type, Qdos))
+         normal_eol = utf_16_be_eol = utf_16_le_eol = EOL_SEEN_CRLF;
+       else
+         normal_eol = utf_16_be_eol = utf_16_le_eol = EOL_SEEN_CR;
+      }
+
+    for (tail = val; CONSP (tail); tail = XCDR (tail))
+      {
+       enum coding_category category;
+       int this_eol;
+
+       id = XINT (XCAR (tail));
+       attrs = CODING_ID_ATTRS (id);
+       category = XINT (CODING_ATTR_CATEGORY (attrs));
+       eol_type = CODING_ID_EOL_TYPE (id);
+       if (VECTORP (eol_type))
+         {
+           if (category == coding_category_utf_16_be
+               || category == coding_category_utf_16_be_nosig)
+             this_eol = utf_16_be_eol;
+           else if (category == coding_category_utf_16_le
+                    || category == coding_category_utf_16_le_nosig)
+             this_eol = utf_16_le_eol;
+           else
+             this_eol = normal_eol;
+
+           if (this_eol == EOL_SEEN_LF)
+             XSETCAR (tail, AREF (eol_type, 0));
+           else if (this_eol == EOL_SEEN_CRLF)
+             XSETCAR (tail, AREF (eol_type, 1));
+           else if (this_eol == EOL_SEEN_CR)
+             XSETCAR (tail, AREF (eol_type, 2));
+           else
+             XSETCAR (tail, CODING_ID_NAME (id));
+         }
+       else
+         XSETCAR (tail, CODING_ID_NAME (id));
+      }
+  }
 
-  /* Make coding->cmp_data point to the first memory block.  */
-  while (coding->cmp_data->prev)
-    coding->cmp_data = coding->cmp_data->prev;
-  coding->cmp_data_start = 0;
+  return (highest ? XCAR (val) : val);
 }
 
-/* Reflect the saved information about compositions to OBJ.
-   CODING->cmp_data points to a memory block for the information.  OBJ
-   is a buffer or a string, defaults to the current buffer.  */
 
-void
-coding_restore_composition (coding, obj)
-     struct coding_system *coding;
-     Lisp_Object obj;
-{
-  struct composition_data *cmp_data = coding->cmp_data;
+DEFUN ("detect-coding-region", Fdetect_coding_region, Sdetect_coding_region,
+       2, 3, 0,
+       doc: /* Detect coding system of the text in the region between START and END.
+Return a list of possible coding systems ordered by priority.
 
-  if (!cmp_data)
-    return;
+If only ASCII characters are found, it returns a list of single element
+`undecided' or its subsidiary coding system according to a detected
+end-of-line format.
 
-  while (cmp_data->prev)
-    cmp_data = cmp_data->prev;
+If optional argument HIGHEST is non-nil, return the coding system of
+highest priority.  */)
+     (start, end, highest)
+     Lisp_Object start, end, highest;
+{
+  int from, to;
+  int from_byte, to_byte;
 
-  while (cmp_data)
-    {
-      int i;
+  CHECK_NUMBER_COERCE_MARKER (start);
+  CHECK_NUMBER_COERCE_MARKER (end);
 
-      for (i = 0; i < cmp_data->used && cmp_data->data[i] > 0;
-          i += cmp_data->data[i])
-       {
-         int *data = cmp_data->data + i;
-         enum composition_method method = (enum composition_method) data[3];
-         Lisp_Object components;
+  validate_region (&start, &end);
+  from = XINT (start), to = XINT (end);
+  from_byte = CHAR_TO_BYTE (from);
+  to_byte = CHAR_TO_BYTE (to);
 
-         if (method == COMPOSITION_RELATIVE)
-           components = Qnil;
-         else
-           {
-             int len = data[0] - 4, j;
-             Lisp_Object args[MAX_COMPOSITION_COMPONENTS * 2 - 1];
-
-             if (method == COMPOSITION_WITH_RULE_ALTCHARS
-                 && len % 2 == 0)
-               len --;
-             for (j = 0; j < len; j++)
-               args[j] = make_number (data[4 + j]);
-             components = (method == COMPOSITION_WITH_ALTCHARS
-                           ? Fstring (len, args) : Fvector (len, args));
-           }
-         compose_text (data[1], data[2], components, Qnil, obj);
-       }
-      cmp_data = cmp_data->next;
-    }
+  if (from < GPT && to >= GPT)
+    move_gap_both (to, to_byte);
+
+  return detect_coding_system (BYTE_POS_ADDR (from_byte),
+                              to_byte - from_byte,
+                              !NILP (highest),
+                              !NILP (current_buffer
+                                     ->enable_multibyte_characters),
+                              Qnil);
 }
 
-/* Decode (if ENCODEP is zero) or encode (if ENCODEP is nonzero) the
-   text from FROM to TO (byte positions are FROM_BYTE and TO_BYTE) by
-   coding system CODING, and return the status code of code conversion
-   (currently, this value has no meaning).
+DEFUN ("detect-coding-string", Fdetect_coding_string, Sdetect_coding_string,
+       1, 2, 0,
+       doc: /* Detect coding system of the text in STRING.
+Return a list of possible coding systems ordered by priority.
 
-   How many characters (and bytes) are converted to how many
-   characters (and bytes) are recorded in members of the structure
-   CODING.
+If only ASCII characters are found, it returns a list of single element
+`undecided' or its subsidiary coding system according to a detected
+end-of-line format.
 
-   If REPLACE is nonzero, we do various things as if the original text
-   is deleted and a new text is inserted.  See the comments in
-   replace_range (insdel.c) to know what we are doing.
+If optional argument HIGHEST is non-nil, return the coding system of
+highest priority.  */)
+     (string, highest)
+     Lisp_Object string, highest;
+{
+  CHECK_STRING (string);
 
-   If REPLACE is zero, it is assumed that the source text is unibyte.
-   Otherwise, it is assumed that the source text is multibyte.  */
+  return detect_coding_system (SDATA (string), SBYTES (string),
+                              !NILP (highest), STRING_MULTIBYTE (string),
+                              Qnil);
+}
 
-int
-code_convert_region (from, from_byte, to, to_byte, coding, encodep, replace)
-     int from, from_byte, to, to_byte, encodep, replace;
-     struct coding_system *coding;
-{
-  int len = to - from, len_byte = to_byte - from_byte;
-  int nchars_del = 0, nbytes_del = 0;
-  int require, inserted, inserted_byte;
-  int head_skip, tail_skip, total_skip = 0;
-  Lisp_Object saved_coding_symbol;
-  int first = 1;
-  unsigned char *src, *dst;
-  Lisp_Object deletion;
-  int orig_point = PT, orig_len = len;
-  int prev_Z;
-  int multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
 
-  deletion = Qnil;
-  saved_coding_symbol = coding->symbol;
+static INLINE int
+char_encodable_p (c, attrs)
+     int c;
+     Lisp_Object attrs;
+{
+  Lisp_Object tail;
+  struct charset *charset;
 
-  if (from < PT && PT < to)
+  for (tail = CODING_ATTR_CHARSET_LIST (attrs);
+       CONSP (tail); tail = XCDR (tail))
     {
-      TEMP_SET_PT_BOTH (from, from_byte);
-      orig_point = from;
+      charset = CHARSET_FROM_ID (XINT (XCAR (tail)));
+      if (CHAR_CHARSET_P (c, charset))
+       break;
     }
+  return (! NILP (tail));
+}
 
-  if (replace)
-    {
-      int saved_from = from;
-      int saved_inhibit_modification_hooks;
 
-      prepare_to_modify_buffer (from, to, &from);
-      if (saved_from != from)
-       {
-         to = from + len;
-         from_byte = CHAR_TO_BYTE (from), to_byte = CHAR_TO_BYTE (to);
-         len_byte = to_byte - from_byte;
-       }
+/* Return a list of coding systems that safely encode the text between
+   START and END.  If EXCLUDE is non-nil, it is a list of coding
+   systems not to check.  The returned list doesn't contain any such
+   coding systems.  In any case, if the text contains only ASCII or is
+   unibyte, return t.  */
 
-      /* The code conversion routine can not preserve text properties
-        for now.  So, we must remove all text properties in the
-        region.  Here, we must suppress all modification hooks.  */
-      saved_inhibit_modification_hooks = inhibit_modification_hooks;
-      inhibit_modification_hooks = 1;
-      Fset_text_properties (make_number (from), make_number (to), Qnil, Qnil);
-      inhibit_modification_hooks = saved_inhibit_modification_hooks;
-    }
+DEFUN ("find-coding-systems-region-internal",
+       Ffind_coding_systems_region_internal,
+       Sfind_coding_systems_region_internal, 2, 3, 0,
+       doc: /* Internal use only.  */)
+     (start, end, exclude)
+     Lisp_Object start, end, exclude;
+{
+  Lisp_Object coding_attrs_list, safe_codings;
+  EMACS_INT start_byte, end_byte;
+  const unsigned char *p, *pbeg, *pend;
+  int c;
+  Lisp_Object tail, elt;
 
-  if (! encodep && CODING_REQUIRE_DETECTION (coding))
+  if (STRINGP (start))
+    {
+      if (!STRING_MULTIBYTE (start)
+         || SCHARS (start) == SBYTES (start))
+       return Qt;
+      start_byte = 0;
+      end_byte = SBYTES (start);
+    }
+  else
     {
-      /* We must detect encoding of text and eol format.  */
+      CHECK_NUMBER_COERCE_MARKER (start);
+      CHECK_NUMBER_COERCE_MARKER (end);
+      if (XINT (start) < BEG || XINT (end) > Z || XINT (start) > XINT (end))
+       args_out_of_range (start, end);
+      if (NILP (current_buffer->enable_multibyte_characters))
+       return Qt;
+      start_byte = CHAR_TO_BYTE (XINT (start));
+      end_byte = CHAR_TO_BYTE (XINT (end));
+      if (XINT (end) - XINT (start) == end_byte - start_byte)
+       return Qt;
 
-      if (from < GPT && to > GPT)
-       move_gap_both (from, from_byte);
-      if (coding->type == coding_type_undecided)
-       {
-         detect_coding (coding, BYTE_POS_ADDR (from_byte), len_byte);
-         if (coding->type == coding_type_undecided)
-           {
-             /* It seems that the text contains only ASCII, but we
-                should not leave it undecided because the deeper
-                decoding routine (decode_coding) tries to detect the
-                encodings again in vain.  */
-             coding->type = coding_type_emacs_mule;
-             coding->category_idx = CODING_CATEGORY_IDX_EMACS_MULE;
-             /* As emacs-mule decoder will handle composition, we
-                need this setting to allocate coding->cmp_data
-                later.  */
-             coding->composing = COMPOSITION_NO;
-           }
-       }
-      if (coding->eol_type == CODING_EOL_UNDECIDED
-         && coding->type != coding_type_ccl)
+      if (XINT (start) < GPT && XINT (end) > GPT)
        {
-         detect_eol (coding, BYTE_POS_ADDR (from_byte), len_byte);
-         if (coding->eol_type == CODING_EOL_UNDECIDED)
-           coding->eol_type = CODING_EOL_LF;
-         /* We had better recover the original eol format if we
-            encounter an inconsistent eol format while decoding.  */
-         coding->mode |= CODING_MODE_INHIBIT_INCONSISTENT_EOL;
+         if ((GPT - XINT (start)) < (XINT (end) - GPT))
+           move_gap_both (XINT (start), start_byte);
+         else
+           move_gap_both (XINT (end), end_byte);
        }
     }
 
-  /* Now we convert the text.  */
+  coding_attrs_list = Qnil;
+  for (tail = Vcoding_system_list; CONSP (tail); tail = XCDR (tail))
+    if (NILP (exclude)
+       || NILP (Fmemq (XCAR (tail), exclude)))
+      {
+       Lisp_Object attrs;
 
-  /* For encoding, we must process pre-write-conversion in advance.  */
-  if (! inhibit_pre_post_conversion
-      && encodep
-      && SYMBOLP (coding->pre_write_conversion)
-      && ! NILP (Ffboundp (coding->pre_write_conversion)))
-    {
-      /* The function in pre-write-conversion may put a new text in a
-         new buffer.  */
-      struct buffer *prev = current_buffer;
-      Lisp_Object new;
+       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);
+      }
 
-      record_unwind_protect (code_convert_region_unwind,
-                            Vlast_coding_system_used);
-      /* We should not call any more pre-write/post-read-conversion
-         functions while this pre-write-conversion is running.  */
-      inhibit_pre_post_conversion = 1;
-      call2 (coding->pre_write_conversion,
-            make_number (from), make_number (to));
-      inhibit_pre_post_conversion = 0;
-      /* Discard the unwind protect.  */
-      specpdl_ptr--;
+  if (STRINGP (start))
+    p = pbeg = SDATA (start);
+  else
+    p = pbeg = BYTE_POS_ADDR (start_byte);
+  pend = p + (end_byte - start_byte);
 
-      if (current_buffer != prev)
-       {
-         len = ZV - BEGV;
-         new = Fcurrent_buffer ();
-         set_buffer_internal_1 (prev);
-         del_range_2 (from, from_byte, to, to_byte, 0);
-         TEMP_SET_PT_BOTH (from, from_byte);
-         insert_from_buffer (XBUFFER (new), 1, len, 0);
-         Fkill_buffer (new);
-         if (orig_point >= to)
-           orig_point += len - orig_len;
-         else if (orig_point > from)
-           orig_point = from;
-         orig_len = len;
-         to = from + len;
-         from_byte = CHAR_TO_BYTE (from);
-         to_byte = CHAR_TO_BYTE (to);
-         len_byte = to_byte - from_byte;
-         TEMP_SET_PT_BOTH (from, from_byte);
-       }
-    }
+  while (p < pend && ASCII_BYTE_P (*p)) p++;
+  while (p < pend && ASCII_BYTE_P (*(pend - 1))) pend--;
 
-  if (replace)
+  while (p < pend)
     {
-      if (! EQ (current_buffer->undo_list, Qt))
-       deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
+      if (ASCII_BYTE_P (*p))
+       p++;
       else
        {
-         nchars_del = to - from;
-         nbytes_del = to_byte - from_byte;
-       }
-    }
+         c = STRING_CHAR_ADVANCE (p);
 
-  if (coding->composing != COMPOSITION_DISABLED)
-    {
-      if (encodep)
-       coding_save_composition (coding, from, to, Fcurrent_buffer ());
-      else
-       coding_allocate_composition_data (coding, from);
+         charset_map_loaded = 0;
+         for (tail = coding_attrs_list; CONSP (tail);)
+           {
+             elt = XCAR (tail);
+             if (NILP (elt))
+               tail = XCDR (tail);
+             else if (char_encodable_p (c, elt))
+               tail = XCDR (tail);
+             else if (CONSP (XCDR (tail)))
+               {
+                 XSETCAR (tail, XCAR (XCDR (tail)));
+                 XSETCDR (tail, XCDR (XCDR (tail)));
+               }
+             else
+               {
+                 XSETCAR (tail, Qnil);
+                 tail = XCDR (tail);
+               }
+           }
+         if (charset_map_loaded)
+           {
+             EMACS_INT p_offset = p - pbeg, pend_offset = pend - pbeg;
+
+             if (STRINGP (start))
+               pbeg = SDATA (start);
+             else
+               pbeg = BYTE_POS_ADDR (start_byte);
+             p = pbeg + p_offset;
+             pend = pbeg + pend_offset;
+           }
+       }
     }
 
-  /* Try to skip the heading and tailing ASCIIs.  */
-  if (coding->type != coding_type_ccl)
-    {
-      int from_byte_orig = from_byte, to_byte_orig = to_byte;
+  safe_codings = Qnil;
+  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);
 
-      if (from < GPT && GPT < to)
-       move_gap_both (from, from_byte);
-      SHRINK_CONVERSION_REGION (&from_byte, &to_byte, coding, NULL, encodep);
-      if (from_byte == to_byte
-         && (encodep || NILP (coding->post_read_conversion))
-         && ! CODING_REQUIRE_FLUSHING (coding))
-       {
-         coding->produced = len_byte;
-         coding->produced_char = len;
-         if (!replace)
-           /* We must record and adjust for this new text now.  */
-           adjust_after_insert (from, from_byte_orig, to, to_byte_orig, len);
-         return 0;
-       }
+  return safe_codings;
+}
 
-      head_skip = from_byte - from_byte_orig;
-      tail_skip = to_byte_orig - to_byte;
-      total_skip = head_skip + tail_skip;
-      from += head_skip;
-      to -= tail_skip;
-      len -= total_skip; len_byte -= total_skip;
-    }
 
-  /* For conversion, we must put the gap before the text in addition to
-     making the gap larger for efficient decoding.  The required gap
-     size starts from 2000 which is the magic number used in make_gap.
-     But, after one batch of conversion, it will be incremented if we
-     find that it is not enough .  */
-  require = 2000;
+DEFUN ("unencodable-char-position", Funencodable_char_position,
+       Sunencodable_char_position, 3, 5, 0,
+       doc: /*
+Return position of first un-encodable character in a region.
+START and END specfiy the region and CODING-SYSTEM specifies the
+encoding to check.  Return nil if CODING-SYSTEM does encode the region.
 
-  if (GAP_SIZE  < require)
-    make_gap (require - GAP_SIZE);
-  move_gap_both (from, from_byte);
+If optional 4th argument COUNT is non-nil, it specifies at most how
+many un-encodable characters to search.  In this case, the value is a
+list of positions.
 
-  inserted = inserted_byte = 0;
+If optional 5th argument STRING is non-nil, it is a string to search
+for un-encodable characters.  In that case, START and END are indexes
+to the string.  */)
+     (start, end, coding_system, count, string)
+     Lisp_Object start, end, coding_system, count, string;
+{
+  int n;
+  struct coding_system coding;
+  Lisp_Object attrs, charset_list;
+  Lisp_Object positions;
+  int from, to;
+  const unsigned char *p, *stop, *pend;
+  int ascii_compatible;
 
-  GAP_SIZE += len_byte;
-  ZV -= len;
-  Z -= len;
-  ZV_BYTE -= len_byte;
-  Z_BYTE -= len_byte;
+  setup_coding_system (Fcheck_coding_system (coding_system), &coding);
+  attrs = CODING_ID_ATTRS (coding.id);
+  if (EQ (CODING_ATTR_TYPE (attrs), Qraw_text))
+    return Qnil;
+  ascii_compatible = ! NILP (CODING_ATTR_ASCII_COMPAT (attrs));
+  charset_list = CODING_ATTR_CHARSET_LIST (attrs);
 
-  if (GPT - BEG < BEG_UNCHANGED)
-    BEG_UNCHANGED = GPT - BEG;
-  if (Z - GPT < END_UNCHANGED)
-    END_UNCHANGED = Z - GPT;
+  if (NILP (string))
+    {
+      validate_region (&start, &end);
+      from = XINT (start);
+      to = XINT (end);
+      if (NILP (current_buffer->enable_multibyte_characters)
+         || (ascii_compatible
+             && (to - from) == (CHAR_TO_BYTE (to) - (CHAR_TO_BYTE (from)))))
+       return Qnil;
+      p = CHAR_POS_ADDR (from);
+      pend = CHAR_POS_ADDR (to);
+      if (from < GPT && to >= GPT)
+       stop = GPT_ADDR;
+      else
+       stop = pend;
+    }
+  else
+    {
+      CHECK_STRING (string);
+      CHECK_NATNUM (start);
+      CHECK_NATNUM (end);
+      from = XINT (start);
+      to = XINT (end);
+      if (from > to
+         || to > SCHARS (string))
+       args_out_of_range_3 (string, start, end);
+      if (! STRING_MULTIBYTE (string))
+       return Qnil;
+      p = SDATA (string) + string_char_to_byte (string, from);
+      stop = pend = SDATA (string) + string_char_to_byte (string, to);
+      if (ascii_compatible && (to - from) == (pend - p))
+       return Qnil;
+    }
 
-  if (!encodep && coding->src_multibyte)
+  if (NILP (count))
+    n = 1;
+  else
     {
-      /* Decoding routines expects that the source text is unibyte.
-        We must convert 8-bit characters of multibyte form to
-        unibyte.  */
-      int len_byte_orig = len_byte;
-      len_byte = str_as_unibyte (GAP_END_ADDR - len_byte, len_byte);
-      if (len_byte < len_byte_orig)
-       safe_bcopy (GAP_END_ADDR - len_byte_orig, GAP_END_ADDR - len_byte,
-                   len_byte);
-      coding->src_multibyte = 0;
+      CHECK_NATNUM (count);
+      n = XINT (count);
     }
 
-  for (;;)
+  positions = Qnil;
+  while (1)
     {
-      int result;
-
-      /* The buffer memory is now:
-        +--------+converted-text+---------+-------original-text-------+---+
-        |<-from->|<--inserted-->|---------|<--------len_byte--------->|---|
-                 |<---------------------- GAP ----------------------->|  */
-      src = GAP_END_ADDR - len_byte;
-      dst = GPT_ADDR + inserted_byte;
+      int c;
 
-      if (encodep)
-       result = encode_coding (coding, src, dst, len_byte, 0);
-      else
+      if (ascii_compatible)
+       while (p < stop && ASCII_BYTE_P (*p))
+         p++, from++;
+      if (p >= stop)
        {
-         if (coding->composing != COMPOSITION_DISABLED)
-           coding->cmp_data->char_offset = from + inserted;
-         result = decode_coding (coding, src, dst, len_byte, 0);
+         if (p >= pend)
+           break;
+         stop = pend;
+         p = GAP_END_ADDR;
        }
 
-      /* The buffer memory is now:
-        +--------+-------converted-text----+--+------original-text----+---+
-        |<-from->|<-inserted->|<-produced->|--|<-(len_byte-consumed)->|---|
-                 |<---------------------- GAP ----------------------->|  */
-
-      inserted += coding->produced_char;
-      inserted_byte += coding->produced;
-      len_byte -= coding->consumed;
-
-      if (result == CODING_FINISH_INSUFFICIENT_CMP)
+      c = STRING_CHAR_ADVANCE (p);
+      if (! (ASCII_CHAR_P (c) && ascii_compatible)
+         && ! char_charset (c, charset_list, NULL))
        {
-         coding_allocate_composition_data (coding, from + inserted);
-         continue;
+         positions = Fcons (make_number (from), positions);
+         n--;
+         if (n == 0)
+           break;
        }
 
-      src += coding->consumed;
-      dst += coding->produced;
+      from++;
+    }
 
-      if (result == CODING_FINISH_NORMAL)
-       {
-         src += len_byte;
-         break;
-       }
-      if (! encodep && result == CODING_FINISH_INCONSISTENT_EOL)
-       {
-         unsigned char *pend = dst, *p = pend - inserted_byte;
-         Lisp_Object eol_type;
+  return (NILP (count) ? Fcar (positions) : Fnreverse (positions));
+}
 
-         /* Encode LFs back to the original eol format (CR or CRLF).  */
-         if (coding->eol_type == CODING_EOL_CR)
-           {
-             while (p < pend) if (*p++ == '\n') p[-1] = '\r';
-           }
-         else
-           {
-             int count = 0;
 
-             while (p < pend) if (*p++ == '\n') count++;
-             if (src - dst < count)
-               {
-                 /* We don't have sufficient room for encoding LFs
-                    back to CRLF.  We must record converted and
-                    not-yet-converted text back to the buffer
-                    content, enlarge the gap, then record them out of
-                    the buffer contents again.  */
-                 int add = len_byte + inserted_byte;
-
-                 GAP_SIZE -= add;
-                 ZV += add; Z += add; ZV_BYTE += add; Z_BYTE += add;
-                 GPT += inserted_byte; GPT_BYTE += inserted_byte;
-                 make_gap (count - GAP_SIZE);
-                 GAP_SIZE += add;
-                 ZV -= add; Z -= add; ZV_BYTE -= add; Z_BYTE -= add;
-                 GPT -= inserted_byte; GPT_BYTE -= inserted_byte;
-                 /* Don't forget to update SRC, DST, and PEND.  */
-                 src = GAP_END_ADDR - len_byte;
-                 dst = GPT_ADDR + inserted_byte;
-                 pend = dst;
-               }
-             inserted += count;
-             inserted_byte += count;
-             coding->produced += count;
-             p = dst = pend + count;
-             while (count)
-               {
-                 *--p = *--pend;
-                 if (*p == '\n') count--, *--p = '\r';
-               }
-           }
+DEFUN ("check-coding-systems-region", Fcheck_coding_systems_region,
+       Scheck_coding_systems_region, 3, 3, 0,
+       doc: /* Check if the region is encodable by coding systems.
 
-         /* Suppress eol-format conversion in the further conversion.  */
-         coding->eol_type = CODING_EOL_LF;
+START and END are buffer positions specifying the region.
+CODING-SYSTEM-LIST is a list of coding systems to check.
 
-         /* Set the coding system symbol to that for Unix-like EOL.  */
-         eol_type = Fget (saved_coding_symbol, Qeol_type);
-         if (VECTORP (eol_type)
-             && XVECTOR (eol_type)->size == 3
-             && SYMBOLP (XVECTOR (eol_type)->contents[CODING_EOL_LF]))
-           coding->symbol = XVECTOR (eol_type)->contents[CODING_EOL_LF];
-         else
-           coding->symbol = saved_coding_symbol;
+The value is an alist ((CODING-SYSTEM POS0 POS1 ...) ...), where
+CODING-SYSTEM is a member of CODING-SYSTEM-LIst and can't encode the
+whole region, POS0, POS1, ... are buffer positions where non-encodable
+characters are found.
 
-         continue;
-       }
-      if (len_byte <= 0)
-       {
-         if (coding->type != coding_type_ccl
-             || coding->mode & CODING_MODE_LAST_BLOCK)
-           break;
-         coding->mode |= CODING_MODE_LAST_BLOCK;
-         continue;
-       }
-      if (result == CODING_FINISH_INSUFFICIENT_SRC)
-       {
-         /* The source text ends in invalid codes.  Let's just
-            make them valid buffer contents, and finish conversion.  */
-         if (multibyte_p)
-           {
-             unsigned char *start = dst;
+If all coding systems in CODING-SYSTEM-LIST can encode the region, the
+value is nil.
 
-             inserted += len_byte;
-             while (len_byte--)
-               {
-                 int c = *src++;
-                 dst += CHAR_STRING (c, dst);
-               }
+START may be a string.  In that case, check if the string is
+encodable, and the value contains indices to the string instead of
+buffer positions.  END is ignored.  */)
+     (start, end, coding_system_list)
+     Lisp_Object start, end, coding_system_list;
+{
+  Lisp_Object list;
+  EMACS_INT start_byte, end_byte;
+  int pos;
+  const unsigned char *p, *pbeg, *pend;
+  int c;
+  Lisp_Object tail, elt;
 
-             inserted_byte += dst - start;
-           }
-         else
-           {
-             inserted += len_byte;
-             inserted_byte += len_byte;
-             while (len_byte--)
-               *dst++ = *src++;
-           }
-         break;
-       }
-      if (result == CODING_FINISH_INTERRUPT)
-       {
-         /* The conversion procedure was interrupted by a user.  */
-         break;
-       }
-      /* Now RESULT == CODING_FINISH_INSUFFICIENT_DST  */
-      if (coding->consumed < 1)
-       {
-         /* It's quite strange to require more memory without
-            consuming any bytes.  Perhaps CCL program bug.  */
-         break;
-       }
-      if (first)
-       {
-         /* We have just done the first batch of conversion which was
-            stopped because of insufficient gap.  Let's reconsider the
-            required gap size (i.e. SRT - DST) now.
-
-            We have converted ORIG bytes (== coding->consumed) into
-            NEW bytes (coding->produced).  To convert the remaining
-            LEN bytes, we may need REQUIRE bytes of gap, where:
-               REQUIRE + LEN_BYTE = LEN_BYTE * (NEW / ORIG)
-               REQUIRE = LEN_BYTE * (NEW - ORIG) / ORIG
-            Here, we are sure that NEW >= ORIG.  */
-         float ratio;
-
-         if (coding->produced <= coding->consumed)
-           {
-             /* This happens because of CCL-based coding system with
-                eol-type CRLF.  */
-             require = 0;
-           }
-         else
-           {
-             ratio = (coding->produced - coding->consumed) / coding->consumed;
-             require = len_byte * ratio;
-           }
-         first = 0;
-       }
-      if ((src - dst) < (require + 2000))
-       {
-         /* See the comment above the previous call of make_gap.  */
-         int add = len_byte + inserted_byte;
-
-         GAP_SIZE -= add;
-         ZV += add; Z += add; ZV_BYTE += add; Z_BYTE += add;
-         GPT += inserted_byte; GPT_BYTE += inserted_byte;
-         make_gap (require + 2000);
-         GAP_SIZE += add;
-         ZV -= add; Z -= add; ZV_BYTE -= add; Z_BYTE -= add;
-         GPT -= inserted_byte; GPT_BYTE -= inserted_byte;
-       }
+  if (STRINGP (start))
+    {
+      if (!STRING_MULTIBYTE (start)
+         && SCHARS (start) != SBYTES (start))
+       return Qnil;
+      start_byte = 0;
+      end_byte = SBYTES (start);
+      pos = 0;
     }
-  if (src - dst > 0) *dst = 0; /* Put an anchor.  */
-
-  if (encodep && coding->dst_multibyte)
+  else
     {
-      /* The output is unibyte.  We must convert 8-bit characters to
-        multibyte form.  */
-      if (inserted_byte * 2 > GAP_SIZE)
+      CHECK_NUMBER_COERCE_MARKER (start);
+      CHECK_NUMBER_COERCE_MARKER (end);
+      if (XINT (start) < BEG || XINT (end) > Z || XINT (start) > XINT (end))
+       args_out_of_range (start, end);
+      if (NILP (current_buffer->enable_multibyte_characters))
+       return Qnil;
+      start_byte = CHAR_TO_BYTE (XINT (start));
+      end_byte = CHAR_TO_BYTE (XINT (end));
+      if (XINT (end) - XINT (start) == end_byte - start_byte)
+       return Qt;
+
+      if (XINT (start) < GPT && XINT (end) > GPT)
        {
-         GAP_SIZE -= inserted_byte;
-         ZV += inserted_byte; Z += inserted_byte;
-         ZV_BYTE += inserted_byte; Z_BYTE += inserted_byte;
-         GPT += inserted_byte; GPT_BYTE += inserted_byte;
-         make_gap (inserted_byte - GAP_SIZE);
-         GAP_SIZE += inserted_byte;
-         ZV -= inserted_byte; Z -= inserted_byte;
-         ZV_BYTE -= inserted_byte; Z_BYTE -= inserted_byte;
-         GPT -= inserted_byte; GPT_BYTE -= inserted_byte;
+         if ((GPT - XINT (start)) < (XINT (end) - GPT))
+           move_gap_both (XINT (start), start_byte);
+         else
+           move_gap_both (XINT (end), end_byte);
        }
-      inserted_byte = str_to_multibyte (GPT_ADDR, GAP_SIZE, inserted_byte);
+      pos = XINT (start);
     }
 
-  /* If we shrank the conversion area, adjust it now.  */
-  if (total_skip > 0)
+  list = Qnil;
+  for (tail = coding_system_list; CONSP (tail); tail = XCDR (tail))
     {
-      if (tail_skip > 0)
-       safe_bcopy (GAP_END_ADDR, GPT_ADDR + inserted_byte, tail_skip);
-      inserted += total_skip; inserted_byte += total_skip;
-      GAP_SIZE += total_skip;
-      GPT -= head_skip; GPT_BYTE -= head_skip;
-      ZV -= total_skip; ZV_BYTE -= total_skip;
-      Z -= total_skip; Z_BYTE -= total_skip;
-      from -= head_skip; from_byte -= head_skip;
-      to += tail_skip; to_byte += tail_skip;
+      elt = XCAR (tail);
+      list = Fcons (Fcons (elt, Fcons (AREF (CODING_SYSTEM_SPEC (elt), 0),
+                                      Qnil)),
+                   list);
     }
 
-  prev_Z = Z;
-  if (! EQ (current_buffer->undo_list, Qt))
-    adjust_after_replace (from, from_byte, deletion, inserted, inserted_byte);
+  if (STRINGP (start))
+    p = pbeg = SDATA (start);
   else
-    adjust_after_replace_noundo (from, from_byte, nchars_del, nbytes_del,
-                                inserted, inserted_byte);
-  inserted = Z - prev_Z;
+    p = pbeg = BYTE_POS_ADDR (start_byte);
+  pend = p + (end_byte - start_byte);
 
-  if (!encodep && coding->cmp_data && coding->cmp_data->used)
-    coding_restore_composition (coding, Fcurrent_buffer ());
-  coding_free_composition_data (coding);
+  while (p < pend && ASCII_BYTE_P (*p)) p++, pos++;
+  while (p < pend && ASCII_BYTE_P (*(pend - 1))) pend--;
 
-  if (! inhibit_pre_post_conversion
-      && ! encodep && ! NILP (coding->post_read_conversion))
+  while (p < pend)
     {
-      Lisp_Object val;
-      Lisp_Object saved_coding_system;
-
-      if (from != PT)
-       TEMP_SET_PT_BOTH (from, from_byte);
-      prev_Z = Z;
-      record_unwind_protect (code_convert_region_unwind,
-                            Vlast_coding_system_used);
-      saved_coding_system = Vlast_coding_system_used;
-      Vlast_coding_system_used = coding->symbol;
-      /* We should not call any more pre-write/post-read-conversion
-         functions while this post-read-conversion is running.  */
-      inhibit_pre_post_conversion = 1;
-      val = call1 (coding->post_read_conversion, make_number (inserted));
-      inhibit_pre_post_conversion = 0;
-      coding->symbol = Vlast_coding_system_used;
-      Vlast_coding_system_used = saved_coding_system;
-      /* Discard the unwind protect.  */
-      specpdl_ptr--;
-      CHECK_NUMBER (val);
-      inserted += Z - prev_Z;
-    }
-
-  if (orig_point >= from)
-    {
-      if (orig_point >= from + orig_len)
-       orig_point += inserted - orig_len;
+      if (ASCII_BYTE_P (*p))
+       p++;
       else
-       orig_point = from;
-      TEMP_SET_PT (orig_point);
+       {
+         c = STRING_CHAR_ADVANCE (p);
+
+         charset_map_loaded = 0;
+         for (tail = list; CONSP (tail); tail = XCDR (tail))
+           {
+             elt = XCDR (XCAR (tail));
+             if (! char_encodable_p (c, XCAR (elt)))
+               XSETCDR (elt, Fcons (make_number (pos), XCDR (elt)));
+           }
+         if (charset_map_loaded)
+           {
+             EMACS_INT p_offset = p - pbeg, pend_offset = pend - pbeg;
+
+             if (STRINGP (start))
+               pbeg = SDATA (start);
+             else
+               pbeg = BYTE_POS_ADDR (start_byte);
+             p = pbeg + p_offset;
+             pend = pbeg + pend_offset;
+           }
+       }
+      pos++;
     }
 
-  if (replace)
+  tail = list;
+  list = Qnil;
+  for (; CONSP (tail); tail = XCDR (tail))
     {
-      signal_after_change (from, to - from, inserted);
-      update_compositions (from, from + inserted, CHECK_BORDER);
+      elt = XCAR (tail);
+      if (CONSP (XCDR (XCDR (elt))))
+       list = Fcons (Fcons (XCAR (elt), Fnreverse (XCDR (XCDR (elt)))),
+                     list);
     }
 
-  {
-    coding->consumed = to_byte - from_byte;
-    coding->consumed_char = to - from;
-    coding->produced = inserted_byte;
-    coding->produced_char = inserted;
-  }
-
-  return 0;
+  return list;
 }
 
-Lisp_Object
-run_pre_post_conversion_on_str (str, coding, encodep)
-     Lisp_Object str;
-     struct coding_system *coding;
-     int encodep;
-{
-  int count = SPECPDL_INDEX ();
-  struct gcpro gcpro1, gcpro2;
-  int multibyte = STRING_MULTIBYTE (str);
-  Lisp_Object buffer;
-  struct buffer *buf;
-  Lisp_Object old_deactivate_mark;
-
-  record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
-  record_unwind_protect (code_convert_region_unwind,
-                        Vlast_coding_system_used);
-  /* It is not crucial to specbind this.  */
-  old_deactivate_mark = Vdeactivate_mark;
-  GCPRO2 (str, old_deactivate_mark);
-
-  buffer = Fget_buffer_create (build_string (" *code-converting-work*"));
-  buf = XBUFFER (buffer);
-
-  delete_all_overlays (buf);
-  buf->directory = current_buffer->directory;
-  buf->read_only = Qnil;
-  buf->filename = Qnil;
-  buf->undo_list = Qt;
-  eassert (buf->overlays_before == NULL);
-  eassert (buf->overlays_after == NULL);
-
-  set_buffer_internal (buf);
-  /* We must insert the contents of STR as is without
-     unibyte<->multibyte conversion.  For that, we adjust the
-     multibyteness of the working buffer to that of STR.  */
-  Ferase_buffer ();
-  buf->enable_multibyte_characters = multibyte ? Qt : Qnil;
 
-  insert_from_string (str, 0, 0,
-                     SCHARS (str), SBYTES (str), 0);
-  UNGCPRO;
-  inhibit_pre_post_conversion = 1;
-  if (encodep)
-    call2 (coding->pre_write_conversion, make_number (BEG), make_number (Z));
-  else
-    {
-      Vlast_coding_system_used = coding->symbol;
-      TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
-      call1 (coding->post_read_conversion, make_number (Z - BEG));
-      coding->symbol = Vlast_coding_system_used;
-    }
-  inhibit_pre_post_conversion = 0;
-  Vdeactivate_mark = old_deactivate_mark;
-  str = make_buffer_string (BEG, Z, 1);
-  return unbind_to (count, str);
-}
 
 Lisp_Object
-decode_coding_string (str, coding, nocopy)
-     Lisp_Object str;
-     struct coding_system *coding;
-     int nocopy;
+code_convert_region (start, end, coding_system, dst_object, encodep, norecord)
+     Lisp_Object start, end, coding_system, dst_object;
+     int encodep, norecord;
 {
-  int len;
-  struct conversion_buffer buf;
-  int from, to_byte;
-  Lisp_Object saved_coding_symbol;
-  int result;
-  int require_decoding;
-  int shrinked_bytes = 0;
-  Lisp_Object newstr;
-  int consumed, consumed_char, produced, produced_char;
-
-  from = 0;
-  to_byte = SBYTES (str);
-
-  saved_coding_symbol = coding->symbol;
-  coding->src_multibyte = STRING_MULTIBYTE (str);
-  coding->dst_multibyte = 1;
-  if (CODING_REQUIRE_DETECTION (coding))
-    {
-      /* See the comments in code_convert_region.  */
-      if (coding->type == coding_type_undecided)
-       {
-         detect_coding (coding, SDATA (str), to_byte);
-         if (coding->type == coding_type_undecided)
-           {
-             coding->type = coding_type_emacs_mule;
-             coding->category_idx = CODING_CATEGORY_IDX_EMACS_MULE;
-             /* As emacs-mule decoder will handle composition, we
-                need this setting to allocate coding->cmp_data
-                later.  */
-             coding->composing = COMPOSITION_NO;
-           }
-       }
-      if (coding->eol_type == CODING_EOL_UNDECIDED
-         && coding->type != coding_type_ccl)
-       {
-         saved_coding_symbol = coding->symbol;
-         detect_eol (coding, SDATA (str), to_byte);
-         if (coding->eol_type == CODING_EOL_UNDECIDED)
-           coding->eol_type = CODING_EOL_LF;
-         /* We had better recover the original eol format if we
-            encounter an inconsistent eol format while decoding.  */
-         coding->mode |= CODING_MODE_INHIBIT_INCONSISTENT_EOL;
-       }
-    }
+  struct coding_system coding;
+  EMACS_INT from, from_byte, to, to_byte;
+  Lisp_Object src_object;
 
-  if (coding->type == coding_type_no_conversion
-      || coding->type == coding_type_raw_text)
-    coding->dst_multibyte = 0;
+  CHECK_NUMBER_COERCE_MARKER (start);
+  CHECK_NUMBER_COERCE_MARKER (end);
+  if (NILP (coding_system))
+    coding_system = Qno_conversion;
+  else
+    CHECK_CODING_SYSTEM (coding_system);
+  src_object = Fcurrent_buffer ();
+  if (NILP (dst_object))
+    dst_object = src_object;
+  else if (! EQ (dst_object, Qt))
+    CHECK_BUFFER (dst_object);
+
+  validate_region (&start, &end);
+  from = XFASTINT (start);
+  from_byte = CHAR_TO_BYTE (from);
+  to = XFASTINT (end);
+  to_byte = CHAR_TO_BYTE (to);
 
-  require_decoding = CODING_REQUIRE_DECODING (coding);
+  setup_coding_system (coding_system, &coding);
+  coding.mode |= CODING_MODE_LAST_BLOCK;
 
-  if (STRING_MULTIBYTE (str))
-    {
-      /* Decoding routines expect the source text to be unibyte.  */
-      str = Fstring_as_unibyte (str);
-      to_byte = SBYTES (str);
-      nocopy = 1;
-      coding->src_multibyte = 0;
-    }
+  if (encodep)
+    encode_coding_object (&coding, src_object, from, from_byte, to, to_byte,
+                         dst_object);
+  else
+    decode_coding_object (&coding, src_object, from, from_byte, to, to_byte,
+                         dst_object);
+  if (! norecord)
+    Vlast_coding_system_used = CODING_ID_NAME (coding.id);
 
-  /* Try to skip the heading and tailing ASCIIs.  */
-  if (require_decoding && coding->type != coding_type_ccl)
-    {
-      SHRINK_CONVERSION_REGION (&from, &to_byte, coding, SDATA (str),
-                               0);
-      if (from == to_byte)
-       require_decoding = 0;
-      shrinked_bytes = from + (SBYTES (str) - to_byte);
-    }
+  if (coding.result != CODING_RESULT_SUCCESS)
+    error ("Code conversion error: %d", coding.result);
 
-  if (!require_decoding
-      && !(SYMBOLP (coding->post_read_conversion)
-          && !NILP (Ffboundp (coding->post_read_conversion))))
-    {
-      coding->consumed = SBYTES (str);
-      coding->consumed_char = SCHARS (str);
-      if (coding->dst_multibyte)
-       {
-         str = Fstring_as_multibyte (str);
-         nocopy = 1;
-       }
-      coding->produced = SBYTES (str);
-      coding->produced_char = SCHARS (str);
-      return (nocopy ? str : Fcopy_sequence (str));
-    }
+  return (BUFFERP (dst_object)
+         ? make_number (coding.produced_char)
+         : coding.dst_object);
+}
 
-  if (coding->composing != COMPOSITION_DISABLED)
-    coding_allocate_composition_data (coding, from);
-  len = decoding_buffer_size (coding, to_byte - from);
-  allocate_conversion_buffer (buf, len);
 
-  consumed = consumed_char = produced = produced_char = 0;
-  while (1)
-    {
-      result = decode_coding (coding, SDATA (str) + from + consumed,
-                             buf.data + produced, to_byte - from - consumed,
-                             buf.size - produced);
-      consumed += coding->consumed;
-      consumed_char += coding->consumed_char;
-      produced += coding->produced;
-      produced_char += coding->produced_char;
-      if (result == CODING_FINISH_NORMAL
-         || (result == CODING_FINISH_INSUFFICIENT_SRC
-             && coding->consumed == 0))
-       break;
-      if (result == CODING_FINISH_INSUFFICIENT_CMP)
-       coding_allocate_composition_data (coding, from + produced_char);
-      else if (result == CODING_FINISH_INSUFFICIENT_DST)
-       extend_conversion_buffer (&buf);
-      else if (result == CODING_FINISH_INCONSISTENT_EOL)
-       {
-         Lisp_Object eol_type;
+DEFUN ("decode-coding-region", Fdecode_coding_region, Sdecode_coding_region,
+       3, 4, "r\nzCoding system: ",
+       doc: /* Decode the current region from the specified coding system.
+When called from a program, takes four arguments:
+       START, END, CODING-SYSTEM, and DESTINATION.
+START and END are buffer positions.
 
-         /* Recover the original EOL format.  */
-         if (coding->eol_type == CODING_EOL_CR)
-           {
-             unsigned char *p;
-             for (p = buf.data; p < buf.data + produced; p++)
-               if (*p == '\n') *p = '\r';
-           }
-         else if (coding->eol_type == CODING_EOL_CRLF)
-           {
-             int num_eol = 0;
-             unsigned char *p0, *p1;
-             for (p0 = buf.data, p1 = p0 + produced; p0 < p1; p0++)
-               if (*p0 == '\n') num_eol++;
-             if (produced + num_eol >= buf.size)
-               extend_conversion_buffer (&buf);
-             for (p0 = buf.data + produced, p1 = p0 + num_eol; p0 > buf.data;)
-               {
-                 *--p1 = *--p0;
-                 if (*p0 == '\n') *--p1 = '\r';
-               }
-             produced += num_eol;
-             produced_char += num_eol;
-           }
-         /* Suppress eol-format conversion in the further conversion.  */
-         coding->eol_type = CODING_EOL_LF;
-
-         /* Set the coding system symbol to that for Unix-like EOL.  */
-         eol_type = Fget (saved_coding_symbol, Qeol_type);
-         if (VECTORP (eol_type)
-             && XVECTOR (eol_type)->size == 3
-             && SYMBOLP (XVECTOR (eol_type)->contents[CODING_EOL_LF]))
-           coding->symbol = XVECTOR (eol_type)->contents[CODING_EOL_LF];
-         else
-           coding->symbol = saved_coding_symbol;
+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 buffer, the decoded text is inserted in the buffer.
+If t, the decoded text is returned.
 
+This function sets `last-coding-system-used' to the precise coding system
+used (which may be different from CODING-SYSTEM if CODING-SYSTEM is
+not fully specified.)
+It returns the length of the decoded text.  */)
+     (start, end, coding_system, destination)
+     Lisp_Object start, end, coding_system, destination;
+{
+  return code_convert_region (start, end, coding_system, destination, 0, 0);
+}
 
-       }
-    }
+DEFUN ("encode-coding-region", Fencode_coding_region, Sencode_coding_region,
+       3, 4, "r\nzCoding system: ",
+       doc: /* Encode the current region by specified coding system.
+When called from a program, takes three arguments:
+START, END, and CODING-SYSTEM.  START and END are buffer positions.
 
-  coding->consumed = consumed;
-  coding->consumed_char = consumed_char;
-  coding->produced = produced;
-  coding->produced_char = produced_char;
+Optional 4th arguments DESTINATION specifies where the encoded text goes.
+If nil, the region between START and END is replace by the encoded text.
+If buffer, the encoded text is inserted in the buffer.
+If t, the encoded text is returned.
 
-  if (coding->dst_multibyte)
-    newstr = make_uninit_multibyte_string (produced_char + shrinked_bytes,
-                                          produced + shrinked_bytes);
-  else
-    newstr = make_uninit_string (produced + shrinked_bytes);
-  if (from > 0)
-    STRING_COPYIN (newstr, 0, SDATA (str), from);
-  STRING_COPYIN (newstr, from, buf.data, produced);
-  if (shrinked_bytes > from)
-    STRING_COPYIN (newstr, from + produced,
-                  SDATA (str) + to_byte,
-                  shrinked_bytes - from);
-  free_conversion_buffer (&buf);
-
-  if (coding->cmp_data && coding->cmp_data->used)
-    coding_restore_composition (coding, newstr);
-  coding_free_composition_data (coding);
-
-  if (SYMBOLP (coding->post_read_conversion)
-      && !NILP (Ffboundp (coding->post_read_conversion)))
-    newstr = run_pre_post_conversion_on_str (newstr, coding, 0);
-
-  return newstr;
+This function sets `last-coding-system-used' to the precise coding system
+used (which may be different from CODING-SYSTEM if CODING-SYSTEM is
+not fully specified.)
+It returns the length of the encoded text.  */)
+  (start, end, coding_system, destination)
+     Lisp_Object start, end, coding_system, destination;
+{
+  return code_convert_region (start, end, coding_system, destination, 1, 0);
 }
 
 Lisp_Object
-encode_coding_string (str, coding, nocopy)
-     Lisp_Object str;
-     struct coding_system *coding;
-     int nocopy;
+code_convert_string (string, coding_system, dst_object,
+                    encodep, nocopy, norecord)
+     Lisp_Object string, coding_system, dst_object;
+     int encodep, nocopy, norecord;
 {
-  int len;
-  struct conversion_buffer buf;
-  int from, to, to_byte;
-  int result;
-  int shrinked_bytes = 0;
-  Lisp_Object newstr;
-  int consumed, consumed_char, produced, produced_char;
-
-  if (SYMBOLP (coding->pre_write_conversion)
-      && !NILP (Ffboundp (coding->pre_write_conversion)))
-    str = run_pre_post_conversion_on_str (str, coding, 1);
-
-  from = 0;
-  to = SCHARS (str);
-  to_byte = SBYTES (str);
-
-  /* Encoding routines determine the multibyteness of the source text
-     by coding->src_multibyte.  */
-  coding->src_multibyte = STRING_MULTIBYTE (str);
-  coding->dst_multibyte = 0;
-  if (! CODING_REQUIRE_ENCODING (coding))
-    {
-      coding->consumed = SBYTES (str);
-      coding->consumed_char = SCHARS (str);
-      if (STRING_MULTIBYTE (str))
-       {
-         str = Fstring_as_unibyte (str);
-         nocopy = 1;
-       }
-      coding->produced = SBYTES (str);
-      coding->produced_char = SCHARS (str);
-      return (nocopy ? str : Fcopy_sequence (str));
-    }
-
-  if (coding->composing != COMPOSITION_DISABLED)
-    coding_save_composition (coding, from, to, str);
+  struct coding_system coding;
+  EMACS_INT chars, bytes;
 
-  /* Try to skip the heading and tailing ASCIIs.  */
-  if (coding->type != coding_type_ccl)
+  CHECK_STRING (string);
+  if (NILP (coding_system))
     {
-      SHRINK_CONVERSION_REGION (&from, &to_byte, coding, SDATA (str),
-                               1);
-      if (from == to_byte)
-       return (nocopy ? str : Fcopy_sequence (str));
-      shrinked_bytes = from + (SBYTES (str) - to_byte);
+      if (! norecord)
+       Vlast_coding_system_used = Qno_conversion;
+      if (NILP (dst_object))
+       return (nocopy ? Fcopy_sequence (string) : string);
     }
 
-  len = encoding_buffer_size (coding, to_byte - from);
-  allocate_conversion_buffer (buf, len);
+  if (NILP (coding_system))
+    coding_system = Qno_conversion;
+  else
+    CHECK_CODING_SYSTEM (coding_system);
+  if (NILP (dst_object))
+    dst_object = Qt;
+  else if (! EQ (dst_object, Qt))
+    CHECK_BUFFER (dst_object);
 
-  consumed = consumed_char = produced = produced_char = 0;
-  while (1)
-    {
-      result = encode_coding (coding, SDATA (str) + from + consumed,
-                             buf.data + produced, to_byte - from - consumed,
-                             buf.size - produced);
-      consumed += coding->consumed;
-      consumed_char += coding->consumed_char;
-      produced += coding->produced;
-      produced_char += coding->produced_char;
-      if (result == CODING_FINISH_NORMAL
-         || (result == CODING_FINISH_INSUFFICIENT_SRC
-             && coding->consumed == 0))
-       break;
-      /* Now result should be CODING_FINISH_INSUFFICIENT_DST.  */
-      extend_conversion_buffer (&buf);
-    }
+  setup_coding_system (coding_system, &coding);
+  coding.mode |= CODING_MODE_LAST_BLOCK;
+  chars = SCHARS (string);
+  bytes = SBYTES (string);
+  if (encodep)
+    encode_coding_object (&coding, string, 0, 0, chars, bytes, dst_object);
+  else
+    decode_coding_object (&coding, string, 0, 0, chars, bytes, dst_object);
+  if (! norecord)
+    Vlast_coding_system_used = CODING_ID_NAME (coding.id);
 
-  coding->consumed = consumed;
-  coding->consumed_char = consumed_char;
-  coding->produced = produced;
-  coding->produced_char = produced_char;
+  if (coding.result != CODING_RESULT_SUCCESS)
+    error ("Code conversion error: %d", coding.result);
 
-  newstr = make_uninit_string (produced + shrinked_bytes);
-  if (from > 0)
-    STRING_COPYIN (newstr, 0, SDATA (str), from);
-  STRING_COPYIN (newstr, from, buf.data, produced);
-  if (shrinked_bytes > from)
-    STRING_COPYIN (newstr, from + produced,
-                  SDATA (str) + to_byte,
-                  shrinked_bytes - from);
+  return (BUFFERP (dst_object)
+         ? make_number (coding.produced_char)
+         : coding.dst_object);
+}
 
-  free_conversion_buffer (&buf);
-  coding_free_composition_data (coding);
 
-  return newstr;
-}
+/* Encode or decode STRING according to CODING_SYSTEM.
+   Do not set Vlast_coding_system_used.
 
-\f
-#ifdef emacs
-/*** 8. Emacs Lisp library functions ***/
+   This function is called only from macros DECODE_FILE and
+   ENCODE_FILE, thus we ignore character composition.  */
 
-DEFUN ("coding-system-p", Fcoding_system_p, Scoding_system_p, 1, 1, 0,
-       doc: /* Return t if OBJECT is nil or a coding-system.
-See the documentation of `make-coding-system' for information
-about coding-system objects.  */)
-     (obj)
-     Lisp_Object obj;
+Lisp_Object
+code_convert_string_norecord (string, coding_system, encodep)
+     Lisp_Object string, coding_system;
+     int encodep;
 {
-  if (NILP (obj))
-    return Qt;
-  if (!SYMBOLP (obj))
-    return Qnil;
-  /* Get coding-spec vector for OBJ.  */
-  obj = Fget (obj, Qcoding_system);
-  return ((VECTORP (obj) && XVECTOR (obj)->size == 5)
-         ? Qt : Qnil);
+  return code_convert_string (string, coding_system, Qt, encodep, 0, 1);
 }
 
-DEFUN ("read-non-nil-coding-system", Fread_non_nil_coding_system,
-       Sread_non_nil_coding_system, 1, 1, 0,
-       doc: /* Read a coding system from the minibuffer, prompting with string PROMPT.  */)
-     (prompt)
-     Lisp_Object prompt;
-{
-  Lisp_Object val;
-  do
-    {
-      val = Fcompleting_read (prompt, Vcoding_system_alist, Qnil,
-                             Qt, Qnil, Qcoding_system_history, Qnil, Qnil);
-    }
-  while (SCHARS (val) == 0);
-  return (Fintern (val, Qnil));
-}
 
-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.  */)
-     (prompt, default_coding_system)
-     Lisp_Object prompt, default_coding_system;
+DEFUN ("decode-coding-string", Fdecode_coding_string, Sdecode_coding_string,
+       2, 4, 0,
+       doc: /* Decode STRING which is encoded in CODING-SYSTEM, and return the result.
+
+Optional third arg NOCOPY non-nil means it is OK to return STRING itself
+if the decoding operation is trivial.
+
+Optional fourth arg BUFFER non-nil meant that the decoded text is
+inserted in BUFFER instead of returned as a string.  In this case,
+the return value is BUFFER.
+
+This function sets `last-coding-system-used' to the precise coding system
+used (which may be different from CODING-SYSTEM if CODING-SYSTEM is
+not fully specified.  */)
+  (string, coding_system, nocopy, buffer)
+     Lisp_Object string, coding_system, nocopy, buffer;
 {
-  Lisp_Object val;
-  if (SYMBOLP (default_coding_system))
-    default_coding_system = SYMBOL_NAME (default_coding_system);
-  val = Fcompleting_read (prompt, Vcoding_system_alist, Qnil,
-                         Qt, Qnil, Qcoding_system_history,
-                         default_coding_system, Qnil);
-  return (SCHARS (val) == 0 ? Qnil : Fintern (val, Qnil));
+  return code_convert_string (string, coding_system, buffer,
+                             0, ! NILP (nocopy), 0);
 }
 
-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.
-It is valid if it is a symbol with a non-nil `coding-system' property.
-The value of property should be a vector of length 5.  */)
-     (coding_system)
-     Lisp_Object coding_system;
+DEFUN ("encode-coding-string", Fencode_coding_string, Sencode_coding_string,
+       2, 4, 0,
+       doc: /* Encode STRING to CODING-SYSTEM, and return the result.
+
+Optional third arg NOCOPY non-nil means it is OK to return STRING
+itself if the encoding operation is trivial.
+
+Optional fourth arg BUFFER non-nil meant that the encoded text is
+inserted in BUFFER instead of returned as a string.  In this case,
+the return value is BUFFER.
+
+This function sets `last-coding-system-used' to the precise coding system
+used (which may be different from CODING-SYSTEM if CODING-SYSTEM is
+not fully specified.)  */)
+     (string, coding_system, nocopy, buffer)
+     Lisp_Object string, coding_system, nocopy, buffer;
 {
-  CHECK_SYMBOL (coding_system);
-  if (!NILP (Fcoding_system_p (coding_system)))
-    return coding_system;
-  while (1)
-    Fsignal (Qcoding_system_error, Fcons (coding_system, Qnil));
+  return code_convert_string (string, coding_system, buffer,
+                             1, ! NILP (nocopy), 1);
 }
+
 \f
-Lisp_Object
-detect_coding_system (src, src_bytes, highest, multibytep)
-     const unsigned char *src;
-     int src_bytes, highest;
-     int multibytep;
+DEFUN ("decode-sjis-char", Fdecode_sjis_char, Sdecode_sjis_char, 1, 1, 0,
+       doc: /* Decode a Japanese character which has CODE in shift_jis encoding.
+Return the corresponding character.  */)
+     (code)
+     Lisp_Object code;
 {
-  int coding_mask, eol_type;
-  Lisp_Object val, tmp;
-  int dummy;
+  Lisp_Object spec, attrs, val;
+  struct charset *charset_roman, *charset_kanji, *charset_kana, *charset;
+  int c;
 
-  coding_mask = detect_coding_mask (src, src_bytes, NULL, &dummy, multibytep);
-  eol_type  = detect_eol_type (src, src_bytes, &dummy);
-  if (eol_type == CODING_EOL_INCONSISTENT)
-    eol_type = CODING_EOL_UNDECIDED;
+  CHECK_NATNUM (code);
+  c = XFASTINT (code);
+  CHECK_CODING_SYSTEM_GET_SPEC (Vsjis_coding_system, spec);
+  attrs = AREF (spec, 0);
 
-  if (!coding_mask)
-    {
-      val = Qundecided;
-      if (eol_type != CODING_EOL_UNDECIDED)
-       {
-         Lisp_Object val2;
-         val2 = Fget (Qundecided, Qeol_type);
-         if (VECTORP (val2))
-           val = XVECTOR (val2)->contents[eol_type];
-       }
-      return (highest ? val : Fcons (val, Qnil));
-    }
+  if (ASCII_BYTE_P (c)
+      && ! NILP (CODING_ATTR_ASCII_COMPAT (attrs)))
+    return code;
 
-  /* At first, gather possible coding systems in VAL.  */
-  val = Qnil;
-  for (tmp = Vcoding_category_list; CONSP (tmp); tmp = XCDR (tmp))
-    {
-      Lisp_Object category_val, category_index;
+  val = CODING_ATTR_CHARSET_LIST (attrs);
+  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)));
 
-      category_index = Fget (XCAR (tmp), Qcoding_category_index);
-      category_val = Fsymbol_value (XCAR (tmp));
-      if (!NILP (category_val)
-         && NATNUMP (category_index)
-         && (coding_mask & (1 << XFASTINT (category_index))))
-       {
-         val = Fcons (category_val, val);
-         if (highest)
-           break;
-       }
+  if (c <= 0x7F)
+    charset = charset_roman;
+  else if (c >= 0xA0 && c < 0xDF)
+    {
+      charset = charset_kana;
+      c -= 0x80;
     }
-  if (!highest)
-    val = Fnreverse (val);
-
-  /* Then, replace the elements with subsidiary coding systems.  */
-  for (tmp = val; CONSP (tmp); tmp = XCDR (tmp))
+  else
     {
-      if (eol_type != CODING_EOL_UNDECIDED
-         && eol_type != CODING_EOL_INCONSISTENT)
-       {
-         Lisp_Object eol;
-         eol = Fget (XCAR (tmp), Qeol_type);
-         if (VECTORP (eol))
-           XSETCAR (tmp, XVECTOR (eol)->contents[eol_type]);
-       }
+      int s1 = c >> 8, s2 = c & 0xFF;
+
+      if (s1 < 0x81 || (s1 > 0x9F && s1 < 0xE0) || s1 > 0xEF
+         || s2 < 0x40 || s2 == 0x7F || s2 > 0xFC)
+       error ("Invalid code: %d", code);
+      SJIS_TO_JIS (c);
+      charset = charset_kanji;
     }
-  return (highest ? XCAR (val) : val);
+  c = DECODE_CHAR (charset, c);
+  if (c < 0)
+    error ("Invalid code: %d", code);
+  return make_number (c);
 }
 
-DEFUN ("detect-coding-region", Fdetect_coding_region, Sdetect_coding_region,
-       2, 3, 0,
-       doc: /* Detect how the byte sequence in the region is encoded.
-Return a list of possible coding systems used on decoding a byte
-sequence containing the bytes in the region between START and END when
-the coding system `undecided' is specified.  The list is ordered by
-priority decided in the current language environment.
 
-If only ASCII characters are found, it returns a list of single element
-`undecided' or its subsidiary coding system according to a detected
-end-of-line format.
+DEFUN ("encode-sjis-char", Fencode_sjis_char, Sencode_sjis_char, 1, 1, 0,
+       doc: /* Encode a Japanese character CHAR to shift_jis encoding.
+Return the corresponding code in SJIS.  */)
+     (ch)
+    Lisp_Object ch;
+{
+  Lisp_Object spec, attrs, charset_list;
+  int c;
+  struct charset *charset;
+  unsigned code;
 
-If optional argument HIGHEST is non-nil, return the coding system of
-highest priority.  */)
-     (start, end, highest)
-     Lisp_Object start, end, highest;
+  CHECK_CHARACTER (ch);
+  c = XFASTINT (ch);
+  CHECK_CODING_SYSTEM_GET_SPEC (Vsjis_coding_system, spec);
+  attrs = AREF (spec, 0);
+
+  if (ASCII_CHAR_P (c)
+      && ! NILP (CODING_ATTR_ASCII_COMPAT (attrs)))
+    return ch;
+
+  charset_list = CODING_ATTR_CHARSET_LIST (attrs);
+  charset = char_charset (c, charset_list, &code);
+  if (code == CHARSET_INVALID_CODE (charset))
+    error ("Can't encode by shift_jis encoding: %d", c);
+  JIS_TO_SJIS (code);
+
+  return make_number (code);
+}
+
+DEFUN ("decode-big5-char", Fdecode_big5_char, Sdecode_big5_char, 1, 1, 0,
+       doc: /* Decode a Big5 character which has CODE in BIG5 coding system.
+Return the corresponding character.  */)
+     (code)
+     Lisp_Object code;
 {
-  int from, to;
-  int from_byte, to_byte;
-  int include_anchor_byte = 0;
+  Lisp_Object spec, attrs, val;
+  struct charset *charset_roman, *charset_big5, *charset;
+  int c;
 
-  CHECK_NUMBER_COERCE_MARKER (start);
-  CHECK_NUMBER_COERCE_MARKER (end);
+  CHECK_NATNUM (code);
+  c = XFASTINT (code);
+  CHECK_CODING_SYSTEM_GET_SPEC (Vbig5_coding_system, spec);
+  attrs = AREF (spec, 0);
 
-  validate_region (&start, &end);
-  from = XINT (start), to = XINT (end);
-  from_byte = CHAR_TO_BYTE (from);
-  to_byte = CHAR_TO_BYTE (to);
+  if (ASCII_BYTE_P (c)
+      && ! NILP (CODING_ATTR_ASCII_COMPAT (attrs)))
+    return code;
 
-  if (from < GPT && to >= GPT)
-    move_gap_both (to, to_byte);
-  /* If we an anchor byte `\0' follows the region, we include it in
-     the detecting source.  Then code detectors can handle the tailing
-     byte sequence more accurately.
+  val = CODING_ATTR_CHARSET_LIST (attrs);
+  charset_roman = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
+  charset_big5 = CHARSET_FROM_ID (XINT (XCAR (val)));
 
-     Fix me: This is not a perfect solution.  It is better that we
-     add one more argument, say LAST_BLOCK, to all detect_coding_XXX.
-  */
-  if (to == Z || (to == GPT && GAP_SIZE > 0))
-    include_anchor_byte = 1;
-  return detect_coding_system (BYTE_POS_ADDR (from_byte),
-                              to_byte - from_byte + include_anchor_byte,
-                              !NILP (highest),
-                              !NILP (current_buffer
-                                     ->enable_multibyte_characters));
+  if (c <= 0x7F)
+    charset = charset_roman;
+  else
+    {
+      int b1 = c >> 8, b2 = c & 0x7F;
+      if (b1 < 0xA1 || b1 > 0xFE
+         || b2 < 0x40 || (b2 > 0x7E && b2 < 0xA1) || b2 > 0xFE)
+       error ("Invalid code: %d", code);
+      charset = charset_big5;
+    }
+  c = DECODE_CHAR (charset, (unsigned )c);
+  if (c < 0)
+    error ("Invalid code: %d", code);
+  return make_number (c);
 }
 
-DEFUN ("detect-coding-string", Fdetect_coding_string, Sdetect_coding_string,
-       1, 2, 0,
-       doc: /* Detect how the byte sequence in STRING is encoded.
-Return a list of possible coding systems used on decoding a byte
-sequence containing the bytes in STRING when the coding system
-`undecided' is specified.  The list is ordered by priority decided in
-the current language environment.
+DEFUN ("encode-big5-char", Fencode_big5_char, Sencode_big5_char, 1, 1, 0,
+       doc: /* Encode the Big5 character CHAR to BIG5 coding system.
+Return the corresponding character code in Big5.  */)
+     (ch)
+     Lisp_Object ch;
+{
+  Lisp_Object spec, attrs, charset_list;
+  struct charset *charset;
+  int c;
+  unsigned code;
+
+  CHECK_CHARACTER (ch);
+  c = XFASTINT (ch);
+  CHECK_CODING_SYSTEM_GET_SPEC (Vbig5_coding_system, spec);
+  attrs = AREF (spec, 0);
+  if (ASCII_CHAR_P (c)
+      && ! NILP (CODING_ATTR_ASCII_COMPAT (attrs)))
+    return ch;
+
+  charset_list = CODING_ATTR_CHARSET_LIST (attrs);
+  charset = char_charset (c, charset_list, &code);
+  if (code == CHARSET_INVALID_CODE (charset))
+    error ("Can't encode by Big5 encoding: %d", c);
+
+  return make_number (code);
+}
 
-If only ASCII characters are found, it returns a list of single element
-`undecided' or its subsidiary coding system according to a detected
-end-of-line format.
+\f
+DEFUN ("set-terminal-coding-system-internal",
+       Fset_terminal_coding_system_internal,
+       Sset_terminal_coding_system_internal, 1, 1, 0,
+       doc: /* Internal use only.  */)
+     (coding_system)
+     Lisp_Object coding_system;
+{
+  CHECK_SYMBOL (coding_system);
+  setup_coding_system (Fcheck_coding_system (coding_system),
+                       &terminal_coding);
 
-If optional argument HIGHEST is non-nil, return the coding system of
-highest priority.  */)
-     (string, highest)
-     Lisp_Object string, highest;
+  /* We had better not send unsafe characters to terminal.  */
+  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;
+  return Qnil;
+}
+
+DEFUN ("set-safe-terminal-coding-system-internal",
+       Fset_safe_terminal_coding_system_internal,
+       Sset_safe_terminal_coding_system_internal, 1, 1, 0,
+       doc: /* Internal use only.  */)
+     (coding_system)
+     Lisp_Object coding_system;
 {
-  CHECK_STRING (string);
+  CHECK_SYMBOL (coding_system);
+  setup_coding_system (Fcheck_coding_system (coding_system),
+                      &safe_terminal_coding);
+  /* Characer composition should be disabled.  */
+  safe_terminal_coding.common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK;
+  safe_terminal_coding.src_multibyte = 1;
+  safe_terminal_coding.dst_multibyte = 0;
+  return Qnil;
+}
 
-  return detect_coding_system (SDATA (string),
-                              /* "+ 1" is to include the anchor byte
-                                 `\0'.  With this, code detectors can
-                                 handle the tailing bytes more
-                                 accurately.  */
-                              SBYTES (string) + 1,
-                              !NILP (highest),
-                              STRING_MULTIBYTE (string));
+DEFUN ("terminal-coding-system",
+       Fterminal_coding_system, Sterminal_coding_system, 0, 0, 0,
+       doc: /* Return coding system specified for terminal output.  */)
+     ()
+{
+  return CODING_ID_NAME (terminal_coding.id);
+}
+
+DEFUN ("set-keyboard-coding-system-internal",
+       Fset_keyboard_coding_system_internal,
+       Sset_keyboard_coding_system_internal, 1, 1, 0,
+       doc: /* Internal use only.  */)
+     (coding_system)
+     Lisp_Object coding_system;
+{
+  CHECK_SYMBOL (coding_system);
+  setup_coding_system (Fcheck_coding_system (coding_system),
+                      &keyboard_coding);
+  /* Characer composition should be disabled.  */
+  keyboard_coding.common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK;
+  return Qnil;
+}
+
+DEFUN ("keyboard-coding-system",
+       Fkeyboard_coding_system, Skeyboard_coding_system, 0, 0, 0,
+       doc: /* Return coding system specified for decoding keyboard input.  */)
+     ()
+{
+  return CODING_ID_NAME (keyboard_coding.id);
 }
 
-/*  Subroutine for Fsafe_coding_systems_region_internal.
+\f
+DEFUN ("find-operation-coding-system", Ffind_operation_coding_system,
+       Sfind_operation_coding_system,  1, MANY, 0,
+       doc: /* Choose a coding system for an operation based on the target name.
+The value names a pair of coding systems: (DECODING-SYSTEM . ENCODING-SYSTEM).
+DECODING-SYSTEM is the coding system to use for decoding
+\(in case OPERATION does decoding), and ENCODING-SYSTEM is the coding system
+for encoding (in case OPERATION does encoding).
 
-    Return a list of coding systems that safely encode the multibyte
-    text between P and PEND.  SAFE_CODINGS, if non-nil, is an alist of
-    possible coding systems.  If it is nil, it means that we have not
-    yet found any coding systems.
+The first argument OPERATION specifies an I/O primitive:
+  For file I/O, `insert-file-contents' or `write-region'.
+  For process I/O, `call-process', `call-process-region', or `start-process'.
+  For network I/O, `open-network-stream'.
 
-    WORK_TABLE is a copy of the char-table Vchar_coding_system_table.  An
-    element of WORK_TABLE is set to t once the element is looked up.
+The remaining arguments should be the same arguments that were passed
+to the primitive.  Depending on which primitive, one of those arguments
+is selected as the TARGET.  For example, if OPERATION does file I/O,
+whichever argument specifies the file name is TARGET.
 
-    If a non-ASCII single byte char is found, set
-    *single_byte_char_found to 1.  */
+TARGET has a meaning which depends on OPERATION:
+  For file I/O, TARGET is a file name.
+  For process I/O, TARGET is a process name.
+  For network I/O, TARGET is a service name or a port number
 
-static Lisp_Object
-find_safe_codings (p, pend, safe_codings, work_table, single_byte_char_found)
-     unsigned char *p, *pend;
-     Lisp_Object safe_codings, work_table;
-     int *single_byte_char_found;
+This function looks up what specified for TARGET in,
+`file-coding-system-alist', `process-coding-system-alist',
+or `network-coding-system-alist' depending on OPERATION.
+They may specify a coding system, a cons of coding systems,
+or a function symbol to call.
+In the last case, we call the function with one argument,
+which is a list of all the arguments given to this function.
+
+usage: (find-operation-coding-system OPERATION ARGUMENTS ...)  */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
 {
-  int c, len;
-  Lisp_Object val, ch;
-  Lisp_Object prev, tail;
+  Lisp_Object operation, target_idx, target, val;
+  register Lisp_Object chain;
 
-  while (p < pend)
+  if (nargs < 2)
+    error ("Too few arguments");
+  operation = args[0];
+  if (!SYMBOLP (operation)
+      || !INTEGERP (target_idx = Fget (operation, Qtarget_idx)))
+    error ("Invalid first arguement");
+  if (nargs < 1 + XINT (target_idx))
+    error ("Too few arguments for operation: %s",
+          SDATA (SYMBOL_NAME (operation)));
+  target = args[XINT (target_idx) + 1];
+  if (!(STRINGP (target)
+       || (EQ (operation, Qopen_network_stream) && INTEGERP (target))))
+    error ("Invalid %dth argument", XINT (target_idx) + 1);
+
+  chain = ((EQ (operation, Qinsert_file_contents)
+           || EQ (operation, Qwrite_region))
+          ? Vfile_coding_system_alist
+          : (EQ (operation, Qopen_network_stream)
+             ? Vnetwork_coding_system_alist
+             : Vprocess_coding_system_alist));
+  if (NILP (chain))
+    return Qnil;
+
+  for (; CONSP (chain); chain = XCDR (chain))
     {
-      c = STRING_CHAR_AND_LENGTH (p, pend - p, len);
-      p += len;
-      if (ASCII_BYTE_P (c))
-       /* We can ignore ASCII characters here.  */
-       continue;
-      if (SINGLE_BYTE_CHAR_P (c))
-       *single_byte_char_found = 1;
-      if (NILP (safe_codings))
-       /* Already all coding systems are excluded.  But, we can't
-          terminate the loop here because non-ASCII single-byte char
-          must be found.  */
-       continue;
-      /* Check the safe coding systems for C.  */
-      ch = make_number (c);
-      val = Faref (work_table, ch);
-      if (EQ (val, Qt))
-       /* This element was already checked.  Ignore it.  */
-       continue;
-      /* Remember that we checked this element.  */
-      Faset (work_table, ch, Qt);
+      Lisp_Object elt;
 
-      for (prev = tail = safe_codings; CONSP (tail); tail = XCDR (tail))
+      elt = XCAR (chain);
+      if (CONSP (elt)
+         && ((STRINGP (target)
+              && STRINGP (XCAR (elt))
+              && fast_string_match (XCAR (elt), target) >= 0)
+             || (INTEGERP (target) && EQ (target, XCAR (elt)))))
        {
-         Lisp_Object elt, translation_table, hash_table, accept_latin_extra;
-         int encodable;
-
-         elt = XCAR (tail);
-         if (CONSP (XCDR (elt)))
-           {
-             /* This entry has this format now:
-                ( CODING SAFE-CHARS TRANSLATION-TABLE HASH-TABLE
-                         ACCEPT-LATIN-EXTRA ) */
-             val = XCDR (elt);
-             encodable = ! NILP (Faref (XCAR (val), ch));
-             if (! encodable)
-               {
-                 val = XCDR (val);
-                 translation_table = XCAR (val);
-                 hash_table = XCAR (XCDR (val));
-                 accept_latin_extra = XCAR (XCDR (XCDR (val)));
-               }
-           }
-         else
-           {
-             /* This entry has this format now: ( CODING . SAFE-CHARS) */
-             encodable = ! NILP (Faref (XCDR (elt), ch));
-             if (! encodable)
-               {
-                 /* Transform the format to:
-                    ( CODING SAFE-CHARS TRANSLATION-TABLE HASH-TABLE
-                      ACCEPT-LATIN-EXTRA )  */
-                 val = Fget (XCAR (elt), Qcoding_system);
-                 translation_table
-                   = Fplist_get (AREF (val, 3),
-                                 Qtranslation_table_for_encode);
-                 if (SYMBOLP (translation_table))
-                   translation_table = Fget (translation_table,
-                                             Qtranslation_table);
-                 hash_table
-                   = (CHAR_TABLE_P (translation_table)
-                      ? XCHAR_TABLE (translation_table)->extras[1]
-                      : Qnil);
-                 accept_latin_extra
-                   = ((EQ (AREF (val, 0), make_number (2))
-                       && VECTORP (AREF (val, 4)))
-                      ? AREF (AREF (val, 4), 16)
-                      : Qnil);
-                 XSETCAR (tail, list5 (XCAR (elt), XCDR (elt),
-                                       translation_table, hash_table,
-                                       accept_latin_extra));
-               }
-           }
-             
-         if (! encodable
-             && ((CHAR_TABLE_P (translation_table)
-                  && ! NILP (Faref (translation_table, ch)))
-                 || (HASH_TABLE_P (hash_table)
-                     && ! NILP (Fgethash (ch, hash_table, Qnil)))
-                 || (SINGLE_BYTE_CHAR_P (c)
-                     && ! NILP (accept_latin_extra)
-                     && VECTORP (Vlatin_extra_code_table)
-                     && ! NILP (AREF (Vlatin_extra_code_table, c)))))
-           encodable = 1;
-         if (encodable)
-           prev = tail;
-         else
+         val = XCDR (elt);
+         /* Here, if VAL is both a valid coding system and a valid
+             function symbol, we return VAL as a coding system.  */
+         if (CONSP (val))
+           return val;
+         if (! SYMBOLP (val))
+           return Qnil;
+         if (! NILP (Fcoding_system_p (val)))
+           return Fcons (val, val);
+         if (! NILP (Ffboundp (val)))
            {
-             /* Exclude this coding system from SAFE_CODINGS.  */
-             if (EQ (tail, safe_codings))
-               safe_codings = XCDR (safe_codings);
-             else
-               XSETCDR (prev, XCDR (tail));
+             val = call1 (val, Flist (nargs, args));
+             if (CONSP (val))
+               return val;
+             if (SYMBOLP (val) && ! NILP (Fcoding_system_p (val)))
+               return Fcons (val, val);
            }
+         return Qnil;
        }
     }
-  return safe_codings;
+  return Qnil;
 }
 
-DEFUN ("find-coding-systems-region-internal",
-       Ffind_coding_systems_region_internal,
-       Sfind_coding_systems_region_internal, 2, 2, 0,
-       doc: /* Internal use only.  */)
-     (start, end)
-     Lisp_Object start, end;
-{
-  Lisp_Object work_table, safe_codings;
-  int non_ascii_p = 0;
-  int single_byte_char_found = 0;
-  const unsigned char *p1, *p1end, *p2, *p2end, *p;
-
-  if (STRINGP (start))
-    {
-      if (!STRING_MULTIBYTE (start))
-       return Qt;
-      p1 = SDATA (start), p1end = p1 + SBYTES (start);
-      p2 = p2end = p1end;
-      if (SCHARS (start) != SBYTES (start))
-       non_ascii_p = 1;
-    }
-  else
-    {
-      int from, to, stop;
-
-      CHECK_NUMBER_COERCE_MARKER (start);
-      CHECK_NUMBER_COERCE_MARKER (end);
-      if (XINT (start) < BEG || XINT (end) > Z || XINT (start) > XINT (end))
-       args_out_of_range (start, end);
-      if (NILP (current_buffer->enable_multibyte_characters))
-       return Qt;
-      from = CHAR_TO_BYTE (XINT (start));
-      to = CHAR_TO_BYTE (XINT (end));
-      stop = from < GPT_BYTE && GPT_BYTE < to ? GPT_BYTE : to;
-      p1 = BYTE_POS_ADDR (from), p1end = p1 + (stop - from);
-      if (stop == to)
-       p2 = p2end = p1end;
-      else
-       p2 = BYTE_POS_ADDR (stop), p2end = p2 + (to - stop);
-      if (XINT (end) - XINT (start) != to - from)
-       non_ascii_p = 1;
-    }
+DEFUN ("set-coding-system-priority", Fset_coding_system_priority,
+       Sset_coding_system_priority, 0, MANY, 0,
+       doc: /* Assign higher priority to the coding systems given as arguments.
+If multiple coding systems belongs to the same category,
+all but the first one are ignored.  */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  int i, j;
+  int changed[coding_category_max];
+  enum coding_category priorities[coding_category_max];
+
+  bzero (changed, sizeof changed);
 
-  if (!non_ascii_p)
+  for (i = j = 0; i < nargs; i++)
     {
-      /* We are sure that the text contains no multibyte character.
-        Check if it contains eight-bit-graphic.  */
-      p = p1;
-      for (p = p1; p < p1end && ASCII_BYTE_P (*p); p++);
-      if (p == p1end)
-       {
-         for (p = p2; p < p2end && ASCII_BYTE_P (*p); p++);
-         if (p == p2end)
-           return Qt;
-       }
-    }
+      enum coding_category category;
+      Lisp_Object spec, attrs;
 
-  /* The text contains non-ASCII characters.  */
+      CHECK_CODING_SYSTEM_GET_SPEC (args[i], spec);
+      attrs = AREF (spec, 0);
+      category = XINT (CODING_ATTR_CATEGORY (attrs));
+      if (changed[category])
+       /* Ignore this coding system because a coding system of the
+          same category already had a higher priority.  */
+       continue;
+      changed[category] = 1;
+      priorities[j++] = category;
+      if (coding_categories[category].id >= 0
+         && ! EQ (args[i], CODING_ID_NAME (coding_categories[category].id)))
+       setup_coding_system (args[i], &coding_categories[category]);
+      Fset (AREF (Vcoding_category_table, category), args[i]);
+    }
 
-  work_table = Fmake_char_table (Qchar_coding_system, Qnil);
-  safe_codings = Fcopy_sequence (XCDR (Vcoding_system_safe_chars));
+  /* Now we have decided top J priorities.  Reflect the order of the
+     original priorities to the remaining priorities.  */
 
-  safe_codings = find_safe_codings (p1, p1end, safe_codings, work_table,
-                                   &single_byte_char_found);
-  if (p2 < p2end)
-    safe_codings = find_safe_codings (p2, p2end, safe_codings, work_table,
-                                     &single_byte_char_found);
-  if (EQ (safe_codings, XCDR (Vcoding_system_safe_chars)))
-    safe_codings = Qt;
-  else
+  for (i = j, j = 0; i < coding_category_max; i++, j++)
     {
-      /* Turn safe_codings to a list of coding systems... */
-      Lisp_Object val;
+      while (j < coding_category_max
+            && changed[coding_priorities[j]])
+       j++;
+      if (j == coding_category_max)
+       abort ();
+      priorities[i] = coding_priorities[j];
+    }
 
-      if (single_byte_char_found)
-       /* ... and append these for eight-bit chars.  */
-       val = Fcons (Qraw_text,
-                    Fcons (Qemacs_mule, Fcons (Qno_conversion, Qnil)));
-      else
-       /* ... and append generic coding systems.  */
-       val = Fcopy_sequence (XCAR (Vcoding_system_safe_chars));
+  bcopy (priorities, coding_priorities, sizeof priorities);
 
-      for (; CONSP (safe_codings); safe_codings = XCDR (safe_codings))
-       val = Fcons (XCAR (XCAR (safe_codings)), val);
-      safe_codings = val;
-    }
+  /* Update `coding-category-list'.  */
+  Vcoding_category_list = Qnil;
+  for (i = coding_category_max - 1; i >= 0; i--)
+    Vcoding_category_list
+      = Fcons (AREF (Vcoding_category_table, priorities[i]),
+              Vcoding_category_list);
 
-  return safe_codings;
+  return Qnil;
 }
 
+DEFUN ("coding-system-priority-list", Fcoding_system_priority_list,
+       Scoding_system_priority_list, 0, 1, 0,
+       doc: /* Return a list of coding systems ordered by their priorities.
+HIGHESTP non-nil means just return the highest priority one.  */)
+     (highestp)
+     Lisp_Object highestp;
+{
+  int i;
+  Lisp_Object val;
 
-/* Search from position POS for such characters that are unencodable
-   accoding to SAFE_CHARS, and return a list of their positions.  P
-   points where in the memory the character at POS exists.  Limit the
-   search at PEND or when Nth unencodable characters are found.
-
-   If SAFE_CHARS is a char table, an element for an unencodable
-   character is nil.
+  for (i = 0, val = Qnil; i < coding_category_max; i++)
+    {
+      enum coding_category category = coding_priorities[i];
+      int id = coding_categories[category].id;
+      Lisp_Object attrs;
 
-   If SAFE_CHARS is nil, all non-ASCII characters are unencodable.
+      if (id < 0)
+       continue;
+      attrs = CODING_ID_ATTRS (id);
+      if (! NILP (highestp))
+       return CODING_ATTR_BASE_NAME (attrs);
+      val = Fcons (CODING_ATTR_BASE_NAME (attrs), val);
+    }
+  return Fnreverse (val);
+}
 
-   Otherwise, SAFE_CHARS is t, and only eight-bit-contrl and
-   eight-bit-graphic characters are unencodable.  */
+static char *suffixes[] = { "-unix", "-dos", "-mac" };
 
 static Lisp_Object
-unencodable_char_position (safe_chars, pos, p, pend, n)
-     Lisp_Object safe_chars;
-     int pos;
-     unsigned char *p, *pend;
-     int n;
+make_subsidiaries (base)
+     Lisp_Object base;
 {
-  Lisp_Object pos_list;
+  Lisp_Object subsidiaries;
+  int base_name_len = SBYTES (SYMBOL_NAME (base));
+  char *buf = (char *) alloca (base_name_len + 6);
+  int i;
 
-  pos_list = Qnil;
-  while (p < pend)
+  bcopy (SDATA (SYMBOL_NAME (base)), buf, base_name_len);
+  subsidiaries = Fmake_vector (make_number (3), Qnil);
+  for (i = 0; i < 3; i++)
     {
-      int len;
-      int c = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, len);
-
-      if (c >= 128
-         && (CHAR_TABLE_P (safe_chars)
-             ? NILP (CHAR_TABLE_REF (safe_chars, c))
-             : (NILP (safe_chars) || c < 256)))
-       {
-         pos_list = Fcons (make_number (pos), pos_list);
-         if (--n <= 0)
-           break;
-       }
-      pos++;
-      p += len;
+      bcopy (suffixes[i], buf + base_name_len, strlen (suffixes[i]) + 1);
+      ASET (subsidiaries, i, intern (buf));
     }
-  return Fnreverse (pos_list);
+  return subsidiaries;
 }
 
 
-DEFUN ("unencodable-char-position", Funencodable_char_position,
-       Sunencodable_char_position, 3, 5, 0,
-       doc: /*
-Return position of first un-encodable character in a region.
-START and END specfiy the region and CODING-SYSTEM specifies the
-encoding to check.  Return nil if CODING-SYSTEM does encode the region.
-
-If optional 4th argument COUNT is non-nil, it specifies at most how
-many un-encodable characters to search.  In this case, the value is a
-list of positions.
-
-If optional 5th argument STRING is non-nil, it is a string to search
-for un-encodable characters.  In that case, START and END are indexes
-to the string.  */)
-     (start, end, coding_system, count, string)
-     Lisp_Object start, end, coding_system, count, string;
+DEFUN ("define-coding-system-internal", Fdefine_coding_system_internal,
+       Sdefine_coding_system_internal, coding_arg_max, MANY, 0,
+       doc: /* For internal use only.
+usage: (define-coding-system-internal ...)  */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
 {
-  int n;
-  Lisp_Object safe_chars;
-  struct coding_system coding;
-  Lisp_Object positions;
-  int from, to;
-  unsigned char *p, *pend;
+  Lisp_Object name;
+  Lisp_Object spec_vec;                /* [ ATTRS ALIASE EOL_TYPE ] */
+  Lisp_Object attrs;           /* Vector of attributes.  */
+  Lisp_Object eol_type;
+  Lisp_Object aliases;
+  Lisp_Object coding_type, charset_list, safe_charsets;
+  enum coding_category category;
+  Lisp_Object tail, val;
+  int max_charset_id = 0;
+  int i;
 
-  if (NILP (string))
-    {
-      validate_region (&start, &end);
-      from = XINT (start);
-      to = XINT (end);
-      if (NILP (current_buffer->enable_multibyte_characters))
-       return Qnil;
-      p = CHAR_POS_ADDR (from);
-      if (to == GPT)
-       pend = GPT_ADDR;
-      else
-       pend = CHAR_POS_ADDR (to);
-    }
-  else
-    {
-      CHECK_STRING (string);
-      CHECK_NATNUM (start);
-      CHECK_NATNUM (end);
-      from = XINT (start);
-      to = XINT (end);
-      if (from > to
-         || to > SCHARS (string))
-       args_out_of_range_3 (string, start, end);
-      if (! STRING_MULTIBYTE (string))
-       return Qnil;
-      p = SDATA (string) + string_char_to_byte (string, from);
-      pend = SDATA (string) + string_char_to_byte (string, to);
-    }
+  if (nargs < coding_arg_max)
+    goto short_args;
 
-  setup_coding_system (Fcheck_coding_system (coding_system), &coding);
+  attrs = Fmake_vector (make_number (coding_attr_last_index), Qnil);
 
-  if (NILP (count))
-    n = 1;
-  else
-    {
-      CHECK_NATNUM (count);
-      n = XINT (count);
-    }
+  name = args[coding_arg_name];
+  CHECK_SYMBOL (name);
+  CODING_ATTR_BASE_NAME (attrs) = name;
 
-  if (coding.type == coding_type_no_conversion
-      || coding.type == coding_type_raw_text)
-    return Qnil;
+  val = args[coding_arg_mnemonic];
+  if (! STRINGP (val))
+    CHECK_CHARACTER (val);
+  CODING_ATTR_MNEMONIC (attrs) = val;
 
-  if (coding.type == coding_type_undecided)
-    safe_chars = Qnil;
-  else
-    safe_chars = coding_safe_chars (coding_system);
+  coding_type = args[coding_arg_coding_type];
+  CHECK_SYMBOL (coding_type);
+  CODING_ATTR_TYPE (attrs) = coding_type;
 
-  if (STRINGP (string)
-      || from >= GPT || to <= GPT)
-    positions = unencodable_char_position (safe_chars, from, p, pend, n);
+  charset_list = args[coding_arg_charset_list];
+  if (SYMBOLP (charset_list))
+    {
+      if (EQ (charset_list, Qiso_2022))
+       {
+         if (! EQ (coding_type, Qiso_2022))
+           error ("Invalid charset-list");
+         charset_list = Viso_2022_charset_list;
+       }
+      else if (EQ (charset_list, Qemacs_mule))
+       {
+         if (! EQ (coding_type, Qemacs_mule))
+           error ("Invalid charset-list");
+         charset_list = Vemacs_mule_charset_list;
+       }
+      for (tail = charset_list; CONSP (tail); tail = XCDR (tail))
+       if (max_charset_id < XFASTINT (XCAR (tail)))
+         max_charset_id = XFASTINT (XCAR (tail));
+    }
   else
     {
-      Lisp_Object args[2];
-
-      args[0] = unencodable_char_position (safe_chars, from, p, GPT_ADDR, n);
-      n -= XINT (Flength (args[0]));
-      if (n <= 0)
-       positions = args[0];
-      else
+      charset_list = Fcopy_sequence (charset_list);
+      for (tail = charset_list; !NILP (tail); tail = Fcdr (tail))
        {
-         args[1] = unencodable_char_position (safe_chars, GPT, GAP_END_ADDR,
-                                              pend, n);
-         positions = Fappend (2, args);
+         struct charset *charset;
+
+         val = Fcar (tail);
+         CHECK_CHARSET_GET_CHARSET (val, charset);
+         if (EQ (coding_type, Qiso_2022)
+             ? CHARSET_ISO_FINAL (charset) < 0
+             : EQ (coding_type, Qemacs_mule)
+             ? CHARSET_EMACS_MULE_ID (charset) < 0
+             : 0)
+           error ("Can't handle charset `%s'",
+                  SDATA (SYMBOL_NAME (CHARSET_NAME (charset))));
+
+         XSETCAR (tail, make_number (charset->id));
+         if (max_charset_id < charset->id)
+           max_charset_id = charset->id;
        }
     }
+  CODING_ATTR_CHARSET_LIST (attrs) = charset_list;
 
-  return  (NILP (count) ? Fcar (positions) : positions);
-}
-
+  safe_charsets = Fmake_string (make_number (max_charset_id + 1),
+                               make_number (255));
+  for (tail = charset_list; CONSP (tail); tail = XCDR (tail))
+    SSET (safe_charsets, XFASTINT (XCAR (tail)), 0);
+  CODING_ATTR_SAFE_CHARSETS (attrs) = safe_charsets;
 
-Lisp_Object
-code_convert_region1 (start, end, coding_system, encodep)
-     Lisp_Object start, end, coding_system;
-     int encodep;
-{
-  struct coding_system coding;
-  int from, to;
+  CODING_ATTR_ASCII_COMPAT (attrs) = args[coding_arg_ascii_compatible_p];
 
-  CHECK_NUMBER_COERCE_MARKER (start);
-  CHECK_NUMBER_COERCE_MARKER (end);
-  CHECK_SYMBOL (coding_system);
+  val = args[coding_arg_decode_translation_table];
+  if (! NILP (val))
+    CHECK_CHAR_TABLE (val);
+  CODING_ATTR_DECODE_TBL (attrs) = val;
 
-  validate_region (&start, &end);
-  from = XFASTINT (start);
-  to = XFASTINT (end);
+  val = args[coding_arg_encode_translation_table];
+  if (! NILP (val))
+    CHECK_CHAR_TABLE (val);
+  CODING_ATTR_ENCODE_TBL (attrs) = val;
 
-  if (NILP (coding_system))
-    return make_number (to - from);
+  val = args[coding_arg_post_read_conversion];
+  CHECK_SYMBOL (val);
+  CODING_ATTR_POST_READ (attrs) = val;
 
-  if (setup_coding_system (Fcheck_coding_system (coding_system), &coding) < 0)
-    error ("Invalid coding system: %s", SDATA (SYMBOL_NAME (coding_system)));
+  val = args[coding_arg_pre_write_conversion];
+  CHECK_SYMBOL (val);
+  CODING_ATTR_PRE_WRITE (attrs) = val;
 
-  coding.mode |= CODING_MODE_LAST_BLOCK;
-  coding.src_multibyte = coding.dst_multibyte
-    = !NILP (current_buffer->enable_multibyte_characters);
-  code_convert_region (from, CHAR_TO_BYTE (from), to, CHAR_TO_BYTE (to),
-                      &coding, encodep, 1);
-  Vlast_coding_system_used = coding.symbol;
-  return make_number (coding.produced_char);
-}
+  val = args[coding_arg_default_char];
+  if (NILP (val))
+    CODING_ATTR_DEFAULT_CHAR (attrs) = make_number (' ');
+  else
+    {
+      CHECK_CHARACTER (val);
+      CODING_ATTR_DEFAULT_CHAR (attrs) = val;
+    }
 
-DEFUN ("decode-coding-region", Fdecode_coding_region, Sdecode_coding_region,
-       3, 3, "r\nzCoding system: ",
-       doc: /* Decode the current region from the specified coding system.
-When called from a program, takes three arguments:
-START, END, and CODING-SYSTEM.  START and END are buffer positions.
-This function sets `last-coding-system-used' to the precise coding system
-used (which may be different from CODING-SYSTEM if CODING-SYSTEM is
-not fully specified.)
-It returns the length of the decoded text.  */)
-     (start, end, coding_system)
-     Lisp_Object start, end, coding_system;
-{
-  return code_convert_region1 (start, end, coding_system, 0);
-}
+  val = args[coding_arg_for_unibyte];
+  CODING_ATTR_FOR_UNIBYTE (attrs) = NILP (val) ? Qnil : Qt;
 
-DEFUN ("encode-coding-region", Fencode_coding_region, Sencode_coding_region,
-       3, 3, "r\nzCoding system: ",
-       doc: /* Encode the current region into the specified coding system.
-When called from a program, takes three arguments:
-START, END, and CODING-SYSTEM.  START and END are buffer positions.
-This function sets `last-coding-system-used' to the precise coding system
-used (which may be different from CODING-SYSTEM if CODING-SYSTEM is
-not fully specified.)
-It returns the length of the encoded text.  */)
-     (start, end, coding_system)
-     Lisp_Object start, end, coding_system;
-{
-  return code_convert_region1 (start, end, coding_system, 1);
-}
+  val = args[coding_arg_plist];
+  CHECK_LIST (val);
+  CODING_ATTR_PLIST (attrs) = val;
 
-Lisp_Object
-code_convert_string1 (string, coding_system, nocopy, encodep)
-     Lisp_Object string, coding_system, nocopy;
-     int encodep;
-{
-  struct coding_system coding;
+  if (EQ (coding_type, Qcharset))
+    {
+      Lisp_Object list;
+      /* Generate a lisp vector of 256 elements.  Each element is nil,
+        integer, or a list of charset IDs.
 
-  CHECK_STRING (string);
-  CHECK_SYMBOL (coding_system);
+        If Nth element is nil, the byte code N is invalid in this
+        coding system.
 
-  if (NILP (coding_system))
-    return (NILP (nocopy) ? Fcopy_sequence (string) : string);
+        If Nth element is a number NUM, N is the first byte of a
+        charset whose ID is NUM.
 
-  if (setup_coding_system (Fcheck_coding_system (coding_system), &coding) < 0)
-    error ("Invalid coding system: %s", SDATA (SYMBOL_NAME (coding_system)));
+        If Nth element is a list of charset IDs, N is the first byte
+        of one of them.  The list is sorted by dimensions of the
+        charsets.  A charset of smaller dimension comes firtst.
+      */
+      for (list = Qnil, tail = charset_list; CONSP (tail); tail = XCDR (tail))
+       {
+         struct charset *charset = CHARSET_FROM_ID (XFASTINT (XCAR (tail)));
 
-  coding.mode |= CODING_MODE_LAST_BLOCK;
-  string = (encodep
-           ? encode_coding_string (string, &coding, !NILP (nocopy))
-           : decode_coding_string (string, &coding, !NILP (nocopy)));
-  Vlast_coding_system_used = coding.symbol;
+         if (charset->method == CHARSET_METHOD_SUPERSET)
+           {
+             val = CHARSET_SUPERSET (charset);
+             for (; CONSP (val); val = XCDR (val))
+               list = Fcons (XCAR (XCAR (val)), list);
+           }
+         else
+           list = Fcons (XCAR (tail), list);
+       }
 
-  return string;
-}
+      val = Fmake_vector (make_number (256), Qnil);
 
-DEFUN ("decode-coding-string", Fdecode_coding_string, Sdecode_coding_string,
-       2, 3, 0,
-       doc: /* Decode STRING which is encoded in CODING-SYSTEM, and return the result.
-Optional arg NOCOPY non-nil means it is OK to return STRING itself
-if the decoding operation is trivial.
-This function sets `last-coding-system-used' to the precise coding system
-used (which may be different from CODING-SYSTEM if CODING-SYSTEM is
-not fully specified.)  */)
-     (string, coding_system, nocopy)
-     Lisp_Object string, coding_system, nocopy;
-{
-  return code_convert_string1 (string, coding_system, nocopy, 0);
-}
+      for (tail = Fnreverse (list); CONSP (tail); tail = XCDR (tail))
+       {
+         struct charset *charset = CHARSET_FROM_ID (XFASTINT (XCAR (tail)));
+         int dim = CHARSET_DIMENSION (charset);
+         int idx = (dim - 1) * 4;
 
-DEFUN ("encode-coding-string", Fencode_coding_string, Sencode_coding_string,
-       2, 3, 0,
-       doc: /* Encode STRING to CODING-SYSTEM, and return the result.
-Optional arg NOCOPY non-nil means it is OK to return STRING itself
-if the encoding operation is trivial.
-This function sets `last-coding-system-used' to the precise coding system
-used (which may be different from CODING-SYSTEM if CODING-SYSTEM is
-not fully specified.)  */)
-     (string, coding_system, nocopy)
-     Lisp_Object string, coding_system, nocopy;
-{
-  return code_convert_string1 (string, coding_system, nocopy, 1);
-}
+         if (CHARSET_ASCII_COMPATIBLE_P (charset))
+           CODING_ATTR_ASCII_COMPAT (attrs) = Qt;
 
-/* Encode or decode STRING according to CODING_SYSTEM.
-   Do not set Vlast_coding_system_used.
+         for (i = charset->code_space[idx];
+              i <= charset->code_space[idx + 1]; i++)
+           {
+             Lisp_Object tmp, tmp2;
+             int dim2;
 
-   This function is called only from macros DECODE_FILE and
-   ENCODE_FILE, thus we ignore character composition.  */
+             tmp = AREF (val, i);
+             if (NILP (tmp))
+               tmp = XCAR (tail);
+             else if (NUMBERP (tmp))
+               {
+                 dim2 = CHARSET_DIMENSION (CHARSET_FROM_ID (XFASTINT (tmp)));
+                 if (dim < dim2)
+                   tmp = Fcons (XCAR (tail), Fcons (tmp, Qnil));
+                 else
+                   tmp = Fcons (tmp, Fcons (XCAR (tail), Qnil));
+               }
+             else
+               {
+                 for (tmp2 = tmp; CONSP (tmp2); tmp2 = XCDR (tmp2))
+                   {
+                     dim2 = CHARSET_DIMENSION (CHARSET_FROM_ID (XFASTINT (XCAR (tmp2))));
+                     if (dim < dim2)
+                       break;
+                   }
+                 if (NILP (tmp2))
+                   tmp = nconc2 (tmp, Fcons (XCAR (tail), Qnil));
+                 else
+                   {
+                     XSETCDR (tmp2, Fcons (XCAR (tmp2), XCDR (tmp2)));
+                     XSETCAR (tmp2, XCAR (tail));
+                   }
+               }
+             ASET (val, i, tmp);
+           }
+       }
+      ASET (attrs, coding_attr_charset_valids, val);
+      category = coding_category_charset;
+    }
+  else if (EQ (coding_type, Qccl))
+    {
+      Lisp_Object valids;
 
-Lisp_Object
-code_convert_string_norecord (string, coding_system, encodep)
-     Lisp_Object string, coding_system;
-     int encodep;
-{
-  struct coding_system coding;
+      if (nargs < coding_arg_ccl_max)
+       goto short_args;
 
-  CHECK_STRING (string);
-  CHECK_SYMBOL (coding_system);
+      val = args[coding_arg_ccl_decoder];
+      CHECK_CCL_PROGRAM (val);
+      if (VECTORP (val))
+       val = Fcopy_sequence (val);
+      ASET (attrs, coding_attr_ccl_decoder, val);
 
-  if (NILP (coding_system))
-    return string;
+      val = args[coding_arg_ccl_encoder];
+      CHECK_CCL_PROGRAM (val);
+      if (VECTORP (val))
+       val = Fcopy_sequence (val);
+      ASET (attrs, coding_attr_ccl_encoder, val);
 
-  if (setup_coding_system (Fcheck_coding_system (coding_system), &coding) < 0)
-    error ("Invalid coding system: %s", SDATA (SYMBOL_NAME (coding_system)));
+      val = args[coding_arg_ccl_valids];
+      valids = Fmake_string (make_number (256), make_number (0));
+      for (tail = val; !NILP (tail); tail = Fcdr (tail))
+       {
+         int from, to;
 
-  coding.composing = COMPOSITION_DISABLED;
-  coding.mode |= CODING_MODE_LAST_BLOCK;
-  return (encodep
-         ? encode_coding_string (string, &coding, 1)
-         : decode_coding_string (string, &coding, 1));
-}
-\f
-DEFUN ("decode-sjis-char", Fdecode_sjis_char, Sdecode_sjis_char, 1, 1, 0,
-       doc: /* Decode a Japanese character which has CODE in shift_jis encoding.
-Return the corresponding character.  */)
-     (code)
-     Lisp_Object code;
-{
-  unsigned char c1, c2, s1, s2;
-  Lisp_Object val;
+         val = Fcar (tail);
+         if (INTEGERP (val))
+           {
+             from = to = XINT (val);
+             if (from < 0 || from > 255)
+               args_out_of_range_3 (val, make_number (0), make_number (255));
+           }
+         else
+           {
+             CHECK_CONS (val);
+             CHECK_NATNUM_CAR (val);
+             CHECK_NATNUM_CDR (val);
+             from = XINT (XCAR (val));
+             if (from > 255)
+               args_out_of_range_3 (XCAR (val),
+                                    make_number (0), make_number (255));
+             to = XINT (XCDR (val));
+             if (to < from || to > 255)
+               args_out_of_range_3 (XCDR (val),
+                                    XCAR (val), make_number (255));
+           }
+         for (i = from; i <= to; i++)
+           SSET (valids, i, 1);
+       }
+      ASET (attrs, coding_attr_ccl_valids, valids);
 
-  CHECK_NUMBER (code);
-  s1 = (XFASTINT (code)) >> 8, s2 = (XFASTINT (code)) & 0xFF;
-  if (s1 == 0)
-    {
-      if (s2 < 0x80)
-       XSETFASTINT (val, s2);
-      else if (s2 >= 0xA0 || s2 <= 0xDF)
-       XSETFASTINT (val, MAKE_CHAR (charset_katakana_jisx0201, s2, 0));
-      else
-       error ("Invalid Shift JIS code: %x", XFASTINT (code));
+      category = coding_category_ccl;
     }
-  else
+  else if (EQ (coding_type, Qutf_16))
     {
-      if ((s1 < 0x80 || (s1 > 0x9F && s1 < 0xE0) || s1 > 0xEF)
-         || (s2 < 0x40 || s2 == 0x7F || s2 > 0xFC))
-       error ("Invalid Shift JIS code: %x", XFASTINT (code));
-      DECODE_SJIS (s1, s2, c1, c2);
-      XSETFASTINT (val, MAKE_CHAR (charset_jisx0208, c1, c2));
-    }
-  return val;
-}
+      Lisp_Object bom, endian;
 
-DEFUN ("encode-sjis-char", Fencode_sjis_char, Sencode_sjis_char, 1, 1, 0,
-       doc: /* Encode a Japanese character CHAR to shift_jis encoding.
-Return the corresponding code in SJIS.  */)
-     (ch)
-     Lisp_Object ch;
-{
-  int charset, c1, c2, s1, s2;
-  Lisp_Object val;
+      CODING_ATTR_ASCII_COMPAT (attrs) = Qnil;
 
-  CHECK_NUMBER (ch);
-  SPLIT_CHAR (XFASTINT (ch), charset, c1, c2);
-  if (charset == CHARSET_ASCII)
-    {
-      val = ch;
-    }
-  else if (charset == charset_jisx0208
-          && c1 > 0x20 && c1 < 0x7F && c2 > 0x20 && c2 < 0x7F)
-    {
-      ENCODE_SJIS (c1, c2, s1, s2);
-      XSETFASTINT (val, (s1 << 8) | s2);
-    }
-  else if (charset == charset_katakana_jisx0201
-          && c1 > 0x20 && c2 < 0xE0)
-    {
-      XSETFASTINT (val, c1 | 0x80);
-    }
-  else
-    error ("Can't encode to shift_jis: %d", XFASTINT (ch));
-  return val;
-}
+      if (nargs < coding_arg_utf16_max)
+       goto short_args;
 
-DEFUN ("decode-big5-char", Fdecode_big5_char, Sdecode_big5_char, 1, 1, 0,
-       doc: /* Decode a Big5 character which has CODE in BIG5 coding system.
-Return the corresponding character.  */)
-     (code)
-     Lisp_Object code;
-{
-  int charset;
-  unsigned char b1, b2, c1, c2;
-  Lisp_Object val;
+      bom = args[coding_arg_utf16_bom];
+      if (! NILP (bom) && ! EQ (bom, Qt))
+       {
+         CHECK_CONS (bom);
+         val = XCAR (bom);
+         CHECK_CODING_SYSTEM (val);
+         val = XCDR (bom);
+         CHECK_CODING_SYSTEM (val);
+       }
+      ASET (attrs, coding_attr_utf_16_bom, bom);
+
+      endian = args[coding_arg_utf16_endian];
+      CHECK_SYMBOL (endian);
+      if (NILP (endian))
+       endian = Qbig;
+      else if (! EQ (endian, Qbig) && ! EQ (endian, Qlittle))
+       error ("Invalid endian: %s", SDATA (SYMBOL_NAME (endian)));
+      ASET (attrs, coding_attr_utf_16_endian, endian);
+
+      category = (CONSP (bom)
+                 ? coding_category_utf_16_auto
+                 : NILP (bom)
+                 ? (EQ (endian, Qbig)
+                    ? coding_category_utf_16_be_nosig
+                    : coding_category_utf_16_le_nosig)
+                 : (EQ (endian, Qbig)
+                    ? coding_category_utf_16_be
+                    : coding_category_utf_16_le));
+    }
+  else if (EQ (coding_type, Qiso_2022))
+    {
+      Lisp_Object initial, reg_usage, request, flags;
+      int i;
+
+      if (nargs < coding_arg_iso2022_max)
+       goto short_args;
+
+      initial = Fcopy_sequence (args[coding_arg_iso2022_initial]);
+      CHECK_VECTOR (initial);
+      for (i = 0; i < 4; i++)
+       {
+         val = Faref (initial, make_number (i));
+         if (! NILP (val))
+           {
+             struct charset *charset;
+
+             CHECK_CHARSET_GET_CHARSET (val, charset);
+             ASET (initial, i, make_number (CHARSET_ID (charset)));
+             if (i == 0 && CHARSET_ASCII_COMPATIBLE_P (charset))
+               CODING_ATTR_ASCII_COMPAT (attrs) = Qt;
+           }
+         else
+           ASET (initial, i, make_number (-1));
+       }
+
+      reg_usage = args[coding_arg_iso2022_reg_usage];
+      CHECK_CONS (reg_usage);
+      CHECK_NUMBER_CAR (reg_usage);
+      CHECK_NUMBER_CDR (reg_usage);
+
+      request = Fcopy_sequence (args[coding_arg_iso2022_request]);
+      for (tail = request; ! NILP (tail); tail = Fcdr (tail))
+       {
+         int id;
+         Lisp_Object tmp;
+
+         val = Fcar (tail);
+         CHECK_CONS (val);
+         tmp = XCAR (val);
+         CHECK_CHARSET_GET_ID (tmp, id);
+         CHECK_NATNUM_CDR (val);
+         if (XINT (XCDR (val)) >= 4)
+           error ("Invalid graphic register number: %d", XINT (XCDR (val)));
+         XSETCAR (val, make_number (id));
+       }
 
-  CHECK_NUMBER (code);
-  b1 = (XFASTINT (code)) >> 8, b2 = (XFASTINT (code)) & 0xFF;
-  if (b1 == 0)
+      flags = args[coding_arg_iso2022_flags];
+      CHECK_NATNUM (flags);
+      i = XINT (flags);
+      if (EQ (args[coding_arg_charset_list], Qiso_2022))
+       flags = make_number (i | CODING_ISO_FLAG_FULL_SUPPORT);
+
+      ASET (attrs, coding_attr_iso_initial, initial);
+      ASET (attrs, coding_attr_iso_usage, reg_usage);
+      ASET (attrs, coding_attr_iso_request, request);
+      ASET (attrs, coding_attr_iso_flags, flags);
+      setup_iso_safe_charsets (attrs);
+
+      if (i & CODING_ISO_FLAG_SEVEN_BITS)
+       category = ((i & (CODING_ISO_FLAG_LOCKING_SHIFT
+                         | CODING_ISO_FLAG_SINGLE_SHIFT))
+                   ? coding_category_iso_7_else
+                   : EQ (args[coding_arg_charset_list], Qiso_2022)
+                   ? coding_category_iso_7
+                   : coding_category_iso_7_tight);
+      else
+       {
+         int id = XINT (AREF (initial, 1));
+
+         category = (((i & CODING_ISO_FLAG_LOCKING_SHIFT)
+                      || EQ (args[coding_arg_charset_list], Qiso_2022)
+                      || id < 0)
+                     ? coding_category_iso_8_else
+                     : (CHARSET_DIMENSION (CHARSET_FROM_ID (id)) == 1)
+                     ? coding_category_iso_8_1
+                     : coding_category_iso_8_2);
+       }
+      if (category != coding_category_iso_8_1
+         && category != coding_category_iso_8_2)
+       CODING_ATTR_ASCII_COMPAT (attrs) = Qnil;
+    }
+  else if (EQ (coding_type, Qemacs_mule))
     {
-      if (b2 >= 0x80)
-       error ("Invalid BIG5 code: %x", XFASTINT (code));
-      val = code;
+      if (EQ (args[coding_arg_charset_list], Qemacs_mule))
+       ASET (attrs, coding_attr_emacs_mule_full, Qt);
+      CODING_ATTR_ASCII_COMPAT (attrs) = Qt;
+      category = coding_category_emacs_mule;
     }
-  else
+  else if (EQ (coding_type, Qshift_jis))
     {
-      if ((b1 < 0xA1 || b1 > 0xFE)
-         || (b2 < 0x40 || (b2 > 0x7E && b2 < 0xA1) || b2 > 0xFE))
-       error ("Invalid BIG5 code: %x", XFASTINT (code));
-      DECODE_BIG5 (b1, b2, charset, c1, c2);
-      XSETFASTINT (val, MAKE_CHAR (charset, c1, c2));
+
+      struct charset *charset;
+
+      if (XINT (Flength (charset_list)) != 3)
+       error ("There should be just three charsets");
+
+      charset = CHARSET_FROM_ID (XINT (XCAR (charset_list)));
+      if (CHARSET_DIMENSION (charset) != 1)
+       error ("Dimension of charset %s is not one",
+              SDATA (SYMBOL_NAME (CHARSET_NAME (charset))));
+      if (CHARSET_ASCII_COMPATIBLE_P (charset))
+       CODING_ATTR_ASCII_COMPAT (attrs) = Qt;
+
+      charset_list = XCDR (charset_list);
+      charset = CHARSET_FROM_ID (XINT (XCAR (charset_list)));
+      if (CHARSET_DIMENSION (charset) != 1)
+       error ("Dimension of charset %s is not one",
+              SDATA (SYMBOL_NAME (CHARSET_NAME (charset))));
+
+      charset_list = XCDR (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;
     }
-  return val;
-}
+  else if (EQ (coding_type, Qbig5))
+    {
+      struct charset *charset;
 
-DEFUN ("encode-big5-char", Fencode_big5_char, Sencode_big5_char, 1, 1, 0,
-       doc: /* Encode the Big5 character CHAR to BIG5 coding system.
-Return the corresponding character code in Big5.  */)
-     (ch)
-     Lisp_Object ch;
-{
-  int charset, c1, c2, b1, b2;
-  Lisp_Object val;
+      if (XINT (Flength (charset_list)) != 2)
+       error ("There should be just two charsets");
+
+      charset = CHARSET_FROM_ID (XINT (XCAR (charset_list)));
+      if (CHARSET_DIMENSION (charset) != 1)
+       error ("Dimension of charset %s is not one",
+              SDATA (SYMBOL_NAME (CHARSET_NAME (charset))));
+      if (CHARSET_ASCII_COMPATIBLE_P (charset))
+       CODING_ATTR_ASCII_COMPAT (attrs) = Qt;
+
+      charset_list = XCDR (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))));
 
-  CHECK_NUMBER (ch);
-  SPLIT_CHAR (XFASTINT (ch), charset, c1, c2);
-  if (charset == CHARSET_ASCII)
+      category = coding_category_big5;
+      Vbig5_coding_system = name;
+    }
+  else if (EQ (coding_type, Qraw_text))
     {
-      val = ch;
+      category = coding_category_raw_text;
+      CODING_ATTR_ASCII_COMPAT (attrs) = Qt;
     }
-  else if ((charset == charset_big5_1
-           && (XFASTINT (ch) >= 0x250a1 && XFASTINT (ch) <= 0x271ec))
-          || (charset == charset_big5_2
-              && XFASTINT (ch) >= 0x290a1 && XFASTINT (ch) <= 0x2bdb2))
+  else if (EQ (coding_type, Qutf_8))
     {
-      ENCODE_BIG5 (charset, c1, c2, b1, b2);
-      XSETFASTINT (val, (b1 << 8) | b2);
+      category = coding_category_utf_8;
+      CODING_ATTR_ASCII_COMPAT (attrs) = Qt;
     }
+  else if (EQ (coding_type, Qundecided))
+    category = coding_category_undecided;
   else
-    error ("Can't encode to Big5: %d", XFASTINT (ch));
-  return val;
-}
-\f
-DEFUN ("set-terminal-coding-system-internal", Fset_terminal_coding_system_internal,
-       Sset_terminal_coding_system_internal, 1, 1, 0,
-       doc: /* Internal use only.  */)
-     (coding_system)
-     Lisp_Object coding_system;
-{
-  CHECK_SYMBOL (coding_system);
-  setup_coding_system (Fcheck_coding_system (coding_system), &terminal_coding);
-  /* We had better not send unsafe characters to terminal.  */
-  terminal_coding.mode |= CODING_MODE_INHIBIT_UNENCODABLE_CHAR;
-  /* Character composition should be disabled.  */
-  terminal_coding.composing = COMPOSITION_DISABLED;
-  /* Error notification should be suppressed.  */
-  terminal_coding.suppress_error = 1;
-  terminal_coding.src_multibyte = 1;
-  terminal_coding.dst_multibyte = 0;
-  return Qnil;
-}
+    error ("Invalid coding system type: %s",
+          SDATA (SYMBOL_NAME (coding_type)));
 
-DEFUN ("set-safe-terminal-coding-system-internal", Fset_safe_terminal_coding_system_internal,
-       Sset_safe_terminal_coding_system_internal, 1, 1, 0,
-       doc: /* Internal use only.  */)
-     (coding_system)
-     Lisp_Object coding_system;
-{
-  CHECK_SYMBOL (coding_system);
-  setup_coding_system (Fcheck_coding_system (coding_system),
-                      &safe_terminal_coding);
-  /* Character composition should be disabled.  */
-  safe_terminal_coding.composing = COMPOSITION_DISABLED;
-  /* Error notification should be suppressed.  */
-  terminal_coding.suppress_error = 1;
-  safe_terminal_coding.src_multibyte = 1;
-  safe_terminal_coding.dst_multibyte = 0;
-  return Qnil;
-}
+  CODING_ATTR_CATEGORY (attrs) = make_number (category);
+  CODING_ATTR_PLIST (attrs)
+    = Fcons (QCcategory, Fcons (AREF (Vcoding_category_table, category),
+                               CODING_ATTR_PLIST (attrs)));
 
-DEFUN ("terminal-coding-system", Fterminal_coding_system,
-       Sterminal_coding_system, 0, 0, 0,
-       doc: /* Return coding system specified for terminal output.  */)
-     ()
-{
-  return terminal_coding.symbol;
-}
+  eol_type = args[coding_arg_eol_type];
+  if (! NILP (eol_type)
+      && ! EQ (eol_type, Qunix)
+      && ! EQ (eol_type, Qdos)
+      && ! EQ (eol_type, Qmac))
+    error ("Invalid eol-type");
 
-DEFUN ("set-keyboard-coding-system-internal", Fset_keyboard_coding_system_internal,
-       Sset_keyboard_coding_system_internal, 1, 1, 0,
-       doc: /* Internal use only.  */)
-     (coding_system)
-     Lisp_Object coding_system;
-{
-  CHECK_SYMBOL (coding_system);
-  setup_coding_system (Fcheck_coding_system (coding_system), &keyboard_coding);
-  /* Character composition should be disabled.  */
-  keyboard_coding.composing = COMPOSITION_DISABLED;
-  return Qnil;
-}
+  aliases = Fcons (name, Qnil);
 
-DEFUN ("keyboard-coding-system", Fkeyboard_coding_system,
-       Skeyboard_coding_system, 0, 0, 0,
-       doc: /* Return coding system specified for decoding keyboard input.  */)
-     ()
-{
-  return keyboard_coding.symbol;
-}
+  if (NILP (eol_type))
+    {
+      eol_type = make_subsidiaries (name);
+      for (i = 0; i < 3; i++)
+       {
+         Lisp_Object this_spec, this_name, this_aliases, this_eol_type;
+
+         this_name = AREF (eol_type, i);
+         this_aliases = Fcons (this_name, Qnil);
+         this_eol_type = (i == 0 ? Qunix : i == 1 ? Qdos : Qmac);
+         this_spec = Fmake_vector (make_number (3), attrs);
+         ASET (this_spec, 1, this_aliases);
+         ASET (this_spec, 2, this_eol_type);
+         Fputhash (this_name, this_spec, Vcoding_system_hash_table);
+         Vcoding_system_list = Fcons (this_name, Vcoding_system_list);
+         Vcoding_system_alist = Fcons (Fcons (Fsymbol_name (this_name), Qnil),
+                                       Vcoding_system_alist);
+       }
+    }
 
-\f
-DEFUN ("find-operation-coding-system", Ffind_operation_coding_system,
-       Sfind_operation_coding_system,  1, MANY, 0,
-       doc: /* Choose a coding system for an operation based on the target name.
-The value names a pair of coding systems: (DECODING-SYSTEM . ENCODING-SYSTEM).
-DECODING-SYSTEM is the coding system to use for decoding
-\(in case OPERATION does decoding), and ENCODING-SYSTEM is the coding system
-for encoding (in case OPERATION does encoding).
+  spec_vec = Fmake_vector (make_number (3), attrs);
+  ASET (spec_vec, 1, aliases);
+  ASET (spec_vec, 2, eol_type);
 
-The first argument OPERATION specifies an I/O primitive:
-  For file I/O, `insert-file-contents' or `write-region'.
-  For process I/O, `call-process', `call-process-region', or `start-process'.
-  For network I/O, `open-network-stream'.
+  Fputhash (name, spec_vec, Vcoding_system_hash_table);
+  Vcoding_system_list = Fcons (name, Vcoding_system_list);
+  Vcoding_system_alist = Fcons (Fcons (Fsymbol_name (name), Qnil),
+                               Vcoding_system_alist);
 
-The remaining arguments should be the same arguments that were passed
-to the primitive.  Depending on which primitive, one of those arguments
-is selected as the TARGET.  For example, if OPERATION does file I/O,
-whichever argument specifies the file name is TARGET.
+  {
+    int id = coding_categories[category].id;
 
-TARGET has a meaning which depends on OPERATION:
-  For file I/O, TARGET is a file name.
-  For process I/O, TARGET is a process name.
-  For network I/O, TARGET is a service name or a port number
+    if (id < 0 || EQ (name, CODING_ID_NAME (id)))
+      setup_coding_system (name, &coding_categories[category]);
+  }
 
-This function looks up what specified for TARGET in,
-`file-coding-system-alist', `process-coding-system-alist',
-or `network-coding-system-alist' depending on OPERATION.
-They may specify a coding system, a cons of coding systems,
-or a function symbol to call.
-In the last case, we call the function with one argument,
-which is a list of all the arguments given to this function.
+  return Qnil;
 
-usage: (find-operation-coding-system OPERATION ARGUMENTS ...)  */)
-     (nargs, args)
-     int nargs;
-     Lisp_Object *args;
-{
-  Lisp_Object operation, target_idx, target, val;
-  register Lisp_Object chain;
+ short_args:
+  return Fsignal (Qwrong_number_of_arguments,
+                 Fcons (intern ("define-coding-system-internal"),
+                        make_number (nargs)));
+}
 
-  if (nargs < 2)
-    error ("Too few arguments");
-  operation = args[0];
-  if (!SYMBOLP (operation)
-      || !INTEGERP (target_idx = Fget (operation, Qtarget_idx)))
-    error ("Invalid first argument");
-  if (nargs < 1 + XINT (target_idx))
-    error ("Too few arguments for operation: %s",
-          SDATA (SYMBOL_NAME (operation)));
-  /* For write-region, if the 6th argument (i.e. VISIT, the 5th
-     argument to write-region) is string, it must be treated as a
-     target file name.  */
-  if (EQ (operation, Qwrite_region)
-      && nargs > 5
-      && STRINGP (args[5]))
-    target_idx = make_number (4);
-  target = args[XINT (target_idx) + 1];
-  if (!(STRINGP (target)
-       || (EQ (operation, Qopen_network_stream) && INTEGERP (target))))
-    error ("Invalid argument %d", XINT (target_idx) + 1);
+/* Fixme: should this record the alias relationships for
+   diagnostics?  Should it update coding-system-list?  */
+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.  */)
+     (alias, coding_system)
+     Lisp_Object alias, coding_system;
+{
+  Lisp_Object spec, aliases, eol_type;
 
-  chain = ((EQ (operation, Qinsert_file_contents)
-           || EQ (operation, Qwrite_region))
-          ? Vfile_coding_system_alist
-          : (EQ (operation, Qopen_network_stream)
-             ? Vnetwork_coding_system_alist
-             : Vprocess_coding_system_alist));
-  if (NILP (chain))
-    return Qnil;
+  CHECK_SYMBOL (alias);
+  CHECK_CODING_SYSTEM_GET_SPEC (coding_system, spec);
+  aliases = AREF (spec, 1);
+  while (!NILP (XCDR (aliases)))
+    aliases = XCDR (aliases);
+  XSETCDR (aliases, Fcons (alias, Qnil));
 
-  for (; CONSP (chain); chain = XCDR (chain))
+  eol_type = AREF (spec, 2);
+  if (VECTORP (eol_type))
     {
-      Lisp_Object elt;
-      elt = XCAR (chain);
+      Lisp_Object subsidiaries;
+      int i;
 
-      if (CONSP (elt)
-         && ((STRINGP (target)
-              && STRINGP (XCAR (elt))
-              && fast_string_match (XCAR (elt), target) >= 0)
-             || (INTEGERP (target) && EQ (target, XCAR (elt)))))
-       {
-         val = XCDR (elt);
-         /* Here, if VAL is both a valid coding system and a valid
-             function symbol, we return VAL as a coding system.  */
-         if (CONSP (val))
-           return val;
-         if (! SYMBOLP (val))
-           return Qnil;
-         if (! NILP (Fcoding_system_p (val)))
-           return Fcons (val, val);
-         if (! NILP (Ffboundp (val)))
-           {
-             val = call1 (val, Flist (nargs, args));
-             if (CONSP (val))
-               return val;
-             if (SYMBOLP (val) && ! NILP (Fcoding_system_p (val)))
-               return Fcons (val, val);
-           }
-         return Qnil;
-       }
+      subsidiaries = make_subsidiaries (alias);
+      for (i = 0; i < 3; i++)
+       Fdefine_coding_system_alias (AREF (subsidiaries, i),
+                                    AREF (eol_type, i));
+
+      ASET (spec, 2, subsidiaries);
     }
+
+  Fputhash (alias, spec, Vcoding_system_hash_table);
+  Vcoding_system_alist = Fcons (Fcons (Fsymbol_name (alias), Qnil),
+                               Vcoding_system_alist);
+
   return Qnil;
 }
 
-DEFUN ("update-coding-systems-internal",  Fupdate_coding_systems_internal,
-       Supdate_coding_systems_internal, 0, 0, 0,
-       doc: /* Update internal database for ISO2022 and CCL based coding systems.
-When values of any coding categories are changed, you must
-call this function.  */)
-     ()
+DEFUN ("coding-system-base", Fcoding_system_base, Scoding_system_base,
+       1, 1, 0,
+       doc: /* Return the base of CODING-SYSTEM.
+Any alias or subsidiary coding system is not a base coding system.  */)
+  (coding_system)
+     Lisp_Object coding_system;
 {
-  int i;
+  Lisp_Object spec, attrs;
 
-  for (i = CODING_CATEGORY_IDX_EMACS_MULE; i < CODING_CATEGORY_IDX_MAX; i++)
-    {
-      Lisp_Object val;
+  if (NILP (coding_system))
+    return (Qno_conversion);
+  CHECK_CODING_SYSTEM_GET_SPEC (coding_system, spec);
+  attrs = AREF (spec, 0);
+  return CODING_ATTR_BASE_NAME (attrs);
+}
 
-      val = SYMBOL_VALUE (XVECTOR (Vcoding_category_table)->contents[i]);
-      if (!NILP (val))
-       {
-         if (! coding_system_table[i])
-           coding_system_table[i] = ((struct coding_system *)
-                                     xmalloc (sizeof (struct coding_system)));
-         setup_coding_system (val, coding_system_table[i]);
-       }
-      else if (coding_system_table[i])
-       {
-         xfree (coding_system_table[i]);
-         coding_system_table[i] = NULL;
-       }
-    }
+DEFUN ("coding-system-plist", Fcoding_system_plist, Scoding_system_plist,
+       1, 1, 0,
+       doc: "Return the property list of CODING-SYSTEM.")
+     (coding_system)
+     Lisp_Object coding_system;
+{
+  Lisp_Object spec, attrs;
 
-  return Qnil;
+  if (NILP (coding_system))
+    coding_system = Qno_conversion;
+  CHECK_CODING_SYSTEM_GET_SPEC (coding_system, spec);
+  attrs = AREF (spec, 0);
+  return CODING_ATTR_PLIST (attrs);
 }
 
-DEFUN ("set-coding-priority-internal", Fset_coding_priority_internal,
-       Sset_coding_priority_internal, 0, 0, 0,
-       doc: /* Update internal database for the current value of `coding-category-list'.
-This function is internal use only.  */)
-     ()
+
+DEFUN ("coding-system-aliases", Fcoding_system_aliases, Scoding_system_aliases,
+       1, 1, 0,
+       doc: /* Return the list of aliases of CODING-SYSTEM.  */)
+     (coding_system)
+     Lisp_Object coding_system;
 {
-  int i = 0, idx;
-  Lisp_Object val;
+  Lisp_Object spec;
 
-  val = Vcoding_category_list;
+  if (NILP (coding_system))
+    coding_system = Qno_conversion;
+  CHECK_CODING_SYSTEM_GET_SPEC (coding_system, spec);
+  return AREF (spec, 1);
+}
 
-  while (CONSP (val) && i < CODING_CATEGORY_IDX_MAX)
-    {
-      if (! SYMBOLP (XCAR (val)))
-       break;
-      idx = XFASTINT (Fget (XCAR (val), Qcoding_category_index));
-      if (idx >= CODING_CATEGORY_IDX_MAX)
-       break;
-      coding_priorities[i++] = (1 << idx);
-      val = XCDR (val);
-    }
-  /* If coding-category-list is valid and contains all coding
-     categories, `i' should be CODING_CATEGORY_IDX_MAX now.  If not,
-     the following code saves Emacs from crashing.  */
-  while (i < CODING_CATEGORY_IDX_MAX)
-    coding_priorities[i++] = CODING_CATEGORY_MASK_RAW_TEXT;
+DEFUN ("coding-system-eol-type", Fcoding_system_eol_type,
+       Scoding_system_eol_type, 1, 1, 0,
+       doc: /* Return eol-type of CODING-SYSTEM.
+An eol-type is integer 0, 1, 2, or a vector of coding systems.
 
-  return Qnil;
-}
+Integer values 0, 1, and 2 indicate a format of end-of-line; LF, CRLF,
+and CR respectively.
 
-DEFUN ("define-coding-system-internal", Fdefine_coding_system_internal,
-       Sdefine_coding_system_internal, 1, 1, 0,
-       doc: /* Register CODING-SYSTEM as a base coding system.
-This function is internal use only.  */)
+A vector value indicates that a format of end-of-line should be
+detected automatically.  Nth element of the vector is the subsidiary
+coding system whose eol-type is N.  */)
      (coding_system)
      Lisp_Object coding_system;
 {
-  Lisp_Object safe_chars, slot;
+  Lisp_Object spec, eol_type;
+  int n;
 
-  if (NILP (Fcheck_coding_system (coding_system)))
-    Fsignal (Qcoding_system_error, Fcons (coding_system, Qnil));
-  safe_chars = coding_safe_chars (coding_system);
-  if (! EQ (safe_chars, Qt) && ! CHAR_TABLE_P (safe_chars))
-    error ("No valid safe-chars property for %s",
-          SDATA (SYMBOL_NAME (coding_system)));
-  if (EQ (safe_chars, Qt))
-    {
-      if (NILP (Fmemq (coding_system, XCAR (Vcoding_system_safe_chars))))
-       XSETCAR (Vcoding_system_safe_chars,
-                Fcons (coding_system, XCAR (Vcoding_system_safe_chars)));
-    }
-  else
-    {
-      slot = Fassq (coding_system, XCDR (Vcoding_system_safe_chars));
-      if (NILP (slot))
-       XSETCDR (Vcoding_system_safe_chars,
-                nconc2 (XCDR (Vcoding_system_safe_chars),
-                        Fcons (Fcons (coding_system, safe_chars), Qnil)));
-      else
-       XSETCDR (slot, safe_chars);
-    }
-  return Qnil;
+  if (NILP (coding_system))
+    coding_system = Qno_conversion;
+  if (! CODING_SYSTEM_P (coding_system))
+    return Qnil;
+  spec = CODING_SYSTEM_SPEC (coding_system);
+  eol_type = AREF (spec, 2);
+  if (VECTORP (eol_type))
+    return Fcopy_sequence (eol_type);
+  n = EQ (eol_type, Qunix) ? 0 : EQ (eol_type, Qdos) ? 1 : 2;
+  return make_number (n);
 }
 
 #endif /* emacs */
@@ -7411,20 +8609,11 @@ init_coding_once ()
 {
   int i;
 
-  /* Emacs' internal format specific initialize routine.  */
-  for (i = 0; i <= 0x20; i++)
-    emacs_code_class[i] = EMACS_control_code;
-  emacs_code_class[0x0A] = EMACS_linefeed_code;
-  emacs_code_class[0x0D] = EMACS_carriage_return_code;
-  for (i = 0x21 ; i < 0x7F; i++)
-    emacs_code_class[i] = EMACS_ascii_code;
-  emacs_code_class[0x7F] = EMACS_control_code;
-  for (i = 0x80; i < 0xFF; i++)
-    emacs_code_class[i] = EMACS_invalid_code;
-  emacs_code_class[LEADING_CODE_PRIVATE_11] = EMACS_leading_code_3;
-  emacs_code_class[LEADING_CODE_PRIVATE_12] = EMACS_leading_code_3;
-  emacs_code_class[LEADING_CODE_PRIVATE_21] = EMACS_leading_code_4;
-  emacs_code_class[LEADING_CODE_PRIVATE_22] = EMACS_leading_code_4;
+  for (i = 0; i < coding_category_max; i++)
+    {
+      coding_categories[i].id = -1;
+      coding_priorities[i] = i;
+    }
 
   /* ISO2022 specific initialize routine.  */
   for (i = 0; i < 0x20; i++)
@@ -7446,24 +8635,16 @@ init_coding_once ()
   iso_code_class[ISO_CODE_SS3] = ISO_single_shift_3;
   iso_code_class[ISO_CODE_CSI] = ISO_control_sequence_introducer;
 
-  setup_coding_system (Qnil, &keyboard_coding);
-  setup_coding_system (Qnil, &terminal_coding);
-  setup_coding_system (Qnil, &safe_terminal_coding);
-  setup_coding_system (Qnil, &default_buffer_file_coding);
-
-  bzero (coding_system_table, sizeof coding_system_table);
-
-  bzero (ascii_skip_code, sizeof ascii_skip_code);
-  for (i = 0; i < 128; i++)
-    ascii_skip_code[i] = 1;
-
-#if defined (MSDOS) || defined (WINDOWSNT)
-  system_eol_type = CODING_EOL_CRLF;
-#else
-  system_eol_type = CODING_EOL_LF;
-#endif
-
   inhibit_pre_post_conversion = 0;
+
+  for (i = 0; i < 256; i++)
+    {
+      emacs_mule_bytes[i] = 1;
+    }
+  emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_11] = 3;
+  emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_12] = 3;
+  emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_21] = 4;
+  emacs_mule_bytes[EMACS_MULE_LEADING_CODE_PRIVATE_22] = 4;
 }
 
 #ifdef emacs
@@ -7471,11 +8652,29 @@ init_coding_once ()
 void
 syms_of_coding ()
 {
-  Qtarget_idx = intern ("target-idx");
-  staticpro (&Qtarget_idx);
+  staticpro (&Vcoding_system_hash_table);
+  {
+    Lisp_Object args[2];
+    args[0] = QCtest;
+    args[1] = Qeq;
+    Vcoding_system_hash_table = Fmake_hash_table (2, args);
+  }
+
+  staticpro (&Vsjis_coding_system);
+  Vsjis_coding_system = Qnil;
 
-  Qcoding_system_history = intern ("coding-system-history");
-  staticpro (&Qcoding_system_history);
+  staticpro (&Vbig5_coding_system);
+  Vbig5_coding_system = Qnil;
+
+  staticpro (&Vcode_conversion_work_buf_list);
+  Vcode_conversion_work_buf_list = Qnil;
+
+  staticpro (&Vcode_conversion_reused_work_buf);
+  Vcode_conversion_reused_work_buf = Qnil;
+
+  DEFSYM (Qcharset, "charset");
+  DEFSYM (Qtarget_idx, "target-idx");
+  DEFSYM (Qcoding_system_history, "coding-system-history");
   Fset (Qcoding_system_history, Qnil);
 
   /* Target FILENAME is the first argument.  */
@@ -7483,117 +8682,117 @@ syms_of_coding ()
   /* Target FILENAME is the third argument.  */
   Fput (Qwrite_region, Qtarget_idx, make_number (2));
 
-  Qcall_process = intern ("call-process");
-  staticpro (&Qcall_process);
+  DEFSYM (Qcall_process, "call-process");
   /* Target PROGRAM is the first argument.  */
   Fput (Qcall_process, Qtarget_idx, make_number (0));
 
-  Qcall_process_region = intern ("call-process-region");
-  staticpro (&Qcall_process_region);
+  DEFSYM (Qcall_process_region, "call-process-region");
   /* Target PROGRAM is the third argument.  */
   Fput (Qcall_process_region, Qtarget_idx, make_number (2));
 
-  Qstart_process = intern ("start-process");
-  staticpro (&Qstart_process);
+  DEFSYM (Qstart_process, "start-process");
   /* Target PROGRAM is the third argument.  */
   Fput (Qstart_process, Qtarget_idx, make_number (2));
 
-  Qopen_network_stream = intern ("open-network-stream");
-  staticpro (&Qopen_network_stream);
+  DEFSYM (Qopen_network_stream, "open-network-stream");
   /* Target SERVICE is the fourth argument.  */
   Fput (Qopen_network_stream, Qtarget_idx, make_number (3));
 
-  Qcoding_system = intern ("coding-system");
-  staticpro (&Qcoding_system);
-
-  Qeol_type = intern ("eol-type");
-  staticpro (&Qeol_type);
+  DEFSYM (Qcoding_system, "coding-system");
+  DEFSYM (Qcoding_aliases, "coding-aliases");
 
-  Qbuffer_file_coding_system = intern ("buffer-file-coding-system");
-  staticpro (&Qbuffer_file_coding_system);
+  DEFSYM (Qeol_type, "eol-type");
+  DEFSYM (Qunix, "unix");
+  DEFSYM (Qdos, "dos");
 
-  Qpost_read_conversion = intern ("post-read-conversion");
-  staticpro (&Qpost_read_conversion);
+  DEFSYM (Qbuffer_file_coding_system, "buffer-file-coding-system");
+  DEFSYM (Qpost_read_conversion, "post-read-conversion");
+  DEFSYM (Qpre_write_conversion, "pre-write-conversion");
+  DEFSYM (Qdefault_char, "default-char");
+  DEFSYM (Qundecided, "undecided");
+  DEFSYM (Qno_conversion, "no-conversion");
+  DEFSYM (Qraw_text, "raw-text");
 
-  Qpre_write_conversion = intern ("pre-write-conversion");
-  staticpro (&Qpre_write_conversion);
+  DEFSYM (Qiso_2022, "iso-2022");
 
-  Qno_conversion = intern ("no-conversion");
-  staticpro (&Qno_conversion);
+  DEFSYM (Qutf_8, "utf-8");
+  DEFSYM (Qutf_8_emacs, "utf-8-emacs");
 
-  Qundecided = intern ("undecided");
-  staticpro (&Qundecided);
+  DEFSYM (Qutf_16, "utf-16");
+  DEFSYM (Qbig, "big");
+  DEFSYM (Qlittle, "little");
 
-  Qcoding_system_p = intern ("coding-system-p");
-  staticpro (&Qcoding_system_p);
+  DEFSYM (Qshift_jis, "shift-jis");
+  DEFSYM (Qbig5, "big5");
 
-  Qcoding_system_error = intern ("coding-system-error");
-  staticpro (&Qcoding_system_error);
+  DEFSYM (Qcoding_system_p, "coding-system-p");
 
+  DEFSYM (Qcoding_system_error, "coding-system-error");
   Fput (Qcoding_system_error, Qerror_conditions,
        Fcons (Qcoding_system_error, Fcons (Qerror, Qnil)));
   Fput (Qcoding_system_error, Qerror_message,
        build_string ("Invalid coding system"));
 
-  Qcoding_category = intern ("coding-category");
-  staticpro (&Qcoding_category);
-  Qcoding_category_index = intern ("coding-category-index");
-  staticpro (&Qcoding_category_index);
-
-  Vcoding_category_table
-    = Fmake_vector (make_number (CODING_CATEGORY_IDX_MAX), Qnil);
-  staticpro (&Vcoding_category_table);
-  {
-    int i;
-    for (i = 0; i < CODING_CATEGORY_IDX_MAX; i++)
-      {
-       XVECTOR (Vcoding_category_table)->contents[i]
-         = intern (coding_category_name[i]);
-       Fput (XVECTOR (Vcoding_category_table)->contents[i],
-             Qcoding_category_index, make_number (i));
-      }
-  }
-
-  Vcoding_system_safe_chars = Fcons (Qnil, Qnil);
-  staticpro (&Vcoding_system_safe_chars);
-
-  Qtranslation_table = intern ("translation-table");
-  staticpro (&Qtranslation_table);
-  Fput (Qtranslation_table, Qchar_table_extra_slots, make_number (2));
-
-  Qtranslation_table_id = intern ("translation-table-id");
-  staticpro (&Qtranslation_table_id);
-
-  Qtranslation_table_for_decode = intern ("translation-table-for-decode");
-  staticpro (&Qtranslation_table_for_decode);
-
-  Qtranslation_table_for_encode = intern ("translation-table-for-encode");
-  staticpro (&Qtranslation_table_for_encode);
-
-  Qsafe_chars = intern ("safe-chars");
-  staticpro (&Qsafe_chars);
-
-  Qchar_coding_system = intern ("char-coding-system");
-  staticpro (&Qchar_coding_system);
-
   /* Intern this now in case it isn't already done.
      Setting this variable twice is harmless.
      But don't staticpro it here--that is done in alloc.c.  */
   Qchar_table_extra_slots = intern ("char-table-extra-slots");
-  Fput (Qsafe_chars, Qchar_table_extra_slots, make_number (0));
-  Fput (Qchar_coding_system, Qchar_table_extra_slots, make_number (0));
 
-  Qvalid_codes = intern ("valid-codes");
-  staticpro (&Qvalid_codes);
+  DEFSYM (Qtranslation_table, "translation-table");
+  Fput (Qtranslation_table, Qchar_table_extra_slots, make_number (1));
+  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");
 
-  Qemacs_mule = intern ("emacs-mule");
-  staticpro (&Qemacs_mule);
+  DEFSYM (Qvalid_codes, "valid-codes");
 
-  Qraw_text = intern ("raw-text");
-  staticpro (&Qraw_text);
+  DEFSYM (Qemacs_mule, "emacs-mule");
 
-  Qutf_8 = intern ("utf-8");
-  staticpro (&Qutf_8);
+  DEFSYM (QCcategory, ":category");
+
+  Vcoding_category_table
+    = Fmake_vector (make_number (coding_category_max), Qnil);
+  staticpro (&Vcoding_category_table);
+  /* Followings are target of code detection.  */
+  ASET (Vcoding_category_table, coding_category_iso_7,
+       intern ("coding-category-iso-7"));
+  ASET (Vcoding_category_table, coding_category_iso_7_tight,
+       intern ("coding-category-iso-7-tight"));
+  ASET (Vcoding_category_table, coding_category_iso_8_1,
+       intern ("coding-category-iso-8-1"));
+  ASET (Vcoding_category_table, coding_category_iso_8_2,
+       intern ("coding-category-iso-8-2"));
+  ASET (Vcoding_category_table, coding_category_iso_7_else,
+       intern ("coding-category-iso-7-else"));
+  ASET (Vcoding_category_table, coding_category_iso_8_else,
+       intern ("coding-category-iso-8-else"));
+  ASET (Vcoding_category_table, coding_category_utf_8,
+       intern ("coding-category-utf-8"));
+  ASET (Vcoding_category_table, coding_category_utf_16_be,
+       intern ("coding-category-utf-16-be"));
+  ASET (Vcoding_category_table, coding_category_utf_16_auto,
+       intern ("coding-category-utf-16-auto"));
+  ASET (Vcoding_category_table, coding_category_utf_16_le,
+       intern ("coding-category-utf-16-le"));
+  ASET (Vcoding_category_table, coding_category_utf_16_be_nosig,
+       intern ("coding-category-utf-16-be-nosig"));
+  ASET (Vcoding_category_table, coding_category_utf_16_le_nosig,
+       intern ("coding-category-utf-16-le-nosig"));
+  ASET (Vcoding_category_table, coding_category_charset,
+       intern ("coding-category-charset"));
+  ASET (Vcoding_category_table, coding_category_sjis,
+       intern ("coding-category-sjis"));
+  ASET (Vcoding_category_table, coding_category_big5,
+       intern ("coding-category-big5"));
+  ASET (Vcoding_category_table, coding_category_ccl,
+       intern ("coding-category-ccl"));
+  ASET (Vcoding_category_table, coding_category_emacs_mule,
+       intern ("coding-category-emacs-mule"));
+  /* Followings are NOT target of code detection.  */
+  ASET (Vcoding_category_table, coding_category_raw_text,
+       intern ("coding-category-raw-text"));
+  ASET (Vcoding_category_table, coding_category_undecided,
+       intern ("coding-category-undecided"));
 
   defsubr (&Scoding_system_p);
   defsubr (&Sread_coding_system);
@@ -7603,6 +8802,7 @@ syms_of_coding ()
   defsubr (&Sdetect_coding_string);
   defsubr (&Sfind_coding_systems_region_internal);
   defsubr (&Sunencodable_char_position);
+  defsubr (&Scheck_coding_systems_region);
   defsubr (&Sdecode_coding_region);
   defsubr (&Sencode_coding_region);
   defsubr (&Sdecode_coding_string);
@@ -7617,15 +8817,20 @@ syms_of_coding ()
   defsubr (&Sset_keyboard_coding_system_internal);
   defsubr (&Skeyboard_coding_system);
   defsubr (&Sfind_operation_coding_system);
-  defsubr (&Supdate_coding_systems_internal);
-  defsubr (&Sset_coding_priority_internal);
+  defsubr (&Sset_coding_system_priority);
   defsubr (&Sdefine_coding_system_internal);
+  defsubr (&Sdefine_coding_system_alias);
+  defsubr (&Scoding_system_base);
+  defsubr (&Scoding_system_plist);
+  defsubr (&Scoding_system_aliases);
+  defsubr (&Scoding_system_eol_type);
+  defsubr (&Scoding_system_priority_list);
 
   DEFVAR_LISP ("coding-system-list", &Vcoding_system_list,
               doc: /* List of coding systems.
 
 Do not alter the value of this variable manually.  This variable should be
-updated by the functions `make-coding-system' and
+updated by the functions `define-coding-system' and
 `define-coding-system-alias'.  */);
   Vcoding_system_list = Qnil;
 
@@ -7650,7 +8855,7 @@ system bound to the corresponding coding-category is selected.  */);
     int i;
 
     Vcoding_category_list = Qnil;
-    for (i = CODING_CATEGORY_IDX_MAX - 1; i >= 0; i--)
+    for (i = coding_category_max - 1; i >= 0; i--)
       Vcoding_category_list
        = Fcons (XVECTOR (Vcoding_category_table)->contents[i],
                 Vcoding_category_list);
@@ -7680,25 +8885,27 @@ the value of `buffer-file-coding-system' is used.  */);
   Vcoding_system_for_write = Qnil;
 
   DEFVAR_LISP ("last-coding-system-used", &Vlast_coding_system_used,
-              doc: /* Coding system used in the latest file or process I/O.
-Also set by `encode-coding-region', `decode-coding-region',
-`encode-coding-string' and `decode-coding-string'.  */);
+              doc: /*
+Coding system used in the latest file or process I/O.  */);
   Vlast_coding_system_used = Qnil;
 
   DEFVAR_BOOL ("inhibit-eol-conversion", &inhibit_eol_conversion,
-              doc: /* *Non-nil means always inhibit code conversion of end-of-line format.
+              doc: /*
+*Non-nil means always inhibit code conversion of end-of-line format.
 See info node `Coding Systems' and info node `Text and Binary' concerning
 such conversion.  */);
   inhibit_eol_conversion = 0;
 
   DEFVAR_BOOL ("inherit-process-coding-system", &inherit_process_coding_system,
-              doc: /* Non-nil means process buffer inherits coding system of process output.
+              doc: /*
+Non-nil means process buffer inherits coding system of process output.
 Bind it to t if the process output is to be treated as if it were a file
 read from some filesystem.  */);
   inherit_process_coding_system = 0;
 
   DEFVAR_LISP ("file-coding-system-alist", &Vfile_coding_system_alist,
-              doc: /* Alist to decide a coding system to use for a file I/O operation.
+              doc: /*
+Alist to decide a coding system to use for a file I/O operation.
 The format is ((PATTERN . VAL) ...),
 where PATTERN is a regular expression matching a file name,
 VAL is a coding system, a cons of coding systems, or a function symbol.
@@ -7708,14 +8915,15 @@ If VAL is a cons of coding systems, the car part is used for decoding,
 and the cdr part is used for encoding.
 If VAL is a function symbol, the function must return a coding system
 or a cons of coding systems which are used as above.  The function gets
-the arguments with which `find-operation-coding-system' was called.
+the arguments with which `find-operation-coding-systems' was called.
 
 See also the function `find-operation-coding-system'
 and the variable `auto-coding-alist'.  */);
   Vfile_coding_system_alist = Qnil;
 
   DEFVAR_LISP ("process-coding-system-alist", &Vprocess_coding_system_alist,
-    doc: /* Alist to decide a coding system to use for a process I/O operation.
+              doc: /*
+Alist to decide a coding system to use for a process I/O operation.
 The format is ((PATTERN . VAL) ...),
 where PATTERN is a regular expression matching a program name,
 VAL is a coding system, a cons of coding systems, or a function symbol.
@@ -7730,7 +8938,8 @@ See also the function `find-operation-coding-system'.  */);
   Vprocess_coding_system_alist = Qnil;
 
   DEFVAR_LISP ("network-coding-system-alist", &Vnetwork_coding_system_alist,
-    doc: /* Alist to decide a coding system to use for a network I/O operation.
+              doc: /*
+Alist to decide a coding system to use for a network I/O operation.
 The format is ((PATTERN . VAL) ...),
 where PATTERN is a regular expression matching a network service name
 or is a port number to connect to,
@@ -7752,23 +8961,28 @@ Also used for decoding keyboard input on X Window system.  */);
 
   /* The eol mnemonics are reset in startup.el system-dependently.  */
   DEFVAR_LISP ("eol-mnemonic-unix", &eol_mnemonic_unix,
-              doc: /* *String displayed in mode line for UNIX-like (LF) end-of-line format.  */);
+              doc: /*
+*String displayed in mode line for UNIX-like (LF) end-of-line format.  */);
   eol_mnemonic_unix = build_string (":");
 
   DEFVAR_LISP ("eol-mnemonic-dos", &eol_mnemonic_dos,
-              doc: /* *String displayed in mode line for DOS-like (CRLF) end-of-line format.  */);
+              doc: /*
+*String displayed in mode line for DOS-like (CRLF) end-of-line format.  */);
   eol_mnemonic_dos = build_string ("\\");
 
   DEFVAR_LISP ("eol-mnemonic-mac", &eol_mnemonic_mac,
-              doc: /* *String displayed in mode line for MAC-like (CR) end-of-line format.  */);
+              doc: /*
+*String displayed in mode line for MAC-like (CR) end-of-line format.  */);
   eol_mnemonic_mac = build_string ("/");
 
   DEFVAR_LISP ("eol-mnemonic-undecided", &eol_mnemonic_undecided,
-              doc: /* *String displayed in mode line when end-of-line format is not yet determined.  */);
+              doc: /*
+*String displayed in mode line when end-of-line format is not yet determined.  */);
   eol_mnemonic_undecided = build_string (":");
 
   DEFVAR_LISP ("enable-character-translation", &Venable_character_translation,
-              doc: /* *Non-nil enables character translation while encoding and decoding.  */);
+              doc: /*
+*Non-nil enables character translation while encoding and decoding.  */);
   Venable_character_translation = Qt;
 
   DEFVAR_LISP ("standard-translation-table-for-decode",
@@ -7781,11 +8995,12 @@ Also used for decoding keyboard input on X Window system.  */);
               doc: /* Table for translating characters while encoding.  */);
   Vstandard_translation_table_for_encode = Qnil;
 
-  DEFVAR_LISP ("charset-revision-table", &Vcharset_revision_alist,
+  DEFVAR_LISP ("charset-revision-table", &Vcharset_revision_table,
               doc: /* Alist of charsets vs revision numbers.
 While encoding, if a charset (car part of an element) is found,
-designate it with the escape sequence identifying revision (cdr part of the element).  */);
-  Vcharset_revision_alist = Qnil;
+designate it with the escape sequence identifying revision (cdr part
+of the element).  */);
+  Vcharset_revision_table = Qnil;
 
   DEFVAR_LISP ("default-process-coding-system",
               &Vdefault_process_coding_system,
@@ -7795,7 +9010,8 @@ the cdr part is used for encoding a text to be sent to a process.  */);
   Vdefault_process_coding_system = Qnil;
 
   DEFVAR_LISP ("latin-extra-code-table", &Vlatin_extra_code_table,
-              doc: /* Table of extra Latin codes in the range 128..159 (inclusive).
+              doc: /*
+Table of extra Latin codes in the range 128..159 (inclusive).
 This is a vector of length 256.
 If Nth element is non-nil, the existence of code N in a file
 \(or output of subprocess) doesn't prevent it to be detected as
@@ -7807,7 +9023,8 @@ Only 128th through 159th elements has a meaning.  */);
 
   DEFVAR_LISP ("select-safe-coding-system-function",
               &Vselect_safe_coding_system_function,
-              doc: /* Function to call to select safe coding system for encoding a text.
+              doc: /*
+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
@@ -7827,7 +9044,8 @@ called even if `coding-system-for-write' is non-nil.  The command
 
   DEFVAR_BOOL ("inhibit-iso-escape-detection",
               &inhibit_iso_escape_detection,
-              doc: /* If non-nil, Emacs ignores ISO2022's escape sequence on code detection.
+              doc: /*
+If non-nil, Emacs ignores ISO2022's escape sequence on code detection.
 
 By default, on reading a file, Emacs tries to detect how the text is
 encoded.  This code detection is sensitive to escape sequences.  If
@@ -7857,6 +9075,49 @@ escape sequence (e.g `latin-1') on reading by \\[universal-coding-system-argumen
 This is applied to the result of input methods, not their input.  See also
 `keyboard-translate-table'.  */);
     Vtranslation_table_for_input = Qnil;
+
+  {
+    Lisp_Object args[coding_arg_max];
+    Lisp_Object plist[16];
+    int i;
+
+    for (i = 0; i < coding_arg_max; i++)
+      args[i] = Qnil;
+
+    plist[0] = intern (":name");
+    plist[1] = args[coding_arg_name] = Qno_conversion;
+    plist[2] = intern (":mnemonic");
+    plist[3] = args[coding_arg_mnemonic] = make_number ('=');
+    plist[4] = intern (":coding-type");
+    plist[5] = args[coding_arg_coding_type] = Qraw_text;
+    plist[6] = intern (":ascii-compatible-p");
+    plist[7] = args[coding_arg_ascii_compatible_p] = Qt;
+    plist[8] = intern (":default-char");
+    plist[9] = args[coding_arg_default_char] = make_number (0);
+    plist[10] = intern (":for-unibyte");
+    plist[11] = args[coding_arg_for_unibyte] = Qt;
+    plist[12] = intern (":docstring");
+    plist[13] = build_string ("Do no conversion.\n\
+\n\
+When you visit a file with this coding, the file is read into a\n\
+unibyte buffer as is, thus each byte of a file is treated as a\n\
+character.");
+    plist[14] = intern (":eol-type");
+    plist[15] = args[coding_arg_eol_type] = Qunix;
+    args[coding_arg_plist] = Flist (16, plist);
+    Fdefine_coding_system_internal (coding_arg_max, args);
+  }
+
+  setup_coding_system (Qno_conversion, &keyboard_coding);
+  setup_coding_system (Qno_conversion, &terminal_coding);
+  setup_coding_system (Qno_conversion, &safe_terminal_coding);
+
+  {
+    int i;
+
+    for (i = 0; i < coding_category_max; i++)
+      Fset (AREF (Vcoding_category_table, i), Qno_conversion);
+  }
 }
 
 char *
@@ -7880,4 +9141,3 @@ emacs_strerror (error_number)
 }
 
 #endif /* emacs */
-