Merge from mainline.
[bpt/emacs.git] / src / charset.c
index b2b5287..125c913 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  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
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H14PRO021
 
@@ -31,6 +31,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <unistd.h>
 #include <ctype.h>
 #include <sys/types.h>
+#include <setjmp.h>
 #include "lisp.h"
 #include "character.h"
 #include "charset.h"
@@ -87,6 +88,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;
@@ -318,7 +320,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
            {
@@ -477,6 +478,7 @@ read_hex (fp, eof)
   return n;
 }
 
+extern Lisp_Object Qfile_name_handler_alist;
 
 /* Return a mapping vector for CHARSET loaded from MAPFILE.
    Each line of MAPFILE has this form
@@ -490,7 +492,10 @@ read_hex (fp, eof)
    The returned vector has this form:
        [ CODE1 CHAR1 CODE2 CHAR2 .... ]
    where CODE1 is a code-point or a cons of code-points specifying a
-   range.  */
+   range.
+
+   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));
 
@@ -507,21 +512,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 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)
@@ -544,9 +555,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;
@@ -558,6 +570,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
@@ -572,6 +585,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)
     {
@@ -579,8 +593,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)
     {
@@ -613,9 +632,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;
@@ -625,6 +645,7 @@ load_charset_map_from_vector (charset, vec, control_flag)
     }
 
   load_charset_map (charset, head, n_entries, control_flag);
+  SAFE_FREE ();
 }
 
 
@@ -641,7 +662,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)
@@ -724,6 +745,7 @@ map_charset_for_dump (c_function, function, arg, from, to)
        }
       c++;
     }
+  UNGCPRO;
 }
 
 void
@@ -804,8 +826,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))
@@ -825,7 +847,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;
 {
@@ -1077,6 +1099,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]))
     {
@@ -1217,6 +1241,8 @@ 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)
@@ -1313,19 +1339,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);
@@ -1789,7 +1815,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);
@@ -2098,15 +2124,41 @@ CH in the charset.  */)
 }
 
 
-DEFUN ("char-charset", Fchar_charset, Schar_charset, 1, 1, 0,
-       doc: /* Return the charset of highest priority that contains CH.  */)
-     (ch)
-     Lisp_Object ch;
+DEFUN ("char-charset", Fchar_charset, Schar_charset, 1, 2, 0,
+       doc: /* Return the charset of highest priority that contains CH.
+If optional 2nd arg RESTRICTION is non-nil, it is a list of charsets
+from which to find the charset.  It may also be a coding system.  In
+that case, find the charset from what supported by that coding system.  */)
+     (ch, restriction)
+     Lisp_Object ch, restriction;
 {
   struct charset *charset;
 
   CHECK_CHARACTER (ch);
-  charset = CHAR_CHARSET (XINT (ch));
+  if (NILP (restriction))
+    charset = CHAR_CHARSET (XINT (ch));
+  else
+    {
+      Lisp_Object charset_list;
+
+      if (CONSP (restriction))
+       {
+         for (charset_list = Qnil; CONSP (restriction);
+              restriction = XCDR (restriction))
+           {
+             int id;
+
+             CHECK_CHARSET_GET_ID (XCAR (restriction), id);
+             charset_list = Fcons (make_number (id), charset_list);
+           }
+         charset_list = Fnreverse (charset_list);
+       }
+      else
+       charset_list = coding_system_charset_list (restriction);
+      charset = char_charset (XINT (ch), charset_list, NULL);
+      if (! charset)
+       return Qnil;
+    }
   return (CHARSET_NAME (charset));
 }
 
@@ -2161,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);
@@ -2225,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))
     {
@@ -2232,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;
 }
@@ -2258,7 +2318,7 @@ 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\
@@ -2287,11 +2347,7 @@ init_charset_once ()
   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
@@ -2393,6 +2449,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 */