(g2-UU+5B73): Add `=decomposition@hanyo-denshi'.
[chise/xemacs-chise.git.1] / src / fns.c
index 3162a1a..9de6fea 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -1,6 +1,7 @@
 /* Random utility Lisp functions.
    Copyright (C) 1985, 86, 87, 93, 94, 95 Free Software Foundation, Inc.
    Copyright (C) 1995, 1996 Ben Wing.
+   Copyright (C) 2002, 2003, 2004, 2008 MORIOKA Tomohiko
 
 This file is part of XEmacs.
 
@@ -49,6 +50,42 @@ Boston, MA 02111-1307, USA.  */
 #include "lstream.h"
 #include "opaque.h"
 
+
+\f
+static Lisp_Object free_malloced_ptr(Lisp_Object unwind_obj)
+{
+       void *ptr = (void *)get_opaque_ptr(unwind_obj);
+       xfree(ptr);
+       free_opaque_ptr(unwind_obj);
+       return Qnil;
+}
+
+/* Don't use alloca for regions larger than this, lest we overflow
+   the stack.  */
+#define MAX_ALLOCA 65536
+
+/* We need to setup proper unwinding, because there is a number of
+   ways these functions can blow up, and we don't want to have memory
+   leaks in those cases.  */
+#define XMALLOC_OR_ALLOCA(ptr, len, type) do {                         \
+  size_t XOA_len = (len);                                              \
+  if (XOA_len > MAX_ALLOCA ) {                                         \
+         ptr = xnew_array (type, XOA_len);                             \
+         record_unwind_protect (free_malloced_ptr,                     \
+                                make_opaque_ptr ((void *)ptr));        \
+  }                                                                    \
+  else                                                                 \
+    ptr = alloca_array (type, XOA_len);                                        \
+} while (0)
+
+#define XMALLOC_UNBIND(ptr, len, speccount) do {                       \
+   if ((len) > MAX_ALLOCA)                                             \
+           unbind_to (speccount, Qnil);                                \
+} while (0)
+
+\f
+
+
 /* NOTE: This symbol is also used in lread.c */
 #define FEATUREP_SYNTAX
 
@@ -56,6 +93,7 @@ Lisp_Object Qstring_lessp;
 Lisp_Object Qidentity;
 
 static int internal_old_equal (Lisp_Object, Lisp_Object, int);
+Lisp_Object safe_copy_tree (Lisp_Object arg, Lisp_Object vecp, int depth);
 
 static Lisp_Object
 mark_bit_vector (Lisp_Object obj)
@@ -72,7 +110,7 @@ print_bit_vector (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
   size_t last = len;
 
   if (INTP (Vprint_length))
-    last = min (len, XINT (Vprint_length));
+    last = min ((EMACS_INT) len, XINT (Vprint_length));
   write_c_string ("#*", printcharfun);
   for (i = 0; i < last; i++)
     {
@@ -112,7 +150,7 @@ static size_t
 size_bit_vector (const void *lheader)
 {
   Lisp_Bit_Vector *v = (Lisp_Bit_Vector *) lheader;
-  return FLEXIBLE_ARRAY_STRUCT_SIZEOF (Lisp_Bit_Vector, bits,
+  return FLEXIBLE_ARRAY_STRUCT_SIZEOF (Lisp_Bit_Vector, unsigned long, bits,
                                       BIT_VECTOR_LONG_STORAGE (bit_vector_length (v)));
 }
 
@@ -142,7 +180,7 @@ extern void seed_random (long arg);
 DEFUN ("random", Frandom, 0, 1, 0, /*
 Return a pseudo-random number.
 All integers representable in Lisp are equally likely.
-  On most systems, this is 28 bits' worth.
+  On most systems, this is 31 bits' worth.
 With positive integer argument N, return random number in interval [0,N).
 With argument t, set the random number seed from the current time and pid.
 */
@@ -162,7 +200,7 @@ With argument t, set the random number seed from the current time and pid.
         it's possible to get a quotient larger than limit; discarding
         these values eliminates the bias that would otherwise appear
         when using a large limit.  */
-      denominator = ((unsigned long)1 << VALBITS) / XINT (limit);
+      denominator = ((unsigned long)1 << INT_VALBITS) / XINT (limit);
       do
        val = get_random () / denominator;
       while (val >= XINT (limit));
@@ -270,25 +308,25 @@ strings, but this is not the case under FSF Emacs 19.  In FSF Emacs 20
 `equal' is the same as in XEmacs, in that respect.)
 Symbols are also allowed; their print names are used instead.
 */
