]> code.delx.au - gnu-emacs/blobdiff - src/lread.c
[TARGET_API_MAC_CARBON] (mac_do_receive_drag): Don't
[gnu-emacs] / src / lread.c
index 31f974d9bc03bd41f6aaaf6ac1b7cdc2f5beb73a..b77a621f51881f19b3bb6808a1f342e3779590a6 100644 (file)
@@ -1,7 +1,7 @@
 /* Lisp parsing and input streams.
    Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994, 1995,
                  1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006 Free Software Foundation, Inc.
+                 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -132,7 +132,7 @@ static int load_force_doc_strings;
 /* Nonzero means read should convert strings to unibyte.  */
 static int load_convert_to_unibyte;
 
-/* Function to use for loading an Emacs lisp source file (not
+/* Function to use for loading an Emacs Lisp source file (not
    compiled) instead of readevalloop.  */
 Lisp_Object Vload_source_file_function;
 
@@ -214,6 +214,9 @@ static void readevalloop P_ ((Lisp_Object, FILE*, Lisp_Object,
 static Lisp_Object load_unwind P_ ((Lisp_Object));
 static Lisp_Object load_descriptor_unwind P_ ((Lisp_Object));
 
+static void invalid_syntax P_ ((const char *, int)) NO_RETURN;
+static void end_of_file_error P_ (()) NO_RETURN;
+
 \f
 /* Handle unreading and rereading of characters.
    Write READCHAR to read a character,
@@ -452,14 +455,19 @@ extern Lisp_Object read_char ();
    character.
 
    If INPUT_METHOD is nonzero, we invoke the current input method
-   if the character warrants that.  */
+   if the character warrants that.
+
+   If SECONDS is a number, we wait that many seconds for input, and
+   return Qnil if no input arrives within that time.  */
 
 Lisp_Object
 read_filtered_event (no_switch_frame, ascii_required, error_nonascii,
-                    input_method)
+                    input_method, seconds)
      int no_switch_frame, ascii_required, error_nonascii, input_method;
+     Lisp_Object seconds;
 {
-  register Lisp_Object val, delayed_switch_frame;
+  Lisp_Object val, delayed_switch_frame;
+  EMACS_TIME end_time;
 
 #ifdef HAVE_WINDOW_SYSTEM
   if (display_hourglass_p)
@@ -468,11 +476,24 @@ read_filtered_event (no_switch_frame, ascii_required, error_nonascii,
 
   delayed_switch_frame = Qnil;
 
+  /* Compute timeout.  */
+  if (NUMBERP (seconds))
+    {
+      EMACS_TIME wait_time;
+      int sec, usec;
+      double duration = extract_float (seconds);
+
+      sec  = (int) duration;
+      usec = (duration - sec) * 1000000;
+      EMACS_GET_TIME (end_time);
+      EMACS_SET_SECS_USECS (wait_time, sec, usec);
+      EMACS_ADD_TIME (end_time, end_time, wait_time);
+    }
+
   /* Read until we get an acceptable event.  */
  retry:
-  val = read_char (0, 0, 0,
-                  (input_method ? Qnil : Qt),
-                  0);
+  val = read_char (0, 0, 0, (input_method ? Qnil : Qt), 0,
+                  NUMBERP (seconds) ? &end_time : NULL);
 
   if (BUFFERP (val))
     goto retry;
@@ -484,13 +505,13 @@ read_filtered_event (no_switch_frame, ascii_required, error_nonascii,
      switch-frame events will read it and process it.  */
   if (no_switch_frame
       && EVENT_HAS_PARAMETERS (val)
-      && EQ (EVENT_HEAD (val), Qswitch_frame))
+      && EQ (EVENT_HEAD_KIND (EVENT_HEAD (val)), Qswitch_frame))
     {
       delayed_switch_frame = val;
       goto retry;
     }
 
-  if (ascii_required)
+  if (ascii_required && !(NUMBERP (seconds) && NILP (val)))
     {
       /* Convert certain symbols to their ASCII equivalents.  */
       if (SYMBOLP (val))
@@ -535,7 +556,7 @@ read_filtered_event (no_switch_frame, ascii_required, error_nonascii,
   return val;
 }
 
-DEFUN ("read-char", Fread_char, Sread_char, 0, 2, 0,
+DEFUN ("read-char", Fread_char, Sread_char, 0, 3, 0,
        doc: /* Read a character from the command input (keyboard or macro).
 It is returned as a number.
 If the user generates an event which is not a character (i.e. a mouse
@@ -548,43 +569,55 @@ If you want to read non-character events, or ignore them, call
 If the optional argument PROMPT is non-nil, display that as a prompt.
 If the optional argument INHERIT-INPUT-METHOD is non-nil and some
 input method is turned on in the current buffer, that input method
-is used for reading a character.  */)
-     (prompt, inherit_input_method)
-     Lisp_Object prompt, inherit_input_method;
+is used for reading a character.
+If the optional argument SECONDS is non-nil, it should be a number
+specifying the maximum number of seconds to wait for input.  If no
+input arrives in that time, return nil.  SECONDS may be a
+floating-point value.  */)
+     (prompt, inherit_input_method, seconds)
+     Lisp_Object prompt, inherit_input_method, seconds;
 {
   if (! NILP (prompt))
     message_with_string ("%s", prompt, 0);
-  return read_filtered_event (1, 1, 1, ! NILP (inherit_input_method));
+  return read_filtered_event (1, 1, 1, ! NILP (inherit_input_method), seconds);
 }
 
-DEFUN ("read-event", Fread_event, Sread_event, 0, 2, 0,
+DEFUN ("read-event", Fread_event, Sread_event, 0, 3, 0,
        doc: /* Read an event object from the input stream.
 If the optional argument PROMPT is non-nil, display that as a prompt.
 If the optional argument INHERIT-INPUT-METHOD is non-nil and some
 input method is turned on in the current buffer, that input method
-is used for reading a character.  */)
-     (prompt, inherit_input_method)
-     Lisp_Object prompt, inherit_input_method;
+is used for reading a character.
+If the optional argument SECONDS is non-nil, it should be a number
+specifying the maximum number of seconds to wait for input.  If no
+input arrives in that time, return nil.  SECONDS may be a
+floating-point value.  */)
+     (prompt, inherit_input_method, seconds)
+     Lisp_Object prompt, inherit_input_method, seconds;
 {
   if (! NILP (prompt))
     message_with_string ("%s", prompt, 0);
-  return read_filtered_event (0, 0, 0, ! NILP (inherit_input_method));
+  return read_filtered_event (0, 0, 0, ! NILP (inherit_input_method), seconds);
 }
 
-DEFUN ("read-char-exclusive", Fread_char_exclusive, Sread_char_exclusive, 0, 2, 0,
+DEFUN ("read-char-exclusive", Fread_char_exclusive, Sread_char_exclusive, 0, 3, 0,
        doc: /* Read a character from the command input (keyboard or macro).
 It is returned as a number.  Non-character events are ignored.
 
 If the optional argument PROMPT is non-nil, display that as a prompt.
 If the optional argument INHERIT-INPUT-METHOD is non-nil and some
 input method is turned on in the current buffer, that input method
-is used for reading a character.  */)
-     (prompt, inherit_input_method)
-     Lisp_Object prompt, inherit_input_method;
+is used for reading a character.
+If the optional argument SECONDS is non-nil, it should be a number
+specifying the maximum number of seconds to wait for input.  If no
+input arrives in that time, return nil.  SECONDS may be a
+floating-point value.  */)
+     (prompt, inherit_input_method, seconds)
+     Lisp_Object prompt, inherit_input_method, seconds;
 {
   if (! NILP (prompt))
     message_with_string ("%s", prompt, 0);
-  return read_filtered_event (1, 1, 0, ! NILP (inherit_input_method));
+  return read_filtered_event (1, 1, 0, ! NILP (inherit_input_method), seconds);
 }
 
 DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0,
@@ -797,10 +830,8 @@ Return t if the file exists and loads successfully.  */)
   if (fd == -1)
     {
       if (NILP (noerror))
-       Fsignal (Qfile_error, Fcons (build_string ("Cannot open load file"),
-                                    Fcons (file, Qnil)));
-      else
-       return Qnil;
+       xsignal2 (Qfile_error, build_string ("Cannot open load file"), file);
+      return Qnil;
     }
 
   /* Tell startup.el whether or not we found the user's init file.  */
@@ -841,8 +872,7 @@ Return t if the file exists and loads successfully.  */)
       {
        if (fd >= 0)
          emacs_close (fd);
-       Fsignal (Qerror, Fcons (build_string ("Recursive load"),
-                               Fcons (found, Vloads_in_progress)));
+       signal_error ("Recursive load", Fcons (found, Vloads_in_progress));
       }
     record_unwind_protect (record_load_unwind, Vloads_in_progress);
     Vloads_in_progress = Fcons (found, Vloads_in_progress);
@@ -1339,11 +1369,9 @@ end_of_file_error ()
   Lisp_Object data;
 
   if (STRINGP (Vload_file_name))
-    data = Fcons (Vload_file_name, Qnil);
-  else
-    data = Qnil;
+    xsignal1 (Qend_of_file, Vload_file_name);
 
-  Fsignal (Qend_of_file, data);
+  xsignal0 (Qend_of_file);
 }
 
 /* UNIBYTE specifies how to set load_convert_to_unibyte
@@ -1369,7 +1397,6 @@ readevalloop (readcharfun, stream, sourcename, evalfun,
   int count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   struct buffer *b = 0;
-  int bpos;
   int continue_reading_p;
   /* Nonzero if reading an entire buffer.  */
   int whole_buffer = 0;
@@ -1379,7 +1406,7 @@ readevalloop (readcharfun, stream, sourcename, evalfun,
   if (MARKERP (readcharfun))
     {
       if (NILP (start))
-       start = readcharfun;    
+       start = readcharfun;
     }
 
   if (BUFFERP (readcharfun))
@@ -1402,8 +1429,8 @@ readevalloop (readcharfun, stream, sourcename, evalfun,
 
   /* Try to ensure sourcename is a truename, except whilst preloading. */
   if (NILP (Vpurify_flag)
-      && !NILP (sourcename) && Ffile_name_absolute_p (sourcename)
-      && (!NILP (Ffboundp (Qfile_truename))))
+      && !NILP (sourcename) && !NILP (Ffile_name_absolute_p (sourcename))
+      && !NILP (Ffboundp (Qfile_truename)))
     sourcename = call1 (Qfile_truename, sourcename) ;
 
   LOADHIST_ATTACH (sourcename);
@@ -1512,7 +1539,7 @@ readevalloop (readcharfun, stream, sourcename, evalfun,
       first_sexp = 0;
     }
 
-  build_load_history (sourcename, 
+  build_load_history (sourcename,
                      stream || whole_buffer);
 
   UNGCPRO;
@@ -1525,7 +1552,7 @@ DEFUN ("eval-buffer", Feval_buffer, Seval_buffer, 0, 5, "",
 Programs can pass two arguments, BUFFER and PRINTFLAG.
 BUFFER is the buffer to evaluate (nil means use current buffer).
 PRINTFLAG controls printing of output:
-nil means discard it; anything else is stream for print.
+A value of nil means discard it; anything else is stream for print.
 
 If the optional third argument FILENAME is non-nil,
 it specifies the file name to use for `load-history'.
@@ -1574,7 +1601,7 @@ When called from programs, expects two arguments,
 giving starting and ending indices in the current buffer
 of the text to be executed.
 Programs can pass third argument PRINTFLAG which controls output:
-nil means discard it; anything else is stream for printing it.
+A value of nil means discard it; anything else is stream for printing it.
 Also the fourth argument READ-FUNCTION, if non-nil, is used
 instead of `read' to read each expression.  It gets one argument
 which is the input stream for reading characters.
@@ -1695,6 +1722,21 @@ read_internal_start (stream, start, end)
   return retval;
 }
 \f
+
+/* Signal Qinvalid_read_syntax error.
+   S is error string of length N (if > 0)  */
+
+static void
+invalid_syntax (s, n)
+     const char *s;
+     int n;
+{
+  if (!n)
+    n = strlen (s);
+  xsignal1 (Qinvalid_read_syntax, make_string (s, n));
+}
+
+
 /* Use this for recursive reads, in contexts where internal tokens
    are not allowed. */
 
@@ -1706,12 +1748,11 @@ read0 (readcharfun)
   int c;
 
   val = read1 (readcharfun, &c, 0);
-  if (c)
-    Fsignal (Qinvalid_read_syntax, Fcons (Fmake_string (make_number (1),
-                                                       make_number (c)),
-                                         Qnil));
+  if (!c)
+    return val;
 
-  return val;
+  xsignal1 (Qinvalid_read_syntax,
+           Fmake_string (make_number (1), make_number (c)));
 }
 \f
 static int read_buffer_size;
@@ -1764,6 +1805,9 @@ read_escape (readcharfun, stringp, byterep)
      int *byterep;
 {
   register int c = READCHAR;
+  /* \u allows up to four hex digits, \U up to eight. Default to the
+     behaviour for \u, and change this value in the case that \U is seen. */
+  int unicode_hex_count = 4;
 
   *byterep = 0;
 
@@ -1928,6 +1972,47 @@ read_escape (readcharfun, stringp, byterep)
        return i;
       }
 
+    case 'U':
+      /* Post-Unicode-2.0: Up to eight hex chars.  */
+      unicode_hex_count = 8;
+    case 'u':
+
+      /* A Unicode escape. We only permit them in strings and characters,
+        not arbitrarily in the source code, as in some other languages.  */
+      {
+       int i = 0;
+       int count = 0;
+       Lisp_Object lisp_char;
+       struct gcpro gcpro1;
+
+       while (++count <= unicode_hex_count)
+         {
+           c = READCHAR;
+           /* isdigit and isalpha may be locale-specific, which we don't
+              want. */
+           if      (c >= '0' && c <= '9')  i = (i << 4) + (c - '0');
+           else if (c >= 'a' && c <= 'f')  i = (i << 4) + (c - 'a') + 10;
+            else if (c >= 'A' && c <= 'F')  i = (i << 4) + (c - 'A') + 10;
+           else
+             {
+               error ("Non-hex digit used for Unicode escape");
+               break;
+             }
+         }
+
+       GCPRO1 (readcharfun);
+       lisp_char = call2 (intern ("decode-char"), intern ("ucs"),
+                         make_number (i));
+       UNGCPRO;
+
+       if (NILP (lisp_char))
+         {
+           error ("Unsupported Unicode code point: U+%x", (unsigned)i);
+         }
+
+       return XFASTINT (lisp_char);
+      }
+
     default:
       if (BASE_LEADING_CODE_P (c))
        c = read_multibyte (c, readcharfun);
@@ -1935,7 +2020,6 @@ read_escape (readcharfun, stringp, byterep)
     }
 }
 
