* xdisp.c (init_xdisp): Initialize echo_area_window (Bug#6451).
[bpt/emacs.git] / src / charset.c
index 1cbfa2f..9ea1366 100644 (file)
@@ -1,8 +1,8 @@
 /* Basic character set support.
    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-     2008, 2009  Free Software Foundation, Inc.
+     2008, 2009, 2010, 2011  Free Software Foundation, Inc.
    Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-     2005, 2006, 2007, 2008, 2009
+     2005, 2006, 2007, 2008, 2009, 2010, 2011
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H14PRO021
 
@@ -28,9 +28,11 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <config.h>
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <ctype.h>
 #include <sys/types.h>
+#include <setjmp.h>
 #include "lisp.h"
 #include "character.h"
 #include "charset.h"
@@ -87,6 +89,7 @@ int charset_emacs;
 int charset_jisx0201_roman;
 int charset_jisx0208_1978;
 int charset_jisx0208;
+int charset_ksc5601;
 
 /* Value of charset attribute `charset-iso-plane'.  */
 Lisp_Object Qgl, Qgr;
@@ -112,7 +115,7 @@ Lisp_Object Viso_2022_charset_list;
 /* List of emacs-mule charsets.  */
 Lisp_Object Vemacs_mule_charset_list;
 
-struct charset *emacs_mule_charset[256];
+int emacs_mule_charset[256];
 
 /* Mapping table from ISO2022's charset (specified by DIMENSION,
    CHARS, and FINAL-CHAR) to Emacs' charset.  */
@@ -318,7 +321,6 @@ load_charset_map (charset, entries, n_entries, control_flag)
            {
              memset (temp_charset_work->table.decoder, -1,
                      sizeof (int) * 0x10000);
-             temp_charset_work->for_encoder = 0;
            }
          else
            {
@@ -436,7 +438,7 @@ load_charset_map (charset, entries, n_entries, control_flag)
 
 
 /* Read a hexadecimal number (preceded by "0x") from the file FP while
-   paying attention to comment charcter '#'.  */
+   paying attention to comment character '#'.  */
 
 static INLINE unsigned
 read_hex (fp, eof)
@@ -493,8 +495,8 @@ extern Lisp_Object Qfile_name_handler_alist;
    where CODE1 is a code-point or a cons of code-points specifying a
    range.
 
-   Note that this funciton uses `openp' to open MAPFILE but ignores
-   `file-name-handler-alist to avoid running any Lisp codes.  */
+   Note that this function uses `openp' to open MAPFILE but ignores
+   `file-name-handler-alist' to avoid running any Lisp code.  */
 
 extern void add_to_log P_ ((char *, Lisp_Object, Lisp_Object));
 
@@ -511,24 +513,27 @@ load_charset_map_from_file (charset, mapfile, control_flag)
   int eof;
   Lisp_Object suffixes;
   struct charset_map_entries *head, *entries;
-  int n_entries;
-  int count = SPECPDL_INDEX ();
+  int n_entries, count;
+  USE_SAFE_ALLOCA;
 
   suffixes = Fcons (build_string (".map"),
                    Fcons (build_string (".TXT"), Qnil));
 
+  count = SPECPDL_INDEX ();
   specbind (Qfile_name_handler_alist, Qnil);
   fd = openp (Vcharset_map_path, mapfile, suffixes, NULL, Qnil);
   unbind_to (count, Qnil);
   if (fd < 0
       || ! (fp = fdopen (fd, "r")))
-    {
-      add_to_log ("Failure in loading charset map: %S", mapfile, Qnil);
-      return;
-    }
+    error ("Failure in loading charset map: %S", SDATA (mapfile));
+
+  /* Use SAFE_ALLOCA instead of alloca, as `charset_map_entries' is
+     large (larger than MAX_ALLOCA).  */
+  SAFE_ALLOCA (head, struct charset_map_entries *,
+              sizeof (struct charset_map_entries));
+  entries = head;
+  bzero (entries, sizeof (struct charset_map_entries));
 
-  head = entries = ((struct charset_map_entries *)
-                   alloca (sizeof (struct charset_map_entries)));
   n_entries = 0;
   eof = 0;
   while (1)
@@ -551,9 +556,10 @@ load_charset_map_from_file (charset, mapfile, control_flag)
 
       if (n_entries > 0 && (n_entries % 0x10000) == 0)
        {
-         entries->next = ((struct charset_map_entries *)
-                          alloca (sizeof (struct charset_map_entries)));
+         SAFE_ALLOCA (entries->next, struct charset_map_entries *,
+                      sizeof (struct charset_map_entries));
          entries = entries->next;
+         bzero (entries, sizeof (struct charset_map_entries));
        }
       idx = n_entries % 0x10000;
       entries->entry[idx].from = from;
@@ -565,6 +571,7 @@ load_charset_map_from_file (charset, mapfile, control_flag)
   close (fd);
 
   load_charset_map (charset, head, n_entries, control_flag);
+  SAFE_FREE ();
 }
 
 static void
@@ -579,6 +586,7 @@ load_charset_map_from_vector (charset, vec, control_flag)
   int n_entries;
   int len = ASIZE (vec);
   int i;
+  USE_SAFE_ALLOCA;
 
   if (len % 2 == 1)
     {
@@ -586,8 +594,13 @@ load_charset_map_from_vector (charset, vec, control_flag)
       return;
     }
 
-  head = entries = ((struct charset_map_entries *)
-                   alloca (sizeof (struct charset_map_entries)));
+  /* Use SAFE_ALLOCA instead of alloca, as `charset_map_entries' is
+     large (larger than MAX_ALLOCA).  */
+  SAFE_ALLOCA (head, struct charset_map_entries *,
+              sizeof (struct charset_map_entries));
+  entries = head;
+  bzero (entries, sizeof (struct charset_map_entries));
+
   n_entries = 0;
   for (i = 0; i < len; i += 2)
     {
@@ -620,9 +633,10 @@ load_charset_map_from_vector (charset, vec, control_flag)
 
       if (n_entries > 0 && (n_entries % 0x10000) == 0)
        {
-         entries->next = ((struct charset_map_entries *)
-                          alloca (sizeof (struct charset_map_entries)));
+         SAFE_ALLOCA (entries->next, struct charset_map_entries *,
+                      sizeof (struct charset_map_entries));
          entries = entries->next;
+         bzero (entries, sizeof (struct charset_map_entries));
        }
       idx = n_entries % 0x10000;
       entries->entry[idx].from = from;
@@ -632,6 +646,7 @@ load_charset_map_from_vector (charset, vec, control_flag)
     }
 
   load_charset_map (charset, head, n_entries, control_flag);
+  SAFE_FREE ();
 }
 
 