-       (s1, s2))
+       (string1, string2))
 {
   Bytecount len;
   Lisp_String *p1, *p2;
 
-  if (SYMBOLP (s1))
-    p1 = XSYMBOL (s1)->name;
+  if (SYMBOLP (string1))
+    p1 = XSYMBOL (string1)->name;
   else
     {
-      CHECK_STRING (s1);
-      p1 = XSTRING (s1);
+      CHECK_STRING (string1);
+      p1 = XSTRING (string1);
     }
 
-  if (SYMBOLP (s2))
-    p2 = XSYMBOL (s2)->name;
+  if (SYMBOLP (string2))
+    p2 = XSYMBOL (string2)->name;
   else
     {
-      CHECK_STRING (s2);
-      p2 = XSTRING (s2);
+      CHECK_STRING (string2);
+      p2 = XSTRING (string2);
     }
 
   return (((len = string_length (p1)) == string_length (p2)) &&
@@ -318,26 +356,26 @@ it is quite likely that a collation table exists (or will exist) for
 Unicode.  When Unicode support is added to XEmacs/Mule, this problem
 may be solved.
 */
-       (s1, s2))
+       (string1, string2))
 {
   Lisp_String *p1, *p2;
   Charcount end, len2;
   int i;
 
-  if (SYMBOLP (s1))
-    p1 = XSYMBOL (s1)->name;
+  if (SYMBOLP (string1))
+    p1 = XSYMBOL (string1)->name;
   else
     {
-      CHECK_STRING (s1);
-      p1 = XSTRING (s1);
+      CHECK_STRING (string1);
+      p1 = XSTRING (string1);
     }
 
-  if (SYMBOLP (s2))
-    p2 = XSYMBOL (s2)->name;
+  if (SYMBOLP (string2))
+    p2 = XSYMBOL (string2)->name;
   else
     {
-      CHECK_STRING (s2);
-      p2 = XSTRING (s2);
+      CHECK_STRING (string2);
+      p2 = XSTRING (string2);
     }
 
   end  = string_char_length (p1);
@@ -435,40 +473,40 @@ static Lisp_Object concat (int nargs, Lisp_Object *args,
                            int last_special);
 
 Lisp_Object
-concat2 (Lisp_Object s1, Lisp_Object s2)
+concat2 (Lisp_Object string1, Lisp_Object string2)
 {
   Lisp_Object args[2];
-  args[0] = s1;
-  args[1] = s2;
+  args[0] = string1;
+  args[1] = string2;
   return concat (2, args, c_string, 0);
 }
 
 Lisp_Object
-concat3 (Lisp_Object s1, Lisp_Object s2, Lisp_Object s3)
+concat3 (Lisp_Object string1, Lisp_Object string2, Lisp_Object string3)
 {
   Lisp_Object args[3];
-  args[0] = s1;
-  args[1] = s2;
-  args[2] = s3;
+  args[0] = string1;
+  args[1] = string2;
+  args[2] = string3;
   return concat (3, args, c_string, 0);
 }
 
 Lisp_Object
-vconcat2 (Lisp_Object s1, Lisp_Object s2)
+vconcat2 (Lisp_Object vec1, Lisp_Object vec2)
 {
   Lisp_Object args[2];
-  args[0] = s1;
-  args[1] = s2;
+  args[0] = vec1;
+  args[1] = vec2;
   return concat (2, args, c_vector, 0);
 }
 
 Lisp_Object
-vconcat3 (Lisp_Object s1, Lisp_Object s2, Lisp_Object s3)
+vconcat3 (Lisp_Object vec1, Lisp_Object vec2, Lisp_Object vec3)
 {
   Lisp_Object args[3];
-  args[0] = s1;
-  args[1] = s2;
-  args[2] = s3;
+  args[0] = vec1;
+  args[1] = vec2;
+  args[2] = vec3;
   return concat (3, args, c_vector, 0);
 }
 
@@ -603,6 +641,8 @@ concat (int nargs, Lisp_Object *args,
   Bufbyte *string_result = 0;
   Bufbyte *string_result_ptr = 0;
   struct gcpro gcpro1;
+  int speccount = specpdl_depth();
+  Charcount total_length;
 
   /* The modus operandi in Emacs is "caller gc-protects args".
      However, concat is called many times in Emacs on freshly
@@ -620,7 +660,7 @@ concat (int nargs, Lisp_Object *args,
      the result in the returned string's `string-translatable' property. */
 #endif
   if (target_type == c_string)
-    args_mse = alloca_array (struct merge_string_extents_struct, nargs);
+    XMALLOC_OR_ALLOCA(args_mse, nargs, struct merge_string_extents_struct);
 
   /* In append, the last arg isn't treated like the others */
   if (last_special && nargs > 0)
@@ -669,7 +709,7 @@ concat (int nargs, Lisp_Object *args,
     /* Charcount is a misnomer here as we might be dealing with the
        length of a vector or list, but emphasizes that we're not dealing
        with Bytecounts in strings */
-    Charcount total_length;
+    /* Charcount total_length; */
 
     for (argnum = 0, total_length = 0; argnum < nargs; argnum++)
       {
@@ -685,8 +725,11 @@ concat (int nargs, Lisp_Object *args,
       {
       case c_cons:
         if (total_length == 0)
+          {
           /* In append, if all but last arg are nil, return last arg */
+            XMALLOC_UNBIND(args_mse, nargs, speccount);
           RETURN_UNGCPRO (last_tail);
+          }
         val = Fmake_list (make_int (total_length), Qnil);
         break;
       case c_vector:
@@ -706,12 +749,14 @@ concat (int nargs, Lisp_Object *args,
           realloc()ing in order to make the char fit properly.
           O(N^2) yuckage. */
         val = Qnil;
-       string_result = (Bufbyte *) alloca (total_length * MAX_EMCHAR_LEN);
+        XMALLOC_OR_ALLOCA( string_result, 
+                           total_length * MAX_EMCHAR_LEN,
+                           Bufbyte );
        string_result_ptr = string_result;
         break;
       default:
        val = Qnil;
-        abort ();
+        ABORT ();
       }
   }
 
@@ -819,6 +864,8 @@ concat (int nargs, Lisp_Object *args,
                                 args_mse[argnum].entry_offset, 0,
                                 args_mse[argnum].entry_length);
        }
+      XMALLOC_UNBIND(string_result, total_length * MAX_EMCHAR_LEN, speccount);
+      XMALLOC_UNBIND(args_mse, nargs, speccount);
     }
 
   if (!NILP (prev))
@@ -863,6 +910,15 @@ are not copied.
 */
        (arg, vecp))
 {
+  return safe_copy_tree (arg, vecp, 0);
+}
+
+Lisp_Object
+safe_copy_tree (Lisp_Object arg, Lisp_Object vecp, int depth)
+{
+  if (depth > 200)
+    signal_simple_error ("Stack overflow in copy-tree", arg);
+    
   if (CONSP (arg))
     {
       Lisp_Object rest;
@@ -872,9 +928,9 @@ are not copied.
          Lisp_Object elt = XCAR (rest);
          QUIT;
          if (CONSP (elt) || VECTORP (elt))
-           XCAR (rest) = Fcopy_tree (elt, vecp);
+           XCAR (rest) = safe_copy_tree (elt, vecp, depth + 1);
          if (VECTORP (XCDR (rest))) /* hack for (a b . [c d]) */
-           XCDR (rest) = Fcopy_tree (XCDR (rest), vecp);
+           XCDR (rest) = safe_copy_tree (XCDR (rest), vecp, depth +1);
          rest = XCDR (rest);
        }
     }
@@ -888,33 +944,33 @@ are not copied.
          Lisp_Object elt = XVECTOR_DATA (arg) [j];
          QUIT;
          if (CONSP (elt) || VECTORP (elt))
-           XVECTOR_DATA (arg) [j] = Fcopy_tree (elt, vecp);
+           XVECTOR_DATA (arg) [j] = safe_copy_tree (elt, vecp, depth + 1);
        }
     }
   return arg;
 }
 
 DEFUN ("substring", Fsubstring, 2, 3, 0, /*
-Return a substring of STRING, starting at index FROM and ending before TO.
-TO may be nil or omitted; then the substring runs to the end of STRING.
-If FROM or TO is negative, it counts from the end.
-Relevant parts of the string-extent-data are copied in the new string.
+Return the substring of STRING starting at START and ending before END.
+END may be nil or omitted; then the substring runs to the end of STRING.
+If START or END is negative, it counts from the end.
+Relevant parts of the string-extent-data are copied to the new string.
 */
-       (string, from, to))
+       (string, start, end))
 {
-  Charcount ccfr, ccto;
-  Bytecount bfr, blen;
+  Charcount ccstart, ccend;
+  Bytecount bstart, blen;
   Lisp_Object val;
 
   CHECK_STRING (string);
-  CHECK_INT (from);
-  get_string_range_char (string, from, to, &ccfr, &ccto,
+  CHECK_INT (start);
+  get_string_range_char (string, start, end, &ccstart, &ccend,
                         GB_HISTORICAL_STRING_BEHAVIOR);
-  bfr = charcount_to_bytecount (XSTRING_DATA (string), ccfr);
-  blen = charcount_to_bytecount (XSTRING_DATA (string) + bfr, ccto - ccfr);
-  val = make_string (XSTRING_DATA (string) + bfr, blen);
-  /* Copy any applicable extent information into the new string: */
-  copy_string_extents (val, string, 0, bfr, blen);
+  bstart = charcount_to_bytecount (XSTRING_DATA (string), ccstart);
+  blen = charcount_to_bytecount (XSTRING_DATA (string) + bstart, ccend - ccstart);
+  val = make_string (XSTRING_DATA (string) + bstart, blen);
+  /* Copy any applicable extent information into the new string. */
+  copy_string_extents (val, string, 0, bstart, blen);
   return val;
 }
 
@@ -991,7 +1047,7 @@ are copied to the new string.
     }
   else
     {
-      abort (); /* unreachable, since Flength (sequence) did not get
+      ABORT (); /* unreachable, since Flength (sequence) did not get
                    an error */
       return Qnil;
     }