-
 /* Read an integer in radix RADIX using READCHARFUN to read
    characters.  RADIX must be in the interval [2..36]; if it isn't, a
    read error is signaled .  Value is the integer read.  Signals an
@@ -1995,7 +2079,7 @@ read_integer (readcharfun, radix)
     {
       char buf[50];
       sprintf (buf, "integer, radix %d", radix);
-      Fsignal (Qinvalid_read_syntax, Fcons (build_string (buf), Qnil));
+      invalid_syntax (buf, 0);
     }
 
   return make_number (sign * number);
@@ -2106,10 +2190,9 @@ read1 (readcharfun, pch, first_in_list)
                  XCHAR_TABLE (tmp)->top = Qnil;
                  return tmp;
                }
-             Fsignal (Qinvalid_read_syntax,
-                      Fcons (make_string ("#^^", 3), Qnil));
+             invalid_syntax ("#^^", 3);
            }
-         Fsignal (Qinvalid_read_syntax, Fcons (make_string ("#^", 2), Qnil));
+         invalid_syntax ("#^", 2);
        }
       if (c == '&')
        {
@@ -2131,8 +2214,7 @@ read1 (readcharfun, pch, first_in_list)
                     Accept such input in case it came from an old version.  */
                  && ! (XFASTINT (length)
                        == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR))
