emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 9f496c5 3/3: Merge branch 'master' of git.sv.gnu.or


From: Michael Albinus
Subject: [Emacs-diffs] master 9f496c5 3/3: Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs
Date: Mon, 5 Jun 2017 07:00:25 -0400 (EDT)

branch: master
commit 9f496c591d457b511a42c0f63e0d2d923cda0247
Merge: 751d592 13e9493
Author: Michael Albinus <address@hidden>
Commit: Michael Albinus <address@hidden>

    Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs
---
 doc/lispref/strings.texi       |  13 ++--
 lisp/desktop.el                |   4 +
 lisp/linum.el                  |  11 ++-
 lisp/progmodes/elisp-mode.el   |   2 +-
 src/data.c                     |  10 +--
 src/dynlib.c                   |  34 ++++-----
 src/dynlib.h                   |  16 ++--
 src/editfns.c                  | 154 +++++++++++++++++----------------------
 src/emacs-module.c             | 162 +++++++++++++++++++++--------------------
 src/emacs-module.h             |   3 +
 src/eval.c                     |   7 +-
 src/lisp.h                     |  16 ++--
 src/print.c                    |  30 +++++++-
 test/Makefile.in               |   2 +-
 test/src/emacs-module-tests.el |   4 +-
 15 files changed, 250 insertions(+), 218 deletions(-)

diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index f365c80..23961f9 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -926,7 +926,8 @@ digit.
 
 @item %%
 Replace the specification with a single @samp{%}.  This format
-specification is unusual in that it does not use a value.  For example,
+specification is unusual in that its only form is plain
address@hidden and that it does not use a value.  For example,
 @code{(format "%% %d" 30)} returns @code{"% 30"}.
 @end table
 
@@ -965,10 +966,9 @@ extra values to be formatted are ignored.
 decimal number immediately after the initial @samp{%}, followed by a
 literal dollar sign @samp{$}.  It causes the format specification to
 convert the argument with the given number instead of the next
-argument.  Field numbers start at 1.  A field number should differ
-from the other field numbers in the same format.  A format can contain
-either numbered or unnumbered format specifications but not both,
-except that @samp{%%} can be mixed with numbered specifications.
+argument.  Field numbers start at 1.  A format can contain either
+numbered or unnumbered format specifications but not both, except that
address@hidden can be mixed with numbered specifications.
 
 @example
 (format "%2$s, %3$s, %%, %1$s" "x" "y" "z")
@@ -1026,8 +1026,7 @@ ignored.
   A specification can have a @dfn{width}, which is a decimal number
 that appears after any field number and flags.  If the printed
 representation of the object contains fewer characters than this
-width, @code{format} extends it with padding.  The width is
-ignored for the @samp{%%} specification.  Any padding introduced by
+width, @code{format} extends it with padding.  Any padding introduced by
 the width normally consists of spaces inserted on the left:
 
 @example
diff --git a/lisp/desktop.el b/lisp/desktop.el
index 39dc92f..540d0e3 100644
--- a/lisp/desktop.el
+++ b/lisp/desktop.el
@@ -733,6 +733,10 @@ if different)."
        (condition-case err
            (unless (or (eq frame this)
                        (eq frame mini)
+                        ;; Don't delete daemon's initial frame, or
+                        ;; we'll never be able to close the last
+                        ;; client's frame (Bug#26912).
+                        (if (daemonp) (not (frame-parameter frame 'client)))
                        (frame-parameter frame 'desktop-dont-clear))
              (delete-frame frame))
          (error
diff --git a/lisp/linum.el b/lisp/linum.el
index 8baa263..9cfb94d 100644
--- a/lisp/linum.el
+++ b/lisp/linum.el
@@ -112,7 +112,16 @@ Linum mode is a buffer-local minor mode."
 (define-globalized-minor-mode global-linum-mode linum-mode linum-on)
 
 (defun linum-on ()
-  (unless (minibufferp)
+  (unless (or (minibufferp)
+              ;; Turning linum-mode in the daemon's initial frame
+              ;; could significantly slow down startup, if the buffer
+              ;; in which this is done is large, because Emacs thinks
+              ;; the "window" spans the entire buffer then.  This
+              ;; could happen when restoring session via desktop.el,
+              ;; if some large buffer was under linum-mode when
+              ;; desktop was saved.  So we disable linum-mode for
+              ;; non-client frames in a daemon session.
+              (and (daemonp) (null (frame-parameter nil 'client))))
     (linum-mode 1)))
 
 (defun linum-delete-overlays ()
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 6c6fb92..b3f452c 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -1372,7 +1372,7 @@ or elsewhere, return a 1-line docstring."
                                (condition-case nil (documentation sym t)
                                  (invalid-function nil))
                                sym))
-                    (car doc))
+                    (substitute-command-keys (car doc)))
                    (t (help-function-arglist sym)))))
              ;; Stringify, and store before highlighting, downcasing, etc.
             (elisp--last-data-store sym (elisp-function-argstring args)
diff --git a/src/data.c b/src/data.c
index 2585910..e4e5529 100644
--- a/src/data.c
+++ b/src/data.c
@@ -700,12 +700,10 @@ global value outside of any lexical scope.  */)
   return (EQ (valcontents, Qunbound) ? Qnil : Qt);
 }
 
-/* FIXME: It has been previously suggested to make this function an
-   alias for symbol-function, but upon discussion at Bug#23957,
-   there is a risk breaking backward compatibility, as some users of
-   fboundp may expect `t' in particular, rather than any true
-   value.  An alias is still welcome so long as the compatibility
-   issues are addressed.  */
+/* It has been previously suggested to make this function an alias for
+   symbol-function, but upon discussion at Bug#23957, there is a risk
+   breaking backward compatibility, as some users of fboundp may
+   expect `t' in particular, rather than any true value.  */
 DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0,
        doc: /* Return t if SYMBOL's function definition is not void.  */)
   (register Lisp_Object symbol)
diff --git a/src/dynlib.c b/src/dynlib.c
index 9561923..79e98b0 100644
--- a/src/dynlib.c
+++ b/src/dynlib.c
@@ -28,6 +28,8 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 
 #include "dynlib.h"
 
+#include <stddef.h>
+
 #ifdef WINDOWSNT
 
 /* MS-Windows systems.  */
@@ -120,7 +122,7 @@ dynlib_sym (dynlib_handle_ptr h, const char *sym)
   return (void *)sym_addr;
 }
 
-bool
+void
 dynlib_addr (void *addr, const char **fname, const char **symname)
 {
   static char dll_filename[MAX_UTF8_PATH];
@@ -128,7 +130,6 @@ dynlib_addr (void *addr, const char **fname, const char 
**symname)
   static GetModuleHandleExA_Proc s_pfn_Get_Module_HandleExA = NULL;
   char *dll_fn = NULL;
   HMODULE hm_kernel32 = NULL;
-  bool result = false;
   HMODULE hm_dll = NULL;
   wchar_t mfn_w[MAX_PATH];
   char mfn_a[MAX_PATH];
@@ -206,23 +207,18 @@ dynlib_addr (void *addr, const char **fname, const char 
**symname)
            dynlib_last_err = GetLastError ();
        }
       if (dll_fn)
-       {
-         dostounix_filename (dll_fn);
-         /* We cannot easily produce the function name, since
-            typically all of the module functions will be unexported,
-            and probably even static, which means the symbols can be
-            obtained only if we link against libbfd (and the DLL can
-            be stripped anyway).  So we just show the address and the
-            file name; they can use that with addr2line or GDB to
-            recover the symbolic name.  */
-         sprintf (addr_str, "at 0x%x", (DWORD_PTR)addr);
-         *symname = addr_str;
-         result = true;
-       }
+        dostounix_filename (dll_fn);
     }
 
   *fname = dll_fn;
-  return result;
+
+  /* We cannot easily produce the function name, since typically all
+     of the module functions will be unexported, and probably even
+     static, which means the symbols can be obtained only if we link
+     against libbfd (and the DLL can be stripped anyway).  So we just
+     show the address and the file name; they can use that with
+     addr2line or GDB to recover the symbolic name.  */
+  *symname = NULL;
 }
 
 const char *
@@ -283,19 +279,19 @@ dynlib_sym (dynlib_handle_ptr h, const char *sym)
   return dlsym (h, sym);
 }
 
