(VALBITS, GCTYPEBITS): Deleted; default is better.
[bpt/emacs.git] / src / fns.c
index 2527f26..e75493d 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -1,5 +1,5 @@
 /* Random utility Lisp functions.
-   Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1993, 1994 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -18,7 +18,7 @@ along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 
-#include "config.h"
+#include <config.h>
 
 /* Note on some machines this defines `vector' as a typedef,
    so make sure we don't use that name in this file.  */
@@ -29,10 +29,15 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "commands.h"
 
 #include "buffer.h"
+#include "keyboard.h"
+#include "intervals.h"
 
-Lisp_Object Qstring_lessp;
+extern Lisp_Object Flookup_key ();
 
-static Lisp_Object internal_equal ();
+Lisp_Object Qstring_lessp, Qprovide, Qrequire;
+Lisp_Object Qyes_or_no_p_history;
+
+static int internal_equal ();
 \f
 DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
   "Return the argument unchanged.")
@@ -48,28 +53,39 @@ On most systems all integers representable in Lisp are equally likely.\n\
   This is 24 bits' worth.\n\
 With argument N, return random number in interval [0,N).\n\
 With argument t, set the random number seed from the current time and pid.")
-  (arg)
-     Lisp_Object arg;
+  (limit)
+     Lisp_Object limit;
 {
   int val;
+  unsigned long denominator;
   extern long random ();
   extern srandom ();
   extern long time ();
 
-  if (EQ (arg, Qt))
+  if (EQ (limit, Qt))
     srandom (getpid () + time (0));
-  val = random ();
-  if (XTYPE (arg) == Lisp_Int && XINT (arg) != 0)
+  if (INTEGERP (limit) && XINT (limit) > 0)
     {
-      /* Try to take our random number from the higher bits of VAL,
-        not the lower, since (says Gentzel) the low bits of `random'
-        are less random than the higher ones.  */
-      val &= 0xfffffff;                /* Ensure positive.  */
-      val >>= 5;
-      if (XINT (arg) < 10000)
-       val >>= 6;
-      val %= XINT (arg);
+      if (XFASTINT (limit) >= 0x40000000)
+       /* This case may occur on 64-bit machines.  */
+       val = random () % XFASTINT (limit);
+      else
+       {
+         /* Try to take our random number from the higher bits of VAL,
+            not the lower, since (says Gentzel) the low bits of `random'
+            are less random than the higher ones.  We do this by using the
+            quotient rather than the remainder.  At the high end of the RNG
+            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)0x40000000 / XFASTINT (limit);
+         do
+           val = (random () & 0x3fffffff) / denominator;
+         while (val >= XFASTINT (limit));
+       }
     }
+  else
+    val = random ();
   return make_number (val);
 }
 \f
@@ -85,43 +101,43 @@ A byte-code function object is also allowed.")
   register int i;
 
  retry:
-  if (XTYPE (obj) == Lisp_Vector || XTYPE (obj) == Lisp_String
-      || XTYPE (obj) == Lisp_Compiled)
-    return Farray_length (obj);
+  if (STRINGP (obj))
+    XSETFASTINT (val, XSTRING (obj)->size);
+  else if (VECTORP (obj))
+    XSETFASTINT (val, XVECTOR (obj)->size);
+  else if (COMPILEDP (obj))
+    XSETFASTINT (val, XVECTOR (obj)->size & PSEUDOVECTOR_SIZE_MASK);
   else if (CONSP (obj))
     {
-      for (i = 0, tail = obj; !NILP(tail); i++)
+      for (i = 0, tail = obj; !NILP (tail); i++)
        {
          QUIT;
          tail = Fcdr (tail);
        }
 
-      XFASTINT (val) = i;
-      return val;
-    }
-  else if (NILP(obj))
-    {
-      XFASTINT (val) = 0;
-      return val;
+      XSETFASTINT (val, i);
     }
+  else if (NILP (obj))
+    XSETFASTINT (val, 0);
   else
     {
       obj = wrong_type_argument (Qsequencep, obj);
       goto retry;
     }
+  return val;
 }
 
 DEFUN ("string-equal", Fstring_equal, Sstring_equal, 2, 2, 0,
   "T if two strings have identical contents.\n\
-Case is significant.\n\
+Case is significant, but text properties are ignored.\n\
 Symbols are also allowed; their print names are used instead.")
   (s1, s2)
      register Lisp_Object s1, s2;
 {
-  if (XTYPE (s1) == Lisp_Symbol)
-    XSETSTRING (s1, XSYMBOL (s1)->name), XSETTYPE (s1, Lisp_String);
-  if (XTYPE (s2) == Lisp_Symbol)
-    XSETSTRING (s2, XSYMBOL (s2)->name), XSETTYPE (s2, Lisp_String);
+  if (SYMBOLP (s1))
+    XSETSTRING (s1, XSYMBOL (s1)->name);
+  if (SYMBOLP (s2))
+    XSETSTRING (s2, XSYMBOL (s2)->name);
   CHECK_STRING (s1, 0);
   CHECK_STRING (s2, 1);
 
@@ -142,10 +158,10 @@ Symbols are also allowed; their print names are used instead.")
   register unsigned char *p1, *p2;
   register int end;
 
-  if (XTYPE (s1) == Lisp_Symbol)
-    XSETSTRING (s1, XSYMBOL (s1)->name), XSETTYPE (s1, Lisp_String);
-  if (XTYPE (s2) == Lisp_Symbol)
-    XSETSTRING (s2, XSYMBOL (s2)->name), XSETTYPE (s2, Lisp_String);
+  if (SYMBOLP (s1))
+    XSETSTRING (s1, XSYMBOL (s1)->name);
+  if (SYMBOLP (s2))
+    XSETSTRING (s2, XSYMBOL (s2)->name);
   CHECK_STRING (s1, 0);
   CHECK_STRING (s2, 1);
 
@@ -180,6 +196,22 @@ concat2 (s1, s2)
 #endif /* NO_ARG_ARRAY */
 }
 
+/* ARGSUSED */
+Lisp_Object
+concat3 (s1, s2, s3)
+     Lisp_Object s1, s2, s3;
+{
+#ifdef NO_ARG_ARRAY
+  Lisp_Object args[3];
+  args[0] = s1;
+  args[1] = s2;
+  args[2] = s3;
+  return concat (3, args, Lisp_String, 0);
+#else
+  return concat (3, &s1, Lisp_String, 0);
+#endif /* NO_ARG_ARRAY */
+}
+
 DEFUN ("append", Fappend, Sappend, 0, MANY, 0,
   "Concatenate all the arguments and make the result a list.\n\
 The result is a list whose elements are the elements of all the arguments.\n\
@@ -195,7 +227,8 @@ The last argument is not copied, just used as the tail of the new list.")
 DEFUN ("concat", Fconcat, Sconcat, 0, MANY, 0,
   "Concatenate all the arguments and make the result a string.\n\
 The result is a string whose elements are the elements of all the arguments.\n\
-Each argument may be a string, a list of numbers, or a vector of numbers.")
+Each argument may be a string, a list of characters (integers),\n\
+or a vector of characters (integers).")
   (nargs, args)
      int nargs;
      Lisp_Object *args;
@@ -211,7 +244,7 @@ Each argument may be a list, vector or string.")
      int nargs;
      Lisp_Object *args;
 {
-  return concat (nargs, args, Lisp_Vector, 0);
+  return concat (nargs, args, Lisp_Vectorlike, 0);
 }
 
 DEFUN ("copy-sequence", Fcopy_sequence, Scopy_sequence, 1, 1, 0,
@@ -222,7 +255,7 @@ with the original.")
      Lisp_Object arg;
 {
   if (NILP (arg)) return arg;
-  if (!CONSP (arg) && XTYPE (arg) != Lisp_Vector && XTYPE (arg) != Lisp_String)
+  if (!CONSP (arg) && !VECTORP (arg) && !STRINGP (arg))
     arg = wrong_type_argument (Qsequencep, arg);
   return concat (1, &arg, CONSP (arg) ? Lisp_Cons : XTYPE (arg), 0);
 }
@@ -256,12 +289,11 @@ concat (nargs, args, target_type, last_special)
   for (argnum = 0; argnum < nargs; argnum++)
     {
       this = args[argnum];
-      if (!(CONSP (this) || NILP (this)
-           || XTYPE (this) == Lisp_Vector || XTYPE (this) == Lisp_String
-           || XTYPE (this) == Lisp_Compiled))
+      if (!(CONSP (this) || NILP (this) || VECTORP (this) || STRINGP (this)
+           || COMPILEDP (this)))
        {
-         if (XTYPE (this) == Lisp_Int)
-            args[argnum] = Fint_to_string (this);
+         if (INTEGERP (this))
+            args[argnum] = Fnumber_to_string (this);
          else
            args[argnum] = wrong_type_argument (Qsequencep, this);
        }
@@ -274,11 +306,11 @@ concat (nargs, args, target_type, last_special)
       leni += XFASTINT (len);
     }
 
-  XFASTINT (len) = leni;
+  XSETFASTINT (len, leni);
 
   if (target_type == Lisp_Cons)
     val = Fmake_list (len, Qnil);
-  else if (target_type == Lisp_Vector)
+  else if (target_type == Lisp_Vectorlike)
     val = Fmake_vector (len, Qnil);
   else
     val = Fmake_string (len, len);
@@ -304,19 +336,27 @@ concat (nargs, args, target_type, last_special)
       if (!CONSP (this))
        thislen = Flength (this), thisleni = XINT (thislen);
 
+      if (STRINGP (this) && STRINGP (val)
+         && ! NULL_INTERVAL_P (XSTRING (this)->intervals))
+       {
+         copy_text_properties (make_number (0), thislen, this,
+                               make_number (toindex), val, Qnil);
+       }
+
       while (1)
        {
          register Lisp_Object elt;
 
-         /* Fetch next element of `this' arg into `elt', or break if `this' is exhausted. */
+         /* Fetch next element of `this' arg into `elt', or break if
+             `this' is exhausted. */
          if (NILP (this)) break;
          if (CONSP (this))
            elt = Fcar (this), this = Fcdr (this);
          else
            {
              if (thisindex >= thisleni) break;
-             if (XTYPE (this) == Lisp_String)
-               XFASTINT (elt) = XSTRING (this)->data[thisindex++];
+             if (STRINGP (this))
+               XSETFASTINT (elt, XSTRING (this)->data[thisindex++]);
              else
                elt = XVECTOR (this)->contents[thisindex++];
            }
@@ -328,11 +368,11 @@ concat (nargs, args, target_type, last_special)
              prev = tail;
              tail = XCONS (tail)->cdr;
            }
-         else if (XTYPE (val) == Lisp_Vector)
+         else if (VECTORP (val))
            XVECTOR (val)->contents[toindex++] = elt;
          else
            {
-             while (XTYPE (elt) != Lisp_Int)
+             while (!INTEGERP (elt))
                elt = wrong_type_argument (Qintegerp, elt);
              {
 #ifdef MASSC_REGISTER_BUG
@@ -388,6 +428,8 @@ If FROM or TO is negative, it counts from the end.")
      Lisp_Object string;
      register Lisp_Object from, to;
 {
+  Lisp_Object res;
+
   CHECK_STRING (string, 0);
   CHECK_NUMBER (from, 1);
   if (NILP (to))
@@ -403,8 +445,10 @@ If FROM or TO is negative, it counts from the end.")
         && XINT (to) <= XSTRING (string)->size))
     args_out_of_range_3 (string, from, to);
 
-  return make_string (XSTRING (string)->data + XINT (from),
-                     XINT (to) - XINT (from));
+  res = make_string (XSTRING (string)->data + XINT (from),
+                    XINT (to) - XINT (from));
+  copy_text_properties (from, to, string, make_number (0), res, Qnil);
+  return res;
 }
 \f
 DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0,
@@ -441,10 +485,9 @@ DEFUN ("elt", Felt, Selt, 2, 2, 0,
   CHECK_NUMBER (n, 0);
   while (1)
     {
-      if (XTYPE (seq) == Lisp_Cons || NILP (seq))
+      if (CONSP (seq) || NILP (seq))
        return Fcar (Fnthcdr (n, seq));
-      else if (XTYPE (seq) == Lisp_String
-              || XTYPE (seq) == Lisp_Vector)
+      else if (STRINGP (seq) || VECTORP (seq))
        return Faref (seq, n);
       else
        seq = wrong_type_argument (Qsequencep, seq);
@@ -452,7 +495,7 @@ DEFUN ("elt", Felt, Selt, 2, 2, 0,
 }
 
 DEFUN ("member", Fmember, Smember, 2, 2, 0,
-  "Return non-nil if ELT is an element of LIST.  Comparison done with EQUAL.\n\
+  "Return non-nil if ELT is an element of LIST.  Comparison done with `equal'.\n\
 The value is actually the tail of LIST whose car is ELT.")
   (elt, list)
      register Lisp_Object elt;
@@ -489,8 +532,8 @@ The value is actually the tail of LIST whose car is ELT.")
 }
 
 DEFUN ("assq", Fassq, Sassq, 2, 2, 0,
-  "Return non-nil if ELT is `eq' to the car of an element of LIST.\n\
-The value is actually the element of LIST whose car is ELT.\n\
+  "Return non-nil if KEY is `eq' to the car of an element of LIST.\n\
+The value is actually the element of LIST whose car is KEY.\n\
 Elements of LIST that are not conses are ignored.")
   (key, list)
      register Lisp_Object key;
@@ -530,8 +573,8 @@ assq_no_quit (key, list)
 }
 
 DEFUN ("assoc", Fassoc, Sassoc, 2, 2, 0,
-  "Return non-nil if ELT is `equal' to the car of an element of LIST.\n\
-The value is actually the element of LIST whose car is ELT.")
+  "Return non-nil if KEY is `equal' to the car of an element of LIST.\n\
+The value is actually the element of LIST whose car is KEY.")
   (key, list)
      register Lisp_Object key;
      Lisp_Object list;
@@ -605,8 +648,9 @@ to be sure of changing the value of `foo'.")
 DEFUN ("delete", Fdelete, Sdelete, 2, 2, 0,
   "Delete by side effect any occurrences of ELT as a member of LIST.\n\
 The modified LIST is returned.  Comparison is done with `equal'.\n\
-If the first member of LIST is ELT, there is no way to remove it by side effect;\n\
-therefore, write `(setq foo (delete element foo))'\n\
+If the first member of LIST is ELT, deleting it is not a side effect;\n\
+it is simply using a different list.\n\
+Therefore, write `(setq foo (delete element foo))'\n\
 to be sure of changing the value of `foo'.")
   (elt, list)
      register Lisp_Object elt;
@@ -620,7 +664,7 @@ to be sure of changing the value of `foo'.")
   while (!NILP (tail))
     {
       tem = Fcar (tail);
-      if (Fequal (elt, tem))
+      if (! NILP (Fequal (elt, tem)))
        {
          if (NILP (prev))
            list = Fcdr (tail);
@@ -819,63 +863,85 @@ DEFUN ("equal", Fequal, Sequal, 2, 2, 0,
 They must have the same data type.\n\
 Conses are compared by comparing the cars and the cdrs.\n\
 Vectors and strings are compared element by element.\n\
-Numbers are compared by value.  Symbols must match exactly.")
+Numbers are compared by value, but integers cannot equal floats.\n\
+ (Use `=' if you want integers and floats to be able to be equal.)\n\
+Symbols must match exactly.")
   (o1, o2)
      register Lisp_Object o1, o2;
 {
-  return internal_equal (o1, o2, 0);
+  return internal_equal (o1, o2, 0) ? Qt : Qnil;
 }
 
-static Lisp_Object
+static int
 internal_equal (o1, o2, depth)
      register Lisp_Object o1, o2;
      int depth;
 {
   if (depth > 200)
     error ("Stack overflow in equal");
-do_cdr:
+ tail_recurse:
   QUIT;
-  if (XTYPE (o1) != XTYPE (o2)) return Qnil;
-  if (XINT (o1) == XINT (o2)) return Qt;
-  if (XTYPE (o1) == Lisp_Cons)
+  if (EQ (o1, o2)) return 1;
+#ifdef LISP_FLOAT_TYPE
+  if (FLOATP (o1) && FLOATP (o2))
+    return (extract_float (o1) == extract_float (o2));
+#endif
+  if (XTYPE (o1) != XTYPE (o2)) return 0;
+  if (MISCP (o1) && XMISC (o1)->type != XMISC (o2)->type) return 0;
+  if (CONSP (o1))
     {
-      Lisp_Object v1;
-      v1 = Fequal (Fcar (o1), Fcar (o2), depth + 1);
-      if (NILP (v1))
-       return v1;
-      o1 = Fcdr (o1), o2 = Fcdr (o2);
-      goto do_cdr;
+      if (!internal_equal (XCONS (o1)->car, XCONS (o2)->car, depth + 1))
+       return 0;
+      o1 = XCONS (o1)->cdr;
+      o2 = XCONS (o2)->cdr;
+      goto tail_recurse;
     }
-  if (XTYPE (o1) == Lisp_Marker)
+  if (OVERLAYP (o1))
+    {
+      if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o1), depth + 1)
+         || !internal_equal (OVERLAY_END (o1), OVERLAY_END (o1), depth + 1))
+       return 0;
+      o1 = XOVERLAY (o1)->plist;
+      o2 = XOVERLAY (o2)->plist;
+      goto tail_recurse;
+    }
+  if (MARKERP (o1))
     {
       return (XMARKER (o1)->buffer == XMARKER (o2)->buffer
-             && XMARKER (o1)->bufpos == XMARKER (o2)->bufpos)
-       ? Qt : Qnil;
+             && (XMARKER (o1)->buffer == 0
+                 || XMARKER (o1)->bufpos == XMARKER (o2)->bufpos));
     }
-  if (XTYPE (o1) == Lisp_Vector)
+  if (VECTORP (o1) || COMPILEDP (o1))
     {
       register int index;
       if (XVECTOR (o1)->size != XVECTOR (o2)->size)
-       return Qnil;
+       return 0;
       for (index = 0; index < XVECTOR (o1)->size; index++)
        {
-         Lisp_Object v, v1, v2;
+         Lisp_Object v1, v2;
          v1 = XVECTOR (o1)->contents [index];
          v2 = XVECTOR (o2)->contents [index];
-         v = Fequal (v1, v2, depth + 1);
-         if (NILP (v)) return v;
+         if (!internal_equal (v1, v2, depth + 1))
+           return 0;
        }
-      return Qt;
+      return 1;
     }
-  if (XTYPE (o1) == Lisp_String)
+  if (STRINGP (o1))
     {
       if (XSTRING (o1)->size != XSTRING (o2)->size)
-       return Qnil;
+       return 0;
       if (bcmp (XSTRING (o1)->data, XSTRING (o2)->data, XSTRING (o1)->size))
-       return Qnil;
-      return Qt;
+       return 0;
+#ifdef USE_TEXT_PROPERTIES
+      /* If the strings have intervals, verify they match;
+        if not, they are unequal.  */
+      if ((XSTRING (o1)->intervals != 0 || XSTRING (o2)->intervals != 0)
+         && ! compare_string_intervals (o1, o2))
+       return 0;
+#endif
+      return 1;
     }
-  return Qnil;
+  return 0;
 }
 \f
 DEFUN ("fillarray", Ffillarray, Sfillarray, 2, 2, 0,
@@ -885,14 +951,14 @@ DEFUN ("fillarray", Ffillarray, Sfillarray, 2, 2, 0,
 {
   register int size, index, charval;
  retry:
-  if (XTYPE (array) == Lisp_Vector)
+  if (VECTORP (array))
     {
       register Lisp_Object *p = XVECTOR (array)->contents;
       size = XVECTOR (array)->size;
       for (index = 0; index < size; index++)
        p[index] = item;
     }
-  else if (XTYPE (array) == Lisp_String)
+  else if (STRINGP (array))
     {
       register unsigned char *p = XSTRING (array)->data;
       CHECK_NUMBER (item, 1);
@@ -991,7 +1057,7 @@ mapcar1 (leni, vals, fn, seq)
   /* We need not explicitly protect `tail' because it is used only on lists, and
     1) lists are not relocated and 2) the list is marked via `seq' so will not be freed */
 
-  if (XTYPE (seq) == Lisp_Vector)
+  if (VECTORP (seq))
     {
       for (i = 0; i < leni; i++)
        {
@@ -999,11 +1065,11 @@ mapcar1 (leni, vals, fn, seq)
          vals[i] = call1 (fn, dummy);
        }
     }
-  else if (XTYPE (seq) == Lisp_String)
+  else if (STRINGP (seq))
     {
       for (i = 0; i < leni; i++)
        {
-         XFASTINT (dummy) = XSTRING (seq)->data[i];
+         XSETFASTINT (dummy, XSTRING (seq)->data[i]);
          vals[i] = call1 (fn, dummy);
        }
     }
@@ -1023,7 +1089,7 @@ mapcar1 (leni, vals, fn, seq)
 DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0,
   "Apply FN to each element of SEQ, and concat the results as strings.\n\
 In between each pair of results, stick in SEP.\n\
-Thus, \" \" as SEP results in spaces between the values return by FN.")
+Thus, \" \" as SEP results in spaces between the values returned by FN.")
   (fn, seq, sep)
      Lisp_Object fn, seq, sep;
 {
@@ -1085,42 +1151,76 @@ Also accepts Space to mean yes, or Delete to mean no.")
   (prompt)
      Lisp_Object prompt;
 {
-  register Lisp_Object obj
-  register int ans;
+  register Lisp_Object obj, key, def, answer_string, map;
+  register int answer;
   Lisp_Object xprompt;
   Lisp_Object args[2];
   int ocech = cursor_in_echo_area;
   struct gcpro gcpro1, gcpro2;
 
+  map = Fsymbol_value (intern ("query-replace-map"));
+
   CHECK_STRING (prompt, 0);
   xprompt = prompt;
   GCPRO2 (prompt, xprompt);
 
   while (1)
     {
-      message ("%s(y or n) ", XSTRING (xprompt)->data);
+#ifdef HAVE_X_MENU
+      if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
+         && using_x_p ())
+       {
+         Lisp_Object pane, menu;
+         redisplay_preserve_echo_area ();
+         pane = Fcons (Fcons (build_string ("Yes"), Qt),
+                       Fcons (Fcons (build_string ("No"), Qnil),
+                              Qnil));
+         menu = Fcons (prompt, pane);
+         obj = Fx_popup_dialog (Qt, menu);
+         answer = !NILP (obj);
+         break;
+       }
+#endif
       cursor_in_echo_area = 1;
+      message ("%s(y or n) ", XSTRING (xprompt)->data);
 
-      obj = read_char (0, 0, 0, Qnil, 0);
-      if (XTYPE (obj) == Lisp_Int)
-       ans = XINT (obj);
-      else
-       continue;
+      obj = read_filtered_event (1, 0, 0);
+      cursor_in_echo_area = 0;
+      /* If we need to quit, quit with cursor_in_echo_area = 0.  */
+      QUIT;
 
-      cursor_in_echo_area = -1;
-      message ("%s(y or n) %c", XSTRING (xprompt)->data, ans);
-      cursor_in_echo_area = ocech;
-      /* Accept a C-g or C-] (abort-recursive-edit) as quit requests.  */
-      if (ans == 7 || ans == '\035')
+      key = Fmake_vector (make_number (1), obj);
+      def = Flookup_key (map, key);
+      answer_string = Fsingle_key_description (obj);
+
+      if (EQ (def, intern ("skip")))
+       {
+         answer = 0;
+         break;
+       }
+      else if (EQ (def, intern ("act")))
+       {
+         answer = 1;
+         break;
+       }
+      else if (EQ (def, intern ("recenter")))
+       {
+         Frecenter (Qnil);
+         xprompt = prompt;
+         continue;
+       }
+      else if (EQ (def, intern ("quit")))
+       Vquit_flag = Qt;
+      /* We want to exit this command for exit-prefix,
+        and this is the only way to do it.  */
+      else if (EQ (def, intern ("exit-prefix")))
        Vquit_flag = Qt;
+
       QUIT;
+
+      /* If we don't clear this, then the next call to read_char will
+        return quit_char again, and we'll enter an infinite loop.  */
       Vquit_flag = Qnil;
-      if (ans >= 0)
-       ans = DOWNCASE (ans);
-      if (ans == 'y' || ans == ' ')
-       { ans = 'y'; break; }
-      if (ans == 'n' || ans == 127)
-       break;
 
       Fding (Qnil);
       Fdiscard_input ();
@@ -1132,7 +1232,15 @@ Also accepts Space to mean yes, or Delete to mean no.")
        }
     }
   UNGCPRO;
-  return (ans == 'y' ? Qt : Qnil);
+
+  if (! noninteractive)
+    {
+      cursor_in_echo_area = -1;
+      message ("%s(y or n) %c", XSTRING (xprompt)->data, answer ? 'y' : 'n');
+      cursor_in_echo_area = ocech;
+    }
+
+  return answer ? Qt : Qnil;
 }
 \f
 /* This is how C code calls `yes-or-no-p' and allows the user
@@ -1161,17 +1269,37 @@ and can edit it until it as been confirmed.")
   register Lisp_Object ans;
   Lisp_Object args[2];
   struct gcpro gcpro1;
+  Lisp_Object menu;
 
   CHECK_STRING (prompt, 0);
 
+#ifdef HAVE_X_MENU
+  if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
+      && using_x_p ())
+    {
+      Lisp_Object pane, menu, obj;
+      redisplay_preserve_echo_area ();
+      pane = Fcons (Fcons (build_string ("Yes"), Qt),
+                   Fcons (Fcons (build_string ("No"), Qnil),
+                          Qnil));
+      GCPRO1 (pane);
+      menu = Fcons (prompt, pane);
+      obj = Fx_popup_dialog (Qt, menu);
+      UNGCPRO;
+      return obj;
+    }
+#endif
+
   args[0] = prompt;
   args[1] = build_string ("(yes or no) ");
   prompt = Fconcat (2, args);
 
   GCPRO1 (prompt);
+
   while (1)
     {
-      ans = Fdowncase (Fread_string (prompt, Qnil));
+      ans = Fdowncase (Fread_from_minibuffer (prompt, Qnil, Qnil, Qnil,
+                                             Qyes_or_no_p_history));
       if (XSTRING (ans)->size == 3 && !strcmp (XSTRING (ans)->data, "yes"))
        {
          UNGCPRO;
@@ -1188,7 +1316,6 @@ and can edit it until it as been confirmed.")
       message ("Please answer yes or no.");
       Fsleep_for (make_number (2), Qnil);
     }
-  UNGCPRO;
 }
 \f
 DEFUN ("load-average", Fload_average, Sload_average, 0, 0, 0,
@@ -1242,6 +1369,7 @@ DEFUN ("provide", Fprovide, Sprovide, 1, 1, 0,
   tem = Fmemq (feature, Vfeatures);
   if (NILP (tem))
     Vfeatures = Fcons (feature, Vfeatures);
+  LOADHIST_ATTACH (Fcons (Qprovide, feature));
   return feature;
 }
 
@@ -1256,6 +1384,7 @@ If FILENAME is omitted, the printname of FEATURE is used as the file name.")
   register Lisp_Object tem;
   CHECK_SYMBOL (feature, 0);
   tem = Fmemq (feature, Vfeatures);
+  LOADHIST_ATTACH (Fcons (Qrequire, feature));
   if (NILP (tem))
     {
       int count = specpdl_ptr - specpdl;
@@ -1283,6 +1412,12 @@ syms_of_fns ()
 {
   Qstring_lessp = intern ("string-lessp");
   staticpro (&Qstring_lessp);
+  Qprovide = intern ("provide");
+  staticpro (&Qprovide);
+  Qrequire = intern ("require");
+  staticpro (&Qrequire);
+  Qyes_or_no_p_history = intern ("yes-or-no-p-history");
+  staticpro (&Qyes_or_no_p_history);
 
   DEFVAR_LISP ("features", &Vfeatures,
     "A list of symbols which are the features of the executing emacs.\n\