-               Fsignal (Qinvalid_read_syntax,
-                        Fcons (make_string ("#&...", 5), Qnil));
+               invalid_syntax ("#&...", 5);
 
              val = Fmake_bool_vector (length, Qnil);
              bcopy (SDATA (tmp), XBOOL_VECTOR (val)->data,
@@ -2143,8 +2225,7 @@ read1 (readcharfun, pch, first_in_list)
                  &= (1 << (XINT (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1;
              return val;
            }
-         Fsignal (Qinvalid_read_syntax, Fcons (make_string ("#&...", 5),
-                                               Qnil));
+         invalid_syntax ("#&...", 5);
        }
       if (c == '[')
        {
@@ -2164,7 +2245,7 @@ read1 (readcharfun, pch, first_in_list)
          /* Read the string itself.  */
          tmp = read1 (readcharfun, &ch, 0);
          if (ch != 0 || !STRINGP (tmp))
-           Fsignal (Qinvalid_read_syntax, Fcons (make_string ("#", 1), Qnil));
+           invalid_syntax ("#", 1);
          GCPRO1 (tmp);
          /* Read the intervals and their properties.  */
          while (1)
@@ -2180,9 +2261,7 @@ read1 (readcharfun, pch, first_in_list)
              if (ch == 0)
                plist = read1 (readcharfun, &ch, 0);
              if (ch)
-               Fsignal (Qinvalid_read_syntax,
-                        Fcons (build_string ("invalid string property list"),
-                               Qnil));
+               invalid_syntax ("Invalid string property list", 0);
              Fset_text_properties (beg, end, plist, tmp);
            }
          UNGCPRO;
@@ -2335,7 +2414,7 @@ read1 (readcharfun, pch, first_in_list)
        return read_integer (readcharfun, 2);
 
       UNREAD (c);
-      Fsignal (Qinvalid_read_syntax, Fcons (make_string ("#", 1), Qnil));
+      invalid_syntax ("#", 1);
 
     case ';':
       while ((c = READCHAR) >= 0 && c != '\n');
@@ -2429,10 +2508,10 @@ read1 (readcharfun, pch, first_in_list)
                          || (new_backquote_flag && next_char == ','))));
          }
        UNREAD (next_char);
