]> code.delx.au - gnu-emacs/blobdiff - src/charset.c
(non_ascii_char_to_string): If C is negative, signal error.
[gnu-emacs] / src / charset.c
index 6134f040663660a1bb2df61e4cd5ed2bdecbd3b3..054b2848894412d1928c95b1d53474b05b8c590e 100644 (file)
@@ -74,9 +74,14 @@ Lisp_Object Vcharset_symbol_table;
 /* A list of charset symbols ever defined.  */
 Lisp_Object Vcharset_list;
 
-/* Vector of unification table ever defined.
-   An ID of a unification table is an index of this vector.  */
-Lisp_Object Vcharacter_unification_table_vector;
+/* Vector of translation table ever defined.
+   ID of a translation table is used to index this vector.  */
+Lisp_Object Vtranslation_table_vector;
+
+/* A char-table for characters which may invoke auto-filling.  */
+Lisp_Object Vauto_fill_chars;
+
+Lisp_Object Qauto_fill_chars;
 
 /* Tables used by macros BYTES_BY_CHAR_HEAD and WIDTH_BY_CHAR_HEAD.  */
 int bytes_by_char_head[256];
@@ -103,7 +108,10 @@ int nonascii_insert_offset;
 
 /* Translation table for converting non-ASCII unibyte characters
    to multibyte codes, or nil.  */
-Lisp_Object Vnonascii_translate_table;
+Lisp_Object Vnonascii_translation_table;
+
+/* List of all possible generic characters.  */
+Lisp_Object Vgeneric_character_list;
 
 #define min(X, Y) ((X) < (Y) ? (X) : (Y))
 #define max(X, Y) ((X) > (Y) ? (X) : (Y))
@@ -112,7 +120,7 @@ void
 invalid_character (c)
      int c;
 {
-  error ("Invalid character: %o, %d, 0x%x", c);
+  error ("Invalid character: 0%o, %d, 0x%x", c, c, c);
 }
 
 