@@ -648,7 +663,7 @@ load_charset (charset, control_flag)
   if (inhibit_load_charset_map
       && temp_charset_work
       && charset == temp_charset_work->current
-      && (control_flag == 2 == temp_charset_work->for_encoder))
+      && ((control_flag == 2) == temp_charset_work->for_encoder))
     return;
 
   if (CHARSET_METHOD (charset) == CHARSET_METHOD_MAP)
@@ -731,6 +746,7 @@ map_charset_for_dump (c_function, function, arg, from, to)
        }
       c++;
     }
+  UNGCPRO;
 }
 
 void
@@ -811,8 +827,8 @@ map_charset_chars (c_function, function, arg,
 
          charset = CHARSET_FROM_ID (XFASTINT (XCAR (XCAR (parents))));
          offset = XINT (XCDR (XCAR (parents)));
-         this_from = from - offset;
-         this_to = to - offset;
+         this_from = from > offset ? from - offset : 0;
+         this_to = to > offset ? to - offset : 0;
          if (this_from < CHARSET_MIN_CODE (charset))
            this_from = CHARSET_MIN_CODE (charset);
          if (this_to > CHARSET_MAX_CODE (charset))
@@ -832,7 +848,7 @@ RANGE is a cons (FROM .  TO), where FROM and TO indicate a range of
 characters contained in CHARSET.
 
 The optional 4th and 5th arguments FROM-CODE and TO-CODE specify the
-range of code points of target characters.  */)
+range of code points (in CHARSET) of target characters.  */)
      (function, charset, arg, from_code, to_code)
        Lisp_Object function, charset, arg, from_code, to_code;
 {
@@ -1084,6 +1100,8 @@ usage: (define-charset-internal ...)  */)
       i = (i >> 12) << 12;
       for (; i <= charset.max_char; i += 0x1000)
        CHARSET_FAST_MAP_SET (i, charset.fast_map);
+      if (charset.code_offset == 0 && charset.max_char >= 0x80)
+       charset.ascii_compatible_p = 1;
     }
   else if (! NILP (args[charset_arg_map]))
     {
@@ -1224,11 +1242,13 @@ usage: (define-charset-internal ...)  */)
        charset_jisx0208_1978 = id;
       else if (ISO_CHARSET_TABLE (2, 0, 'B') == id)
        charset_jisx0208 = id;