@@ -1185,7 +1241,7 @@ If LIST has N or fewer elements, nil is returned.
 */
        (list, n))
 {
-  int int_n;
+  EMACS_INT int_n;
 
   CHECK_LIST (list);
 
@@ -1286,13 +1342,13 @@ memq_no_quit (Lisp_Object elt, Lisp_Object list)
 }
 
 DEFUN ("assoc", Fassoc, 2, 2, 0, /*
-Return non-nil if KEY is `equal' to the car of an element of LIST.
-The value is actually the element of LIST whose car equals KEY.
+Return non-nil if KEY is `equal' to the car of an element of ALIST.
+The value is actually the element of ALIST whose car equals KEY.
 */
-       (key, list))
+       (key, alist))
 {
   /* This function can GC. */
-  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, list)
+  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
     {
       if (internal_equal (key, elt_car, 0))
        return elt;
@@ -1301,13 +1357,13 @@ The value is actually the element of LIST whose car equals KEY.
 }
 
 DEFUN ("old-assoc", Fold_assoc, 2, 2, 0, /*
-Return non-nil if KEY is `old-equal' to the car of an element of LIST.
-The value is actually the element of LIST whose car equals KEY.
+Return non-nil if KEY is `old-equal' to the car of an element of ALIST.
+The value is actually the element of ALIST whose car equals KEY.
 */
-       (key, list))
+       (key, alist))
 {
   /* This function can GC. */
-  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, list)
+  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
     {
       if (internal_old_equal (key, elt_car, 0))
        return elt;
@@ -1316,21 +1372,21 @@ The value is actually the element of LIST whose car equals KEY.
 }
 
 Lisp_Object
-assoc_no_quit (Lisp_Object key, Lisp_Object list)
+assoc_no_quit (Lisp_Object key, Lisp_Object alist)
 {
   int speccount = specpdl_depth ();
   specbind (Qinhibit_quit, Qt);
-  return unbind_to (speccount, Fassoc (key, list));
+  return unbind_to (speccount, Fassoc (key, alist));
 }
 
 DEFUN ("assq", Fassq, 2, 2, 0, /*
-Return non-nil if KEY is `eq' to the car of an element of LIST.
-The value is actually the element of LIST whose car is KEY.
-Elements of LIST that are not conses are ignored.
+Return non-nil if KEY is `eq' to the car of an element of ALIST.
+The value is actually the element of ALIST whose car is KEY.
+Elements of ALIST that are not conses are ignored.
 */
-       (key, list))
+       (key, alist))
 {
-  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, list)
+  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
     {
       if (EQ_WITH_EBOLA_NOTICE (key, elt_car))
        return elt;
@@ -1339,15 +1395,15 @@ Elements of LIST that are not conses are ignored.
 }
 
 DEFUN ("old-assq", Fold_assq, 2, 2, 0, /*
-Return non-nil if KEY is `old-eq' to the car of an element of LIST.
-The value is actually the element of LIST whose car is KEY.
-Elements of LIST that are not conses are ignored.
+Return non-nil if KEY is `old-eq' to the car of an element of ALIST.
+The value is actually the element of ALIST whose car is KEY.
+Elements of ALIST that are not conses are ignored.
 This function is provided only for byte-code compatibility with v19.
 Do not use it.
 */
-       (key, list))
+       (key, alist))
 {
-  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, list)
+  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
     {
       if (HACKEQ_UNSAFE (key, elt_car))
        return elt;
@@ -1359,10 +1415,10 @@ Do not use it.
    Use only on lists known never to be circular.  */
 
 Lisp_Object
-assq_no_quit (Lisp_Object key, Lisp_Object list)
+assq_no_quit (Lisp_Object key, Lisp_Object alist)
 {
   /* This cannot GC. */
-  LIST_LOOP_2 (elt, list)
+  LIST_LOOP_2 (elt, alist)
     {
       Lisp_Object elt_car = XCAR (elt);
       if (EQ_WITH_EBOLA_NOTICE (key, elt_car))
@@ -1372,70 +1428,70 @@ assq_no_quit (Lisp_Object key, Lisp_Object list)
 }
 
 DEFUN ("rassoc", Frassoc, 2, 2, 0, /*
-Return non-nil if KEY is `equal' to the cdr of an element of LIST.
-The value is actually the element of LIST whose cdr equals KEY.
+Return non-nil if VALUE is `equal' to the cdr of an element of ALIST.
+The value is actually the element of ALIST whose cdr equals VALUE.
 */
-       (key, list))
+       (value, alist))
 {
-  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, list)
+  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
     {
-      if (internal_equal (key, elt_cdr, 0))
+      if (internal_equal (value, elt_cdr, 0))
        return elt;
     }
   return Qnil;
 }
 
 DEFUN ("old-rassoc", Fold_rassoc, 2, 2, 0, /*
-Return non-nil if KEY is `old-equal' to the cdr of an element of LIST.
-The value is actually the element of LIST whose cdr equals KEY.
+Return non-nil if VALUE is `old-equal' to the cdr of an element of ALIST.
+The value is actually the element of ALIST whose cdr equals VALUE.
 */
-       (key, list))
+       (value, alist))
 {
-  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, list)
+  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
     {
-      if (internal_old_equal (key, elt_cdr, 0))
+      if (internal_old_equal (value, elt_cdr, 0))
        return elt;
     }
   return Qnil;
 }
 
 DEFUN ("rassq", Frassq, 2, 2, 0, /*
-Return non-nil if KEY is `eq' to the cdr of an element of LIST.
-The value is actually the element of LIST whose cdr is KEY.
+Return non-nil if VALUE is `eq' to the cdr of an element of ALIST.
+The value is actually the element of ALIST whose cdr is VALUE.
 */
-       (key, list))
+       (value, alist))
 {
-  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, list)
+  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
     {
-      if (EQ_WITH_EBOLA_NOTICE (key, elt_cdr))
+      if (EQ_WITH_EBOLA_NOTICE (value, elt_cdr))
        return elt;
     }
   return Qnil;
 }
 
 DEFUN ("old-rassq", Fold_rassq, 2, 2, 0, /*
-Return non-nil if KEY is `old-eq' to the cdr of an element of LIST.
-The value is actually the element of LIST whose cdr is KEY.
+Return non-nil if VALUE is `old-eq' to the cdr of an element of ALIST.
+The value is actually the element of ALIST whose cdr is VALUE.
 */
-       (key, list))
+       (value, alist))
 {
-  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, list)
+  EXTERNAL_ALIST_LOOP_4 (elt, elt_car, elt_cdr, alist)
     {
-      if (HACKEQ_UNSAFE (key, elt_cdr))
+      if (HACKEQ_UNSAFE (value, elt_cdr))
        return elt;
     }
   return Qnil;
 }
 
-/* Like Frassq, but caller must ensure that LIST is properly
+/* Like Frassq, but caller must ensure that ALIST is properly
    nil-terminated and ebola-free. */
 Lisp_Object