@@ -133,6 +141,9 @@ non_ascii_char_to_string (c, workbuf, str)
 {
   int charset, c1, c2;
 
+  if (c < 0)
+    invalid_character (c);
+
   if (COMPOSITE_CHAR_P (c))
     {
       int cmpchar_id = COMPOSITE_CHAR_ID (c);
@@ -168,51 +179,84 @@ non_ascii_char_to_string (c, workbuf, str)
 
 /* Return a non-ASCII character of which multi-byte form is at STR of
    length LEN.  If ACTUAL_LEN is not NULL, the actual length of the
-   character is set to the address ACTUAL_LEN.
+   multibyte form is set to the address ACTUAL_LEN.
+
+   If exclude_tail_garbage is nonzero, ACTUAL_LEN excludes gabage
+   bytes following the non-ASCII character.
 
    Use macro `STRING_CHAR (STR, LEN)' instead of calling this function
    directly if STR can hold an ASCII character.  */
 
-string_to_non_ascii_char (str, len, actual_len)
-     unsigned char *str;
-     int len, *actual_len;
+int
+string_to_non_ascii_char (str, len, actual_len, exclude_tail_garbage)
+     const unsigned char *str;
+     int len, *actual_len, exclude_tail_garbage;
 {
   int charset;
   unsigned char c1, c2;
-  register int c;
+  int c, bytes;
+  const unsigned char *begp = str;
 
-  if (SPLIT_STRING (str, len, charset, c1, c2) == CHARSET_ASCII)
-    {
-      if (actual_len)
-       *actual_len = 1;
-      return (int) *str;
-    }
+  c = *str++;
+  bytes = 1;
 
-  c = MAKE_NON_ASCII_CHAR (charset, c1, c2);
+  if (BASE_LEADING_CODE_P (c))
+    do {
+      while (bytes < len && ! CHAR_HEAD_P (begp[bytes])) bytes++;
+
+      if (c == LEADING_CODE_COMPOSITION)
+       {
+         int cmpchar_id = str_cmpchar_id (begp, bytes);
+
+         if (cmpchar_id >= 0)
+           {
+             c = MAKE_COMPOSITE_CHAR (cmpchar_id);
+             str += cmpchar_table[cmpchar_id]->len - 1;
+           }
+         else
+           str += bytes - 1;
+       }
+      else
+       {
+         const unsigned char *endp = begp + bytes;
+         int charset = c, c1, c2 = 0;
+
+         if (str >= endp) break;
+         if (c >= LEADING_CODE_PRIVATE_11 && c <= LEADING_CODE_PRIVATE_22)
+           {
+             charset = *str++;
+             if (str < endp)
+               c1 = *str++ & 0x7F;
+             else
+               c1 = charset, charset = c;
+           }
+         else
+           c1 = *str++ & 0x7f;
+         if (CHARSET_DEFINED_P (charset)
+             && CHARSET_DIMENSION (charset) == 2
+             && str < endp)
+           c2 = *str++ & 0x7F;
+         c = MAKE_NON_ASCII_CHAR (charset, c1, c2);
+       }
+    } while (0);
 
   if (actual_len)
-    *actual_len = (charset == CHARSET_COMPOSITION
-                  ? cmpchar_table[COMPOSITE_CHAR_ID (c)]->len
-                  : BYTES_BY_CHAR_HEAD (*str));
+    *actual_len = exclude_tail_garbage ? str - begp : bytes;
   return c;
 }
 
 /* Return the length of the multi-byte form at string STR of length LEN.  */
 int
 multibyte_form_length (str, len)
-     unsigned char *str;
+     const unsigned char *str;
      int len;
 {
-  int charset;
-  unsigned char c1, c2;
-  register int c;
+  int bytes = 1;
 
-  if (SPLIT_STRING (str, len, charset, c1, c2) == CHARSET_ASCII)
-    return 1;
+  if (BASE_LEADING_CODE_P (*str))
+    while (bytes < len && ! CHAR_HEAD_P (str[bytes])) bytes++;
 
-  return (charset == CHARSET_COMPOSITION
-         ? cmpchar_table[(c1 << 7) | c2]->len
-         : BYTES_BY_CHAR_HEAD (*str));
+  return bytes;
 }
 
 /* Check if string STR of length LEN contains valid multi-byte form of
@@ -221,8 +265,10 @@ multibyte_form_length (str, len)
    return -1.  This should be used only in the macro SPLIT_STRING
    which checks range of STR in advance.  */
 
+int
 split_non_ascii_string (str, len, charset, c1, c2)
-     register unsigned char *str, *c1, *c2;
+     register const unsigned char *str;
+     register unsigned char *c1, *c2;
      register int len, *charset;
 {
   register unsigned int cs = *str++;
@@ -254,10 +300,12 @@ split_non_ascii_string (str, len, charset, c1, c2)
   return 0;
 }
 
-/* Return a character unified with C (or a character made of CHARSET,
-   C1, and C2) in unification table TABLE.  If no unification is found
-   in TABLE, return C.  */
-unify_char (table, c, charset, c1, c2)
+/* Translate character C by translation table TABLE.  If C
+   is negative, translate a character specified by CHARSET, C1, and C2
+   (C1 and C2 are code points of the character).  If no translation is
+   found in TABLE, return C.  */
+int
+translate_char (table, c, charset, c1, c2)
      Lisp_Object table;
      int c, charset, c1, c2;
 {
@@ -287,26 +335,77 @@ unify_char (table, c, charset, c1, c2)
 }
 
 /* Convert the unibyte character C to multibyte based on
-   Vnonascii_translate_table or nonascii_insert_offset.  If they can't
+   Vnonascii_translation_table or nonascii_insert_offset.  If they can't
    convert C to a valid multibyte character, convert it based on
    DEFAULT_NONASCII_INSERT_OFFSET which makes C a Latin-1 character.  */
 
+int
 unibyte_char_to_multibyte (c)
      int c;
 {
-  if (c >= 0240 && c < 0400)
+  if (c < 0400)
     {
       int c_save = c;
 
-      if (! NILP (Vnonascii_translate_table))
-       c = XINT (Faref (Vnonascii_translate_table, make_number (c)));
-      else if (nonascii_insert_offset > 0)
-       c += nonascii_insert_offset;
-      if (c >= 0240 && (c < 0400 || ! VALID_MULTIBYTE_CHAR_P (c)))
+      if (! NILP (Vnonascii_translation_table))
+       {
+         c = XINT (Faref (Vnonascii_translation_table, make_number (c)));
+         if (c >= 0400 && ! VALID_MULTIBYTE_CHAR_P (c))
+           c = c_save + DEFAULT_NONASCII_INSERT_OFFSET;
+       }
+      else if (c >= 0240 && nonascii_insert_offset > 0)
+       {
+         c += nonascii_insert_offset;
+         if (c < 0400 || ! VALID_MULTIBYTE_CHAR_P (c))
+           c = c_save + DEFAULT_NONASCII_INSERT_OFFSET;
+       }
+      else if (c >= 0240)
        c = c_save + DEFAULT_NONASCII_INSERT_OFFSET;
     }
   return c;
 }
+
+
+/* Convert the multibyte character C to unibyte 8-bit character based
+   on Vnonascii_translation_table or nonascii_insert_offset.  If
+   REV_TBL is non-nil, it should be a reverse table of
+   Vnonascii_translation_table, i.e. what given by:
+     Fchar_table_extra_slot (Vnonascii_translation_table, make_number (0))  */
+
+int
+multibyte_char_to_unibyte (c, rev_tbl)
+     int c;
+     Lisp_Object rev_tbl;
+{
+  if (!SINGLE_BYTE_CHAR_P (c))
+    {
+      int c_save = c;
+
+      if (! CHAR_TABLE_P (rev_tbl)
+         && CHAR_TABLE_P (Vnonascii_translation_table))
+       rev_tbl = Fchar_table_extra_slot (Vnonascii_translation_table,
+                                         make_number (0));
+      if (CHAR_TABLE_P (rev_tbl))
+       {
+         Lisp_Object temp;
+         temp = Faref (rev_tbl, make_number (c));
+         if (INTEGERP (temp))
+           c = XINT (temp);
+         if (c >= 256)
+           c = (c_save & 0177) + 0200;
+       }
+      else
+       {
+         if (nonascii_insert_offset > 0)
+           c -= nonascii_insert_offset;
+         if (c < 128 || c >= 256)
+           c = (c_save & 0177) + 0200;
+       }
+    }
+
+  return c;
+}
+
 \f
 /* Update the table Vcharset_table with the given arguments (see the
    document of `define-charset' for the meaning of each argument).
@@ -357,6 +456,9 @@ update_charset_table (charset_id, dimension, chars, width, direction,
       leading_code_ext = charset;
     } 
 
+  if (BYTES_BY_CHAR_HEAD (leading_code_base) != bytes)
+    error ("Invalid dimension for the charset-ID %d", charset);
+
   CHARSET_TABLE_INFO (charset, CHARSET_ID_IDX) = charset_id;
   CHARSET_TABLE_INFO (charset, CHARSET_BYTES_IDX) = make_number (bytes);
   CHARSET_TABLE_INFO (charset, CHARSET_DIMENSION_IDX) = dimension;
@@ -406,8 +508,6 @@ update_charset_table (charset_id, dimension, chars, width, direction,
   if (charset != CHARSET_ASCII
       && charset < MIN_CHARSET_PRIVATE_DIMENSION1)
     {
-      /* Update tables bytes_by_char_head and width_by_char_head.  */
-      bytes_by_char_head[leading_code_base] = bytes;
       width_by_char_head[leading_code_base] = XINT (width);
 
       /* Update table emacs_code_class.  */
@@ -485,8 +585,8 @@ WIDTH (integer) is the number of columns a character in the charset\n\
 occupies on the screen: one of 0, 1, and 2.\n\
 \n\
 DIRECTION (integer) is the rendering direction of characters in the\n\
-charset when rendering.  If 0, render from right to left, else\n\
-render from left to right.\n\
+charset when rendering.  If 0, render from left to right, else\n\
+render from right to left.\n\
 \n\
 ISO-FINAL-CHAR (character) is the final character of the\n\
 corresponding ISO 2022 charset.\n\
@@ -548,6 +648,15 @@ DESCRIPTION (string) is the description string of the charset.")
   return Qnil;
 }
 
+DEFUN ("generic-character-list", Fgeneric_character_list,
+       Sgeneric_character_list, 0, 0, 0,
+  "Return a list of all possible generic characters.\n\
+It includes a generic character for a charset not yet defined.")
+  ()
+{
+  return Vgeneric_character_list;
+}
+
 DEFUN ("get-unused-iso-final-char", Fget_unused_iso_final_char,
        Sget_unused_iso_final_char, 2, 2, 0,
   "Return an unsed ISO's final char for a charset of DIMENISION and CHARS.\n\
@@ -608,13 +717,18 @@ CHARSET should be defined by `defined-charset' in advance.")
 /* Return number of different charsets in STR of length LEN.  In
    addition, for each found charset N, CHARSETS[N] is set 1.  The
    caller should allocate CHARSETS (MAX_CHARSET + 1 elements) in advance.
-   It may lookup a unification table TABLE if supplied.  */
+   It may lookup a translation table TABLE if supplied.
+
+   If CMPCHARP is nonzero and some composite character is found,
+   CHARSETS[128] is also set 1 and the returned number is incremented
+   by 1.  */
 
 int
-find_charset_in_str (str, len, charsets, table)
+find_charset_in_str (str, len, charsets, table, cmpcharp)
      unsigned char *str;
      int len, *charsets;
      Lisp_Object table;
+     int cmpcharp;
 {
   register int num = 0, c;
 
@@ -631,18 +745,18 @@ find_charset_in_str (str, len, charsets, table)
          int cmpchar_id = str_cmpchar_id (str, len);
          GLYPH *glyph;
 
-         if (cmpchar_id > 0)
+         if (cmpchar_id >= 0)
            {
-             struct cmpchar_info *cmpcharp = cmpchar_table[cmpchar_id];
+             struct cmpchar_info *cmp_p = cmpchar_table[cmpchar_id];
              int i;
 
-             for (i = 0; i < cmpcharp->glyph_len; i++)
+             for (i = 0; i < cmp_p->glyph_len; i++)
                {
-                 c = cmpcharp->glyph[i];
+                 c = cmp_p->glyph[i];
                  if (!NILP (table))
                    {
-                     if ((c = unify_char (table, c, 0, 0, 0)) < 0)
-                       c = cmpcharp->glyph[i];
+                     if ((c = translate_char (table, c, 0, 0, 0)) < 0)
+                       c = cmp_p->glyph[i];
                    }
                  if ((charset = CHAR_CHARSET (c)) < 0)
                    charset = CHARSET_ASCII;
@@ -652,8 +766,13 @@ find_charset_in_str (str, len, charsets, table)
                      num += 1;
                    }
                }
-             str += cmpcharp->len;
-             len -= cmpcharp->len;
+             str += cmp_p->len;
+             len -= cmp_p->len;
+             if (cmpcharp && !charsets[CHARSET_COMPOSITION])
+               {
+                 charsets[CHARSET_COMPOSITION] = 1;
+                 num += 1;
+               }
              continue;
            }
 
@@ -665,7 +784,7 @@ find_charset_in_str (str, len, charsets, table)
          c = STRING_CHAR_AND_LENGTH (str, len, bytes);
          if (! NILP (table))
            {
-             int c1 = unify_char (table, c, 0, 0, 0);
+             int c1 = translate_char (table, c, 0, 0, 0);
              if (c1 >= 0)
                c = c1;
            }
@@ -687,7 +806,9 @@ DEFUN ("find-charset-region", Ffind_charset_region, Sfind_charset_region,
        2, 3, 0,
   "Return a list of charsets in the region between BEG and END.\n\
 BEG and END are buffer positions.\n\
-Optional arg TABLE if non-nil is a unification table to look up.")
+If the region contains any composite character,\n\
+`composition' is included in the returned list.\n\
+Optional arg TABLE if non-nil is a translation table to look up.")
   (beg, end, table)
      Lisp_Object beg, end, table;
 {
@@ -699,6 +820,11 @@ Optional arg TABLE if non-nil is a unification table to look up.")
   from = XFASTINT (beg);
   stop = to = XFASTINT (end);
 
+  if (NILP (current_buffer->enable_multibyte_characters))
+    return (from == to
+           ? Qnil
+           : Fcons (Qascii, Qnil));
+
   if (from < GPT && GPT < to)
     {
       stop = GPT;
@@ -713,7 +839,7 @@ Optional arg TABLE if non-nil is a unification table to look up.")
   while (1)
     {
       find_charset_in_str (BYTE_POS_ADDR (from_byte), stop_byte - from_byte,
-                          charsets, table);
+                          charsets, table, 1);
       if (stop < to)
        {
          from = stop, from_byte = stop_byte;
@@ -733,7 +859,9 @@ Optional arg TABLE if non-nil is a unification table to look up.")
 DEFUN ("find-charset-string", Ffind_charset_string, Sfind_charset_string,
        1, 2, 0,
   "Return a list of charsets in STR.\n\
-Optional arg TABLE if non-nil is a unification table to look up.")
+If the string contains any composite characters,\n\
+`composition' is included in the returned list.\n\
+Optional arg TABLE if non-nil is a translation table to look up.")
   (str, table)
      Lisp_Object str, table;
 {
@@ -744,11 +872,13 @@ Optional arg TABLE if non-nil is a unification table to look up.")
   CHECK_STRING (str, 0);
 
   if (! STRING_MULTIBYTE (str))
-    return Qnil;
+    return (XSTRING (str)->size == 0
+           ? Qnil
+           : Fcons (Qascii, Qnil));
 
   bzero (charsets, (MAX_CHARSET + 1) * sizeof (int));
-  find_charset_in_str (XSTRING (str)->data, XSTRING (str)->size_byte,
-                      charsets, table);
+  find_charset_in_str (XSTRING (str)->data, STRING_BYTES (XSTRING (str)),
+                      charsets, table, 1);
   val = Qnil;
   for (i = MAX_CHARSET; i >= 0; i--)
     if (charsets[i])
@@ -804,6 +934,30 @@ DEFUN ("char-charset", Fchar_charset, Schar_charset, 1, 1, 0,
   return CHARSET_SYMBOL (CHAR_CHARSET (XINT (ch)));
 }
 
+DEFUN ("charset-after", Fcharset_after, Scharset_after, 0, 1, 0,
+  "Return charset of a character in current buffer at position POS.\n\
+If POS is nil, it defauls to the current point.")
+  (pos)
+     Lisp_Object pos;
+{
+  register int pos_byte, c, charset;
+  register unsigned char *p;
+
+  if (NILP (pos))
+    pos_byte = PT_BYTE;
+  else if (MARKERP (pos))
+    pos_byte = marker_byte_position (pos);
+  else
+    {
+      CHECK_NUMBER (pos, 0);
+      pos_byte = CHAR_TO_BYTE (XINT (pos));
+    }
+  p = BYTE_POS_ADDR (pos_byte);
+  c = STRING_CHAR (p, Z_BYTE - pos_byte);
+  charset = CHAR_CHARSET (c);
+  return CHARSET_SYMBOL (charset);
+}
+
 DEFUN ("iso-charset", Fiso_charset, Siso_charset, 3, 3, 0,
   "Return charset of ISO's specification DIMENSION, CHARS, and FINAL-CHAR.\n\
 \n\
@@ -841,7 +995,7 @@ char_valid_p (c, genericp)
   if (SINGLE_BYTE_CHAR_P (c))
     return 1;
   SPLIT_NON_ASCII_CHAR (c, charset, c1, c2);
-  if (!CHARSET_VALID_P (charset))
+  if (charset != CHARSET_COMPOSITION && !CHARSET_DEFINED_P (charset))
     return 0;
   return (c < MIN_CHAR_COMPOSITION
          ? ((c & CHAR_FIELD1_MASK) /* i.e. dimension of C is two.  */
@@ -867,8 +1021,8 @@ a valid generic character.")
 DEFUN ("unibyte-char-to-multibyte", Funibyte_char_to_multibyte,
        Sunibyte_char_to_multibyte, 1, 1, 0,
   "Convert the unibyte character CH to multibyte character.\n\
-The conversion is done based on nonascii-translate-table (which see)\n\
- or nonascii-insert-offset (which see).")
+The conversion is done based on `nonascii-translation-table' (which see)\n\
+ or `nonascii-insert-offset' (which see).")
   (ch)
      Lisp_Object ch;
 {
@@ -884,30 +1038,60 @@ The conversion is done based on nonascii-translate-table (which see)\n\
   return make_number (c);
 }
 
+DEFUN ("multibyte-char-to-unibyte", Fmultibyte_char_to_unibyte,
+       Smultibyte_char_to_unibyte, 1, 1, 0,
+  "Convert the multibyte character CH to unibyte character.\n\
+The conversion is done based on `nonascii-translation-table' (which see)\n\
+ or `nonascii-insert-offset' (which see).")
+  (ch)
+     Lisp_Object ch;
+{
+  int c;
+
+  CHECK_NUMBER (ch, 0);
+  c = XINT (ch);
+  if (c < 0)
+    error ("Invalid multibyte character: %d", c);
+  c = multibyte_char_to_unibyte (c, Qnil);
+  if (c < 0)
+    error ("Can't convert to unibyte character: %d", XINT (ch));
+  return make_number (c);
+}
+
 DEFUN ("char-bytes", Fchar_bytes, Schar_bytes, 1, 1, 0,
-  "Return byte length of multi-byte form of CHAR.")
+  "Return 1 regardless of the argument CHAR.\n\
+This is now an obsolete function.  We keep it just for backward compatibility.")
   (ch)
      Lisp_Object ch;
 {
   Lisp_Object val;
-  int bytes;
 
   CHECK_NUMBER (ch, 0);
-  if (COMPOSITE_CHAR_P (XFASTINT (ch)))
+  return make_number (1);
+}
+
+/* Return how many bytes C will occupy in a multibyte buffer.
+   Don't call this function directly, instead use macro CHAR_BYTES.  */
+int
+char_bytes (c)
+     int c;
+{
+  int bytes;
+
+  if (COMPOSITE_CHAR_P (c))
     {
-      unsigned int id = COMPOSITE_CHAR_ID (XFASTINT (ch));
+      unsigned int id = COMPOSITE_CHAR_ID (c);
 
       bytes = (id < n_cmpchars ? cmpchar_table[id]->len : 1);
     }
   else
     {
-      int charset = CHAR_CHARSET (XFASTINT (ch));
+      int charset = CHAR_CHARSET (c);
 
       bytes = CHARSET_DEFINED_P (charset) ? CHARSET_BYTES (charset) : 1;
     }
 
-  XSETFASTINT (val, bytes);
-  return val;
+  return bytes;
 }
 
 /* Return the width of character of which multi-byte form starts with
@@ -926,8 +1110,7 @@ DEFUN ("char-bytes", Fchar_bytes, Schar_bytes, 1, 1, 0,
         : ((! NILP (current_buffer->enable_multibyte_characters)       \
             && BASE_LEADING_CODE_P (c))                                \
            ? WIDTH_BY_CHAR_HEAD (c)                                    \
-           : 4))))                                                     \
-
+           : 4))))
 
 DEFUN ("char-width", Fchar_width, Schar_width, 1, 1, 0,
   "Return width of CHAR when displayed in the current buffer.\n\
@@ -997,8 +1180,8 @@ strwidth (str, len)
       else
        {
          Lisp_Object disp;
-         int thiswidth;
-         int c = STRING_CHAR (str, endp - str);
+         int thislen;
+         int c = STRING_CHAR_AND_LENGTH (str, endp - str, thislen);
 
          /* Get the way the display table would display it.  */
          if (dp)
@@ -1007,12 +1190,11 @@ strwidth (str, len)
            disp = Qnil;
 
          if (VECTORP (disp))
-           thiswidth = XVECTOR (disp)->size;
+           width += XVECTOR (disp)->size;
          else
-           thiswidth = ONE_BYTE_CHAR_WIDTH (*str);
+           width += ONE_BYTE_CHAR_WIDTH (*str);
 
-         width += thiswidth;
-         str += BYTES_BY_CHAR_HEAD (*str);
+         str += thislen;
        }
     }
   return width;
@@ -1030,7 +1212,8 @@ the following bytes is not checked.")
   Lisp_Object val;
 
   CHECK_STRING (str, 0);
-  XSETFASTINT (val, strwidth (XSTRING (str)->data, XSTRING (str)->size));
+  XSETFASTINT (val, strwidth (XSTRING (str)->data,
+                             STRING_BYTES (XSTRING (str))));
   return val;
 }
 
@@ -1056,10 +1239,13 @@ DEFUN ("chars-in-region", Fchars_in_region, Schars_in_region, 2, 2, 0,
 {
   int from, to;
 
+  CHECK_NUMBER_COERCE_MARKER (beg, 0);
+  CHECK_NUMBER_COERCE_MARKER (end, 1);
+
   from = min (XFASTINT (beg), XFASTINT (end));
   to = max (XFASTINT (beg), XFASTINT (end));
 
-  return to - from;
+  return make_number (to - from);
 }
 
 /* Return the number of characters in the NBYTES bytes at PTR.
@@ -1149,7 +1335,9 @@ DEFUN ("string", Fstring, Sstring, 1, MANY, 0,
       p += len;
     }
 
-  val = make_multibyte_string (buf, n, p - buf);
+  /* Here, we can't use make_string_from_bytes because of byte
+     combining problem.  */
+  val = make_string (buf, p - buf);
   return val;
 }
 
@@ -1205,7 +1393,7 @@ static int *cmpchar_hash_table[CMPCHAR_HASH_TABLE_SIZE];
    is the sole function for assigning CMPCHAR-ID.  */
 int
 str_cmpchar_id (str, len)
-     unsigned char *str;
+     const unsigned char *str;
      int len;
 {
   int hash_idx, *hashp;
@@ -1220,7 +1408,7 @@ str_cmpchar_id (str, len)
 
   /* At first, get the actual length of the composite character.  */
   {
-    unsigned char *p, *endp = str + 1, *lastp = str + len;
+    const unsigned char *p, *endp = str + 1, *lastp = str + len;
     int bytes;
 
     while (endp < lastp && ! CHAR_HEAD_P (*endp)) endp++;
@@ -1232,7 +1420,12 @@ str_cmpchar_id (str, len)
     p = str + 1;
     while (p < endp)
       {
-       if (embedded_rule) p++;
+       if (embedded_rule)
+         {
+           p++;
+           if (p >= endp)
+             return -1;
+         }
        /* No need of checking if *P is 0xA0 because
           BYTES_BY_CHAR_HEAD (0x80) surely returns 2.  */
        p += BYTES_BY_CHAR_HEAD (*p - 0x20);
@@ -1346,7 +1539,7 @@ str_cmpchar_id (str, len)
            /* Make `bufp' point normal multi-byte form temporally.  */
            *bufp -= 0x20;
            cmpcharp->glyph[i]
-             = FAST_MAKE_GLYPH (string_to_non_ascii_char (bufp, 4, 0), 0);
+             = FAST_MAKE_GLYPH (string_to_non_ascii_char (bufp, 4, 0, 0), 0);
            width = WIDTH_BY_CHAR_HEAD (*bufp);
            *bufp += 0x20;
            bufp += BYTES_BY_CHAR_HEAD (*bufp - 0x20);
@@ -1412,16 +1605,27 @@ str_cmpchar_id (str, len)
   return n_cmpchars++;
 }
 
-/* Return the Nth element of the composite character C.  */
+/* Return the Nth element of the composite character C.  If NOERROR is
+   nonzero, return 0 on error condition (C is an invalid composite
+   charcter, or N is out of range). */
 int
-cmpchar_component (c, n)
-     unsigned int c, n;
+cmpchar_component (c, n, noerror)
+     int c, n, noerror;
 {
   int id = COMPOSITE_CHAR_ID (c);
 
-  if (id >= n_cmpchars         /* C is not a valid composite character.  */
-      || n >= cmpchar_table[id]->glyph_len) /* No such component.  */
-    return -1;
+  if (id < 0 || id >= n_cmpchars)
+    {
+      /* C is not a valid composite character.  */
+      if (noerror) return 0;
+      error ("Invalid composite character: %d", c)  ;
+    }
+  if (n >= cmpchar_table[id]->glyph_len)
+    {
+      /* No such component.  */
+      if (noerror) return 0;
+      args_out_of_range (make_number (c), make_number (n));
+    }
   /* No face data is stored in glyph code.  */
   return ((int) (cmpchar_table[id]->glyph[n]));
 }
@@ -1437,30 +1641,28 @@ DEFUN ("cmpcharp", Fcmpcharp, Scmpcharp, 1, 1, 0,
 
 DEFUN ("composite-char-component", Fcmpchar_component, Scmpchar_component,
        2, 2, 0,
-  "Return the IDXth component character of composite character CHARACTER.")
-  (character, idx)
-     Lisp_Object character, idx;
+  "Return the Nth component character of composite character CHARACTER.")
+  (character, n)
+     Lisp_Object character, n;
 {
-  int c;
+  int id;
 
   CHECK_NUMBER (character, 0);
-  CHECK_NUMBER (idx, 1);
-
-  if ((c = cmpchar_component (XINT (character), XINT (idx))) < 0)
-    args_out_of_range (character, idx);
+  CHECK_NUMBER (n, 1);
 
-  return make_number (c);
+  return (make_number (cmpchar_component (XINT (character), XINT (n), 0)));
 }
 
 DEFUN ("composite-char-composition-rule", Fcmpchar_cmp_rule, Scmpchar_cmp_rule,
        2, 2, 0,
-  "Return the Nth composition rule embedded in composite character CHARACTER.\n\
+  "Return the Nth composition rule of composite character CHARACTER.\n\
 The returned rule is for composing the Nth component\n\
-on the (N-1)th component.  If N is 0, the returned value is always 255.")
+on the (N-1)th component.\n\
+If CHARACTER should be composed relatively or N is 0, return 255.")
   (character, n)
      Lisp_Object character, n;
 {
-  int id, i;
+  int id;
 
   CHECK_NUMBER (character, 0);
   CHECK_NUMBER (n, 1);
@@ -1468,11 +1670,12 @@ on the (N-1)th component.  If N is 0, the returned value is always 255.")
   id = COMPOSITE_CHAR_ID (XINT (character));
   if (id < 0 || id >= n_cmpchars)
     error ("Invalid composite character: %d", XINT (character));
-  i = XINT (n);
-  if (i > cmpchar_table[id]->glyph_len)
+  if (XINT (n) < 0 || XINT (n) >= cmpchar_table[id]->glyph_len)
     args_out_of_range (character, n);
 
-  return make_number (cmpchar_table[id]->cmp_rule[i]);
+  return make_number (cmpchar_table[id]->cmp_rule
+                     ? cmpchar_table[id]->cmp_rule[XINT (n)]
+                     : 255);
 }
 
 DEFUN ("composite-char-composition-rule-p", Fcmpchar_cmp_rule_p,
@@ -1520,11 +1723,11 @@ DEFUN ("compose-string", Fcompose_string, Scompose_string,
 
   buf[0] = LEADING_CODE_COMPOSITION;
   p = XSTRING (str)->data;
-  pend = p + XSTRING (str)->size_byte;
+  pend = p + STRING_BYTES (XSTRING (str));
   i = 1;
   while (p < pend)
     {
-      if (*p < 0x20 || *p == 127) /* control code */
+      if (*p < 0x20) /* control code */
        error ("Invalid component character: %d", *p);
       else if (*p < 0x80)      /* ASCII */
        {
@@ -1541,8 +1744,12 @@ DEFUN ("compose-string", Fcompose_string, Scompose_string,
              LEADING_CODE_COMPOSITION, keep the remaining bytes
              unchanged.  */
          p++;
+         if (*p == 255)
+           error ("Can't compose a rule-based composition character");
          ptemp = p;
          while (! CHAR_HEAD_P (*p)) p++;
+         if (str_cmpchar_id (ptemp - 1, p - ptemp + 1) < 0)
+           error ("Can't compose an invalid composition character");
          if (i + (p - ptemp) >= MAX_LENGTH_OF_MULTI_BYTE_FORM)
            error ("Too long string to be composed: %s", XSTRING (str)->data);
          bcopy (ptemp, buf + i, p - ptemp);
@@ -1552,7 +1759,10 @@ DEFUN ("compose-string", Fcompose_string, Scompose_string,
        {
          /* Add 0x20 to the base leading-code, keep the remaining
              bytes unchanged.  */
-         len = BYTES_BY_CHAR_HEAD (*p);
+         int c = STRING_CHAR_AND_CHAR_LENGTH (p, pend - p, len);
+
+         if (len <= 1 || ! CHAR_VALID_P (c, 0))
+           error ("Can't compose an invalid character");
          if (i + len >= MAX_LENGTH_OF_MULTI_BYTE_FORM)
            error ("Too long string to be composed: %s", XSTRING (str)->data);
          bcopy (p, buf + i, len);
@@ -1565,15 +1775,17 @@ DEFUN ("compose-string", Fcompose_string, Scompose_string,
     /* STR contains only one character, which can't be composed.  */
     error ("Too short string to be composed: %s", XSTRING (str)->data);
 
-  return make_multibyte_string (buf, 1, i);
+  return make_string_from_bytes (buf, 1, i);
 }
 
 \f
+int
 charset_id_internal (charset_name)
      char *charset_name;
 {
-  Lisp_Object val = Fget (intern (charset_name), Qcharset);
+  Lisp_Object val;
 
+  val= Fget (intern (charset_name), Qcharset);
   if (!VECTORP (val))
     error ("Charset %s is not defined", charset_name);
 
@@ -1594,12 +1806,14 @@ DEFUN ("setup-special-charsets", Fsetup_special_charsets,
   return Qnil;
 }
 
+void
 init_charset_once ()
 {
   int i, j, k;
 
   staticpro (&Vcharset_table);
   staticpro (&Vcharset_symbol_table);
+  staticpro (&Vgeneric_character_list);
 
   /* This has to be done here, before we call Fmake_char_table.  */
   Qcharset_table = intern ("charset-table");
@@ -1628,13 +1842,21 @@ init_charset_once ()
 
   for (i = 0; i < 256; i++)
     BYTES_BY_CHAR_HEAD (i) = 1;
+  for (i = MIN_CHARSET_OFFICIAL_DIMENSION1;
+       i <= MAX_CHARSET_OFFICIAL_DIMENSION1; i++)
+    BYTES_BY_CHAR_HEAD (i) = 2;
+  for (i = MIN_CHARSET_OFFICIAL_DIMENSION2;
+       i <= MAX_CHARSET_OFFICIAL_DIMENSION2; i++)
+    BYTES_BY_CHAR_HEAD (i) = 3;
   BYTES_BY_CHAR_HEAD (LEADING_CODE_PRIVATE_11) = 3;
   BYTES_BY_CHAR_HEAD (LEADING_CODE_PRIVATE_12) = 3;
   BYTES_BY_CHAR_HEAD (LEADING_CODE_PRIVATE_21) = 4;
   BYTES_BY_CHAR_HEAD (LEADING_CODE_PRIVATE_22) = 4;
-  /* The following doesn't reflect the actual bytes, but just to tell
+  /* The followings don't reflect the actual bytes, but just to tell
      that it is a start of a multibyte character.  */
   BYTES_BY_CHAR_HEAD (LEADING_CODE_COMPOSITION) = 2;
+  BYTES_BY_CHAR_HEAD (0x9E) = 2;
+  BYTES_BY_CHAR_HEAD (0x9F) = 2;
 
   for (i = 0; i < 128; i++)
     WIDTH_BY_CHAR_HEAD (i) = 1;
@@ -1644,10 +1866,30 @@ init_charset_once ()
   WIDTH_BY_CHAR_HEAD (LEADING_CODE_PRIVATE_12) = 2;
   WIDTH_BY_CHAR_HEAD (LEADING_CODE_PRIVATE_21) = 1;
   WIDTH_BY_CHAR_HEAD (LEADING_CODE_PRIVATE_22) = 2;
+
+  {
+    Lisp_Object val;
+
+    val = Qnil;
+    for (i = 0x81; i < 0x90; i++)
+      val = Fcons (make_number ((i - 0x70) << 7), val);
+    for (; i < 0x9A; i++)
+      val = Fcons (make_number ((i - 0x8F) << 14), val);
+    for (i = 0xA0; i < 0xF0; i++)
+      val = Fcons (make_number ((i - 0x70) << 7), val);
+    for (; i < 0xFF; i++)
+      val = Fcons (make_number ((i - 0xE0) << 14), val);
+    val = Fcons (make_number (GENERIC_COMPOSITION_CHAR), val);
+    Vgeneric_character_list = Fnreverse (val);
+  }
+
+  nonascii_insert_offset = 0;
+  Vnonascii_translation_table = Qnil;
 }
 
 #ifdef emacs
 
+void
 syms_of_charset ()
 {
   Qascii = intern ("ascii");
@@ -1673,7 +1915,12 @@ syms_of_charset ()
   staticpro (&Qcomposition);
   CHARSET_SYMBOL (CHARSET_COMPOSITION) = Qcomposition;
 
+  Qauto_fill_chars = intern ("auto-fill-chars");
+  staticpro (&Qauto_fill_chars);
+  Fput (Qauto_fill_chars, Qchar_table_extra_slots, make_number (0));
+
   defsubr (&Sdefine_charset);
+  defsubr (&Sgeneric_character_list);
   defsubr (&Sget_unused_iso_final_char);
   defsubr (&Sdeclare_equiv_charset);
   defsubr (&Sfind_charset_region);
@@ -1681,9 +1928,11 @@ syms_of_charset ()
   defsubr (&Smake_char_internal);
   defsubr (&Ssplit_char);
   defsubr (&Schar_charset);
+  defsubr (&Scharset_after);
   defsubr (&Siso_charset);
   defsubr (&Schar_valid_p);
   defsubr (&Sunibyte_char_to_multibyte);
+  defsubr (&Smultibyte_char_to_unibyte);
   defsubr (&Schar_bytes);
   defsubr (&Schar_width);
   defsubr (&Sstring_width);
@@ -1702,11 +1951,10 @@ syms_of_charset ()
     "List of charsets ever defined.");
   Vcharset_list = Fcons (Qascii, Qnil);
 
-  DEFVAR_LISP ("character-unification-table-vector",
-              &Vcharacter_unification_table_vector,
-    "Vector of cons cell of a symbol and unification table ever defined.\n\
-An ID of a unification table is an index of this vector.");
-  Vcharacter_unification_table_vector = Fmake_vector (make_number (16), Qnil);
+  DEFVAR_LISP ("translation-table-vector",  &Vtranslation_table_vector,
+    "Vector of cons cell of a symbol and translation table ever defined.\n\
+An ID of a translation table is an index of this vector.");
+  Vtranslation_table_vector = Fmake_vector (make_number (16), Qnil);
 
   DEFVAR_INT ("leading-code-composition", &leading_code_composition,
     "Leading-code of composite characters.");
@@ -1732,25 +1980,34 @@ An ID of a unification table is an index of this vector.");
     "Offset for converting non-ASCII unibyte codes 0240...0377 to multibyte.\n\
 This is used for converting unibyte text to multibyte,\n\
 and for inserting character codes specified by number.\n\n\
-Conversion is performed only when multibyte characters are enabled,\n\
-and it serves to convert a Latin-1 or similar 8-bit character code\n\
-to the corresponding Emacs character code.\n\
-If `nonascii-translate-table' is non-nil, it overrides this variable.");
+This serves to convert a Latin-1 or similar 8-bit character code\n\
+to the corresponding Emacs multibyte character code.\n\
+Typically the value should be (- (make-char CHARSET 0) 128),\n\
+for your choice of character set.\n\
+If `nonascii-translation-table' is non-nil, it overrides this variable.");
   nonascii_insert_offset = 0;
 
-  DEFVAR_LISP ("nonascii-translate-table", &Vnonascii_translate_table,
-    "Translate table for converting non-ASCII unibyte codes to multibyte.\n\
+  DEFVAR_LISP ("nonascii-translation-table", &Vnonascii_translation_table,
+    "Translation table to convert non-ASCII unibyte codes to multibyte.\n\
 This is used for converting unibyte text to multibyte,\n\
 and for inserting character codes specified by number.\n\n\
 Conversion is performed only when multibyte characters are enabled,\n\
 and it serves to convert a Latin-1 or similar 8-bit character code\n\
 to the corresponding Emacs character code.\n\n\
-If this is nil, `nonascii-insert-offset' is used instead.");
-  Vnonascii_translate_table = Qnil;
+If this is nil, `nonascii-insert-offset' is used instead.\n\
+See also the docstring of `make-translation-table'.");
+  Vnonascii_translation_table = Qnil;
 
   DEFVAR_INT ("min-composite-char", &min_composite_char,
     "Minimum character code of a composite character.");
   min_composite_char = MIN_CHAR_COMPOSITION;
+
+  DEFVAR_LISP ("auto-fill-chars", &Vauto_fill_chars,
+    "A char-table for characters which invoke auto-filling.\n\
+Such characters has value t in this table.");
+  Vauto_fill_chars = Fmake_char_table (Qauto_fill_chars, Qnil);
+  CHAR_TABLE_SET (Vauto_fill_chars, make_number (' '), Qt);
+  CHAR_TABLE_SET (Vauto_fill_chars, make_number ('\n'), Qt);
 }
 
 #endif /* emacs */