-bool
+void
 dynlib_addr (void *ptr, const char **path, const char **sym)
 {
+  *path = NULL;
+  *sym = NULL;
 #ifdef HAVE_DLADDR
   Dl_info info;
   if (dladdr (ptr, &info) && info.dli_fname && info.dli_sname)
     {
       *path = info.dli_fname;
       *sym = info.dli_sname;
-      return true;
     }
 #endif
-  return false;
 }
 
 const char *
diff --git a/src/dynlib.h b/src/dynlib.h
index 5ccec11..1d53b8e 100644
--- a/src/dynlib.h
+++ b/src/dynlib.h
@@ -24,11 +24,17 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 
 typedef void *dynlib_handle_ptr;
 dynlib_handle_ptr dynlib_open (const char *path);
-void *dynlib_sym (dynlib_handle_ptr h, const char *sym);
-typedef struct dynlib_function_ptr_nonce *(*dynlib_function_ptr) (void);
-dynlib_function_ptr dynlib_func (dynlib_handle_ptr h, const char *sym);
-bool dynlib_addr (void *ptr, const char **path, const char **sym);
-const char *dynlib_error (void);
 int dynlib_close (dynlib_handle_ptr h);
+const char *dynlib_error (void);
+
+ATTRIBUTE_MAY_ALIAS void *dynlib_sym (dynlib_handle_ptr h, const char *sym);
+
+typedef struct dynlib_function_ptr_nonce *(ATTRIBUTE_MAY_ALIAS 
*dynlib_function_ptr) (void);
+dynlib_function_ptr dynlib_func (dynlib_handle_ptr h, const char *sym);
+
+/* Sets *FILE to the file name from which PTR was loaded, and *SYM to
+   its symbol name.  If the file or symbol name could not be
+   determined, set the corresponding argument to NULL.  */
+void dynlib_addr (void *ptr, const char **file, const char **sym);
 
 #endif /* DYNLIB_H */
diff --git a/src/editfns.c b/src/editfns.c
index 56aa8ce..43b17f9 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3891,8 +3891,8 @@ the next available argument, or the argument explicitly 
specified:
 The argument used for %d, %o, %x, %e, %f, %g or %c must be a number.
 Use %% to put a single % into the output.
 
-A %-sequence may contain optional field number, flag, width, and
-precision specifiers, as follows:
+A %-sequence other than %% may contain optional field number, flag,
+width, and precision specifiers, as follows:
 
   %<field><flags><width><precision>character
 
@@ -3901,10 +3901,9 @@ where field is [0-9]+ followed by a literal dollar "$", 
flags is
 followed by [0-9]+.
 
 If a %-sequence is numbered with a field with positive value N, the
-Nth argument is substituted instead of the next one.  A field number
-should differ from the other field numbers in the same format.  A
-format can contain either numbered or unnumbered %-sequences but not
-both, except that %% can be mixed with numbered %-sequences.
+Nth argument is substituted instead of the next one.  A format can
+contain either numbered or unnumbered %-sequences but not both, except
+that %% can be mixed with numbered %-sequences.
 
 The + flag character inserts a + before any positive number, while a
 space inserts a space before any positive number; these flags only