-rassq_no_quit (Lisp_Object key, Lisp_Object list)
+rassq_no_quit (Lisp_Object value, Lisp_Object alist)
 {
-  LIST_LOOP_2 (elt, list)
+  LIST_LOOP_2 (elt, alist)
     {
       Lisp_Object elt_cdr = XCDR (elt);
-      if (EQ_WITH_EBOLA_NOTICE (key, elt_cdr))
+      if (EQ_WITH_EBOLA_NOTICE (value, elt_cdr))
        return elt;
     }
   return Qnil;
@@ -1546,92 +1602,92 @@ delq_no_quit_and_free_cons (Lisp_Object elt, Lisp_Object list)
 }
 
 DEFUN ("remassoc", Fremassoc, 2, 2, 0, /*
-Delete by side effect any elements of LIST whose car is `equal' to KEY.
-The modified LIST is returned.  If the first member of LIST has a car
+Delete by side effect any elements of ALIST whose car is `equal' to KEY.
+The modified ALIST is returned.  If the first member of ALIST has a car
 that is `equal' to KEY, there is no way to remove it by side effect;
 therefore, write `(setq foo (remassoc key foo))' to be sure of changing
 the value of `foo'.
 */
-       (key, list))
+       (key, alist))
 {
-  EXTERNAL_LIST_LOOP_DELETE_IF (elt, list,
+  EXTERNAL_LIST_LOOP_DELETE_IF (elt, alist,
                                (CONSP (elt) &&
                                 internal_equal (key, XCAR (elt), 0)));
-  return list;
+  return alist;
 }
 
 Lisp_Object
-remassoc_no_quit (Lisp_Object key, Lisp_Object list)
+remassoc_no_quit (Lisp_Object key, Lisp_Object alist)
 {
   int speccount = specpdl_depth ();
   specbind (Qinhibit_quit, Qt);
-  return unbind_to (speccount, Fremassoc (key, list));
+  return unbind_to (speccount, Fremassoc (key, alist));
 }
 
 DEFUN ("remassq", Fremassq, 2, 2, 0, /*
-Delete by side effect any elements of LIST whose car is `eq' to KEY.
-The modified LIST is returned.  If the first member of LIST has a car
+Delete by side effect any elements of ALIST whose car is `eq' to KEY.
+The modified ALIST is returned.  If the first member of ALIST has a car
 that is `eq' to KEY, there is no way to remove it by side effect;
 therefore, write `(setq foo (remassq key foo))' to be sure of changing
 the value of `foo'.
 */
-       (key, list))
+       (key, alist))
 {
-  EXTERNAL_LIST_LOOP_DELETE_IF (elt, list,
+  EXTERNAL_LIST_LOOP_DELETE_IF (elt, alist,
                                (CONSP (elt) &&
                                 EQ_WITH_EBOLA_NOTICE (key, XCAR (elt))));
-  return list;
+  return alist;
 }
 
 /* no quit, no errors; be careful */
 
 Lisp_Object
-remassq_no_quit (Lisp_Object key, Lisp_Object list)
+remassq_no_quit (Lisp_Object key, Lisp_Object alist)
 {
-  LIST_LOOP_DELETE_IF (elt, list,
+  LIST_LOOP_DELETE_IF (elt, alist,
                       (CONSP (elt) &&
                        EQ_WITH_EBOLA_NOTICE (key, XCAR (elt))));
-  return list;
+  return alist;
 }
 
 DEFUN ("remrassoc", Fremrassoc, 2, 2, 0, /*
-Delete by side effect any elements of LIST whose cdr is `equal' to VALUE.
-The modified LIST is returned.  If the first member of LIST has a car
+Delete by side effect any elements of ALIST whose cdr is `equal' to VALUE.
+The modified ALIST is returned.  If the first member of ALIST has a car
 that is `equal' to VALUE, there is no way to remove it by side effect;
 therefore, write `(setq foo (remrassoc value foo))' to be sure of changing
 the value of `foo'.
 */
-       (value, list))
+       (value, alist))
 {
-  EXTERNAL_LIST_LOOP_DELETE_IF (elt, list,
+  EXTERNAL_LIST_LOOP_DELETE_IF (elt, alist,
                                (CONSP (elt) &&
                                 internal_equal (value, XCDR (elt), 0)));
-  return list;
+  return alist;
 }
 
 DEFUN ("remrassq", Fremrassq, 2, 2, 0, /*
-Delete by side effect any elements of LIST whose cdr is `eq' to VALUE.
-The modified LIST is returned.  If the first member of LIST has a car
+Delete by side effect any elements of ALIST whose cdr is `eq' to VALUE.
+The modified ALIST is returned.  If the first member of ALIST has a car
 that is `eq' to VALUE, there is no way to remove it by side effect;
 therefore, write `(setq foo (remrassq value foo))' to be sure of changing
 the value of `foo'.
 */
-       (value, list))
+       (value, alist))
 {
-  EXTERNAL_LIST_LOOP_DELETE_IF (elt, list,
+  EXTERNAL_LIST_LOOP_DELETE_IF (elt, alist,
                                (CONSP (elt) &&
                                 EQ_WITH_EBOLA_NOTICE (value, XCDR (elt))));
-  return list;
+  return alist;
 }
 
 /* Like Fremrassq, fast and unsafe; be careful */
 Lisp_Object
-remrassq_no_quit (Lisp_Object value, Lisp_Object list)
+remrassq_no_quit (Lisp_Object value, Lisp_Object alist)
 {
-  LIST_LOOP_DELETE_IF (elt, list,
+  LIST_LOOP_DELETE_IF (elt, alist,
                       (CONSP (elt) &&
                        EQ_WITH_EBOLA_NOTICE (value, XCDR (elt))));
-  return list;
+  return alist;
 }
 
 DEFUN ("nreverse", Fnreverse, 1, 1, 0, /*
@@ -1689,12 +1745,11 @@ list_sort (Lisp_Object list,
   Lisp_Object back, tem;
   Lisp_Object front = list;
   Lisp_Object len = Flength (list);
-  int length = XINT (len);
 
-  if (length < 2)
+  if (XINT (len) < 2)
     return list;
 
-  XSETINT (len, (length / 2) - 1);
+  len = make_int (XINT (len) / 2 - 1);
   tem = Fnthcdr (len, list);
   back = Fcdr (tem);
   Fsetcdr (tem, Qnil);
@@ -1735,9 +1790,9 @@ Returns the sorted list.  LIST is modified by side effects.
 PREDICATE is called with two elements of LIST, and should return T
 if the first element is "less" than the second.
 */
-       (list, pred))
+       (list, predicate))
 {
-  return list_sort (list, pred, merge_pred_function);
+  return list_sort (list, predicate, merge_pred_function);
 }
 
 Lisp_Object
@@ -1831,6 +1886,7 @@ plists_differ (Lisp_Object a, Lisp_Object b, int nil_means_not_present,
   Lisp_Object *keys, *vals;
   char *flags;
   Lisp_Object rest;
+  int speccount = specpdl_depth();
 
   if (NILP (a) && NILP (b))
     return 0;
@@ -1842,9 +1898,9 @@ plists_differ (Lisp_Object a, Lisp_Object b, int nil_means_not_present,
   lb = XINT (Flength (b));
   m = (la > lb ? la : lb);
   fill = 0;
-  keys  = alloca_array (Lisp_Object, m);
-  vals  = alloca_array (Lisp_Object, m);
-  flags = alloca_array (char, m);
+  XMALLOC_OR_ALLOCA(keys, m, Lisp_Object);
+  XMALLOC_OR_ALLOCA(vals, m, Lisp_Object);
+  XMALLOC_OR_ALLOCA(flags, m, char);
 
   /* First extract the pairs from A. */
   for (rest = a; !NILP (rest); rest = XCDR (XCDR (rest)))
@@ -1889,10 +1945,17 @@ plists_differ (Lisp_Object a, Lisp_Object b, int nil_means_not_present,
     if (flags [i] == 0)
       goto MISMATCH;
 
+
+  XMALLOC_UNBIND(flags, m, speccount);
+  XMALLOC_UNBIND(vals, m, speccount);
+  XMALLOC_UNBIND(keys, m, speccount);
   /* Ok. */
   return 0;
 
  MISMATCH:
+  XMALLOC_UNBIND(flags, m, speccount);
+  XMALLOC_UNBIND(vals, m, speccount);
+  XMALLOC_UNBIND(keys, m, speccount);
   return 1;
 }
 
@@ -2267,51 +2330,54 @@ external_remprop (Lisp_Object *plist, Lisp_Object property,
 DEFUN ("plist-get", Fplist_get, 2, 3, 0, /*
 Extract a value from a property list.
 PLIST is a property list, which is a list of the form
-\(PROP1 VALUE1 PROP2 VALUE2...).  This function returns the value
-corresponding to the given PROP, or DEFAULT if PROP is not
-one of the properties on the list.
+\(PROPERTY1 VALUE1 PROPERTY2 VALUE2...).
+PROPERTY is usually a symbol.
+This function returns the value corresponding to the PROPERTY,
+or DEFAULT if PROPERTY is not one of the properties on the list.
 */
-       (plist, prop, default_))
+       (plist, property, default_))
 {
-  Lisp_Object val = external_plist_get (&plist, prop, 0, ERROR_ME);
-  return UNBOUNDP (val) ? default_ : val;
+  Lisp_Object value = external_plist_get (&plist, property, 0, ERROR_ME);
+  return UNBOUNDP (value) ? default_ : value;
 }
 
 DEFUN ("plist-put", Fplist_put, 3, 3, 0, /*
-Change value in PLIST of PROP to VAL.
-PLIST is a property list, which is a list of the form \(PROP1 VALUE1
-PROP2 VALUE2 ...).  PROP is usually a symbol and VAL is any object.
-If PROP is already a property on the list, its value is set to VAL,
-otherwise the new PROP VAL pair is added.  The new plist is returned;
-use `(setq x (plist-put x prop val))' to be sure to use the new value.
-The PLIST is modified by side effects.
+Change value in PLIST of PROPERTY to VALUE.
+PLIST is a property list, which is a list of the form
+\(PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...).
+PROPERTY is usually a symbol and VALUE is any object.
+If PROPERTY is already a property on the list, its value is set to VALUE,
+otherwise the new PROPERTY VALUE pair is added.
+The new plist is returned; use `(setq x (plist-put x property value))'
+to be sure to use the new value.  PLIST is modified by side effect.
 */
-       (plist, prop, val))
+       (plist, property, value))
 {
-  external_plist_put (&plist, prop, val, 0, ERROR_ME);
+  external_plist_put (&plist, property, value, 0, ERROR_ME);
   return plist;
 }
 
 DEFUN ("plist-remprop", Fplist_remprop, 2, 2, 0, /*
-Remove from PLIST the property PROP and its value.
-PLIST is a property list, which is a list of the form \(PROP1 VALUE1
-PROP2 VALUE2 ...).  PROP is usually a symbol.  The new plist is
-returned; use `(setq x (plist-remprop x prop val))' to be sure to use
-the new value.  The PLIST is modified by side effects.
+Remove from PLIST the property PROPERTY and its value.
+PLIST is a property list, which is a list of the form
+\(PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...).
+PROPERTY is usually a symbol.
+The new plist is returned; use `(setq x (plist-remprop x property))'
+to be sure to use the new value.  PLIST is modified by side effect.
 */
-       (plist, prop))
+       (plist, property))
 {
-  external_remprop (&plist, prop, 0, ERROR_ME);
+  external_remprop (&plist, property, 0, ERROR_ME);
   return plist;
 }
 
 DEFUN ("plist-member", Fplist_member, 2, 2, 0, /*
-Return t if PROP has a value specified in PLIST.
+Return t if PROPERTY has a value specified in PLIST.
 */
-       (plist, prop))
+       (plist, property))
 {
-  Lisp_Object val = Fplist_get (plist, prop, Qunbound);
-  return UNBOUNDP (val) ? Qnil : Qt;
+  Lisp_Object value = Fplist_get (plist, property, Qunbound);
+  return UNBOUNDP (value) ? Qnil : Qt;
 }
 
 DEFUN ("check-valid-plist", Fcheck_valid_plist, 1, 1, 0, /*
@@ -2409,58 +2475,60 @@ The new plist is returned.  If NIL-MEANS-NOT-PRESENT is given, the
 
 DEFUN ("lax-plist-get", Flax_plist_get, 2, 3, 0, /*
 Extract a value from a lax property list.
-
-LAX-PLIST is a lax property list, which is a list of the form \(PROP1
-VALUE1 PROP2 VALUE2...), where comparisons between properties is done
-using `equal' instead of `eq'.  This function returns the value
-corresponding to the given PROP, or DEFAULT if PROP is not one of the
-properties on the list.
+LAX-PLIST is a lax property list, which is a list of the form
+\(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
+properties is done using `equal' instead of `eq'.
+PROPERTY is usually a symbol.
+This function returns the value corresponding to PROPERTY,
+or DEFAULT if PROPERTY is not one of the properties on the list.
 */
-       (lax_plist, prop, default_))
+       (lax_plist, property, default_))
 {
-  Lisp_Object val = external_plist_get (&lax_plist, prop, 1, ERROR_ME);
-  return UNBOUNDP (val) ? default_ : val;
+  Lisp_Object value = external_plist_get (&lax_plist, property, 1, ERROR_ME);
+  return UNBOUNDP (value) ? default_ : value;
 }
 
 DEFUN ("lax-plist-put", Flax_plist_put, 3, 3, 0, /*
-Change value in LAX-PLIST of PROP to VAL.
-LAX-PLIST is a lax property list, which is a list of the form \(PROP1
-VALUE1 PROP2 VALUE2...), where comparisons between properties is done
-using `equal' instead of `eq'.  PROP is usually a symbol and VAL is
-any object.  If PROP is already a property on the list, its value is
-set to VAL, otherwise the new PROP VAL pair is added.  The new plist
-is returned; use `(setq x (lax-plist-put x prop val))' to be sure to
-use the new value.  The LAX-PLIST is modified by side effects.
-*/
-       (lax_plist, prop, val))
-{
-  external_plist_put (&lax_plist, prop, val, 1, ERROR_ME);
+Change value in LAX-PLIST of PROPERTY to VALUE.
+LAX-PLIST is a lax property list, which is a list of the form
+\(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
+properties is done using `equal' instead of `eq'.
+PROPERTY is usually a symbol and VALUE is any object.
+If PROPERTY is already a property on the list, its value is set to
+VALUE, otherwise the new PROPERTY VALUE pair is added.
+The new plist is returned; use `(setq x (lax-plist-put x property value))'
+to be sure to use the new value.  LAX-PLIST is modified by side effect.
+*/
+       (lax_plist, property, value))
+{
+  external_plist_put (&lax_plist, property, value, 1, ERROR_ME);
   return lax_plist;
 }
 
 DEFUN ("lax-plist-remprop", Flax_plist_remprop, 2, 2, 0, /*
-Remove from LAX-PLIST the property PROP and its value.
-LAX-PLIST is a lax property list, which is a list of the form \(PROP1
-VALUE1 PROP2 VALUE2...), where comparisons between properties is done
-using `equal' instead of `eq'.  PROP is usually a symbol.  The new
-plist is returned; use `(setq x (lax-plist-remprop x prop val))' to be
-sure to use the new value.  The LAX-PLIST is modified by side effects.
+Remove from LAX-PLIST the property PROPERTY and its value.
+LAX-PLIST is a lax property list, which is a list of the form
+\(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
+properties is done using `equal' instead of `eq'.
+PROPERTY is usually a symbol.
+The new plist is returned; use `(setq x (lax-plist-remprop x property))'
+to be sure to use the new value.  LAX-PLIST is modified by side effect.
 */
-       (lax_plist, prop))
+       (lax_plist, property))
 {
-  external_remprop (&lax_plist, prop, 1, ERROR_ME);
+  external_remprop (&lax_plist, property, 1, ERROR_ME);
   return lax_plist;
 }
 
 DEFUN ("lax-plist-member", Flax_plist_member, 2, 2, 0, /*
-Return t if PROP has a value specified in LAX-PLIST.
-LAX-PLIST is a lax property list, which is a list of the form \(PROP1
-VALUE1 PROP2 VALUE2...), where comparisons between properties is done
-using `equal' instead of `eq'.
+Return t if PROPERTY has a value specified in LAX-PLIST.
+LAX-PLIST is a lax property list, which is a list of the form
+\(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
+properties is done using `equal' instead of `eq'.
 */
-       (lax_plist, prop))
+       (lax_plist, property))
 {
-  return UNBOUNDP (Flax_plist_get (lax_plist, prop, Qunbound)) ? Qnil : Qt;
+  return UNBOUNDP (Flax_plist_get (lax_plist, property, Qunbound)) ? Qnil : Qt;
 }
 
 DEFUN ("canonicalize-lax-plist", Fcanonicalize_lax_plist, 1, 2, 0, /*
@@ -2679,9 +2747,9 @@ Conses are compared by comparing the cars and the cdrs.
 Vectors and strings are compared element by element.
 Numbers are compared by value.  Symbols must match exactly.
 */
-       (obj1, obj2))
+       (object1, object2))
 {
-  return internal_equal (obj1, obj2, 0) ? Qt : Qnil;
+  return internal_equal (object1, object2, 0) ? Qt : Qnil;
 }
 
 DEFUN ("old-equal", Fold_equal, 2, 2, 0, /*
@@ -2693,9 +2761,9 @@ this is known as the "char-int confoundance disease." See `eq' and
 This function is provided only for byte-code compatibility with v19.
 Do not use it.
 */
-       (obj1, obj2))
+       (object1, object2))
 {
-  return internal_old_equal (obj1, obj2, 0) ? Qt : Qnil;
+  return internal_old_equal (object1, object2, 0) ? Qt : Qnil;
 }
 
 \f