+      else if (ISO_CHARSET_TABLE (2, 0, 'C') == id)
+       charset_ksc5601 = id;
     }
 
   if (charset.emacs_mule_id >= 0)
     {
-      emacs_mule_charset[charset.emacs_mule_id] = CHARSET_FROM_ID (id);
+      emacs_mule_charset[charset.emacs_mule_id] = id;
       if (charset.emacs_mule_id < 0xA0)
        emacs_mule_bytes[charset.emacs_mule_id] = charset.dimension + 1;
       else
@@ -1320,19 +1340,19 @@ define_charset_internal (name, dimension, code_space, min_code, max_code,
   args[charset_arg_superset] = Qnil;
   args[charset_arg_unify_map] = Qnil;
 
-  plist[0] = intern (":name");
+  plist[0] = intern_c_string (":name");
   plist[1] = args[charset_arg_name];
-  plist[2] = intern (":dimension");
+  plist[2] = intern_c_string (":dimension");
   plist[3] = args[charset_arg_dimension];
-  plist[4] = intern (":code-space");
+  plist[4] = intern_c_string (":code-space");
   plist[5] = args[charset_arg_code_space];
-  plist[6] = intern (":iso-final-char");
+  plist[6] = intern_c_string (":iso-final-char");
   plist[7] = args[charset_arg_iso_final];
-  plist[8] = intern (":emacs-mule-id");
+  plist[8] = intern_c_string (":emacs-mule-id");
   plist[9] = args[charset_arg_emacs_mule_id];
-  plist[10] = intern (":ascii-compatible-p");
+  plist[10] = intern_c_string (":ascii-compatible-p");
   plist[11] = args[charset_arg_ascii_compatible_p];
-  plist[12] = intern (":code-offset");
+  plist[12] = intern_c_string (":code-offset");
   plist[13] = args[charset_arg_code_offset];
 
   args[charset_arg_plist] = Flist (14, plist);
@@ -1796,7 +1816,7 @@ encode_char (charset, c)
 
   if (CHARSET_UNIFIED_P (charset))
     {
-      Lisp_Object deunifier, deunified;
+      Lisp_Object deunifier;
       int code_index = -1;
 
       deunifier = CHARSET_DEUNIFIER (charset);
@@ -2120,23 +2140,22 @@ that case, find the charset from what supported by that coding system.  */)
     charset = CHAR_CHARSET (XINT (ch));
   else
     {
-      Lisp_Object charset_list;
-
       if (CONSP (restriction))
        {
-         for (charset_list = Qnil; CONSP (restriction);
-              restriction = XCDR (restriction))
+         int c = XFASTINT (ch);
+
+         for (; CONSP (restriction); restriction = XCDR (restriction))
            {
-             int id;
+             struct charset *charset;
 
-             CHECK_CHARSET_GET_ID (XCAR (restriction), id);
-             charset_list = Fcons (make_number (id), charset_list);
+             CHECK_CHARSET_GET_CHARSET (XCAR (restriction), charset);
+             if (ENCODE_CHAR (charset, c) != CHARSET_INVALID_CODE (charset))
+               return XCAR (restriction);
            }
-         charset_list = Fnreverse (charset_list);
+         return Qnil;
        }
-      else
-       charset_list = coding_system_charset_list (restriction);
-      charset = char_charset (XINT (ch), charset_list, NULL);
+      restriction = coding_system_charset_list (restriction);
+      charset = char_charset (XINT (ch), restriction, NULL);
       if (! charset)
        return Qnil;
     }
@@ -2194,10 +2213,6 @@ Clear temporary charset mapping tables.
 It should be called only from temacs invoked for dumping.  */)
      ()
 {
-  int i;
-  struct charset *charset;
-  Lisp_Object attrs;
-
   if (temp_charset_work)
     {
       free (temp_charset_work);
@@ -2258,6 +2273,7 @@ usage: (set-charset-priority &rest charsets)  */)
   Vcharset_ordered_list = Fnconc (2, arglist);
   charset_ordered_list_tick++;
 
+  charset_unibyte = -1;
   for (old_list = Vcharset_ordered_list, list_2022 = list_emacs_mule = Qnil;
        CONSP (old_list); old_list = XCDR (old_list))
     {
@@ -2265,9 +2281,20 @@ usage: (set-charset-priority &rest charsets)  */)
        list_2022 = Fcons (XCAR (old_list), list_2022);
       if (! NILP (Fmemq (XCAR (old_list), Vemacs_mule_charset_list)))
        list_emacs_mule = Fcons (XCAR (old_list), list_emacs_mule);
+      if (charset_unibyte < 0)
+       {
+         struct charset *charset = CHARSET_FROM_ID (XINT (XCAR (old_list)));
+
+         if (CHARSET_DIMENSION (charset) == 1
+             && CHARSET_ASCII_COMPATIBLE_P (charset)
+             && CHARSET_MAX_CHAR (charset) >= 0x80)
+           charset_unibyte = CHARSET_ID (charset);
+       }
     }
   Viso_2022_charset_list = Fnreverse (list_2022);
   Vemacs_mule_charset_list = Fnreverse (list_emacs_mule);
+  if (charset_unibyte < 0)
+    charset_unibyte = charset_iso_8859_1;
 
   return Qnil;
 }