@@ -3980,49 +3979,40 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
   bool arg_intervals = false;
   USE_SAFE_ALLOCA;
 
-  /* Each element records, for one field,
-     the corresponding argument,
-     the start and end bytepos in the output string,
-     whether the argument has been converted to string (e.g., due to "%S"),
-     and whether the argument is a string with intervals.  */
+  /* Information recorded for each format spec.  */
   struct info
   {
+    /* The corresponding argument, converted to string if conversion
+       was needed.  */
     Lisp_Object argument;
+
+    /* The start and end bytepos in the output string.  */
     ptrdiff_t start, end;
-    bool_bf converted_to_string : 1;
+
+    /* Whether the argument is a string with intervals.  */
     bool_bf intervals : 1;
   } *info;
 
   CHECK_STRING (args[0]);
   char *format_start = SSDATA (args[0]);
+  bool multibyte_format = STRING_MULTIBYTE (args[0]);
   ptrdiff_t formatlen = SBYTES (args[0]);
 
-  /* The number of percent characters is a safe upper bound for the
-     number of format fields.  */
-  ptrdiff_t num_percent = 0;
-  for (ptrdiff_t i = 0; i < formatlen; ++i)
-    if (format_start[i] == '%')
-      ++num_percent;
+  /* Upper bound on number of format specs.  Each uses at least 2 chars.  */
+  ptrdiff_t nspec_bound = SCHARS (args[0]) >> 1;
 
   /* Allocate the info and discarded tables.  */
   ptrdiff_t alloca_size;
-  if (INT_MULTIPLY_WRAPV (num_percent, sizeof *info, &alloca_size)
-      || INT_ADD_WRAPV (sizeof *info, alloca_size, &alloca_size)
+  if (INT_MULTIPLY_WRAPV (nspec_bound, sizeof *info, &alloca_size)
       || INT_ADD_WRAPV (formatlen, alloca_size, &alloca_size)
       || SIZE_MAX < alloca_size)
     memory_full (SIZE_MAX);
-  /* info[0] is unused.  Unused elements have -1 for start.  */
   info = SAFE_ALLOCA (alloca_size);
-  memset (info, 0, alloca_size);
-  for (ptrdiff_t i = 0; i < num_percent + 1; i++)
-    {
-      info[i].argument = Qunbound;
-      info[i].start = -1;
-    }
   /* discarded[I] is 1 if byte I of the format
      string was not copied into the output.
      It is 2 if byte I was not the first byte of its character.  */
-  char *discarded = (char *) &info[num_percent + 1];
+  char *discarded = (char *) &info[nspec_bound];
+  memset (discarded, 0, formatlen);
 
   /* Try to determine whether the result should be multibyte.
      This is not always right; sometimes the result needs to be multibyte
@@ -4030,8 +4020,6 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
      or because a grave accent or apostrophe is requoted,
      and in that case, we won't know it here.  */
 
-  /* True if the format is multibyte.  */
-  bool multibyte_format = STRING_MULTIBYTE (args[0]);
   /* True if the output should be a multibyte string,
      which is true if any of the inputs is one.  */
   bool multibyte = multibyte_format;
@@ -4042,6 +4030,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
   int quoting_style = message ? text_quoting_style () : -1;
 
   ptrdiff_t ispec;
+  ptrdiff_t nspec = 0;
 
   /* If we start out planning a unibyte result,
      then discover it has to be multibyte, we jump back to retry.  */
@@ -4155,11 +4144,14 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
          if (! (n < nargs))
            error ("Not enough arguments for format string");
 
-          eassert (ispec < num_percent);
-          ++ispec;
-
-          if (EQ (info[ispec].argument, Qunbound))
-            info[ispec].argument = args[n];
+         struct info *spec = &info[ispec++];
+         if (nspec < ispec)
+           {
+             spec->argument = args[n];
+             spec->intervals = false;
+             nspec = ispec;
+           }
+         Lisp_Object arg = spec->argument;
 
          /* For 'S', prin1 the argument, and then treat like 's'.
             For 's', princ any argument that is not a string or
@@ -4167,16 +4159,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
             happen after retrying.  */
          if ((conversion == 'S'
               || (conversion == 's'
-                  && ! STRINGP (info[ispec].argument)
-                   && ! SYMBOLP (info[ispec].argument))))
+                  && ! STRINGP (arg) && ! SYMBOLP (arg))))
            {
-             if (! info[ispec].converted_to_string)
+             if (EQ (arg, args[n]))
                {
                  Lisp_Object noescape = conversion == 'S' ? Qnil : Qt;
-                 info[ispec].argument =
-                    Fprin1_to_string (info[ispec].argument, noescape);
-                 info[ispec].converted_to_string = true;
-                 if (STRING_MULTIBYTE (info[ispec].argument) && ! multibyte)
+                 spec->argument = arg = Fprin1_to_string (arg, noescape);
+                 if (STRING_MULTIBYTE (arg) && ! multibyte)
                    {
                      multibyte = true;
                      goto retry;
@@ -4186,29 +4175,25 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
            }
          else if (conversion == 'c')
            {
-             if (INTEGERP (info[ispec].argument)
-                  && ! ASCII_CHAR_P (XINT (info[ispec].argument)))
+             if (INTEGERP (arg) && ! ASCII_CHAR_P (XINT (arg)))
                {
                  if (!multibyte)
                    {
                      multibyte = true;
                      goto retry;
                    }
-                 info[ispec].argument =
-                    Fchar_to_string (info[ispec].argument);
-                 info[ispec].converted_to_string = true;
+                 spec->argument = arg = Fchar_to_string (arg);
                }
 
-             if (info[ispec].converted_to_string)
+             if (!EQ (arg, args[n]))
                conversion = 's';
              zero_flag = false;
            }
 
-         if (SYMBOLP (info[ispec].argument))
+         if (SYMBOLP (arg))
            {
-             info[ispec].argument =
-                SYMBOL_NAME (info[ispec].argument);
-             if (STRING_MULTIBYTE (info[ispec].argument) && ! multibyte)
+             spec->argument = arg = SYMBOL_NAME (arg);
+             if (STRING_MULTIBYTE (arg) && ! multibyte)
                {
                  multibyte = true;
                  goto retry;
@@ -4239,12 +4224,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
              else
                {
                  ptrdiff_t nch, nby;
-                 width = lisp_string_width (info[ispec].argument,
-                                             prec, &nch, &nby);
+                 width = lisp_string_width (arg, prec, &nch, &nby);
                  if (prec < 0)
                    {
-                     nchars_string = SCHARS (info[ispec].argument);
-                     nbytes = SBYTES (info[ispec].argument);
+                     nchars_string = SCHARS (arg);
+                     nbytes = SBYTES (arg);
                    }
                  else
                    {
@@ -4254,11 +4238,8 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                }
 
              convbytes = nbytes;
-             if (convbytes && multibyte &&
-                  ! STRING_MULTIBYTE (info[ispec].argument))
-               convbytes =
-                  count_size_as_multibyte (SDATA (info[ispec].argument),
-                                           nbytes);
+             if (convbytes && multibyte && ! STRING_MULTIBYTE (arg))
+               convbytes = count_size_as_multibyte (SDATA (arg), nbytes);
 
              ptrdiff_t padding
                = width < field_width ? field_width - width : 0;
@@ -4274,20 +4255,18 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                      p += padding;
                      nchars += padding;
                    }
-                  info[ispec].start = nchars;
+                 spec->start = nchars;
 
                  if (p > buf
                      && multibyte
                      && !ASCII_CHAR_P (*((unsigned char *) p - 1))
-                     && STRING_MULTIBYTE (info[ispec].argument)
-                     && !CHAR_HEAD_P (SREF (info[ispec].argument, 0)))
+                     && STRING_MULTIBYTE (arg)
+                     && !CHAR_HEAD_P (SREF (arg, 0)))
                    maybe_combine_byte = true;
 
-                 p += copy_text (SDATA (info[ispec].argument),
-                                  (unsigned char *) p,
+                 p += copy_text (SDATA (arg), (unsigned char *) p,
                                  nbytes,
-                                 STRING_MULTIBYTE (info[ispec].argument),
-                                  multibyte);
+                                 STRING_MULTIBYTE (arg), multibyte);
 
                  nchars += nchars_string;
 
@@ -4297,12 +4276,12 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                      p += padding;
                      nchars += padding;
                    }
-                 info[ispec].end = nchars;
+                 spec->end = nchars;
 
                  /* If this argument has text properties, record where
                     in the result string it appears.  */
-                 if (string_intervals (info[ispec].argument))
-                   info[ispec].intervals = arg_intervals = true;
+                 if (string_intervals (arg))
+                   spec->intervals = arg_intervals = true;
 
                  continue;
                }
@@ -4313,8 +4292,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                      || conversion == 'X'))
            error ("Invalid format operation %%%c",
                   STRING_CHAR ((unsigned char *) format - 1));