@@ -2735,7 +2803,7 @@ ARRAY is a vector, bit vector, or string.
   else if (VECTORP (array))
     {
       Lisp_Object *p = XVECTOR_DATA (array);
-      int len = XVECTOR_LENGTH (array);
+      size_t len = XVECTOR_LENGTH (array);
       CHECK_LISP_WRITEABLE (array);
       while (len--)
        *p++ = item;
@@ -2743,11 +2811,11 @@ ARRAY is a vector, bit vector, or string.
   else if (BIT_VECTORP (array))
     {
       Lisp_Bit_Vector *v = XBIT_VECTOR (array);
-      int len = bit_vector_length (v);
+      size_t len = bit_vector_length (v);
       int bit;
       CHECK_BIT (item);
-      CHECK_LISP_WRITEABLE (array);
       bit = XINT (item);
+      CHECK_LISP_WRITEABLE (array);
       while (len--)
        set_bit_vector_bit (v, len, bit);
     }
@@ -2782,7 +2850,7 @@ bytecode_nconc2 (Lisp_Object *args)
     {
       /* (setcdr (last args[0]) args[1]) */
       Lisp_Object tortoise, hare;
-      int count;
+      size_t count;
 
       for (hare = tortoise = args[0], count = 0;
           CONSP (XCDR (hare));
@@ -2851,7 +2919,7 @@ changing the value of `foo'.
              if (CONSP (next) || argnum == nargs -1)
                {
                  /* (setcdr (last val) next) */
-                 int count;
+                 size_t count;
 
                  for (count = 0;
                       CONSP (XCDR (last_cons));
@@ -2905,7 +2973,6 @@ mapcar1 (size_t leni, Lisp_Object *vals,
 {
   Lisp_Object result;
   Lisp_Object args[2];
-  int i;
   struct gcpro gcpro1;
 
   if (vals)
@@ -2935,6 +3002,7 @@ mapcar1 (size_t leni, Lisp_Object *vals,
       if (vals)
        {
          Lisp_Object *val = vals;
+         size_t i;
 
          LIST_LOOP_2 (elt, sequence)
              *val++ = elt;
@@ -2969,6 +3037,7 @@ mapcar1 (size_t leni, Lisp_Object *vals,
   else if (VECTORP (sequence))
     {
       Lisp_Object *objs = XVECTOR_DATA (sequence);
+      size_t i;
       for (i = 0; i < leni; i++)
        {
          args[1] = *objs++;
@@ -2980,8 +3049,12 @@ mapcar1 (size_t leni, Lisp_Object *vals,
     {
       /* The string data of `sequence' might be relocated during GC. */
       Bytecount slen = XSTRING_LENGTH (sequence);
-      Bufbyte *p = alloca_array (Bufbyte, slen);
-      Bufbyte *end = p + slen;
+      Bufbyte *p = NULL;
+      Bufbyte *end = NULL;
+      int speccount = specpdl_depth();
+      
+      XMALLOC_OR_ALLOCA(p, slen, Bufbyte);
+      end = p + slen;
 
       memcpy (p, XSTRING_DATA (sequence), slen);
 
@@ -2992,10 +3065,12 @@ mapcar1 (size_t leni, Lisp_Object *vals,
          result = Ffuncall (2, args);
          if (vals) vals[gcpro1.nvars++] = result;
        }
+      XMALLOC_UNBIND(p, slen, speccount);
     }
   else if (BIT_VECTORP (sequence))
     {
       Lisp_Bit_Vector *v = XBIT_VECTOR (sequence);
+      size_t i;
       for (i = 0; i < leni; i++)
        {
          args[1] = make_int (bit_vector_bit (v, i));
@@ -3004,28 +3079,32 @@ mapcar1 (size_t leni, Lisp_Object *vals,
        }
     }
   else
-    abort (); /* unreachable, since Flength (sequence) did not get an error */
+    ABORT (); /* unreachable, since Flength (sequence) did not get an error */
 
   if (vals)
     UNGCPRO;
 }
 
 DEFUN ("mapconcat", Fmapconcat, 3, 3, 0, /*
-Apply FUNCTION to each element of SEQUENCE, and concat the results as strings.
-In between each pair of results, insert SEPARATOR.  Thus, using " " as
-SEPARATOR results in spaces between the values returned by FUNCTION.
-SEQUENCE may be a list, a vector, a bit vector, or a string.
+Apply FUNCTION to each element of SEQUENCE, and concat the results to a string.
+Between each pair of results, insert SEPARATOR.
+
+Each result, and SEPARATOR, should be strings.  Thus, using " " as SEPARATOR
+results in spaces between the values returned by FUNCTION.  SEQUENCE itself
+may be a list, a vector, a bit vector, or a string.
 */
        (function, sequence, separator))
 {
-  size_t len = XINT (Flength (sequence));
+  EMACS_INT len = XINT (Flength (sequence));
   Lisp_Object *args;
-  int i;
-  int nargs = len + len - 1;
+  Lisp_Object result;
+  EMACS_INT i;
+  EMACS_INT nargs = len + len - 1;
+  int speccount = specpdl_depth();
 
   if (len == 0) return build_string ("");
 
-  args = alloca_array (Lisp_Object, nargs);
+  XMALLOC_OR_ALLOCA(args, nargs, Lisp_Object);
 
   mapcar1 (len, args, function, sequence);
 
@@ -3035,7 +3114,9 @@ SEQUENCE may be a list, a vector, a bit vector, or a string.
   for (i = 1; i < nargs; i += 2)
     args[i] = separator;
 
-  return Fconcat (nargs, args);
+  result = Fconcat(nargs, args);
+  XMALLOC_UNBIND(args, nargs, speccount);
+  return result;
 }
 
 DEFUN ("mapcar", Fmapcar, 2, 2, 0, /*
@@ -3046,11 +3127,17 @@ SEQUENCE may be a list, a vector, a bit vector, or a string.
        (function, sequence))
 {
   size_t len = XINT (Flength (sequence));
-  Lisp_Object *args = alloca_array (Lisp_Object, len);
+  Lisp_Object *args = NULL;
+  Lisp_Object result;
+  int speccount = specpdl_depth();
+
+  XMALLOC_OR_ALLOCA(args, len, Lisp_Object);
 
   mapcar1 (len, args, function, sequence);
 
-  return Flist (len, args);
+  result = Flist(len, args);
+  XMALLOC_UNBIND(args, len, speccount);
+  return result;
 }
 
 DEFUN ("mapvector", Fmapvector, 2, 2, 0, /*
@@ -3312,7 +3399,7 @@ If FEATURE is not a member of the list `features', then the feature
 is not loaded; so load the file FILENAME.
 If FILENAME is omitted, the printname of FEATURE is used as the file name.
 */
-       (feature, file_name))
+       (feature, filename))
 {
   Lisp_Object tem;
   CHECK_SYMBOL (feature);
@@ -3328,7 +3415,7 @@ If FILENAME is omitted, the printname of FEATURE is used as the file name.
       record_unwind_protect (un_autoload, Vautoload_queue);
       Vautoload_queue = Qt;
 
-      call4 (Qload, NILP (file_name) ? Fsymbol_name (feature) : file_name,
+      call4 (Qload, NILP (filename) ? Fsymbol_name (feature) : filename,
             Qnil, Qt, Qnil);
 
       tem = Fmemq (feature, Vfeatures);
@@ -3553,46 +3640,14 @@ base64_decode_1 (Lstream *istream, Bufbyte *to, Charcount *ccptr)
 #undef ADVANCE_INPUT_IGNORE_NONBASE64
 #undef STORE_BYTE
 
-static Lisp_Object
-free_malloced_ptr (Lisp_Object unwind_obj)
-{
-  void *ptr = (void *)get_opaque_ptr (unwind_obj);
-  xfree (ptr);
-  free_opaque_ptr (unwind_obj);
-  return Qnil;
-}
-
-/* Don't use alloca for regions larger than this, lest we overflow
-   the stack.  */
-#define MAX_ALLOCA 65536
-
-/* We need to setup proper unwinding, because there is a number of
-   ways these functions can blow up, and we don't want to have memory
-   leaks in those cases.  */
-#define XMALLOC_OR_ALLOCA(ptr, len, type) do {                 \
-  size_t XOA_len = (len);                                      \
-  if (XOA_len > MAX_ALLOCA)                                    \
-    {                                                          \
-      ptr = xnew_array (type, XOA_len);                                \
-      record_unwind_protect (free_malloced_ptr,                        \
-                            make_opaque_ptr ((void *)ptr));    \
-    }                                                          \
-  else                                                         \
-    ptr = alloca_array (type, XOA_len);                                \
-} while (0)
-
-#define XMALLOC_UNBIND(ptr, len, speccount) do {               \
-  if ((len) > MAX_ALLOCA)                                      \
-    unbind_to (speccount, Qnil);                               \
-} while (0)
 
 DEFUN ("base64-encode-region", Fbase64_encode_region, 2, 3, "r", /*
-Base64-encode the region between BEG and END.
+Base64-encode the region between START and END.
 Return the length of the encoded text.
 Optional third argument NO-LINE-BREAK means do not break long lines
 into shorter lines.
 */
-       (beg, end, no_line_break))
+       (start, end, no_line_break))
 {
   Bufbyte *encoded;
   Bytind encoded_length;
@@ -3602,7 +3657,7 @@ into shorter lines.
   Lisp_Object input;
   int speccount = specpdl_depth();
 
-  get_buffer_range_char (buf, beg, end, &begv, &zv, 0);
+  get_buffer_range_char (buf, start, end, &begv, &zv, 0);
   barf_if_buffer_read_only (buf, begv, zv);
 
   /* We need to allocate enough room for encoding the text.
@@ -3619,7 +3674,7 @@ into shorter lines.
   encoded_length = base64_encode_1 (XLSTREAM (input), encoded,
                                    NILP (no_line_break));
   if (encoded_length > allength)
-    abort ();
+    ABORT ();
   Lstream_delete (XLSTREAM (input));
 
   /* Now we have encoded the region, so we insert the new contents
@@ -3639,6 +3694,8 @@ into shorter lines.
 
 DEFUN ("base64-encode-string", Fbase64_encode_string, 1, 2, 0, /*
 Base64 encode STRING and return the result.
+Optional argument NO-LINE-BREAK means do not break long lines
+into shorter lines.
 */
        (string, no_line_break))
 {
@@ -3659,7 +3716,7 @@ Base64 encode STRING and return the result.
   encoded_length = base64_encode_1 (XLSTREAM (input), encoded,
                                    NILP (no_line_break));
   if (encoded_length > allength)
-    abort ();
+    ABORT ();
   Lstream_delete (XLSTREAM (input));
   result = make_string (encoded, encoded_length);
   XMALLOC_UNBIND (encoded, allength, speccount);
@@ -3667,12 +3724,12 @@ Base64 encode STRING and return the result.
 }
 
 DEFUN ("base64-decode-region", Fbase64_decode_region, 2, 2, "r", /*
-Base64-decode the region between BEG and END.
+Base64-decode the region between START and END.
 Return the length of the decoded text.
 If the region can't be decoded, return nil and don't modify the buffer.
 Characters out of the base64 alphabet are ignored.
 */
-       (beg, end))
+       (start, end))
 {
   struct buffer *buf = current_buffer;
   Bufpos begv, zv, old_pt = BUF_PT (buf);
@@ -3682,7 +3739,7 @@ Characters out of the base64 alphabet are ignored.
   Lisp_Object input;
   int speccount = specpdl_depth();
 
-  get_buffer_range_char (buf, beg, end, &begv, &zv, 0);
+  get_buffer_range_char (buf, start, end, &begv, &zv, 0);
   barf_if_buffer_read_only (buf, begv, zv);
 
   length = zv - begv;
@@ -3692,7 +3749,7 @@ Characters out of the base64 alphabet are ignored.
   XMALLOC_OR_ALLOCA (decoded, length * MAX_EMCHAR_LEN, Bufbyte);
   decoded_length = base64_decode_1 (XLSTREAM (input), decoded, &cc_decoded_length);
   if (decoded_length > length * MAX_EMCHAR_LEN)
-    abort ();
+    ABORT ();
   Lstream_delete (XLSTREAM (input));
 
   /* Now we have decoded the region, so we insert the new contents
@@ -3733,7 +3790,7 @@ Characters out of the base64 alphabet are ignored.
   decoded_length = base64_decode_1 (XLSTREAM (input), decoded,
                                    &cc_decoded_length);
   if (decoded_length > length * MAX_EMCHAR_LEN)
-    abort ();
+    ABORT ();
   Lstream_delete (XLSTREAM (input));
 
   result = make_string (decoded, decoded_length);
@@ -3741,6 +3798,154 @@ Characters out of the base64 alphabet are ignored.
   return result;
 }
 \f
+Lisp_Object Qideographic_structure;
+Lisp_Object Qkeyword_char;
+
+EXFUN (Fideographic_structure_to_ids, 1);
+
+Lisp_Object ids_format_unit (Lisp_Object ids_char);
+Lisp_Object
+ids_format_unit (Lisp_Object ids_char)
+{
+  if (CHARP (ids_char))
+    return Fchar_to_string (ids_char);
+  else if (INTP (ids_char))
+    return Fchar_to_string (Fdecode_char (Qrep_ucs, ids_char, Qnil, Qnil));
+  else
+    {
+      Lisp_Object ret = Ffind_char (ids_char);
+
+      if (CHARP (ret))
+       return Fchar_to_string (ret);
+      else
+       {
+         ret = Fassq (Qideographic_structure, ids_char);
+
+         if (CONSP (ret))
+           return Fideographic_structure_to_ids (XCDR (ret));
+       }
+    }
+  return Qnil;
+}
+
+DEFUN ("ideographic-structure-to-ids",
+       Fideographic_structure_to_ids, 1, 1, 0, /*
+Format ideographic-structure IDS-LIST as an IDS-string.
+*/
+       (ids_list))
+{
+  Lisp_Object dest = Qnil;
+
+  while (CONSP (ids_list))
+    {
+      Lisp_Object cell = XCAR (ids_list);
+
+      if (!NILP (Fchar_ref_p (cell)))
+       cell = Fplist_get (cell, Qkeyword_char, Qnil);
+      dest = concat2 (dest, ids_format_unit (cell));
+      ids_list = XCDR (ids_list);
+    }
+  return dest;
+}
+
+Lisp_Object simplify_char_spec (Lisp_Object char_spec);
+Lisp_Object
+simplify_char_spec (Lisp_Object char_spec)
+{
+  if (CHARP (char_spec))
+    {
+      Lisp_Object ccs;
+      int code_point = ENCODE_CHAR (XCHAR (char_spec), ccs);
+
+      if (code_point >= 0)
+       {
+         int cid = decode_defined_char (ccs, code_point, Qnil);
+
+         if (cid >= 0)
+           return make_char (cid);
+       }
+      return char_spec;
+    }
+  else if (INTP (char_spec))
+    return Fdecode_char (Qrep_ucs, char_spec, Qnil, Qnil);
+  else
+    {
+#if 0
+      Lisp_Object ret = Ffind_char (char_spec);
+#else
+      Lisp_Object ret;
+      Lisp_Object rest = char_spec;
+      int have_ccs = 0;
+
+      while (CONSP (rest))
+       {
+         Lisp_Object cell = Fcar (rest);
+         Lisp_Object ccs;
+
+#if 0
+         if (!LISTP (cell))
+           signal_simple_error ("Invalid argument", char_spec);
+#endif
+         if (!NILP (ccs = Ffind_charset (Fcar (cell))))
+           {
+             cell = Fcdr (cell);
+             if (CONSP (cell))
+               ret = Fmake_char (ccs, Fcar (cell), Fcar (Fcdr (cell)));
+             else
+               ret = Fdecode_char (ccs, cell, Qt, Qt);
+             have_ccs = 1;
+             if (CHARP (ret))
+               return ret;
+           }
+         rest = Fcdr (rest);
+       }
+      if (have_ccs)
+       ret = Fdefine_char (char_spec);
+      else
+       ret = Qnil;
+#endif
+
+      if (CHARP (ret))
+       return ret;
+      else
+       return char_spec;
+    }
+}
+
+Lisp_Object char_ref_simplify_spec (Lisp_Object char_ref);
+Lisp_Object
+char_ref_simplify_spec (Lisp_Object char_ref)
+{
+  if (!NILP (Fchar_ref_p (char_ref)))
+    {
+      Lisp_Object ret = Fplist_get (char_ref, Qkeyword_char, Qnil);
+
+      if (NILP (ret))
+       return char_ref;
+      else
+       return Fplist_put (Fcopy_sequence (char_ref), Qkeyword_char,
+                          simplify_char_spec (ret));
+    }
+  else
+    return simplify_char_spec (char_ref);
+}
+
+DEFUN ("char-refs-simplify-char-specs",
+       Fchar_refs_simplify_char_specs, 1, 1, 0, /*
+Simplify char-specs in CHAR-REFS.
+*/
+       (char_refs))
+{
+  Lisp_Object rest = char_refs;
+
+  while (CONSP (rest))
+    {
+      Fsetcar (rest, char_ref_simplify_spec (XCAR (rest)));
+      rest = XCDR (rest);
+    }
+  return char_refs;
+}
+\f
 Lisp_Object Qyes_or_no_p;
 
 void
@@ -3750,6 +3955,8 @@ syms_of_fns (void)
 
   defsymbol (&Qstring_lessp, "string-lessp");
   defsymbol (&Qidentity, "identity");
+  defsymbol (&Qideographic_structure, "ideographic-structure");
+  defsymbol (&Qkeyword_char, ":char");
   defsymbol (&Qyes_or_no_p, "yes-or-no-p");
 
   DEFSUBR (Fidentity);
@@ -3836,6 +4043,8 @@ syms_of_fns (void)
   DEFSUBR (Fbase64_encode_string);
   DEFSUBR (Fbase64_decode_region);
   DEFSUBR (Fbase64_decode_string);
+  DEFSUBR (Fideographic_structure_to_ids);
+  DEFSUBR (Fchar_refs_simplify_char_specs);
 }
 
 void