@@ -2285,13 +2312,76 @@ Return charset identification number of CHARSET.  */)
   return make_number (id);
 }
 
+struct charset_sort_data
+{
+  Lisp_Object charset;
+  int id;
+  int priority;
+};
+
+static int
+charset_compare (const void *d1, const void *d2)
+{
+  const struct charset_sort_data *data1 = d1, *data2 = d2;
+  return (data1->priority - data2->priority);
+}
+
+DEFUN ("sort-charsets", Fsort_charsets, Ssort_charsets, 1, 1, 0,
+       doc: /* Sort charset list CHARSETS by a priority of each charset.
+Return the sorted list.  CHARSETS is modified by side effects.
+See also `charset-priority-list' and `set-charset-priority'.  */)
+     (Lisp_Object charsets)
+{
+  Lisp_Object len = Flength (charsets);
+  int n = XFASTINT (len), i, j, done;
+  Lisp_Object tail, elt, attrs;
+  struct charset_sort_data *sort_data;
+  int id, min_id, max_id;
+  USE_SAFE_ALLOCA;
+
+  if (n == 0)
+    return Qnil;
+  SAFE_ALLOCA (sort_data, struct charset_sort_data *, sizeof (*sort_data) * n);
+  for (tail = charsets, i = 0; CONSP (tail); tail = XCDR (tail), i++)
+    {
+      elt = XCAR (tail);
+      CHECK_CHARSET_GET_ATTR (elt, attrs);
+      sort_data[i].charset = elt;
+      sort_data[i].id = id = XINT (CHARSET_ATTR_ID (attrs));
+      if (i == 0)
+       min_id = max_id = id;
+      else if (id < min_id)
+       min_id = id;
+      else if (id > max_id)
+       max_id = id;
+    }
+  for (done = 0, tail = Vcharset_ordered_list, i = 0;
+       done < n && CONSP (tail); tail = XCDR (tail), i++)
+    {
+      elt = XCAR (tail);
+      id = XFASTINT (elt);
+      if (id >= min_id && id <= max_id)
+       for (j = 0; j < n; j++)
+         if (sort_data[j].id == id)
+           {
+             sort_data[j].priority = i;
+             done++;
+           }
+    }
+  qsort (sort_data, n, sizeof *sort_data, charset_compare);
+  for (i = 0, tail = charsets; CONSP (tail); tail = XCDR (tail), i++)
+    XSETCAR (tail, sort_data[i].charset);
+  SAFE_FREE ();
+  return charsets;
+}
+
 \f
 void
 init_charset ()
 {
   Lisp_Object tempdir;
   tempdir = Fexpand_file_name (build_string ("charsets"), Vdata_directory);
-  if (access (SDATA (tempdir), 0) < 0)
+  if (access ((char *) SDATA (tempdir), 0) < 0)
     {
       dir_warning ("Error: charsets directory (%s) does not exist.\n\
 Emacs will not function correctly without the character map files.\n\
@@ -2315,16 +2405,12 @@ init_charset_once ()
        iso_charset_table[i][j][k] = -1;
 
   for (i = 0; i < 256; i++)
-    emacs_mule_charset[i] = NULL;
+    emacs_mule_charset[i] = -1;
 
   charset_jisx0201_roman = -1;
   charset_jisx0208_1978 = -1;
   charset_jisx0208 = -1;
-
-  for (i = 0; i < 128; i++)
-    unibyte_to_multibyte_table[i] = i;
-  for (; i < 256; i++)
-    unibyte_to_multibyte_table[i] = BYTE8_TO_CHAR (i);
+  charset_ksc5601 = -1;
 }
 
 #ifdef emacs
@@ -2391,6 +2477,7 @@ syms_of_charset ()
   defsubr (&Scharset_priority_list);
   defsubr (&Sset_charset_priority);
   defsubr (&Scharset_id_internal);
+  defsubr (&Ssort_charsets);
 
   DEFVAR_LISP ("charset-map-path", &Vcharset_map_path,
               doc: /* *List of directories to search for charset map files.  */);
@@ -2426,6 +2513,7 @@ the value may be a list of mnemonics.  */);
     = define_charset_internal (Qeight_bit, 1, "\x80\xFF\x00\x00\x00\x00",
                               128, 255, -1, 0, -1, 0, 1,
                               MAX_5_BYTE_CHAR + 1);
+  charset_unibyte = charset_iso_8859_1;
 }
 
 #endif /* emacs */