-         else if (! (INTEGERP (info[ispec].argument)
-                     || (FLOATP (info[ispec].argument) && conversion != 'c')))
+         else if (! (INTEGERP (arg) || (FLOATP (arg) && conversion != 'c')))
            error ("Format specifier doesn't match argument type");
          else
            {
@@ -4376,7 +4354,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                    if (INT_AS_LDBL)
                      {
                        *f = 'L';
-                       f += INTEGERP (info[ispec].argument);
+                       f += INTEGERP (arg);
                      }
                  }
                else if (conversion != 'c')
@@ -4408,22 +4386,22 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
              ptrdiff_t sprintf_bytes;
              if (float_conversion)
                {
-                 if (INT_AS_LDBL && INTEGERP (info[ispec].argument))
+                 if (INT_AS_LDBL && INTEGERP (arg))
                    {
                      /* Although long double may have a rounding error if
                         DIG_BITS_LBOUND * LDBL_MANT_DIG < FIXNUM_BITS - 1,
                         it is more accurate than plain 'double'.  */
-                     long double x = XINT (info[ispec].argument);
+                     long double x = XINT (arg);
                      sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
                    }
                  else
                    sprintf_bytes = sprintf (sprintf_buf, convspec, prec,
-                                            XFLOATINT (info[ispec].argument));
+                                            XFLOATINT (arg));
                }
              else if (conversion == 'c')
                {
                  /* Don't use sprintf here, as it might mishandle prec.  */
-                 sprintf_buf[0] = XINT (info[ispec].argument);
+                 sprintf_buf[0] = XINT (arg);
                  sprintf_bytes = prec != 0;
                }
              else if (conversion == 'd' || conversion == 'i')
@@ -4432,11 +4410,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                     instead so it also works for values outside
                     the integer range.  */
                  printmax_t x;