-       if (!ok)
-         Fsignal (Qinvalid_read_syntax, Fcons (make_string ("?", 1), Qnil));
+       if (ok)
+         return make_number (c);
 
-       return make_number (c);
+       invalid_syntax ("?", 1);
       }
 
     case '"':
@@ -3077,8 +3156,7 @@ read_list (flag, readcharfun)
            {
              if (ch == ']')
                return val;
-             Fsignal (Qinvalid_read_syntax,
-                      Fcons (make_string (") or . in a vector", 18), Qnil));
+             invalid_syntax (") or . in a vector", 18);
            }
          if (ch == ')')
            return val;
@@ -3171,9 +3249,9 @@ read_list (flag, readcharfun)
 
                  return val;
                }
-             return Fsignal (Qinvalid_read_syntax, Fcons (make_string (". in wrong context", 18), Qnil));
+             invalid_syntax (". in wrong context", 18);
            }
-         return Fsignal (Qinvalid_read_syntax, Fcons (make_string ("] in a list", 11), Qnil));
+         invalid_syntax ("] in a list", 11);
        }
       tem = (read_pure && flag <= 0
             ? pure_cons (elt, Qnil)
@@ -3206,12 +3284,11 @@ Lisp_Object
 check_obarray (obarray)
      Lisp_Object obarray;
 {
-  while (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
+  if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
     {
       /* If Vobarray is now invalid, force it to be valid.  */
       if (EQ (Vobarray, obarray)) Vobarray = initial_obarray;
-
-      obarray = wrong_type_argument (Qvectorp, obarray);
+      wrong_type_argument (Qvectorp, obarray);
     }
   return obarray;
 }
@@ -4040,7 +4117,7 @@ The default is nil, which means use the function `read'.  */);
   Vload_read_function = Qnil;
 
   DEFVAR_LISP ("load-source-file-function", &Vload_source_file_function,
-              doc: /* Function called in `load' for loading an Emacs lisp source file.
+              doc: /* Function called in `load' for loading an Emacs Lisp source file.
 This function is for doing code conversion before reading the source file.
 If nil, loading is done without any code conversion.
 Arguments are FULLNAME, FILE, NOERROR, NOMESSAGE, where