Now on revision 110892. ------------------------------------------------------------ revno: 110892 committer: Dmitry Gutov branch nick: trunk timestamp: Wed 2012-11-14 10:34:17 +0400 message: * lisp/progmodes/ruby-mode.el (ruby-expr-beg): Make heredoc detection more strict. Add docstring. * test/automated/ruby-mode-tests.el (ruby-indent-singleton-class): Pass. (ruby-indent-inside-heredoc-after-operator) (ruby-indent-inside-heredoc-after-space): New tests. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-11-14 01:12:52 +0000 +++ lisp/ChangeLog 2012-11-14 06:34:17 +0000 @@ -1,3 +1,8 @@ +2012-11-14 Dmitry Gutov + + * progmodes/ruby-mode.el (ruby-expr-beg): Make heredoc detection + more strict. Add docstring. + 2012-11-14 Stefan Monnier * emacs-lisp/gv.el (setf): Fix debug spec for multiple assignments === modified file 'lisp/progmodes/ruby-mode.el' --- lisp/progmodes/ruby-mode.el 2012-11-14 05:07:33 +0000 +++ lisp/progmodes/ruby-mode.el 2012-11-14 06:34:17 +0000 @@ -384,7 +384,9 @@ (looking-at "class\\s *<<")))) (defun ruby-expr-beg (&optional option) - "TODO: document." + "Check if point is possibly at the beginning of an expression. +OPTION specifies the type of the expression. +Can be one of `heredoc', `modifier', `expr-qstr', `expr-re'." (save-excursion (store-match-data nil) (let ((space (skip-chars-backward " \t")) @@ -397,10 +399,10 @@ (or (eq (char-syntax (char-before (point))) ?w) (ruby-special-char-p)))) nil) - ((and (eq option 'heredoc) (< space 0)) - (not (progn (goto-char start) (ruby-singleton-class-p)))) - ((or (looking-at ruby-operator-re) - (looking-at "[\\[({,;]") + ((looking-at ruby-operator-re)) + ((eq option 'heredoc) + (and (< space 0) (not (ruby-singleton-class-p start)))) + ((or (looking-at "[\\[({,;]") (and (looking-at "[!?]") (or (not (eq option 'modifier)) (bolp) === modified file 'test/ChangeLog' --- test/ChangeLog 2012-11-13 18:57:26 +0000 +++ test/ChangeLog 2012-11-14 06:34:17 +0000 @@ -1,3 +1,9 @@ +2012-11-14 Dmitry Gutov + + * automated/ruby-mode-tests.el (ruby-indent-singleton-class): Pass. + (ruby-indent-inside-heredoc-after-operator) + (ruby-indent-inside-heredoc-after-space): New tests. + 2012-11-13 Dmitry Gutov * automated/ruby-mode-tests.el (ruby-heredoc-font-lock) === modified file 'test/automated/ruby-mode-tests.el' --- test/automated/ruby-mode-tests.el 2012-11-13 18:57:26 +0000 +++ test/automated/ruby-mode-tests.el 2012-11-14 06:34:17 +0000 @@ -154,7 +154,6 @@ |")) (ert-deftest ruby-indent-singleton-class () - :expected-result :failed ; Doesn't work yet, when no space before "<<". (ruby-should-indent-buffer "class< branch nick: trunk timestamp: Tue 2012-11-13 21:29:54 -0800 message: Use trunk version of gnulib lib/fcntl.in.h. This corrects a recent checkin, which used an experimental version of this file by mistake. Stick with the standard version. diff: === modified file 'lib/fcntl.in.h' --- lib/fcntl.in.h 2012-11-14 04:55:41 +0000 +++ lib/fcntl.in.h 2012-11-14 05:29:54 +0000 @@ -213,11 +213,7 @@ #endif #ifndef O_EXEC -# ifdef O_PATH -# define O_EXEC O_PATH -# else -# define O_EXEC O_RDONLY /* This is often close enough in older systems. */ -# endif +# define O_EXEC O_RDONLY /* This is often close enough in older systems. */ #endif #ifndef O_IGNORE_CTTY @@ -274,11 +270,7 @@ #endif #ifndef O_SEARCH -# ifdef O_PATH -# define O_SEARCH O_PATH -# else -# define O_SEARCH O_RDONLY /* This is often close enough in older systems. */ -# endif +# define O_SEARCH O_RDONLY /* This is often close enough in older systems. */ #endif #ifndef O_SYNC ------------------------------------------------------------ revno: 110890 committer: Paul Eggert branch nick: trunk timestamp: Tue 2012-11-13 21:07:33 -0800 message: Spelling fixes. diff: === modified file 'doc/lispref/windows.texi' --- doc/lispref/windows.texi 2012-11-07 09:41:52 +0000 +++ doc/lispref/windows.texi 2012-11-14 05:07:33 +0000 @@ -1055,7 +1055,7 @@ @end smallexample @noindent -This can be counterintutive, in particular if @code{W4} were used for +This can be counterintuitive, in particular if @code{W4} were used for displaying a buffer only temporarily (@pxref{Temporary Displays}), and you want to continue working with the initial layout. @@ -2343,7 +2343,7 @@ @code{switch-to-prev-buffer} (@pxref{Window History}) to show some other buffer instead. -The optional argument @var{bury-or-kill} specifes how to deal with +The optional argument @var{bury-or-kill} specifies how to deal with @var{window}'s buffer. The following values are handled: @table @code === modified file 'doc/misc/ses.texi' --- doc/misc/ses.texi 2012-11-12 05:53:53 +0000 +++ doc/misc/ses.texi 2012-11-14 05:07:33 +0000 @@ -482,9 +482,9 @@ Pops up a menu to set the current row as the header, or revert to column letters. @item M-x ses-rename-cell -@findex ses-rename-cell -Rename a cell from a standard A1-like name to any -string. +@findex ses-rename-cell +Rename a cell from a standard A1-like name to any +string. @item M-x ses-repair-cell-reference-all @findex ses-repair-cell-reference-all When you interrupt a cell formula update by clicking @kbd{C-g}, then @@ -606,15 +606,15 @@ are empty. Similarly, @code{(ses-range A1 A4 _ )} will do the same as @code{(list A1 0 A3 0)}. @item >v -When order matters, list cells by reading cells rowwise from top left +When order matters, list cells by reading cells row-wise from top left to bottom right. This flag is provided for completeness only as it is the default reading order. @item -List cells by reading cells columnwise from top left to bottom right. +List cells by reading cells column-wise from top left to bottom right. @item v< -List cells by reading cells columnwise from top right to bottom left. +List cells by reading cells column-wise from top right to bottom left. @item v A short hand for @code{v>}. @item ^ === modified file 'doc/misc/url.texi' --- doc/misc/url.texi 2012-11-09 08:34:17 +0000 +++ doc/misc/url.texi 2012-11-14 05:07:33 +0000 @@ -346,7 +346,7 @@ The value of this option is an integer specifying the maximum number of concurrent @code{url-queue-retrieve} network processes. If the number of @code{url-queue-retrieve} calls is larger than this number, -later ones are queued until ealier ones are finished. +later ones are queued until earlier ones are finished. @end defopt @vindex url-queue-timeout === modified file 'lisp/gnus/pop3.el' --- lisp/gnus/pop3.el 2012-11-02 23:37:02 +0000 +++ lisp/gnus/pop3.el 2012-11-14 05:07:33 +0000 @@ -178,7 +178,7 @@ 1000)))))) (defvar pop3-uidl) -;; List of UIDLs of existing messages at pesent in the server: +;; List of UIDLs of existing messages at present in the server: ;; ("UIDL1" "UIDL2" "UIDL3"...) (defvar pop3-uidl-saved) === modified file 'lisp/progmodes/ruby-mode.el' --- lisp/progmodes/ruby-mode.el 2012-11-13 18:57:26 +0000 +++ lisp/progmodes/ruby-mode.el 2012-11-14 05:07:33 +0000 @@ -897,7 +897,7 @@ (t (setq pos (current-indentation)) (cond - ;; Deeper intendation, we found a block. + ;; Deeper indentation, we found a block. ;; FIXME: We can't recognize empty blocks this way. ((< start pos) (setq down t)) ------------------------------------------------------------ revno: 110889 fixes bug: http://debbugs.gnu.org/12632 committer: Paul Eggert branch nick: trunk timestamp: Tue 2012-11-13 20:55:41 -0800 message: Use faccessat, not access, when checking file permissions. This fixes a bug that has been present in Emacs since its creation. It was reported by Chris Torek in 1983 even before GNU Emacs existed, which must set some sort of record. (Torek's bug report was against a predecessor of GNU Emacs, but GNU Emacs happened to have the same common flaw.) See Torek's Usenet posting "setuid/setgid programs & Emacs" Article-I.D.: sri-arpa.858 Posted: Fri Apr 8 14:18:56 1983. * .bzrignore: Add lib/fcntl.h. * configure.ac (euidaccess): Remove check; gnulib does this for us now. (gl_FCNTL_O_FLAGS): Define a dummy version. * lib/at-func.c, lib/euidaccess.c, lib/faccessat.c, lib/fcntl.in.h: * lib/getgroups.c, lib/group-member.c, lib/root-uid.h: * lib/xalloc-oversized.h, m4/euidaccess.m4, m4/faccessat.m4: * m4/fcntl_h.m4, m4/getgroups.m4, m4/group-member.m4: New files, from gnulib. * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. * admin/merge-gnulib (GNULIB_MODULES): Add faccessat. (GNULIB_TOOL_FLAGS): Avoid at-internal, fchdir, malloc-posix, openat-die, openat-h, save-cwd. Do not avoid fcntl-h. Omit gnulib's m4/fcntl-o.m4. * nt/inc/ms-w32.h (AT_FDCWD, AT_EACCESS): New symbols. (access): Remove. (faccessat): New macro. * src/Makefile.in (LIB_EACCESS): New macro. (LIBES): Use it. * src/callproc.c (init_callproc): * src/charset.c (init_charset): * src/fileio.c (check_existing, check_executable, check_writable) (Ffile_readable_p): * src/lread.c (openp, load_path_check): * src/process.c (allocate_pty): * src/xrdb.c (file_p): Use effective UID when checking permissions, not real UID. * src/callproc.c (init_callproc): * src/charset.c (init_charset): * src/lread.c (load_path_check, init_lread): Test whether directories are accessible, not merely whether they exist. * src/conf_post.h (GNULIB_SUPPORT_ONLY_AT_FDCWD): New macro. * src/fileio.c (check_existing, check_executable, check_writable) (Ffile_readable_p): Use symbolic names instead of integers for the flags, as they're portable now. (check_writable): New arg AMODE. All uses changed. Set errno on failure. (Ffile_readable_p): Use faccessat, not stat + open + close. (Ffile_writable_p): No need to call check_existing + check_writable. Just call check_writable and then look at errno. This saves a syscall. dir should never be nil; replace an unnecessary runtime check with an eassert. When checking the parent directory of a nonexistent file, check that the directory is searchable as well as writable, as we can't create files in unsearchable directories. (file_directory_p): New function, which uses 'stat' on most platforms but faccessat with D_OK (for efficiency) if WINDOWSNT. (Ffile_directory_p, Fset_file_times): Use it. (file_accessible_directory_p): New function, which uses a single syscall for efficiency. (Ffile_accessible_directory_p): Use it. * src/xrdb.c (file_p): Use file_directory_p. * src/lisp.h (file_directory_p, file_accessible_directory_p): New decls. * src/lread.c (openp): When opening a file, use fstat rather than stat, as that avoids a permissions race. When not opening a file, use file_directory_p rather than stat. (dir_warning): First arg is now a usage string, not a format. Use errno. All uses changed. * src/nsterm.m (ns_term_init): Remove unnecessary call to file-readable that merely introduced a race. * src/process.c, src/sysdep.c, src/term.c: All uses of '#ifdef O_NONBLOCK' changed to '#if O_NONBLOCK', to accommodate gnulib O_* style, and similarly for the other O_* flags. * src/w32.c (sys_faccessat): Rename from sys_access and switch to faccessat's API. All uses changed. * src/xrdb.c: Do not include ; no longer needed. (magic_db): Rename from magic_file_p. (magic_db, search_magic_path): Return an XrmDatabase rather than a char *, so that we don't have to test for file existence separately from opening the file for reading. This removes a race fixes a permission-checking problem, and simplifies the code. All uses changed. (file_p): Remove; no longer needed. diff: === modified file '.bzrignore' --- .bzrignore 2012-10-19 19:25:18 +0000 +++ .bzrignore 2012-11-14 04:55:41 +0000 @@ -88,6 +88,7 @@ lib/arg-nonnull.h lib/c++defs.h lib/execinfo.h +lib/fcntl.h lib/getopt.h lib/inttypes.h lib/stdalign.h === modified file 'ChangeLog' --- ChangeLog 2012-11-05 03:18:32 +0000 +++ ChangeLog 2012-11-14 04:55:41 +0000 @@ -1,3 +1,16 @@ +2012-11-14 Paul Eggert + + Use faccessat, not access, when checking file permissions (Bug#12632). + * .bzrignore: Add lib/fcntl.h. + * configure.ac (euidaccess): Remove check; gnulib does this for us now. + (gl_FCNTL_O_FLAGS): Define a dummy version. + * lib/at-func.c, lib/euidaccess.c, lib/faccessat.c, lib/fcntl.in.h: + * lib/getgroups.c, lib/group-member.c, lib/root-uid.h: + * lib/xalloc-oversized.h, m4/euidaccess.m4, m4/faccessat.m4: + * m4/fcntl_h.m4, m4/getgroups.m4, m4/group-member.m4: + New files, from gnulib. + * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. + 2012-11-05 Paul Eggert Assume at least POSIX.1-1988 for getpgrp, setpgid, setsid (Bug#12800). === modified file 'admin/ChangeLog' --- admin/ChangeLog 2012-11-05 03:18:32 +0000 +++ admin/ChangeLog 2012-11-14 04:55:41 +0000 @@ -1,3 +1,11 @@ +2012-11-14 Paul Eggert + + Use faccessat, not access, when checking file permissions (Bug#12632). + * merge-gnulib (GNULIB_MODULES): Add faccessat. + (GNULIB_TOOL_FLAGS): Avoid at-internal, fchdir, malloc-posix, + openat-die, openat-h, save-cwd. Do not avoid fcntl-h. + Omit gnulib's m4/fcntl-o.m4. + 2012-11-05 Paul Eggert Assume at least POSIX.1-1988 for getpgrp, setpgid, setsid (Bug#12800). === modified file 'admin/merge-gnulib' --- admin/merge-gnulib 2012-11-03 18:54:17 +0000 +++ admin/merge-gnulib 2012-11-14 04:55:41 +0000 @@ -28,7 +28,7 @@ GNULIB_MODULES=' alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 - dtoastr dtotimespec dup2 environ execinfo + dtoastr dtotimespec dup2 environ execinfo faccessat filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink @@ -39,9 +39,12 @@ ' GNULIB_TOOL_FLAGS=' - --avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat - --avoid=msvc-inval --avoid=msvc-nothrow - --avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types + --avoid=at-internal + --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat + --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow + --avoid=openat-die --avoid=openat-h + --avoid=raise + --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --conditional-dependencies --import --no-changelog --no-vc-files --makefile-name=gnulib.mk @@ -85,7 +88,7 @@ } "$gnulib_srcdir"/gnulib-tool --dir="$src" $GNULIB_TOOL_FLAGS $GNULIB_MODULES && -rm -- "$src"m4/gnulib-cache.m4 "$src"m4/warn-on-use.m4 && +rm -- "$src"m4/fcntl-o.m4 "$src"m4/gnulib-cache.m4 "$src"m4/warn-on-use.m4 && cp -- "$gnulib_srcdir"/build-aux/texinfo.tex "$src"doc/misc && cp -- "$gnulib_srcdir"/build-aux/move-if-change "$src"build-aux && autoreconf -i -I m4 -- ${src:+"$src"} === modified file 'configure.ac' --- configure.ac 2012-11-05 03:18:32 +0000 +++ configure.ac 2012-11-14 04:55:41 +0000 @@ -572,6 +572,8 @@ test "x$NON_GCC_TEST_OPTIONS" != x && CC="$CC $NON_GCC_TEST_OPTIONS" fi +# Avoid gnulib's tests for O_NOATIME and O_NOFOLLOW, as we don't use them. +AC_DEFUN([gl_FCNTL_O_FLAGS]) # Avoid gnulib's threadlib module, as we do threads our own way. AC_DEFUN([gl_THREADLIB]) @@ -2872,7 +2874,7 @@ AC_CHECK_FUNCS(gethostname \ closedir getrusage get_current_dir_name \ lrand48 \ -fpathconf select euidaccess getpagesize setlocale \ +fpathconf select getpagesize setlocale \ utimes getrlimit setrlimit getcwd shutdown getaddrinfo \ strsignal setitimer \ sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \ === added file 'lib/at-func.c' --- lib/at-func.c 1970-01-01 00:00:00 +0000 +++ lib/at-func.c 2012-11-14 04:55:41 +0000 @@ -0,0 +1,146 @@ +/* Define at-style functions like fstatat, unlinkat, fchownat, etc. + Copyright (C) 2006, 2009-2012 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* written by Jim Meyering */ + +#include "dosname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */ + +#ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD +# include +# ifndef ENOTSUP +# define ENOTSUP EINVAL +# endif +#else +# include "openat.h" +# include "openat-priv.h" +# include "save-cwd.h" +#endif + +#ifdef AT_FUNC_USE_F1_COND +# define CALL_FUNC(F) \ + (flag == AT_FUNC_USE_F1_COND \ + ? AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS) \ + : AT_FUNC_F2 (F AT_FUNC_POST_FILE_ARGS)) +# define VALIDATE_FLAG(F) \ + if (flag & ~AT_FUNC_USE_F1_COND) \ + { \ + errno = EINVAL; \ + return FUNC_FAIL; \ + } +#else +# define CALL_FUNC(F) (AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS)) +# define VALIDATE_FLAG(F) /* empty */ +#endif + +#ifdef AT_FUNC_RESULT +# define FUNC_RESULT AT_FUNC_RESULT +#else +# define FUNC_RESULT int +#endif + +#ifdef AT_FUNC_FAIL +# define FUNC_FAIL AT_FUNC_FAIL +#else +# define FUNC_FAIL -1 +#endif + +/* Call AT_FUNC_F1 to operate on FILE, which is in the directory + open on descriptor FD. If AT_FUNC_USE_F1_COND is defined to a value, + AT_FUNC_POST_FILE_PARAM_DECLS must include a parameter named flag; + call AT_FUNC_F2 if FLAG is 0 or fail if FLAG contains more bits than + AT_FUNC_USE_F1_COND. Return int and fail with -1 unless AT_FUNC_RESULT + or AT_FUNC_FAIL are defined. If possible, do it without changing the + working directory. Otherwise, resort to using save_cwd/fchdir, + then AT_FUNC_F?/restore_cwd. If either the save_cwd or the restore_cwd + fails, then give a diagnostic and exit nonzero. */ +FUNC_RESULT +AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS) +{ + VALIDATE_FLAG (flag); + + if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file)) + return CALL_FUNC (file); + +#ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD + errno = ENOTSUP; + return FUNC_FAIL; +#else + { + /* Be careful to choose names unlikely to conflict with + AT_FUNC_POST_FILE_PARAM_DECLS. */ + struct saved_cwd saved_cwd; + int saved_errno; + FUNC_RESULT err; + + { + char proc_buf[OPENAT_BUFFER_SIZE]; + char *proc_file = openat_proc_name (proc_buf, fd, file); + if (proc_file) + { + FUNC_RESULT proc_result = CALL_FUNC (proc_file); + int proc_errno = errno; + if (proc_file != proc_buf) + free (proc_file); + /* If the syscall succeeds, or if it fails with an unexpected + errno value, then return right away. Otherwise, fall through + and resort to using save_cwd/restore_cwd. */ + if (FUNC_FAIL != proc_result) + return proc_result; + if (! EXPECTED_ERRNO (proc_errno)) + { + errno = proc_errno; + return proc_result; + } + } + } + + if (save_cwd (&saved_cwd) != 0) + openat_save_fail (errno); + if (0 <= fd && fd == saved_cwd.desc) + { + /* If saving the working directory collides with the user's + requested fd, then the user's fd must have been closed to + begin with. */ + free_cwd (&saved_cwd); + errno = EBADF; + return FUNC_FAIL; + } + + if (fchdir (fd) != 0) + { + saved_errno = errno; + free_cwd (&saved_cwd); + errno = saved_errno; + return FUNC_FAIL; + } + + err = CALL_FUNC (file); + saved_errno = (err == FUNC_FAIL ? errno : 0); + + if (restore_cwd (&saved_cwd) != 0) + openat_restore_fail (errno); + + free_cwd (&saved_cwd); + + if (saved_errno) + errno = saved_errno; + return err; + } +#endif +} +#undef CALL_FUNC +#undef FUNC_RESULT +#undef FUNC_FAIL === added file 'lib/euidaccess.c' --- lib/euidaccess.c 1970-01-01 00:00:00 +0000 +++ lib/euidaccess.c 2012-11-14 04:55:41 +0000 @@ -0,0 +1,221 @@ +/* euidaccess -- check if effective user id can access file + + Copyright (C) 1990-1991, 1995, 1998, 2000, 2003-2006, 2008-2012 Free + Software Foundation, Inc. + + This file is part of the GNU C Library. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by David MacKenzie and Torbjorn Granlund. + Adapted for GNU C library by Roland McGrath. */ + +#ifndef _LIBC +# include +#endif + +#include +#include +#include +#include + +#include "root-uid.h" + +#if HAVE_LIBGEN_H +# include +#endif + +#include +#ifndef __set_errno +# define __set_errno(val) errno = (val) +#endif + +#if defined EACCES && !defined EACCESS +# define EACCESS EACCES +#endif + +#ifndef F_OK +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + + +#ifdef _LIBC + +# define access __access +# define getuid __getuid +# define getgid __getgid +# define geteuid __geteuid +# define getegid __getegid +# define group_member __group_member +# define euidaccess __euidaccess +# undef stat +# define stat stat64 + +#endif + +/* Return 0 if the user has permission of type MODE on FILE; + otherwise, return -1 and set 'errno'. + Like access, except that it uses the effective user and group + id's instead of the real ones, and it does not always check for read-only + file system, text busy, etc. */ + +int +euidaccess (const char *file, int mode) +{ +#if HAVE_FACCESSAT /* glibc, AIX 7, Solaris 11, Cygwin 1.7 */ + return faccessat (AT_FDCWD, file, mode, AT_EACCESS); +#elif defined EFF_ONLY_OK /* IRIX, OSF/1, Interix */ + return access (file, mode | EFF_ONLY_OK); +#elif defined ACC_SELF /* AIX */ + return accessx (file, mode, ACC_SELF); +#elif HAVE_EACCESS /* FreeBSD */ + return eaccess (file, mode); +#else /* Mac OS X, NetBSD, OpenBSD, HP-UX, Solaris, Cygwin, mingw, BeOS */ + + uid_t uid = getuid (); + gid_t gid = getgid (); + uid_t euid = geteuid (); + gid_t egid = getegid (); + struct stat stats; + +# if HAVE_DECL_SETREGID && PREFER_NONREENTRANT_EUIDACCESS + + /* Define PREFER_NONREENTRANT_EUIDACCESS if you prefer euidaccess to + return the correct result even if this would make it + nonreentrant. Define this only if your entire application is + safe even if the uid or gid might temporarily change. If your + application uses signal handlers or threads it is probably not + safe. */ + + if (mode == F_OK) + return stat (file, &stats); + else + { + int result; + int saved_errno; + + if (uid != euid) + setreuid (euid, uid); + if (gid != egid) + setregid (egid, gid); + + result = access (file, mode); + saved_errno = errno; + + /* Restore them. */ + if (uid != euid) + setreuid (uid, euid); + if (gid != egid) + setregid (gid, egid); + + errno = saved_errno; + return result; + } + +# else + + /* The following code assumes the traditional Unix model, and is not + correct on systems that have ACLs or the like. However, it's + better than nothing, and it is reentrant. */ + + unsigned int granted; + if (uid == euid && gid == egid) + /* If we are not set-uid or set-gid, access does the same. */ + return access (file, mode); + + if (stat (file, &stats) != 0) + return -1; + + /* The super-user can read and write any file, and execute any file + that anyone can execute. */ + if (euid == ROOT_UID + && ((mode & X_OK) == 0 + || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))) + return 0; + + /* Convert the mode to traditional form, clearing any bogus bits. */ + if (R_OK == 4 && W_OK == 2 && X_OK == 1 && F_OK == 0) + mode &= 7; + else + mode = ((mode & R_OK ? 4 : 0) + + (mode & W_OK ? 2 : 0) + + (mode & X_OK ? 1 : 0)); + + if (mode == 0) + return 0; /* The file exists. */ + + /* Convert the file's permission bits to traditional form. */ + if (S_IRUSR == (4 << 6) && S_IWUSR == (2 << 6) && S_IXUSR == (1 << 6) + && S_IRGRP == (4 << 3) && S_IWGRP == (2 << 3) && S_IXGRP == (1 << 3) + && S_IROTH == (4 << 0) && S_IWOTH == (2 << 0) && S_IXOTH == (1 << 0)) + granted = stats.st_mode; + else + granted = ((stats.st_mode & S_IRUSR ? 4 << 6 : 0) + + (stats.st_mode & S_IWUSR ? 2 << 6 : 0) + + (stats.st_mode & S_IXUSR ? 1 << 6 : 0) + + (stats.st_mode & S_IRGRP ? 4 << 3 : 0) + + (stats.st_mode & S_IWGRP ? 2 << 3 : 0) + + (stats.st_mode & S_IXGRP ? 1 << 3 : 0) + + (stats.st_mode & S_IROTH ? 4 << 0 : 0) + + (stats.st_mode & S_IWOTH ? 2 << 0 : 0) + + (stats.st_mode & S_IXOTH ? 1 << 0 : 0)); + + if (euid == stats.st_uid) + granted >>= 6; + else if (egid == stats.st_gid || group_member (stats.st_gid)) + granted >>= 3; + + if ((mode & ~granted) == 0) + return 0; + __set_errno (EACCESS); + return -1; + +# endif +#endif +} +#undef euidaccess +#ifdef weak_alias +weak_alias (__euidaccess, euidaccess) +#endif + +#ifdef TEST +# include +# include +# include + +char *program_name; + +int +main (int argc, char **argv) +{ + char *file; + int mode; + int err; + + program_name = argv[0]; + if (argc < 3) + abort (); + file = argv[1]; + mode = atoi (argv[2]); + + err = euidaccess (file, mode); + printf ("%d\n", err); + if (err != 0) + error (0, errno, "%s", file); + exit (0); +} +#endif === added file 'lib/faccessat.c' --- lib/faccessat.c 1970-01-01 00:00:00 +0000 +++ lib/faccessat.c 2012-11-14 04:55:41 +0000 @@ -0,0 +1,45 @@ +/* Check the access rights of a file relative to an open directory. + Copyright (C) 2009-2012 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* written by Eric Blake */ + +#include + +#include +#include + +#ifndef HAVE_ACCESS +/* Mingw lacks access, but it also lacks real vs. effective ids, so + the gnulib euidaccess module is good enough. */ +# undef access +# define access euidaccess +#endif + +/* Invoke access or euidaccess on file, FILE, using mode MODE, in the directory + open on descriptor FD. If possible, do it without changing the + working directory. Otherwise, resort to using save_cwd/fchdir, then + (access|euidaccess)/restore_cwd. If either the save_cwd or the + restore_cwd fails, then give a diagnostic and exit nonzero. + Note that this implementation only supports AT_EACCESS, although some + native versions also support AT_SYMLINK_NOFOLLOW. */ + +#define AT_FUNC_NAME faccessat +#define AT_FUNC_F1 euidaccess +#define AT_FUNC_F2 access +#define AT_FUNC_USE_F1_COND AT_EACCESS +#define AT_FUNC_POST_FILE_PARAM_DECLS , int mode, int flag +#define AT_FUNC_POST_FILE_ARGS , mode +#include "at-func.c" === added file 'lib/fcntl.in.h' --- lib/fcntl.in.h 1970-01-01 00:00:00 +0000 +++ lib/fcntl.in.h 2012-11-14 04:55:41 +0000 @@ -0,0 +1,355 @@ +/* Like , but with non-working flags defined to 0. + + Copyright (C) 2006-2012 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* written by Paul Eggert */ + +#if __GNUC__ >= 3 +@PRAGMA_SYSTEM_HEADER@ +#endif +@PRAGMA_COLUMNS@ + +#if defined __need_system_fcntl_h +/* Special invocation convention. */ + +/* Needed before . + May also define off_t to a 64-bit type on native Windows. */ +#include +/* On some systems other than glibc, is a prerequisite of + . On glibc systems, we would like to avoid namespace pollution. + But on glibc systems, includes inside an + extern "C" { ... } block, which leads to errors in C++ mode with the + overridden from gnulib. These errors are known to be gone + with g++ version >= 4.3. */ +#if !(defined __GLIBC__ || defined __UCLIBC__) || (defined __cplusplus && defined GNULIB_NAMESPACE && !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) +# include +#endif +#@INCLUDE_NEXT@ @NEXT_FCNTL_H@ + +#else +/* Normal invocation convention. */ + +#ifndef _@GUARD_PREFIX@_FCNTL_H + +/* Needed before . + May also define off_t to a 64-bit type on native Windows. */ +#include +/* On some systems other than glibc, is a prerequisite of + . On glibc systems, we would like to avoid namespace pollution. + But on glibc systems, includes inside an + extern "C" { ... } block, which leads to errors in C++ mode with the + overridden from gnulib. These errors are known to be gone + with g++ version >= 4.3. */ +#if !(defined __GLIBC__ || defined __UCLIBC__) || (defined __cplusplus && defined GNULIB_NAMESPACE && !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) +# include +#endif +/* The include_next requires a split double-inclusion guard. */ +#@INCLUDE_NEXT@ @NEXT_FCNTL_H@ + +#ifndef _@GUARD_PREFIX@_FCNTL_H +#define _@GUARD_PREFIX@_FCNTL_H + +#ifndef __GLIBC__ /* Avoid namespace pollution on glibc systems. */ +# include +#endif + +/* Native Windows platforms declare open(), creat() in . */ +#if (@GNULIB_OPEN@ || defined GNULIB_POSIXCHECK) \ + && ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__) +# include +#endif + + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_ARG_NONNULL is copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + + +/* Declare overridden functions. */ + +#if @GNULIB_FCNTL@ +# if @REPLACE_FCNTL@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef fcntl +# define fcntl rpl_fcntl +# endif +_GL_FUNCDECL_RPL (fcntl, int, (int fd, int action, ...)); +_GL_CXXALIAS_RPL (fcntl, int, (int fd, int action, ...)); +# else +# if !@HAVE_FCNTL@ +_GL_FUNCDECL_SYS (fcntl, int, (int fd, int action, ...)); +# endif +_GL_CXXALIAS_SYS (fcntl, int, (int fd, int action, ...)); +# endif +_GL_CXXALIASWARN (fcntl); +#elif defined GNULIB_POSIXCHECK +# undef fcntl +# if HAVE_RAW_DECL_FCNTL +_GL_WARN_ON_USE (fcntl, "fcntl is not always POSIX compliant - " + "use gnulib module fcntl for portability"); +# endif +#endif + +#if @GNULIB_OPEN@ +# if @REPLACE_OPEN@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef open +# define open rpl_open +# endif +_GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...) + _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...)); +# else +_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...)); +# endif +/* On HP-UX 11, in C++ mode, open() is defined as an inline function with a + default argument. _GL_CXXALIASWARN does not work in this case. */ +# if !defined __hpux +_GL_CXXALIASWARN (open); +# endif +#elif defined GNULIB_POSIXCHECK +# undef open +/* Assume open is always declared. */ +_GL_WARN_ON_USE (open, "open is not always POSIX compliant - " + "use gnulib module open for portability"); +#endif + +#if @GNULIB_OPENAT@ +# if @REPLACE_OPENAT@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef openat +# define openat rpl_openat +# endif +_GL_FUNCDECL_RPL (openat, int, + (int fd, char const *file, int flags, /* mode_t mode */ ...) + _GL_ARG_NONNULL ((2))); +_GL_CXXALIAS_RPL (openat, int, + (int fd, char const *file, int flags, /* mode_t mode */ ...)); +# else +# if !@HAVE_OPENAT@ +_GL_FUNCDECL_SYS (openat, int, + (int fd, char const *file, int flags, /* mode_t mode */ ...) + _GL_ARG_NONNULL ((2))); +# endif +_GL_CXXALIAS_SYS (openat, int, + (int fd, char const *file, int flags, /* mode_t mode */ ...)); +# endif +_GL_CXXALIASWARN (openat); +#elif defined GNULIB_POSIXCHECK +# undef openat +# if HAVE_RAW_DECL_OPENAT +_GL_WARN_ON_USE (openat, "openat is not portable - " + "use gnulib module openat for portability"); +# endif +#endif + + +/* Fix up the FD_* macros, only known to be missing on mingw. */ + +#ifndef FD_CLOEXEC +# define FD_CLOEXEC 1 +#endif + +/* Fix up the supported F_* macros. Intentionally leave other F_* + macros undefined. Only known to be missing on mingw. */ + +#ifndef F_DUPFD_CLOEXEC +# define F_DUPFD_CLOEXEC 0x40000000 +/* Witness variable: 1 if gnulib defined F_DUPFD_CLOEXEC, 0 otherwise. */ +# define GNULIB_defined_F_DUPFD_CLOEXEC 1 +#else +# define GNULIB_defined_F_DUPFD_CLOEXEC 0 +#endif + +#ifndef F_DUPFD +# define F_DUPFD 1 +#endif + +#ifndef F_GETFD +# define F_GETFD 2 +#endif + +/* Fix up the O_* macros. */ + +#if !defined O_DIRECT && defined O_DIRECTIO +/* Tru64 spells it 'O_DIRECTIO'. */ +# define O_DIRECT O_DIRECTIO +#endif + +#if !defined O_CLOEXEC && defined O_NOINHERIT +/* Mingw spells it 'O_NOINHERIT'. */ +# define O_CLOEXEC O_NOINHERIT +#endif + +#ifndef O_CLOEXEC +# define O_CLOEXEC 0 +#endif + +#ifndef O_DIRECT +# define O_DIRECT 0 +#endif + +#ifndef O_DIRECTORY +# define O_DIRECTORY 0 +#endif + +#ifndef O_DSYNC +# define O_DSYNC 0 +#endif + +#ifndef O_EXEC +# ifdef O_PATH +# define O_EXEC O_PATH +# else +# define O_EXEC O_RDONLY /* This is often close enough in older systems. */ +# endif +#endif + +#ifndef O_IGNORE_CTTY +# define O_IGNORE_CTTY 0 +#endif + +#ifndef O_NDELAY +# define O_NDELAY 0 +#endif + +#ifndef O_NOATIME +# define O_NOATIME 0 +#endif + +#ifndef O_NONBLOCK +# define O_NONBLOCK O_NDELAY +#endif + +/* If the gnulib module 'nonblocking' is in use, guarantee a working non-zero + value of O_NONBLOCK. Otherwise, O_NONBLOCK is defined (above) to O_NDELAY + or to 0 as fallback. */ +#if @GNULIB_NONBLOCKING@ +# if O_NONBLOCK +# define GNULIB_defined_O_NONBLOCK 0 +# else +# define GNULIB_defined_O_NONBLOCK 1 +# undef O_NONBLOCK +# define O_NONBLOCK 0x40000000 +# endif +#endif + +#ifndef O_NOCTTY +# define O_NOCTTY 0 +#endif + +#ifndef O_NOFOLLOW +# define O_NOFOLLOW 0 +#endif + +#ifndef O_NOLINK +# define O_NOLINK 0 +#endif + +#ifndef O_NOLINKS +# define O_NOLINKS 0 +#endif + +#ifndef O_NOTRANS +# define O_NOTRANS 0 +#endif + +#ifndef O_RSYNC +# define O_RSYNC 0 +#endif + +#ifndef O_SEARCH +# ifdef O_PATH +# define O_SEARCH O_PATH +# else +# define O_SEARCH O_RDONLY /* This is often close enough in older systems. */ +# endif +#endif + +#ifndef O_SYNC +# define O_SYNC 0 +#endif + +#ifndef O_TTY_INIT +# define O_TTY_INIT 0 +#endif + +#if ~O_ACCMODE & (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH) +# undef O_ACCMODE +# define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH) +#endif + +/* For systems that distinguish between text and binary I/O. + O_BINARY is usually declared in fcntl.h */ +#if !defined O_BINARY && defined _O_BINARY + /* For MSC-compatible compilers. */ +# define O_BINARY _O_BINARY +# define O_TEXT _O_TEXT +#endif + +#if defined __BEOS__ || defined __HAIKU__ + /* BeOS 5 and Haiku have O_BINARY and O_TEXT, but they have no effect. */ +# undef O_BINARY +# undef O_TEXT +#endif + +#ifndef O_BINARY +# define O_BINARY 0 +# define O_TEXT 0 +#endif + +/* Fix up the AT_* macros. */ + +/* Work around a bug in Solaris 9 and 10: AT_FDCWD is positive. Its + value exceeds INT_MAX, so its use as an int doesn't conform to the + C standard, and GCC and Sun C complain in some cases. If the bug + is present, undef AT_FDCWD here, so it can be redefined below. */ +#if 0 < AT_FDCWD && AT_FDCWD == 0xffd19553 +# undef AT_FDCWD +#endif + +/* Use the same bit pattern as Solaris 9, but with the proper + signedness. The bit pattern is important, in case this actually is + Solaris with the above workaround. */ +#ifndef AT_FDCWD +# define AT_FDCWD (-3041965) +#endif + +/* Use the same values as Solaris 9. This shouldn't matter, but + there's no real reason to differ. */ +#ifndef AT_SYMLINK_NOFOLLOW +# define AT_SYMLINK_NOFOLLOW 4096 +#endif + +#ifndef AT_REMOVEDIR +# define AT_REMOVEDIR 1 +#endif + +/* Solaris 9 lacks these two, so just pick unique values. */ +#ifndef AT_SYMLINK_FOLLOW +# define AT_SYMLINK_FOLLOW 2 +#endif + +#ifndef AT_EACCESS +# define AT_EACCESS 4 +#endif + + +#endif /* _@GUARD_PREFIX@_FCNTL_H */ +#endif /* _@GUARD_PREFIX@_FCNTL_H */ +#endif === added file 'lib/getgroups.c' --- lib/getgroups.c 1970-01-01 00:00:00 +0000 +++ lib/getgroups.c 2012-11-14 04:55:41 +0000 @@ -0,0 +1,116 @@ +/* provide consistent interface to getgroups for systems that don't allow N==0 + + Copyright (C) 1996, 1999, 2003, 2006-2012 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* written by Jim Meyering */ + +#include + +#include + +#include +#include +#include + +#if !HAVE_GETGROUPS + +/* Provide a stub that fails with ENOSYS, since there is no group + information available on mingw. */ +int +getgroups (int n _GL_UNUSED, GETGROUPS_T *groups _GL_UNUSED) +{ + errno = ENOSYS; + return -1; +} + +#else /* HAVE_GETGROUPS */ + +# undef getgroups +# ifndef GETGROUPS_ZERO_BUG +# define GETGROUPS_ZERO_BUG 0 +# endif + +/* On at least Ultrix 4.3 and NextStep 3.2, getgroups (0, NULL) always + fails. On other systems, it returns the number of supplemental + groups for the process. This function handles that special case + and lets the system-provided function handle all others. However, + it can fail with ENOMEM if memory is tight. It is unspecified + whether the effective group id is included in the list. */ + +int +rpl_getgroups (int n, gid_t *group) +{ + int n_groups; + GETGROUPS_T *gbuf; + int saved_errno; + + if (n < 0) + { + errno = EINVAL; + return -1; + } + + if (n != 0 || !GETGROUPS_ZERO_BUG) + { + int result; + if (sizeof *group == sizeof *gbuf) + return getgroups (n, (GETGROUPS_T *) group); + + if (SIZE_MAX / sizeof *gbuf <= n) + { + errno = ENOMEM; + return -1; + } + gbuf = malloc (n * sizeof *gbuf); + if (!gbuf) + return -1; + result = getgroups (n, gbuf); + if (0 <= result) + { + n = result; + while (n--) + group[n] = gbuf[n]; + } + saved_errno = errno; + free (gbuf); + errno == saved_errno; + return result; + } + + n = 20; + while (1) + { + /* No need to worry about address arithmetic overflow here, + since the ancient systems that we're running on have low + limits on the number of secondary groups. */ + gbuf = malloc (n * sizeof *gbuf); + if (!gbuf) + return -1; + n_groups = getgroups (n, gbuf); + if (n_groups == -1 ? errno != EINVAL : n_groups < n) + break; + free (gbuf); + n *= 2; + } + + saved_errno = errno; + free (gbuf); + errno = saved_errno; + + return n_groups; +} + +#endif /* HAVE_GETGROUPS */ === modified file 'lib/gnulib.mk' --- lib/gnulib.mk 2012-11-03 18:54:17 +0000 +++ lib/gnulib.mk 2012-11-14 04:55:41 +0000 @@ -21,7 +21,7 @@ # the same distribution terms as the rest of that program. # # Generated by gnulib-tool. -# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat --avoid=msvc-inval --avoid=msvc-nothrow --avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub utimens warnings +# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=at-internal --avoid=errno --avoid=fchdir --avoid=fcntl --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=openat-die --avoid=openat-h --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub utimens warnings MOSTLYCLEANFILES += core *.stackdump @@ -158,6 +158,17 @@ ## end gnulib module dup2 +## begin gnulib module euidaccess + +if gl_GNULIB_ENABLED_euidaccess + +endif +EXTRA_DIST += euidaccess.c + +EXTRA_libgnu_a_SOURCES += euidaccess.c + +## end gnulib module euidaccess + ## begin gnulib module execinfo BUILT_SOURCES += $(EXECINFO_H) @@ -183,6 +194,50 @@ ## end gnulib module execinfo +## begin gnulib module faccessat + + +EXTRA_DIST += at-func.c faccessat.c + +EXTRA_libgnu_a_SOURCES += at-func.c faccessat.c + +## end gnulib module faccessat + +## begin gnulib module fcntl-h + +BUILT_SOURCES += fcntl.h + +# We need the following in order to create when the system +# doesn't have one that works with the given compiler. +fcntl.h: fcntl.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H) + $(AM_V_GEN)rm -f $@-t $@ && \ + { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ + sed -e 's|@''GUARD_PREFIX''@|GL|g' \ + -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \ + -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ + -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ + -e 's|@''NEXT_FCNTL_H''@|$(NEXT_FCNTL_H)|g' \ + -e 's/@''GNULIB_FCNTL''@/$(GNULIB_FCNTL)/g' \ + -e 's/@''GNULIB_NONBLOCKING''@/$(GNULIB_NONBLOCKING)/g' \ + -e 's/@''GNULIB_OPEN''@/$(GNULIB_OPEN)/g' \ + -e 's/@''GNULIB_OPENAT''@/$(GNULIB_OPENAT)/g' \ + -e 's|@''HAVE_FCNTL''@|$(HAVE_FCNTL)|g' \ + -e 's|@''HAVE_OPENAT''@|$(HAVE_OPENAT)|g' \ + -e 's|@''REPLACE_FCNTL''@|$(REPLACE_FCNTL)|g' \ + -e 's|@''REPLACE_OPEN''@|$(REPLACE_OPEN)|g' \ + -e 's|@''REPLACE_OPENAT''@|$(REPLACE_OPENAT)|g' \ + -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ + -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ + -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ + < $(srcdir)/fcntl.in.h; \ + } > $@-t && \ + mv $@-t $@ +MOSTLYCLEANFILES += fcntl.h fcntl.h-t + +EXTRA_DIST += fcntl.in.h + +## end gnulib module fcntl-h + ## begin gnulib module filemode libgnu_a_SOURCES += filemode.c @@ -200,6 +255,17 @@ ## end gnulib module fpending +## begin gnulib module getgroups + +if gl_GNULIB_ENABLED_getgroups + +endif +EXTRA_DIST += getgroups.c + +EXTRA_libgnu_a_SOURCES += getgroups.c + +## end gnulib module getgroups + ## begin gnulib module getloadavg @@ -259,6 +325,17 @@ ## end gnulib module gettimeofday +## begin gnulib module group-member + +if gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1 + +endif +EXTRA_DIST += group-member.c + +EXTRA_libgnu_a_SOURCES += group-member.c + +## end gnulib module group-member + ## begin gnulib module ignore-value @@ -371,6 +448,15 @@ ## end gnulib module readlink +## begin gnulib module root-uid + +if gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c + +endif +EXTRA_DIST += root-uid.h + +## end gnulib module root-uid + ## begin gnulib module signal-h BUILT_SOURCES += signal.h @@ -1329,6 +1415,15 @@ ## end gnulib module verify +## begin gnulib module xalloc-oversized + +if gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec + +endif +EXTRA_DIST += xalloc-oversized.h + +## end gnulib module xalloc-oversized + mostlyclean-local: mostlyclean-generic @for dir in '' $(MOSTLYCLEANDIRS); do \ === added file 'lib/group-member.c' --- lib/group-member.c 1970-01-01 00:00:00 +0000 +++ lib/group-member.c 2012-11-14 04:55:41 +0000 @@ -0,0 +1,119 @@ +/* group-member.c -- determine whether group id is in calling user's group list + + Copyright (C) 1994, 1997-1998, 2003, 2005-2006, 2009-2012 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +/* Specification. */ +#include + +#include +#include +#include + +#include "xalloc-oversized.h" + +/* Most processes have no more than this many groups, and for these + processes we can avoid using malloc. */ +enum { GROUPBUF_SIZE = 100 }; + +struct group_info + { + gid_t *group; + gid_t groupbuf[GROUPBUF_SIZE]; + }; + +static void +free_group_info (struct group_info const *g) +{ + if (g->group != g->groupbuf) + free (g->group); +} + +static int +get_group_info (struct group_info *gi) +{ + int n_groups = getgroups (GROUPBUF_SIZE, gi->groupbuf); + gi->group = gi->groupbuf; + + if (n_groups < 0) + { + int n_group_slots = getgroups (0, NULL); + if (0 <= n_group_slots + && ! xalloc_oversized (n_group_slots, sizeof *gi->group)) + { + gi->group = malloc (n_group_slots * sizeof *gi->group); + if (gi->group) + n_groups = getgroups (n_group_slots, gi->group); + } + } + + /* In case of error, the user loses. */ + return n_groups; +} + +/* Return non-zero if GID is one that we have in our groups list. + Note that the groups list is not guaranteed to contain the current + or effective group ID, so they should generally be checked + separately. */ + +int +group_member (gid_t gid) +{ + int i; + int found; + struct group_info gi; + int n_groups = get_group_info (&gi); + + /* Search through the list looking for GID. */ + found = 0; + for (i = 0; i < n_groups; i++) + { + if (gid == gi.group[i]) + { + found = 1; + break; + } + } + + free_group_info (&gi); + + return found; +} + +#ifdef TEST + +char *program_name; + +int +main (int argc, char **argv) +{ + int i; + + program_name = argv[0]; + + for (i = 1; i < argc; i++) + { + gid_t gid; + + gid = atoi (argv[i]); + printf ("%d: %s\n", gid, group_member (gid) ? "yes" : "no"); + } + exit (0); +} + +#endif /* TEST */ === added file 'lib/root-uid.h' --- lib/root-uid.h 1970-01-01 00:00:00 +0000 +++ lib/root-uid.h 2012-11-14 04:55:41 +0000 @@ -0,0 +1,30 @@ +/* The user ID that always has appropriate privileges in the POSIX sense. + + Copyright 2012 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Paul Eggert. */ + +#ifndef ROOT_UID_H_ +#define ROOT_UID_H_ + +/* The user ID that always has appropriate privileges in the POSIX sense. */ +#ifdef __TANDEM +# define ROOT_UID 65535 +#else +# define ROOT_UID 0 +#endif + +#endif === added file 'lib/xalloc-oversized.h' --- lib/xalloc-oversized.h 1970-01-01 00:00:00 +0000 +++ lib/xalloc-oversized.h 2012-11-14 04:55:41 +0000 @@ -0,0 +1,38 @@ +/* xalloc-oversized.h -- memory allocation size checking + + Copyright (C) 1990-2000, 2003-2004, 2006-2012 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef XALLOC_OVERSIZED_H_ +# define XALLOC_OVERSIZED_H_ + +# include + +/* Return 1 if an array of N objects, each of size S, cannot exist due + to size arithmetic overflow. S must be positive and N must be + nonnegative. This is a macro, not a function, so that it + works correctly even when SIZE_MAX < N. + + By gnulib convention, SIZE_MAX represents overflow in size + calculations, so the conservative dividend to use here is + SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value. + However, malloc (SIZE_MAX) fails on all known hosts where + sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for + exactly-SIZE_MAX allocations on such hosts; this avoids a test and + branch when S is known to be 1. */ +# define xalloc_oversized(n, s) \ + ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) + +#endif /* !XALLOC_OVERSIZED_H_ */ === added file 'm4/euidaccess.m4' --- m4/euidaccess.m4 1970-01-01 00:00:00 +0000 +++ m4/euidaccess.m4 2012-11-14 04:55:41 +0000 @@ -0,0 +1,52 @@ +# euidaccess.m4 serial 15 +dnl Copyright (C) 2002-2012 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_NONREENTRANT_EUIDACCESS], +[ + AC_REQUIRE([gl_FUNC_EUIDACCESS]) + AC_CHECK_DECLS([setregid]) + AC_DEFINE([PREFER_NONREENTRANT_EUIDACCESS], [1], + [Define this if you prefer euidaccess to return the correct result + even if this would make it nonreentrant. Define this only if your + entire application is safe even if the uid or gid might temporarily + change. If your application uses signal handlers or threads it + is probably not safe.]) +]) + +AC_DEFUN([gl_FUNC_EUIDACCESS], +[ + AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) + + dnl Persuade glibc to declare euidaccess(). + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + + AC_CHECK_FUNCS([euidaccess]) + if test $ac_cv_func_euidaccess = no; then + HAVE_EUIDACCESS=0 + fi +]) + +# Prerequisites of lib/euidaccess.c. +AC_DEFUN([gl_PREREQ_EUIDACCESS], [ + dnl Prefer POSIX faccessat over non-standard euidaccess. + AC_CHECK_FUNCS_ONCE([faccessat]) + dnl Try various other non-standard fallbacks. + AC_CHECK_HEADERS([libgen.h]) + AC_FUNC_GETGROUPS + + # Solaris 9 and 10 need -lgen to get the eaccess function. + # Save and restore LIBS so -lgen isn't added to it. Otherwise, *all* + # programs in the package would end up linked with that potentially-shared + # library, inducing unnecessary run-time overhead. + LIB_EACCESS= + AC_SUBST([LIB_EACCESS]) + gl_saved_libs=$LIBS + AC_SEARCH_LIBS([eaccess], [gen], + [test "$ac_cv_search_eaccess" = "none required" || + LIB_EACCESS=$ac_cv_search_eaccess]) + AC_CHECK_FUNCS([eaccess]) + LIBS=$gl_saved_libs +]) === added file 'm4/faccessat.m4' --- m4/faccessat.m4 1970-01-01 00:00:00 +0000 +++ m4/faccessat.m4 2012-11-14 04:55:41 +0000 @@ -0,0 +1,28 @@ +# serial 6 +# See if we need to provide faccessat replacement. + +dnl Copyright (C) 2009-2012 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Written by Eric Blake. + +AC_DEFUN([gl_FUNC_FACCESSAT], +[ + AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) + + dnl Persuade glibc to declare faccessat(). + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + + AC_CHECK_FUNCS_ONCE([faccessat]) + if test $ac_cv_func_faccessat = no; then + HAVE_FACCESSAT=0 + fi +]) + +# Prerequisites of lib/faccessat.m4. +AC_DEFUN([gl_PREREQ_FACCESSAT], +[ + AC_CHECK_FUNCS([access]) +]) === added file 'm4/fcntl_h.m4' --- m4/fcntl_h.m4 1970-01-01 00:00:00 +0000 +++ m4/fcntl_h.m4 2012-11-14 04:55:41 +0000 @@ -0,0 +1,50 @@ +# serial 15 +# Configure fcntl.h. +dnl Copyright (C) 2006-2007, 2009-2012 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Written by Paul Eggert. + +AC_DEFUN([gl_FCNTL_H], +[ + AC_REQUIRE([gl_FCNTL_H_DEFAULTS]) + AC_REQUIRE([gl_FCNTL_O_FLAGS]) + gl_NEXT_HEADERS([fcntl.h]) + + dnl Ensure the type pid_t gets defined. + AC_REQUIRE([AC_TYPE_PID_T]) + + dnl Ensure the type mode_t gets defined. + AC_REQUIRE([AC_TYPE_MODE_T]) + + dnl Check for declarations of anything we want to poison if the + dnl corresponding gnulib module is not in use, if it is not common + dnl enough to be declared everywhere. + gl_WARN_ON_USE_PREPARE([[#include + ]], [fcntl openat]) +]) + +AC_DEFUN([gl_FCNTL_MODULE_INDICATOR], +[ + dnl Use AC_REQUIRE here, so that the default settings are expanded once only. + AC_REQUIRE([gl_FCNTL_H_DEFAULTS]) + gl_MODULE_INDICATOR_SET_VARIABLE([$1]) + dnl Define it also as a C macro, for the benefit of the unit tests. + gl_MODULE_INDICATOR_FOR_TESTS([$1]) +]) + +AC_DEFUN([gl_FCNTL_H_DEFAULTS], +[ + GNULIB_FCNTL=0; AC_SUBST([GNULIB_FCNTL]) + GNULIB_NONBLOCKING=0; AC_SUBST([GNULIB_NONBLOCKING]) + GNULIB_OPEN=0; AC_SUBST([GNULIB_OPEN]) + GNULIB_OPENAT=0; AC_SUBST([GNULIB_OPENAT]) + dnl Assume proper GNU behavior unless another module says otherwise. + HAVE_FCNTL=1; AC_SUBST([HAVE_FCNTL]) + HAVE_OPENAT=1; AC_SUBST([HAVE_OPENAT]) + REPLACE_FCNTL=0; AC_SUBST([REPLACE_FCNTL]) + REPLACE_OPEN=0; AC_SUBST([REPLACE_OPEN]) + REPLACE_OPENAT=0; AC_SUBST([REPLACE_OPENAT]) +]) === added file 'm4/getgroups.m4' --- m4/getgroups.m4 1970-01-01 00:00:00 +0000 +++ m4/getgroups.m4 2012-11-14 04:55:41 +0000 @@ -0,0 +1,107 @@ +# serial 18 + +dnl From Jim Meyering. +dnl A wrapper around AC_FUNC_GETGROUPS. + +# Copyright (C) 1996-1997, 1999-2004, 2008-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +m4_version_prereq([2.70], [] ,[ + +# This is taken from the following Autoconf patch: +# http://git.savannah.gnu.org/gitweb/?p=autoconf.git;a=commitdiff;h=7fbb553727ed7e0e689a17594b58559ecf3ea6e9 +AC_DEFUN([AC_FUNC_GETGROUPS], +[ + AC_REQUIRE([AC_TYPE_GETGROUPS])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles + AC_CHECK_FUNC([getgroups]) + + # If we don't yet have getgroups, see if it's in -lbsd. + # This is reported to be necessary on an ITOS 3000WS running SEIUX 3.1. + ac_save_LIBS=$LIBS + if test $ac_cv_func_getgroups = no; then + AC_CHECK_LIB(bsd, getgroups, [GETGROUPS_LIB=-lbsd]) + fi + + # Run the program to test the functionality of the system-supplied + # getgroups function only if there is such a function. + if test $ac_cv_func_getgroups = yes; then + AC_CACHE_CHECK([for working getgroups], [ac_cv_func_getgroups_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [AC_INCLUDES_DEFAULT], + [[/* On Ultrix 4.3, getgroups (0, 0) always fails. */ + return getgroups (0, 0) == -1;]]) + ], + [ac_cv_func_getgroups_works=yes], + [ac_cv_func_getgroups_works=no], + [case "$host_os" in # (( + # Guess yes on glibc systems. + *-gnu*) ac_cv_func_getgroups_works="guessing yes" ;; + # If we don't know, assume the worst. + *) ac_cv_func_getgroups_works="guessing no" ;; + esac + ]) + ]) + else + ac_cv_func_getgroups_works=no + fi + case "$ac_cv_func_getgroups_works" in + *yes) + AC_DEFINE([HAVE_GETGROUPS], [1], + [Define to 1 if your system has a working `getgroups' function.]) + ;; + esac + LIBS=$ac_save_LIBS +])# AC_FUNC_GETGROUPS + +]) + +AC_DEFUN([gl_FUNC_GETGROUPS], +[ + AC_REQUIRE([AC_TYPE_GETGROUPS]) + AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + AC_FUNC_GETGROUPS + if test $ac_cv_func_getgroups != yes; then + HAVE_GETGROUPS=0 + else + if test "$ac_cv_type_getgroups" != gid_t \ + || { case "$ac_cv_func_getgroups_works" in + *yes) false;; + *) true;; + esac + }; then + REPLACE_GETGROUPS=1 + AC_DEFINE([GETGROUPS_ZERO_BUG], [1], [Define this to 1 if + getgroups(0,NULL) does not return the number of groups.]) + else + dnl Detect FreeBSD bug; POSIX requires getgroups(-1,ptr) to fail. + AC_CACHE_CHECK([whether getgroups handles negative values], + [gl_cv_func_getgroups_works], + [AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], + [[int size = getgroups (0, 0); + gid_t *list = malloc (size * sizeof *list); + return getgroups (-1, list) != -1;]])], + [gl_cv_func_getgroups_works=yes], + [gl_cv_func_getgroups_works=no], + [case "$host_os" in + # Guess yes on glibc systems. + *-gnu*) gl_cv_func_getgroups_works="guessing yes" ;; + # If we don't know, assume the worst. + *) gl_cv_func_getgroups_works="guessing no" ;; + esac + ])]) + case "$gl_cv_func_getgroups_works" in + *yes) ;; + *) REPLACE_GETGROUPS=1 ;; + esac + fi + fi + test -n "$GETGROUPS_LIB" && LIBS="$GETGROUPS_LIB $LIBS" +]) === modified file 'm4/gnulib-comp.m4' --- m4/gnulib-comp.m4 2012-11-03 18:54:17 +0000 +++ m4/gnulib-comp.m4 2012-11-14 04:55:41 +0000 @@ -54,18 +54,23 @@ # Code from module dtotimespec: # Code from module dup2: # Code from module environ: + # Code from module euidaccess: # Code from module execinfo: # Code from module extensions: AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) # Code from module extern-inline: + # Code from module faccessat: + # Code from module fcntl-h: # Code from module filemode: # Code from module fpending: + # Code from module getgroups: # Code from module getloadavg: # Code from module getopt-gnu: # Code from module getopt-posix: # Code from module gettext-h: # Code from module gettime: # Code from module gettimeofday: + # Code from module group-member: # Code from module ignore-value: # Code from module include_next: # Code from module intprops: @@ -81,6 +86,7 @@ # Code from module pselect: # Code from module pthread_sigmask: # Code from module readlink: + # Code from module root-uid: # Code from module signal-h: # Code from module snippet/_Noreturn: # Code from module snippet/arg-nonnull: @@ -122,6 +128,7 @@ # Code from module utimens: # Code from module verify: # Code from module warnings: + # Code from module xalloc-oversized: ]) # This macro should be invoked from ./configure.ac, in the section @@ -160,6 +167,14 @@ gl_UNISTD_MODULE_INDICATOR([environ]) gl_EXECINFO_H AC_REQUIRE([gl_EXTERN_INLINE]) + gl_FUNC_FACCESSAT + if test $HAVE_FACCESSAT = 0; then + AC_LIBOBJ([faccessat]) + gl_PREREQ_FACCESSAT + fi + gl_MODULE_INDICATOR([faccessat]) + gl_UNISTD_MODULE_INDICATOR([faccessat]) + gl_FCNTL_H gl_FILEMODE gl_FUNC_FPENDING if test $ac_cv_func___fpending = no; then @@ -278,18 +293,53 @@ gl_UNISTD_H gl_UTIMENS gl_gnulib_enabled_dosname=false + gl_gnulib_enabled_euidaccess=false + gl_gnulib_enabled_getgroups=false gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false + gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false gl_gnulib_enabled_pathmax=false + gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false gl_gnulib_enabled_stat=false gl_gnulib_enabled_strtoll=false gl_gnulib_enabled_strtoull=false gl_gnulib_enabled_verify=false + gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false func_gl_gnulib_m4code_dosname () { if ! $gl_gnulib_enabled_dosname; then gl_gnulib_enabled_dosname=true fi } + func_gl_gnulib_m4code_euidaccess () + { + if ! $gl_gnulib_enabled_euidaccess; then + gl_FUNC_EUIDACCESS + if test $HAVE_EUIDACCESS = 0; then + AC_LIBOBJ([euidaccess]) + gl_PREREQ_EUIDACCESS + fi + gl_UNISTD_MODULE_INDICATOR([euidaccess]) + gl_gnulib_enabled_euidaccess=true + if test $HAVE_EUIDACCESS = 0; then + func_gl_gnulib_m4code_a9786850e999ae65a836a6041e8e5ed1 + fi + func_gl_gnulib_m4code_6099e9737f757db36c47fa9d9f02e88c + if test $HAVE_EUIDACCESS = 0; then + func_gl_gnulib_m4code_stat + fi + fi + } + func_gl_gnulib_m4code_getgroups () + { + if ! $gl_gnulib_enabled_getgroups; then + gl_FUNC_GETGROUPS + if test $HAVE_GETGROUPS = 0 || test $REPLACE_GETGROUPS = 1; then + AC_LIBOBJ([getgroups]) + fi + gl_UNISTD_MODULE_INDICATOR([getgroups]) + gl_gnulib_enabled_getgroups=true + fi + } func_gl_gnulib_m4code_be453cec5eecf5731a274f2de7f2db36 () { if ! $gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36; then @@ -298,6 +348,24 @@ gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=true fi } + func_gl_gnulib_m4code_a9786850e999ae65a836a6041e8e5ed1 () + { + if ! $gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1; then + gl_FUNC_GROUP_MEMBER + if test $HAVE_GROUP_MEMBER = 0; then + AC_LIBOBJ([group-member]) + gl_PREREQ_GROUP_MEMBER + fi + gl_UNISTD_MODULE_INDICATOR([group-member]) + gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=true + if test $HAVE_GROUP_MEMBER = 0; then + func_gl_gnulib_m4code_getgroups + fi + if test $HAVE_GROUP_MEMBER = 0; then + func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec + fi + fi + } func_gl_gnulib_m4code_pathmax () { if ! $gl_gnulib_enabled_pathmax; then @@ -305,6 +373,12 @@ gl_gnulib_enabled_pathmax=true fi } + func_gl_gnulib_m4code_6099e9737f757db36c47fa9d9f02e88c () + { + if ! $gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c; then + gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=true + fi + } func_gl_gnulib_m4code_stat () { if ! $gl_gnulib_enabled_stat; then @@ -356,6 +430,18 @@ gl_gnulib_enabled_verify=true fi } + func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec () + { + if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then + gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=true + fi + } + if test $HAVE_FACCESSAT = 0; then + func_gl_gnulib_m4code_dosname + fi + if test $HAVE_FACCESSAT = 0; then + func_gl_gnulib_m4code_euidaccess + fi if test $REPLACE_GETOPT = 1; then func_gl_gnulib_m4code_be453cec5eecf5731a274f2de7f2db36 fi @@ -382,12 +468,17 @@ fi m4_pattern_allow([^gl_GNULIB_ENABLED_]) AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosname]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], [$gl_gnulib_enabled_euidaccess]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups]) AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], [$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1]) AM_CONDITIONAL([gl_GNULIB_ENABLED_pathmax], [$gl_gnulib_enabled_pathmax]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c]) AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat]) AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll]) AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoull], [$gl_gnulib_enabled_strtoull]) AM_CONDITIONAL([gl_GNULIB_ENABLED_verify], [$gl_gnulib_enabled_verify]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec]) # End of code from modules m4_ifval(gl_LIBSOURCES_LIST, [ m4_syscmd([test ! -d ]m4_defn([gl_LIBSOURCES_DIR])[ || @@ -536,6 +627,7 @@ lib/alloca.in.h lib/allocator.c lib/allocator.h + lib/at-func.c lib/c-ctype.c lib/c-ctype.h lib/c-strcase.h @@ -549,14 +641,18 @@ lib/dtoastr.c lib/dtotimespec.c lib/dup2.c + lib/euidaccess.c lib/execinfo.c lib/execinfo.in.h + lib/faccessat.c + lib/fcntl.in.h lib/filemode.c lib/filemode.h lib/fpending.c lib/fpending.h lib/ftoastr.c lib/ftoastr.h + lib/getgroups.c lib/getloadavg.c lib/getopt.c lib/getopt.in.h @@ -565,6 +661,7 @@ lib/gettext.h lib/gettime.c lib/gettimeofday.c + lib/group-member.c lib/ignore-value.h lib/intprops.h lib/inttypes.in.h @@ -577,6 +674,7 @@ lib/pselect.c lib/pthread_sigmask.c lib/readlink.c + lib/root-uid.h lib/sha1.c lib/sha1.h lib/sha256.c @@ -618,6 +716,7 @@ lib/utimens.c lib/utimens.h lib/verify.h + lib/xalloc-oversized.h m4/00gnulib.m4 m4/alloca.m4 m4/c-strtod.m4 @@ -625,16 +724,22 @@ m4/close-stream.m4 m4/dup2.m4 m4/environ.m4 + m4/euidaccess.m4 m4/execinfo.m4 m4/extensions.m4 m4/extern-inline.m4 + m4/faccessat.m4 + m4/fcntl-o.m4 + m4/fcntl_h.m4 m4/filemode.m4 m4/fpending.m4 + m4/getgroups.m4 m4/getloadavg.m4 m4/getopt.m4 m4/gettime.m4 m4/gettimeofday.m4 m4/gnulib-common.m4 + m4/group-member.m4 m4/include_next.m4 m4/inttypes.m4 m4/largefile.m4 === added file 'm4/group-member.m4' --- m4/group-member.m4 1970-01-01 00:00:00 +0000 +++ m4/group-member.m4 2012-11-14 04:55:41 +0000 @@ -0,0 +1,29 @@ +# serial 14 + +# Copyright (C) 1999-2001, 2003-2007, 2009-2012 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +dnl Written by Jim Meyering + +AC_DEFUN([gl_FUNC_GROUP_MEMBER], +[ + AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) + + dnl Persuade glibc to declare group_member(). + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + + dnl Do this replacement check manually because I want the hyphen + dnl (not the underscore) in the filename. + AC_CHECK_FUNC([group_member], , [ + HAVE_GROUP_MEMBER=0 + ]) +]) + +# Prerequisites of lib/group-member.c. +AC_DEFUN([gl_PREREQ_GROUP_MEMBER], +[ + AC_REQUIRE([AC_FUNC_GETGROUPS]) +]) === modified file 'nt/ChangeLog' --- nt/ChangeLog 2012-11-05 16:21:18 +0000 +++ nt/ChangeLog 2012-11-14 04:55:41 +0000 @@ -1,3 +1,10 @@ +2012-11-14 Paul Eggert + + Use faccessat, not access, when checking file permissions (Bug#12632). + * inc/ms-w32.h (AT_FDCWD, AT_EACCESS): New symbols. + (access): Remove. + (faccessat): New macro. + 2012-11-05 Eli Zaretskii * inc/unistd.h (tcgetpgrp, setsid): Provide prototypes. === modified file 'nt/inc/ms-w32.h' --- nt/inc/ms-w32.h 2012-10-19 19:25:18 +0000 +++ nt/inc/ms-w32.h 2012-11-14 04:55:41 +0000 @@ -124,6 +124,10 @@ #define MAXPATHLEN _MAX_PATH #endif +/* Use values compatible with gnulib, as there's no reason to differ. */ +#define AT_FDCWD (-3041965) +#define AT_EACCESS 4 + #ifdef HAVE_NTGUI #define HAVE_WINDOW_SYSTEM 1 #define HAVE_MENUS 1 @@ -145,8 +149,6 @@ #endif /* Calls that are emulated or shadowed. */ -#undef access -#define access sys_access #undef chdir #define chdir sys_chdir #undef chmod @@ -161,6 +163,7 @@ #define dup sys_dup #undef dup2 #define dup2 sys_dup2 +#define faccessat sys_faccessat #define fopen sys_fopen #define link sys_link #define localtime sys_localtime === modified file 'src/ChangeLog' --- src/ChangeLog 2012-11-13 13:50:58 +0000 +++ src/ChangeLog 2012-11-14 04:55:41 +0000 @@ -1,3 +1,70 @@ +2012-11-14 Paul Eggert + + Use faccessat, not access, when checking file permissions (Bug#12632). + This fixes a bug that has been present in Emacs since its creation. + It was reported by Chris Torek in 1983 even before GNU Emacs existed, + which must set some sort of record. (Torek's bug report was against + a predecessor of GNU Emacs, but GNU Emacs happened to have the + same common flaw.) See Torek's Usenet posting + "setuid/setgid programs & Emacs" Article-I.D.: sri-arpa.858 + Posted: Fri Apr 8 14:18:56 1983. + * Makefile.in (LIB_EACCESS): New macro. + (LIBES): Use it. + * callproc.c (init_callproc): + * charset.c (init_charset): + * fileio.c (check_existing, check_executable, check_writable) + (Ffile_readable_p): + * lread.c (openp, load_path_check): + * process.c (allocate_pty): + * xrdb.c (file_p): + Use effective UID when checking permissions, not real UID. + * callproc.c (init_callproc): + * charset.c (init_charset): + * lread.c (load_path_check, init_lread): + Test whether directories are accessible, not merely whether they exist. + * conf_post.h (GNULIB_SUPPORT_ONLY_AT_FDCWD): New macro. + * fileio.c (check_existing, check_executable, check_writable) + (Ffile_readable_p): + Use symbolic names instead of integers for the flags, as they're + portable now. + (check_writable): New arg AMODE. All uses changed. + Set errno on failure. + (Ffile_readable_p): Use faccessat, not stat + open + close. + (Ffile_writable_p): No need to call check_existing + check_writable. + Just call check_writable and then look at errno. This saves a syscall. + dir should never be nil; replace an unnecessary runtime check + with an eassert. When checking the parent directory of a nonexistent + file, check that the directory is searchable as well as writable, as + we can't create files in unsearchable directories. + (file_directory_p): New function, which uses 'stat' on most platforms + but faccessat with D_OK (for efficiency) if WINDOWSNT. + (Ffile_directory_p, Fset_file_times): Use it. + (file_accessible_directory_p): New function, which uses a single + syscall for efficiency. + (Ffile_accessible_directory_p): Use it. + * xrdb.c (file_p): Use file_directory_p. + * lisp.h (file_directory_p, file_accessible_directory_p): New decls. + * lread.c (openp): When opening a file, use fstat rather than + stat, as that avoids a permissions race. When not opening a file, + use file_directory_p rather than stat. + (dir_warning): First arg is now a usage string, not a format. + Use errno. All uses changed. + * nsterm.m (ns_term_init): Remove unnecessary call to file-readable + that merely introduced a race. + * process.c, sysdep.c, term.c: All uses of '#ifdef O_NONBLOCK' + changed to '#if O_NONBLOCK', to accommodate gnulib O_* style, + and similarly for the other O_* flags. + * w32.c (sys_faccessat): Rename from sys_access and switch to + faccessat's API. All uses changed. + * xrdb.c: Do not include ; no longer needed. + (magic_db): Rename from magic_file_p. + (magic_db, search_magic_path): Return an XrmDatabase rather than a + char *, so that we don't have to test for file existence + separately from opening the file for reading. This removes a race + fixes a permission-checking problem, and simplifies the code. + All uses changed. + (file_p): Remove; no longer needed. + 2012-11-13 Dmitry Antipov Omit glyphs initialization at startup. === modified file 'src/Makefile.in' --- src/Makefile.in 2012-10-19 19:25:18 +0000 +++ src/Makefile.in 2012-11-14 04:55:41 +0000 @@ -150,6 +150,7 @@ M17N_FLT_LIBS = @M17N_FLT_LIBS@ LIB_CLOCK_GETTIME=@LIB_CLOCK_GETTIME@ +LIB_EACCESS=@LIB_EACCESS@ LIB_TIMER_TIME=@LIB_TIMER_TIME@ DBUS_CFLAGS = @DBUS_CFLAGS@ @@ -392,7 +393,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBX_BASE) $(LIBIMAGE) \ $(LIBX_OTHER) $(LIBSOUND) \ $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_CLOCK_GETTIME) \ - $(LIB_TIMER_TIME) $(DBUS_LIBS) \ + $(LIB_EACCESS) $(LIB_TIMER_TIME) $(DBUS_LIBS) \ $(LIB_EXECINFO) \ $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \ $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ === modified file 'src/callproc.c' --- src/callproc.c 2012-11-05 03:18:32 +0000 +++ src/callproc.c 2012-11-14 04:55:41 +0000 @@ -1576,15 +1576,13 @@ #endif { tempdir = Fdirectory_file_name (Vexec_directory); - if (access (SSDATA (tempdir), 0) < 0) - dir_warning ("Warning: arch-dependent data dir (%s) does not exist.\n", - Vexec_directory); + if (! file_accessible_directory_p (SSDATA (tempdir))) + dir_warning ("arch-dependent data dir", Vexec_directory); } tempdir = Fdirectory_file_name (Vdata_directory); - if (access (SSDATA (tempdir), 0) < 0) - dir_warning ("Warning: arch-independent data dir (%s) does not exist.\n", - Vdata_directory); + if (! file_accessible_directory_p (SSDATA (tempdir))) + dir_warning ("arch-independent data dir", Vdata_directory); sh = (char *) getenv ("SHELL"); Vshell_file_name = build_string (sh ? sh : "/bin/sh"); @@ -1593,7 +1591,7 @@ Vshared_game_score_directory = Qnil; #else Vshared_game_score_directory = build_string (PATH_GAME); - if (NILP (Ffile_directory_p (Vshared_game_score_directory))) + if (NILP (Ffile_accessible_directory_p (Vshared_game_score_directory))) Vshared_game_score_directory = Qnil; #endif } === modified file 'src/charset.c' --- src/charset.c 2012-10-19 19:25:18 +0000 +++ src/charset.c 2012-11-14 04:55:41 +0000 @@ -2293,7 +2293,7 @@ { Lisp_Object tempdir; tempdir = Fexpand_file_name (build_string ("charsets"), Vdata_directory); - if (access (SSDATA (tempdir), 0) < 0) + if (! file_accessible_directory_p (SSDATA (tempdir))) { /* This used to be non-fatal (dir_warning), but it should not happen, and if it does sooner or later it will cause some === modified file 'src/conf_post.h' --- src/conf_post.h 2012-11-05 03:18:32 +0000 +++ src/conf_post.h 2012-11-14 04:55:41 +0000 @@ -178,6 +178,10 @@ #endif #endif +/* Tell gnulib to omit support for openat-related functions having a + first argument other than AT_FDCWD. */ +#define GNULIB_SUPPORT_ONLY_AT_FDCWD + #include #include === modified file 'src/fileio.c' --- src/fileio.c 2012-11-13 01:35:14 +0000 +++ src/fileio.c 2012-11-14 04:55:41 +0000 @@ -2425,15 +2425,7 @@ bool check_existing (const char *filename) { -#ifdef DOS_NT - /* The full emulation of Posix 'stat' is too expensive on - DOS/Windows, when all we want to know is whether the file exists. - So we use 'access' instead, which is much more lightweight. */ - return (access (filename, F_OK) >= 0); -#else - struct stat st; - return (stat (filename, &st) >= 0); -#endif + return faccessat (AT_FDCWD, filename, F_OK, AT_EACCESS) == 0; } /* Return true if file FILENAME exists and can be executed. */ @@ -2441,56 +2433,40 @@ static bool check_executable (char *filename) { -#ifdef DOS_NT - struct stat st; - if (stat (filename, &st) < 0) - return 0; - return ((st.st_mode & S_IEXEC) != 0); -#else /* not DOS_NT */ -#ifdef HAVE_EUIDACCESS - return (euidaccess (filename, 1) >= 0); -#else - /* Access isn't quite right because it uses the real uid - and we really want to test with the effective uid. - But Unix doesn't give us a right way to do it. */ - return (access (filename, 1) >= 0); -#endif -#endif /* not DOS_NT */ + return faccessat (AT_FDCWD, filename, X_OK, AT_EACCESS) == 0; } -/* Return true if file FILENAME exists and can be written. */ +/* Return true if file FILENAME exists and can be accessed + according to AMODE, which should include W_OK. + On failure, return false and set errno. */ static bool -check_writable (const char *filename) +check_writable (const char *filename, int amode) { #ifdef MSDOS + /* FIXME: an faccessat implementation should be added to the + DOS/Windows ports and this #ifdef branch should be removed. */ struct stat st; if (stat (filename, &st) < 0) return 0; + errno = EPERM; return (st.st_mode & S_IWRITE || S_ISDIR (st.st_mode)); #else /* not MSDOS */ -#ifdef HAVE_EUIDACCESS - bool res = (euidaccess (filename, 2) >= 0); + bool res = faccessat (AT_FDCWD, filename, amode, AT_EACCESS) == 0; #ifdef CYGWIN - /* euidaccess may have returned failure because Cygwin couldn't + /* faccessat may have returned failure because Cygwin couldn't determine the file's UID or GID; if so, we return success. */ if (!res) { + int faccessat_errno = errno; struct stat st; if (stat (filename, &st) < 0) return 0; res = (st.st_uid == -1 || st.st_gid == -1); + errno = faccessat_errno; } #endif /* CYGWIN */ return res; -#else /* not HAVE_EUIDACCESS */ - /* Access isn't quite right because it uses the real uid - and we really want to test with the effective uid. - But Unix doesn't give us a right way to do it. - Opening with O_WRONLY could work for an ordinary file, - but would lose for directories. */ - return (access (filename, 2) >= 0); -#endif /* not HAVE_EUIDACCESS */ #endif /* not MSDOS */ } @@ -2547,9 +2523,6 @@ { Lisp_Object absname; Lisp_Object handler; - int desc; - int flags; - struct stat statbuf; CHECK_STRING (filename); absname = Fexpand_file_name (filename, Qnil); @@ -2561,35 +2534,10 @@ return call2 (handler, Qfile_readable_p, absname); absname = ENCODE_FILE (absname); - -#if defined (DOS_NT) || defined (macintosh) - /* Under MS-DOS, Windows, and Macintosh, open does not work for - directories. */ - if (access (SDATA (absname), 0) == 0) - return Qt; - return Qnil; -#else /* not DOS_NT and not macintosh */ - flags = O_RDONLY; -#ifdef O_NONBLOCK - /* Opening a fifo without O_NONBLOCK can wait. - We don't want to wait. But we don't want to mess wth O_NONBLOCK - except in the case of a fifo, on a system which handles it. */ - desc = stat (SSDATA (absname), &statbuf); - if (desc < 0) - return Qnil; - if (S_ISFIFO (statbuf.st_mode)) - flags |= O_NONBLOCK; -#endif - desc = emacs_open (SSDATA (absname), flags, 0); - if (desc < 0) - return Qnil; - emacs_close (desc); - return Qt; -#endif /* not DOS_NT and not macintosh */ + return (faccessat (AT_FDCWD, SSDATA (absname), R_OK, AT_EACCESS) == 0 + ? Qt : Qnil); } -/* Having this before file-symlink-p mysteriously caused it to be forgotten - on the RT/PC. */ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, doc: /* Return t if file FILENAME can be written or created by you. */) (Lisp_Object filename) @@ -2607,14 +2555,15 @@ return call2 (handler, Qfile_writable_p, absname); encoded = ENCODE_FILE (absname); - if (check_existing (SSDATA (encoded))) - return (check_writable (SSDATA (encoded)) - ? Qt : Qnil); + if (check_writable (SSDATA (encoded), W_OK)) + return Qt; + if (errno != ENOENT) + return Qnil; dir = Ffile_name_directory (absname); + eassert (!NILP (dir)); #ifdef MSDOS - if (!NILP (dir)) - dir = Fdirectory_file_name (dir); + dir = Fdirectory_file_name (dir); #endif /* MSDOS */ dir = ENCODE_FILE (dir); @@ -2622,10 +2571,9 @@ /* The read-only attribute of the parent directory doesn't affect whether a file or directory can be created within it. Some day we should check ACLs though, which do affect this. */ - return (access (SDATA (dir), D_OK) < 0) ? Qnil : Qt; + return file_directory_p (SDATA (dir)) ? Qt : Qnil; #else - return (check_writable (!NILP (dir) ? SSDATA (dir) : "") - ? Qt : Qnil); + return check_writable (SSDATA (dir), W_OK | X_OK) ? Qt : Qnil; #endif } @@ -2703,8 +2651,7 @@ See `file-symlink-p' to distinguish symlinks. */) (Lisp_Object filename) { - register Lisp_Object absname; - struct stat st; + Lisp_Object absname; Lisp_Object handler; absname = expand_and_dir_to_file (filename, BVAR (current_buffer, directory)); @@ -2717,9 +2664,20 @@ absname = ENCODE_FILE (absname); - if (stat (SSDATA (absname), &st) < 0) - return Qnil; - return S_ISDIR (st.st_mode) ? Qt : Qnil; + return file_directory_p (SSDATA (absname)) ? Qt : Qnil; +} + +/* Return true if FILE is a directory or a symlink to a directory. */ +bool +file_directory_p (char const *file) +{ +#ifdef WINDOWSNT + /* This is cheaper than 'stat'. */ + return faccessat (AT_FDCWD, file, D_OK, AT_EACCESS) == 0; +#else + struct stat st; + return stat (file, &st) == 0 && S_ISDIR (st.st_mode); +#endif } DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, @@ -2733,21 +2691,65 @@ searchable directory. */) (Lisp_Object filename) { + Lisp_Object absname; Lisp_Object handler; - bool tem; - struct gcpro gcpro1; + + CHECK_STRING (filename); + absname = Fexpand_file_name (filename, Qnil); /* If the file name has special constructs in it, call the corresponding file handler. */ - handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p); + handler = Ffind_file_name_handler (absname, Qfile_accessible_directory_p); if (!NILP (handler)) - return call2 (handler, Qfile_accessible_directory_p, filename); - - GCPRO1 (filename); - tem = (NILP (Ffile_directory_p (filename)) - || NILP (Ffile_executable_p (filename))); - UNGCPRO; - return tem ? Qnil : Qt; + return call2 (handler, Qfile_accessible_directory_p, absname); + + absname = ENCODE_FILE (absname); + return file_accessible_directory_p (SSDATA (absname)) ? Qt : Qnil; +} + +/* If FILE is a searchable directory or a symlink to a + searchable directory, return true. Otherwise return + false and set errno to an error number. */ +bool +file_accessible_directory_p (char const *file) +{ +#ifdef DOS_NT + /* There's no need to test whether FILE is searchable, as the + searchable/executable bit is invented on DOS_NT platforms. */ + return file_directory_p (file); +#else + /* On POSIXish platforms, use just one system call; this avoids a + race and is typically faster. */ + ptrdiff_t len = strlen (file); + char const *dir; + bool ok; + int saved_errno; + USE_SAFE_ALLOCA; + + /* Normally a file "FOO" is an accessible directory if "FOO/." exists. + There are three exceptions: "", "/", and "//". Leave "" alone, + as it's invalid. Append only "." to the other two exceptions as + "/" and "//" are distinct on some platforms, whereas "/", "///", + "////", etc. are all equivalent. */ + if (! len) + dir = file; + else + { + /* Just check for trailing '/' when deciding whether to append '/'. + That's simpler than testing the two special cases "/" and "//", + and it's a safe optimization here. */ + char *buf = SAFE_ALLOCA (len + 3); + memcpy (buf, file, len); + strcpy (buf + len, "/." + (file[len - 1] == '/')); + dir = buf; + } + + ok = check_existing (dir); + saved_errno = errno; + SAFE_FREE (); + errno = saved_errno; + return ok; +#endif } DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0, @@ -3044,10 +3046,8 @@ if (set_file_times (-1, SSDATA (encoded_absname), t, t)) { #ifdef MSDOS - struct stat st; - /* Setting times on a directory always fails. */ - if (stat (SSDATA (encoded_absname), &st) == 0 && S_ISDIR (st.st_mode)) + if (file_directory_p (SSDATA (encoded_absname))) return Qnil; #endif report_file_error ("Setting file times", Fcons (absname, Qnil)); === modified file 'src/lisp.h' --- src/lisp.h 2012-11-09 22:20:47 +0000 +++ src/lisp.h 2012-11-14 04:55:41 +0000 @@ -3202,6 +3202,8 @@ extern Lisp_Object restore_point_unwind (Lisp_Object); extern _Noreturn void report_file_error (const char *, Lisp_Object); extern void internal_delete_file (Lisp_Object); +extern bool file_directory_p (const char *); +extern bool file_accessible_directory_p (const char *); extern void syms_of_fileio (void); extern Lisp_Object make_temp_name (Lisp_Object, bool); extern Lisp_Object Qdelete_file; === modified file 'src/lread.c' --- src/lread.c 2012-11-08 14:10:28 +0000 +++ src/lread.c 2012-11-14 04:55:41 +0000 @@ -1403,7 +1403,7 @@ If SUFFIXES is non-nil, it should be a list of suffixes to append to file name when searching. If non-nil, PREDICATE is used instead of `file-readable-p'. -PREDICATE can also be an integer to pass to the access(2) function, +PREDICATE can also be an integer to pass to the faccessat(2) function, in which case file-name-handlers are ignored. This function will normally skip directories, so if you want it to find directories, make sure the PREDICATE function returns `dir-ok' for them. */) @@ -1441,7 +1441,6 @@ int openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *storeptr, Lisp_Object predicate) { - int fd; ptrdiff_t fn_size = 100; char buf[100]; char *fn = buf; @@ -1496,7 +1495,6 @@ { ptrdiff_t fnlen, lsuffix = SBYTES (XCAR (tail)); Lisp_Object handler; - bool exists; /* Concatenate path element/specified name with the suffix. If the directory starts with /:, remove that. */ @@ -1520,6 +1518,7 @@ handler = Ffind_file_name_handler (string, Qfile_exists_p); if ((!NILP (handler) || !NILP (predicate)) && !NATNUMP (predicate)) { + bool exists; if (NILP (predicate)) exists = !NILP (Ffile_readable_p (string)); else @@ -1541,37 +1540,40 @@ } else { -#ifndef WINDOWSNT - struct stat st; -#endif + int fd; const char *pfn; encoded_fn = ENCODE_FILE (string); pfn = SSDATA (encoded_fn); -#ifdef WINDOWSNT - exists = access (pfn, F_OK) == 0 && access (pfn, D_OK) < 0; -#else - exists = (stat (pfn, &st) == 0 && ! S_ISDIR (st.st_mode)); -#endif - if (exists) + + /* Check that we can access or open it. */ + if (NATNUMP (predicate)) + fd = (((XFASTINT (predicate) & ~INT_MAX) == 0 + && (faccessat (AT_FDCWD, pfn, XFASTINT (predicate), + AT_EACCESS) + == 0) + && ! file_directory_p (pfn)) + ? 1 : -1); + else { - /* Check that we can access or open it. */ - if (NATNUMP (predicate)) - fd = (((XFASTINT (predicate) & ~INT_MAX) == 0 - && access (pfn, XFASTINT (predicate)) == 0) - ? 1 : -1); - else - fd = emacs_open (pfn, O_RDONLY, 0); - - if (fd >= 0) + struct stat st; + fd = emacs_open (pfn, O_RDONLY, 0); + if (0 <= fd + && (fstat (fd, &st) != 0 || S_ISDIR (st.st_mode))) { - /* We succeeded; return this descriptor and filename. */ - if (storeptr) - *storeptr = string; - UNGCPRO; - return fd; + emacs_close (fd); + fd = -1; } } + + if (fd >= 0) + { + /* We succeeded; return this descriptor and filename. */ + if (storeptr) + *storeptr = string; + UNGCPRO; + return fd; + } } } if (absolute) @@ -4087,9 +4089,8 @@ if (STRINGP (dirfile)) { dirfile = Fdirectory_file_name (dirfile); - if (access (SSDATA (dirfile), 0) < 0) - dir_warning ("Warning: Lisp directory `%s' does not exist.\n", - XCAR (path_tail)); + if (! file_accessible_directory_p (SSDATA (dirfile))) + dir_warning ("Lisp directory", XCAR (path_tail)); } } } @@ -4201,11 +4202,11 @@ Lisp_Object tem, tem1; /* Add to the path the lisp subdir of the installation - dir, if it exists. Note: in out-of-tree builds, + dir, if it is accessible. Note: in out-of-tree builds, this directory is empty save for Makefile. */ tem = Fexpand_file_name (build_string ("lisp"), Vinstallation_directory); - tem1 = Ffile_exists_p (tem); + tem1 = Ffile_accessible_directory_p (tem); if (!NILP (tem1)) { if (NILP (Fmember (tem, Vload_path))) @@ -4222,10 +4223,10 @@ Lisp dirs instead. */ Vload_path = nconc2 (Vload_path, dump_path); - /* Add leim under the installation dir, if it exists. */ + /* Add leim under the installation dir, if it is accessible. */ tem = Fexpand_file_name (build_string ("leim"), Vinstallation_directory); - tem1 = Ffile_exists_p (tem); + tem1 = Ffile_accessible_directory_p (tem); if (!NILP (tem1)) { if (NILP (Fmember (tem, Vload_path))) @@ -4237,7 +4238,7 @@ { tem = Fexpand_file_name (build_string ("site-lisp"), Vinstallation_directory); - tem1 = Ffile_exists_p (tem); + tem1 = Ffile_accessible_directory_p (tem); if (!NILP (tem1)) { if (NILP (Fmember (tem, Vload_path))) @@ -4282,7 +4283,7 @@ { tem = Fexpand_file_name (build_string ("site-lisp"), Vsource_directory); - tem1 = Ffile_exists_p (tem); + tem1 = Ffile_accessible_directory_p (tem); if (!NILP (tem1)) { if (NILP (Fmember (tem, Vload_path))) @@ -4338,21 +4339,28 @@ Vloads_in_progress = Qnil; } -/* Print a warning, using format string FORMAT, that directory DIRNAME - does not exist. Print it on stderr and put it in *Messages*. */ +/* Print a warning that directory intended for use USE and with name + DIRNAME cannot be accessed. On entry, errno should correspond to + the access failure. Print the warning on stderr and put it in + *Messages*. */ void -dir_warning (const char *format, Lisp_Object dirname) +dir_warning (char const *use, Lisp_Object dirname) { - fprintf (stderr, format, SDATA (dirname)); + static char const format[] = "Warning: %s `%s': %s\n"; + int access_errno = errno; + fprintf (stderr, format, use, SSDATA (dirname), strerror (access_errno)); /* Don't log the warning before we've initialized!! */ if (initialized) { + char const *diagnostic = emacs_strerror (access_errno); USE_SAFE_ALLOCA; - char *buffer = SAFE_ALLOCA (SBYTES (dirname) - + strlen (format) - (sizeof "%s" - 1) + 1); - ptrdiff_t message_len = esprintf (buffer, format, SDATA (dirname)); + char *buffer = SAFE_ALLOCA (sizeof format - 3 * (sizeof "%s" - 1) + + strlen (use) + SBYTES (dirname) + + strlen (diagnostic)); + ptrdiff_t message_len = esprintf (buffer, format, use, SSDATA (dirname), + diagnostic); message_dolog (buffer, message_len, 0, STRING_MULTIBYTE (dirname)); SAFE_FREE (); } === modified file 'src/nsterm.m' --- src/nsterm.m 2012-11-06 18:31:19 +0000 +++ src/nsterm.m 2012-11-14 04:55:41 +0000 @@ -4112,8 +4112,6 @@ color_file = Fexpand_file_name (build_string ("rgb.txt"), Fsymbol_value (intern ("data-directory"))); - if (NILP (Ffile_readable_p (color_file))) - fatal ("Could not find %s.\n", SDATA (color_file)); color_map = Fx_load_color_file (color_file); if (NILP (color_map)) === modified file 'src/process.c' --- src/process.c 2012-11-05 04:00:58 +0000 +++ src/process.c 2012-11-14 04:55:41 +0000 @@ -208,7 +208,7 @@ #ifndef NON_BLOCKING_CONNECT #ifdef HAVE_SELECT #if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX) -#if defined (O_NONBLOCK) || defined (O_NDELAY) +#if O_NONBLOCK || O_NDELAY #if defined (EWOULDBLOCK) || defined (EINPROGRESS) #define NON_BLOCKING_CONNECT #endif /* EWOULDBLOCK || EINPROGRESS */ @@ -655,7 +655,7 @@ PTY_OPEN; #else /* no PTY_OPEN */ { -# ifdef O_NONBLOCK +# if O_NONBLOCK fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0); # else fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0); @@ -672,7 +672,7 @@ #else sprintf (pty_name, "/dev/tty%c%x", c, i); #endif /* no PTY_TTY_NAME_SPRINTF */ - if (access (pty_name, 6) != 0) + if (faccessat (AT_FDCWD, pty_name, R_OK | W_OK, AT_EACCESS) != 0) { emacs_close (fd); # ifndef __sgi @@ -1624,7 +1624,7 @@ #if ! defined (USG) || defined (USG_SUBTTY_WORKS) /* On most USG systems it does not work to open the pty's tty here, then close it and reopen it in the child. */ -#ifdef O_NOCTTY +#if O_NOCTTY /* Don't let this terminal become our controlling terminal (in case we don't have one). */ forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); @@ -1678,11 +1678,11 @@ } #endif -#ifdef O_NONBLOCK +#if O_NONBLOCK fcntl (inchannel, F_SETFL, O_NONBLOCK); fcntl (outchannel, F_SETFL, O_NONBLOCK); #else -#ifdef O_NDELAY +#if O_NDELAY fcntl (inchannel, F_SETFL, O_NDELAY); fcntl (outchannel, F_SETFL, O_NDELAY); #endif @@ -1943,7 +1943,7 @@ #if ! defined (USG) || defined (USG_SUBTTY_WORKS) /* On most USG systems it does not work to open the pty's tty here, then close it and reopen it in the child. */ -#ifdef O_NOCTTY +#if O_NOCTTY /* Don't let this terminal become our controlling terminal (in case we don't have one). */ int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); @@ -1963,11 +1963,11 @@ } #endif /* HAVE_PTYS */ -#ifdef O_NONBLOCK +#if O_NONBLOCK fcntl (inchannel, F_SETFL, O_NONBLOCK); fcntl (outchannel, F_SETFL, O_NONBLOCK); #else -#ifdef O_NDELAY +#if O_NDELAY fcntl (inchannel, F_SETFL, O_NDELAY); fcntl (outchannel, F_SETFL, O_NDELAY); #endif @@ -2927,7 +2927,7 @@ { /* Don't support network sockets when non-blocking mode is not available, since a blocked Emacs is not useful. */ -#if !defined (O_NONBLOCK) && !defined (O_NDELAY) +#if !O_NONBLOCK && !O_NDELAY error ("Network servers not supported"); #else is_server = 1; @@ -3193,7 +3193,7 @@ #ifdef NON_BLOCKING_CONNECT if (is_non_blocking_client) { -#ifdef O_NONBLOCK +#if O_NONBLOCK ret = fcntl (s, F_SETFL, O_NONBLOCK); #else ret = fcntl (s, F_SETFL, O_NDELAY); @@ -3410,10 +3410,10 @@ chan_process[inch] = proc; -#ifdef O_NONBLOCK +#if O_NONBLOCK fcntl (inch, F_SETFL, O_NONBLOCK); #else -#ifdef O_NDELAY +#if O_NDELAY fcntl (inch, F_SETFL, O_NDELAY); #endif #endif @@ -4145,10 +4145,10 @@ chan_process[s] = proc; -#ifdef O_NONBLOCK +#if O_NONBLOCK fcntl (s, F_SETFL, O_NONBLOCK); #else -#ifdef O_NDELAY +#if O_NDELAY fcntl (s, F_SETFL, O_NDELAY); #endif #endif @@ -4849,11 +4849,11 @@ #endif /* ISC 4.1 defines both EWOULDBLOCK and O_NONBLOCK, and Emacs uses O_NONBLOCK, so what we get is EAGAIN. */ -#ifdef O_NONBLOCK +#if O_NONBLOCK else if (nread == -1 && errno == EAGAIN) ; #else -#ifdef O_NDELAY +#if O_NDELAY else if (nread == -1 && errno == EAGAIN) ; /* Note that we cannot distinguish between no input @@ -7348,7 +7348,7 @@ #ifdef HAVE_GETSOCKNAME ADD_SUBFEATURE (QCservice, Qt); #endif -#if defined (O_NONBLOCK) || defined (O_NDELAY) +#if O_NONBLOCK || O_NDELAY ADD_SUBFEATURE (QCserver, Qt); #endif === modified file 'src/sysdep.c' --- src/sysdep.c 2012-11-05 03:18:32 +0000 +++ src/sysdep.c 2012-11-14 04:55:41 +0000 @@ -1287,7 +1287,7 @@ old_fcntl_owner[fileno (tty_out->input)]); } #endif /* F_SETOWN */ -#ifdef O_NDELAY +#if O_NDELAY fcntl (fileno (tty_out->input), F_SETFL, fcntl (fileno (tty_out->input), F_GETFL, 0) & ~O_NDELAY); #endif @@ -2384,12 +2384,12 @@ fd = emacs_open ((char*) port, O_RDWR -#ifdef O_NONBLOCK +#if O_NONBLOCK | O_NONBLOCK #else | O_NDELAY #endif -#ifdef O_NOCTTY +#if O_NOCTTY | O_NOCTTY #endif , 0); === modified file 'src/term.c' --- src/term.c 2012-11-05 03:18:32 +0000 +++ src/term.c 2012-11-14 04:55:41 +0000 @@ -2992,7 +2992,7 @@ int fd; FILE *file; -#ifdef O_IGNORE_CTTY +#if O_IGNORE_CTTY if (!ctty) /* Open the terminal device. Don't recognize it as our controlling terminal, and don't make it the controlling tty @@ -3023,7 +3023,7 @@ name); } -#ifndef O_IGNORE_CTTY +#if !O_IGNORE_CTTY if (!ctty) dissociate_if_controlling_tty (fd); #endif === modified file 'src/w32.c' --- src/w32.c 2012-10-19 19:25:18 +0000 +++ src/w32.c 2012-11-14 04:55:41 +0000 @@ -1597,7 +1597,7 @@ see if it succeeds. But I think that's too much to ask. */ /* MSVCRT's _access crashes with D_OK. */ - if (tmp && sys_access (tmp, D_OK) == 0) + if (tmp && sys_faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0) { char * var = alloca (strlen (tmp) + 8); sprintf (var, "TMPDIR=%s", tmp); @@ -2714,10 +2714,16 @@ long file names. */ int -sys_access (const char * path, int mode) +sys_faccessat (int dirfd, const char * path, int mode, int flags) { DWORD attributes; + if (dirfd != AT_FDCWD) + { + errno = EBADF; + return -1; + } + /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its newer versions blow up when passed D_OK. */ path = map_w32_filename (path, NULL); @@ -2960,7 +2966,7 @@ { int save_errno = errno; p[0] = first_char[i]; - if (sys_access (template, 0) < 0) + if (sys_faccessat (AT_FDCWD, template, F_OK, AT_EACCESS) < 0) { errno = save_errno; return template; @@ -4011,7 +4017,7 @@ { /* Non-absolute FILENAME is understood as being relative to LINKNAME's directory. We need to prepend that directory to - FILENAME to get correct results from sys_access below, since + FILENAME to get correct results from sys_faccessat below, since otherwise it will interpret FILENAME relative to the directory where the Emacs process runs. Note that make-symbolic-link always makes sure LINKNAME is a fully @@ -4025,10 +4031,10 @@ strncpy (tem, linkfn, p - linkfn); tem[p - linkfn] = '\0'; strcat (tem, filename); - dir_access = sys_access (tem, D_OK); + dir_access = sys_faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS); } else - dir_access = sys_access (filename, D_OK); + dir_access = sys_faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS); /* Since Windows distinguishes between symlinks to directories and to files, we provide a kludgy feature: if FILENAME doesn't === modified file 'src/xrdb.c' --- src/xrdb.c 2012-10-19 19:25:18 +0000 +++ src/xrdb.c 2012-11-14 04:55:41 +0000 @@ -41,7 +41,6 @@ #ifdef HAVE_PWD_H #include #endif -#include #ifdef USE_MOTIF /* For Vdouble_click_time. */ @@ -50,7 +49,6 @@ char *x_get_string_resource (XrmDatabase rdb, const char *name, const char *class); -static int file_p (const char *filename); /* X file search path processing. */ @@ -108,7 +106,7 @@ database associated with display. (This is x_customization_string.) - Return the expanded file name if it exists and is readable, and + Return the resource database if its file was read successfully, and refers to %L only when the LANG environment variable is set, or otherwise provided by X. @@ -117,10 +115,11 @@ Return NULL otherwise. */ -static char * -magic_file_p (const char *string, ptrdiff_t string_len, const char *class, - const char *escaped_suffix) +static XrmDatabase +magic_db (const char *string, ptrdiff_t string_len, const char *class, + const char *escaped_suffix) { + XrmDatabase db; char *lang = getenv ("LANG"); ptrdiff_t path_size = 100; @@ -217,14 +216,9 @@ } path[path_len] = '\0'; - - if (! file_p (path)) - { - xfree (path); - return NULL; - } - - return path; + db = XrmGetFileDatabase (path); + xfree (path); + return db; } @@ -258,22 +252,11 @@ } -static int -file_p (const char *filename) -{ - struct stat status; - - return (access (filename, 4) == 0 /* exists and is readable */ - && stat (filename, &status) == 0 /* get the status */ - && (S_ISDIR (status.st_mode)) == 0); /* not a directory */ -} - - /* Find the first element of SEARCH_PATH which exists and is readable, after expanding the %-escapes. Return 0 if we didn't find any, and the path name of the one we found otherwise. */ -static char * +static XrmDatabase search_magic_path (const char *search_path, const char *class, const char *escaped_suffix) { @@ -286,18 +269,16 @@ if (p > s) { - char *path = magic_file_p (s, p - s, class, escaped_suffix); - if (path) - return path; + XrmDatabase db = magic_db (s, p - s, class, escaped_suffix); + if (db) + return db; } else if (*p == ':') { - char *path; - - s = "%N%S"; - path = magic_file_p (s, strlen (s), class, escaped_suffix); - if (path) - return path; + static char const ns[] = "%N%S"; + XrmDatabase db = magic_db (ns, strlen (ns), class, escaped_suffix); + if (db) + return db; } if (*p == ':') @@ -312,21 +293,12 @@ static XrmDatabase get_system_app (const char *class) { - XrmDatabase db = NULL; const char *path; - char *p; path = getenv ("XFILESEARCHPATH"); if (! path) path = PATH_X_DEFAULTS; - p = search_magic_path (path, class, 0); - if (p) - { - db = XrmGetFileDatabase (p); - xfree (p); - } - - return db; + return search_magic_path (path, class, 0); } @@ -340,35 +312,40 @@ static XrmDatabase get_user_app (const char *class) { + XrmDatabase db = 0; const char *path; - char *file = 0; - char *free_it = 0; /* Check for XUSERFILESEARCHPATH. It is a path of complete file names, not directories. */ - if (((path = getenv ("XUSERFILESEARCHPATH")) - && (file = search_magic_path (path, class, 0))) + path = getenv ("XUSERFILESEARCHPATH"); + if (path) + db = search_magic_path (path, class, 0); + if (! db) + { /* Check for APPLRESDIR; it is a path of directories. In each, we have to search for LANG/CLASS and then CLASS. */ - || ((path = getenv ("XAPPLRESDIR")) - && ((file = search_magic_path (path, class, "/%L/%N")) - || (file = search_magic_path (path, class, "/%N")))) + path = getenv ("XAPPLRESDIR"); + if (path) + { + db = search_magic_path (path, class, "/%L/%N"); + if (!db) + db = search_magic_path (path, class, "/%N"); + } + } + if (! db) + { /* Check in the home directory. This is a bit of a hack; let's hope one's home directory doesn't contain any %-escapes. */ - || (free_it = gethomedir (), - ((file = search_magic_path (free_it, class, "%L/%N")) - || (file = search_magic_path (free_it, class, "%N"))))) - { - XrmDatabase db = XrmGetFileDatabase (file); - xfree (file); - xfree (free_it); - return db; + char *home = gethomedir (); + db = search_magic_path (home, class, "%L/%N"); + if (! db) + db = search_magic_path (home, class, "%N"); + xfree (home); } - xfree (free_it); - return NULL; + return db; } ------------------------------------------------------------ revno: 110888 fixes bug: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=12879 committer: Stefan Monnier branch nick: trunk timestamp: Tue 2012-11-13 20:12:52 -0500 message: * lisp/emacs-lisp/gv.el (setf): Fix debug spec for multiple assignments. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-11-13 18:57:26 +0000 +++ lisp/ChangeLog 2012-11-14 01:12:52 +0000 @@ -1,3 +1,8 @@ +2012-11-14 Stefan Monnier + + * emacs-lisp/gv.el (setf): Fix debug spec for multiple assignments + (bug#12879). + 2012-11-13 Dmitry Gutov * progmodes/ruby-mode.el (ruby-move-to-block): Looks for a block === modified file 'lisp/emacs-lisp/gv.el' --- lisp/emacs-lisp/gv.el 2012-11-13 02:25:59 +0000 +++ lisp/emacs-lisp/gv.el 2012-11-14 01:12:52 +0000 @@ -236,7 +236,7 @@ The return value is the last VAL in the list. \(fn PLACE VAL PLACE VAL ...)" - (declare (debug (gv-place form))) + (declare (debug (&rest [gv-place form]))) (if (and args (null (cddr args))) (let ((place (pop args)) (val (car args))) ------------------------------------------------------------ revno: 110887 committer: Dmitry Gutov branch nick: trunk timestamp: Tue 2012-11-13 22:57:26 +0400 message: * lisp/progmodes/ruby-mode.el (ruby-move-to-block): Looks for a block start/end keyword a bit harder. Works with different values of N. Add more comments. (ruby-end-of-block): Update accordingly. * test/automated/ruby-mode-tests.el (ruby-heredoc-font-lock) (ruby-singleton-class-no-heredoc-font-lock) (ruby-add-log-current-method-examples): New tests. (ruby-test-string): Extract from ruby-should-indent-buffer. (ruby-deftest-move-to-block): New macro. Add several move-to-block tests. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-11-13 16:59:34 +0000 +++ lisp/ChangeLog 2012-11-13 18:57:26 +0000 @@ -1,3 +1,10 @@ +2012-11-13 Dmitry Gutov + + * progmodes/ruby-mode.el (ruby-move-to-block): Looks for a block + start/end keyword a bit harder. Works with different values of N. + Add more comments. + (ruby-end-of-block): Update accordingly. + 2012-11-13 Stefan Monnier * woman.el (woman-file-name): Don't mess with unread-command-events === modified file 'lisp/progmodes/ruby-mode.el' --- lisp/progmodes/ruby-mode.el 2012-11-13 09:30:16 +0000 +++ lisp/progmodes/ruby-mode.el 2012-11-13 18:57:26 +0000 @@ -865,39 +865,54 @@ (beginning-of-line))))) (defun ruby-move-to-block (n) - "Move to the beginning (N < 0) or the end (N > 0) of the current block -or blocks containing the current block." - ;; TODO: Make this work for n > 1, - ;; make it not loop for n = 0, - ;; document body + "Move to the beginning (N < 0) or the end (N > 0) of the +current block, a sibling block, or an outer block. Do that (abs N) times." (let ((orig (point)) (start (ruby-calculate-indent)) - (down (looking-at (if (< n 0) ruby-block-end-re - (concat "\\<\\(" ruby-block-beg-re "\\)\\>")))) - pos done) - (while (and (not done) (not (if (< n 0) (bobp) (eobp)))) - (forward-line n) - (cond - ((looking-at "^\\s *$")) - ((looking-at "^\\s *#")) - ((and (> n 0) (looking-at "^=begin\\>")) - (re-search-forward "^=end\\>")) - ((and (< n 0) (looking-at "^=end\\>")) - (re-search-backward "^=begin\\>")) - (t - (setq pos (current-indentation)) + (signum (if (> n 0) 1 -1)) + (backward (< n 0)) + down pos done) + (dotimes (_ (abs n)) + (setq done nil) + (setq down (save-excursion + (back-to-indentation) + ;; There is a block start or block end keyword on this + ;; line, don't need to look for another block. + (and (re-search-forward + (if backward ruby-block-end-re + (concat "\\_<\\(" ruby-block-beg-re "\\)\\_>")) + (line-end-position) t) + (not (nth 8 (syntax-ppss)))))) + (while (and (not done) (not (if backward (bobp) (eobp)))) + (forward-line signum) (cond - ((< start pos) - (setq down t)) - ((and down (= pos start)) - (setq done t)) - ((> start pos) - (setq done t))))) - (if done - (save-excursion - (back-to-indentation) - (if (looking-at (concat "\\<\\(" ruby-block-mid-re "\\)\\>")) - (setq done nil))))) + ;; Skip empty and commented out lines. + ((looking-at "^\\s *$")) + ((looking-at "^\\s *#")) + ;; Skip block comments; + ((and (not backward) (looking-at "^=begin\\>")) + (re-search-forward "^=end\\>")) + ((and backward (looking-at "^=end\\>")) + (re-search-backward "^=begin\\>")) + (t + (setq pos (current-indentation)) + (cond + ;; Deeper intendation, we found a block. + ;; FIXME: We can't recognize empty blocks this way. + ((< start pos) + (setq down t)) + ;; Block found, and same indentation as when started, stop. + ((and down (= pos start)) + (setq done t)) + ;; Shallower indentation, means outer block, can stop now. + ((> start pos) + (setq done t))))) + (if done + (save-excursion + (back-to-indentation) + ;; Not really at the first or last line of the block, move on. + (if (looking-at (concat "\\<\\(" ruby-block-mid-re "\\)\\>")) + (setq done nil)))))) (back-to-indentation))) (defun ruby-beginning-of-block (&optional arg) @@ -909,8 +924,7 @@ (defun ruby-end-of-block (&optional arg) "Move forward to the end of the current block. With ARG, move out of multiple blocks." - ;; Passing a value > 1 to ruby-move-to-block currently doesn't work. - (interactive) + (interactive "p") (ruby-move-to-block (or arg 1))) (defun ruby-forward-sexp (&optional arg) === modified file 'test/ChangeLog' --- test/ChangeLog 2012-11-13 09:30:16 +0000 +++ test/ChangeLog 2012-11-13 18:57:26 +0000 @@ -4,6 +4,8 @@ (ruby-singleton-class-no-heredoc-font-lock) (ruby-add-log-current-method-examples): New tests. (ruby-test-string): Extract from ruby-should-indent-buffer. + (ruby-deftest-move-to-block): New macro. + Add several move-to-block tests. 2012-11-12 Stefan Monnier === modified file 'test/automated/ruby-mode-tests.el' --- test/automated/ruby-mode-tests.el 2012-11-13 09:30:16 +0000 +++ test/automated/ruby-mode-tests.el 2012-11-13 18:57:26 +0000 @@ -283,6 +283,54 @@ (should (string= (ruby-add-log-current-method) (format "M::C%s" value))))))) +(defvar ruby-block-test-example + (ruby-test-string + "class C + | def foo + | 1 + | end + | + | def bar + | 2 + | end + | + | def baz + | some do + | end + | end + |end")) + +(defmacro ruby-deftest-move-to-block (name &rest body) + `(ert-deftest ,(intern (format "ruby-move-to-block-%s" name)) () + (with-temp-buffer + (insert ruby-block-test-example) + (ruby-mode) + ,@body))) + +(put 'ruby-deftest-move-to-block 'lisp-indent-function 'defun) + +(ruby-deftest-move-to-block works-on-do + (goto-line 11) + (ruby-end-of-block) + (should (= 12 (line-number-at-pos))) + (ruby-beginning-of-block) + (should (= 11 (line-number-at-pos)))) + +(ruby-deftest-move-to-block zero-is-noop + (goto-line 5) + (ruby-move-to-block 0) + (should (= 5 (line-number-at-pos)))) + +(ruby-deftest-move-to-block ok-with-three + (goto-line 2) + (ruby-move-to-block 3) + (should (= 13 (line-number-at-pos)))) + +(ruby-deftest-move-to-block ok-with-minus-two + (goto-line 10) + (ruby-move-to-block -2) + (should (= 2 (line-number-at-pos)))) + (provide 'ruby-mode-tests) ;;; ruby-mode-tests.el ends here ------------------------------------------------------------ revno: 110886 author: Tsuyoshi Kitamoto committer: Stefan Monnier branch nick: trunk timestamp: Tue 2012-11-13 13:09:20 -0500 message: * emacs-lisp/advice.el: Fix typos in comment. diff: === modified file 'lisp/emacs-lisp/nadvice.el' --- lisp/emacs-lisp/nadvice.el 2012-11-13 03:00:09 +0000 +++ lisp/emacs-lisp/nadvice.el 2012-11-13 18:09:20 +0000 @@ -30,7 +30,7 @@ ;; holds a function. ;; This part provides mainly 2 macros: `add-function' and `remove-function'. ;; -;; - The second part provides `add-advice' and `remove-advice' which are +;; - The second part provides `advice-add' and `advice-remove' which are ;; refined version of the previous macros specially tailored for the case ;; where the place that we want to modify is a `symbol-function'. @@ -234,7 +234,7 @@ (cond ((special-form-p def) ;; Not worth the trouble trying to handle this, I think. - (error "add-advice failure: %S is a special form" symbol)) + (error "advice-add failure: %S is a special form" symbol)) ((and (symbolp def) (eq 'macro (car-safe (ignore-errors (indirect-function def))))) (let ((newval (cons 'macro (cdr (indirect-function def))))) ------------------------------------------------------------ revno: 110885 fixes bug: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=12861 committer: Stefan Monnier branch nick: trunk timestamp: Tue 2012-11-13 11:59:34 -0500 message: * lisp/woman.el (woman-file-name): Don't mess with unread-command-events. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-11-13 14:12:46 +0000 +++ lisp/ChangeLog 2012-11-13 16:59:34 +0000 @@ -1,5 +1,8 @@ 2012-11-13 Stefan Monnier + * woman.el (woman-file-name): Don't mess with unread-command-events + (bug#12861). + * emacs-lisp/advice.el: Layer on top of nadvice.el. Remove out of date self-require hack. (ad-do-advised-functions): Use simple `dolist'. @@ -7,9 +10,9 @@ (ad-advice-definition): Redefine as functions. (ad-advice-classes): Move before first use. (ad-make-origname, ad-set-orig-definition, ad-clear-orig-definition) - (ad-make-mapped-call, ad-make-advised-docstring, ad-make-plain-docstring) + (ad-make-mapped-call, ad-make-advised-docstring,ad-make-plain-docstring) (ad--defalias-fset): Remove functions. - (ad-make-advicefunname, ad-clear-advicefunname-definition): New functions. + (ad-make-advicefunname, ad-clear-advicefunname-definition): New funs. (ad-get-orig-definition): Rewrite. (ad-make-advised-definition-docstring): Change base docstring. (ad-real-orig-definition): Rewrite. @@ -17,7 +20,7 @@ (ad--make-advised-docstring): Redirect `function' from ad-Advice-... (ad-make-advised-definition): Simplify. (ad-assemble-advised-definition): Tweak for new calling context. - (ad-activate-advised-definition): Setup ad-Advice-* instead of ad-Orig-*. + (ad-activate-advised-definition): Setup ad-Advice-* i.s.o ad-Orig-*. (ad--defalias-fset): Rename from ad-handle-definition. Make it set the function and call ad-activate if needed. (ad-activate, ad-deactivate): Don't call ad-handle-definition any more. === modified file 'lisp/woman.el' --- lisp/woman.el 2012-11-06 01:49:44 +0000 +++ lisp/woman.el 2012-11-13 16:59:34 +0000 @@ -1303,12 +1303,12 @@ ((null (cdr files)) (car (car files))) ; only 1 file for topic. (t ;; Multiple files for topic, so must select 1. - ;; Unread the command event (TAB = ?\t = 9) that runs the command - ;; `minibuffer-complete' in order to automatically complete the - ;; minibuffer contents as far as possible. - (setq unread-command-events '(9)) ; and delete any type-ahead! - (completing-read "Manual file: " files nil 1 - (try-completion "" files) 'woman-file-history)))))) + ;; Run the command `minibuffer-complete' in order to automatically + ;; complete the minibuffer contents as far as possible. + (minibuffer-with-setup-hook + (lambda () (let ((this-command this-command)) (minibuffer-complete))) + (completing-read "Manual file: " files nil 1 + (try-completion "" files) 'woman-file-history))))))) (defun woman-select (predicate list) "Select unique elements for which PREDICATE is true in LIST. ------------------------------------------------------------ revno: 110884 committer: Stefan Monnier branch nick: trunk timestamp: Tue 2012-11-13 09:12:46 -0500 message: * lisp/emacs-lisp/advice.el: Layer on top of nadvice.el. Remove out of date self-require hack. (ad-do-advised-functions): Use simple `dolist'. (ad-advice-name, ad-advice-protected, ad-advice-enabled) (ad-advice-definition): Redefine as functions. (ad-advice-classes): Move before first use. (ad-make-origname, ad-set-orig-definition, ad-clear-orig-definition) (ad-make-mapped-call, ad-make-advised-docstring, ad-make-plain-docstring) (ad--defalias-fset): Remove functions. (ad-make-advicefunname, ad-clear-advicefunname-definition): New functions. (ad-get-orig-definition): Rewrite. (ad-make-advised-definition-docstring): Change base docstring. (ad-real-orig-definition): Rewrite. (ad-map-arglists): Change name of called function. (ad--make-advised-docstring): Redirect `function' from ad-Advice-... (ad-make-advised-definition): Simplify. (ad-assemble-advised-definition): Tweak for new calling context. (ad-activate-advised-definition): Setup ad-Advice-* instead of ad-Orig-*. (ad--defalias-fset): Rename from ad-handle-definition. Make it set the function and call ad-activate if needed. (ad-activate, ad-deactivate): Don't call ad-handle-definition any more. (ad-recover): Clear ad-Advice-* instead of ad-Orig-*. (ad-compile-function): Compile ad-Advice-*. (ad-activate-on-top-level, ad-with-auto-activation-disabled): Remove. (ad-start-advice, ad-stop-advice): Remove. diff: === modified file 'etc/NEWS' --- etc/NEWS 2012-11-13 04:05:35 +0000 +++ etc/NEWS 2012-11-13 14:12:46 +0000 @@ -43,7 +43,8 @@ * Incompatible Lisp Changes in Emacs 24.4 -** `defadvice' does not honor the `freeze' flag any more. +** `defadvice' does not honor the `freeze' flag and cannot advise +special-forms any more. ** `dolist' in lexical-binding mode does not bind VAR in RESULT any more. VAR was bound to nil which was not tremendously useful and just lead to === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-11-13 09:30:16 +0000 +++ lisp/ChangeLog 2012-11-13 14:12:46 +0000 @@ -1,3 +1,31 @@ +2012-11-13 Stefan Monnier + + * emacs-lisp/advice.el: Layer on top of nadvice.el. + Remove out of date self-require hack. + (ad-do-advised-functions): Use simple `dolist'. + (ad-advice-name, ad-advice-protected, ad-advice-enabled) + (ad-advice-definition): Redefine as functions. + (ad-advice-classes): Move before first use. + (ad-make-origname, ad-set-orig-definition, ad-clear-orig-definition) + (ad-make-mapped-call, ad-make-advised-docstring, ad-make-plain-docstring) + (ad--defalias-fset): Remove functions. + (ad-make-advicefunname, ad-clear-advicefunname-definition): New functions. + (ad-get-orig-definition): Rewrite. + (ad-make-advised-definition-docstring): Change base docstring. + (ad-real-orig-definition): Rewrite. + (ad-map-arglists): Change name of called function. + (ad--make-advised-docstring): Redirect `function' from ad-Advice-... + (ad-make-advised-definition): Simplify. + (ad-assemble-advised-definition): Tweak for new calling context. + (ad-activate-advised-definition): Setup ad-Advice-* instead of ad-Orig-*. + (ad--defalias-fset): Rename from ad-handle-definition. Make it set the + function and call ad-activate if needed. + (ad-activate, ad-deactivate): Don't call ad-handle-definition any more. + (ad-recover): Clear ad-Advice-* instead of ad-Orig-*. + (ad-compile-function): Compile ad-Advice-*. + (ad-activate-on-top-level, ad-with-auto-activation-disabled): Remove. + (ad-start-advice, ad-stop-advice): Remove. + 2012-11-13 Dmitry Gutov * progmodes/ruby-mode.el (ruby-add-log-current-method): Print the === modified file 'lisp/emacs-lisp/advice.el' --- lisp/emacs-lisp/advice.el 2012-11-13 04:05:35 +0000 +++ lisp/emacs-lisp/advice.el 2012-11-13 14:12:46 +0000 @@ -47,14 +47,12 @@ ;; @ Highlights: ;; ============= ;; - Clean definition of multiple, named before/around/after advices -;; for functions, macros, subrs and special forms +;; for functions and macros. ;; - Full control over the arguments an advised function will receive, ;; the binding environment in which it will be executed, as well as the ;; value it will return. -;; - Allows re/definition of interactive behavior for functions and subrs -;; - Every piece of advice can have its documentation string which will be -;; combined with the original documentation of the advised function at -;; call-time of `documentation' for proper command-key substitution. +;; - Allows re/definition of interactive behavior for commands. +;; - Every piece of advice can have its documentation string. ;; - The execution of every piece of advice can be protected against error ;; and non-local exits in preceding code or advices. ;; - Simple argument access either by name, or, more portable but as @@ -63,7 +61,7 @@ ;; version of a function. ;; - Advised functions can be byte-compiled either at file-compile time ;; (see preactivation) or activation time. -;; - Separation of advice definition and activation +;; - Separation of advice definition and activation. ;; - Forward advice is possible, that is ;; as yet undefined or autoload functions can be advised without having to ;; preload the file in which they are defined. @@ -77,7 +75,7 @@ ;; - En/disablement mechanism allows the use of different "views" of advised ;; functions depending on what pieces of advice are currently en/disabled ;; - Provides manipulation mechanisms for sets of advised functions via -;; regular expressions that match advice names +;; regular expressions that match advice names. ;; @ Overview, or how to read this file: ;; ===================================== @@ -113,23 +111,12 @@ ;; others come from the various Lisp advice mechanisms I've come across ;; so far, and a few are simply mine. -;; @ Comments, suggestions, bug reports: -;; ===================================== -;; If you find any bugs, have suggestions for new advice features, find the -;; documentation wrong, confusing, incomplete, or otherwise unsatisfactory, -;; have any questions about Advice, or have otherwise enlightening -;; comments feel free to send me email at . - ;; @ Safety Rules and Emergency Exits: ;; =================================== ;; Before we begin: CAUTION!! ;; Advice provides you with a lot of rope to hang yourself on very ;; easily accessible trees, so, here are a few important things you -;; should know: Once Advice has been started with `ad-start-advice' -;; (which happens automatically when you load this file), it -;; generates an advised definition of the `documentation' function, and -;; it will enable automatic advice activation when functions get defined. -;; All of this can be undone at any time with `M-x ad-stop-advice'. +;; should know: ;; ;; If you experience any strange behavior/errors etc. that you attribute to ;; Advice or to some ill-advised function do one of the following: @@ -137,45 +124,37 @@ ;; - M-x ad-deactivate FUNCTION (if you have a definite suspicion what ;; function gives you problems) ;; - M-x ad-deactivate-all (if you don't have a clue what's going wrong) -;; - M-x ad-stop-advice (if you think the problem is related to the -;; advised functions used by Advice itself) ;; - M-x ad-recover-normality (for real emergencies) ;; - If none of the above solves your Advice-related problem go to another ;; terminal, kill your Emacs process and send me some hate mail. -;; The first three measures have restarts, i.e., once you've figured out +;; The first two measures have restarts, i.e., once you've figured out ;; the problem you can reactivate advised functions with either `ad-activate', -;; `ad-activate-all', or `ad-start-advice'. `ad-recover-normality' unadvises +;; or `ad-activate-all'. `ad-recover-normality' unadvises ;; everything so you won't be able to reactivate any advised functions, you'll ;; have to stick with their standard incarnations for the rest of the session. -;; IMPORTANT: With Advice loaded always do `M-x ad-deactivate-all' before -;; you byte-compile a file, because advised special forms and macros can lead -;; to unwanted compilation results. When you are done compiling use -;; `M-x ad-activate-all' to go back to the advised state of all your -;; advised functions. - ;; RELAX: Advice is pretty safe even if you are oblivious to the above. ;; I use it extensively and haven't run into any serious trouble in a long -;; time. Just wanted you to be warned. +;; time. Just wanted you to be warned. ;; @ Customization: ;; ================ ;; Look at the documentation of `ad-redefinition-action' for possible values -;; of this variable. Its default value is `warn' which will print a warning +;; of this variable. Its default value is `warn' which will print a warning ;; message when an already defined advised function gets redefined with a ;; new original definition and de/activated. ;; Look at the documentation of `ad-default-compilation-action' for possible -;; values of this variable. Its default value is `maybe' which will compile +;; values of this variable. Its default value is `maybe' which will compile ;; advised definitions during activation in case the byte-compiler is already -;; loaded. Otherwise, it will leave them uncompiled. +;; loaded. Otherwise, it will leave them uncompiled. ;; @ Motivation: ;; ============= ;; Before I go on explaining how advice works, here are four simple examples -;; how this package can be used. The first three are very useful, the last one +;; how this package can be used. The first three are very useful, the last one ;; is just a joke: ;;(defadvice switch-to-buffer (before existing-buffers-only activate) @@ -206,13 +185,12 @@ ;; @ Advice documentation: ;; ======================= -;; Below is general documentation of the various features of advice. For more +;; Below is general documentation of the various features of advice. For more ;; concrete examples check the corresponding sections in the tutorial part. ;; @@ Terminology: ;; =============== ;; - Emacs: Emacs as released by the GNU Project -;; - jwz: Jamie Zawinski - creator of the byte-compiler used in v19s. ;; - Advice: The name of this package. ;; - advices: Short for "pieces of advice". @@ -236,22 +214,22 @@ ;; is the name of the advice which has to be a non-nil symbol. ;; Names uniquely identify a piece of advice in a certain advice class, ;; hence, advices can be redefined by defining an advice with the same class -;; and name. Advice names are global symbols, hence, the same name space +;; and name. Advice names are global symbols, hence, the same name space ;; conventions used for function names should be applied. ;; An optional specifies where in the current list of advices of -;; the specified this new advice will be placed. has to +;; the specified this new advice will be placed. has to ;; be either `first', `last' or a number that specifies a zero-based -;; position (`first' is equivalent to 0). If no position is specified -;; `first' will be used as a default. If this call to `defadvice' redefines +;; position (`first' is equivalent to 0). If no position is specified +;; `first' will be used as a default. If this call to `defadvice' redefines ;; an already existing advice (see above) then the position argument will ;; be ignored and the position of the already existing advice will be used. ;; An optional which has to be a list can be used to define the -;; argument list of the advised function. This argument list should of +;; argument list of the advised function. This argument list should of ;; course be compatible with the argument list of the original function, ;; otherwise functions that call the advised function with the original -;; argument list in mind will break. If more than one advice specify an +;; argument list in mind will break. If more than one advice specify an ;; argument list then the first one (the one with the smallest position) ;; found in the list of before/around/after advices will be used. @@ -267,10 +245,10 @@ ;; `disable': Specifies that the defined advice should be disabled, hence, ;; it will not be used in an activation until somebody enables it. ;; `preactivate': Specifies that the advised function should get preactivated -;; at macro-expansion/compile time of this `defadvice'. This +;; at macro-expansion/compile time of this `defadvice'. This ;; generates a compiled advised definition according to the ;; current advice state which will be used during activation -;; if appropriate. Only use this if the `defadvice' gets +;; if appropriate. Only use this if the `defadvice' gets ;; actually compiled. ;; An optional can be supplied to document the advice. @@ -278,20 +256,20 @@ ;; documentation strings of the original function and other advices. ;; An optional form can be supplied to change/add -;; interactive behavior of the original function. If more than one advice +;; interactive behavior of the original function. If more than one advice ;; has an `(interactive ...)' specification then the first one (the one ;; with the smallest position) found in the list of before/around/after ;; advices will be used. ;; A possibly empty list of specifies the body of the advice in -;; an implicit progn. The body of an advice can access/change arguments, +;; an implicit progn. The body of an advice can access/change arguments, ;; the return value, the binding environment, and can have all sorts of ;; other side effects. ;; @@ Assembling advised definitions: ;; ================================== ;; Suppose a function/macro/subr/special-form has N pieces of before advice, -;; M pieces of around advice and K pieces of after advice. Assuming none of +;; M pieces of around advice and K pieces of after advice. Assuming none of ;; the advices is protected, its advised definition will look like this ;; (body-form indices correspond to the position of the respective advice in ;; that advice class): @@ -330,11 +308,11 @@ ;; be expanded into a proper documentation string upon call of `documentation'. ;; (interactive ...) is an optional interactive form either taken from the -;; original function or from a before/around/after advice. For advised +;; original function or from a before/around/after advice. For advised ;; interactive subrs that do not have an interactive form specified in any ;; advice we have to use (interactive) and then call the subr interactively ;; if the advised function was called interactively, because the -;; interactive specification of subrs is not accessible. This is the only +;; interactive specification of subrs is not accessible. This is the only ;; case where changing the values of arguments will not have an affect ;; because they will be reset by the interactive specification of the subr. ;; If this is a problem one can always specify an interactive form in a @@ -343,45 +321,44 @@ ;; ;; Then the body forms of the various advices in the various classes of advice ;; are assembled in order. The forms of around advice L are normally part of -;; one of the forms of around advice L-1. An around advice can specify where +;; one of the forms of around advice L-1. An around advice can specify where ;; the forms of the wrapped or surrounded forms should go with the special -;; keyword `ad-do-it', which will be substituted with a `progn' containing the -;; forms of the surrounded code. +;; keyword `ad-do-it', which will run the forms of the surrounded code. ;; The innermost part of the around advice onion is ;; > -;; whose form depends on the type of the original function. The variable -;; `ad-return-value' will be set to its result. This variable is visible to +;; whose form depends on the type of the original function. The variable +;; `ad-return-value' will be set to its result. This variable is visible to ;; all pieces of advice which can access and modify it before it gets returned. ;; ;; The semantic structure of advised functions that contain protected pieces -;; of advice is the same. The only difference is that `unwind-protect' forms +;; of advice is the same. The only difference is that `unwind-protect' forms ;; make sure that the protected advice gets executed even if some previous -;; piece of advice had an error or a non-local exit. If any around advice is +;; piece of advice had an error or a non-local exit. If any around advice is ;; protected then the whole around advice onion will be protected. ;; @@ Argument access in advised functions: ;; ======================================== ;; As already mentioned, the simplest way to access the arguments of an -;; advised function in the body of an advice is to refer to them by name. To -;; do that, the advice programmer needs to know either the names of the +;; advised function in the body of an advice is to refer to them by name. +;; To do that, the advice programmer needs to know either the names of the ;; argument variables of the original function, or the names used in the -;; argument list redefinition given in a piece of advice. While this simple +;; argument list redefinition given in a piece of advice. While this simple ;; method might be sufficient in many cases, it has the disadvantage that it ;; is not very portable because it hardcodes the argument names into the ;; advice. If the definition of the original function changes the advice -;; might break even though the code might still be correct. Situations like +;; might break even though the code might still be correct. Situations like ;; that arise, for example, if one advises a subr like `eval-region' which ;; gets redefined in a non-advice style into a function by the edebug -;; package. If the advice assumes `eval-region' to be a subr it might break -;; once edebug is loaded. Similar situations arise when one wants to use the +;; package. If the advice assumes `eval-region' to be a subr it might break +;; once edebug is loaded. Similar situations arise when one wants to use the ;; same piece of advice across different versions of Emacs. ;; As a solution to that advice provides argument list access macros that get ;; translated into the proper access forms at activation time, i.e., when the -;; advised definition gets constructed. Access macros access actual arguments +;; advised definition gets constructed. Access macros access actual arguments ;; by position regardless of how these actual argument get distributed onto -;; the argument variables of a function. The rational behind this is that in +;; the argument variables of a function. The rational behind this is that in ;; Emacs Lisp the semantics of an argument is strictly determined by its ;; position (there are no keyword arguments). @@ -393,9 +370,9 @@ ;; ;; (foo 0 1 2 3 4 5 6) -;; which means that X=0, Y=1, Z=2 and R=(3 4 5 6). The assumption is that -;; the semantics of an actual argument is determined by its position. It is -;; this semantics that has to be known by the advice programmer. Then s/he +;; which means that X=0, Y=1, Z=2 and R=(3 4 5 6). The assumption is that +;; the semantics of an actual argument is determined by its position. It is +;; this semantics that has to be known by the advice programmer. Then s/he ;; can access these arguments in a piece of advice with some of the ;; following macros (the arrows indicate what value they will return): @@ -408,17 +385,17 @@ ;; `(ad-get-arg )' will return the actual argument that was supplied ;; at , `(ad-get-args )' will return the list of actual -;; arguments supplied starting at . Note that these macros can be +;; arguments supplied starting at . Note that these macros can be ;; used without any knowledge about the form of the actual argument list of ;; the original function. ;; Similarly, `(ad-set-arg )' can be used to set the -;; value of the actual argument at to . For example, +;; value of the actual argument at to . For example, ;; ;; (ad-set-arg 5 "five") ;; ;; will have the effect that R=(3 4 "five" 6) once the original function is -;; called. `(ad-set-args )' can be used to set +;; called. `(ad-set-args )' can be used to set ;; the list of actual arguments starting at to . ;; For example, ;; @@ -427,7 +404,7 @@ ;; will have the effect that X=5, Y=4, Z=3 and R=(2 1 0) once the original ;; function is called. -;; All these access macros are text macros rather than real Lisp macros. When +;; All these access macros are text macros rather than real Lisp macros. When ;; the advised definition gets constructed they get replaced with actual access ;; forms depending on the argument list of the advised function, i.e., after ;; that argument access is in most cases as efficient as using the argument @@ -437,7 +414,7 @@ ;; ======================================================= ;; Some functions (such as `trace-function' defined in trace.el) need a ;; method of accessing the names and bindings of the arguments of an -;; arbitrary advised function. To do that within an advice one can use the +;; arbitrary advised function. To do that within an advice one can use the ;; special keyword `ad-arg-bindings' which is a text macro that will be ;; substituted with a form that will evaluate to a list of binding ;; specifications, one for every argument variable. These binding @@ -463,7 +440,7 @@ ;; ========================== ;; Because `defadvice' allows the specification of the argument list ;; of the advised function we need a mapping mechanism that maps this -;; argument list onto that of the original function. Hence SYM and +;; argument list onto that of the original function. Hence SYM and ;; NEWDEF have to be properly mapped onto the &rest variable when the ;; original definition is called. Advice automatically takes care of ;; that mapping, hence, the advice programmer can specify an argument @@ -474,11 +451,10 @@ ;; @@ Activation and deactivation: ;; =============================== ;; The definition of an advised function does not change until all its advice -;; gets actually activated. Activation can either happen with the `activate' +;; gets actually activated. Activation can either happen with the `activate' ;; flag specified in the `defadvice', with an explicit call or interactive -;; invocation of `ad-activate', or if forward advice is enabled (i.e., the -;; value of `ad-activate-on-definition' is t) at the time an already advised -;; function gets defined. +;; invocation of `ad-activate', or at the time an already advised function +;; gets defined. ;; When a function gets first activated its original definition gets saved, ;; all defined and enabled pieces of advice will get combined with the @@ -496,7 +472,7 @@ ;; the file that contained the `defadvice' with the `preactivate' flag. ;; `ad-deactivate' can be used to back-define an advised function to its -;; original definition. It can be called interactively or directly. Because +;; original definition. It can be called interactively or directly. Because ;; `ad-activate' caches the advised definition the function can be ;; reactivated via `ad-activate' with only minor overhead (it is checked ;; whether the current advice state is consistent with the cached @@ -504,12 +480,12 @@ ;; `ad-activate-regexp' and `ad-deactivate-regexp' can be used to de/activate ;; all currently advised function that have a piece of advice with a name that -;; contains a match for a regular expression. These functions can be used to +;; contains a match for a regular expression. These functions can be used to ;; de/activate sets of functions depending on certain advice naming ;; conventions. ;; Finally, `ad-activate-all' and `ad-deactivate-all' can be used to -;; de/activate all currently advised functions. These are useful to +;; de/activate all currently advised functions. These are useful to ;; (temporarily) return to an un/advised state. ;; @@@ Reasons for the separation of advice definition and activation: @@ -521,26 +497,26 @@ ;; The advantage of this is that various pieces of advice can be defined ;; before they get combined into an advised definition which avoids -;; unnecessary constructions of intermediate advised definitions. The more +;; unnecessary constructions of intermediate advised definitions. The more ;; important advantage is that it allows the implementation of forward advice. ;; Advice information for a certain function accumulates as the value of the -;; `advice-info' property of the function symbol. This accumulation is +;; `advice-info' property of the function symbol. This accumulation is ;; completely independent of the fact that that function might not yet be -;; defined. The special forms `defun' and `defmacro' have been advised to -;; check whether the function/macro they defined had advice information -;; associated with it. If so and forward advice is enabled, the original +;; defined. The macros `defun' and `defmacro' check whether the +;; function/macro they defined had advice information +;; associated with it. If so and forward advice is enabled, the original ;; definition will be saved, and then the advice will be activated. ;; @@ Enabling/disabling pieces or sets of advice: ;; =============================================== ;; A major motivation for the development of this advice package was to bring ;; a little bit more structure into the function overloading chaos in Emacs -;; Lisp. Many packages achieve some of their functionality by adding a little +;; Lisp. Many packages achieve some of their functionality by adding a little ;; bit (or a lot) to the standard functionality of some Emacs Lisp function. -;; ange-ftp is a very popular package that achieves its magic by overloading -;; most Emacs Lisp functions that deal with files. A popular function that's -;; overloaded by many packages is `expand-file-name'. The situation that one -;; function is multiply overloaded can arise easily. +;; ange-ftp is a very popular package that used to achieve its magic by +;; overloading most Emacs Lisp functions that deal with files. A popular +;; function that's overloaded by many packages is `expand-file-name'. +;; The situation that one function is multiply overloaded can arise easily. ;; Once in a while it would be desirable to be able to disable some/all ;; overloads of a particular package while keeping all the rest. Ideally - @@ -548,7 +524,7 @@ ;; I know I am dreaming right now... In that ideal case the enable/disable ;; mechanism of advice could be used to achieve just that. -;; Every piece of advice is associated with an enablement flag. When the +;; Every piece of advice is associated with an enablement flag. When the ;; advised definition of a particular function gets constructed (e.g., during ;; activation) only the currently enabled pieces of advice will be considered. ;; This mechanism allows one to have different "views" of an advised function @@ -556,17 +532,15 @@ ;; Another motivation for this mechanism is that it allows one to define a ;; piece of advice for some function yet keep it dormant until a certain -;; condition is met. Until then activation of the function will not make use -;; of that piece of advice. Once the condition is met the advice can be +;; condition is met. Until then activation of the function will not make use +;; of that piece of advice. Once the condition is met the advice can be ;; enabled and a reactivation of the function will add its functionality as -;; part of the new advised definition. For example, the advices of `defun' -;; etc. used by advice itself will stay disabled until `ad-start-advice' is -;; called and some variables have the proper values. Hence, if somebody +;; part of the new advised definition. Hence, if somebody ;; else advised these functions too and activates them the advices defined ;; by advice will get used only if they are intended to be used. ;; The main interface to this mechanism are the interactive functions -;; `ad-enable-advice' and `ad-disable-advice'. For example, the following +;; `ad-enable-advice' and `ad-disable-advice'. For example, the following ;; would disable a particular advice of the function `foo': ;; ;; (ad-disable-advice 'foo 'before 'my-advice) @@ -576,28 +550,28 @@ ;; ;; (ad-activate 'foo) ;; -;; or interactively. To disable whole sets of advices one can use a regular -;; expression mechanism. For example, let us assume that ange-ftp actually +;; or interactively. To disable whole sets of advices one can use a regular +;; expression mechanism. For example, let us assume that ange-ftp actually ;; used advice to overload all its functions, and that it used the ;; "ange-ftp-" prefix for all its advice names, then we could temporarily ;; disable all its advices with ;; -;; (ad-disable-regexp "^ange-ftp-") +;; (ad-disable-regexp "\\`ange-ftp-") ;; ;; and the following call would put that actually into effect: ;; -;; (ad-activate-regexp "^ange-ftp-") +;; (ad-activate-regexp "\\`ange-ftp-") ;; ;; A safer way would have been to use ;; -;; (ad-update-regexp "^ange-ftp-") +;; (ad-update-regexp "\\`ange-ftp-") ;; ;; instead which would have only reactivated currently actively advised -;; functions, but not functions that were currently inactive. All these +;; functions, but not functions that were currently inactive. All these ;; functions can also be called interactively. ;; A certain piece of advice is considered a match if its name contains a -;; match for the regular expression. To enable ange-ftp again we would use +;; match for the regular expression. To enable ange-ftp again we would use ;; `ad-enable-regexp' and then activate or update again. ;; @@ Forward advice, automatic advice activation: @@ -616,7 +590,7 @@ ;; of advice definition and activation that makes it possible to accumulate ;; advice information without having the original function already defined, ;; 2) special versions of the built-in functions `fset/defalias' which check -;; for advice information whenever they define a function. If advice +;; for advice information whenever they define a function. If advice ;; information was found then the advice will immediately get activated when ;; the function gets defined. @@ -625,16 +599,11 @@ ;; file, and the function has some advice-info stored with it then that ;; advice will get activated right away. -;; @@@ Enabling automatic advice activation: -;; ========================================= -;; Automatic advice activation is enabled by default. It can be disabled with -;; `M-x ad-stop-advice' and enabled again with `M-x ad-start-advice'. - ;; @@ Caching of advised definitions: ;; ================================== ;; After an advised definition got constructed it gets cached as part of the ;; advised function's advice-info so it can be reused, for example, after an -;; intermediate deactivation. Because the advice-info of a function might +;; intermediate deactivation. Because the advice-info of a function might ;; change between the time of caching and reuse a cached definition gets ;; a cache-id associated with it so it can be verified whether the cached ;; definition is still valid (the main application of this is preactivation @@ -642,19 +611,19 @@ ;; When an advised function gets activated and a verifiable cached definition ;; is available, then that definition will be used instead of creating a new -;; advised definition from scratch. If you want to make sure that a new +;; advised definition from scratch. If you want to make sure that a new ;; definition gets constructed then you should use `ad-clear-cache' before you ;; activate the advised function. ;; @@ Preactivation: ;; ================= -;; Constructing an advised definition is moderately expensive. In a situation +;; Constructing an advised definition is moderately expensive. In a situation ;; where one package defines a lot of advised functions it might be ;; prohibitively expensive to do all the advised definition construction at -;; runtime. Preactivation is a mechanism that allows compile-time construction +;; runtime. Preactivation is a mechanism that allows compile-time construction ;; of compiled advised definitions that can be activated cheaply during -;; runtime. Preactivation uses the caching mechanism to do that. Here's how it -;; works: +;; runtime. Preactivation uses the caching mechanism to do that. Here's how +;; it works: ;; When the byte-compiler compiles a `defadvice' that has the `preactivate' ;; flag specified, it uses the current original definition of the advised @@ -665,27 +634,27 @@ ;; byte-compiler. ;; When the file with the compiled, preactivating `defadvice' gets loaded the ;; precompiled advised definition will be cached on the advised function's -;; advice-info. When it gets activated (can be immediately on execution of the +;; advice-info. When it gets activated (can be immediately on execution of the ;; `defadvice' or any time later) the cache-id gets checked against the ;; current state of advice and if it is verified the precompiled definition -;; will be used directly (the verification is pretty cheap). If it couldn't get -;; verified a new advised definition for that function will be built from -;; scratch, hence, the efficiency added by the preactivation mechanism does -;; not at all impair the flexibility of the advice mechanism. +;; will be used directly (the verification is pretty cheap). If it couldn't +;; get verified a new advised definition for that function will be built from +;; scratch, hence, the efficiency added by the preactivation mechanism does not +;; at all impair the flexibility of the advice mechanism. ;; MORAL: In order get all the efficiency out of preactivation the advice ;; state of an advised function at the time the file with the ;; preactivating `defadvice' gets byte-compiled should be exactly ;; the same as it will be when the advice of that function gets -;; actually activated. If it is not there is a high chance that the +;; actually activated. If it is not there is a high chance that the ;; cache-id will not match and hence a new advised definition will ;; have to be constructed at runtime. -;; Preactivation and forward advice do not contradict each other. It is +;; Preactivation and forward advice do not contradict each other. It is ;; perfectly ok to load a file with a preactivating `defadvice' before the -;; original definition of the advised function is available. The constructed +;; original definition of the advised function is available. The constructed ;; advised definition will be used once the original function gets defined and -;; its advice gets activated. The only constraint is that at the time the +;; its advice gets activated. The only constraint is that at the time the ;; file with the preactivating `defadvice' got compiled the original function ;; definition was available. @@ -697,18 +666,18 @@ ;; - `byte-compile' is part of the `features' variable even though you ;; did not use the byte-compiler ;; Right now advice does not provide an elegant way to find out whether -;; and why a preactivation failed. What you can do is to trace the +;; and why a preactivation failed. What you can do is to trace the ;; function `ad-cache-id-verification-code' (with the function ;; `trace-function-background' defined in my trace.el package) before -;; any of your advised functions get activated. After they got +;; any of your advised functions get activated. After they got ;; activated check whether all calls to `ad-cache-id-verification-code' -;; returned `verified' as a result. Other values indicate why the +;; returned `verified' as a result. Other values indicate why the ;; verification failed which should give you enough information to ;; fix your preactivation/compile/load/activation sequence. ;; IMPORTANT: There is one case (that I am aware of) that can make ;; preactivation fail, i.e., a preconstructed advised definition that does -;; NOT match the current state of advice gets used nevertheless. That case +;; NOT match the current state of advice gets used nevertheless. That case ;; arises if one package defines a certain piece of advice which gets used ;; during preactivation, and another package incompatibly redefines that ;; very advice (i.e., same function/class/name), and it is the second advice @@ -720,30 +689,20 @@ ;; MORAL-II: Redefining somebody else's advice is BAAAAD (to speak with ;; George Walker Bush), and why would you redefine your own advice anyway? ;; Advice is a mechanism to facilitate function redefinition, not advice -;; redefinition (wait until I write Meta-Advice :-). If you really have -;; to undo somebody else's advice try to write a "neutralizing" advice. +;; redefinition (wait until I write Meta-Advice :-). If you really have +;; to undo somebody else's advice, try to write a "neutralizing" advice. -;; @@ Advising macros and special forms and other dangerous things: -;; ================================================================ +;; @@ Advising macros and other dangerous things: +;; ============================================== ;; Look at the corresponding tutorial sections for more information on -;; these topics. Here it suffices to point out that the special treatment -;; of macros and special forms by the byte-compiler can lead to problems -;; when they get advised. Macros can create problems because they get -;; expanded at compile time, hence, they might not have all the necessary -;; runtime support and such advice cannot be de/activated or changed as -;; it is possible for functions. Special forms create problems because they -;; have to be advised "into" macros, i.e., an advised special form is a -;; implemented as a macro, hence, in most cases the byte-compiler will -;; not recognize it as a special form anymore which can lead to very strange -;; results. +;; these topics. Here it suffices to point out that the special treatment +;; of macros can lead to problems when they get advised. Macros can create +;; problems because they get expanded at compile or load time, hence, they +;; might not have all the necessary runtime support and such advice cannot be +;; de/activated or changed as it is possible for functions. +;; Special forms cannot be advised. ;; -;; MORAL: - Only advise macros or special forms when you are absolutely sure -;; what you are doing. -;; - As a safety measure, always do `ad-deactivate-all' before you -;; byte-compile a file to make sure that even if some inconsiderate -;; person advised some special forms you'll get proper compilation -;; results. After compilation do `ad-activate-all' to get back to -;; the previous state. +;; MORAL: - Only advise macros when you are absolutely sure what you are doing. ;; @@ Adding a piece of advice with `ad-add-advice': ;; ================================================= @@ -754,10 +713,10 @@ ;; @@ Activation/deactivation advices, file load hooks: ;; ==================================================== ;; There are two special classes of advice called `activation' and -;; `deactivation'. The body forms of these advices are not included into the +;; `deactivation'. The body forms of these advices are not included into the ;; advised definition of a function, rather they are assembled into a hook ;; form which will be evaluated whenever the advice-info of the advised -;; function gets activated or deactivated. One application of this mechanism +;; function gets activated or deactivated. One application of this mechanism ;; is to define file load hooks for files that do not provide such hooks. ;; For example, suppose you want to print a message whenever `file-x' gets ;; loaded, and suppose the last function defined in `file-x' is @@ -769,7 +728,7 @@ ;; ;; This will constitute a forward advice for function `file-x-last-fn' which ;; will get activated when `file-x' is loaded (only if forward advice is -;; enabled of course). Because there are no "real" pieces of advice +;; enabled of course). Because there are no "real" pieces of advice ;; available for it, its definition will not be changed, but the activation ;; advice will be run during its activation which is equivalent to having a ;; file load hook for `file-x'. @@ -784,14 +743,14 @@ ;; enabled advices are considered during construction of an advised ;; definition. ;; - Activation: -;; Redefine an advised function with its advised definition. Constructs +;; Redefine an advised function with its advised definition. Constructs ;; an advised definition from scratch if no verifiable cached advised ;; definition is available and caches it. ;; - Deactivation: ;; Back-define an advised function to its original definition. ;; - Update: ;; Reactivate an advised function but only if its advice is currently -;; active. This can be used to bring all currently advised function up +;; active. This can be used to bring all currently advised function up ;; to date with the current state of advice without also activating ;; currently inactive functions. ;; - Caching: @@ -800,7 +759,7 @@ ;; - Preactivation: ;; Is the construction of an advised definition according to the current ;; state of advice during byte-compilation of a file with a preactivating -;; `defadvice'. That advised definition can then rather cheaply be used +;; `defadvice'. That advised definition can then rather cheaply be used ;; during activation without having to construct an advised definition ;; from scratch at runtime. @@ -860,12 +819,8 @@ ;; @ Foo games: An advice tutorial ;; =============================== -;; The following tutorial was created in Emacs 18.59. Left-justified +;; The following tutorial was created in Emacs 18.59. Left-justified ;; s-expressions are input forms followed by one or more result forms. -;; First we have to start the advice magic: -;; -;; (ad-start-advice) -;; nil ;; ;; We start by defining an innocent looking function `foo' that simply ;; adds 1 to its argument X: @@ -988,19 +943,6 @@ ;; (call-interactively 'foo) ;; 6 ;; -;; Let's have a look at what the definition of `foo' looks like now -;; (indentation added by hand for legibility): -;; -;; (symbol-function 'foo) -;; (lambda (x) -;; "$ad-doc: foo$" -;; (interactive (list 5)) -;; (let (ad-return-value) -;; (setq x (1- x)) -;; (setq x (1+ x)) -;; (setq ad-return-value (ad-Orig-foo x)) -;; ad-return-value)) -;; ;; @@ Around advices: ;; ================== ;; Now we'll try some `around' advices. An around advice is a wrapper around @@ -1038,20 +980,6 @@ ;; (foo 3) ;; 8 ;; -;; Again, let's see what the definition of `foo' looks like so far: -;; -;; (symbol-function 'foo) -;; (lambda (x) -;; "$ad-doc: foo$" -;; (interactive (list 5)) -;; (let (ad-return-value) -;; (setq x (1- x)) -;; (setq x (1+ x)) -;; (let ((x (* x 2))) -;; (let ((x (1+ x))) -;; (setq ad-return-value (ad-Orig-foo x)))) -;; ad-return-value)) -;; ;; @@ Controlling advice activation: ;; ================================= ;; In every `defadvice' so far we have used the flag `activate' to activate @@ -1071,9 +999,9 @@ ;; 8 ;; ;; Now we define another advice and activate which will also activate the -;; previous advice `fg-times-x'. Note the use of the special variable +;; previous advice `fg-times-x'. Note the use of the special variable ;; `ad-return-value' in the body of the advice which is set to the result of -;; the original function. If we change its value then the value returned by +;; the original function. If we change its value then the value returned by ;; the advised function will be changed accordingly: ;; ;; (defadvice foo (after fg-times-x-again act) @@ -1121,24 +1049,6 @@ ;; "Let's clean up now!" ;; error-in-foo ;; -;; Again, let's see what `foo' looks like: -;; -;; (symbol-function 'foo) -;; (lambda (x) -;; "$ad-doc: foo$" -;; (interactive (list 5)) -;; (let (ad-return-value) -;; (unwind-protect -;; (progn (setq x (1- x)) -;; (setq x (1+ x)) -;; (let ((x (* x 2))) -;; (let ((x (1+ x))) -;; (setq ad-return-value (ad-Orig-foo x)))) -;; (setq ad-return-value (* ad-return-value x)) -;; (setq ad-return-value (* ad-return-value x))) -;; (print "Let's clean up now!")) -;; ad-return-value)) -;; ;; @@ Compilation of advised definitions: ;; ====================================== ;; Finally, we can specify the `compile' keyword in a `defadvice' to say @@ -1150,13 +1060,10 @@ ;; (print "Let's clean up now!")) ;; foo ;; -;; Now `foo' is byte-compiled: +;; Now `foo's advice is byte-compiled: ;; -;; (symbol-function 'foo) -;; (lambda (x) -;; "$ad-doc: foo$" -;; (interactive (byte-code "....." [5] 1)) -;; (byte-code "....." [ad-return-value x nil ((byte-code "....." [print "Let's clean up now!"] 2)) * 2 ad-Orig-foo] 6)) +;; (byte-code-function-p 'ad-Advice-foo) +;; t ;; ;; (foo 3) ;; "Let's clean up now!" @@ -1262,7 +1169,7 @@ ;; deactivate functions that have a piece of advice defined by a certain ;; package (we save the old definition to check out caching): ;; -;; (setq old-definition (symbol-function 'foo)) +;; (setq old-definition (symbol-function 'ad-Advice-foo)) ;; (lambda (x) ....) ;; ;; (ad-deactivate-regexp "^fg-") @@ -1274,7 +1181,7 @@ ;; (ad-activate-regexp "^fg-") ;; nil ;; -;; (eq old-definition (symbol-function 'foo)) +;; (eq old-definition (symbol-function 'ad-Advice-foo)) ;; t ;; ;; (foo 3) @@ -1283,14 +1190,6 @@ ;; ;; @@ Forward advice: ;; ================== -;; To enable automatic activation of forward advice we first have to set -;; `ad-activate-on-definition' to t and restart advice: -;; -;; (setq ad-activate-on-definition t) -;; t -;; -;; (ad-start-advice) -;; (ad-activate-defined-function) ;; ;; Let's define a piece of advice for an undefined function: ;; @@ -1303,9 +1202,7 @@ ;; (fboundp 'bar) ;; nil ;; -;; Now we define it and the forward advice will get activated (only because -;; `ad-activate-on-definition' was t when we started advice above with -;; `ad-start-advice'): +;; Now we define it and the forward advice will get activated: ;; ;; (defun bar (x) ;; "Subtract 1 from X." @@ -1357,7 +1254,7 @@ ;; (ad-activate 'fie) ;; fie ;; -;; (eq cached-definition (symbol-function 'fie)) +;; (eq cached-definition (symbol-function 'ad-Advice-fie)) ;; t ;; ;; (fie 2) @@ -1365,7 +1262,7 @@ ;; ;; If you put a preactivating `defadvice' into a Lisp file that gets byte- ;; compiled then the constructed advised definition will get compiled by -;; the byte-compiler. For that to occur in a v18 Emacs you had to put the +;; the byte-compiler. For that to occur in a v18 Emacs you had to put the ;; `defadvice' inside a `defun' because the v18 compiler did not compile ;; top-level forms other than `defun' or `defmacro', for example, ;; @@ -1407,18 +1304,16 @@ ;; constructed during preactivation was used, even though we did not specify ;; the `compile' flag: ;; -;; (symbol-function 'fum) -;; (lambda (x) -;; "$ad-doc: fum$" -;; (byte-code "....." [ad-return-value x nil * 2 ad-Orig-fum] 4)) +;; (byte-code-function-p 'ad-Advice-fum) +;; t ;; ;; (fum 2) ;; 8 ;; ;; A preactivated definition will only be used if it matches the current -;; function definition and advice information. If it does not match it +;; function definition and advice information. If it does not match it ;; will simply be discarded and a new advised definition will be constructed -;; from scratch. For example, let's first remove all advice-info for `fum': +;; from scratch. For example, let's first remove all advice-info for `fum': ;; ;; (ad-unadvise 'fum) ;; (("fie") ("bar") ("foo") ...) @@ -1431,7 +1326,7 @@ ;; fum ;; ;; When we now try to use a preactivation it will not be used because the -;; current advice state is different from the one at preactivation time. This +;; current advice state is different from the one at preactivation time. This ;; is no tragedy, everything will work as expected just not as efficient, ;; because a new advised definition has to be constructed from scratch: ;; @@ -1440,7 +1335,7 @@ ;; ;; A new uncompiled advised definition got constructed: ;; -;; (ad-compiled-p (symbol-function 'fum)) +;; (byte-code-function-p 'ad-Advice-fum) ;; nil ;; ;; (fum 2) @@ -1448,7 +1343,7 @@ ;; ;; MORAL: To get all the efficiency out of preactivation the function ;; definition and advice state at preactivation time must be the same as the -;; state at activation time. Preactivation does work with forward advice, all +;; state at activation time. Preactivation does work with forward advice, all ;; that's necessary is that the definition of the forward advised function is ;; available when the `defadvice' with the preactivation gets compiled. ;; @@ -1702,15 +1597,9 @@ ;; @@ Compilation idiosyncrasies: ;; ============================== -;; `defadvice' expansion needs quite a few advice functions and variables, -;; hence, I need to preload the file before it can be compiled. To avoid -;; interference of bogus compiled files I always preload the source file: -(provide 'advice-preload) -;; During a normal load this is a noop: -(require 'advice-preload "advice.el") (require 'macroexp) ;; At run-time also, since ad-do-advised-functions returns code that uses it. -(require 'cl-lib) +(eval-when-compile (require 'cl-lib)) ;; @@ Variable definitions: ;; ======================== @@ -1789,7 +1678,7 @@ ;; (after adv1 adv2 ...) ;; (activation adv1 adv2 ...) ;; (deactivation adv1 adv2 ...) -;; (origname . ) +;; (advicefunname . ) ;; (cache . ( . ))) ;; List of currently advised though not necessarily activated functions @@ -1816,7 +1705,7 @@ On each iteration VAR will be bound to the name of an advised function \(a symbol)." (declare (indent 1)) - `(cl-dolist (,(car varform) ad-advised-functions) + `(dolist (,(car varform) ad-advised-functions) (setq ,(car varform) (intern (car ,(car varform)))) ,@body)) @@ -1882,18 +1771,17 @@ ;; ad-find-advice uses the alist structure directly -> ;; change if this data structure changes!! -(defmacro ad-advice-name (advice) - (list 'car advice)) -(defmacro ad-advice-protected (advice) - (list 'nth 1 advice)) -(defmacro ad-advice-enabled (advice) - (list 'nth 2 advice)) -(defmacro ad-advice-definition (advice) - (list 'nth 3 advice)) +(defsubst ad-advice-name (advice) (car advice)) +(defsubst ad-advice-protected (advice) (nth 1 advice)) +(defsubst ad-advice-enabled (advice) (nth 2 advice)) +(defsubst ad-advice-definition (advice) (nth 3 advice)) (defun ad-advice-set-enabled (advice flag) (rplaca (cdr (cdr advice)) flag)) +(defvar ad-advice-classes '(before around after activation deactivation) + "List of defined advice classes.") + (defun ad-class-p (thing) (memq thing ad-advice-classes)) (defun ad-name-p (thing) @@ -1906,9 +1794,6 @@ ;; @@ Advice access functions: ;; =========================== -;; List of defined advice classes: -(defvar ad-advice-classes '(before around after activation deactivation)) - (defun ad-has-enabled-advice (function class) "True if at least one of FUNCTION's advices in CLASS is enabled." (cl-dolist (advice (ad-get-advice-info-field function class)) @@ -1948,58 +1833,23 @@ ;; Whether advised definitions created by automatic activations will be ;; compiled depends on the value of `ad-default-compilation-action'. -;; Since calling `ad-activate-internal' in the built-in definition of `fset' can -;; create major disasters we have to be a bit careful. One precaution is -;; to provide a dummy definition for `ad-activate-internal' which can be used to -;; turn off automatic advice activation (e.g., when `ad-stop-advice' or -;; `ad-recover-normality' are called). Another is to avoid recursive calls -;; to `ad-activate' by using `ad-with-auto-activation-disabled' where -;; appropriate, especially in a safe version of `fset'. - -(defun ad--defalias-fset (fsetfun function definition) - (funcall (or fsetfun #'fset) function definition) - (ad-activate-internal function nil)) - -;; For now define `ad-activate-internal' to the dummy definition: -(defun ad-activate-internal (_function &optional _compile) - "Automatic advice activation is disabled. `ad-start-advice' enables it." - nil) - -;; This is just a copy of the above: -(defun ad-activate-internal-off (_function &optional _compile) - "Automatic advice activation is disabled. `ad-start-advice' enables it." - nil) - -;; This will be t for top-level calls to `ad-activate-internal-on': -(defvar ad-activate-on-top-level t) - -(defmacro ad-with-auto-activation-disabled (&rest body) - `(let ((ad-activate-on-top-level nil)) - ,@body)) - -;; @@ Access functions for original definitions: -;; ============================================ -;; The advice-info of an advised function contains its `origname' which is -;; a symbol that is fbound to the original definition available at the first -;; proper activation of the function after a valid re/definition. If the -;; original was defined via fcell indirection then `origname' will be defined -;; just so. Hence, to get hold of the actual original definition of a function -;; we need to use `ad-real-orig-definition'. - -(defun ad-make-origname (function) - "Make name to be used to call the original FUNCTION." - (intern (format "ad-Orig-%s" function))) - -(defmacro ad-get-orig-definition (function) - `(let ((origname (ad-get-advice-info-field ,function 'origname))) - (if (fboundp origname) - (symbol-function origname)))) - -(defmacro ad-set-orig-definition (function definition) - `(fset (ad-get-advice-info-field ,function 'origname) ,definition)) - -(defmacro ad-clear-orig-definition (function) - `(fmakunbound (ad-get-advice-info-field ,function 'origname))) +(defalias 'ad-activate-internal 'ad-activate) + +(defun ad-make-advicefunname (function) + "Make name to be used to call the assembled advice function." + (intern (format "ad-Advice-%s" function))) + +(defun ad-get-orig-definition (function) ;FIXME: Rename to "-unadvised-". + (if (symbolp function) + (setq function (if (fboundp function) + (advice--strip-macro (symbol-function function))))) + (while (advice--p function) (setq function (advice--cdr function))) + function) + +(defun ad-clear-advicefunname-definition (function) + (let ((advicefunname (ad-get-advice-info-field function 'advicefunname))) + (advice-remove function advicefunname) + (fmakunbound advicefunname))) ;; @@ Interactive input functions: @@ -2259,7 +2109,7 @@ (cond ((not (ad-is-advised function)) (ad-initialize-advice-info function) (ad-set-advice-info-field - function 'origname (ad-make-origname function)))) + function 'advicefunname (ad-make-advicefunname function)))) (let* ((previous-position (ad-advice-position function class (ad-advice-name advice))) (advices (ad-get-advice-info-field function class)) @@ -2374,7 +2224,8 @@ to generate a proper advised docstring even if we are just given a definition (see the code for `documentation')." (eval-when-compile - (propertize "Advice doc string" 'dynamic-docstring-function + (propertize "Advice function assembled by advice.el." + 'dynamic-docstring-function #'ad--make-advised-docstring))) (defun ad-advised-definition-p (definition) @@ -2417,9 +2268,9 @@ definition)))) (defun ad-real-orig-definition (function) - "Find FUNCTION's real original definition starting from its `origname'." - (if (ad-is-advised function) - (ad-real-definition (ad-get-advice-info-field function 'origname)))) + (let* ((fun1 (ad-get-orig-definition function)) + (fun2 (indirect-function fun1))) + (unless (autoloadp fun2) fun2))) (defun ad-is-compilable (function) "True if FUNCTION has an interpreted definition that can be compiled." @@ -2430,24 +2281,15 @@ (defvar warning-suppress-types) ;From warnings.el. (defun ad-compile-function (function) - "Byte-compiles FUNCTION (or macro) if it is not yet compiled." - (interactive "aByte-compile function: ") - (if (ad-is-compilable function) - ;; Need to turn off auto-activation - ;; because `byte-compile' uses `fset': - (ad-with-auto-activation-disabled - (require 'bytecomp) - (require 'warnings) ;To define warning-suppress-types - ;before we let-bind it. - (let ((symbol (make-symbol "advice-compilation")) - (byte-compile-warnings byte-compile-warnings) - ;; Don't pop up windows showing byte-compiler warnings. - (warning-suppress-types '((bytecomp)))) - (if (featurep 'cl) - (byte-compile-disable-warning 'cl-functions)) - (fset symbol (symbol-function function)) - (byte-compile symbol) - (fset function (symbol-function symbol)))))) + "Byte-compile the assembled advice function." + (require 'bytecomp) + (require 'warnings) ;To define warning-suppress-types before we let-bind it. + (let ((byte-compile-warnings byte-compile-warnings) + ;; Don't pop up windows showing byte-compiler warnings. + (warning-suppress-types '((bytecomp)))) + (if (featurep 'cl) + (byte-compile-disable-warning 'cl-functions)) + (byte-compile (ad-get-advice-info-field function 'advicefunname)))) ;; @@@ Accessing argument lists: ;; ============================= @@ -2634,7 +2476,7 @@ supplied as nil. Returns a `funcall' or `apply' form with the second element being `function' which has to be replaced by an actual function argument. Example: `(ad-map-arglists '(a &rest args) '(w x y z))' will return - `(funcall function a (car args) (car (cdr args)) (nth 2 args))'." + `(funcall ad--addoit-function a (car args) (car (cdr args)) (nth 2 args))'." (let* ((parsed-source-arglist (ad-parse-arglist source-arglist)) (source-reqopt-args (append (nth 0 parsed-source-arglist) (nth 1 parsed-source-arglist))) @@ -2648,7 +2490,7 @@ ;; This produces ``error-proof'' target function calls with the exception ;; of a case like (&rest a) mapped onto (x &rest y) where the actual args ;; supplied to A might not be enough to supply the required target arg X - (append (list (if need-apply 'apply 'funcall) 'function) + (append (list (if need-apply 'apply 'funcall) 'ad--addoit-function) (cond (need-apply ;; `apply' can take care of that directly: (append source-reqopt-args (list source-rest-arg))) @@ -2663,13 +2505,6 @@ (nthcdr (length target-reqopt-args) source-reqopt-args))))))))) -(defun ad-make-mapped-call (source-arglist target-arglist target-function) - "Make form to call TARGET-FUNCTION with args from SOURCE-ARGLIST." - (let ((mapped-form (ad-map-arglists source-arglist target-arglist))) - (if (eq (car mapped-form) 'funcall) - (cons target-function (cdr (cdr mapped-form))) - (prog1 mapped-form - (setcar (cdr mapped-form) (list 'quote target-function)))))) ;; @@@ Making an advised documentation string: ;; =========================================== @@ -2697,13 +2532,6 @@ (require 'help-fns) ;For help-split-fundoc and help-add-fundoc-usage. -(defun ad-make-advised-docstring (function &optional style) - (let* ((origdef (ad-real-orig-definition function)) - (origdoc - ;; Retrieve raw doc, key substitution will be taken care of later: - (documentation origdef t))) - (ad--make-advised-docstring origdoc function style))) - (defun ad--make-advised-docstring (origdoc function &optional style) "Construct a documentation string for the advised FUNCTION. It concatenates the original documentation with the documentation @@ -2712,14 +2540,14 @@ will be interpreted as `default'. The order of the advice documentation strings corresponds to before/around/after and the individual ordering in any of these classes." - (let* ((origdef (ad-real-orig-definition function)) - (origtype (symbol-name (ad-definition-type origdef))) - (usage (help-split-fundoc origdoc function)) + (if (and (symbolp function) + (string-match "\\`ad-+Advice-" (symbol-name function))) + (setq function + (intern (substring (symbol-name function) (match-end 0))))) + (let* ((usage (help-split-fundoc origdoc function)) paragraphs advice-docstring) (setq usage (if (null usage) t (setq origdoc (cdr usage)) (car usage))) (if origdoc (setq paragraphs (list origdoc))) - (unless (eq style 'plain) - (push (concat "This " origtype " is advised.") paragraphs)) (dolist (class ad-advice-classes) (dolist (advice (ad-get-enabled-advices function class)) (setq advice-docstring @@ -2735,8 +2563,6 @@ #'ad--make-advised-docstring))) (help-add-fundoc-usage origdoc usage))) -(defun ad-make-plain-docstring (function) - (ad-make-advised-docstring function 'plain)) ;; @@@ Accessing overriding arglists and interactive forms: ;; ======================================================== @@ -2770,64 +2596,16 @@ (if (and (ad-is-advised function) (ad-has-redefining-advice function)) (let* ((origdef (ad-real-orig-definition function)) - (origname (ad-get-advice-info-field function 'origname)) - (orig-interactive-p (commandp origdef)) - (orig-subr-p (ad-subr-p origdef)) - (orig-special-form-p (special-form-p origdef)) - (orig-macro-p (ad-macro-p origdef)) ;; Construct the individual pieces that we need for assembly: (orig-arglist (ad-arglist origdef)) (advised-arglist (or (ad-advised-arglist function) orig-arglist)) - (advised-interactive-form (ad-advised-interactive-form function)) - (interactive-form - (cond (orig-macro-p nil) - (advised-interactive-form) - ((interactive-form origdef) - (interactive-form - (if (and (symbolp function) (get function 'elp-info)) - (aref (get function 'elp-info) 2) - origdef))))) + (interactive-form (ad-advised-interactive-form function)) (orig-form - (cond ((or orig-special-form-p orig-macro-p) - ;; Special forms and macros will be advised into macros. - ;; The trick is to construct an expansion for the advised - ;; macro that does the correct thing when it gets eval'ed. - ;; For macros we'll just use the expansion of the original - ;; macro and return that. This way compiled advised macros - ;; will be expanded into something useful. Note that after - ;; advices have full control over whether they want to - ;; evaluate the expansion (the value of `ad-return-value') - ;; at macro expansion time or not. For special forms there - ;; is no solution that interacts reasonably with the - ;; compiler, hence we just evaluate the original at macro - ;; expansion time and return the result. The moral of that - ;; is that one should always deactivate advised special - ;; forms before one byte-compiles a file. - `(,(if orig-macro-p 'macroexpand 'eval) - (cons ',origname - ,(ad-get-arguments advised-arglist 0)))) - ((and orig-subr-p - orig-interactive-p - (not interactive-form) - (not advised-interactive-form)) - ;; Check whether we were called interactively - ;; in order to do proper prompting: - `(if (called-interactively-p 'any) - (call-interactively ',origname) - ,(ad-make-mapped-call advised-arglist - orig-arglist - origname))) - ;; And now for normal functions and non-interactive subrs - ;; (or subrs whose interactive behavior was advised): - (t (ad-make-mapped-call - advised-arglist orig-arglist origname))))) + (ad-map-arglists advised-arglist orig-arglist))) ;; Finally, build the sucker: (ad-assemble-advised-definition - (cond (orig-macro-p 'macro) - (orig-special-form-p 'special-form) - (t 'function)) advised-arglist (ad-make-advised-definition-docstring function) interactive-form @@ -2837,13 +2615,11 @@ (ad-get-enabled-advices function 'after))))) (defun ad-assemble-advised-definition - (type args docstring interactive orig &optional befores arounds afters) - - "Assembles an original and its advices into an advised function. -It constructs a function or macro definition according to TYPE which has to -be either `macro', `function' or `special-form'. ARGS is the argument list -that has to be used, DOCSTRING if non-nil defines the documentation of the -definition, INTERACTIVE if non-nil is the interactive form to be used, + (args docstring interactive orig &optional befores arounds afters) + "Assemble the advices into an overall advice function. +ARGS is the argument list that has to be used, +DOCSTRING if non-nil defines the documentation of the definition, +INTERACTIVE if non-nil is the interactive form to be used, ORIG is a form that calls the body of the original unadvised function, and BEFORES, AROUNDS and AFTERS are the lists of advices with which ORIG should be modified. The assembled function will be returned." @@ -2894,16 +2670,12 @@ (ad-body-forms (ad-advice-definition advice))))))) (setq definition - `(,@(if (memq type '(macro special-form)) '(macro)) - lambda - ,args + `(lambda (ad--addoit-function ,@args) ,@(if docstring (list docstring)) ,@(if interactive (list interactive)) (let (ad-return-value) ,@after-forms - ,(if (eq type 'special-form) - '(list 'quote ad-return-value) - 'ad-return-value)))) + ad-return-value))) (ad-insert-argument-access-forms definition args))) @@ -3000,11 +2772,11 @@ "Generate an identifying image of the current advices of FUNCTION." (let ((original-definition (ad-real-orig-definition function)) (cached-definition (ad-get-cache-definition function))) - (list (mapcar (function (lambda (advice) (ad-advice-name advice))) + (list (mapcar #'ad-advice-name (ad-get-enabled-advices function 'before)) - (mapcar (function (lambda (advice) (ad-advice-name advice))) + (mapcar #'ad-advice-name (ad-get-enabled-advices function 'around)) - (mapcar (function (lambda (advice) (ad-advice-name advice))) + (mapcar #'ad-advice-name (ad-get-enabled-advices function 'after)) (ad-definition-type original-definition) (if (equal (ad-arglist original-definition) @@ -3147,25 +2919,32 @@ The current definition and its cache-id will be put into the cache." (let ((verified-cached-definition (if (ad-verify-cache-id function) - (ad-get-cache-definition function)))) - (fset function - (or verified-cached-definition - (ad-make-advised-definition function))) + (ad-get-cache-definition function))) + (advicefunname (ad-get-advice-info-field function 'advicefunname))) + (fset advicefunname + (or verified-cached-definition + (ad-make-advised-definition function))) + (advice-add function :around advicefunname) (if (ad-should-compile function compile) - (ad-compile-function function)) + (byte-compile advicefunname)) (if verified-cached-definition - (if (not (eq verified-cached-definition (symbol-function function))) + (if (not (eq verified-cached-definition + (symbol-function advicefunname))) ;; we must have compiled, cache the compiled definition: - (ad-set-cache - function (symbol-function function) (ad-get-cache-id function))) + (ad-set-cache function (symbol-function advicefunname) + (ad-get-cache-id function))) ;; We created a new advised definition, cache it with a proper id: (ad-clear-cache function) ;; ad-make-cache-id needs the new cached definition: - (ad-set-cache function (symbol-function function) nil) + (ad-set-cache function (symbol-function advicefunname) nil) (ad-set-cache - function (symbol-function function) (ad-make-cache-id function))))) + function (symbol-function advicefunname) (ad-make-cache-id function))))) -(defun ad-handle-definition (function) +(defun ad--defalias-fset (fsetfun function newdef) + ;; Besides ad-redefinition-action we use this defalias-fset-function hook + ;; for two other reasons: + ;; - for `activation/deactivation' advices. + ;; - to rebuild the ad-Advice-* function with the right argument names. "Handle re/definition of an advised FUNCTION during de/activation. If FUNCTION does not have an original definition associated with it and the current definition is usable, then it will be stored as FUNCTION's @@ -3177,33 +2956,27 @@ de/activated. If you do not like the current redefinition action change the value of `ad-redefinition-action' and de/activate again." (let ((original-definition (ad-get-orig-definition function)) - (current-definition (if (ad-real-definition function) - (symbol-function function)))) + (current-definition (ad-get-orig-definition newdef))) (if original-definition (if current-definition - (if (and (not (eq current-definition original-definition)) - ;; Redefinition with an advised definition from a - ;; different function won't count as such: - (not (ad-advised-definition-p current-definition))) - ;; we have a redefinition: + (if (not (eq current-definition original-definition)) + ;; We have a redefinition: (if (not (memq ad-redefinition-action '(accept discard warn))) - (error "ad-handle-definition (see its doc): `%s' %s" + (error "ad-redefinition-action: `%s' %s" function "invalidly redefined") (if (eq ad-redefinition-action 'discard) - (fset function original-definition) - (ad-set-orig-definition function current-definition) + nil ;; Just drop it! + (funcall (or fsetfun #'fset) function newdef) + (ad-activate-internal function) (if (eq ad-redefinition-action 'warn) (message "ad-handle-definition: `%s' got redefined" function)))) ;; either advised def or correct original is in place: nil) - ;; we have an undefinition, ignore it: - nil) - (if current-definition - ;; we have a first definition, save it as original: - (ad-set-orig-definition function current-definition) - ;; we don't have anything noteworthy: - nil)))) + ;; We have an undefinition, ignore it: + (funcall (or fsetfun #'fset) function newdef)) + (funcall (or fsetfun #'fset) function newdef) + (when current-definition (ad-activate-internal function))))) ;; @@ The top-level advice interface: @@ -3229,24 +3002,20 @@ (interactive (list (ad-read-advised-function "Activate advice of") current-prefix-arg)) - (if ad-activate-on-top-level - ;; avoid recursive calls to `ad-activate': - (ad-with-auto-activation-disabled - (if (not (ad-is-advised function)) - (error "ad-activate: `%s' is not advised" function) - (ad-handle-definition function) - ;; Just return for forward advised and not yet defined functions: - (if (ad-get-orig-definition function) - (if (not (ad-has-any-advice function)) - (ad-unadvise function) - ;; Otherwise activate the advice: - (cond ((ad-has-redefining-advice function) - (ad-activate-advised-definition function compile) - (ad-set-advice-info-field function 'active t) - (eval (ad-make-hook-form function 'activation)) - function) - ;; Here we are if we have all disabled advices: - (t (ad-deactivate function))))))))) + (if (not (ad-is-advised function)) + (error "ad-activate: `%s' is not advised" function) + ;; Just return for forward advised and not yet defined functions: + (if (ad-get-orig-definition function) + (if (not (ad-has-any-advice function)) + (ad-unadvise function) + ;; Otherwise activate the advice: + (cond ((ad-has-redefining-advice function) + (ad-activate-advised-definition function compile) + (ad-set-advice-info-field function 'active t) + (eval (ad-make-hook-form function 'activation)) + function) + ;; Here we are if we have all disabled advices: + (t (ad-deactivate function))))))) (defalias 'ad-activate-on 'ad-activate) @@ -3261,11 +3030,10 @@ (if (not (ad-is-advised function)) (error "ad-deactivate: `%s' is not advised" function) (cond ((ad-is-active function) - (ad-handle-definition function) (if (not (ad-get-orig-definition function)) (error "ad-deactivate: `%s' has no original definition" function) - (fset function (ad-get-orig-definition function)) + (ad-clear-advicefunname-definition function) (ad-set-advice-info-field function 'active nil) (eval (ad-make-hook-form function 'deactivation)) function))))) @@ -3287,7 +3055,7 @@ (cond ((ad-is-advised function) (if (ad-is-active function) (ad-deactivate function)) - (ad-clear-orig-definition function) + (ad-clear-advicefunname-definition function) (ad-set-advice-info function nil) (ad-pop-advised-function function)))) @@ -3302,9 +3070,7 @@ (list (intern (completing-read "Recover advised function: " obarray nil t)))) (cond ((ad-is-advised function) - (cond ((ad-get-orig-definition function) - (fset function (ad-get-orig-definition function)) - (ad-clear-orig-definition function))) + (ad-clear-advicefunname-definition function) (ad-set-advice-info function nil) (ad-pop-advised-function function)))) @@ -3544,35 +3310,15 @@ ;; @@ Starting, stopping and recovering from the advice package magic: ;; =================================================================== -(defun ad-start-advice () - "Start the automatic advice handling magic." - (interactive) - ;; Advising `ad-activate-internal' means death!! - (ad-set-advice-info 'ad-activate-internal nil) - (fset 'ad-activate-internal 'ad-activate)) - -(defun ad-stop-advice () - "Stop the automatic advice handling magic. -You should only need this in case of Advice-related emergencies." - (interactive) - ;; Advising `ad-activate-internal' means death!! - (ad-set-advice-info 'ad-activate-internal nil) - (fset 'ad-activate-internal 'ad-activate-internal-off)) - (defun ad-recover-normality () "Undo all advice related redefinitions and unadvises everything. Use only in REAL emergencies." (interactive) - ;; Advising `ad-activate-internal' means death!! - (ad-set-advice-info 'ad-activate-internal nil) - (fset 'ad-activate-internal 'ad-activate-internal-off) (ad-recover-all) (ad-do-advised-functions (function) (message "Oops! Left over advised function %S" function) (ad-pop-advised-function function))) -(ad-start-advice) - (provide 'advice) ;;; advice.el ends here === modified file 'test/automated/advice-tests.el' --- test/automated/advice-tests.el 2012-11-13 03:00:09 +0000 +++ test/automated/advice-tests.el 2012-11-13 14:12:46 +0000 @@ -57,6 +57,29 @@ (defmacro sm-test3 (x) `(call-test3 ,x)) (macroexpand '(sm-test3 56)) (toto (call-test3 56))) + ((defadvice sm-test4 (around wrap-with-toto activate) + ad-do-it (setq ad-return-value `(toto ,ad-return-value))) + (defmacro sm-test4 (x) `(call-test4 ,x)) + (macroexpand '(sm-test4 56)) (toto (call-test4 56))) + ((defmacro sm-test4 (x) `(call-testq ,x)) + (macroexpand '(sm-test4 56)) (toto (call-testq 56))) + + ;; Combining old style and new style advices. + ((defun sm-test5 (x) (+ x 4)) + (sm-test5 6) 10) + ((advice-add 'sm-test5 :around (lambda (f y) (* (funcall f y) 5))) + (sm-test5 6) 50) + ((defadvice sm-test5 (around test activate) + ad-do-it (setq ad-return-value (+ ad-return-value 0.1))) + (sm-test5 5) 45.1) + ((ad-deactivate 'sm-test5) + (sm-test5 6) 50) + ((ad-activate 'sm-test5) + (sm-test5 6) 50.1) + ((defun sm-test5 (x) (+ x 14)) + (sm-test5 6) 100.1) + ((advice-remove 'sm-test5 (lambda (f y) (* (funcall f y) 5))) + (sm-test5 6) 20.1) )) (ert-deftest advice-tests () ------------------------------------------------------------ revno: 110883 committer: Eli Zaretskii branch nick: trunk timestamp: Tue 2012-11-13 15:50:58 +0200 message: Fix a typo in src/ChangeLog. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2012-11-13 06:11:40 +0000 +++ src/ChangeLog 2012-11-13 13:50:58 +0000 @@ -4,7 +4,7 @@ * dispnew.c (glyphs_initialized_initially_p): Remove. (adjust_frame_glyphs_initially): Likewise. Adjust users. (Fredraw_frame): Move actual code from here... - (redraw_here): ...to here. Add eassert. Adjust comment. + (redraw_frame): ...to here. Add eassert. Adjust comment. (Fredraw_display): Use redraw_frame. * xdisp.c (clear_garbaged_frames): Likewise. ------------------------------------------------------------ revno: 110882 committer: Dmitry Gutov branch nick: trunk timestamp: Tue 2012-11-13 13:30:16 +0400 message: * lisp/progmodes/ruby-mode.el (ruby-add-log-current-method): Print the period before class method names, not after. Remove handling of one impossible case. Add comments. * test/automated/ruby-mode-tests.el (ruby-add-log-current-method-examples): New test. (ruby-test-string): Extract from ruby-should-indent-buffer. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-11-13 04:05:35 +0000 +++ lisp/ChangeLog 2012-11-13 09:30:16 +0000 @@ -1,3 +1,9 @@ +2012-11-13 Dmitry Gutov + + * progmodes/ruby-mode.el (ruby-add-log-current-method): Print the + period before class method names, not after. Remove handling of + one impossible case. Add comments. + 2012-11-13 Stefan Monnier * emacs-lisp/advice.el: Remove support for freezing. === modified file 'lisp/progmodes/ruby-mode.el' --- lisp/progmodes/ruby-mode.el 2012-11-13 03:07:09 +0000 +++ lisp/progmodes/ruby-mode.el 2012-11-13 09:30:16 +0000 @@ -1033,21 +1033,19 @@ #exit String#gsub Net::HTTP#active? - File::open. + File.open See `add-log-current-defun-function'." - ;; TODO: Document body - ;; Why does this append a period to class methods? (condition-case nil (save-excursion (let (mname mlist (indent 0)) - ;; get current method (or class/module) + ;; Get the current method definition (or class/module). (if (re-search-backward (concat "^[ \t]*" ruby-defun-beg-re "[ \t]+" "\\(" - ;; \\. and :: for class method - "\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)" - "+\\)") + ;; \\. and :: for class methods + "\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)" + "+\\)") nil t) (progn (setq mname (match-string 2)) @@ -1056,7 +1054,7 @@ (goto-char (match-beginning 1)) (setq indent (current-column)) (beginning-of-line))) - ;; nest class/module + ;; Walk up the class/module nesting. (while (and (> indent 0) (re-search-backward (concat @@ -1069,28 +1067,26 @@ (setq mlist (cons (match-string 2) mlist)) (setq indent (current-column)) (beginning-of-line)))) + ;; Process the method name. (when mname (let ((mn (split-string mname "\\.\\|::"))) (if (cdr mn) (progn - (cond - ((string-equal "" (car mn)) - (setq mn (cdr mn) mlist nil)) - ((string-equal "self" (car mn)) - (setq mn (cdr mn))) - ((let ((ml (nreverse mlist))) + (unless (string-equal "self" (car mn)) ; def self.foo + ;; def C.foo + (let ((ml (nreverse mlist))) + ;; If the method name references one of the + ;; containing modules, drop the more nested ones. (while ml (if (string-equal (car ml) (car mn)) (setq mlist (nreverse (cdr ml)) ml nil)) - (or (setq ml (cdr ml)) (nreverse mlist)))))) - (if mlist - (setcdr (last mlist) mn) - (setq mlist mn)) - (setq mn (last mn 2)) - (setq mname (concat "." (cadr mn))) - (setcdr mn nil)) + (or (setq ml (cdr ml)) (nreverse mlist)))) + (if mlist + (setcdr (last mlist) (butlast mn)) + (setq mlist (butlast mn)))) + (setq mname (concat "." (car (last mn))))) (setq mname (concat "#" mname))))) - ;; generate string + ;; Generate the string. (if (consp mlist) (setq mlist (mapconcat (function identity) mlist "::"))) (if mname === modified file 'test/ChangeLog' --- test/ChangeLog 2012-11-13 03:07:09 +0000 +++ test/ChangeLog 2012-11-13 09:30:16 +0000 @@ -1,7 +1,9 @@ 2012-11-13 Dmitry Gutov * automated/ruby-mode-tests.el (ruby-heredoc-font-lock) - (ruby-singleton-class-no-heredoc-font-lock): New tests. + (ruby-singleton-class-no-heredoc-font-lock) + (ruby-add-log-current-method-examples): New tests. + (ruby-test-string): Extract from ruby-should-indent-buffer. 2012-11-12 Stefan Monnier === modified file 'test/automated/ruby-mode-tests.el' --- test/automated/ruby-mode-tests.el 2012-11-13 03:07:09 +0000 +++ test/automated/ruby-mode-tests.el 2012-11-13 09:30:16 +0000 @@ -36,11 +36,13 @@ The whitespace before and including \"|\" on each line is removed." (with-temp-buffer - (cl-flet ((fix-indent (s) (replace-regexp-in-string "^[ \t]*|" "" s))) - (insert (fix-indent content)) - (ruby-mode) - (indent-region (point-min) (point-max)) - (should (string= (fix-indent expected) (buffer-string)))))) + (insert (ruby-test-string content)) + (ruby-mode) + (indent-region (point-min) (point-max)) + (should (string= (ruby-test-string expected) (buffer-string))))) + +(defun ruby-test-string (s &rest args) + (apply 'format (replace-regexp-in-string "^[ \t]*|" "" s) args)) (defun ruby-assert-state (content &rest values-plist) "Assert syntax state values at the end of CONTENT. @@ -261,6 +263,26 @@ (ruby-assert-face "# #{comment}\n \"#{interpolation}\"" 16 'font-lock-variable-name-face)) +(ert-deftest ruby-add-log-current-method-examples () + (let ((pairs '(("foo" . "#foo") + ("C.foo" . ".foo") + ("self.foo" . ".foo")))) + (loop for (name . value) in pairs + do (with-temp-buffer + (insert (ruby-test-string + "module M + | class C + | def %s + | end + | end + |end" + name)) + (ruby-mode) + (search-backward "def") + (forward-line) + (should (string= (ruby-add-log-current-method) + (format "M::C%s" value))))))) + (provide 'ruby-mode-tests) ;;; ruby-mode-tests.el ends here ------------------------------------------------------------ revno: 110881 committer: Dmitry Antipov branch nick: trunk timestamp: Tue 2012-11-13 10:11:40 +0400 message: Omit glyphs initialization at startup. * dispnew.c (glyphs_initialized_initially_p): Remove. (adjust_frame_glyphs_initially): Likewise. Adjust users. (Fredraw_frame): Move actual code from here... (redraw_here): ...to here. Add eassert. Adjust comment. (Fredraw_display): Use redraw_frame. * xdisp.c (clear_garbaged_frames): Likewise. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2012-11-13 02:25:59 +0000 +++ src/ChangeLog 2012-11-13 06:11:40 +0000 @@ -1,3 +1,13 @@ +2012-11-13 Dmitry Antipov + + Omit glyphs initialization at startup. + * dispnew.c (glyphs_initialized_initially_p): Remove. + (adjust_frame_glyphs_initially): Likewise. Adjust users. + (Fredraw_frame): Move actual code from here... + (redraw_here): ...to here. Add eassert. Adjust comment. + (Fredraw_display): Use redraw_frame. + * xdisp.c (clear_garbaged_frames): Likewise. + 2012-11-13 Eli Zaretskii * xdisp.c (decode_mode_spec): Limit the value of WIDTH argument === modified file 'src/dispnew.c' --- src/dispnew.c 2012-11-06 13:26:20 +0000 +++ src/dispnew.c 2012-11-13 06:11:40 +0000 @@ -141,10 +141,6 @@ static bool delayed_size_change; -/* 1 means glyph initialization has been completed at startup. */ - -static bool glyphs_initialized_initially_p; - /* Updated window if != 0. Set by update_window. */ struct window *updated_window; @@ -1850,43 +1846,6 @@ unblock_input (); } - -/* Adjust frame glyphs when Emacs is initialized. - - To be called from init_display. - - We need a glyph matrix because redraw will happen soon. - Unfortunately, window sizes on selected_frame are not yet set to - meaningful values. I believe we can assume that there are only two - windows on the frame---the mini-buffer and the root window. Frame - height and width seem to be correct so far. So, set the sizes of - windows to estimated values. */ - -static void -adjust_frame_glyphs_initially (void) -{ - struct frame *sf = SELECTED_FRAME (); - struct window *root = XWINDOW (sf->root_window); - struct window *mini = XWINDOW (root->next); - int frame_lines = FRAME_LINES (sf); - int frame_cols = FRAME_COLS (sf); - int top_margin = FRAME_TOP_MARGIN (sf); - - /* Do it for the root window. */ - wset_top_line (root, make_number (top_margin)); - wset_total_lines (root, make_number (frame_lines - 1 - top_margin)); - wset_total_cols (root, make_number (frame_cols)); - - /* Do it for the mini-buffer window. */ - wset_top_line (mini, make_number (frame_lines - 1)); - wset_total_lines (mini, make_number (1)); - wset_total_cols (mini, make_number (frame_cols)); - - adjust_frame_glyphs (sf); - glyphs_initialized_initially_p = 1; -} - - /* Allocate/reallocate glyph matrices of a single frame F. */ static void @@ -3071,19 +3030,13 @@ Redrawing Frames **********************************************************************/ -DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 0, 1, 0, - doc: /* Clear frame FRAME and output again what is supposed to appear on it. -If FRAME is omitted or nil, the selected frame is used. */) - (Lisp_Object frame) +/* Redraw frame F. */ + +void +redraw_frame (struct frame *f) { - struct frame *f = decode_live_frame (frame); - - /* Ignore redraw requests, if frame has no glyphs yet. - (Implementation note: It still has to be checked why we are - called so early here). */ - if (!glyphs_initialized_initially_p) - return Qnil; - + /* Error if F has no glyphs. */ + eassert (f->glyphs_initialized_p); update_begin (f); #ifdef MSDOS if (FRAME_MSDOS_P (f)) @@ -3100,22 +3053,17 @@ mark_window_display_accurate (FRAME_ROOT_WINDOW (f), 0); set_window_update_flags (XWINDOW (FRAME_ROOT_WINDOW (f)), 1); f->garbaged = 0; +} + +DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 0, 1, 0, + doc: /* Clear frame FRAME and output again what is supposed to appear on it. +If FRAME is omitted or nil, the selected frame is used. */) + (Lisp_Object frame) +{ + redraw_frame (decode_live_frame (frame)); return Qnil; } - -/* Redraw frame F. This is nothing more than a call to the Lisp - function redraw-frame. */ - -void -redraw_frame (struct frame *f) -{ - Lisp_Object frame; - XSETFRAME (frame, f); - Fredraw_frame (frame); -} - - DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "", doc: /* Clear and redisplay all visible frames. */) (void) @@ -3124,7 +3072,7 @@ FOR_EACH_FRAME (tail, frame) if (FRAME_VISIBLE_P (XFRAME (frame))) - Fredraw_frame (frame); + redraw_frame (XFRAME (frame)); return Qnil; } @@ -6208,7 +6156,6 @@ So call tgetent. */ { char b[2044]; tgetent (b, "xterm");} #endif - adjust_frame_glyphs_initially (); return; } #endif /* HAVE_X_WINDOWS */ @@ -6218,7 +6165,6 @@ { Vinitial_window_system = Qw32; Vwindow_system_version = make_number (1); - adjust_frame_glyphs_initially (); return; } #endif /* HAVE_NTGUI */ @@ -6232,7 +6178,6 @@ { Vinitial_window_system = Qns; Vwindow_system_version = make_number (10); - adjust_frame_glyphs_initially (); return; } #endif @@ -6322,7 +6267,6 @@ fatal ("screen size %dx%d too big", width, height); } - adjust_frame_glyphs_initially (); calculate_costs (XFRAME (selected_frame)); /* Set up faces of the initial terminal frame of a dumped Emacs. */ === modified file 'src/xdisp.c' --- src/xdisp.c 2012-11-13 02:25:59 +0000 +++ src/xdisp.c 2012-11-13 06:11:40 +0000 @@ -10769,7 +10769,7 @@ { if (f->resized_p) { - Fredraw_frame (frame); + redraw_frame (f); f->force_flush_display_p = 1; } clear_current_matrices (f);