-                 if (INTEGERP (info[ispec].argument))
-                   x = XINT (info[ispec].argument);
+                 if (INTEGERP (arg))
+                   x = XINT (arg);
                  else
                    {
-                     double d = XFLOAT_DATA (info[ispec].argument);
+                     double d = XFLOAT_DATA (arg);
                      if (d < 0)
                        {
                          x = TYPE_MINIMUM (printmax_t);
@@ -4456,11 +4434,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                {
                  /* Don't sign-extend for octal or hex printing.  */
                  uprintmax_t x;
-                 if (INTEGERP (info[ispec].argument))
-                   x = XUINT (info[ispec].argument);
+                 if (INTEGERP (arg))
+                   x = XUINT (arg);
                  else
                    {
-                     double d = XFLOAT_DATA (info[ispec].argument);
+                     double d = XFLOAT_DATA (arg);
                      if (d < 0)
                        x = 0;
                      else
@@ -4541,7 +4519,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                        exponent_bytes = src + sprintf_bytes - e;
                    }
 
-                  info[ispec].start = nchars;
+                 spec->start = nchars;
                  if (! minus_flag)
                    {
                      memset (p, ' ', padding);
@@ -4572,7 +4550,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                      p += padding;
                      nchars += padding;
                    }
-                 info[ispec].end = nchars;
+                 spec->end = nchars;
 
                  continue;
                }
@@ -4681,7 +4659,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
       if (CONSP (props))
        {
          ptrdiff_t bytepos = 0, position = 0, translated = 0;
-         ptrdiff_t fieldn = 1;
+         ptrdiff_t fieldn = 0;
 
          /* Adjust the bounds of each text property
             to the proper start and end in the output string.  */
@@ -4747,7 +4725,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
 
       /* Add text properties from arguments.  */
       if (arg_intervals)
-       for (ptrdiff_t i = 1; i <= num_percent; i++)
+       for (ptrdiff_t i = 0; i < nspec; i++)
          if (info[i].intervals)
            {
              len = make_number (SCHARS (info[i].argument));
diff --git a/src/emacs-module.c b/src/emacs-module.c
index 33c5fbd..71e04d8 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -28,6 +28,7 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 #include "lisp.h"
 #include "dynlib.h"
 #include "coding.h"
+#include "keyboard.h"
 #include "syssignal.h"
 
 #include <intprops.h>
@@ -36,12 +37,6 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 
 /* Feature tests.  */
 
-#if __has_attribute (cleanup)
-enum { module_has_cleanup = true };
-#else
-enum { module_has_cleanup = false };
-#endif
-
 #ifdef WINDOWSNT
 #include <windows.h>
 #include "w32term.h"
@@ -88,8 +83,6 @@ struct emacs_env_private
    environment.  */
 struct emacs_runtime_private
 {
-  /* FIXME: Ideally, we would just define "struct emacs_runtime_private"
-     as a synonym of "emacs_env", but I don't know how to do that in C.  */
   emacs_env pub;
 };
 
@@ -102,8 +95,8 @@ static Lisp_Object value_to_lisp (emacs_value);
 static emacs_value lisp_to_value (Lisp_Object);
 static enum emacs_funcall_exit module_non_local_exit_check (emacs_env *);
 static void check_main_thread (void);
-static void finalize_environment (struct emacs_env_private *);
-static void initialize_environment (emacs_env *, struct emacs_env_private 
*priv);
+static void initialize_environment (emacs_env *, struct emacs_env_private *);
+static void finalize_environment (emacs_env *, struct emacs_env_private *);
 static void module_handle_signal (emacs_env *, Lisp_Object);
 static void module_handle_throw (emacs_env *, Lisp_Object);
 static void module_non_local_exit_signal_1 (emacs_env *, Lisp_Object, 
Lisp_Object);
@@ -169,7 +162,7 @@ static emacs_value const module_nil = 0;
       module_out_of_memory (env);                                      \
       return retval;                                                   \
     }                                                                  \
-  verify (module_has_cleanup);                                         \
+  verify (__has_attribute (cleanup));                                   \
   struct handler *c __attribute__ ((cleanup (module_reset_handlerlist))) \
     = c0;                                                              \
   if (sys_setjmp (c->jmp))                                             \
@@ -213,14 +206,24 @@ static emacs_value const module_nil = 0;
       instead of reporting the error back to Lisp, and also because
       'eassert' is compiled to nothing in the release version.  */
 
+/* Use MODULE_FUNCTION_BEGIN_NO_CATCH to implement steps 2 and 3 for
+   environment functions that are known to never exit non-locally.  On
+   error it will return its argument, which can be a sentinel
+   value.  */
+
+#define MODULE_FUNCTION_BEGIN_NO_CATCH(error_retval)                    \
+  do {                                                                  \
+    check_main_thread ();                                               \
+    if (module_non_local_exit_check (env) != emacs_funcall_exit_return) \
+      return error_retval;                                              \
+  } while (false)
+
 /* Use MODULE_FUNCTION_BEGIN to implement steps 2 through 4 for most
    environment functions.  On error it will return its argument, which
-   should be a sentinel value.  */
+   can be a sentinel value.  */
 
-#define MODULE_FUNCTION_BEGIN(error_retval)                             \
-  check_main_thread ();                                                 \
-  if (module_non_local_exit_check (env) != emacs_funcall_exit_return)   \
-    return error_retval;                                                \
+#define MODULE_FUNCTION_BEGIN(error_retval)      \
+  MODULE_FUNCTION_BEGIN_NO_CATCH (error_retval); \
   MODULE_HANDLE_NONLOCAL_EXIT (error_retval)
 
 static void
@@ -342,7 +345,7 @@ module_non_local_exit_throw (emacs_env *env, emacs_value 
tag, emacs_value value)
                                   value_to_lisp (value));
 }
 
-/* A module function is a pseudovector of subtype type
+/* A module function is a pseudovector of subtype
    PVEC_MODULE_FUNCTION; see lisp.h for the definition.  */
 
 static emacs_value
@@ -418,18 +421,14 @@ module_type_of (emacs_env *env, emacs_value value)
 static bool
 module_is_not_nil (emacs_env *env, emacs_value value)
 {
-  check_main_thread ();
-  if (module_non_local_exit_check (env) != emacs_funcall_exit_return)
-    return false;
+  MODULE_FUNCTION_BEGIN_NO_CATCH (false);
   return ! NILP (value_to_lisp (value));
 }
 
 static bool
 module_eq (emacs_env *env, emacs_value a, emacs_value b)
 {
-  check_main_thread ();
-  if (module_non_local_exit_check (env) != emacs_funcall_exit_return)
-    return false;
+  MODULE_FUNCTION_BEGIN_NO_CATCH (false);
   return EQ (value_to_lisp (a), value_to_lisp (b));
 }
 
@@ -487,8 +486,6 @@ module_copy_string_contents (emacs_env *env, emacs_value 
value, char *buffer,
       return true;
     }
 
-  eassert (*length >= 0);
-
   if (*length < required_buf_size)
     {
       *length = required_buf_size;
@@ -505,6 +502,8 @@ static emacs_value
 module_make_string (emacs_env *env, const char *str, ptrdiff_t length)
 {
   MODULE_FUNCTION_BEGIN (module_nil);
+  if (! (0 <= length && length <= STRING_BYTES_BOUND))
+    xsignal0 (Qoverflow_error);
   AUTO_STRING_WITH_LEN (lstr, str, length);
   return lisp_to_value (code_convert_string_norecord (lstr, Qutf_8, false));
 }
@@ -593,6 +592,15 @@ module_vec_size (emacs_env *env, emacs_value vec)
   return ASIZE (lvec);
 }
 
+/* This function should return true if and only if maybe_quit would do
+   anything.  */
+static bool
+module_should_quit (emacs_env *env)
+{
+  MODULE_FUNCTION_BEGIN_NO_CATCH (false);
+  return (! NILP (Vquit_flag) && NILP (Vinhibit_quit)) || pending_signals;
+}
+
 
 /* Subroutines.  */
 
@@ -607,15 +615,15 @@ DEFUN ("module-load", Fmodule_load, Smodule_load, 1, 1, 0,
   CHECK_STRING (file);
   handle = dynlib_open (SSDATA (file));
   if (!handle)
-    error ("Cannot load file %s: %s", SDATA (file), dynlib_error ());
+    xsignal2 (Qmodule_open_failed, file, build_string (dynlib_error ()));
 
   gpl_sym = dynlib_sym (handle, "plugin_is_GPL_compatible");
   if (!gpl_sym)
-    error ("Module %s is not GPL compatible", SDATA (file));
+    xsignal1 (Qmodule_not_gpl_compatible, file);
 
   module_init = (emacs_init_function) dynlib_func (handle, 
"emacs_module_init");
   if (!module_init)
-    error ("Module %s does not have an init function.", SDATA (file));
+    xsignal1 (Qmissing_module_init_function, file);
 
   struct emacs_runtime_private rt; /* Includes the public emacs_env.  */
   struct emacs_env_private priv;
@@ -627,34 +635,33 @@ DEFUN ("module-load", Fmodule_load, Smodule_load, 1, 1, 0,
       .get_environment = module_get_environment
     };
   int r = module_init (&pub);
-  finalize_environment (&priv);
+  finalize_environment (&rt.pub, &priv);
 
   if (r != 0)
     {
       if (FIXNUM_OVERFLOW_P (r))
         xsignal0 (Qoverflow_error);
-      xsignal2 (Qmodule_load_failed, file, make_number (r));
+      xsignal2 (Qmodule_init_failed, file, make_number (r));
     }
 
   return Qt;
 }
 
 Lisp_Object
-funcall_module (const struct Lisp_Module_Function *const function,
-                ptrdiff_t nargs, Lisp_Object *arglist)
+funcall_module (Lisp_Object function, ptrdiff_t nargs, Lisp_Object *arglist)
 {
-  eassume (0 <= function->min_arity);
-  if (! (function->min_arity <= nargs
-        && (function->max_arity < 0 || nargs <= function->max_arity)))
-    xsignal2 (Qwrong_number_of_arguments, module_format_fun_env (function),
-             make_number (nargs));
+  const struct Lisp_Module_Function *func = XMODULE_FUNCTION (function);
+  eassume (0 <= func->min_arity);
+  if (! (func->min_arity <= nargs
+        && (func->max_arity < 0 || nargs <= func->max_arity)))
+    xsignal2 (Qwrong_number_of_arguments, function, make_number (nargs));
 
   emacs_env pub;
   struct emacs_env_private priv;
   initialize_environment (&pub, &priv);
 
   USE_SAFE_ALLOCA;
-  emacs_value *args;
+  ATTRIBUTE_MAY_ALIAS emacs_value *args;
   if (plain_values)
     args = (emacs_value *) arglist;
   else
@@ -664,28 +671,32 @@ funcall_module (const struct Lisp_Module_Function *const 
function,
        args[i] = lisp_to_value (arglist[i]);
     }
 
-  emacs_value ret = function->subr (&pub, nargs, args, function->data);
+  emacs_value ret = func->subr (&pub, nargs, args, func->data);
   SAFE_FREE ();
 
   eassert (&priv == pub.private_members);
 
+  /* Process the quit flag first, so that quitting doesn't get
+     overridden by other non-local exits.  */
+  maybe_quit ();
+
   switch (priv.pending_non_local_exit)
     {
     case emacs_funcall_exit_return:
-      finalize_environment (&priv);
+      finalize_environment (&pub, &priv);
       return value_to_lisp (ret);
     case emacs_funcall_exit_signal:
       {
         Lisp_Object symbol = priv.non_local_exit_symbol;
         Lisp_Object data = priv.non_local_exit_data;
-        finalize_environment (&priv);
+        finalize_environment (&pub, &priv);
         xsignal (symbol, data);
       }
     case emacs_funcall_exit_throw:
       {
         Lisp_Object tag = priv.non_local_exit_symbol;
         Lisp_Object value = priv.non_local_exit_data;
-        finalize_environment (&priv);
+        finalize_environment (&pub, &priv);
         Fthrow (tag, value);
       }
     default:
@@ -894,14 +905,17 @@ initialize_environment (emacs_env *env, struct 
emacs_env_private *priv)
   env->vec_set = module_vec_set;
   env->vec_get = module_vec_get;
   env->vec_size = module_vec_size;
+  env->should_quit = module_should_quit;
   Vmodule_environments = Fcons (make_save_ptr (env), Vmodule_environments);
 }
 
 /* Must be called before the lifetime of the environment object
    ends.  */
 static void
-finalize_environment (struct emacs_env_private *env)
+finalize_environment (emacs_env *env, struct emacs_env_private *priv)
 {
+  eassert (env->private_members == priv);
+  eassert (XSAVE_POINTER (XCAR (Vmodule_environments), 0) == env);
   Vmodule_environments = XCDR (Vmodule_environments);
 }
 
@@ -937,35 +951,6 @@ module_handle_throw (emacs_env *env, Lisp_Object tag_val)
 }
 
 
-/* Function environments.  */
-
-/* Return a string object that contains a user-friendly
-   representation of the function environment.  */
-Lisp_Object
-module_format_fun_env (const struct Lisp_Module_Function *env)
-{
-  /* Try to print a function name if possible.  */
-  /* FIXME: Move this function into print.c, then use prin1-to-string
-     above.  */
-  const char *path, *sym;
-  static char const noaddr_format[] = "#<module function at %p>";
-  char buffer[sizeof noaddr_format + INT_STRLEN_BOUND (intptr_t) + 256];
-  char *buf = buffer;
-  ptrdiff_t bufsize = sizeof buffer;
-  ptrdiff_t size
-    = (dynlib_addr (env->subr, &path, &sym)
-       ? exprintf (&buf, &bufsize, buffer, -1,
-                  "#<module function %s from %s>", sym, path)
-       : sprintf (buffer, noaddr_format, env->subr));
-  AUTO_STRING_WITH_LEN (unibyte_result, buffer, size);
-  Lisp_Object result = code_convert_string_norecord (unibyte_result,
-                                                    Qutf_8, false);
-  if (buf != buffer)
-    xfree (buf);
-  return result;
-}
-
-
 /* Segment initializer.  */
 
 void
@@ -999,11 +984,34 @@ syms_of_module (void)
   Fput (Qmodule_load_failed, Qerror_message,
         build_pure_c_string ("Module load failed"));
 
-  DEFSYM (Qinvalid_module_call, "invalid-module-call");
-  Fput (Qinvalid_module_call, Qerror_conditions,
-        listn (CONSTYPE_PURE, 2, Qinvalid_module_call, Qerror));
-  Fput (Qinvalid_module_call, Qerror_message,
-        build_pure_c_string ("Invalid module call"));
+  DEFSYM (Qmodule_open_failed, "module-open-failed");
+  Fput (Qmodule_open_failed, Qerror_conditions,
+        listn (CONSTYPE_PURE, 3,
+               Qmodule_open_failed, Qmodule_load_failed, Qerror));
+  Fput (Qmodule_open_failed, Qerror_message,
+        build_pure_c_string ("Module could not be opened"));
+
+  DEFSYM (Qmodule_not_gpl_compatible, "module-not-gpl-compatible");
+  Fput (Qmodule_not_gpl_compatible, Qerror_conditions,
+        listn (CONSTYPE_PURE, 3,
+               Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
+  Fput (Qmodule_not_gpl_compatible, Qerror_message,
+        build_pure_c_string ("Module is not GPL compatible"));
+
+  DEFSYM (Qmissing_module_init_function, "missing-module-init-function");
+  Fput (Qmissing_module_init_function, Qerror_conditions,
+        listn (CONSTYPE_PURE, 3,
+               Qmissing_module_init_function, Qmodule_load_failed, Qerror));
+  Fput (Qmissing_module_init_function, Qerror_message,
+        build_pure_c_string ("Module does not export an "
+                             "initialization function"));
+
+  DEFSYM (Qmodule_init_failed, "module-init-failed");
+  Fput (Qmodule_init_failed, Qerror_conditions,
+        listn (CONSTYPE_PURE, 3,
+               Qmodule_init_failed, Qmodule_load_failed, Qerror));
+  Fput (Qmodule_init_failed, Qerror_message,
+        build_pure_c_string ("Module initialization failed"));
 
   DEFSYM (Qinvalid_arity, "invalid-arity");
   Fput (Qinvalid_arity, Qerror_conditions,
diff --git a/src/emacs-module.h b/src/emacs-module.h
index d9eeeab..b8bf2ed 100644
--- a/src/emacs-module.h
+++ b/src/emacs-module.h
@@ -185,6 +185,9 @@ struct emacs_env_25
                   emacs_value val);
 
   ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vec);
+
+  /* Returns whether a quit is pending.  */
+  bool (*should_quit) (emacs_env *env);
 };
 
 /* Every module should define a function as follows.  */
diff --git a/src/eval.c b/src/eval.c
index f472efa..ef96104 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1474,7 +1474,10 @@ process_quit_flag (void)
    If quit-flag is set to `kill-emacs' the SIGINT handler has received
    a request to exit Emacs when it is safe to do.
 
-   When not quitting, process any pending signals.  */
+   When not quitting, process any pending signals.
+
+   If you change this function, also adapt module_should_quit in
+   emacs-module.c.  */
 
 void
 maybe_quit (void)
@@ -2952,7 +2955,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
     }
 #ifdef HAVE_MODULES
   else if (MODULE_FUNCTIONP (fun))
-    return funcall_module (XMODULE_FUNCTION (fun), nargs, arg_vector);
+    return funcall_module (fun, nargs, arg_vector);
 #endif
   else
     emacs_abort ();
diff --git a/src/lisp.h b/src/lisp.h
index 7b8f1e7..c35bd1f 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -1346,7 +1346,9 @@ SSET (Lisp_Object string, ptrdiff_t index, unsigned char 
new)
 INLINE ptrdiff_t
 SCHARS (Lisp_Object string)
 {
-  return XSTRING (string)->size;
+  ptrdiff_t nchars = XSTRING (string)->size;
+  eassume (0 <= nchars);
+  return nchars;
 }
 
 #ifdef GC_CHECK_STRING_BYTES
@@ -1356,10 +1358,12 @@ INLINE ptrdiff_t
 STRING_BYTES (struct Lisp_String *s)
 {
 #ifdef GC_CHECK_STRING_BYTES
-  return string_bytes (s);
+  ptrdiff_t nbytes = string_bytes (s);
 #else
-  return s->size_byte < 0 ? s->size : s->size_byte;
+  ptrdiff_t nbytes = s->size_byte < 0 ? s->size : s->size_byte;
 #endif
+  eassume (0 <= nbytes);
+  return nbytes;
 }
 
 INLINE ptrdiff_t
@@ -1373,7 +1377,7 @@ STRING_SET_CHARS (Lisp_Object string, ptrdiff_t newsize)
   /* This function cannot change the size of data allocated for the
      string when it was created.  */
   eassert (STRING_MULTIBYTE (string)
-          ? newsize <= SBYTES (string)
+          ? 0 <= newsize && newsize <= SBYTES (string)
           : newsize == SCHARS (string));
   XSTRING (string)->size = newsize;
 }
@@ -3952,10 +3956,8 @@ XMODULE_FUNCTION (Lisp_Object o)
 extern Lisp_Object make_user_ptr (void (*finalizer) (void *), void *p);
 
 /* Defined in emacs-module.c.  */
-extern Lisp_Object funcall_module (const struct Lisp_Module_Function *,
-                                   ptrdiff_t, Lisp_Object *);
+extern Lisp_Object funcall_module (Lisp_Object, ptrdiff_t, Lisp_Object *);
 extern Lisp_Object module_function_arity (const struct Lisp_Module_Function *);
-extern Lisp_Object module_format_fun_env (const struct Lisp_Module_Function *);
 extern void syms_of_module (void);
 #endif
 
diff --git a/src/print.c b/src/print.c
index 49408bb..76ae10f 100644
--- a/src/print.c
+++ b/src/print.c
@@ -33,6 +33,7 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 #include "intervals.h"
 #include "blockinput.h"
 #include "xwidget.h"
+#include "dynlib.h"
 
 #include <c-ctype.h>
 #include <float.h>
@@ -1699,8 +1700,33 @@ print_vectorlike (Lisp_Object obj, Lisp_Object 
printcharfun, bool escapeflag,
 
 #ifdef HAVE_MODULES
     case PVEC_MODULE_FUNCTION:
-      print_string (module_format_fun_env (XMODULE_FUNCTION (obj)),
-                   printcharfun);
+      {
+        print_c_string ("#<module function ", printcharfun);
+        void *ptr = XMODULE_FUNCTION (obj)->subr;
+        const char *file = NULL;
+        const char *symbol = NULL;
+        dynlib_addr (ptr, &file, &symbol);
+
+        if (symbol == NULL)
+          {
+            print_c_string ("at ", printcharfun);
+            enum { pointer_bufsize = sizeof ptr * 16 / CHAR_BIT + 2 + 1 };
+            char buffer[pointer_bufsize];
+            int needed = snprintf (buffer, sizeof buffer, "%p", ptr);
+            eassert (needed <= sizeof buffer);
+            print_c_string (buffer, printcharfun);
+          }
+        else
+          print_c_string (symbol, printcharfun);
+
+        if (file != NULL)
+          {
+            print_c_string (" from ", printcharfun);
+            print_c_string (file, printcharfun);
+          }
+
+        printchar ('>', printcharfun);
+      }
       break;
 #endif
 
diff --git a/test/Makefile.in b/test/Makefile.in
index 4f12a8e..7b8c967 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -182,7 +182,7 @@ test_module_dir := $(srcdir)/data/emacs-module
 test_module_name := address@hidden@
 test_module := $(test_module_dir)/$(test_module_name)
 $(srcdir)/src/emacs-module-tests.log: $(test_module)
-$(test_module): $(srcdir)/../src/emacs-module.[ch]
+$(test_module): $(srcdir)/../src/emacs-module.[ch] 
$(test_module_dir)/mod-test.c
        $(MAKE) -C $(test_module_dir) $(test_module_name) address@hidden@
 endif
 
diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el
index 5e78aeb..622bbad 100644
--- a/test/src/emacs-module-tests.el
+++ b/test/src/emacs-module-tests.el
@@ -31,13 +31,13 @@
   (should (= (mod-test-sum 1 2) 3))
   (let ((descr (should-error (mod-test-sum 1 2 3))))
     (should (eq (car descr) 'wrong-number-of-arguments))
-    (should (stringp (nth 1 descr)))
+    (should (module-function-p (nth 1 descr)))
     (should (eq 0
                 (string-match
                  (concat "#<module function "
                          "\\(at \\(0x\\)?[0-9a-fA-F]+\\( from .*\\)?"
                          "\\|Fmod_test_sum from .*\\)>")
-                 (nth 1 descr))))
+                 (prin1-to-string (nth 1 descr)))))
     (should (= (nth 2 descr) 3)))
   (should-error (mod-test-sum "1" 2) :type 'wrong-type-argument)
   (should-error (mod-test-sum 1 "2") :type 'wrong-type-argument)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]