# HG changeset patch # User Miles Bader # Date 1184465120 0 # Node ID 0ece58f6e0aa2d9989fa696e553029c6d24c27a6 # Parent 70b38dec13a1d3fbb4f02d3c2874a5daf02edd7c# Parent e0cd45299f772887852fe669926670d99f495367 Merge from emacs--devo--0 Patches applied: * emacs--devo--0 (patch 803-813) - Update from CVS - Merge from emacs--rel--22 * emacs--rel--22 (patch 51-58) - Update from CVS - Merge from gnus--rel--5.10 * gnus--rel--5.10 (patch 233-236) - Merge from emacs--devo--0 - Update from CVS Revision: emacs@sv.gnu.org/emacs--multi-tty--0--patch-25 diff -r 70b38dec13a1 -r 0ece58f6e0aa ChangeLog --- a/ChangeLog Sun Jul 08 11:35:01 2007 +0000 +++ b/ChangeLog Sun Jul 15 02:05:20 2007 +0000 @@ -1,3 +1,12 @@ +2007-06-20 Jan Dj,Ad(Brv + + * configure.in: Complain if X seems to be installed but no + development files were found. + +2007-06-20 Glenn Morris + + * configure.in: Prefer libgif over libungif. + 2007-06-14 Jan Dj,Ad(Brv * configure.in: Check for all image libraries before exiting. @@ -6,11 +15,6 @@ * configure.in: Exit with error if image libraries aren't found. -2007-06-13 Michael Kifer - - * ediff-ptch.el (ediff-context-diff-label-regexp): partially undid - previous patch - 2007-06-13 Chong Yidong * configure.in: Merge xaw3d and libXaw checks. Check xaw3d even diff -r 70b38dec13a1 -r 0ece58f6e0aa configure --- a/configure Sun Jul 08 11:35:01 2007 +0000 +++ b/configure Sun Jul 15 02:05:20 2007 +0000 @@ -686,6 +686,7 @@ CFLAGS_SOUND SET_MAKE XMKMF +HAVE_XSERVER GTK_CFLAGS GTK_LIBS XFT_CFLAGS @@ -1337,7 +1338,7 @@ --with-xpm use -lXpm for displaying XPM images --with-jpeg use -ljpeg for displaying JPEG images --with-tiff use -ltiff for displaying TIFF images - --with-gif use -lungif (or -lgif) for displaying GIF images + --with-gif use -lgif (or -lungif) for displaying GIF images --with-png use -lpng for displaying PNG images --with-gpm use -lgpm for mouse support on a GNU/Linux console --with-gtk use GTK (same as --with-x-toolkit=gtk) @@ -9584,6 +9585,68 @@ ;; esac +if test "$window_system" = none && test "X$with_x" != "Xno"; then + # Extract the first word of "X", so it can be a program name with args. +set dummy X; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_HAVE_XSERVER+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$HAVE_XSERVER"; then + ac_cv_prog_HAVE_XSERVER="$HAVE_XSERVER" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_HAVE_XSERVER="true" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_HAVE_XSERVER" && ac_cv_prog_HAVE_XSERVER="false" +fi +fi +HAVE_XSERVER=$ac_cv_prog_HAVE_XSERVER +if test -n "$HAVE_XSERVER"; then + { echo "$as_me:$LINENO: result: $HAVE_XSERVER" >&5 +echo "${ECHO_T}$HAVE_XSERVER" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + if test "$HAVE_XSERVER" = true || + test -n "$DISPLAY" || + test "`echo /usr/lib/libX11.*`" != "/usr/lib/libX11.*"; then + { { echo "$as_me:$LINENO: error: You seem to be running X, but no X development libraries +where found. You should install the relevant development files for X +and the for the toolkit you want, such as Gtk+, Lesstif or Motif. Also make +sure you have development files for image handling, i.e. +tiff, gif, jpeg, png and xpm. +If you are sure you want Emacs compiled without X window support, pass + --without-x +to configure." >&5 +echo "$as_me: error: You seem to be running X, but no X development libraries +where found. You should install the relevant development files for X +and the for the toolkit you want, such as Gtk+, Lesstif or Motif. Also make +sure you have development files for image handling, i.e. +tiff, gif, jpeg, png and xpm. +If you are sure you want Emacs compiled without X window support, pass + --without-x +to configure." >&2;} + { (exit 1); exit 1; }; } + fi +fi + ### If we're using X11, we should use the X menu package. HAVE_MENUS=no case ${HAVE_X11} in @@ -13880,6 +13943,83 @@ if test $ac_cv_header_gif_lib_h = yes; then # EGifPutExtensionLast only exists from version libungif-4.1.0b1. # Earlier versions can crash Emacs. + { echo "$as_me:$LINENO: checking for EGifPutExtensionLast in -lgif" >&5 +echo $ECHO_N "checking for EGifPutExtensionLast in -lgif... $ECHO_C" >&6; } +if test "${ac_cv_lib_gif_EGifPutExtensionLast+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgif $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char EGifPutExtensionLast (); +int +main () +{ +return EGifPutExtensionLast (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_gif_EGifPutExtensionLast=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_gif_EGifPutExtensionLast=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gif_EGifPutExtensionLast" >&5 +echo "${ECHO_T}$ac_cv_lib_gif_EGifPutExtensionLast" >&6; } +if test $ac_cv_lib_gif_EGifPutExtensionLast = yes; then + HAVE_GIF=yes +else + try_libungif=yes +fi + +fi + + + + if test "$HAVE_GIF" = yes; then + ac_gif_lib_name="-lgif" + fi + +# If gif_lib.h but no libgif, try libungif. + if test x"$try_libungif" = xyes; then { echo "$as_me:$LINENO: checking for EGifPutExtensionLast in -lungif" >&5 echo $ECHO_N "checking for EGifPutExtensionLast in -lungif... $ECHO_C" >&6; } if test "${ac_cv_lib_ungif_EGifPutExtensionLast+set}" = set; then @@ -13943,93 +14083,16 @@ echo "${ECHO_T}$ac_cv_lib_ungif_EGifPutExtensionLast" >&6; } if test $ac_cv_lib_ungif_EGifPutExtensionLast = yes; then HAVE_GIF=yes -else - try_libgif=yes -fi - -fi - - - - if test "$HAVE_GIF" = yes; then - ac_gif_lib_name="-lungif" - fi - -# If gif_lib.h but no libungif, try libgif. - if test x"$try_libgif" = xyes; then - { echo "$as_me:$LINENO: checking for EGifPutExtensionLast in -lgif" >&5 -echo $ECHO_N "checking for EGifPutExtensionLast in -lgif... $ECHO_C" >&6; } -if test "${ac_cv_lib_gif_EGifPutExtensionLast+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lgif $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char EGifPutExtensionLast (); -int -main () -{ -return EGifPutExtensionLast (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_gif_EGifPutExtensionLast=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_gif_EGifPutExtensionLast=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_gif_EGifPutExtensionLast" >&5 -echo "${ECHO_T}$ac_cv_lib_gif_EGifPutExtensionLast" >&6; } -if test $ac_cv_lib_gif_EGifPutExtensionLast = yes; then - HAVE_GIF=yes fi if test "$HAVE_GIF" = yes; then cat >>confdefs.h <<\_ACEOF -#define LIBGIF -lgif -_ACEOF - - ac_gif_lib_name="-lgif" +#define LIBGIF -lungif +_ACEOF + + ac_gif_lib_name="-lungif" fi fi @@ -24215,6 +24278,7 @@ CFLAGS_SOUND!$CFLAGS_SOUND$ac_delim SET_MAKE!$SET_MAKE$ac_delim XMKMF!$XMKMF$ac_delim +HAVE_XSERVER!$HAVE_XSERVER$ac_delim GTK_CFLAGS!$GTK_CFLAGS$ac_delim GTK_LIBS!$GTK_LIBS$ac_delim XFT_CFLAGS!$XFT_CFLAGS$ac_delim @@ -24241,7 +24305,6 @@ gamedir!$gamedir$ac_delim gameuser!$gameuser$ac_delim c_switch_system!$c_switch_system$ac_delim -c_switch_machine!$c_switch_machine$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -24283,6 +24346,7 @@ ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +c_switch_machine!$c_switch_machine$ac_delim LD_SWITCH_X_SITE!$LD_SWITCH_X_SITE$ac_delim LD_SWITCH_X_SITE_AUX!$LD_SWITCH_X_SITE_AUX$ac_delim C_SWITCH_X_SITE!$C_SWITCH_X_SITE$ac_delim @@ -24293,7 +24357,7 @@ LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 8; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 9; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 diff -r 70b38dec13a1 -r 0ece58f6e0aa configure.in --- a/configure.in Sun Jul 08 11:35:01 2007 +0000 +++ b/configure.in Sun Jul 15 02:05:20 2007 +0000 @@ -105,7 +105,7 @@ AC_ARG_WITH(tiff, [ --with-tiff use -ltiff for displaying TIFF images]) AC_ARG_WITH(gif, -[ --with-gif use -lungif (or -lgif) for displaying GIF images]) +[ --with-gif use -lgif (or -lungif) for displaying GIF images]) AC_ARG_WITH(png, [ --with-png use -lpng for displaying PNG images]) AC_ARG_WITH(gpm, @@ -1892,6 +1892,22 @@ ;; esac +if test "$window_system" = none && test "X$with_x" != "Xno"; then + AC_CHECK_PROG(HAVE_XSERVER, X, true, false) + if test "$HAVE_XSERVER" = true || + test -n "$DISPLAY" || + test "`echo /usr/lib/libX11.*`" != "/usr/lib/libX11.*"; then + AC_MSG_ERROR([You seem to be running X, but no X development libraries +were found. You should install the relevant development files for X +and for the toolkit you want, such as Gtk+, Lesstif or Motif. Also make +sure you have development files for image handling, i.e. +tiff, gif, jpeg, png and xpm. +If you are sure you want Emacs compiled without X window support, pass + --without-x +to configure.]) + fi +fi + ### If we're using X11, we should use the X menu package. HAVE_MENUS=no case ${HAVE_X11} in @@ -2528,24 +2544,24 @@ AC_CHECK_HEADER(gif_lib.h, # EGifPutExtensionLast only exists from version libungif-4.1.0b1. # Earlier versions can crash Emacs. - AC_CHECK_LIB(ungif, EGifPutExtensionLast, HAVE_GIF=yes, try_libgif=yes)) + AC_CHECK_LIB(gif, EGifPutExtensionLast, HAVE_GIF=yes, try_libungif=yes)) if test "$HAVE_GIF" = yes; then - ac_gif_lib_name="-lungif" + ac_gif_lib_name="-lgif" fi -# If gif_lib.h but no libungif, try libgif. - if test x"$try_libgif" = xyes; then - AC_CHECK_LIB(gif, EGifPutExtensionLast, HAVE_GIF=yes) +# If gif_lib.h but no libgif, try libungif. + if test x"$try_libungif" = xyes; then + AC_CHECK_LIB(ungif, EGifPutExtensionLast, HAVE_GIF=yes) if test "$HAVE_GIF" = yes; then - AC_DEFINE(LIBGIF, -lgif, [Compiler option to link with the gif library (if not -lungif).]) - ac_gif_lib_name="-lgif" + AC_DEFINE(LIBGIF, -lungif, [Compiler option to link with the gif library (if not -lgif).]) + ac_gif_lib_name="-lungif" fi fi if test "${HAVE_GIF}" = "yes"; then - AC_DEFINE(HAVE_GIF, 1, [Define to 1 if you have a gif library (default -lungif; otherwise specify with LIBGIF).]) + AC_DEFINE(HAVE_GIF, 1, [Define to 1 if you have a gif library (default -lgif; otherwise specify with LIBGIF).]) fi fi diff -r 70b38dec13a1 -r 0ece58f6e0aa etc/ChangeLog --- a/etc/ChangeLog Sun Jul 08 11:35:01 2007 +0000 +++ b/etc/ChangeLog Sun Jul 15 02:05:20 2007 +0000 @@ -1,3 +1,40 @@ +2007-07-15 Karl Fogel + + * NEWS: Revert revision 1.1509 (commitid xdXJjPiU1ZfI9Fps), which + documented bookmark keybinding changes that were later reverted. + +2007-07-14 Jan Dj,Ad(Brv + + * PROBLEMS: Mention gtk-engines-qt problem. + +2007-07-13 Karl Fogel + + * NEWS: Update for recent bookmark keybinding changes. + +2007-07-10 Michael Albinus + + * NEWS: Add Tramp and comint-mode changes. + +2007-07-08 Michael Albinus + + * NEWS: `file-remote-p' has a new optional parameter CONNECTED. + +2007-07-07 Michael Albinus + + * NEWS: New function `start-file-process'. + +2007-07-02 Carsten Dominik + + * orgcard.tex: Version 5.01 + +2007-06-27 Michael Albinus + + * NEWS: `dired-call-process' has been removed. + +2007-06-20 Glenn Morris + + * NEWS: configure prefers libgif over libungif. + 2007-06-14 Nick Roberts * NEWS: Mention mouse highlighting in a GNU/Linux console. diff -r 70b38dec13a1 -r 0ece58f6e0aa etc/NEWS --- a/etc/NEWS Sun Jul 08 11:35:01 2007 +0000 +++ b/etc/NEWS Sun Jul 15 02:05:20 2007 +0000 @@ -28,17 +28,24 @@ ** The default X toolkit is now Gtk+, rather than Lucid. -** configure now checks for libgif (as well as libungif) when -searching for a GIF library. +** configure now checks for libgif before libungif when searching for +a GIF library. * Changes in Emacs 23.1 +** If you set find-file-confirm-nonexistent-file to t, then C-x C-f +requires confirmation before opening a non-existent file. + ** If the gpm mouse server is running and t-mouse-mode enabled, Emacs uses a Unix socket in a GNU/Linux console to talk to server, rather than faking events using the client program mev. This C level approach provides mouse highlighting, and help echoing in the minibuffer. +** The new variable next-error-recenter specifies how next-error should +recenter the visited source file. Its value can be a number (for example, +0 for top line, -1 for bottom line), or nil for no recentering. + * Startup Changes in Emacs 23.1 @@ -57,6 +64,8 @@ ** bibtex-style-mode helps you write BibTeX's *.bst files. +** vera-mode to edit Vera files. + ** socks.el (which had been part of W3) is now part of Emacs. ** minibuffer-indicate-depth-mode shows the minibuffer depth in the prompt. @@ -64,22 +73,96 @@ * Changes in Specialized Modes and Packages in Emacs 23.1 +** compilation-auto-jump-to-first-error tells `compile' to jump to +the first error encountered during compilations. + ** In the `copyright' package, you can specify your copyright holders's names. Only copyright lines with holders matching copyright-names-regexp will be considered for update. +** VC +*** VC backends can provide completion of revision names. +*** VC has some support for Bazaar (bzr). -** VC has some support for Bazaar (bzr). +*** VC has some support for Mercurial (hg). + +** sgml-electric-tag-pair-mode lets you simultaneously edit matched tag pairs. + +** BibTeX mode: + +*** New `bibtex-entry-format' options `whitespace', `braces', and +`string', disabled by default. + +*** New variable `bibtex-cite-matcher-alist' contains rules to +identify cited keys in BibTeX entries, used by `bibtex-find-crossref. + +*** Command `bibtex-url' now allows multiple URLs per entry. + ++++ +** Tramp + +*** New connection methods. +The new methods "plinkx", "plink2", "psftp", "sftp" and "fish" have +been introduced. There are also new so-called gateway methods +"tunnel" and "socks". + +*** Multihop syntax has been removed. +The pseudo-method "multi" has been removed. Instead of, multi hops +can be specified by the new variable `tramp-default-proxies-alist'. + +*** More default settings. +Default values can be set via the variables `tramp-default-user', +`tramp-default-user-alist' and `tramp-default-host'. + +*** Connection information is cached. +In order to reduce connection setup, information about used +connections are kept persistent in a file. The name of this file is +defined in the variable `tramp-persistency-file-name'. + +*** Control of remote processes. +Running processes on a remote host can be controlled by settings in +`tramp-remote-path' and `tramp-remote-process-environment'. + +*** Success of remote copy is checked. +When the variable `file-precious-flag' is set, the success of a remote +file copy is checked via the file's checksum. + +** comint-mode uses `start-file-process' now (see Lisp Changes). +If `default-directory' is a remote file name, subprocesses are started +on the corresponding remote system. * Changes in Emacs 23.1 on non-free operating systems +--- +** IPv6 is supported on MS-Windows. +Emacs now supports IPv6 on Windows XP and later, and earlier versions +of Windows with third party IPv6 stacks installed. Previously IPv6 was +supported on other platforms, but not on Windows due to using the winsock +1.1 header file, even though Emacs was linking to the winsock 2 library. + * Incompatible Lisp Changes in Emacs 23.1 ++++ +** The function `dired-call-process' has been removed. + * Lisp Changes in Emacs 23.1 ++++ +** In `condition-case', a handler can specify "let the debugger run first". + +You do this by writing `debug' in the list of conditions to be handled, +like this: + + (condition-case nil + (foo bar) + ((debug error) nil)) + +** The `require-match' argument to `completing-read' accepts a new value +`confirm-only'. + +++ ** The regexp form \(?:\) specifies the group number explicitly. @@ -91,6 +174,19 @@ ** The new function `image-refresh' refreshes all images associated with a given image specification. ++++ +** The new function `start-file-process is similar to `start-process', +but obeys file handlers. The file handler is chosen based on +`default-directory'. + ++++ +** `file-remote-p' has a new optional parameter CONNECTED. +With this paramter passed non-nil, it is checked whether a remote +connection has been established already. + +** The two new functions `looking-at-p' and `string-match-p' can do +the same matching as `looking-at' and `string-match' without changing +the match data. * New Packages for Lisp Programming in Emacs 23.1 diff -r 70b38dec13a1 -r 0ece58f6e0aa etc/NEWS.22 --- a/etc/NEWS.22 Sun Jul 08 11:35:01 2007 +0000 +++ b/etc/NEWS.22 Sun Jul 15 02:05:20 2007 +0000 @@ -46,12 +46,23 @@ than the window, the usual keys for moving the cursor cause the image to be scrolled horizontally or vertically instead. +** Scrollbars follow the system theme on Windows XP and later. +Windows XP introduced themed scrollbars, but applications have to take +special steps to use them. Emacs now has the appropriate resources linked +in to make it use the scrollbars from the system theme. + * New Modes and Packages in Emacs 22.2 ** The new package css-mode.el provides a major mode for editing CSS files. +** The new package vera-mode.el provides a major mode for editing Vera files. + ** The new package socks.el implements the SOCKS v5 protocol. +** VC + +*** VC has some support for Mercurial (hg). + * Installation Changes in Emacs 22.1 @@ -259,6 +270,14 @@ keymaps that are active in the minibuffer are described below under "New keymaps for typing file names". +If you want the old behavior back, put these two key bindings to your +~/.emacs init file: + + (define-key minibuffer-local-filename-completion-map + " " 'minibuffer-complete-word) + (define-key minibuffer-local-must-match-filename-map + " " 'minibuffer-complete-word) + ** The completion commands TAB, SPC and ? in the minibuffer apply only to the text before point. If there is text in the buffer after point, it remains unchanged. diff -r 70b38dec13a1 -r 0ece58f6e0aa etc/PROBLEMS --- a/etc/PROBLEMS Sun Jul 08 11:35:01 2007 +0000 +++ b/etc/PROBLEMS Sun Jul 15 02:05:20 2007 +0000 @@ -1160,6 +1160,10 @@ Emacs*Foreground Emacs*Background +It is also reported that a bug in the gtk-engines-qt engine can cause this if +Emacs is compiled with Gtk+. +The bug is fixed in version 0.7 or newer of gtk-engines-qt. + *** KDE: Emacs hangs on KDE when a large portion of text is killed. This is caused by a bug in the KDE applet `klipper' which periodically diff -r 70b38dec13a1 -r 0ece58f6e0aa etc/orgcard.tex --- a/etc/orgcard.tex Sun Jul 08 11:35:01 2007 +0000 +++ b/etc/orgcard.tex Sun Jul 15 02:05:20 2007 +0000 @@ -1,5 +1,5 @@ % Reference Card for Org Mode -\def\orgversionnumber{4.77} +\def\orgversionnumber{5.03} \def\versionyear{2007} % latest update \def\year{2007} % latest copyright year @@ -111,14 +111,17 @@ \footline{\hss\folio} \def\makefootline{\baselineskip10pt\hsize6.5in\line{\the\footline}} \else %2 or 3 columns uses prereduced size - \hsize 3.2in \if 1\the\letterpaper + \hsize 3.2in \vsize 7.95in + \hoffset -.75in + \voffset -.745in \else + \hsize 3.2in \vsize 7.65in + \hoffset -.25in + \voffset -.745in \fi - \hoffset -.75in - \voffset -.745in \font\titlefont=cmbx10 \scaledmag2 \font\headingfont=cmbx10 \scaledmag1 \font\smallfont=cmr6 @@ -418,6 +421,7 @@ \key{toggle coordinate grid}{C-c \}} \key{toggle formula debugger}{C-c \{} +\newcolumn {\it Formula Editor} \key{edit formulas in separate buffer}{C-c '} @@ -540,6 +544,24 @@ \key{create sparse tree with matching tags}{C-c \\} \key{globally (agenda) match tags at cursor}{C-c C-o} +\section{Properties and Column View} + +\key{special commands in property lines}{C-c C-c} +\key{next/previous allowed value}{S-left/right} +\key{turn on column view}{C-c C-x C-c} + +\key{quit column view}{q} +\key{next/previous allowed value}{S-left/right} +\key{next/previous allowed value}{n / p} +\key{edit value}{e} +\key{edit allowed values list}{a} +\key{show value}{v} +\key{make column wider/narrower}{> / <} +\key{move column left/right}{M-left/right} +\key{add new column}{M-S-right} +\key{Delete current column}{M-S-left} + + \section{Timestamps} \key{prompt for date and insert timestamp}{C-c .} @@ -562,6 +584,8 @@ %\key{... forward/backward one month}{M-S-LEFT/RIGT} \key{Toggle custom format display for dates/times}{C-c C-x C-t} +\newcolumn + {\bf Clocking time} \key{start clock on current item}{C-c C-x C-i} @@ -571,12 +595,6 @@ \key{remove displayed times}{C-c C-c} \key{insert/update table with clock report}{C-c C-x C-r} -\section{LaTeX and cdlatex-mode} - -\key{preview LaTeX fragment}{C-c C-x C-l} -\key{Expand abbreviation (cdlatex-mode)}{TAB} -\key{Insert/modify math symbol (cdlatex-mode)}{` / '} - \section{Agenda Views} \key{add/move current file to front of agenda}{C-c [} @@ -617,7 +635,7 @@ {\bf Change display} \key{delete other windows}{o} -\key{switch to daily / weekly view}{d / w} +\key{switch to day/week/month/year view}{d w m y} \key{toggle inclusion of diary entries}{D} \key{toggle time grid for daily schedule}{g} \key{toggle display of logbook entries}{l} @@ -644,6 +662,7 @@ \key{change timestamp to today}{>} \key{insert new entry into diary}{i} +\newcolumn \key{start the clock on current item (clock-in)}{I} \key{stop the clock (clock-out)}{O} \key{cancel current clock}{X} @@ -652,7 +671,6 @@ \key{Open link in current line}{C-c C-o} -\newcolumn {\bf Calendar commands} \key{find agenda cursor date in calendar}{c} @@ -674,6 +692,12 @@ (setq org-agenda-include-diary t) \endexample +\section{LaTeX and cdlatex-mode} + +\key{preview LaTeX fragment}{C-c C-x C-l} +\key{Expand abbreviation (cdlatex-mode)}{TAB} +\key{Insert/modify math symbol (cdlatex-mode)}{` / '} + \section{Exporting and Publishing} Exporting creates files with extensions {\it .txt\/} and {\it .html\/} @@ -686,17 +710,17 @@ \key{insert template of export options}{C-c C-x t} \key{toggle fixed width for entry or region}{C-c :} -{\bf HTML formatting} +%{\bf HTML formatting} -\key{make words {\bf bold}}{*bold*} -\key{make words {\it italic}}{/italic/} -\key{make words \underbar{underlined}}{_underlined_} -\key{sub- and superscripts}{x\^{}3, J_dust} -\key{\TeX{}-like macros}{\\alpha, \\to} -\key{typeset lines in fixed width font}{start with :} -\key{tables are exported as HTML tables}{start with |} -\key{links become HTML links}{http:... etc} -\key{include html tags}{@...@} +%\key{make words {\bf bold}}{*bold*} +%\key{make words {\it italic}}{/italic/} +%\key{make words \underbar{underlined}}{_underlined_} +%\key{sub- and superscripts}{x\^{}3, J_dust} +%\key{\TeX{}-like macros}{\\alpha, \\to} +%\key{typeset lines in fixed width font}{start with :} +%\key{tables are exported as HTML tables}{start with |} +%\key{links become HTML links}{http:... etc} +%\key{include html tags}{@...@} %{\bf Export options} % diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/ChangeLog --- a/lisp/ChangeLog Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/ChangeLog Sun Jul 15 02:05:20 2007 +0000 @@ -1,3 +1,1125 @@ +2007-07-15 Karl Fogel + + * bookmark.el: Revert revision 1.90 (commitid mWoPbju3pgNotDps), + thus restoring bookmark bindings to three slots under C-x r. See + http://lists.gnu.org/archive/html/emacs-devel/2007-07/msg00705.html. + +2007-07-15 Jeff Miller (tiny change) + + * calendar/cal-bahai.el (calendar-goto-bahai-date): Add autoload + cookie. + +2007-07-15 Jason Rumney + + * w32-fns.el (set-default-process-coding-system): Use dos line ends + for input to cmdproxy on all versions of Windows. + Use dos line ends for input to plink. + + * comint.el (comint-simple-send): Concat newline before sending. + (comint-password-prompt-regexp): Recognize plink's passphrase prompt. + +2007-07-14 Stefan Monnier + + * emacs-lisp/autoload.el (generated-autoload-file): Autoload the + safe-local-variable setting. + +2007-07-14 David Kastrup + + * emacs-lisp/advice.el (defadvice): Doc fix. + +2007-07-14 Juanma Barranquero + + * subr.el (when, unless): Doc fix. + +2007-07-13 Dan Nicolaescu + + * replace.el (match): Use yellow1 instead of yellow. + + * progmodes/gdb-ui.el (breakpoint-enabled): Use red1 instead of + red. + + * pcvs-info.el (cvs-unknown): Likewise. + +2007-07-13 Eli Zaretskii + + * makefile.w32-in (install-lisp-SH, install-lisp-CMD): New targets. + (install): Use them to copy all *.el files before *.elc. + +2007-07-13 Drew Adams + + * bookmark.el (bookmark-jump-other-window): New function. + (bookmark-map): Bind it to "o". + + http://lists.gnu.org/archive/html/emacs-devel/2007-07/msg00633.html + and its thread contains discussion about this change. + The original patch was slightly tweaked by Karl Fogel + before committing. + +2007-07-13 Karl Fogel + + * bookmark.el: Shorten some comments to fit within 80 lines. + +2007-07-13 Karl Fogel + + * bookmark.el: Don't define bookmark keys under the "C-xr" map; + instead, make "C-xp" a prefix for bookmark-map. Patch by Drew + Adams , mildly tweaked by me. See + http://lists.gnu.org/archive/html/emacs-devel/2007-07/msg00633.html. + +2007-07-13 Carsten Dominik + + * textmodes/org.el: Bug fixes. + (org-end-of-line): Move to end of line if in headline without tags. + +2007-07-13 Stefan Monnier + + * vc-hooks.el: Remove spurious * in docstrings. + (vc-handled-backends): Add BZR. + + * vc-hooks.el (vc-find-file-hook): Use with-demoted-errors. + +2007-07-12 Davis Herring + + * desktop.el (desktop-buffer-info, desktop-save): + Use `desktop-dirname' instead of `dirname'. + +2007-07-12 Paul Pogonyshev + + * progmodes/which-func.el (which-func-modes): Add `python-mode'. + + * progmodes/python.el (python-which-func-length-limit): New var. + (python-which-func): New function. + (python-current-defun): Add optional `length-limit' and try to fit + computed function name to that length. + (python-mode): Hook `python-which-func' up. + +2007-07-12 Sean O'Rourke (tiny change) + + * pcomplete.el (pcomplete-entries): Obey pcomplete-ignore-case. + + * comint.el (comint-dynamic-complete-as-filename): + Use read-file-name-completion-ignore-case. + +2007-07-12 Stefan Monnier + + * comint.el (comint-dynamic-list-filename-completions): + Use read-file-name-completion-ignore-case. + + * vc-cvs.el: Require CL. + (vc-cvs-revision-table, vc-cvs-revision-completion-table): + New functions to provide completion of revision names. + + * vc-cvs.el (vc-functions): Clear up the cache when reloading the file. + (vc-cvs-annotate-first-line-re): New const. + (vc-cvs-annotate-process-filter): New fun. + (vc-cvs-annotate-command): Use them and run the command asynchronously. + +2007-07-12 Paul Pogonyshev + + * emacs-lisp/eldoc.el (eldoc-last-data): Revise documentation. + (eldoc-print-current-symbol-info): Adjust for changed helper + function signatures. + (eldoc-get-fnsym-args-string): Add `args' argument. Use new + `eldoc-highlight-function-argument'. + (eldoc-highlight-function-argument): New function. + (eldoc-get-var-docstring): Format documentation with + `font-lock-variable-name-face'. + (eldoc-docstring-format-sym-doc): Add `face' argument and apply it + where suited. + (eldoc-fnsym-in-current-sexp): Return a list with argument index. + (eldoc-beginning-of-sexp): Return number of skipped sexps. + +2007-07-11 Michael Albinus + + * progmodes/compile.el (compilation-start): `start-process' must + still be redefined when calling `start-process-shell-command'. + + * progmodes/gud.el (gud-file-name): When `default-directory' is a + remote file name, prepend its remote part to the filename. + (gud-common-init): When `default-directory' is a remote file name, + make the filename relative to it. + Based on a patch by Nick Roberts . + +2007-07-11 Dan Nicolaescu + + * vc-hooks.el (vc-default-mode-line-string): Add a mouse face, + mouse binding and a tooltip. + +2007-07-11 Stefan Monnier + + * menu-bar.el (vc-menu-map): New defalias. + +2007-07-10 Richard Stallman + + * emacs-lisp/lisp-mode.el (eval-defun): + Explain special handling of `defface'. + +2007-07-10 Jim Meyering (tiny change) + + * emacs-lisp/copyright.el (copyright-current-gpl-version): Set to 3. + + * autoinsert.el (auto-insert-alist): s/2/3/ in the generated comment. + +2007-07-10 Stefan Monnier + + * emacs-lisp/cl.el: Load cl-loaddefs.el quietly. + + * vc-arch.el (vc-arch-complete): Remove. + (vc-arch-revision-completion-table): Use complete-with-action. + + * subr.el (condition-case-no-debug, with-demoted-errors): New macros. + (complete-with-action): New function. + (dynamic-completion-table): Use it. + +2007-07-10 Michael Albinus + + * comint.el (make-comint, make-comint-in-buffer) + (comint-exec-1): Replace `start-process' by `start-file-process'. + + * progmodes/compile.el (compilation-start): Revert redefining + `start-process'. + +2007-07-10 Stefan Monnier + + * emacs-lisp/autoload.el (autoload-generate-file-autoloads): Be careful + with EOLs when generating MD5 checksums. + + * follow.el: Don't change the global map from the follow-mode-map + defvar, but from the toplevel. Use easy-menu to unify the Emacs and + XEmacs code. + (turn-on-follow-mode, turn-off-follow-mode): Remove interactive spec + since `follow-mode' should be used instead for that. + + * emacs-lisp/easymenu.el (easy-menu-binding): New function. + (easy-menu-do-define): Use it. + (easy-menu-do-add-item): Inline into easy-menu-add-item and then remove. + + * progmodes/compile.el (compilation-auto-jump-to-first-error) + (compilation-auto-jump-to-next): New vars. + (compilation-auto-jump): New function. + (compilation-error-properties): Use them to jump to first error. + (compilation-start): Set the var if requested. + + * emacs-lisp/autoload.el (update-directory-autoloads): Remove + duplicates without also removing entries from other directories. + +2007-07-10 Carsten Dominik + + * textmodes/org.el (org-agenda-day-view, org-agenda-week-view): + Remember span as default. + (org-columns-edit-value): Rename from `org-column-edit'. + (org-columns-display-here-title): Rename from + `org-overlay-columns-title'. + (org-columns-remove-overlays): Rename from org-remove-column-overlays. + (org-columns-get-autowidth-alist): Rename from + `org-get-columns-autowidth-alist'. + (org-columns-display-here): Rename from `org-overlay-columns'. + (org-columns-new-overlay): Rename from `org-new-column-overlay'. + (org-columns-quit): Rename from `org-column-quit'. + (org-columns-show-value): Rename from `org-column-show-value'. + (org-columns-content, org-columns-widen) + (org-columns-next-allowed-value) + (org-columns-edit-allowed, org-columns-store-format) + (org-columns-uncompile-format, org-columns-redo) + (org-columns-edit-attributes, org-delete-property) + (org-set-property, org-columns-update) + (org-columns-compute, org-columns-eval) + (org-columns-not-in-agenda, org-columns-compute-all) + (org-property-next-allowed-value) + (org-columns-compile-format) + (org-fill-paragraph-experimental) + (org-string-to-number, org-property-action) + (org-columns-move-left, org-columns-new ) + (org-column-number-to-string) + (org-property-previous-allowed-value) + (org-at-property-p, org-columns-delete) + (org-columns-previous-allowed-value) + (org-columns-move-right, org-columns-narrow) + (org-property-get-allowed-values) + (org-verify-version, org-column-string-to-number) + (org-delete-property-globally): New functions. + (org-columns-current-fmt): Rename from `org-current-columns-fmt'. + (org-columns-overlays): Rename from `org-column-overlays'. + (org-columns-map): Rename from `org-column-map'. + (org-columns-current-maxwidths): Rename from + `org-current-columns-maxwidths'. + (org-columns-begin-marker, org-columns-current-fmt-compiled) + (org-previous-header-line-format) + (org-columns-inhibit-recalculation) + (org-columns-top-level-marker): New variables. + (org-columns-default-format): Rename from `org-default-columns-format'. + (org-property-re): New constant. + +2007-07-10 Guanpeng Xu + + * subr.el (looking-at-p, string-match-p): New functions. + +2007-07-09 Reiner Steib + + * textmodes/tex-mode.el (tex-fontify-script) + (tex-font-script-display): New variables to make display of + superscripts and subscripts customizable. + (tex-font-lock-suscript, tex-font-lock-match-suscript): Use them. + +2007-07-09 Richard Stallman + + * isearch.el (isearch-edit-string): Call to isearch-push-state + after the search. + +2007-07-09 Jan Dj,Ad(Brv + + * window.el (fit-window-to-buffer): Remove setting of window-min-height + to 1 as enlarge-window uses the value to resize/shrink windows other + than WINDOW if needed. + +2007-07-08 Katsumi Yamaoka + + * cus-start.el (file-coding-system-alist): Fix custom type. + +2007-07-08 Chong Yidong + + * longlines.el (longlines-wrap-region): Avoid marking buffer as + modified. + (longlines-auto-wrap, longlines-window-change-function): + Remove unnecessary calls to set-buffer-modified-p. + +2007-07-08 Katsumi Yamaoka + + * cus-start.el (file-coding-system-alist): Fix custom type. + +2007-07-08 Stefan Monnier + + * vc-cvs.el (vc-cvs-revert): Use vc-default-revert. + (vc-cvs-checkout): Remove last arg now unused; simplify. + +2007-07-08 Michael Albinus + + * files.el (file-remote-p): Introduce optional parameter CONNECTED. + + * net/tramp.el: + * net/tramp-ftp.el: + * net/tramp-smb.el: + * net/tramp-uu.el: + * net/trampver.el: Migrate to Tramp 2.1. + + * net/tramp-cache.el: + * net/tramp-fish.el: + * net/tramp-gw.el: New Tramp packages. + + * net/tramp-util.el: + * net/tramp-vc.el: Removed. + + * net/ange-ftp.el: Add ange-ftp property to 'start-file-process + (ange-ftp-file-remote-p): Handle optional parameter CONNECTED. + + * net/rcompile.el (remote-compile): Handle Tramp 2.1 arguments. + + * progmodes/compile.el (compilation-start): Redefine + `start-process' temporarily when `default-directory' is remote. + Remove case of synchronous compilation, this won't happen ever. + (compilation-setup): Make local variable `comint-file-name-prefix' + for remote compilation. + +2007-07-08 Martin Rudalics + + * novice.el (disabled-command-function): Fit window to buffer to + make last line visible. + Reported by Stephen Berman . + + * mouse.el (mouse-drag-track): Reset transient-mark-mode to nil + when handling the terminating event. + +2007-07-07 Jay Belanger + + * calc/calc.el (math-read-number-simple): Remove leading 0s. + (math-bignum-digit-length): Change to optimal value. + + * calc/calc-bin.el (math-bignum-logb-digit-size) + (math-bignum-digit-power-of-two): Evaluate when compiled. + + * calc/calc-comb.el (math-small-factorial-table) + (math-init-random-base, math-prime-test): Remove unnecessary calls + to `math-read-number-simple'. + + * calc/calc-ext.el (math-approx-pi, math-approx-sqrt-e) + (math-approx-gamma-const): Add docstrings. + + * calc/calc-forms.el (math-julian-date-beginning) + (math-julian-date-beginning-int): New constants. + (math-format-date-part, math-parse-standard-date, calcFunc-julian): + Use the new constants. + + * calc/calc-funcs.el (math-gammap1-raw): Add docstring. + + * calc/calc-math.el (math-approx-ln-10, math-approx-ln-2): + Add docstrings. + +2007-07-07 Tom Tromey + + * vc.el (vc-annotate): Jump to line and output message only after the + process is really all done. + +2007-07-07 Stefan Monnier + + * vc.el (vc-exec-after): Don't move point from the sentinel. + Forcefully read all the remaining text in the pipe upon process exit. + (vc-annotate-display-autoscale, vc-annotate-lines): + Don't stop at the first unrecognized line. + (vc-annotate-display-select): Run autoscale after the process is done + since it depends on the whole result. + +2007-07-07 Eli Zaretskii + + * term/w32-win.el (menu-bar-open): New function. + Bind to it. + +2007-07-07 Michael Albinus + + * simple.el (start-file-process): New defun. + +2007-07-07 Stefan Monnier + + * files.el (find-file-confirm-nonexistent-file): Rename from + find-file-confirm-inexistent-file. Update users. + + * emacs-lisp/autoload.el (autoload-find-destination): Understand a new + format of autoload block where the file's time-stamp is replaced by its + MD5 checksum. + (autoload-generate-file-autoloads): Use MD5 checksum instead of + time-stamp for secondary autoloads files. + (update-directory-autoloads): Remove duplicate entries. + Use time-less-p for time-stamps, as done in autoload-find-destination. + +2007-07-07 Jay Belanger + + * calc/calc.el (math-read-number): Replace number by variable. + (math-read-number-simple): Properly parse small integers. + +2007-07-07 Dan Nicolaescu + + * vc.el: Fix doc for the checkout function. + +2007-07-06 Dan Nicolaescu + + * vc-hg.el (vc-hg-root): New function. + (vc-hg-registered): Use it. + (vc-hg-diff-tree): New defalias. + (vc-hg-responsible-p): Likewise. + (vc-hg-checkout): Comment out, not needed. + (vc-hg-delete-file, vc-hg-rename-file, vc-hg-could-register) + (vc-hg-find-version, vc-hg-next-version): New functions. + +2007-07-06 Andreas Schwab + + * emacs-lisp/lisp-mode.el (eval-last-sexp): Avoid introducing any + dynamic bindings around the evaluation of the expression. + Reported by Jay Belanger . + +2007-07-06 Stefan Monnier + + * autorevert.el (auto-revert-tail-handler): Use inhibit-read-only. + Run before-revert-hook. Suggested by Denis Bueno . + Use run-hooks rather than run-mode-hooks. + +2007-07-05 Jay Belanger + + * calc/calc-comb.el (math-random-digit): Rename to + `math-random-three-digit-number'. + (math-random-digits): Don't depend on representation of integer. + + * calc/calc-bin.el (math-bignum-logb-digit-size) + (math-bignum-digit-power-of-two): New constants. + (math-and-bignum, math-or-bignum, math-xor-bignum, math-diff-bignum) + (math-not-bignum, math-clip-bignum): Use the constants + `math-bignum-digit-power-of-two' and `math-bignum-logb-digit-size' + instead of their values. + (math-clip): Use math-small-integer-size instead of its value. + + * calc/calc.el (math-add-bignum): Replace number by constant. + +2007-07-05 Chong Yidong + + * wid-edit.el (widget-documentation-string-value-create): + Insert indentation spaces. + +2007-07-05 Thien-Thi Nguyen + + * emacs-lisp/byte-opt.el: Revert last change. + +2007-07-05 Dan Nicolaescu + + * vc-hooks.el (vc-handled-backends): Add HG. + + * vc-hg.el (vc-handled-backends): Remove, done in vc-hooks.el now. + +2007-07-05 Stefan Monnier + + * complete.el (PC-do-complete-and-exit): Add support for the new + `confirm-only' confirmation mode. + +2007-07-05 Chong Yidong + + * cus-edit.el (custom-commands): New variable. + (custom-tool-bar-map): New variable. Initialize using + `custom-commands'. + (custom-mode): Use `custom-tool-bar-map'. + (custom-buffer-create-internal): Insert action buttons only if + tool bar is not used. Use `custom-commands'. + (Custom-help, custom-command-apply): New function. + (custom-command-apply, Custom-set, Custom-save) + (Custom-reset-current, Custom-reset-saved, Custom-reset-standard): + Use `custom-command-apply' instead of duplicating code. + (customize-group-other-window): Call `customize-group' instead of + duplicating code. + (customize-face-other-window): Call `customize-face' instead of + duplicating code. + (customize-group, customize-face): Add optional args for opening + in another window. + (custom-variable-tag): Don't inherit `variable-pitch' face. + (custom-group-tag): Inherit `variable-pitch' face. + (custom-variable-value-create): Set documentation indentation. + (custom-group-value-create): Make group name a link, instead of + using an extra "go to group" button. + (custom-prompt-variable, custom-group-set, custom-group-save) + (custom-group-reset-current, custom-group-reset-saved) + (custom-group-reset-standard): Minor cleanup. + +2007-07-05 Thien-Thi Nguyen + + * Makefile.in (bootstrap-prepare): When copying from + ldefs-boot.el, make sure loaddefs.el is writeable. + + (bootstrap-prepare): Make $(lisp)/ps-print.el + and $(lisp)/emacs-lisp/cl-loaddefs.el writable, as well. + +2007-07-05 Dan Nicolaescu + + * vc-hg.el (vc-hg-internal-status): Inline in `vc-hg-state', the + only caller, and delete. + (vc-hg-state): Deal with exceptions and only parse the output on + successful return. + (vc-hg-internal-log): Inline in `vc-hg-workfile-version', the only + caller, and delete. + (vc-hg-workfile-version): Deal with exceptions and only parse the + output on successful return. + (vc-hg-revert): New function. + +2007-07-04 Jay Belanger + + * calculator.el (calculator-expt): Use more cases to determine + the value. + +2007-07-03 Dan Nicolaescu + + * progmodes/gud.el (auto-mode-alist): Match more valid gdb init + file names. + +2007-07-03 Jay Belanger + + * calculator.el (calculator-expt, calculator-integer-p): + New functions. + (calculator-fact): Check to see if the factorial will be too + large before computing it. + (calculator-initial-operators): Use `calculator-expt' to + compute "^". + (calculator-mode): Mention that results which are too large + will return inf. + * calc/calc-comb.el (math-small-factorial-table): Replace list + by vector. + +2007-07-03 David Kastrup + + * shell.el: On request of the authors, remove their addresses for + the sake of bug reports, and add the developer list address as + maintainer information. + +2007-07-03 Richard Stallman + + * files.el (make-directory): Doc fix. + (find-file-confirm-inexistent-file): Make it a defcustom. + Make nil the default. + +2007-07-02 Richard Stallman + + * startup.el (command-line): Set buffer-offer-save in *scratch* + and enable auto-save in it. + +2007-07-02 Carsten Dominik + + * textmodes/org.el (orgstruct-mode-map): New variable. + (orgstruct-mode): New minor mode. + (turn-on-orgstruct, orgstruct-error, orgstruct-setup) + (orgstruct-make-binding, org-context-p, org-get-local-variables) + (org-run-like-in-org-mode): New functions. + (org-cycle-list-bullet): New command. + (org-special-properties, org-property-start-re) + (org-property-end-re): New constants. + (org-with-point-at): New macro. + (org-get-property-block, org-entry-properties, org-entry-get) + (org-entry-delete, org-entry-get-with-inheritance) + (org-entry-put, org-buffer-property-keys): New functions. + (org-insert-property-drawer): New command. + (org-entry-property-inherited-from): New variable. + (org-column): New face. + (org-column-overlays, org-current-columns-fmt) + (org-current-columns-maxwidths, org-column-map): New variables. + (org-column-menu): New menu. + (org-new-column-overlay, org-overlay-columns) + (org-overlay-columns-title, org-remove-column-overlays) + (org-column-show-value, org-column-quit, org-column-edit): New + functions. + (org-columns, org-agenda-columns): New commands. + (org-get-columns-autowidth-alist): New functions. + (org-properties): New customize group. + (org-default-columns-format): New option. + (org-priority): Realign tags after changing priority. + (org-preserve-lc): New macro. + (org-update-checkbox-count): Catch case when there is no headline. + (org-agenda-quit): Remove any column overlays. + (org-beginning-of-item-list): Fixed bug when non-item line is + indented too deep. + (org-cached-props): New variable. + (org-cached-entry-get): New function. + (org-make-tags-matcher): Handle property matches. + (org-table-recalculate): Swap evaluation order: Field formula + first, then column formulas, but don't allow them to overwrite the + field formulas. + (org-table-eval-formula): New argument untouchable. + (org-table-put-field-property): New function. + +2007-07-02 Martin Rudalics + + * help-mode.el (help-make-xrefs): Skip spaces too when + skipping tabs. + + * ffap.el (dired-at-point-prompter): Improve prompt in + list-directory case. + +2007-07-01 Richard Stallman + + * files.el (find-file-visit-truename): Fix safe-local-variable value. + +2007-07-01 Richard Stallman + + * cus-start.el (max-mini-window-height): Added. + +2007-07-01 Sean O'Rourke (tiny change) + + * complete.el (partial-completion-mode): Remove advice of + read-file-name-internal. + (PC-do-completion): Rebind minibuffer-completion-table. + (PC-read-file-name-internal): New function doing what + read-file-name-internal advice did. + +2007-07-01 Paul Pogonyshev + + * emacs-lisp/byte-opt.el: Set `binding-is-magic' + property on a few symbols. + (byte-compile-side-effect-free-dynamically-safe-ops): New defconst. + (byte-optimize-lapcode): Remove bindings that are not referenced + and certainly will not effect through dynamic scoping. + +2007-07-01 Stefan Monnier + + * files.el (find-file-confirm-inexistent-file): New var. + (find-file, find-file-other-window, find-file-other-frame) + (find-file-read-only, find-file-read-only-other-window) + (find-file-read-only-other-frame): Use it. + +2007-06-30 Stefan Monnier + + * emacs-lisp/rx.el (rx-constituents): Fix up `anything'. + +2007-06-29 Juanma Barranquero + + * generic-x.el (generic-define-mswindows-modes) + (generic-define-unix-modes, apache-log-generic-mode) + (bat-generic-mode-keymap, java-manifest-generic-mode) + (show-tabs-generic-mode): Fix typos in docstrings. + +2007-06-29 Ryan Yeske + + * net/rcirc.el (rcirc-server-alist): Rename from rcirc-connections. + (rcirc-default-full-name): Rename from rcirc-default-user-full-name. + (rcirc-clear-activity): Make sure RCIRC-ACTIVITY isn't modified. + (rcirc-print): Never ignore messages from ourself. + +2007-06-29 Stefan Monnier + + * font-lock.el (lisp-font-lock-keywords-2): Recognize the new \(?1:..\) + syntax as well. Reported by Juri Linkov . + +2007-06-28 Jan Dj,Ad(Brv + + * dnd.el (dnd-get-local-file-name): Set fixcase to t in call to + replace-regexp-in-string. + +2007-06-28 Stefan Monnier + + * emacs-lisp/cl.el: Set edebug and indentation before loading + cl-loaddefs.el so that its use of dolist doesn't load cl-macs. + +2007-06-28 Andreas Schwab + + * Makefile.in ($(lisp)/mh-e/mh-loaddefs.el): Depend on + $(lisp)/subdirs.el. + +2007-06-28 Juanma Barranquero + + * speedbar.el (speedbar-handle-delete-frame): Don't try to delete + the speedbar frame if nil; that deletes the current frame or + causes an error if it is the only frame. + Reported by Angelo Graziosi . + +2007-06-28 Kevin Ryde + + * textmodes/nroff-mode.el: Groff \# comments. + (nroff-mode-syntax-table): \# comment intro, + plain # as punct per global table. + (nroff-font-lock-keywords): Add # as a single char escape. + (nroff-mode): In comment-start-skip, match \#. + +2007-06-28 Stefan Monnier + + * vc-bzr.el (vc-functions): Clear up the cache when reloading the file. + (vc-bzr-workfile-version, vc-bzr-could-register): Don't hardcode + point-min == 1. + +2007-06-28 Nick Roberts + + * pcvs-util.el (cvs-strings->string, cvs-string->strings): + Rename and move to... + + * subr.el (strings->string, string->strings): ...here. + + * pcvs.el (cvs-reread-cvsrc, cvs-header-msg, cvs-checkout) + (cvs-mode-checkout, cvs-execute-single-file): Use new function names. + + * progmodes/gud.el (gud-common-init): Call string->strings instead + of split-string. + +2007-06-27 Michael Albinus + + * dired-aux.el: Remove `dired-call-process'. + (dired-check-process): Call `process-file'. + + * wdired.el (wdired-do-perm-changes): Call `process-file'. + + * net/ange-ftp.el (ange-ftp-dired-call-process): Reimplement it as + `ange-ftp-process-file'. + +2007-06-27 Stefan Monnier + + * emacs-lisp/cl.el: Use cl-loaddefs.el rather than manual autoloads. + + * emacs-lisp/cl-extra.el: + * emacs-lisp/cl-seq.el: + * emacs-lisp/cl-macs.el: Set generated-autoload-file to cl-loaddefs.el. + Add autoload cookies on all defs autoloaded manually in cl.el. + + * emacs-lisp/cl-loaddefs.el: New file. + + * textmodes/texinfmt.el (texinfo-raisesections-alist) + (texinfo-lowersections-alist): Merge definition and declaration. + (texinfo-start-of-header, texinfo-end-of-header): Remove. + (texinfo-format-syntax-table): Merge init into declaration. + (texinfo-format-parse-line-args, texinfo-format-parse-args) + (texinfo-format-parse-defun-args, texinfo-format-node) + (texinfo-push-stack, texinfo-multitable-widths) + (texinfo-define-info-enclosure, texinfo-alias) + (texinfo-format-defindex, batch-texinfo-format): Use push. + (texinfo-footnote-number): Remove duplicate declaration. + + * ps-print.el: Update with auto-generated autoloads. + + * ps-mule.el: Set generated-autoload-file to "ps-print.el". + +2007-06-26 Stefan Monnier + + * emacs-lisp/autoload.el (autoload-generated-file): Interpret names + relative to current dir for file-local settings. + (autoload-generate-file-autoloads): Add `outfile' arg. + (update-directory-autoloads): Use it to directly call + autoload-generate-file-autoloads instead of going through + update-file-autoloads so we avoid redundant searches and so we can know + the set of buffers changed so we can save them all. + + * emacs-lisp/autoload.el (autoload-find-destination): Return nil + rather than throwing `up-to-date'. + (autoload-generate-file-autoloads): Adjust correspondingly. + (update-file-autoloads): Be careful to let-bind + autoload-modified-buffers and adjust to new calling conventions. + (autoload-modified-buffers): Make it a dynamically scoped var. + (update-directory-autoloads): Use file-relative-name instead of + autoload-trim-file-name. + (autoload-insert-section-header): Don't use autoload-trim-file-name + since the file is already relative now. + (autoload-trim-file-name): Remove. + + * vc-arch.el (vc-arch-add-tagline): Do a slightly cleaner job. + (vc-arch-complete, vc-arch--version-completion-table) + (vc-arch-revision-completion-table): New functions to provide + completion of revision names. + (vc-arch-trim-find-least-useful-rev, vc-arch-trim-make-sentinel) + (vc-arch-trim-one-revlib, vc-arch-trim-revlib): New functions + to let the user trim the revlib. + + * vc.el: Add new VC operation `revision-completion-table'. + (vc-default-revision-completion-table): New function. + (vc-version-diff, vc-version-other-window): Use it to provide + completion of revision names if the backend provides it. + + * log-edit.el (log-edit-changelog-entries): Use with-current-buffer. + + * vc-svn.el (vc-svn-repository-hostname): Adjust to non-XML format + of newer .svn/entries. + +2007-06-25 David Kastrup + + * calc/calc-poly.el (math-padded-polynomial) + (math-partial-fractions): Add some function comments. + +2007-06-25 Stefan Monnier + + * emacs-lisp/autoload.el (autoload-generate-file-autoloads): + Make `outbuf' optional. + (update-file-autoloads): Use it. + +2007-06-25 Stefan Monnier + + * emacs-lisp/autoload.el (autoload-modified-buffers): New var. + (autoload-find-destination): Keep it uptodate. + (autoload-save-buffers): New fun. + (update-file-autoloads): Use it. Re-add the "up to date" message. + + * emacs-lisp/autoload.el: Refactor for upcoming changes. + (autoload-find-destination): New function extracted from + update-file-autoloads. + (update-file-autoloads): Use it. + (autoload-generate-file-autoloads): New function extracted from + generate-file-autoloads. Use file-relative-name. Delay computation of + output-start to the first cookie. Remove done-any, replaced by + output-start. + (generate-file-autoloads): Use it. + +2007-06-24 Jay Belanger + + * calc/calc-comb.el (math-init-random-base, math-prime-test): + Use math-read-number-simple to insert constants. + (math-prime-test): Redo calculation of sum. + + * calc/calc-misc.el (math-div2-bignum): Use math-bignum-digit-size. + + * calc/calc-math.el (math-scale-bignum-digit-size): Rename from + math-scale-bignum-3. + (math-isqrt-bignum): Use math-scale-bignum-digit-size and + math-bignum-digit-size. + (math-isqrt-small): Add another possible initial guess. + +2007-06-23 Roland Winkler + + * textmodes/bibtex.el (bibtex-entry-format): New options + `whitespace', `braces', and `string'. + (bibtex-field-braces-alist, bibtex-field-strings-alist) + (bibtex-field-braces-opt, bibtex-field-strings-opt) + (bibtex-cite-matcher-alist): New variables. + (bibtex-font-lock-keywords): Use bibtex-cite-matcher-alist. + (bibtex-flash-head): Use blink-matching-delay. + (bibtex-insert-kill, bibtex-mark-entry): Use push-mark. + (bibtex-format-entry, bibtex-reformat): Handle new options of + bibtex-entry-format. + (bibtex-field-re-init, bibtex-font-lock-cite, bibtex-dist): + New functions. + (bibtex-complete-internal): Do not display messages while + minibuffer is used. Do not leave around a completions buffer + that is out of date. + (bibtex-copy-summary-as-kill): New optional arg. + (bibtex-font-lock-url): New optional arg no-button. + (bibtex-find-crossref): Use `bibtex-cite-matcher-alist'. + (bibtex-url): Allow multiple URLs per entry. + +2007-06-23 Stefan Monnier + + * emacs-lisp/autoload.el (autoload-generated-file): New function. + (update-file-autoloads, update-directory-autoloads): Use it. + (autoload-file-load-name): New function. + (generate-file-autoloads, update-file-autoloads): Use it. + (autoload-find-file): Accept non-absolute argument. Set default-dir. + (generate-file-autoloads): If the autoloaded form is malformed, + indicate the problem with a warning instead of aborting. + +2007-06-23 Thien-Thi Nguyen + + * simple.el (next-error-recenter): Accept `(4)' as well; + also, specify `integer' instead of `number'. + +2007-06-23 Eli Zaretskii + + * ls-lisp.el (insert-directory): If an invalid regexp error is + thrown, try using FILE as a literal file name, not a wildcard. + +2007-06-23 Juanma Barranquero + + * ruler-mode.el (ruler-mode): Prevent clobbering the original + `header-line-format' when reentering ruler mode. + +2007-06-23 Eli Zaretskii + + * ls-lisp.el (insert-directory): Don't treat FILE as a wildcard if + FILE exists as a file. + +2007-06-22 Jay Belanger + + * calc/calc.el (math-bignum-digit-length) + (math-bignum-digit-size, math-small-integer-size): + New constants. + (math-normalize, math-bignum-big, math-make-float) + (math-div10-bignum, math-scale-left, math-scale-left-bignum) + (math-scale-right, math-scale-right-bignum, math-scale-rounding) + (math-add, math-add-bignum, math-sub-bignum, math-sub, math-mul) + (math-mul-bignum, math-mul-bignum-digit, math-idivmod) + (math-quotient, math-div-bignum, math-div-bignum-digit) + (math-div-bignum-part, math-format-bignum-decimal) + (math-read-bignum): Use math-bignum-digit-length, + math-bignum-digit-size and math-small-integer-size. + + * calc/calc-ext.el (math-fixnum-big): Use the variable + math-bignum-digit-size. + +2007-06-23 Dan Nicolaescu + + * log-view.el (log-view-mode-menu): New menu. + +2007-06-22 Stefan Monnier + + * diff-mode.el (diff-font-lock-keywords): Fix M. Kifer's last change + differently. + + * vc-hg.el (vc-hg-registered): Add an autoloaded version. + (vc-hg-log-view-mode): Use log-view-font-lock-keywords. + +2007-06-22 Dan Nicolaescu + + * vc-hg.el (vc-hg-print-log): Insert the file name. + (vc-hg-log-view-mode): Fontify the file name. + +2007-06-22 Jay Belanger + + * calc/calc-forms.el (math-format-date-part, calc-parse-standard-date) + (calcFunc-julian): Fix incorrect number used in calculations. + +2007-06-22 Thien-Thi Nguyen + + * simple.el (next-error-recenter): New defcustom. + (next-error, next-error-internal): Recenter if specified, + immediately prior to running `next-error-hook'. + + * progmodes/hideshow.el (hs-show-block): Use line-end-position. + (hs-hide-block-at-point, hs-hide-comment-region): Likewise. + + * progmodes/hideshow.el (hs-hide-all): Use progress reporter. + +2007-06-22 Jay Belanger + + * calc/calc-comb.el (math-small-factorial-table): New variable. + (calcFunc-fact): Use `math-small-factorial-table'. + + * calc/calc-ext.el (math-defcache): Allow forms to evaluate + initial values. + (math-approx-pi, math-approx-sqrt-e, math-approx-gamma-const): + New variables to use in caches. + + * calc/calc-forms.el (math-format-date-part, math-parse-standard-date) + (calcFunc-julian): Use `math-read-number-simple' to insert bignums. + + * calc/calc-func.el (math-besJ0, math-besJ1, math-besY0, math-besY1) + (math-bernoulli-b-cache): Use math-read-number-simple to insert + bignums. + + * calc/calc-math.el (math-approx-ln-10, math-approx-ln-2): + New variables to use in caches. + +2007-06-22 Dan Nicolaescu + + * vc-bzr.el (vc-bzr-log-view-mode): Add + to the email address regexp. + + * vc-hg.el (vc-hg-log-view-mode): New mode. + +2007-06-21 Jay Belanger + + * calc/calc.el (math-read-number-simple): New function. + +2007-06-21 Stefan Monnier + + * vera-mode.el (vera-mode): Fix `commend-end-skip' setting. + (vera-font-lock-match-item): Fix doc string. + (vera-in-comment-p): Remove unused function. + (vera-skip-forward-literal, vera-skip-backward-literal): Improve code, + use `syntax-ppss'. + (vera-forward-syntactic-ws): Fix argument order. + (vera-prepare-search): Use `with-syntax-table'. + (vera-indent-line): Fix doc string. + (vera-electric-tab): Fix doc string. + (vera-expand-abbrev): Define alias instead of using `fset'. + (vera-comment-uncomment-region): Use `comment-start-skip'. + +2007-06-21 Carsten Dominik + + * textmodes/org.el (org-export-with-footnotes): New option. + (org-export-as-html): Fix replacement bug for XEmacs. + (org-agenda-default-appointment-duration): New option. + +2007-06-21 Dan Nicolaescu + + * vc-hg.el: Add to do items. + (vc-hg-diff): Add support for comparing different revisions. + (vc-hg-diff, vc-hg-annotate-command, vc-hg-annotate-time) + (vc-hg-annotate-extract-revision-at-line) + (vc-hg-previous-version, vc-hg-checkin): New functions. + (vc-hg-annotate-re): New constant. + +2007-06-20 Jay Belanger + + * calc/calc.el (math-standard-ops): Fix precedence of multiplication. + +2007-06-20 Stefan Monnier + + * log-view.el (log-view-font-lock-keywords): Use `eval' to consult the + buffer-local value of log-view-*-re if applicable. + + * vc-bzr.el (vc-bzr-dir-state): Use setq rather than set. + Use vc-bzr-command rather than the ill defined vc-bzr-command*. + (vc-bzr-command*): Remove both (incompatible) versions. + (vc-bzr-do-command*): Remove. + (vc-bzr-with-process-environment, vc-bzr-std-process-invocation): + Remove by folding into its only caller vc-bzr-command. + (vc-bzr-command): Always set the environment, even when ineffective. + (vc-bzr-version): Minor fix up. + (vc-bzr-admin-dirname): New var. + (vc-bzr-bzr-dir): Remove. + (vc-bzr-root-dir): New fun. + (vc-bzr-registered): Use it. Add an autoloaded version. + (vc-bzr-responsible-p): Use vc-bzr-root-dir as well. + (vc-bzr-view-log-function): Remove. + (vc-bzr-log-view-mode): New major mode to replace it. + (vc-bzr-print-log): Only activate the old hack if needed. + + * vc.el (vc-default-log-view-mode): New function. + (vc-print-log): Add new `log-view-mode' VC operation. + +2007-06-20 Juanma Barranquero + + * ido.el (ido-find-file-in-dir): Don't signal an error for + empty directories. + + * add-log.el (change-log-mode): Set `show-trailing-whitespace'. + + * desktop.el (desktop-read): Run `desktop-not-loaded-hook' in the + directory where the desktop file was found, as the docstring says. + (desktop-kill): Use `read-directory-name'. + +2007-06-20 Alan Mackenzie + + * progmodes/cc-mode.el (c-remove-any-local-eval-or-mode-variables): + When removing lines, also remove the \n. Correction of patch of + 2007-04-21. + +2007-06-20 Martin Rudalics + + * mouse.el (mouse-drag-mode-line-1): Quit mouse tracking when + event is not a cons cell. Do not unread drag-mouse-1 events. + Select right window in check whether space was stolen from + window above. + + * help-mode.el (help-make-xrefs): Adjust position of new forward + button. + +2007-06-20 Riccardo Murri + + * vc-bzr.el (vc-bzr-with-process-environment) + (vc-bzr-std-process-invocation): New macros. + (vc-bzr-command, vc-bzr-command*): Use them. + (vc-bzr-with-c-locale): Remove. + (vc-bzr-dir-state): Replace its use with vc-bzr-command. + (vc-bzr-buffer-nonblank-p): New function. + (vc-bzr-state-words): New const. + (vc-bzr-state): Look for `bzr status` keywords in output. + Display everything else as a warning message to the user. + Fix status report with bzr >= 0.15. + +2007-06-20 Dan Nicolaescu + + * vc-hg.el (vc-hg-global-switches): Simplify. + (vc-hg-state): Handle more states. + (vc-hg-diff): Fix doc-string. + (vc-hg-register): New function. + (vc-hg-checkout): Likewise. + +2007-06-20 Reto Zimmermann + + * progmodes/vera-mode.el: New file. + +2007-06-19 Jay Belanger + + * calc/calc.el (calc-multiplication-has-precendence): + New variable. + (math-standard-ops, math-standard-ops-p, math-expr-ops): + New functions. + (math-expr-opers): Define using math-standard-ops rather than + math-standard-opers. + * calc/calc-aent.el (calc-do-calc-eval): Let math-expr-opers + equal the function math-standard-ops rather than the variable + math-standard-opers. + (calc-algebraic-entry): Let math-expr-opers equal + math-standard-ops or math-expr-ops, as appropriate. + (math-expr-read-level, math-read-factor): Let math-expr-opers + equal math-expr-ops. + * calc/calc-embed.el (calc-embedded-finish-edit): + Let math-expr-opers equal the function math-standard-ops + rather than the variable math-standard-opers. + * calc/calc-ext.el (math-read-plain-expr) + (math-format-flat-expr-fancy): Let math-expr-opers equal the + function math-standard-ops rather than the variable + math-standard-opers. + * calc/calc-lang.el (calc-set-language, math-read-big-rec): + Let math-expr-opers equal the function math-standard-ops rather + than the variable math-standard-opers. + * calc/calc-prog.el (calc-read-parse-table): Let math-expr-opers + equal the function math-standard-ops rather than the variable + math-standard-opers. + * calc/calc-yank.el (calc-finish-stack-edit): Let math-expr-opers + equal the function math-standard-ops rather than the variable + math-standard-opers. + * calc/calccomp.el (math-compose-expr): Let math-expr-opers equal + math-expr-ops. + +2007-06-19 Ivan Kanis + + * vc-hg.el: New file. + +2007-06-18 Stefan Monnier + + * progmodes/sh-script.el (sh-font-lock-paren): Mark the relevant text + with font-lock-multiline. + +2007-06-17 Glenn Morris + + * lpr.el (lpr-page-header-switches): Move %s to separate element + for correct quoting. Doc fix. + +2007-06-17 Stefan Monnier + + * textmodes/sgml-mode.el (sgml-xml-guess): Return the result rather + than setting sgml-xml-mode. + (sgml-mode, html-mode): Set sgml-xml-mode. + (sgml-skip-tag-backward): Tell if we skipped over matched tags. + (sgml-skip-tag-backward, sgml-electric-tag-pair-overlays): New var. + (sgml-electric-tag-pair-before-change-function) + (sgml-electric-tag-pair-flush-overlays): New functions. + (sgml-electric-tag-pair-mode): New minor mode. + (sgml-font-lock-keywords-2, sgml-get-context, sgml-unclosed-tag-p) + (sgml-calculate-indent): Use assoc-string. + 2007-06-16 Karl Fogel * thingatpt.el (thing-at-point-email-regexp): Don't require two @@ -11,19 +1133,18 @@ (thing-at-point-email-regexp): New variable. (`email'): Put `bounds-of-thing-at-point' and `thing-at-point' properties on this symbol, with lambda forms for values. - + 2007-06-15 Masatake YAMATO - * vc-bzr.el (vc-bzr-root): Cache the output of shell command - execution. - - * vc.el (vc-dired-hook): Check the backend returned from + * vc-bzr.el (vc-bzr-root): Cache the output of shell command execution. + + * vc.el (vc-dired-hook): Check the backend returned from `vc-responsible-backend' can really handle `subdir'. 2007-06-15 Chong Yidong - * wid-edit.el (widget-add-documentation-string-button): Fix - handling of documentation indent. + * wid-edit.el (widget-add-documentation-string-button): + Fix handling of documentation indent. 2007-06-15 Miles Bader @@ -47,8 +1168,8 @@ (custom-variable-value-create, custom-face-value-create) (custom-visibility): New widget. (custom-visibility): New face. - (custom-group-value-create): Call - widget-add-documentation-string-button, using `custom-visibility'. + (custom-group-value-create): + Call widget-add-documentation-string-button, using `custom-visibility'. 2007-06-14 Stefan Monnier @@ -60,8 +1181,8 @@ 2007-06-14 Michael Kifer * viper.el (viper-describe-key-ad, viper-describe-key-briefly-ad): - different advices for Emacs and XEmacs. Compile them conditionally. - (viper-version): belated version change. + Different advices for Emacs and XEmacs. Compile them conditionally. + (viper-version): Belated version change. 2007-06-14 Juanma Barranquero @@ -129,7 +1250,7 @@ post-command-hook. (rcirc-window-configuration-change-1): Update mode-line and overlay arrows here. - (rcirc-authenticate): Fix chanserv identification. + (rcirc-authenticate): Fixc hanserv identification. (rcirc-default-server): Remove variable. (rcirc): Connect according to rcirc-connections. (rcirc-connections): Add variable. @@ -156,6 +1277,11 @@ * vc-arch.el (vc-arch-command): Remove bzr. It's a different program. +2007-06-13 Michael Kifer + + * ediff-ptch.el (ediff-context-diff-label-regexp): Partially undo + previous change. + 2007-06-12 Tom Tromey * subr.el (user-emacs-directory): New defconst. @@ -260,7 +1386,7 @@ (desktop-kill): Tell `desktop-save' that this is the last save. Release the lock afterwards. (desktop-buffer-info): New function. - (desktop-save): Use it. Run `desktop-save-hook' where the doc + (desktop-save): Use it. Run `desktop-save-hook' where the doc says to. Detect conflicts, and manage the lock. (desktop-read): Detect conflicts. Manage the lock. @@ -270,7 +1396,7 @@ * emulation/tpu-edt.el (tpu-gold-map): Rename from GOLD-map. (tpu-lucid-emacs-p): Remove. Use (featurep 'xemacs) instead. - (CSI-map, GOLD-CSI-map, GOLD-SS3-map, SS3-map): Delete vars. + (CSI-map, GOLD-CSI-map, GOLD-SS3-map, SS3-map): Delete vars. (tpu-gold-map, tpu-global-map): Add all the SS3 and CSI bindings, using keysyms rather than byte sequences. (tpu-copy-keyfile): Don't force the user to use tpu-mapper.el. @@ -469,9 +1595,9 @@ (org-table-use-standard-references, org-disputed-keys) (org-export-skip-text-before-1st-heading, org-agenda-with-colors) (org-agenda-export-html-style): New option. - (org-allow-auto-repeat, org-agenda-remove-tags-when-in-prefix) + (org-allow-auto-repeat, org-agenda-remove-tags-when-in-prefix) (org-CUA-compatible): Option removed. - (org-agenda-structure, org-sexp-date): New face. + (org-agenda-structure, org-sexp-date): New face. (org-todo-keywords-for-agenda, org-not-done-keywords) (org-planning-or-clock-line-re, org-agenda-name) (org-table-colgroup-info, org-todo-sets) @@ -487,7 +1613,7 @@ (org-repeat-re, org-todo-kwd-max-priority) (org-version, org-done-string) (org-table-clean-did-remove-column-1, org-disputed-keys): - Remove Variables. + Remove variables. (org-table-translate-regexp, org-repeat-re, org-version): New consts. (org-ts-lengths): Constant removed. (org-follow-gnus-link): Don't ask how many articles to read. @@ -644,7 +1770,7 @@ 2007-05-25 Stefan Monnier * emacs-lisp/derived.el (define-derived-mode): Remove bogus - compatibiity code. + compatibility code. * emacs-lisp/copyright.el (copyright-names-regexp): New var. (copyright-update-year): Use it. @@ -742,7 +1868,7 @@ * files.el (auto-mode-alist): Open `.asd' files in lisp-mode. -2007-05-22 Katsumi Yamaoka (tiny change) +2007-05-22 Katsumi Yamaoka * mail/mail-extr.el (mail-extract-address-components): Recognize non-ASCII characters except for NBSP as words. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/ChangeLog.10 --- a/lisp/ChangeLog.10 Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/ChangeLog.10 Sun Jul 15 02:05:20 2007 +0000 @@ -1340,7 +1340,7 @@ (shell-directory-tracker): Make regexp used for skipping to next command correspond to one used for command itself. -2003-06-13 Katsumi Yamaoka (tiny change) +2003-06-13 Katsumi Yamaoka * textmodes/texinfmt.el (texinfo-format-scan): Silence `whitespace-cleanup'. @@ -11805,7 +11805,7 @@ * vc-hooks.el (vc-kill-buffer-hook): Add it to kill-buffer-hook again. -2002-08-22 Katsumi Yamaoka (tiny change) +2002-08-22 Katsumi Yamaoka * frame.el (select-frame-by-name, select-frame-set-input-focus): Always call x-focus-frame, if using x. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/ChangeLog.11 --- a/lisp/ChangeLog.11 Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/ChangeLog.11 Sun Jul 15 02:05:20 2007 +0000 @@ -5295,7 +5295,7 @@ (reb-lisp-syntax-p, reb-change-syntax): `rx' is a Lisp syntax. (reb-cook-regexp): Call `rx-to-string' when `re-reb-syntax' is `rx'. -2004-08-05 Katsumi Yamaoka (tiny change) +2004-08-05 Katsumi Yamaoka * mail/mail-extr.el (mail-extr-disable-voodoo): New variable. (mail-extr-voodoo): Check mail-extr-disable-voodoo. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/ChangeLog.12 --- a/lisp/ChangeLog.12 Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/ChangeLog.12 Sun Jul 15 02:05:20 2007 +0000 @@ -1092,8 +1092,8 @@ North American rule. Replace "daylight savings" with "daylight saving" in doc. - * calendar/cal-china.el,cal-dst.el,calendar.el,diary-lib.el: - * calendar/lunar.el,solar.el: Replace "daylight savings" with + * calendar/cal-china.el, cal-dst.el, calendar.el, diary-lib.el: + * calendar/lunar.el, solar.el: Replace "daylight savings" with "daylight saving" in text. * woman.el (woman-change-fonts): Tweak previous change by using @@ -2595,7 +2595,7 @@ path. Rewrite function in `cond' style for readability. Suggested by: Stephen Eglen . - (The path shortening, that is, not the rearrarangement.) + (The path shortening, that is, not the rearrangement.) 2007-01-15 YAMAMOTO Mitsuharu @@ -6360,7 +6360,7 @@ * help.el (describe-key-briefly): When reading a down-event on mode lines or scroll bar, swallow the following up event, too. - Use the new mouse sensitity of `key-binding' for lookup. + Use the new mouse sensitivity of `key-binding' for lookup. (describe-key): The same here. 2006-09-15 Juanma Barranquero @@ -7911,11 +7911,11 @@ * tumme.el (tumme-display-thumbnail-original-image): Make sure image display buffer is displayed before call to - `tumme-display-image. + `tumme-display-image'. (tumme-dired-display-image): Make sure image display buffer is - displayed before call to `tumme-display-image. + displayed before call to `tumme-display-image'. (tumme-mouse-display-image): Make sure image display buffer is - displayed before call to `tumme-display-image. + displayed before call to `tumme-display-image'. (tumme-widget-list): Add. (tumme-dired-edit-comment-and-tags): Add. (tumme-save-information-from-widgets): Add. @@ -8042,7 +8042,7 @@ instead of retired `allout-resumptions'. For hook functions, use `local' parameter so hook settings are created and removed as buffer-local settings. Revise (resumptions) setting - auto-fill-function so it is set only if already active. (The + auto-fill-function so it is set only if already active. The related fill-function settings are all made in either case, so that activating auto-fill-mode activity will have the custom allout-mode behaviors (hanging indent on topics, if configured for it). @@ -8709,7 +8709,7 @@ * term.el (term-handle-scroll, term-delete-lines) (term-insert-lines): Fix off by one errors. -2006-06-15 Katsumi Yamaoka (tiny change) +2006-06-15 Katsumi Yamaoka * net/tramp.el (tramp-touch): Use UTC to express time. @@ -9788,7 +9788,7 @@ * calendar/cal-menu.el (calendar-mode-map, calendar-mouse-3-map): * calendar/calendar.el (calendar-mode-map): - * calendar/diary-lib.el (include-other-diary-files,diary-mail-entries): + * calendar/diary-lib.el (include-other-diary-files, diary-mail-entries): * calendar/appt.el (appt-check, appt-make-list): Refer to diary-view-entries, diary-list-entries, diary-show-all-entries rather than obsolete aliases. @@ -9998,7 +9998,7 @@ 2006-05-09 Masatake YAMATO - * font-lock.el (cpp-font-lock-keywords-source-directives): Addded + * font-lock.el (cpp-font-lock-keywords-source-directives): Added "warning" and "import". (cpp-font-lock-keywords): Added "warning". @@ -10865,7 +10865,7 @@ (org-table-create-or-convert-from-region): New commands (org-table-toggle-vline-visibility): Command removed. (org-table-convert-region): Made a command. - (orgtbl-deleta-backward-char,orgtbl-delete-char): Remove commands. + (orgtbl-deleta-backward-char, orgtbl-delete-char): Remove commands. Replace with the normal org- functions. (org-self-insert-command): Don't trigger realign unnecessarily when blanking a field that is not full. @@ -11275,7 +11275,7 @@ (ibuffer-mode-header-map): New keymaps. (ibuffer-update-title-and-summary): Enable mouse face highlighting and keybindings for column headers. - (name,size,mode) : Add a header-mouse-map + (name, size, mode) : Add a header-mouse-map property. 2006-04-02 Drew Adams (tiny change) @@ -20649,7 +20649,7 @@ (ibuffer-do-print, ibuffer-filter-by-mode, ibuffer-filter-by-used-mode) (ibuffer-filter-by-name, ibuffer-filter-by-filename) (ibuffer-filter-by-size-gt, ibuffer-filter-by-size-lt) - (ibuffer-filter-by-content, ibuffer-filter-by-predicate + (ibuffer-filter-by-content, ibuffer-filter-by-predicate) (ibuffer-do-sort-by-major-mode, ibuffer-do-sort-by-mode-name) (ibuffer-do-sort-by-alphabetic, ibuffer-do-sort-by-size): Autoload file sans suffix. @@ -20758,7 +20758,7 @@ (gdb-info-frames-custom): Put `font-lock-function-name-face' and `font-lock-variable-name-face' (gdb-registers-font-lock-keywords): New font lock keywords definition. - (gdb-registers-mode): Use `gdb-registers-font-lock-keywords`. + (gdb-registers-mode): Use `gdb-registers-font-lock-keywords'. (gdb-memory-font-lock-keywords): New font lock keywords definition. (gdb-memory-mode): Use `gdb-memory-font-lock-keywords'. (gdb-local-font-lock-keywords): New font lock keywords definition. @@ -22168,7 +22168,7 @@ 2005-08-30 Richard M. Stallman * files.el (risky-local-variable-p): - Match `-predicates' and `-commands. + Match `-predicates' and `-commands'. * cus-edit.el (custom-buffer-sort-alphabetically): Default to t. (custom-save-all): Visit the file if necessary; @@ -22969,7 +22969,7 @@ * menu-bar.el (menu-bar-showhide-menu): Add `showhide-battery'. -2005-08-09 Katsumi Yamaoka (tiny change) +2005-08-09 Katsumi Yamaoka * net/ange-ftp.el (ange-ftp-send-cmd): Make it work properly with uploading files. @@ -23161,7 +23161,7 @@ (tramp-handle-set-visited-file-modtime) (tramp-handle-insert-file-contents) (tramp-handle-write-region): No special handling for - `last-coding-system-used, because this is done in + `last-coding-system-used', because this is done in `tramp-accept-process-output' now. (tramp-accept-process-output): New defun. (tramp-process-one-action, tramp-process-one-multi-action) @@ -23199,7 +23199,7 @@ * net/tramp-smb.el: Remove defvar of `last-coding-system-used' in the XEmacs case; not necessary anymore. (tramp-smb-handle-write-region): No special handling for - `last-coding-system-used, because this is done in + `last-coding-system-used', because this is done in `tramp-accept-process-output' now. (tramp-smb-wait-for-output): Call `tramp-accept-process-output'. @@ -24623,7 +24623,7 @@ (tree-widget-theme, tree-widget-image-properties-emacs) (tree-widget-image-properties-xemacs, tree-widget-create-image) (tree-widget-image-formats, tree-widget-control) - (tree-widget-empty-control, tree-widget-leaf-control + (tree-widget-empty-control, tree-widget-leaf-control) (tree-widget-guide, tree-widget-end-guide, tree-widget-no-guide) (tree-widget-handle, tree-widget-no-handle, tree-widget-p) (tree-widget-keep, tree-widget-after-toggle-functions) @@ -25831,8 +25831,7 @@ (ebrowse-draw-member-buffer-class-line, ebrowse-draw-member-long-fn) (ebrowse-draw-member-short-fn): Use renamed ebrowse faces. - * progmodes/antlr-mode.el (antlr-default, antlr-keyword, - antlr-syntax) + * progmodes/antlr-mode.el (antlr-default, antlr-keyword, antlr-syntax) (antlr-ruledef, antlr-tokendef, antlr-ruleref, antlr-tokenref) (antlr-literal): Remove "-face" suffix and "font-lock-" from face names. @@ -27770,7 +27769,7 @@ * progmodes/make-mode.el (makefile-add-this-line-targets): Simplify and integrate into `makefile-pickup-targets'. (makefile-add-this-line-macro): Simplify and integrate into - `makefile-pickup-macros. + `makefile-pickup-macros'. (makefile-pickup-filenames-as-targets): Simplify. (makefile-previous-dependency, makefile-match-dependency): Don't stumble over `::'. @@ -32755,7 +32754,7 @@ Adrian Aichner . * net/tramp-smb.el (tramp-smb-file-name-handler-alist): Add entry for - `substitute-in-file-name. + `substitute-in-file-name'. (tramp-smb-handle-substitute-in-file-name): New defun. (tramp-smb-advice-PC-do-completion): Delete advice. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/Makefile.in --- a/lisp/Makefile.in Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/Makefile.in Sun Jul 15 02:05:20 2007 +0000 @@ -239,7 +239,7 @@ $(lisp)/mh-e/mh-xface.el mh-autoloads: $(lisp)/mh-e/mh-loaddefs.el -$(lisp)/mh-e/mh-loaddefs.el: $(MH_E_SRC) +$(lisp)/mh-e/mh-loaddefs.el: $(lisp)/subdirs.el $(MH_E_SRC) echo ";;; mh-loaddefs.el --- automatically extracted autoloads" > $@ echo "" >> $@ echo ";; Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc." >> $@ @@ -275,6 +275,9 @@ # an up-to-date copy of loaddefs.el that is uncorrupted by # local changes. (Because loaddefs.el is an automatically generated # file, we don't want to store it in the source repository). +# +# The chmod +w is to handle env var CVSREAD=1. Files named +# are identified by being the value of `generated-autoload-file'. bootstrap-prepare: if test -x $(EMACS); then \ @@ -282,6 +285,9 @@ else \ cp $(lisp)/ldefs-boot.el $(lisp)/loaddefs.el; \ fi + chmod +w $(lisp)/loaddefs.el \ + $(lisp)/ps-print.el \ + $(lisp)/emacs-lisp/cl-loaddefs.el maintainer-clean: distclean cd $(lisp); rm -f *.elc */*.elc $(AUTOGENEL) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/add-log.el --- a/lisp/add-log.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/add-log.el Sun Jul 15 02:05:20 2007 +0000 @@ -695,7 +695,8 @@ (setq left-margin 8 fill-column 74 indent-tabs-mode t - tab-width 8) + tab-width 8 + show-trailing-whitespace t) (set (make-local-variable 'fill-paragraph-function) 'change-log-fill-paragraph) (set (make-local-variable 'indent-line-function) 'change-log-indent) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/autoinsert.el --- a/lisp/autoinsert.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/autoinsert.el Sun Jul 15 02:05:20 2007 +0000 @@ -188,7 +188,7 @@ \;; This file 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 2, or (at your option) +\;; the Free Software Foundation; either version 3, or (at your option) \;; any later version. \;; This file is distributed in the hope that it will be useful, diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/autorevert.el --- a/lisp/autorevert.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/autorevert.el Sun Jul 15 02:05:20 2007 +0000 @@ -447,20 +447,21 @@ (defun auto-revert-tail-handler () (let ((size (nth 7 (file-attributes buffer-file-name))) (modified (buffer-modified-p)) - buffer-read-only ; ignore + (inhibit-read-only t) ; Ignore. (file buffer-file-name) - buffer-file-name) ; ignore that file has changed + (buffer-file-name nil)) ; Ignore that file has changed. (when (> size auto-revert-tail-pos) + (run-hooks 'before-revert-hook) (undo-boundary) (save-restriction (widen) (save-excursion (goto-char (point-max)) (insert-file-contents file nil auto-revert-tail-pos size))) - (run-mode-hooks 'after-revert-hook) + (run-hooks 'after-revert-hook) (undo-boundary) (setq auto-revert-tail-pos size) - (set-buffer-modified-p modified))) + (restore-buffer-modified-p modified))) (set-visited-file-modtime)) (defun auto-revert-buffers () @@ -534,5 +535,5 @@ (run-hooks 'auto-revert-load-hook) -;;; arch-tag: f6bcb07b-4841-477e-9e44-b18678e58876 +;; arch-tag: f6bcb07b-4841-477e-9e44-b18678e58876 ;;; autorevert.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/bookmark.el --- a/lisp/bookmark.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/bookmark.el Sun Jul 15 02:05:20 2007 +0000 @@ -240,12 +240,13 @@ ;; Read the help on all of these functions for details... ;;;###autoload (define-key bookmark-map "x" 'bookmark-set) -;;;###autoload (define-key bookmark-map "m" 'bookmark-set) ; "m" for "mark" +;;;###autoload (define-key bookmark-map "m" 'bookmark-set) ;"m"ark ;;;###autoload (define-key bookmark-map "j" 'bookmark-jump) -;;;###autoload (define-key bookmark-map "g" 'bookmark-jump) ; "g" for "go" +;;;###autoload (define-key bookmark-map "g" 'bookmark-jump) ;"g"o +;;;###autoload (define-key bookmark-map "o" 'bookmark-jump-other-window) ;;;###autoload (define-key bookmark-map "i" 'bookmark-insert) ;;;###autoload (define-key bookmark-map "e" 'edit-bookmarks) -;;;###autoload (define-key bookmark-map "f" 'bookmark-insert-location) ; "f" for "find" +;;;###autoload (define-key bookmark-map "f" 'bookmark-insert-location) ;"f"ind ;;;###autoload (define-key bookmark-map "r" 'bookmark-rename) ;;;###autoload (define-key bookmark-map "d" 'bookmark-delete) ;;;###autoload (define-key bookmark-map "l" 'bookmark-load) @@ -1083,6 +1084,27 @@ (bookmark-show-annotation bookmark))))) +;;;###autoload +(defun bookmark-jump-other-window (bookmark) + "Jump to BOOKMARK (a point in some file) in another window. +See `bookmark-jump'." + (interactive + (let ((bkm (bookmark-completing-read "Jump to bookmark (in another window)" + bookmark-current-bookmark))) + (if (> emacs-major-version 21) + (list bkm) bkm))) + (when bookmark + (bookmark-maybe-historicize-string bookmark) + (let ((cell (bookmark-jump-noselect bookmark))) + (and cell + (switch-to-buffer-other-window (car cell)) + (goto-char (cdr cell)) + (if bookmark-automatically-show-annotations + ;; if there is an annotation for this bookmark, + ;; show it in a buffer. + (bookmark-show-annotation bookmark)))))) + + (defun bookmark-file-or-variation-thereof (file) "Return FILE (a string) if it exists, or return a reasonable variation of FILE if that exists. Reasonable variations are checked diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-aent.el --- a/lisp/calc/calc-aent.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-aent.el Sun Jul 15 02:05:20 2007 +0000 @@ -100,7 +100,7 @@ (cond ((and (consp str) (not (symbolp (car str)))) (let ((calc-language nil) - (math-expr-opers math-standard-opers) + (math-expr-opers (math-standard-ops)) (calc-internal-prec 12) (calc-word-size 32) (calc-symbolic-mode nil) @@ -254,7 +254,7 @@ (interactive "P") (calc-wrapper (let ((calc-language (if prefix nil calc-language)) - (math-expr-opers (if prefix math-standard-opers math-expr-opers))) + (math-expr-opers (if prefix (math-standard-ops) (math-expr-ops)))) (calc-alg-entry (and auto (char-to-string last-command-char)))))) (defvar calc-alg-entry-history nil @@ -876,7 +876,10 @@ calcFunc-eq calcFunc-neq)) (defun math-read-expr-level (exp-prec &optional exp-term) - (let* ((x (math-read-factor)) (first t) op op2) + (let* ((math-expr-opers (math-expr-ops)) + (x (math-read-factor)) + (first t) + op op2) (while (and (or (and calc-user-parse-table (setq op (calc-check-user-syntax x exp-prec)) (setq x op @@ -1121,7 +1124,8 @@ (assoc math-expr-data '(("(") ("[") ("{")))))) (defun math-read-factor () - (let (op) + (let ((math-expr-opers (math-expr-ops)) + op) (cond ((eq math-exp-token 'number) (let ((num (math-read-number math-expr-data))) (if (not num) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-bin.el --- a/lisp/calc/calc-bin.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-bin.el Sun Jul 15 02:05:20 2007 +0000 @@ -32,6 +32,17 @@ (require 'calc-ext) (require 'calc-macs) +;;; Some useful numbers +(defconst math-bignum-logb-digit-size + (eval-when-compile (logb math-bignum-digit-size)) + "The logb of the size of a bignum digit. +This is the largest value of B such that 2^B is less than +the size of a Calc bignum digit.") + +(defconst math-bignum-digit-power-of-two + (eval-when-compile (expt 2 (logb math-bignum-digit-size))) + "The largest power of 2 less than the size of a Calc bignum digit.") + ;;; b-prefix binary commands. (defun calc-and (n) @@ -297,11 +308,11 @@ (defun math-and-bignum (a b) ; [l l l] (and a b - (let ((qa (math-div-bignum-digit a 512)) - (qb (math-div-bignum-digit b 512))) + (let ((qa (math-div-bignum-digit a math-bignum-digit-power-of-two)) + (qb (math-div-bignum-digit b math-bignum-digit-power-of-two))) (math-mul-bignum-digit (math-and-bignum (math-norm-bignum (car qa)) (math-norm-bignum (car qb))) - 512 + math-bignum-digit-power-of-two (logand (cdr qa) (cdr qb)))))) (defun calcFunc-or (a b &optional w) ; [I I I] [Public] @@ -324,11 +335,11 @@ (defun math-or-bignum (a b) ; [l l l] (and (or a b) - (let ((qa (math-div-bignum-digit a 512)) - (qb (math-div-bignum-digit b 512))) + (let ((qa (math-div-bignum-digit a math-bignum-digit-power-of-two)) + (qb (math-div-bignum-digit b math-bignum-digit-power-of-two))) (math-mul-bignum-digit (math-or-bignum (math-norm-bignum (car qa)) (math-norm-bignum (car qb))) - 512 + math-bignum-digit-power-of-two (logior (cdr qa) (cdr qb)))))) (defun calcFunc-xor (a b &optional w) ; [I I I] [Public] @@ -351,11 +362,11 @@ (defun math-xor-bignum (a b) ; [l l l] (and (or a b) - (let ((qa (math-div-bignum-digit a 512)) - (qb (math-div-bignum-digit b 512))) + (let ((qa (math-div-bignum-digit a math-bignum-digit-power-of-two)) + (qb (math-div-bignum-digit b math-bignum-digit-power-of-two))) (math-mul-bignum-digit (math-xor-bignum (math-norm-bignum (car qa)) (math-norm-bignum (car qb))) - 512 + math-bignum-digit-power-of-two (logxor (cdr qa) (cdr qb)))))) (defun calcFunc-diff (a b &optional w) ; [I I I] [Public] @@ -378,11 +389,11 @@ (defun math-diff-bignum (a b) ; [l l l] (and a - (let ((qa (math-div-bignum-digit a 512)) - (qb (math-div-bignum-digit b 512))) + (let ((qa (math-div-bignum-digit a math-bignum-digit-power-of-two)) + (qb (math-div-bignum-digit b math-bignum-digit-power-of-two))) (math-mul-bignum-digit (math-diff-bignum (math-norm-bignum (car qa)) (math-norm-bignum (car qb))) - 512 + math-bignum-digit-power-of-two (logand (cdr qa) (lognot (cdr qb))))))) (defun calcFunc-not (a &optional w) ; [I I] [Public] @@ -402,14 +413,15 @@ w)))))) (defun math-not-bignum (a w) ; [l l] - (let ((q (math-div-bignum-digit a 512))) - (if (<= w 9) + (let ((q (math-div-bignum-digit a math-bignum-digit-power-of-two))) + (if (<= w math-bignum-logb-digit-size) (list (logand (lognot (cdr q)) (1- (lsh 1 w)))) (math-mul-bignum-digit (math-not-bignum (math-norm-bignum (car q)) - (- w 9)) - 512 - (logxor (cdr q) 511))))) + (- w math-bignum-logb-digit-size)) + math-bignum-digit-power-of-two + (logxor (cdr q) + (1- math-bignum-digit-power-of-two)))))) (defun calcFunc-lsh (a &optional n w) ; [I I] [Public] (setq a (math-trunc a) @@ -510,8 +522,8 @@ (math-sub a (math-power-of-2 (- w))))) ((Math-negp a) (math-normalize (cons 'bigpos (math-binary-arg a w)))) - ((and (integerp a) (< a 1000000)) - (if (>= w 20) + ((and (integerp a) (< a math-small-integer-size)) + (if (> w (logb math-small-integer-size)) a (logand a (1- (lsh 1 w))))) (t @@ -523,13 +535,13 @@ (defalias 'calcFunc-clip 'math-clip) (defun math-clip-bignum (a w) ; [l l] - (let ((q (math-div-bignum-digit a 512))) - (if (<= w 9) + (let ((q (math-div-bignum-digit a math-bignum-digit-power-of-two))) + (if (<= w math-bignum-logb-digit-size) (list (logand (cdr q) (1- (lsh 1 w)))) (math-mul-bignum-digit (math-clip-bignum (math-norm-bignum (car q)) - (- w 9)) - 512 + (- w math-bignum-logb-digit-size)) + math-bignum-digit-power-of-two (cdr q))))) (defvar math-max-digits-cache nil) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-comb.el --- a/lisp/calc/calc-comb.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-comb.el Sun Jul 15 02:05:20 2007 +0000 @@ -294,6 +294,19 @@ ;;; Factorial and related functions. +(defconst math-small-factorial-table + (eval-when-compile + (vector 1 1 2 6 24 120 720 5040 40320 362880 3628800 39916800 + (math-read-number-simple "479001600") + (math-read-number-simple "6227020800") + (math-read-number-simple "87178291200") + (math-read-number-simple "1307674368000") + (math-read-number-simple "20922789888000") + (math-read-number-simple "355687428096000") + (math-read-number-simple "6402373705728000") + (math-read-number-simple "121645100408832000") + (math-read-number-simple "2432902008176640000")))) + (defun calcFunc-fact (n) ; [I I] [F F] [Public] (let (temp) (cond ((Math-integer-negp n) @@ -302,14 +315,7 @@ (math-reject-arg n 'range))) ((integerp n) (if (<= n 20) - (aref '[1 1 2 6 24 120 720 5040 40320 362880 - (bigpos 800 628 3) (bigpos 800 916 39) - (bigpos 600 1 479) (bigpos 800 20 227 6) - (bigpos 200 291 178 87) (bigpos 0 368 674 307 1) - (bigpos 0 888 789 922 20) (bigpos 0 96 428 687 355) - (bigpos 0 728 705 373 402 6) - (bigpos 0 832 408 100 645 121) - (bigpos 0 640 176 8 902 432 2)] n) + (aref math-small-factorial-table n) (math-factorial-iter (1- n) 2 1))) ((and (math-messy-integerp n) (Math-lessp n 100)) @@ -551,9 +557,9 @@ nil (if (Math-integerp var-RandSeed) (let* ((seed (math-sub 161803 var-RandSeed)) - (mj (1+ (math-mod seed '(bigpos 0 0 1)))) - (mk (1+ (math-mod (math-quotient seed '(bigpos 0 0 1)) - '(bigpos 0 0 1)))) + (mj (1+ (math-mod seed 1000000))) + (mk (1+ (math-mod (math-quotient seed 1000000) + 1000000))) (i 0)) (setq math-random-table (cons 'vec (make-list 55 mj))) (while (<= (setq i (1+ i)) 54) @@ -601,7 +607,8 @@ ;;; Avoid various pitfalls that may lurk in the built-in (random) function! ;;; Shuffling algorithm from Numerical Recipes, section 7.1. (defvar math-random-last) -(defun math-random-digit () +(defun math-random-three-digit-number () + "Return a random three digit number." (let (i) (or (and (boundp 'var-RandSeed) (eq var-RandSeed math-last-RandSeed)) (math-init-random-base)) @@ -621,17 +628,17 @@ ;;; Produce an N-digit random integer. (defun math-random-digits (n) - (cond ((<= n 6) - (math-scale-right (+ (* (math-random-digit) 1000) (math-random-digit)) - (- 6 n))) - (t (let* ((slop (% (- 900003 n) 3)) - (i (/ (+ n slop) 3)) - (digs nil)) - (while (> i 0) - (setq digs (cons (math-random-digit) digs) - i (1- i))) - (math-normalize (math-scale-right (cons 'bigpos digs) - slop)))))) + "Produce a random N digit integer." + (let* ((slop (% (- 3 (% n 3)) 3)) + (i (/ (+ n slop) 3)) + (rnum 0)) + (while (> i 0) + (setq rnum + (math-add + (math-random-three-digit-number) + (math-mul rnum 1000))) + (setq i (1- i))) + (math-normalize (math-scale-right rnum slop)))) ;;; Produce a uniformly-distributed random float 0 <= N < 1. (defun math-random-float () @@ -802,7 +809,7 @@ (error "Argument must be an integer")) ((Math-integer-negp n) '(nil)) - ((Math-natnum-lessp n '(bigpos 0 0 8)) + ((Math-natnum-lessp n 8000000) (setq n (math-fixnum n)) (let ((i -1) v) (while (and (> (% n (setq v (aref math-primes-table @@ -815,15 +822,17 @@ ((not (equal n (car math-prime-test-cache))) (cond ((= (% (nth 1 n) 2) 0) '(nil 2)) ((= (% (nth 1 n) 5) 0) '(nil 5)) - (t (let ((dig (cdr n)) (sum 0)) - (while dig - (if (cdr dig) - (setq sum (% (+ (+ sum (car dig)) - (* (nth 1 dig) 1000)) - 111111) - dig (cdr (cdr dig))) - (setq sum (% (+ sum (car dig)) 111111) - dig nil))) + (t (let ((q n) (sum 0)) + (while (not (eq q 0)) + (setq sum (% + (+ + sum + (calcFunc-mod + q 1000000)) + 111111)) + (setq q + (math-quotient + q 1000000))) (cond ((= (% sum 3) 0) '(nil 3)) ((= (% sum 7) 0) '(nil 7)) ((= (% sum 11) 0) '(nil 11)) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-embed.el --- a/lisp/calc/calc-embed.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-embed.el Sun Jul 15 02:05:20 2007 +0000 @@ -403,7 +403,7 @@ (let ((val (save-excursion (set-buffer (aref info 1)) (let ((calc-language nil) - (math-expr-opers math-standard-opers)) + (math-expr-opers (math-standard-ops))) (math-read-expr str))))) (if (eq (car-safe val) 'error) (progn diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-ext.el --- a/lisp/calc/calc-ext.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-ext.el Sun Jul 15 02:05:20 2007 +0000 @@ -1878,8 +1878,19 @@ (last-prec (intern (concat (symbol-name name) "-last-prec"))) (last-val (intern (concat (symbol-name name) "-last")))) (list 'progn - (list 'defvar cache-prec (if init (math-numdigs (nth 1 init)) -100)) - (list 'defvar cache-val (list 'quote init)) +; (list 'defvar cache-prec (if init (math-numdigs (nth 1 init)) -100)) + (list 'defvar cache-prec + `(cond + ((consp ,init) (math-numdigs (nth 1 ,init))) + (,init + (nth 1 (math-numdigs (eval ,init)))) + (t + -100))) + (list 'defvar cache-val + `(cond + ((consp ,init) ,init) + (,init (eval ,init)) + (t ,init))) (list 'defvar last-prec -100) (list 'defvar last-val nil) (list 'setq 'math-cache-list @@ -1914,7 +1925,12 @@ (put 'math-defcache 'lisp-indent-hook 2) ;;; Betcha didn't know that pi = 16 atan(1/5) - 4 atan(1/239). [F] [Public] -(math-defcache math-pi (float (bigpos 463 238 793 589 653 592 141 3) -21) +(defconst math-approx-pi + (eval-when-compile + (math-read-number-simple "3.141592653589793238463")) + "An approximation for pi.") + +(math-defcache math-pi math-approx-pi (math-add-float (math-mul-float '(float 16 0) (math-arctan-raw '(float 2 -1))) (math-mul-float '(float -4 0) @@ -1945,7 +1961,11 @@ (math-defcache math-sqrt-two-pi nil (math-sqrt-float (math-two-pi))) -(math-defcache math-sqrt-e (float (bigpos 849 146 128 700 270 721 648 1) -21) +(defconst math-approx-sqrt-e + (eval-when-compile (math-read-number-simple "1.648721270700128146849")) + "An approximation for sqrt(3).") + +(math-defcache math-sqrt-e math-approx-sqrt-e (math-add-float '(float 1 0) (math-exp-minus-1-raw '(float 5 -1)))) (math-defcache math-e nil @@ -1955,10 +1975,14 @@ (math-mul-float (math-add-float (math-sqrt-raw '(float 5 0)) '(float 1 0)) '(float 5 -1))) -(math-defcache math-gamma-const nil - '(float (bigpos 495 467 917 632 470 369 709 646 776 267 677 848 348 672 - 057 988 235 399 359 593 421 310 024 824 900 120 065 606 - 328 015 649 156 772 5) -100)) +(defconst math-approx-gamma-const + (eval-when-compile + (math-read-number-simple + "0.5772156649015328606065120900824024310421593359399235988057672348848677267776646709369470632917467495")) + "An approximation for gamma.") + +(math-defcache math-gamma-const nil + math-approx-gamma-const) (defun math-half-circle (symb) (if (eq calc-angle-mode 'rad) @@ -2202,7 +2226,7 @@ (defun math-fixnum-big (a) (if (cdr a) - (+ (car a) (* (math-fixnum-big (cdr a)) 1000)) + (+ (car a) (* (math-fixnum-big (cdr a)) math-bignum-digit-size)) (car a))) (defvar math-simplify-only nil) @@ -2960,7 +2984,7 @@ (defun math-read-plain-expr (exp-str &optional error-check) (let* ((calc-language nil) - (math-expr-opers math-standard-opers) + (math-expr-opers (math-standard-ops)) (val (math-read-expr exp-str))) (and error-check (eq (car-safe val) 'error) @@ -3116,7 +3140,7 @@ (concat (substring (symbol-name (car a)) 9) "(" (math-vector-to-string (nth 1 a) t) ")")) (t - (let ((op (math-assq2 (car a) math-standard-opers))) + (let ((op (math-assq2 (car a) (math-standard-ops)))) (cond ((and op (= (length a) 3)) (if (> prec (min (nth 2 op) (nth 3 op))) (concat "(" (math-format-flat-expr a 0) ")") diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-forms.el --- a/lisp/calc/calc-forms.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-forms.el Sun Jul 15 02:05:20 2007 +0000 @@ -544,6 +544,14 @@ (setcdr math-fd-dt nil)) fmt)))) +(defconst math-julian-date-beginning '(float 17214235 -1) + "The beginning of the Julian calendar, +as measured in the number of days before January 1 of the year 1AD.") + +(defconst math-julian-date-beginning-int 1721424 + "The beginning of the Julian calendar, +as measured in the integer number of days before January 1 of the year 1AD.") + (defun math-format-date-part (x) (cond ((stringp x) x) @@ -558,9 +566,12 @@ ((eq x 'n) (math-format-number (math-floor math-fd-date))) ((eq x 'J) - (math-format-number (math-add math-fd-date '(float (bigpos 235 214 17) -1)))) + (math-format-number + (math-add math-fd-date math-julian-date-beginning))) ((eq x 'j) - (math-format-number (math-add (math-floor math-fd-date) '(bigpos 424 721 1)))) + (math-format-number (math-add + (math-floor math-fd-date) + math-julian-date-beginning-int))) ((eq x 'U) (math-format-number (nth 1 (math-date-parts math-fd-date 719164)))) ((progn @@ -935,9 +946,8 @@ 0 (if (or (eq this 'j) (math-integerp num)) - '(bigpos 424 721 1) - '(float (bigpos 235 214 17) - -1)))) + math-julian-date-beginning-int + math-julian-date-beginning))) hour (or (nth 3 num) hour) minute (or (nth 4 num) minute) second (or (nth 5 num) second) @@ -1146,14 +1156,14 @@ (defun calcFunc-julian (date &optional zone) (if (math-realp date) (list 'date (if (math-integerp date) - (math-sub date '(bigpos 424 721 1)) - (setq date (math-sub date '(float (bigpos 235 214 17) -1))) + (math-sub date math-julian-date-beginning-int) + (setq date (math-sub date math-julian-date-beginning)) (math-sub date (math-div (calcFunc-tzone zone date) '(float 864 2))))) (if (eq (car date) 'date) (math-add (nth 1 date) (if (math-integerp (nth 1 date)) - '(bigpos 424 721 1) - (math-add '(float (bigpos 235 214 17) -1) + math-julian-date-beginning-int + (math-add math-julian-date-beginning (math-div (calcFunc-tzone zone date) '(float 864 2))))) (math-reject-arg date 'datep)))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-funcs.el --- a/lisp/calc/calc-funcs.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-funcs.el Sun Jul 15 02:05:20 2007 +0000 @@ -147,7 +147,8 @@ (or (math-numberp x) (math-reject-arg x 'numberp)) (calcFunc-fact (math-add x -1))) -(defun math-gammap1-raw (x &optional fprec nfprec) ; compute gamma(1 + x) +(defun math-gammap1-raw (x &optional fprec nfprec) + "Compute gamma(1+X) to the appropriate precision." (or fprec (setq fprec (math-float calc-internal-prec) nfprec (math-float (- calc-internal-prec)))) @@ -567,42 +568,54 @@ ((Math-lessp '(float 8 0) (math-abs-approx x)) (let* ((z (math-div '(float 8 0) x)) (y (math-sqr z)) - (xx (math-add x '(float (bigneg 164 398 785) -9))) + (xx (math-add x + (eval-when-compile + (math-read-number-simple "-0.785398164")))) (a1 (math-poly-eval y - '((float (bigpos 211 887 093 2) -16) - (float (bigneg 639 370 073 2) -15) - (float (bigpos 407 510 734 2) -14) - (float (bigneg 627 628 098 1) -12) - (float 1 0)))) + (eval-when-compile + (list + (math-read-number-simple "0.0000002093887211") + (math-read-number-simple "-0.000002073370639") + (math-read-number-simple "0.00002734510407") + (math-read-number-simple "-0.001098628627") + '(float 1 0))))) (a2 (math-poly-eval y - '((float (bigneg 152 935 934) -16) - (float (bigpos 161 095 621 7) -16) - (float (bigneg 651 147 911 6) -15) - (float (bigpos 765 488 430 1) -13) - (float (bigneg 995 499 562 1) -11)))) + (eval-when-compile + (list + (math-read-number-simple "-0.0000000934935152") + (math-read-number-simple "0.0000007621095161") + (math-read-number-simple "-0.000006911147651") + (math-read-number-simple "0.0001430488765") + (math-read-number-simple "-0.01562499995"))))) (sc (math-sin-cos-raw xx))) (if yflag (setq sc (cons (math-neg (cdr sc)) (car sc)))) (math-mul (math-sqrt - (math-div '(float (bigpos 722 619 636) -9) x)) + (math-div (eval-when-compile + (math-read-number-simple "0.636619722")) + x)) (math-sub (math-mul (cdr sc) a1) (math-mul (car sc) (math-mul z a2)))))) (t (let ((y (math-sqr x))) (math-div (math-poly-eval y - '((float (bigneg 456 052 849 1) -7) - (float (bigpos 017 233 739 7) -5) - (float (bigneg 418 442 121 1) -2) - (float (bigpos 407 196 516 6) -1) - (float (bigneg 354 590 362 13) 0) - (float (bigpos 574 490 568 57) 0))) + (eval-when-compile + (list + (math-read-number-simple "-184.9052456") + (math-read-number-simple "77392.33017") + (math-read-number-simple "-11214424.18") + (math-read-number-simple "651619640.7") + (math-read-number-simple "-13362590354.0") + (math-read-number-simple "57568490574.0")))) (math-poly-eval y - '((float 1 0) - (float (bigpos 712 532 678 2) -7) - (float (bigpos 853 264 927 5) -5) - (float (bigpos 718 680 494 9) -3) - (float (bigpos 985 532 029 1) 0) - (float (bigpos 411 490 568 57) 0)))))))) + (eval-when-compile + (list + '(float 1 0) + (math-read-number-simple "267.8532712") + (math-read-number-simple "59272.64853") + (math-read-number-simple "9494680.718") + (math-read-number-simple "1029532985.0") + (math-read-number-simple "57568490411.0"))))))))) (defun math-besJ1 (x &optional yflag) (cond ((and (math-negp (calcFunc-re x)) (not yflag)) @@ -610,25 +623,33 @@ ((Math-lessp '(float 8 0) (math-abs-approx x)) (let* ((z (math-div '(float 8 0) x)) (y (math-sqr z)) - (xx (math-add x '(float (bigneg 491 194 356 2) -9))) + (xx (math-add x (eval-when-compile + (math-read-number-simple "-2.356194491")))) (a1 (math-poly-eval y - '((float (bigneg 019 337 240) -15) - (float (bigpos 174 520 457 2) -15) - (float (bigneg 496 396 516 3) -14) - (float 183105 -8) - (float 1 0)))) + (eval-when-compile + (list + (math-read-number-simple "-0.000000240337019") + (math-read-number-simple "0.000002457520174") + (math-read-number-simple "-0.00003516396496") + '(float 183105 -8) + '(float 1 0))))) (a2 (math-poly-eval y - '((float (bigpos 412 787 105) -15) - (float (bigneg 987 228 88) -14) - (float (bigpos 096 199 449 8) -15) - (float (bigneg 873 690 002 2) -13) - (float (bigpos 995 499 687 4) -11)))) + (eval-when-compile + (list + (math-read-number-simple "0.000000105787412") + (math-read-number-simple "-0.00000088228987") + (math-read-number-simple "0.000008449199096") + (math-read-number-simple "-0.0002002690873") + (math-read-number-simple "0.04687499995"))))) (sc (math-sin-cos-raw xx))) (if yflag (setq sc (cons (math-neg (cdr sc)) (car sc))) (if (math-negp x) (setq sc (cons (math-neg (car sc)) (math-neg (cdr sc)))))) - (math-mul (math-sqrt (math-div '(float (bigpos 722 619 636) -9) x)) + (math-mul (math-sqrt (math-div + (eval-when-compile + (math-read-number-simple "0.636619722")) + x)) (math-sub (math-mul (cdr sc) a1) (math-mul (car sc) (math-mul z a2)))))) (t @@ -636,20 +657,23 @@ (math-mul x (math-div (math-poly-eval y - '((float (bigneg 606 036 016 3) -8) - (float (bigpos 826 044 157) -4) - (float (bigneg 439 611 972 2) -3) - (float (bigpos 531 968 423 2) -1) - (float (bigneg 235 059 895 7) 0) - (float (bigpos 232 614 362 72) 0))) + (eval-when-compile + (list + (math-read-number-simple "-30.16036606") + (math-read-number-simple "15704.4826") + (math-read-number-simple "-2972611.439") + (math-read-number-simple "242396853.1") + (math-read-number-simple "-7895059235.0") + (math-read-number-simple "72362614232.0")))) (math-poly-eval y - '((float 1 0) - (float (bigpos 397 991 769 3) -7) - (float (bigpos 394 743 944 9) -5) - (float (bigpos 474 330 858 1) -2) - (float (bigpos 178 535 300 2) 0) - (float (bigpos 442 228 725 144) - 0))))))))) + (eval-when-compile + (list + '(float 1 0) + (math-read-number-simple "376.9991397") + (math-read-number-simple "99447.43394") + (math-read-number-simple "18583304.74") + (math-read-number-simple "2300535178.0") + (math-read-number-simple "144725228442.0")))))))))) (defun calcFunc-besY (v x) (math-inexact-result) @@ -690,20 +714,25 @@ (let ((y (math-sqr x))) (math-add (math-div (math-poly-eval y - '((float (bigpos 733 622 284 2) -7) - (float (bigneg 757 792 632 8) -5) - (float (bigpos 129 988 087 1) -2) - (float (bigneg 036 598 123 5) -1) - (float (bigpos 065 834 062 7) 0) - (float (bigneg 389 821 957 2) 0))) + (eval-when-compile + (list + (math-read-number-simple "228.4622733") + (math-read-number-simple "-86327.92757") + (math-read-number-simple "10879881.29") + (math-read-number-simple "-512359803.6") + (math-read-number-simple "7062834065.0") + (math-read-number-simple "-2957821389.0")))) (math-poly-eval y - '((float 1 0) - (float (bigpos 244 030 261 2) -7) - (float (bigpos 647 472 474) -4) - (float (bigpos 438 466 189 7) -3) - (float (bigpos 648 499 452 7) -1) - (float (bigpos 269 544 076 40) 0)))) - (math-mul '(float (bigpos 772 619 636) -9) + (eval-when-compile + (list + '(float 1 0) + (math-read-number-simple "226.1030244") + (math-read-number-simple "47447.2647") + (math-read-number-simple "7189466.438") + (math-read-number-simple "745249964.8") + (math-read-number-simple "40076544269.0"))))) + (math-mul (eval-when-compile + (math-read-number-simple "0.636619772")) (math-mul (math-besJ0 x) (math-ln-raw x)))))) ((math-negp (calcFunc-re x)) (math-add (math-besJ0 (math-neg x) t) @@ -719,22 +748,26 @@ (math-mul x (math-div (math-poly-eval y - '((float (bigpos 935 937 511 8) -6) - (float (bigneg 726 922 237 4) -3) - (float (bigpos 551 264 349 7) -1) - (float (bigneg 139 438 153 5) 1) - (float (bigpos 439 527 127) 4) - (float (bigneg 943 604 900 4) 3))) + (eval-when-compile + (list + (math-read-number-simple "8511.937935") + (math-read-number-simple "-4237922.726") + (math-read-number-simple "734926455.1") + (math-read-number-simple "-51534381390.0") + (math-read-number-simple "1275274390000.0") + (math-read-number-simple "-4900604943000.0")))) (math-poly-eval y - '((float 1 0) - (float (bigpos 885 632 549 3) -7) - (float (bigpos 605 042 102) -3) - (float (bigpos 002 904 245 2) -2) - (float (bigpos 367 650 733 3) 0) - (float (bigpos 664 419 244 4) 2) - (float (bigpos 057 958 249) 5))))) - (math-mul '(float (bigpos 772 619 636) -9) - (math-sub (math-mul (math-besJ1 x) (math-ln-raw x)) + (eval-when-compile + (list + '(float 1 0) + (math-read-number-simple "354.9632885") + (math-read-number-simple "102042.605") + (math-read-number-simple "22459040.02") + (math-read-number-simple "3733650367.0") + (math-read-number-simple "424441966400.0") + (math-read-number-simple "24995805700000.0")))))) + (math-mul (eval-when-compile (math-read-number-simple "0.636619772")) + (math-sub (math-mul (math-besJ1 x) (math-ln-raw x)) (math-div 1 x)))))) ((math-negp (calcFunc-re x)) (math-neg @@ -799,16 +832,40 @@ (calcFunc-euler n '(float 5 -1))) (calcFunc-euler n '(frac 1 2)))))) -(defvar math-bernoulli-b-cache '((frac -174611 - (bigpos 0 200 291 698 662 857 802)) - (frac 43867 (bigpos 0 944 170 217 94 109 5)) - (frac -3617 (bigpos 0 880 842 622 670 10)) - (frac 1 (bigpos 600 249 724 74)) - (frac -691 (bigpos 0 368 674 307 1)) - (frac 1 (bigpos 160 900 47)) - (frac -1 (bigpos 600 209 1)) - (frac 1 30240) (frac -1 720) - (frac 1 12) 1 )) +(defvar math-bernoulli-b-cache + (eval-when-compile + (list + (list 'frac + -174611 + (math-read-number-simple "802857662698291200000")) + (list 'frac + 43867 + (math-read-number-simple "5109094217170944000")) + (list 'frac + -3617 + (math-read-number-simple "10670622842880000")) + (list 'frac + 1 + (math-read-number-simple "74724249600")) + (list 'frac + -691 + (math-read-number-simple "1307674368000")) + (list 'frac + 1 + (math-read-number-simple "47900160")) + (list 'frac + -1 + (math-read-number-simple "1209600")) + (list 'frac + 1 + 30240) + (list 'frac + -1 + 720) + (list 'frac + 1 + 12) + 1 ))) (defvar math-bernoulli-B-cache '((frac -174611 330) (frac 43867 798) (frac -3617 510) (frac 7 6) (frac -691 2730) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-lang.el --- a/lisp/calc/calc-lang.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-lang.el Sun Jul 15 02:05:20 2007 +0000 @@ -35,7 +35,7 @@ ;;; Alternate entry/display languages. (defun calc-set-language (lang &optional option no-refresh) - (setq math-expr-opers (or (get lang 'math-oper-table) math-standard-opers) + (setq math-expr-opers (or (get lang 'math-oper-table) (math-standard-ops)) math-expr-function-mapping (get lang 'math-function-table) math-expr-special-function-mapping (get lang 'math-special-function-table) math-expr-variable-mapping (get lang 'math-variable-table) @@ -1225,7 +1225,7 @@ h (1+ v) (1+ h) math-rb-v2) (string-match "<=\\|>=\\|\\+/-\\|!=\\|&&\\|||\\|:=\\|=>\\|." line h) (assoc (math-match-substring line 0) - math-standard-opers))) + (math-standard-ops)))) (and (>= (nth 2 widest) prec) (setq h (match-end 0))) (and (not (eq (string-match ",\\|;\\|\\.\\.\\|)\\|\\]\\|:" line h) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-math.el --- a/lisp/calc/calc-math.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-math.el Sun Jul 15 02:05:20 2007 +0000 @@ -310,15 +310,15 @@ (let* ((top (nthcdr (- len 2) a))) (math-isqrt-bignum-iter a - (math-scale-bignum-3 + (math-scale-bignum-digit-size (math-bignum-big (1+ (math-isqrt-small - (+ (* (nth 1 top) 1000) (car top))))) + (+ (* (nth 1 top) math-bignum-digit-size) (car top))))) (1- (/ len 2))))) (let* ((top (nth (1- len) a))) (math-isqrt-bignum-iter a - (math-scale-bignum-3 + (math-scale-bignum-digit-size (list (1+ (math-isqrt-small top))) (/ len 2))))))) @@ -341,14 +341,15 @@ (while (eq (car (setq a (cdr a))) 0)) (null a)))) -(defun math-scale-bignum-3 (a n) ; [L L S] +(defun math-scale-bignum-digit-size (a n) ; [L L S] (while (> n 0) (setq a (cons 0 a) n (1- n))) a) (defun math-isqrt-small (a) ; A > 0. [S S] - (let ((g (cond ((>= a 10000) 1000) + (let ((g (cond ((>= a 1000000) 10000) + ((>= a 10000) 1000) ((>= a 100) 100) (t 10))) g2) @@ -1717,10 +1718,20 @@ sum (math-lnp1-series nextsum (1+ n) nextx x)))) -(math-defcache math-ln-10 (float (bigpos 018 684 045 994 092 585 302 2) -21) +(defconst math-approx-ln-10 + (eval-when-compile + (math-read-number-simple "2.302585092994045684018")) + "An approximation for ln(10).") + +(math-defcache math-ln-10 math-approx-ln-10 (math-ln-raw-2 '(float 1 1))) -(math-defcache math-ln-2 (float (bigpos 417 309 945 559 180 147 693) -21) +(defconst math-approx-ln-2 + (eval-when-compile + (math-read-number-simple "0.693147180559945309417")) + "An approximation for ln(2).") + +(math-defcache math-ln-2 math-approx-ln-2 (math-ln-raw-3 (math-float '(frac 1 3)))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-misc.el --- a/lisp/calc/calc-misc.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-misc.el Sun Jul 15 02:05:20 2007 +0000 @@ -579,7 +579,7 @@ (defun math-div2-bignum (a) ; [l l] (if (cdr a) - (cons (+ (/ (car a) 2) (* (% (nth 1 a) 2) 500)) + (cons (+ (/ (car a) 2) (* (% (nth 1 a) 2) (/ math-bignum-digit-size 2))) (math-div2-bignum (cdr a))) (list (/ (car a) 2)))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-poly.el --- a/lisp/calc/calc-poly.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-poly.el Sun Jul 15 02:05:20 2007 +0000 @@ -982,10 +982,16 @@ (defun math-padded-polynomial (expr var deg) + "Return a polynomial as list of coefficients. +If EXPR is of the form \"a + bx + cx^2 + ...\" in the variable VAR, return +the list (a b c ...) with at least DEG elements, else return NIL." (let ((p (math-is-polynomial expr var deg))) (append p (make-list (- deg (length p)) 0)))) (defun math-partial-fractions (r den var) + "Return R divided by DEN expressed in partial fractions of VAR. +All whole factors of DEN have already been split off from R. +If no partial fraction representation can be found, return nil." (let* ((fden (calcFunc-factors den var)) (tdeg (math-polynomial-p den var)) (fp fden) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-prog.el --- a/lisp/calc/calc-prog.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-prog.el Sun Jul 15 02:05:20 2007 +0000 @@ -568,7 +568,7 @@ (set-buffer calc-buf) (let ((calc-user-parse-tables nil) (calc-language nil) - (math-expr-opers math-standard-opers) + (math-expr-opers (math-standard-ops)) (calc-hashes-used 0)) (math-read-expr (if (string-match ",[ \t]*\\'" str) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc-yank.el --- a/lisp/calc/calc-yank.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc-yank.el Sun Jul 15 02:05:20 2007 +0000 @@ -559,7 +559,7 @@ (aset str pos ?\,))) (switch-to-buffer calc-original-buffer) (let ((vals (let ((calc-language nil) - (math-expr-opers math-standard-opers)) + (math-expr-opers (math-standard-ops))) (and (string-match "[^\n\t ]" str) (math-read-exprs str))))) (when (eq (car-safe vals) 'error) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calc.el --- a/lisp/calc/calc.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calc.el Sun Jul 15 02:05:20 2007 +0000 @@ -401,6 +401,13 @@ :group 'calc :type '(choice (string) (sexp))) +(defcustom calc-multiplication-has-precedence + t + "*If non-nil, multiplication has precedence over division +in normal mode." + :group 'calc + :type 'boolean) + (defvar calc-bug-address "jay.p.belanger@gmail.com" "Address of the maintainer of Calc, for use by `report-calc-bug'.") @@ -2276,7 +2283,21 @@ - +(defconst math-bignum-digit-length 4 +; (truncate (/ (log10 (/ most-positive-fixnum 2)) 2)) + "The length of a \"digit\" in Calc bignums. +If a big integer is of the form (bigpos N0 N1 ...), this is the +length of the allowable Emacs integers N0, N1,... +The value of 2*10^(2*MATH-BIGNUM-DIGIT-LENGTH) must be less than the +largest Emacs integer.") + +(defconst math-bignum-digit-size + (expt 10 math-bignum-digit-length) + "An upper bound for the size of the \"digit\"s in Calc bignums.") + +(defconst math-small-integer-size + (expt math-bignum-digit-size 2) + "An upper bound for the size of \"small integer\"s in Calc.") ;;;; Arithmetic routines. @@ -2285,11 +2306,17 @@ ;;; following forms: ;;; ;;; integer An integer. For normalized numbers, this format -;;; is used only for -999999 ... 999999. +;;; is used only for +;;; negative math-small-integer-size + 1 to +;;; math-small-integer-size - 1 ;;; -;;; (bigpos N0 N1 N2 ...) A big positive integer, N0 + N1*1000 + N2*10^6 ... -;;; (bigneg N0 N1 N2 ...) A big negative integer, - N0 - N1*1000 ... -;;; Each digit N is in the range 0 ... 999. +;;; (bigpos N0 N1 N2 ...) A big positive integer, +;;; N0 + N1*math-bignum-digit-size +;;; + N2*(math-bignum-digit-size)^2 ... +;;; (bigneg N0 N1 N2 ...) A big negative integer, +;;; - N0 - N1*math-bignum-digit-size ... +;;; Each digit N is in the range +;;; 0 ... math-bignum-digit-size -1. ;;; Normalized, always at least three N present, ;;; and the most significant N is nonzero. ;;; @@ -2379,7 +2406,8 @@ (cond ((not (consp math-normalize-a)) (if (integerp math-normalize-a) - (if (or (>= math-normalize-a 1000000) (<= math-normalize-a -1000000)) + (if (or (>= math-normalize-a math-small-integer-size) + (<= math-normalize-a (- math-small-integer-size))) (math-bignum math-normalize-a) math-normalize-a) math-normalize-a)) @@ -2394,7 +2422,8 @@ math-normalize-a (cond ((cdr (cdr math-normalize-a)) (+ (nth 1 math-normalize-a) - (* (nth 2 math-normalize-a) 1000))) + (* (nth 2 math-normalize-a) + math-bignum-digit-size))) ((cdr math-normalize-a) (nth 1 math-normalize-a)) (t 0)))) ((eq (car math-normalize-a) 'bigneg) @@ -2408,7 +2437,8 @@ math-normalize-a (cond ((cdr (cdr math-normalize-a)) (- (+ (nth 1 math-normalize-a) - (* (nth 2 math-normalize-a) 1000)))) + (* (nth 2 math-normalize-a) + math-bignum-digit-size)))) ((cdr math-normalize-a) (- (nth 1 math-normalize-a))) (t 0)))) ((eq (car math-normalize-a) 'float) @@ -2528,7 +2558,8 @@ (defun math-bignum-big (a) ; [L s] (if (= a 0) nil - (cons (% a 1000) (math-bignum-big (/ a 1000))))) + (cons (% a math-bignum-digit-size) + (math-bignum-big (/ a math-bignum-digit-size))))) ;;; Build a normalized floating-point number. [F I S] @@ -2545,7 +2576,7 @@ (progn (while (= (car digs) 0) (setq digs (cdr digs) - exp (+ exp 3))) + exp (+ exp math-bignum-digit-length))) (while (= (% (car digs) 10) 0) (setq digs (math-div10-bignum digs) exp (1+ exp))) @@ -2563,7 +2594,8 @@ (defun math-div10-bignum (a) ; [l l] (if (cdr a) - (cons (+ (/ (car a) 10) (* (% (nth 1 a) 10) 100)) + (cons (+ (/ (car a) 10) (* (% (nth 1 a) 10) + (expt 10 (1- math-bignum-digit-length)))) (math-div10-bignum (cdr a))) (list (/ (car a) 10)))) @@ -2594,7 +2626,7 @@ (if (cdr a) (let* ((len (1- (length a))) (top (nth len a))) - (+ (* len 3) (cond ((>= top 100) 0) ((>= top 10) -1) (t -2)))) + (+ (* (1- len) math-bignum-digit-length) (math-numdigs top))) 0) (cond ((>= a 100) (+ (math-numdigs (/ a 1000)) 3)) ((>= a 10) 2) @@ -2615,24 +2647,24 @@ a (if (consp a) (cons (car a) (math-scale-left-bignum (cdr a) n)) - (if (>= n 3) - (if (or (>= a 1000) (<= a -1000)) + (if (>= n math-bignum-digit-length) + (if (or (>= a math-bignum-digit-size) + (<= a (- math-bignum-digit-size))) (math-scale-left (math-bignum a) n) - (math-scale-left (* a 1000) (- n 3))) - (if (= n 2) - (if (or (>= a 10000) (<= a -10000)) - (math-scale-left (math-bignum a) 2) - (* a 100)) - (if (or (>= a 100000) (<= a -100000)) - (math-scale-left (math-bignum a) 1) - (* a 10))))))) + (math-scale-left (* a math-bignum-digit-size) + (- n math-bignum-digit-length))) + (let ((sz (expt 10 (- (* 2 math-bignum-digit-length) n)))) + (if (or (>= a sz) (<= a (- sz))) + (math-scale-left (math-bignum a) n) + (* a (expt 10 n)))))))) (defun math-scale-left-bignum (a n) - (if (>= n 3) + (if (>= n math-bignum-digit-length) (while (>= (setq a (cons 0 a) - n (- n 3)) 3))) + n (- n math-bignum-digit-length)) + math-bignum-digit-length))) (if (> n 0) - (math-mul-bignum-digit a (if (= n 2) 100 10) 0) + (math-mul-bignum-digit a (expt 10 n) 0) a)) (defun math-scale-right (a n) ; [i i S] @@ -2644,21 +2676,20 @@ (if (= a 0) 0 (- (math-scale-right (- a) n))) - (if (>= n 3) - (while (and (> (setq a (/ a 1000)) 0) - (>= (setq n (- n 3)) 3)))) - (if (= n 2) - (/ a 100) - (if (= n 1) - (/ a 10) - a)))))) + (if (>= n math-bignum-digit-length) + (while (and (> (setq a (/ a math-bignum-digit-size)) 0) + (>= (setq n (- n math-bignum-digit-length)) + math-bignum-digit-length)))) + (if (> n 0) + (/ a (expt 10 n)) + a))))) (defun math-scale-right-bignum (a n) ; [L L S; l l S] - (if (>= n 3) - (setq a (nthcdr (/ n 3) a) - n (% n 3))) + (if (>= n math-bignum-digit-length) + (setq a (nthcdr (/ n math-bignum-digit-length) a) + n (% n math-bignum-digit-length))) (if (> n 0) - (cdr (math-mul-bignum-digit a (if (= n 2) 10 100) 0)) + (cdr (math-mul-bignum-digit a (expt 10 (- math-bignum-digit-length n)) 0)) a)) ;;; Multiply (with rounding) the integer A by 10^N. [I i S] @@ -2668,16 +2699,18 @@ ((consp a) (math-normalize (cons (car a) - (let ((val (if (< n -3) - (math-scale-right-bignum (cdr a) (- -3 n)) - (if (= n -2) - (math-mul-bignum-digit (cdr a) 10 0) - (if (= n -1) - (math-mul-bignum-digit (cdr a) 100 0) - (cdr a)))))) ; n = -3 - (if (and val (>= (car val) 500)) + (let ((val (if (< n (- math-bignum-digit-length)) + (math-scale-right-bignum + (cdr a) + (- (- math-bignum-digit-length) n)) + (if (< n 0) + (math-mul-bignum-digit + (cdr a) + (expt 10 (+ math-bignum-digit-length n)) 0) + (cdr a))))) ; n = -math-bignum-digit-length + (if (and val (>= (car val) (/ math-bignum-digit-size 2))) (if (cdr val) - (if (eq (car (cdr val)) 999) + (if (eq (car (cdr val)) (1- math-bignum-digit-size)) (math-add-bignum (cdr val) '(1)) (cons (1+ (car (cdr val))) (cdr (cdr val)))) '(1)) @@ -2696,7 +2729,7 @@ (and (not (or (consp a) (consp b))) (progn (setq a (+ a b)) - (if (or (<= a -1000000) (>= a 1000000)) + (if (or (<= a (- math-small-integer-size)) (>= a math-small-integer-size)) (math-bignum a) a))) (and (Math-zerop a) (not (eq (car-safe a) 'mod)) @@ -2745,21 +2778,22 @@ (let* ((a (copy-sequence a)) (aa a) (carry nil) sum) (while (and aa b) (if carry - (if (< (setq sum (+ (car aa) (car b))) 999) + (if (< (setq sum (+ (car aa) (car b))) + (1- math-bignum-digit-size)) (progn (setcar aa (1+ sum)) (setq carry nil)) - (setcar aa (+ sum -999))) - (if (< (setq sum (+ (car aa) (car b))) 1000) + (setcar aa (- sum (1- math-bignum-digit-size)))) + (if (< (setq sum (+ (car aa) (car b))) math-bignum-digit-size) (setcar aa sum) - (setcar aa (+ sum -1000)) + (setcar aa (- sum math-bignum-digit-size)) (setq carry t))) (setq aa (cdr aa) b (cdr b))) (if carry (if b (nconc a (math-add-bignum b '(1))) - (while (eq (car aa) 999) + (while (eq (car aa) (1- math-bignum-digit-size)) (setcar aa 0) (setq aa (cdr aa))) (if aa @@ -2783,17 +2817,17 @@ (progn (setcar aa (1- diff)) (setq borrow nil)) - (setcar aa (+ diff 999))) + (setcar aa (+ diff (1- math-bignum-digit-size)))) (if (>= (setq diff (- (car aa) (car b))) 0) (setcar aa diff) - (setcar aa (+ diff 1000)) + (setcar aa (+ diff math-bignum-digit-size)) (setq borrow t))) (setq aa (cdr aa) b (cdr b))) (if borrow (progn (while (eq (car aa) 0) - (setcar aa 999) + (setcar aa (1- math-bignum-digit-size)) (setq aa (cdr aa))) (if aa (progn @@ -2833,7 +2867,7 @@ (if (or (consp a) (consp b)) (math-add a (math-neg b)) (setq a (- a b)) - (if (or (<= a -1000000) (>= a 1000000)) + (if (or (<= a (- math-small-integer-size)) (>= a math-small-integer-size)) (math-bignum a) a))) @@ -2860,7 +2894,8 @@ (defun math-mul (a b) (or (and (not (consp a)) (not (consp b)) - (< a 1000) (> a -1000) (< b 1000) (> b -1000) + (< a math-bignum-digit-size) (> a (- math-bignum-digit-size)) + (< b math-bignum-digit-size) (> b (- math-bignum-digit-size)) (* a b)) (and (Math-zerop a) (not (eq (car-safe b) 'mod)) (if (Math-scalarp b) @@ -2929,14 +2964,14 @@ aa a) (while (progn (setcar ss (% (setq prod (+ (+ (car ss) (* (car aa) d)) - c)) 1000)) + c)) math-bignum-digit-size)) (setq aa (cdr aa))) - (setq c (/ prod 1000) + (setq c (/ prod math-bignum-digit-size) ss (or (cdr ss) (setcdr ss (list 0))))) - (if (>= prod 1000) + (if (>= prod math-bignum-digit-size) (if (cdr ss) - (setcar (cdr ss) (+ (/ prod 1000) (car (cdr ss)))) - (setcdr ss (list (/ prod 1000)))))) + (setcar (cdr ss) (+ (/ prod math-bignum-digit-size) (car (cdr ss)))) + (setcdr ss (list (/ prod math-bignum-digit-size)))))) sum))) ;;; Multiply digit list A by digit D. [L L D D; l l D D] @@ -2946,12 +2981,14 @@ (and (= d 1) a) (let* ((a (copy-sequence a)) (aa a) prod) (while (progn - (setcar aa (% (setq prod (+ (* (car aa) d) c)) 1000)) + (setcar aa + (% (setq prod (+ (* (car aa) d) c)) + math-bignum-digit-size)) (cdr aa)) (setq aa (cdr aa) - c (/ prod 1000))) - (if (>= prod 1000) - (setcdr aa (list (/ prod 1000)))) + c (/ prod math-bignum-digit-size))) + (if (>= prod math-bignum-digit-size) + (setcdr aa (list (/ prod math-bignum-digit-size)))) a)) (and (> c 0) (list c)))) @@ -2964,7 +3001,7 @@ (if (eq b 0) (math-reject-arg a "*Division by zero")) (if (or (consp a) (consp b)) - (if (and (natnump b) (< b 1000)) + (if (and (natnump b) (< b math-bignum-digit-size)) (let ((res (math-div-bignum-digit (cdr a) b))) (cons (math-normalize (cons (car a) (car res))) @@ -2983,7 +3020,7 @@ (if (= b 0) (math-reject-arg a "*Division by zero") (/ a b)) - (if (and (natnump b) (< b 1000)) + (if (and (natnump b) (< b math-bignum-digit-size)) (if (= b 0) (math-reject-arg a "*Division by zero") (math-normalize (cons (car a) @@ -2992,7 +3029,7 @@ (or (consp b) (setq b (math-bignum b))) (let* ((alen (1- (length a))) (blen (1- (length b))) - (d (/ 1000 (1+ (nth (1- blen) (cdr b))))) + (d (/ math-bignum-digit-size (1+ (nth (1- blen) (cdr b))))) (res (math-div-bignum-big (math-mul-bignum-digit (cdr a) d 0) (math-mul-bignum-digit (cdr b) d 0) alen blen))) @@ -3006,7 +3043,7 @@ (if (cdr b) (let* ((alen (length a)) (blen (length b)) - (d (/ 1000 (1+ (nth (1- blen) b)))) + (d (/ math-bignum-digit-size (1+ (nth (1- blen) b)))) (res (math-div-bignum-big (math-mul-bignum-digit a d 0) (math-mul-bignum-digit b d 0) alen blen))) @@ -3021,7 +3058,7 @@ (defun math-div-bignum-digit (a b) (if a (let* ((res (math-div-bignum-digit (cdr a) b)) - (num (+ (* (cdr res) 1000) (car a)))) + (num (+ (* (cdr res) math-bignum-digit-size) (car a)))) (cons (cons (/ num b) (car res)) (% num b))) @@ -3037,10 +3074,11 @@ (cons (car res2) (car res)) (cdr res2))))) -(defun math-div-bignum-part (a b blen) ; a < b*1000 [D.l l L] - (let* ((num (+ (* (or (nth blen a) 0) 1000) (or (nth (1- blen) a) 0))) +(defun math-div-bignum-part (a b blen) ; a < b*math-bignum-digit-size [D.l l L] + (let* ((num (+ (* (or (nth blen a) 0) math-bignum-digit-size) + (or (nth (1- blen) a) 0))) (den (nth (1- blen) b)) - (guess (min (/ num den) 999))) + (guess (min (/ num den) (1- math-bignum-digit-size)))) (math-div-bignum-try a b (math-mul-bignum-digit b guess 0) guess))) (defun math-div-bignum-try (a b c guess) ; [D.l l l D] @@ -3351,15 +3389,22 @@ (if a (let ((s "")) (while (cdr (cdr a)) - (setq s (concat (format "%06d" (+ (* (nth 1 a) 1000) (car a))) s) + (setq s (concat + (format + (concat "%0" + (number-to-string (* 2 math-bignum-digit-length)) + "d") + (+ (* (nth 1 a) math-bignum-digit-size) (car a))) s) a (cdr (cdr a)))) - (concat (int-to-string (+ (* (or (nth 1 a) 0) 1000) (car a))) s)) + (concat (int-to-string + (+ (* (or (nth 1 a) 0) math-bignum-digit-size) (car a))) s)) "0")) ;;; Parse a simple number in string form. [N X] [Public] (defun math-read-number (s) + "Convert the string S into a Calc number." (math-normalize (cond @@ -3370,7 +3415,7 @@ (> (length digs) 1) (eq (aref digs 0) ?0)) (math-read-number (concat "8#" digs)) - (if (<= (length digs) 6) + (if (<= (length digs) (* 2 math-bignum-digit-length)) (string-to-number digs) (cons 'bigpos (math-read-bignum digs)))))) @@ -3416,15 +3461,42 @@ ;; Syntax error! (t nil)))) +;;; Parse a very simple number, keeping all digits. +(defun math-read-number-simple (s) + "Convert the string S into a Calc number. +S is assumed to be a simple number (integer or float without an exponent) +and all digits are kept, regardless of Calc's current precision." + (cond + ;; Integer + ((string-match "^[0-9]+$" s) + (if (string-match "^\\(0+\\)" s) + (setq s (substring s (match-end 0)))) + (if (<= (length s) (* 2 math-bignum-digit-length)) + (string-to-number s) + (cons 'bigpos (math-read-bignum s)))) + ;; Minus sign + ((string-match "^-[0-9]+$" s) + (if (<= (length s) (1+ (* 2 math-bignum-digit-length))) + (string-to-number s) + (cons 'bigneg (math-read-bignum (substring s 1))))) + ;; Decimal point + ((string-match "^\\(-?[0-9]*\\)\\.\\([0-9]*\\)$" s) + (let ((int (math-match-substring s 1)) + (frac (math-match-substring s 2))) + (list 'float (math-read-number-simple (concat int frac)) + (- (length frac))))) + ;; Syntax error! + (t nil))) + (defun math-match-substring (s n) (if (match-beginning n) (substring s (match-beginning n) (match-end n)) "")) (defun math-read-bignum (s) ; [l X] - (if (> (length s) 3) - (cons (string-to-number (substring s -3)) - (math-read-bignum (substring s 0 -3))) + (if (> (length s) math-bignum-digit-length) + (cons (string-to-number (substring s (- math-bignum-digit-length))) + (math-read-bignum (substring s 0 (- math-bignum-digit-length)))) (list (string-to-number s)))) @@ -3467,8 +3539,6 @@ ( "!" calcFunc-fact 210 -1 ) ( "^" ^ 201 200 ) ( "**" ^ 201 200 ) - ( "*" * 196 195 ) - ( "2x" * 196 195 ) ( "/" / 190 191 ) ( "%" % 190 191 ) ( "\\" calcFunc-idiv 190 191 ) @@ -3492,7 +3562,31 @@ ( "::" calcFunc-condition 45 46 ) ( "=>" calcFunc-evalto 40 41 ) ( "=>" calcFunc-evalto 40 -1 ))) -(defvar math-expr-opers math-standard-opers) + +(defun math-standard-ops () + (if calc-multiplication-has-precedence + (cons + '( "*" * 196 195 ) + (cons + '( "2x" * 196 195 ) + math-standard-opers)) + (cons + '( "*" * 190 191 ) + (cons + '( "2x" * 190 191 ) + math-standard-opers)))) + +(defvar math-expr-opers (math-standard-ops)) + +(defun math-standard-ops-p () + (let ((meo (caar math-expr-opers))) + (and (stringp meo) + (string= meo "*")))) + +(defun math-expr-ops () + (if (math-standard-ops-p) + (math-standard-ops) + math-expr-opers)) ;;;###autoload (defun calc-grab-region (top bot arg) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calc/calccomp.el --- a/lisp/calc/calccomp.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calc/calccomp.el Sun Jul 15 02:05:20 2007 +0000 @@ -83,6 +83,7 @@ (defun math-compose-expr (a prec) (let ((math-compose-level (1+ math-compose-level)) + (math-expr-opers (math-expr-ops)) spfn) (cond ((or (and (eq a math-comp-selected) a) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calculator.el --- a/lisp/calculator.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calculator.el Sun Jul 15 02:05:20 2007 +0000 @@ -278,7 +278,7 @@ ("IC" acos (D (acos X)) x 6) ("IT" atan (D (atan X)) x 6) ("Q" sqrt sqrt x 7) - ("^" ^ expt 2 7) + ("^" ^ calculator-expt 2 7) ("!" ! calculator-fact x 7) (";" 1/ (/ 1 X) 1 7) ("_" - - 1 8) @@ -596,7 +596,8 @@ `+' and `-' can be used as either binary operators or prefix unary operators. Numbers can be entered with exponential notation using `e', except when using a non-decimal radix mode for input (in this case `e' -will be the hexadecimal digit). +will be the hexadecimal digit). If the result of a calculation is too +large (out of range for Emacs), the value of \"inf\" is returned. Here are the editing keys: * `RET' `=' evaluate the current expression @@ -1779,13 +1780,57 @@ (car calculator-last-opXY) (nth 1 calculator-last-opXY) x)) x)) +(defun calculator-integer-p (x) + "Non-nil if X is equal to an integer." + (condition-case nil + (= x (ftruncate x)) + (error nil))) + +(defun calculator-expt (x y) + "Compute X^Y, dealing with errors appropriately." + (condition-case + nil + (expt x y) + (domain-error 0.0e+NaN) + (range-error + (cond + ((and (< x 1.0) (> x -1.0)) + ;; For small x, the range error comes from large y. + 0.0) + ((and (> x 0.0) (< y 0.0)) + ;; For large positive x and negative y, the range error + ;; comes from large negative y. + 0.0) + ((and (> x 0.0) (> y 0.0)) + ;; For large positive x and positive y, the range error + ;; comes from large y. + 1.0e+INF) + ;; For the rest, x must be large and negative. + ;; The range errors come from large integer y. + ((< y 0.0) + 0.0) + ((oddp (truncate y)) + ;; If y is odd + -1.0e+INF) + (t + ;; + 1.0e+INF))) + (error 0.0e+NaN))) + (defun calculator-fact (x) "Simple factorial of X." - (let ((r (if (<= x 10) 1 1.0))) - (while (> x 0) - (setq r (* r (truncate x))) - (setq x (1- x))) - (+ 0.0 r))) + (if (and (>= x 0) + (calculator-integer-p x)) + (if (= (calculator-expt (/ x 3.0) x) 1.0e+INF) + 1.0e+INF + (let ((r (if (<= x 10) 1 1.0))) + (while (> x 0) + (setq r (* r (truncate x))) + (setq x (1- x))) + (+ 0.0 r))) + (if (= x 1.0e+INF) + x + 0.0e+NaN))) (defun calculator-truncate (n) "Truncate N, return 0 in case of overflow." diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/calendar/cal-bahai.el --- a/lisp/calendar/cal-bahai.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/calendar/cal-bahai.el Sun Jul 15 02:05:20 2007 +0000 @@ -149,6 +149,7 @@ (message "Baha'i date: %s" (calendar-bahai-date-string (calendar-cursor-to-date t)))) +;;;###autoload (defun calendar-goto-bahai-date (date &optional noecho) "Move cursor to Baha'i date DATE. Echo Baha'i date unless NOECHO is t." diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/comint.el --- a/lisp/comint.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/comint.el Sun Jul 15 02:05:20 2007 +0000 @@ -333,12 +333,13 @@ ;; kinit prints a prompt like `Password for devnull@GNU.ORG: '. ;; ksu prints a prompt like `Kerberos password for devnull/root@GNU.ORG: '. ;; ssh-add prints a prompt like `Enter passphrase: '. +;; plink prints a prompt like `Passphrase for key "root@GNU.ORG": '. ;; Some implementations of passwd use "Password (again)" as the 2nd prompt. (defcustom comint-password-prompt-regexp "\\(\\([Oo]ld \\|[Nn]ew \\|'s \\|login \\|\ Kerberos \\|CVS \\|UNIX \\| SMB \\|^\\)\ \[Pp]assword\\( (again)\\)?\\|\ -pass phrase\\|\\(Enter\\|Repeat\\|Bad\\) passphrase\\)\ +pass phrase\\|\\(Enter \\|Repeat \\|Bad \\)?[Pp]assphrase\\)\ \\(?:, try again\\)?\\(?: for [^:]+\\)?:\\s *\\'" "*Regexp matching prompts for passwords in the inferior process. This is used by `comint-watch-for-password-prompt'." @@ -670,13 +671,13 @@ "Make a Comint process NAME in BUFFER, running PROGRAM. If BUFFER is nil, it defaults to NAME surrounded by `*'s. PROGRAM should be either a string denoting an executable program to create -via `start-process', or a cons pair of the form (HOST . SERVICE) denoting a TCP -connection to be opened via `open-network-stream'. If there is already a -running process in that buffer, it is not restarted. Optional fourth arg +via `start-file-process', or a cons pair of the form (HOST . SERVICE) denoting +a TCP connection to be opened via `open-network-stream'. If there is already +a running process in that buffer, it is not restarted. Optional fourth arg STARTFILE is the name of a file to send the contents of to the process. If PROGRAM is a string, any more args are arguments to PROGRAM." - (or (fboundp 'start-process) + (or (fboundp 'start-file-process) (error "Multi-processing is not supported for this system")) (setq buffer (get-buffer-create (or buffer (concat "*" name "*")))) ;; If no process, or nuked process, crank up a new one and put buffer in @@ -693,9 +694,9 @@ "Make a Comint process NAME in a buffer, running PROGRAM. The name of the buffer is made by surrounding NAME with `*'s. PROGRAM should be either a string denoting an executable program to create -via `start-process', or a cons pair of the form (HOST . SERVICE) denoting a TCP -connection to be opened via `open-network-stream'. If there is already a -running process in that buffer, it is not restarted. Optional third arg +via `start-file-process', or a cons pair of the form (HOST . SERVICE) denoting +a TCP connection to be opened via `open-network-stream'. If there is already +a running process in that buffer, it is not restarted. Optional third arg STARTFILE is the name of a file to send the contents of the process to. If PROGRAM is a string, any more args are arguments to PROGRAM." @@ -781,17 +782,17 @@ ;; If the command has slashes, make sure we ;; first look relative to the current directory. (cons default-directory exec-path) exec-path))) - (setq proc (apply 'start-process name buffer command switches))) + (setq proc (apply 'start-file-process name buffer command switches))) (let ((coding-systems (process-coding-system proc))) (setq decoding (car coding-systems) encoding (cdr coding-systems))) - ;; If start-process decided to use some coding system for decoding + ;; If start-file-process decided to use some coding system for decoding ;; data sent from the process and the coding system doesn't ;; specify EOL conversion, we had better convert CRLF to LF. (if (vectorp (coding-system-eol-type decoding)) (setq decoding (coding-system-change-eol-conversion decoding 'dos) changed t)) - ;; Even if start-process left the coding system for encoding data + ;; Even if start-file-process left the coding system for encoding data ;; sent from the process undecided, we had better use the same one ;; as what we use for decoding. But, we should suppress EOL ;; conversion. @@ -1953,11 +1954,16 @@ "Default function for sending to PROC input STRING. This just sends STRING plus a newline. To override this, set the hook `comint-input-sender'." - (comint-send-string proc string) - (if comint-input-sender-no-newline - (if (not (string-equal string "")) - (process-send-eof)) - (comint-send-string proc "\n"))) + (let ((send-string + (if comint-input-sender-no-newline + string + ;; Sending as two separate strings does not work + ;; on Windows, so concat the \n before sending. + (concat string "\n")))) + (comint-send-string proc send-string)) + (if (and comint-input-sender-no-newline + (not (string-equal string ""))) + (process-send-eof))) (defun comint-line-beginning-position () "Return the buffer position of the beginning of the line, after any prompt. @@ -2805,7 +2811,7 @@ (defun comint-dynamic-complete-as-filename () "Dynamically complete at point as a filename. See `comint-dynamic-complete-filename'. Returns t if successful." - (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt cygwin))) + (let* ((completion-ignore-case read-file-name-completion-ignore-case) (completion-ignored-extensions comint-completion-fignore) ;; If we bind this, it breaks remote directory tracking in rlogin.el. ;; I think it was originally bound to solve file completion problems, @@ -2934,7 +2940,7 @@ (defun comint-dynamic-list-filename-completions () "List in help buffer possible completions of the filename at point." (interactive) - (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt cygwin))) + (let* ((completion-ignore-case read-file-name-completion-ignore-case) ;; If we bind this, it breaks remote directory tracking in rlogin.el. ;; I think it was originally bound to solve file completion problems, ;; but subsequent changes may have made this unnecessary. sm. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/complete.el --- a/lisp/complete.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/complete.el Sun Jul 15 02:05:20 2007 +0000 @@ -222,13 +222,6 @@ (remove-hook 'find-file-not-found-functions 'PC-look-for-include-file)) ((not PC-disable-includes) (add-hook 'find-file-not-found-functions 'PC-look-for-include-file))) - ;; ... with some underhand redefining. - (cond ((not partial-completion-mode) - (ad-disable-advice 'read-file-name-internal 'around 'PC-include-file) - (ad-activate 'read-file-name-internal)) - ((not PC-disable-includes) - (ad-enable-advice 'read-file-name-internal 'around 'PC-include-file) - (ad-activate 'read-file-name-internal))) ;; Adjust the completion selection in *Completion* buffers to the way ;; we work. The default minibuffer completion code only completes the ;; text before point and leaves the text after point alone (new in @@ -335,14 +328,24 @@ (PC-do-complete-and-exit))) (defun PC-do-complete-and-exit () - (if (= (point-max) (minibuffer-prompt-end)) ; Duplicate the "bug" that Info-menu relies on... - (exit-minibuffer) + (cond + ((= (point-max) (minibuffer-prompt-end)) + ;; Duplicate the "bug" that Info-menu relies on... + (exit-minibuffer)) + ((eq minibuffer-completion-confirm 'confirm-only) + (if (or (eq last-command this-command) + (test-completion (field-string) + minibuffer-completion-table + minibuffer-completion-predicate)) + (exit-minibuffer) + (PC-temp-minibuffer-message " [Confirm]"))) + (t (let ((flag (PC-do-completion 'exit))) (and flag (if (or (eq flag 'complete) (not minibuffer-completion-confirm)) (exit-minibuffer) - (PC-temp-minibuffer-message " [Confirm]")))))) + (PC-temp-minibuffer-message " [Confirm]"))))))) (defun PC-completion-help () @@ -430,7 +433,9 @@ GOTO-END is non-nil, however, it instead replaces up to END." (or beg (setq beg (minibuffer-prompt-end))) (or end (setq end (point-max))) - (let* ((table minibuffer-completion-table) + (let* ((table (if (eq minibuffer-completion-table 'read-file-name-internal) + 'PC-read-file-name-internal + minibuffer-completion-table)) (pred minibuffer-completion-predicate) (filename (funcall PC-completion-as-file-name-predicate)) (dirname nil) ; non-nil only if a filename is being completed @@ -523,11 +528,11 @@ (insert str) (setq end (+ beg (length str))))) (if origstr - ;; If the wildcards were introduced by us, it's possible - ;; that read-file-name-internal (especially our - ;; PC-include-file advice) can still find matches for the - ;; original string even if we couldn't, so remove the - ;; added wildcards. + ;; If the wildcards were introduced by us, it's + ;; possible that PC-read-file-name-internal can + ;; still find matches for the original string + ;; even if we couldn't, so remove the added + ;; wildcards. (setq str origstr) (setq filename nil table nil pred nil))))) @@ -912,7 +917,7 @@ (point-min) t) (+ (point) 2) (point-min))) - (minibuffer-completion-table 'read-file-name-internal) + (minibuffer-completion-table 'PC-read-file-name-internal) (minibuffer-completion-predicate "") (PC-not-minibuffer t)) (goto-char end) @@ -1098,24 +1103,23 @@ (setq sorted (cdr sorted))) compressed)))) -(defadvice read-file-name-internal (around PC-include-file disable) - (if (string-match "<\\([^\"<>]*\\)>?\\'" (ad-get-arg 0)) - (let* ((string (ad-get-arg 0)) - (action (ad-get-arg 2)) - (name (match-string 1 string)) +(defun PC-read-file-name-internal (string dir action) + "Extend `read-file-name-internal' to handle include files. +This is only used by " + (if (string-match "<\\([^\"<>]*\\)>?\\'" string) + (let* ((name (match-string 1 string)) (str2 (substring string (match-beginning 0))) (completion-table (mapcar (lambda (x) (format (if (string-match "/\\'" x) "<%s" "<%s>") x)) (PC-include-file-all-completions name (PC-include-file-path))))) - (setq ad-return-value (cond ((not completion-table) nil) ((eq action 'lambda) (test-completion str2 completion-table nil)) ((eq action nil) (PC-try-completion str2 completion-table nil)) - ((eq action t) (all-completions str2 completion-table nil))))) - ad-do-it)) + ((eq action t) (all-completions str2 completion-table nil)))) + (read-file-name-internal string dir action))) (provide 'complete) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/cus-edit.el --- a/lisp/cus-edit.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/cus-edit.el Sun Jul 15 02:05:20 2007 +0000 @@ -755,52 +755,86 @@ ;;; Custom Mode Commands. +;; This variable is used by `custom-tool-bar-map', or directly by +;; `custom-buffer-create-internal' if the toolbar is not present and +;; `custom-buffer-verbose-help' is non-nil. + +(defvar custom-commands + '(("Set for current session" Custom-set t + "Apply all settings in this buffer to the current session" + "index") + ("Save for future sessions" Custom-save + (or custom-file user-init-file) + "Apply all settings in this buffer and save them for future Emacs sessions." + "save") + ("Undo edits" Custom-reset-current t + "Restore all settings in this buffer to reflect their current values." + "refresh") + ("Reset to saved" Custom-reset-saved t + "Restore all settings in this buffer to their saved values (if any)." + "undo") + ("Erase customizations" Custom-reset-standard + (or custom-file user-init-file) + "Un-customize all settings in this buffer and save them with standard values." + "delete") + ("Help for Customize" Custom-help t + "Get help for using Customize." + "help") + ("Exit" Custom-buffer-done t "Exit Customize." "exit"))) + +(defun Custom-help () + "Read the node on Easy Customization in the Emacs manual." + (interactive) + (info "(emacs)Easy Customization")) + +(defvar custom-reset-menu + '(("Undo Edits" . Custom-reset-current) + ("Reset to Saved" . Custom-reset-saved) + ("Erase Customizations (use standard values)" . Custom-reset-standard)) + "Alist of actions for the `Reset' button. +The key is a string containing the name of the action, the value is a +Lisp function taking the widget as an element which will be called +when the action is chosen.") + (defvar custom-options nil "Customization widgets in the current buffer.") -(defun Custom-set () +(defun custom-command-apply (fun query &optional strong-query) + "Call function FUN on all widgets in `custom-options'. +If there is more than one widget, ask user for confirmation using +the query string QUERY, using `y-or-n-p' if STRONG-QUERY is nil, +and `yes-or-no-p' otherwise." + (if (or (and (= 1 (length custom-options)) + (memq (widget-type (car custom-options)) + '(custom-variable custom-face))) + (funcall (if strong-query 'yes-or-no-p 'y-or-n-p) query)) + (progn (mapc fun custom-options) t) + (message "Aborted") + nil)) + +(defun Custom-set (&rest ignore) "Set the current value of all edited settings in the buffer." (interactive) - (let ((children custom-options)) - (if (or (and (= 1 (length children)) - (memq (widget-type (car children)) - '(custom-variable custom-face))) - (y-or-n-p "Set all values according to this buffer? ")) - (mapc (lambda (child) - (when (eq (widget-get child :custom-state) 'modified) - (widget-apply child :custom-set))) - children) - (message "Aborted")))) - -(defun Custom-save () + (custom-command-apply + (lambda (child) + (when (eq (widget-get child :custom-state) 'modified) + (widget-apply child :custom-set))) + "Set all values according to this buffer? ")) + +(defun Custom-save (&rest ignore) "Set all edited settings, then save all settings that have been set. If a setting was edited and set before, this saves it. If a setting was merely edited before, this sets it then saves it." (interactive) - (let ((children custom-options)) - (if (or (and (= 1 (length children)) - (memq (widget-type (car children)) - '(custom-variable custom-face))) - (yes-or-no-p "Save all settings in this buffer? ")) - (progn - (mapc (lambda (child) - (when (memq (widget-get child :custom-state) - '(modified set changed rogue)) - (widget-apply child :custom-save))) - children) - (custom-save-all)) - (message "Aborted")))) - -(defvar custom-reset-menu - '(("Undo Edits" . Custom-reset-current) - ("Reset to Saved" . Custom-reset-saved) - ("Erase Customization (use standard values)" . Custom-reset-standard)) - "Alist of actions for the `Reset' button. -The key is a string containing the name of the action, the value is a -Lisp function taking the widget as an element which will be called -when the action is chosen.") - -(defun custom-reset (event) + (if (custom-command-apply + (lambda (child) + (when (memq (widget-get child :custom-state) + '(modified set changed rogue)) + (widget-apply child :custom-save))) + "Save all settings in this buffer? " t) + (custom-save-all))) + +(defun custom-reset (widget &optional event) "Select item from reset menu." (let* ((completion-ignore-case t) (answer (widget-choose "Reset settings" @@ -812,33 +846,21 @@ (defun Custom-reset-current (&rest ignore) "Reset all edited settings in the buffer to show their current values." (interactive) - (let ((children custom-options)) - (if (or (and (= 1 (length children)) - (memq (widget-type (car children)) - '(custom-variable custom-face))) - (y-or-n-p "Reset all settings' buffer text to show current values? ")) - (mapc (lambda (widget) - (if (memq (widget-get widget :custom-state) - '(modified changed)) - (widget-apply widget :custom-reset-current))) - children) - (message "Aborted")))) + (custom-command-apply + (lambda (widget) + (if (memq (widget-get widget :custom-state) '(modified changed)) + (widget-apply widget :custom-reset-current))) + "Reset all settings' buffer text to show current values? ")) (defun Custom-reset-saved (&rest ignore) "Reset all edited or set settings in the buffer to their saved value. This also shows the saved values in the buffer." (interactive) - (let ((children custom-options)) - (if (or (and (= 1 (length children)) - (memq (widget-type (car children)) - '(custom-variable custom-face))) - (y-or-n-p "Reset all settings (current values and buffer text) to saved values? ")) - (mapc (lambda (widget) - (if (memq (widget-get widget :custom-state) - '(modified set changed rogue)) - (widget-apply widget :custom-reset-saved))) - children) - (message "Aborted")))) + (custom-command-apply + (lambda (widget) + (if (memq (widget-get widget :custom-state) '(modified set changed rogue)) + (widget-apply widget :custom-reset-saved))) + "Reset all settings (current values and buffer text) to saved values? ")) (defun Custom-reset-standard (&rest ignore) "Erase all customization (either current or saved) for the group members. @@ -846,20 +868,14 @@ This operation eliminates any saved values for the group members, making them as if they had never been customized at all." (interactive) - (let ((children custom-options)) - (if (or (and (= 1 (length children)) - (memq (widget-type (car children)) - '(custom-variable custom-face))) - (yes-or-no-p "Erase all customizations for settings in this buffer? ")) - (mapc (lambda (widget) - (and (if (widget-get widget :custom-standard-value) - (widget-apply widget :custom-standard-value) - t) - (memq (widget-get widget :custom-state) - '(modified set changed saved rogue)) - (widget-apply widget :custom-reset-standard))) - children) - (message "Aborted")))) + (custom-command-apply + (lambda (widget) + (and (or (null (widget-get widget :custom-standard-value)) + (widget-apply widget :custom-standard-value)) + (memq (widget-get widget :custom-state) + '(modified set changed saved rogue)) + (widget-apply widget :custom-reset-standard))) + "Erase all customizations for settings in this buffer? " t)) ;;; The Customize Commands @@ -888,9 +904,9 @@ (cond (prop ;; Use VAR's `variable-interactive' property ;; as an interactive spec for prompting. - (call-interactively (list 'lambda '(arg) - (list 'interactive prop) - 'arg))) + (call-interactively `(lambda (arg) + (interactive ,prop) + arg))) (type (widget-prompt-value type prompt @@ -1018,17 +1034,20 @@ ;;;###autoload -(defun customize-group (group) +(defun customize-group (&optional group prompt-for-group other-window) "Customize GROUP, which must be a customization group." - (interactive - (list (let ((completion-ignore-case t)) - (completing-read "Customize group (default emacs): " - obarray - (lambda (symbol) - (or (and (get symbol 'custom-loads) - (not (get symbol 'custom-autoload))) - (get symbol 'custom-group))) - t)))) + (interactive) + (and (null group) + (or prompt-for-group (called-interactively-p)) + (let ((completion-ignore-case t)) + (setq group + (completing-read "Customize group (default emacs): " + obarray + (lambda (symbol) + (or (and (get symbol 'custom-loads) + (not (get symbol 'custom-autoload))) + (get symbol 'custom-group))) + t)))) (when (stringp group) (if (string-equal "" group) (setq group 'emacs) @@ -1036,42 +1055,25 @@ (let ((name (format "*Customize Group: %s*" (custom-unlispify-tag-name group)))) (if (get-buffer name) - (pop-to-buffer name) - (custom-buffer-create (list (list group 'custom-group)) - name - (concat " for group " - (custom-unlispify-tag-name group)))))) + (if other-window + (let ((pop-up-windows t) + (same-window-buffer-names nil) + (same-window-regexps nil)) + (pop-to-buffer name)) + (pop-to-buffer name)) + (funcall (if other-window + 'custom-buffer-create-other-window + 'custom-buffer-create) + (list (list group 'custom-group)) + name + (concat " for group " + (custom-unlispify-tag-name group)))))) ;;;###autoload -(defun customize-group-other-window (group) - "Customize GROUP, which must be a customization group." - (interactive - (list (let ((completion-ignore-case t)) - (completing-read "Customize group (default emacs): " - obarray - (lambda (symbol) - (or (and (get symbol 'custom-loads) - (not (get symbol 'custom-autoload))) - (get symbol 'custom-group))) - t)))) - (when (stringp group) - (if (string-equal "" group) - (setq group 'emacs) - (setq group (intern group)))) - (let ((name (format "*Customize Group: %s*" - (custom-unlispify-tag-name group)))) - (if (get-buffer name) - (let ( - ;; Copied from `custom-buffer-create-other-window'. - (pop-up-windows t) - (same-window-buffer-names nil) - (same-window-regexps nil)) - (pop-to-buffer name)) - (custom-buffer-create-other-window - (list (list group 'custom-group)) - name - (concat " for group " - (custom-unlispify-tag-name group)))))) +(defun customize-group-other-window (&optional group) + "Customize GROUP, which must be a customization group, in another window." + (interactive) + (customize-group group t t)) ;;;###autoload (defalias 'customize-variable 'customize-option) @@ -1252,34 +1254,41 @@ (< minor1 minor2))))) ;;;###autoload -(defun customize-face (&optional face) +(defun customize-face (&optional face prompt-for-face other-window) "Customize FACE, which should be a face name or nil. If FACE is nil, customize all faces. If FACE is actually a face-alias, customize the face it is aliased to. Interactively, when point is on text which has a face specified, suggest to customize that face, if it's customizable." - (interactive - (list (read-face-name "Customize face" "all faces" t))) + (interactive) + (and (null face) + (or prompt-for-face (called-interactively-p)) + (setq face (read-face-name "Customize face" "all faces" t))) (if (member face '(nil "")) (setq face (face-list))) (if (and (listp face) (null (cdr face))) (setq face (car face))) - (if (listp face) - (custom-buffer-create (custom-sort-items - (mapcar (lambda (s) - (list s 'custom-face)) - face) - t nil) - "*Customize Faces*") - ;; If FACE is actually an alias, customize the face it is aliased to. - (if (get face 'face-alias) - (setq face (get face 'face-alias))) - (unless (facep face) - (error "Invalid face %S" face)) - (custom-buffer-create (list (list face 'custom-face)) - (format "*Customize Face: %s*" - (custom-unlispify-tag-name face))))) + (let ((create-buffer-fn (if other-window + 'custom-buffer-create-other-window + 'custom-buffer-create))) + (if (listp face) + (funcall create-buffer-fn + (custom-sort-items + (mapcar (lambda (s) + (list s 'custom-face)) + face) + t nil) + "*Customize Faces*") + ;; If FACE is actually an alias, customize the face it is aliased to. + (if (get face 'face-alias) + (setq face (get face 'face-alias))) + (unless (facep face) + (error "Invalid face %S" face)) + (funcall create-buffer-fn + (list (list face 'custom-face)) + (format "*Customize Face: %s*" + (custom-unlispify-tag-name face)))))) ;;;###autoload (defun customize-face-other-window (&optional face) @@ -1288,28 +1297,8 @@ Interactively, when point is on text which has a face specified, suggest to customize that face, if it's customizable." - (interactive - (list (read-face-name "Customize face" "all faces" t))) - (if (member face '(nil "")) - (setq face (face-list))) - (if (and (listp face) (null (cdr face))) - (setq face (car face))) - (if (listp face) - (custom-buffer-create-other-window - (custom-sort-items - (mapcar (lambda (s) - (list s 'custom-face)) - face) - t nil) - "*Customize Faces*") - (if (get face 'face-alias) - (setq face (get face 'face-alias))) - (unless (facep face) - (error "Invalid face %S" face)) - (custom-buffer-create-other-window - (list (list face 'custom-face)) - (format "*Customize Face: %s*" - (custom-unlispify-tag-name face))))) + (interactive) + (customize-face face t t)) (defalias 'customize-customized 'customize-unsaved) @@ -1541,96 +1530,60 @@ (defun custom-buffer-create-internal (options &optional description) (custom-mode) - (if custom-buffer-verbose-help - (progn - (widget-insert "This is a customization buffer") - (if description - (widget-insert description)) - (widget-insert (format ". -%s buttons; type RET or click mouse-1 to actuate one. -Editing a setting changes only the text in the buffer." - (if custom-raised-buttons - "`Raised' text indicates" - "Square brackets indicate"))) - (if init-file-user - (widget-insert " -Use the Save or Set buttons to set apply your changes. -Saving a change normally works by editing your Emacs ") - (widget-insert " -\nSince you started Emacs with `-q', you cannot save settings into -the Emacs ")) - (widget-create 'custom-manual - :tag "init file" - "(emacs)Saving Customizations") - (widget-insert ".\nSee ") - (widget-create 'custom-manual - :tag "Help" - :help-echo "Read the online help." - "(emacs)Easy Customization") - (widget-insert " for more information.\n\n") - (widget-insert "Operate on all settings in this buffer that \ -are not marked HIDDEN:\n ")) - (widget-insert " ")) - (widget-create 'push-button - :tag "Set for Current Session" - :help-echo "\ -Make your editing in this buffer take effect for this session." - :action (lambda (widget &optional event) - (Custom-set))) - (if (not custom-buffer-verbose-help) - (progn - (widget-insert " ") - (widget-create 'custom-manual - :tag "Help" - :help-echo "Read the online help." - "(emacs)Easy Customization"))) - (when (or custom-file user-init-file) - (widget-insert " ") - (widget-create 'push-button - :tag "Save for Future Sessions" - :help-echo "\ -Make your editing in this buffer take effect for future Emacs sessions. -This updates your Emacs initialization file or creates a new one." - :action (lambda (widget &optional event) - (Custom-save)))) - (if custom-reset-button-menu - (progn - (widget-insert " ") - (widget-create 'push-button - :tag "Reset buffer" - :help-echo "Show a menu with reset operations." - :mouse-down-action (lambda (&rest junk) t) - :action (lambda (widget &optional event) - (custom-reset event)))) - (widget-insert "\n ") - (widget-create 'push-button - :tag "Undo Edits" - :help-echo "\ -Reset all edited text in this buffer to reflect current values." - :action 'Custom-reset-current) - (widget-insert " ") - (widget-create 'push-button - :tag "Reset to Saved" - :help-echo "\ -Reset all settings in this buffer to their saved values." - :action 'Custom-reset-saved) - (widget-insert " ") - (when (or custom-file user-init-file) - (widget-create 'push-button - :tag "Erase Customization" - :help-echo "\ -Un-customize all settings in this buffer and save them with standard values." - :action 'Custom-reset-standard))) - (widget-insert " ") - (widget-create 'push-button - :tag "Finish" - :help-echo - (lambda (&rest ignore) - (if custom-buffer-done-kill - "Kill this buffer" - "Bury this buffer")) - :action #'Custom-buffer-done) - (widget-insert "\n\n") + (let ((init-file (or custom-file user-init-file))) + ;; Insert verbose help at the top of the custom buffer. + (when custom-buffer-verbose-help + (widget-insert "Editing a setting changes only the text in this buffer." + (if init-file + " +To set apply your changes, use the Save or Set buttons. +Saving a change normally works by editing your init file." + " +Currently, these settings cannot be saved for future Emacs sessions, +possibly because you started Emacs with `-q'.") + "\nFor details, see ") + (widget-create 'custom-manual + :tag "Saving Customizations" + "(emacs)Saving Customizations") + (widget-insert " in the ") + (widget-create 'custom-manual + :tag "Emacs manual" + :help-echo "Read the Emacs manual." + "(emacs)Top") + (widget-insert ".")) + ;; Insert custom command buttons if the toolbar is not in use. + + (widget-insert "\n") + (when (not (and tool-bar-mode (display-graphic-p))) + (if custom-buffer-verbose-help + (widget-insert "\n + Operate on all settings in this buffer that are not marked HIDDEN:\n")) + (let ((button (lambda (tag action active help icon) + (widget-insert " ") + (if (eval active) + (widget-create 'push-button :tag tag + :help-echo help :action action)))) + (commands custom-commands)) + (apply button (pop commands)) ; Set for current session + (apply button (pop commands)) ; Save for future sessions + (if custom-reset-button-menu + (progn + (widget-insert " ") + (widget-create 'push-button + :tag "Reset buffer" + :help-echo "Show a menu with reset operations." + :mouse-down-action 'ignore + :action 'custom-reset)) + (widget-insert "\n") + (apply button (pop commands)) ; Undo edits + (apply button (pop commands)) ; Reset to saved + (apply button (pop commands)) ; Erase customization + (widget-insert " ") + (pop commands) ; Help (omitted) + (apply button (pop commands))))) ; Exit + (widget-insert "\n\n")) + + ;; Now populate the custom buffer. (message "Creating customization items...") (buffer-disable-undo) (setq custom-options @@ -2431,13 +2384,13 @@ (defface custom-variable-tag `((((class color) (background dark)) - (:foreground "light blue" :weight bold :inherit variable-pitch)) + (:foreground "light blue" :weight bold)) (((min-colors 88) (class color) (background light)) - (:foreground "blue1" :weight bold :inherit variable-pitch)) + (:foreground "blue1" :weight bold)) (((class color) (background light)) - (:foreground "blue" :weight bold :inherit variable-pitch)) + (:foreground "blue" :weight bold)) (t (:weight bold))) "Face used for unpushable variable tags." :group 'custom-faces) @@ -2629,8 +2582,8 @@ (widget-put widget :custom-magic magic) (push magic buttons)) (widget-put widget :buttons buttons) - (insert "\n") ;; Insert documentation. + (widget-put widget :documentation-indent 3) (widget-add-documentation-string-button widget :visibility-widget 'custom-visibility) @@ -3750,13 +3703,13 @@ (defface custom-group-tag `((((class color) (background dark)) - (:foreground "light blue" :weight bold :height 1.2)) + (:foreground "light blue" :weight bold :height 1.2 :inherit variable-pitch)) (((min-colors 88) (class color) (background light)) - (:foreground "blue1" :weight bold :height 1.2)) + (:foreground "blue1" :weight bold :height 1.2 :inherit variable-pitch)) (((class color) (background light)) - (:foreground "blue" :weight bold :height 1.2)) + (:foreground "blue" :weight bold :height 1.2 :inherit variable-pitch)) (t (:weight bold))) "Face used for low level group tags." :group 'custom-faces) @@ -3900,28 +3853,22 @@ ;; Nested style. ((eq state 'hidden) ;; Create level indicator. - (unless (eq custom-buffer-style 'links) - (insert-char ?\ (* custom-buffer-indent (1- level))) - (insert "-- ")) ;; Create tag. - (let ((begin (point))) - (insert tag) - (widget-specify-sample widget begin (point))) - (insert " group: ") - ;; Create link/visibility indicator. (if (eq custom-buffer-style 'links) (push (widget-create-child-and-convert widget 'custom-group-link - :tag "Go to Group" + :tag tag symbol) buttons) + (insert-char ?\ (* custom-buffer-indent (1- level))) + (insert "-- ") (push (widget-create-child-and-convert widget 'custom-group-visibility :help-echo "Show members of this group." :action 'custom-toggle-parent (not (eq state 'hidden))) buttons)) - (insert " \n") + (insert " : ") ;; Create magic button. (let ((magic (widget-create-child-and-convert widget 'custom-magic nil))) @@ -3949,9 +3896,9 @@ (insert "/- ") ;; Create tag. (let ((start (point))) - (insert tag) + (insert tag " group: ") (widget-specify-sample widget start (point))) - (insert " group: ") + (insert (widget-docstring widget)) ;; Create visibility indicator. (unless (eq custom-buffer-style 'links) (insert "--------") @@ -4072,44 +4019,34 @@ (defun custom-group-set (widget) "Set changes in all modified group members." - (let ((children (widget-get widget :children))) - (mapc (lambda (child) - (when (eq (widget-get child :custom-state) 'modified) - (widget-apply child :custom-set))) - children ))) + (dolist (child (widget-get widget :children)) + (when (eq (widget-get child :custom-state) 'modified) + (widget-apply child :custom-set)))) (defun custom-group-save (widget) "Save all modified group members." - (let ((children (widget-get widget :children))) - (mapc (lambda (child) - (when (memq (widget-get child :custom-state) '(modified set)) - (widget-apply child :custom-save))) - children ))) + (dolist (child (children (widget-get widget :children))) + (when (memq (widget-get child :custom-state) '(modified set)) + (widget-apply child :custom-save)))) (defun custom-group-reset-current (widget) "Reset all modified group members." - (let ((children (widget-get widget :children))) - (mapc (lambda (child) - (when (eq (widget-get child :custom-state) 'modified) - (widget-apply child :custom-reset-current))) - children ))) + (dolist (child (widget-get widget :children)) + (when (eq (widget-get child :custom-state) 'modified) + (widget-apply child :custom-reset-current)))) (defun custom-group-reset-saved (widget) "Reset all modified or set group members." - (let ((children (widget-get widget :children))) - (mapc (lambda (child) - (when (memq (widget-get child :custom-state) '(modified set)) - (widget-apply child :custom-reset-saved))) - children ))) + (dolist (child (widget-get widget :children)) + (when (memq (widget-get child :custom-state) '(modified set)) + (widget-apply child :custom-reset-saved)))) (defun custom-group-reset-standard (widget) "Reset all modified, set, or saved group members." - (let ((children (widget-get widget :children))) - (mapc (lambda (child) - (when (memq (widget-get child :custom-state) - '(modified set saved)) - (widget-apply child :custom-reset-standard))) - children ))) + (dolist (child (widget-get widget :children)) + (when (memq (widget-get child :custom-state) + '(modified set saved)) + (widget-apply child :custom-reset-standard)))) (defun custom-group-state-update (widget) "Update magic." @@ -4498,6 +4435,32 @@ (let ((menu (custom-menu-create ',symbol))) (if (consp menu) (cdr menu) menu))))) +;;; Toolbar and menubar support + +(easy-menu-define + Custom-mode-menu custom-mode-map + "Menu used in customization buffers." + (nconc (list "Custom" + (customize-menu-create 'customize)) + (mapcar (lambda (arg) + (let ((tag (nth 0 arg)) + (command (nth 1 arg)) + (active (nth 2 arg)) + (help (nth 3 arg))) + (vector tag command :active (eval active) :help help))) + custom-commands))) + +(defvar tool-bar-map) +(defvar custom-tool-bar-map + (if (display-graphic-p) + (let ((map (make-sparse-keymap))) + (mapc + (lambda (arg) + (tool-bar-local-item-from-menu + (nth 1 arg) (nth 4 arg) map custom-mode-map)) + custom-commands) + map))) + ;;; The Custom Mode. (defun Custom-no-edit (pos &optional event) @@ -4513,18 +4476,6 @@ (widget-apply-action button event) (error "You can't edit this part of the Custom buffer")))) -(easy-menu-define Custom-mode-menu - custom-mode-map - "Menu used in customization buffers." - `("Custom" - ,(customize-menu-create 'customize) - ["Set" Custom-set t] - ["Save" Custom-save t] - ["Undo Edits" Custom-reset-current t] - ["Reset to Saved" Custom-reset-saved t] - ["Erase Customization" Custom-reset-standard t] - ["Info" (info "(emacs)Easy Customization") t])) - (defvar custom-field-keymap (let ((map (copy-keymap widget-field-keymap))) (define-key map "\C-c\C-c" 'Custom-set) @@ -4581,6 +4532,7 @@ mode-name "Custom") (use-local-map custom-mode-map) (easy-menu-add Custom-mode-menu) + (set (make-local-variable 'tool-bar-map) custom-tool-bar-map) (make-local-variable 'custom-options) (make-local-variable 'custom-local-buffer) (make-local-variable 'widget-documentation-face) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/cus-start.el --- a/lisp/cus-start.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/cus-start.el Sun Jul 15 02:05:20 2007 +0000 @@ -122,8 +122,11 @@ :value (undecided . undecided) (coding-system :tag "Decoding") (coding-system :tag "Encoding")) - (coding-system :tag "Single coding system" - :value undecided) + (coding-system + :tag "Single coding system" + :value undecided + :match (lambda (widget value) + (and value (not (functionp value))))) (function :value ignore)))) (selection-coding-system mule coding-system) ;; dired.c @@ -139,6 +142,9 @@ ;; eval.c (max-specpdl-size limits integer) (max-lisp-eval-depth limits integer) + (max-mini-window-height limits + (choice (const :tag "quarter screen" nil) + number)) (stack-trace-on-error debug (choice (const :tag "off") (repeat :menu-tag "When" diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/desktop.el --- a/lisp/desktop.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/desktop.el Sun Jul 15 02:05:20 2007 +0000 @@ -626,9 +626,7 @@ (setq desktop-dirname (file-name-as-directory (expand-file-name - (call-interactively - (lambda (dir) - (interactive "DDirectory for desktop file: ") dir)))))) + (read-directory-name "Directory for desktop file: " nil nil t))))) (condition-case err (desktop-save desktop-dirname t) (file-error @@ -654,7 +652,7 @@ (set-buffer buffer) (list ;; basic information - (desktop-file-name (buffer-file-name) dirname) + (desktop-file-name (buffer-file-name) desktop-dirname) (buffer-name) major-mode ;; minor modes @@ -675,7 +673,7 @@ buffer-read-only ;; auxiliary information (when (functionp desktop-save-buffer) - (funcall desktop-save-buffer dirname)) + (funcall desktop-save-buffer desktop-dirname)) ;; local variables (let ((locals desktop-locals-to-save) (loclist (buffer-local-variables)) @@ -898,7 +896,7 @@ (insert "\n " (desktop-value-to-string e))) (insert ")\n\n"))) - (setq default-directory dirname) + (setq default-directory desktop-dirname) (let ((coding-system-for-write 'emacs-mule)) (write-region (point-min) (point-max) (desktop-full-file-name) nil 'nomessage)) ;; We remember when it was modified (which is presumably just now). @@ -964,9 +962,9 @@ (not (y-or-n-p (format "Warning: desktop file appears to be in use by PID %s.\n\ Using it may cause conflicts. Use it anyway? " owner))))) (progn - (setq desktop-dirname nil) (let ((default-directory desktop-dirname)) (run-hooks 'desktop-not-loaded-hook)) + (setq desktop-dirname nil) (message "Desktop file in use; not loaded.")) (desktop-lazy-abort) ;; Evaluate desktop buffer and remember when it was modified. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/diff-mode.el --- a/lisp/diff-mode.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/diff-mode.el Sun Jul 15 02:05:20 2007 +0000 @@ -338,7 +338,7 @@ ("^--- .+ ----$" . diff-hunk-header-face) ;context ("^[0-9,]+[acd][0-9,]+$" . diff-hunk-header-face) ;normal ("^---$" . diff-hunk-header-face) ;normal - ("^\\(---\\|\\+\\+\\+\\|\\*\\*\\*\\) \\([^ \t]+\\)\\(.*[^*-]\\)?\n" + ("^\\(---\\|\\+\\+\\+\\|\\*\\*\\*\\) \\([^\t\n]+\\)\\(.*[^*-]\\)?\n" (0 diff-header-face) (2 diff-file-header-face prepend)) ("^\\([-<]\\)\\(.*\n\\)" (1 diff-indicator-removed-face) (2 diff-removed-face)) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/dired-aux.el --- a/lisp/dired-aux.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/dired-aux.el Sun Jul 15 02:05:20 2007 +0000 @@ -582,18 +582,6 @@ ;; Return nil for sake of nconc in dired-bunch-files. nil) -;; In Emacs 19 this will return program's exit status. -;; This is a separate function so that ange-ftp can redefine it. -(defun dired-call-process (program discard &rest arguments) -; "Run PROGRAM with output to current buffer unless DISCARD is t. -;Remaining arguments are strings passed as command arguments to PROGRAM." - ;; Look for a handler for default-directory in case it is a remote file name. - (let ((handler - (find-file-name-handler (directory-file-name default-directory) - 'dired-call-process))) - (if handler (apply handler 'dired-call-process - program discard arguments) - (apply 'call-process program nil (not discard) nil arguments)))) (defun dired-check-process (msg program &rest arguments) ; "Display MSG while running PROGRAM, and check for output. @@ -610,8 +598,7 @@ (set-buffer err-buffer) (erase-buffer) (setq default-directory dir ; caller's default-directory - err (not (eq 0 - (apply (function dired-call-process) program nil arguments)))) + err (not (eq 0 (apply 'process-file program nil t nil arguments)))) (if err (progn (dired-log (concat program " " (prin1-to-string arguments) "\n")) @@ -1203,7 +1190,7 @@ ;; It is a symlink (make-symbolic-link (car attrs) to ok-flag) (copy-file from to ok-flag dired-copy-preserve-time)) - (file-date-error + (file-date-error (push (dired-make-relative from) dired-create-files-failures) (dired-log "Can't set date on %s:\n%s\n" from err)))))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/dnd.el --- a/lisp/dnd.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/dnd.el Sun Jul 15 02:05:20 2007 +0000 @@ -149,7 +149,7 @@ "%[A-Fa-f0-9][A-Fa-f0-9]" (lambda (arg) (format "%c" (string-to-number (substring arg 1) 16))) - f nil t)) + f t t)) (let* ((decoded-f (decode-coding-string f (or file-name-coding-system diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/advice.el --- a/lisp/emacs-lisp/advice.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/advice.el Sun Jul 15 02:05:20 2007 +0000 @@ -3759,7 +3759,7 @@ \(defadvice FUNCTION (CLASS NAME [POSITION] [ARGLIST] FLAG...) [DOCSTRING] [INTERACTIVE-FORM] - BODY... ) + BODY...) FUNCTION ::= Name of the function to be advised. CLASS ::= `before' | `around' | `after' | `activation' | `deactivation'. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/autoload.el --- a/lisp/emacs-lisp/autoload.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/autoload.el Sun Jul 15 02:05:20 2007 +0000 @@ -41,15 +41,19 @@ A `.el' file can set this in its local variables section to make its autoloads go somewhere else. The autoload file is assumed to contain a trailer starting with a FormFeed character.") +;;;###autoload +(put 'generated-autoload-file 'safe-local-variable 'stringp) -(defconst generate-autoload-cookie ";;;###autoload" +;; This feels like it should be a defconst, but MH-E sets it to +;; ";;;###mh-autoload" for the autoloads that are to go into mh-loaddefs.el. +(defvar generate-autoload-cookie ";;;###autoload" "Magic comment indicating the following form should be autoloaded. Used by \\[update-file-autoloads]. This string should be meaningless to Lisp (e.g., a comment). This string is used: -;;;###autoload +\;;;###autoload \(defun function-to-be-autoloaded () ...) If this string appears alone on a line, the following form will be @@ -65,6 +69,8 @@ (defconst generate-autoload-section-continuation ";;;;;; " "String to add on each continuation of the section header form.") +(defvar autoload-modified-buffers) ;Dynamically scoped var. + (defun make-autoload (form file) "Turn FORM into an autoload or defvar for source file FILE. Returns nil if FORM is not a special autoload form (i.e. a function definition @@ -149,16 +155,14 @@ ;; the doc-string in FORM. ;; Those properties are now set in lisp-mode.el. +(defun autoload-generated-file () + (expand-file-name generated-autoload-file + ;; File-local settings of generated-autoload-file should + ;; be interpreted relative to the file's location, + ;; of course. + (if (not (local-variable-p 'generated-autoload-file)) + (expand-file-name "lisp" source-directory)))) -(defun autoload-trim-file-name (file) - ;; Returns a relative file path for FILE - ;; starting from the directory that loaddefs.el is in. - ;; That is normally a directory in load-path, - ;; which means Emacs will be able to find FILE when it looks. - ;; Any extra directory names here would prevent finding the file. - (setq file (expand-file-name file)) - (file-relative-name file - (file-name-directory generated-autoload-file))) (defun autoload-read-section-header () "Read a section header form. @@ -253,9 +257,7 @@ "Insert the section-header line, which lists the file name and which functions are in it, etc." (insert generate-autoload-section-header) - (prin1 (list 'autoloads autoloads load-name - (if (stringp file) (autoload-trim-file-name file) file) - time) + (prin1 (list 'autoloads autoloads load-name file time) outbuf) (terpri outbuf) ;; Break that line at spaces, to avoid very long lines. @@ -272,12 +274,14 @@ (defun autoload-find-file (file) "Fetch file and put it in a temp buffer. Return the buffer." ;; It is faster to avoid visiting the file. + (setq file (expand-file-name file)) (with-current-buffer (get-buffer-create " *autoload-file*") (kill-all-local-variables) (erase-buffer) (setq buffer-undo-list t buffer-read-only nil) (emacs-lisp-mode) + (setq default-directory (file-name-directory file)) (insert-file-contents file nil) (let ((enable-local-variables :safe)) (hack-local-variables)) @@ -286,6 +290,12 @@ (defvar no-update-autoloads nil "File local variable to prevent scanning this file for autoload cookies.") +(defun autoload-file-load-name (file) + (let ((name (file-name-nondirectory file))) + (if (string-match "\\.elc?\\(\\.\\|\\'\\)" name) + (substring name 0 (match-beginning 0)) + name))) + (defun generate-file-autoloads (file) "Insert at point a loaddefs autoload section for FILE. Autoloads are generated for defuns and defmacros in FILE @@ -294,100 +304,155 @@ are used. Return non-nil in the case where no autoloads were added at point." (interactive "fGenerate autoloads for file: ") - (let ((outbuf (current-buffer)) - (autoloads-done '()) - (load-name (let ((name (file-name-nondirectory file))) - (if (string-match "\\.elc?\\(\\.\\|$\\)" name) - (substring name 0 (match-beginning 0)) - name))) - (print-length nil) - (print-readably t) ; This does something in Lucid Emacs. - (float-output-format nil) - (done-any nil) - (visited (get-file-buffer file)) - output-start) + (autoload-generate-file-autoloads file (current-buffer))) + +;; When called from `generate-file-autoloads' we should ignore +;; `generated-autoload-file' altogether. When called from +;; `update-file-autoloads' we don't know `outbuf'. And when called from +;; `update-directory-autoloads' it's in between: we know the default +;; `outbuf' but we should obey any file-local setting of +;; `generated-autoload-file'. +(defun autoload-generate-file-autoloads (file &optional outbuf outfile) + "Insert an autoload section for FILE in the appropriate buffer. +Autoloads are generated for defuns and defmacros in FILE +marked by `generate-autoload-cookie' (which see). +If FILE is being visited in a buffer, the contents of the buffer are used. +OUTBUF is the buffer in which the autoload statements should be inserted. +If OUTBUF is nil, it will be determined by `autoload-generated-file'. - ;; If the autoload section we create here uses an absolute - ;; file name for FILE in its header, and then Emacs is installed - ;; under a different path on another system, - ;; `update-autoloads-here' won't be able to find the files to be - ;; autoloaded. So, if FILE is in the same directory or a - ;; subdirectory of the current buffer's directory, we'll make it - ;; relative to the current buffer's directory. - (setq file (expand-file-name file)) - (let* ((source-truename (file-truename file)) - (dir-truename (file-name-as-directory - (file-truename default-directory))) - (len (length dir-truename))) - (if (and (< len (length source-truename)) - (string= dir-truename (substring source-truename 0 len))) - (setq file (substring source-truename len)))) +If provided, OUTFILE is expected to be the file name of OUTBUF. +If OUTFILE is non-nil and FILE specifies a `generated-autoload-file' +different from OUTFILE, then OUTBUF is ignored. + +Return non-nil iff FILE adds no autoloads to OUTFILE +\(or OUTBUF if OUTFILE is nil)." + (catch 'done + (let ((autoloads-done '()) + (load-name (autoload-file-load-name file)) + (print-length nil) + (print-readably t) ; This does something in Lucid Emacs. + (float-output-format nil) + (visited (get-file-buffer file)) + (otherbuf nil) + (absfile (expand-file-name file)) + relfile + ;; nil until we found a cookie. + output-start) - (with-current-buffer (or visited - ;; It is faster to avoid visiting the file. - (autoload-find-file file)) - ;; Obey the no-update-autoloads file local variable. - (unless no-update-autoloads - (message "Generating autoloads for %s..." file) - (setq output-start (with-current-buffer outbuf (point))) - (save-excursion - (save-restriction - (widen) - (goto-char (point-min)) - (while (not (eobp)) - (skip-chars-forward " \t\n\f") - (cond - ((looking-at (regexp-quote generate-autoload-cookie)) - (search-forward generate-autoload-cookie) - (skip-chars-forward " \t") - (setq done-any t) - (if (eolp) - ;; Read the next form and make an autoload. - (let* ((form (prog1 (read (current-buffer)) - (or (bolp) (forward-line 1)))) - (autoload (make-autoload form load-name))) - (if autoload - (push (nth 1 form) autoloads-done) - (setq autoload form)) - (let ((autoload-print-form-outbuf outbuf)) - (autoload-print-form autoload))) + (with-current-buffer (or visited + ;; It is faster to avoid visiting the file. + (autoload-find-file file)) + ;; Obey the no-update-autoloads file local variable. + (unless no-update-autoloads + (message "Generating autoloads for %s..." file) + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (while (not (eobp)) + (skip-chars-forward " \t\n\f") + (cond + ((looking-at (regexp-quote generate-autoload-cookie)) + ;; If not done yet, figure out where to insert this text. + (unless output-start + (when (and outfile + (not (equal outfile (autoload-generated-file)))) + ;; A file-local setting of autoload-generated-file says + ;; we should ignore OUTBUF. + (setq outbuf nil) + (setq otherbuf t)) + (unless outbuf + (setq outbuf (autoload-find-destination absfile)) + (unless outbuf + ;; The file has autoload cookies, but they're + ;; already up-to-date. If OUTFILE is nil, the + ;; entries are in the expected OUTBUF, otherwise + ;; they're elsewhere. + (throw 'done outfile))) + (with-current-buffer outbuf + (setq relfile (file-relative-name absfile)) + (setq output-start (point))) + ;; (message "file=%S, relfile=%S, dest=%S" + ;; file relfile (autoload-generated-file)) + ) + (search-forward generate-autoload-cookie) + (skip-chars-forward " \t") + (if (eolp) + (condition-case err + ;; Read the next form and make an autoload. + (let* ((form (prog1 (read (current-buffer)) + (or (bolp) (forward-line 1)))) + (autoload (make-autoload form load-name))) + (if autoload + (push (nth 1 form) autoloads-done) + (setq autoload form)) + (let ((autoload-print-form-outbuf outbuf)) + (autoload-print-form autoload))) + (error + (message "Error in %s: %S" file err))) - ;; Copy the rest of the line to the output. - (princ (buffer-substring - (progn - ;; Back up over whitespace, to preserve it. - (skip-chars-backward " \f\t") - (if (= (char-after (1+ (point))) ? ) - ;; Eat one space. - (forward-char 1)) - (point)) - (progn (forward-line 1) (point))) - outbuf))) - ((looking-at ";") - ;; Don't read the comment. - (forward-line 1)) - (t - (forward-sexp 1) - (forward-line 1)))))) + ;; Copy the rest of the line to the output. + (princ (buffer-substring + (progn + ;; Back up over whitespace, to preserve it. + (skip-chars-backward " \f\t") + (if (= (char-after (1+ (point))) ? ) + ;; Eat one space. + (forward-char 1)) + (point)) + (progn (forward-line 1) (point))) + outbuf))) + ((looking-at ";") + ;; Don't read the comment. + (forward-line 1)) + (t + (forward-sexp 1) + (forward-line 1)))))) - (when done-any - (with-current-buffer outbuf - (save-excursion - ;; Insert the section-header line which lists the file name - ;; and which functions are in it, etc. - (goto-char output-start) - (autoload-insert-section-header - outbuf autoloads-done load-name file - (nth 5 (file-attributes file))) - (insert ";;; Generated autoloads from " - (autoload-trim-file-name file) "\n")) - (insert generate-autoload-section-trailer))) - (message "Generating autoloads for %s...done" file)) - (or visited - ;; We created this buffer, so we should kill it. - (kill-buffer (current-buffer)))) - (not done-any))) + (when output-start + (let ((secondary-autoloads-file-buf + (if (local-variable-p 'generated-autoload-file) + (current-buffer)))) + (with-current-buffer outbuf + (save-excursion + ;; Insert the section-header line which lists the file name + ;; and which functions are in it, etc. + (goto-char output-start) + (autoload-insert-section-header + outbuf autoloads-done load-name relfile + (if secondary-autoloads-file-buf + ;; MD5 checksums are much better because they do not + ;; change unless the file changes (so they'll be + ;; equal on two different systems and will change + ;; less often than time-stamps, thus leading to fewer + ;; unneeded changes causing spurious conflicts), but + ;; using time-stamps is a very useful optimization, + ;; so we use time-stamps for the main autoloads file + ;; (loaddefs.el) where we have special ways to + ;; circumvent the "random change problem", and MD5 + ;; checksum in secondary autoload files where we do + ;; not need the time-stamp optimization because it is + ;; already provided by the primary autoloads file. + (md5 secondary-autoloads-file-buf + ;; We'd really want to just use + ;; `emacs-internal' instead. + nil nil 'emacs-mule-unix) + (nth 5 (file-attributes relfile)))) + (insert ";;; Generated autoloads from " relfile "\n")) + (insert generate-autoload-section-trailer)))) + (message "Generating autoloads for %s...done" file)) + (or visited + ;; We created this buffer, so we should kill it. + (kill-buffer (current-buffer)))) + ;; If the entries were added to some other buffer, then the file + ;; doesn't add entries to OUTFILE. + (or (not output-start) otherbuf)))) +(defun autoload-save-buffers () + (while autoload-modified-buffers + (with-current-buffer (pop autoload-modified-buffers) + (save-buffer)))) + ;;;###autoload (defun update-file-autoloads (file &optional save-after) "Update the autoloads for FILE in `generated-autoload-file' @@ -397,80 +462,80 @@ Return FILE if there was no autoload cookie in it, else nil." (interactive "fUpdate autoloads for file: \np") - (let ((load-name (let ((name (file-name-nondirectory file))) - (if (string-match "\\.elc?\\(\\.\\|$\\)" name) - (substring name 0 (match-beginning 0)) - name))) - (found nil) - (existing-buffer (get-file-buffer file)) - (no-autoloads nil)) - (save-excursion - ;; We want to get a value for generated-autoload-file from - ;; the local variables section if it's there. - (if existing-buffer - (set-buffer existing-buffer)) - ;; We must read/write the file without any code conversion, - ;; but still decode EOLs. - (let ((coding-system-for-read 'raw-text)) - (set-buffer (find-file-noselect - (autoload-ensure-default-file - (expand-file-name generated-autoload-file - (expand-file-name "lisp" - source-directory))))) - ;; This is to make generated-autoload-file have Unix EOLs, so - ;; that it is portable to all platforms. - (setq buffer-file-coding-system 'raw-text-unix)) - (or (> (buffer-size) 0) - (error "Autoloads file %s does not exist" buffer-file-name)) - (or (file-writable-p buffer-file-name) - (error "Autoloads file %s is not writable" buffer-file-name)) - (save-excursion - (save-restriction - (widen) - (goto-char (point-min)) - ;; Look for the section for LOAD-NAME. - (while (and (not found) - (search-forward generate-autoload-section-header nil t)) - (let ((form (autoload-read-section-header))) - (cond ((string= (nth 2 form) load-name) - ;; We found the section for this file. - ;; Check if it is up to date. - (let ((begin (match-beginning 0)) - (last-time (nth 4 form)) - (file-time (nth 5 (file-attributes file)))) - (if (and (or (null existing-buffer) - (not (buffer-modified-p existing-buffer))) - (listp last-time) (= (length last-time) 2) - (not (time-less-p last-time file-time))) - (progn - (if (interactive-p) - (message "\ -Autoload section for %s is up to date." - file)) - (setq found 'up-to-date)) - (search-forward generate-autoload-section-trailer) - (delete-region begin (point)) - (setq found t)))) - ((string< load-name (nth 2 form)) - ;; We've come to a section alphabetically later than - ;; LOAD-NAME. We assume the file is in order and so - ;; there must be no section for LOAD-NAME. We will - ;; insert one before the section here. - (goto-char (match-beginning 0)) - (setq found 'new))))) - (or found - (progn - (setq found 'new) - ;; No later sections in the file. Put before the last page. - (goto-char (point-max)) - (search-backward "\f" nil t))) - (or (eq found 'up-to-date) - (setq no-autoloads (generate-file-autoloads file))))) - (and save-after - (buffer-modified-p) - (save-buffer)) + (let* ((autoload-modified-buffers nil) + (no-autoloads (autoload-generate-file-autoloads file))) + (if autoload-modified-buffers + (if save-after (autoload-save-buffers)) + (if (interactive-p) + (message "Autoload section for %s is up to date." file))) + (if no-autoloads file))) - (if no-autoloads file)))) +(defun autoload-find-destination (file) + "Find the destination point of the current buffer's autoloads. +FILE is the file name of the current buffer. +Returns a buffer whose point is placed at the requested location. +Returns nil if the file's autoloads are uptodate, otherwise +removes any prior now out-of-date autoload entries." + (catch 'up-to-date + (let* ((load-name (autoload-file-load-name file)) + (buf (current-buffer)) + (existing-buffer (if buffer-file-name buf)) + (found nil)) + (with-current-buffer + ;; We must read/write the file without any code conversion, + ;; but still decode EOLs. + (let ((coding-system-for-read 'raw-text)) + (find-file-noselect + (autoload-ensure-default-file (autoload-generated-file)))) + ;; This is to make generated-autoload-file have Unix EOLs, so + ;; that it is portable to all platforms. + (setq buffer-file-coding-system 'raw-text-unix) + (or (> (buffer-size) 0) + (error "Autoloads file %s does not exist" buffer-file-name)) + (or (file-writable-p buffer-file-name) + (error "Autoloads file %s is not writable" buffer-file-name)) + (widen) + (goto-char (point-min)) + ;; Look for the section for LOAD-NAME. + (while (and (not found) + (search-forward generate-autoload-section-header nil t)) + (let ((form (autoload-read-section-header))) + (cond ((string= (nth 2 form) load-name) + ;; We found the section for this file. + ;; Check if it is up to date. + (let ((begin (match-beginning 0)) + (last-time (nth 4 form)) + (file-time (nth 5 (file-attributes file)))) + (if (and (or (null existing-buffer) + (not (buffer-modified-p existing-buffer))) + (or + ;; last-time is the time-stamp (specifying + ;; the last time we looked at the file) and + ;; the file hasn't been changed since. + (and (listp last-time) (= (length last-time) 2) + (not (time-less-p last-time file-time))) + ;; last-time is an MD5 checksum instead. + (and (stringp last-time) + (equal last-time + (md5 buf nil nil 'emacs-mule))))) + (throw 'up-to-date nil) + (autoload-remove-section begin) + (setq found t)))) + ((string< load-name (nth 2 form)) + ;; We've come to a section alphabetically later than + ;; LOAD-NAME. We assume the file is in order and so + ;; there must be no section for LOAD-NAME. We will + ;; insert one before the section here. + (goto-char (match-beginning 0)) + (setq found t))))) + (or found + (progn + ;; No later sections in the file. Put before the last page. + (goto-char (point-max)) + (search-backward "\f" nil t))) + (unless (memq (current-buffer) autoload-modified-buffers) + (push (current-buffer) autoload-modified-buffers)) + (current-buffer))))) (defun autoload-remove-section (begin) (goto-char begin) @@ -498,20 +563,21 @@ (directory-files (expand-file-name dir) t files-re)) dirs))) + (done ()) (this-time (current-time)) - (no-autoloads nil) ;files with no autoload cookies. - (autoloads-file - (expand-file-name generated-autoload-file - (expand-file-name "lisp" source-directory))) - (top-dir (file-name-directory autoloads-file))) + ;; Files with no autoload cookies or whose autoloads go to other + ;; files because of file-local autoload-generated-file settings. + (no-autoloads nil) + (autoload-modified-buffers nil)) (with-current-buffer - (find-file-noselect (autoload-ensure-default-file autoloads-file)) + (find-file-noselect + (autoload-ensure-default-file (autoload-generated-file))) (save-excursion ;; Canonicalize file names and remove the autoload file itself. - (setq files (delete (autoload-trim-file-name buffer-file-name) - (mapcar 'autoload-trim-file-name files))) + (setq files (delete (file-relative-name buffer-file-name) + (mapcar 'file-relative-name files))) (goto-char (point-min)) (while (search-forward generate-autoload-section-header nil t) @@ -531,19 +597,27 @@ (push file no-autoloads) (setq files (delete file files))))))) ((not (stringp file))) - ((not (file-exists-p (expand-file-name file top-dir))) - ;; Remove the obsolete section. + ((or (not (file-exists-p file)) + ;; Remove duplicates as well, just in case. + (member file done)) + ;; Remove the obsolete section. (autoload-remove-section (match-beginning 0))) - ((equal (nth 4 form) (nth 5 (file-attributes file))) + ((not (time-less-p (nth 4 form) + (nth 5 (file-attributes file)))) ;; File hasn't changed. nil) (t - (update-file-autoloads file))) + (autoload-remove-section (match-beginning 0)) + (if (autoload-generate-file-autoloads + file (current-buffer) buffer-file-name) + (push file no-autoloads)))) + (push file done) (setq files (delete file files))))) ;; Elements remaining in FILES have no existing autoload sections yet. - (setq no-autoloads - (append no-autoloads - (delq nil (mapcar 'update-file-autoloads files)))) + (dolist (file files) + (if (autoload-generate-file-autoloads file nil buffer-file-name) + (push file no-autoloads))) + (when no-autoloads ;; Sort them for better readability. (setq no-autoloads (sort no-autoloads 'string<)) @@ -554,7 +628,10 @@ (current-buffer) nil nil no-autoloads this-time) (insert generate-autoload-section-trailer)) - (save-buffer)))) + (save-buffer) + ;; In case autoload entries were added to other files because of + ;; file-local autoload-generated-file settings. + (autoload-save-buffers)))) (define-obsolete-function-alias 'update-autoloads-from-directories 'update-directory-autoloads "22.1") diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/cl-extra.el --- a/lisp/emacs-lisp/cl-extra.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/cl-extra.el Sun Jul 15 02:05:20 2007 +0000 @@ -43,6 +43,7 @@ ;;; Type coercion. +;;;###autoload (defun coerce (x type) "Coerce OBJECT to type TYPE. TYPE is a Common Lisp type specifier. @@ -60,6 +61,7 @@ ;;; Predicates. +;;;###autoload (defun equalp (x y) "Return t if two Lisp objects have similar structures and contents. This is like `equal', except that it accepts numerically equal @@ -87,6 +89,7 @@ ;;; Control structures. +;;;###autoload (defun cl-mapcar-many (cl-func cl-seqs) (if (cdr (cdr cl-seqs)) (let* ((cl-res nil) @@ -119,6 +122,7 @@ cl-res))) (nreverse cl-res)))) +;;;###autoload (defun map (cl-type cl-func cl-seq &rest cl-rest) "Map a FUNCTION across one or more SEQUENCEs, returning a sequence. TYPE is the sequence type to return. @@ -126,6 +130,7 @@ (let ((cl-res (apply 'mapcar* cl-func cl-seq cl-rest))) (and cl-type (coerce cl-res cl-type)))) +;;;###autoload (defun maplist (cl-func cl-list &rest cl-rest) "Map FUNCTION to each sublist of LIST or LISTs. Like `mapcar', except applies to lists and their cdr's rather than to @@ -154,6 +159,7 @@ cl-seq) (mapc cl-func cl-seq))) +;;;###autoload (defun mapl (cl-func cl-list &rest cl-rest) "Like `maplist', but does not accumulate values returned by the function. \n(fn FUNCTION LIST...)" @@ -163,16 +169,19 @@ (while cl-p (funcall cl-func cl-p) (setq cl-p (cdr cl-p))))) cl-list) +;;;###autoload (defun mapcan (cl-func cl-seq &rest cl-rest) "Like `mapcar', but nconc's together the values returned by the function. \n(fn FUNCTION SEQUENCE...)" (apply 'nconc (apply 'mapcar* cl-func cl-seq cl-rest))) +;;;###autoload (defun mapcon (cl-func cl-list &rest cl-rest) "Like `maplist', but nconc's together the values returned by the function. \n(fn FUNCTION LIST...)" (apply 'nconc (apply 'maplist cl-func cl-list cl-rest))) +;;;###autoload (defun some (cl-pred cl-seq &rest cl-rest) "Return true if PREDICATE is true of any element of SEQ or SEQs. If so, return the true (non-nil) value returned by PREDICATE. @@ -188,6 +197,7 @@ (while (and cl-seq (not (setq cl-x (funcall cl-pred (pop cl-seq)))))) cl-x))) +;;;###autoload (defun every (cl-pred cl-seq &rest cl-rest) "Return true if PREDICATE is true of every element of SEQ or SEQs. \n(fn PREDICATE SEQ...)" @@ -201,19 +211,23 @@ (setq cl-seq (cdr cl-seq))) (null cl-seq))) +;;;###autoload (defun notany (cl-pred cl-seq &rest cl-rest) "Return true if PREDICATE is false of every element of SEQ or SEQs. \n(fn PREDICATE SEQ...)" (not (apply 'some cl-pred cl-seq cl-rest))) +;;;###autoload (defun notevery (cl-pred cl-seq &rest cl-rest) "Return true if PREDICATE is false of some element of SEQ or SEQs. \n(fn PREDICATE SEQ...)" (not (apply 'every cl-pred cl-seq cl-rest))) ;;; Support for `loop'. +;;;###autoload (defalias 'cl-map-keymap 'map-keymap) +;;;###autoload (defun cl-map-keymap-recursively (cl-func-rec cl-map &optional cl-base) (or cl-base (setq cl-base (copy-sequence [0]))) @@ -228,6 +242,7 @@ (funcall cl-func-rec cl-base cl-bind)))) cl-map)) +;;;###autoload (defun cl-map-intervals (cl-func &optional cl-what cl-prop cl-start cl-end) (or cl-what (setq cl-what (current-buffer))) (if (bufferp cl-what) @@ -255,6 +270,7 @@ (funcall cl-func cl-start (min cl-next cl-end)) (setq cl-start cl-next))))) +;;;###autoload (defun cl-map-overlays (cl-func &optional cl-buffer cl-start cl-end cl-arg) (or cl-buffer (setq cl-buffer (current-buffer))) (if (fboundp 'overlay-lists) @@ -296,6 +312,7 @@ (set-marker cl-mark nil) (if cl-mark2 (set-marker cl-mark2 nil))))) ;;; Support for `setf'. +;;;###autoload (defun cl-set-frame-visible-p (frame val) (cond ((null val) (make-frame-invisible frame)) ((eq val 'icon) (iconify-frame frame)) @@ -304,6 +321,7 @@ ;;; Support for `progv'. (defvar cl-progv-save) +;;;###autoload (defun cl-progv-before (syms values) (while syms (push (if (boundp (car syms)) @@ -323,6 +341,7 @@ ;;; Numbers. +;;;###autoload (defun gcd (&rest args) "Return the greatest common divisor of the arguments." (let ((a (abs (or (pop args) 0)))) @@ -331,6 +350,7 @@ (while (> b 0) (setq b (% a (setq a b)))))) a)) +;;;###autoload (defun lcm (&rest args) "Return the least common multiple of the arguments." (if (memq 0 args) @@ -341,6 +361,7 @@ (setq a (* (/ a (gcd a b)) b)))) a))) +;;;###autoload (defun isqrt (x) "Return the integer square root of the argument." (if (and (integerp x) (> x 0)) @@ -352,12 +373,14 @@ g) (if (eq x 0) 0 (signal 'arith-error nil)))) +;;;###autoload (defun floor* (x &optional y) "Return a list of the floor of X and the fractional part of X. With two arguments, return floor and remainder of their quotient." (let ((q (floor x y))) (list q (- x (if y (* y q) q))))) +;;;###autoload (defun ceiling* (x &optional y) "Return a list of the ceiling of X and the fractional part of X. With two arguments, return ceiling and remainder of their quotient." @@ -365,12 +388,14 @@ (if (= (car (cdr res)) 0) res (list (1+ (car res)) (- (car (cdr res)) (or y 1)))))) +;;;###autoload (defun truncate* (x &optional y) "Return a list of the integer part of X and the fractional part of X. With two arguments, return truncation and remainder of their quotient." (if (eq (>= x 0) (or (null y) (>= y 0))) (floor* x y) (ceiling* x y))) +;;;###autoload (defun round* (x &optional y) "Return a list of X rounded to the nearest integer and the remainder. With two arguments, return rounding and remainder of their quotient." @@ -389,14 +414,17 @@ (let ((q (round x))) (list q (- x q)))))) +;;;###autoload (defun mod* (x y) "The remainder of X divided by Y, with the same sign as Y." (nth 1 (floor* x y))) +;;;###autoload (defun rem* (x y) "The remainder of X divided by Y, with the same sign as X." (nth 1 (truncate* x y))) +;;;###autoload (defun signum (x) "Return 1 if X is positive, -1 if negative, 0 if zero." (cond ((> x 0) 1) ((< x 0) -1) (t 0))) @@ -405,6 +433,7 @@ ;; Random numbers. (defvar *random-state*) +;;;###autoload (defun random* (lim &optional state) "Return a random nonnegative number less than LIM, an integer or float. Optional second arg STATE is a random-state object." @@ -412,7 +441,7 @@ ;; Inspired by "ran3" from Numerical Recipes. Additive congruential method. (let ((vec (aref state 3))) (if (integerp vec) - (let ((i 0) (j (- 1357335 (% (abs vec) 1357333))) (k 1) ii) + (let ((i 0) (j (- 1357335 (% (abs vec) 1357333))) (k 1)) (aset state 3 (setq vec (make-vector 55 nil))) (aset vec 0 j) (while (> (setq i (% (+ i 21) 55)) 0) @@ -429,6 +458,7 @@ (if (< (setq n (logand n mask)) lim) n (random* lim state)))) (* (/ n '8388608e0) lim))))) +;;;###autoload (defun make-random-state (&optional state) "Return a copy of random-state STATE, or of `*random-state*' if omitted. If STATE is t, return a new state object seeded from the time of day." @@ -437,6 +467,7 @@ ((integerp state) (vector 'cl-random-state-tag -1 30 state)) (t (make-random-state (cl-random-time))))) +;;;###autoload (defun random-state-p (object) "Return t if OBJECT is a random-state object." (and (vectorp object) (= (length object) 4) @@ -460,6 +491,7 @@ (defvar float-epsilon) (defvar float-negative-epsilon) +;;;###autoload (defun cl-float-limits () (or most-positive-float (not (numberp '2e1)) (let ((x '2e0) y z) @@ -497,6 +529,7 @@ ;;; Sequence functions. +;;;###autoload (defun subseq (seq start &optional end) "Return the subsequence of SEQ from START to END. If END is omitted, it defaults to the length of the sequence. @@ -522,6 +555,7 @@ (setq i (1+ i) start (1+ start))) res)))))) +;;;###autoload (defun concatenate (type &rest seqs) "Concatenate, into a sequence of type TYPE, the argument SEQUENCEs. \n(fn TYPE SEQUENCE...)" @@ -533,14 +567,17 @@ ;;; List functions. +;;;###autoload (defun revappend (x y) "Equivalent to (append (reverse X) Y)." (nconc (reverse x) y)) +;;;###autoload (defun nreconc (x y) "Equivalent to (nconc (nreverse X) Y)." (nconc (nreverse x) y)) +;;;###autoload (defun list-length (x) "Return the length of list X. Return nil if list is circular." (let ((n 0) (fast x) (slow x)) @@ -548,6 +585,7 @@ (setq n (+ n 2) fast (cdr (cdr fast)) slow (cdr slow))) (if fast (if (cdr fast) nil (1+ n)) n))) +;;;###autoload (defun tailp (sublist list) "Return true if SUBLIST is a tail of LIST." (while (and (consp list) (not (eq sublist list))) @@ -559,6 +597,7 @@ ;;; Property lists. +;;;###autoload (defun get* (sym tag &optional def) ; See compiler macro in cl-macs.el "Return the value of SYMBOL's PROPNAME property, or DEFAULT if none. \n(fn SYMBOL PROPNAME &optional DEFAULT)" @@ -569,6 +608,7 @@ (setq plist (cdr (cdr plist)))) (if plist (car (cdr plist)) def))))) +;;;###autoload (defun getf (plist tag &optional def) "Search PROPLIST for property PROPNAME; return its value or DEFAULT. PROPLIST is a list of the sort returned by `symbol-plist'. @@ -583,16 +623,19 @@ (setq plist (cdr (cdr plist)))) (if plist (car (cdr plist)) def)))) +;;;###autoload (defun cl-set-getf (plist tag val) (let ((p plist)) (while (and p (not (eq (car p) tag))) (setq p (cdr (cdr p)))) (if p (progn (setcar (cdr p) val) plist) (list* tag val plist)))) +;;;###autoload (defun cl-do-remf (plist tag) (let ((p (cdr plist))) (while (and (cdr p) (not (eq (car (cdr p)) tag))) (setq p (cdr (cdr p)))) (and (cdr p) (progn (setcdr p (cdr (cdr (cdr p)))) t)))) +;;;###autoload (defun cl-remprop (sym tag) "Remove from SYMBOL's plist the property PROPNAME and its value. \n(fn SYMBOL PROPNAME)" @@ -600,6 +643,7 @@ (if (and plist (eq tag (car plist))) (progn (setplist sym (cdr (cdr plist))) t) (cl-do-remf plist tag)))) +;;;###autoload (defalias 'remprop 'cl-remprop) @@ -616,14 +660,22 @@ (defvar cl-builtin-clrhash (symbol-function 'clrhash)) (defvar cl-builtin-maphash (symbol-function 'maphash)) +;;;###autoload (defalias 'cl-gethash 'gethash) +;;;###autoload (defalias 'cl-puthash 'puthash) +;;;###autoload (defalias 'cl-remhash 'remhash) +;;;###autoload (defalias 'cl-clrhash 'clrhash) +;;;###autoload (defalias 'cl-maphash 'maphash) ;; These three actually didn't exist in Emacs-20. +;;;###autoload (defalias 'cl-make-hash-table 'make-hash-table) +;;;###autoload (defalias 'cl-hash-table-p 'hash-table-p) +;;;###autoload (defalias 'cl-hash-table-count 'hash-table-count) ;;; Some debugging aids. @@ -672,6 +724,7 @@ (defvar cl-macroexpand-cmacs nil) (defvar cl-closure-vars nil) +;;;###autoload (defun cl-macroexpand-all (form &optional env) "Expand all macro calls through a Lisp FORM. This also does some trivial optimizations to make the form prettier." @@ -753,6 +806,7 @@ (defun cl-macroexpand-body (body &optional env) (mapcar (function (lambda (x) (cl-macroexpand-all x env))) body)) +;;;###autoload (defun cl-prettyexpand (form &optional full) (message "Expanding...") (let ((cl-macroexpand-cmacs full) (cl-compiling-file full) @@ -767,5 +821,9 @@ (run-hooks 'cl-extra-load-hook) +;; Local variables: +;; generated-autoload-file: "cl-loaddefs.el" +;; End: + ;; arch-tag: bcd03437-0871-43fb-a8f1-ad0e0b5427ed ;;; cl-extra.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/cl-loaddefs.el --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/emacs-lisp/cl-loaddefs.el Sun Jul 15 02:05:20 2007 +0000 @@ -0,0 +1,1234 @@ +;;; cl-loaddefs.el --- automatically extracted autoloads +;; +;;; Code: + + +;;;### (autoloads (cl-prettyexpand cl-macroexpand-all cl-remprop +;;;;;; cl-do-remf cl-set-getf getf get* tailp list-length nreconc +;;;;;; revappend concatenate subseq cl-float-limits random-state-p +;;;;;; make-random-state random* signum rem* mod* round* truncate* +;;;;;; ceiling* floor* isqrt lcm gcd cl-progv-before cl-set-frame-visible-p +;;;;;; cl-map-overlays cl-map-intervals cl-map-keymap-recursively +;;;;;; notevery notany every some mapcon mapcan mapl maplist map +;;;;;; cl-mapcar-many equalp coerce) "cl-extra" "cl-extra.el" "47c92504dda976a632c2c10bedd4b6a4") +;;; Generated autoloads from cl-extra.el + +(autoload (quote coerce) "cl-extra" "\ +Coerce OBJECT to type TYPE. +TYPE is a Common Lisp type specifier. + +\(fn OBJECT TYPE)" nil nil) + +(autoload (quote equalp) "cl-extra" "\ +Return t if two Lisp objects have similar structures and contents. +This is like `equal', except that it accepts numerically equal +numbers of different types (float vs. integer), and also compares +strings case-insensitively. + +\(fn X Y)" nil nil) + +(autoload (quote cl-mapcar-many) "cl-extra" "\ +Not documented + +\(fn CL-FUNC CL-SEQS)" nil nil) + +(autoload (quote map) "cl-extra" "\ +Map a FUNCTION across one or more SEQUENCEs, returning a sequence. +TYPE is the sequence type to return. + +\(fn TYPE FUNCTION SEQUENCE...)" nil nil) + +(autoload (quote maplist) "cl-extra" "\ +Map FUNCTION to each sublist of LIST or LISTs. +Like `mapcar', except applies to lists and their cdr's rather than to +the elements themselves. + +\(fn FUNCTION LIST...)" nil nil) + +(autoload (quote mapl) "cl-extra" "\ +Like `maplist', but does not accumulate values returned by the function. + +\(fn FUNCTION LIST...)" nil nil) + +(autoload (quote mapcan) "cl-extra" "\ +Like `mapcar', but nconc's together the values returned by the function. + +\(fn FUNCTION SEQUENCE...)" nil nil) + +(autoload (quote mapcon) "cl-extra" "\ +Like `maplist', but nconc's together the values returned by the function. + +\(fn FUNCTION LIST...)" nil nil) + +(autoload (quote some) "cl-extra" "\ +Return true if PREDICATE is true of any element of SEQ or SEQs. +If so, return the true (non-nil) value returned by PREDICATE. + +\(fn PREDICATE SEQ...)" nil nil) + +(autoload (quote every) "cl-extra" "\ +Return true if PREDICATE is true of every element of SEQ or SEQs. + +\(fn PREDICATE SEQ...)" nil nil) + +(autoload (quote notany) "cl-extra" "\ +Return true if PREDICATE is false of every element of SEQ or SEQs. + +\(fn PREDICATE SEQ...)" nil nil) + +(autoload (quote notevery) "cl-extra" "\ +Return true if PREDICATE is false of some element of SEQ or SEQs. + +\(fn PREDICATE SEQ...)" nil nil) + +(defalias (quote cl-map-keymap) (quote map-keymap)) + +(autoload (quote cl-map-keymap-recursively) "cl-extra" "\ +Not documented + +\(fn CL-FUNC-REC CL-MAP &optional CL-BASE)" nil nil) + +(autoload (quote cl-map-intervals) "cl-extra" "\ +Not documented + +\(fn CL-FUNC &optional CL-WHAT CL-PROP CL-START CL-END)" nil nil) + +(autoload (quote cl-map-overlays) "cl-extra" "\ +Not documented + +\(fn CL-FUNC &optional CL-BUFFER CL-START CL-END CL-ARG)" nil nil) + +(autoload (quote cl-set-frame-visible-p) "cl-extra" "\ +Not documented + +\(fn FRAME VAL)" nil nil) + +(autoload (quote cl-progv-before) "cl-extra" "\ +Not documented + +\(fn SYMS VALUES)" nil nil) + +(autoload (quote gcd) "cl-extra" "\ +Return the greatest common divisor of the arguments. + +\(fn &rest ARGS)" nil nil) + +(autoload (quote lcm) "cl-extra" "\ +Return the least common multiple of the arguments. + +\(fn &rest ARGS)" nil nil) + +(autoload (quote isqrt) "cl-extra" "\ +Return the integer square root of the argument. + +\(fn X)" nil nil) + +(autoload (quote floor*) "cl-extra" "\ +Return a list of the floor of X and the fractional part of X. +With two arguments, return floor and remainder of their quotient. + +\(fn X &optional Y)" nil nil) + +(autoload (quote ceiling*) "cl-extra" "\ +Return a list of the ceiling of X and the fractional part of X. +With two arguments, return ceiling and remainder of their quotient. + +\(fn X &optional Y)" nil nil) + +(autoload (quote truncate*) "cl-extra" "\ +Return a list of the integer part of X and the fractional part of X. +With two arguments, return truncation and remainder of their quotient. + +\(fn X &optional Y)" nil nil) + +(autoload (quote round*) "cl-extra" "\ +Return a list of X rounded to the nearest integer and the remainder. +With two arguments, return rounding and remainder of their quotient. + +\(fn X &optional Y)" nil nil) + +(autoload (quote mod*) "cl-extra" "\ +The remainder of X divided by Y, with the same sign as Y. + +\(fn X Y)" nil nil) + +(autoload (quote rem*) "cl-extra" "\ +The remainder of X divided by Y, with the same sign as X. + +\(fn X Y)" nil nil) + +(autoload (quote signum) "cl-extra" "\ +Return 1 if X is positive, -1 if negative, 0 if zero. + +\(fn X)" nil nil) + +(autoload (quote random*) "cl-extra" "\ +Return a random nonnegative number less than LIM, an integer or float. +Optional second arg STATE is a random-state object. + +\(fn LIM &optional STATE)" nil nil) + +(autoload (quote make-random-state) "cl-extra" "\ +Return a copy of random-state STATE, or of `*random-state*' if omitted. +If STATE is t, return a new state object seeded from the time of day. + +\(fn &optional STATE)" nil nil) + +(autoload (quote random-state-p) "cl-extra" "\ +Return t if OBJECT is a random-state object. + +\(fn OBJECT)" nil nil) + +(autoload (quote cl-float-limits) "cl-extra" "\ +Not documented + +\(fn)" nil nil) + +(autoload (quote subseq) "cl-extra" "\ +Return the subsequence of SEQ from START to END. +If END is omitted, it defaults to the length of the sequence. +If START or END is negative, it counts from the end. + +\(fn SEQ START &optional END)" nil nil) + +(autoload (quote concatenate) "cl-extra" "\ +Concatenate, into a sequence of type TYPE, the argument SEQUENCEs. + +\(fn TYPE SEQUENCE...)" nil nil) + +(autoload (quote revappend) "cl-extra" "\ +Equivalent to (append (reverse X) Y). + +\(fn X Y)" nil nil) + +(autoload (quote nreconc) "cl-extra" "\ +Equivalent to (nconc (nreverse X) Y). + +\(fn X Y)" nil nil) + +(autoload (quote list-length) "cl-extra" "\ +Return the length of list X. Return nil if list is circular. + +\(fn X)" nil nil) + +(autoload (quote tailp) "cl-extra" "\ +Return true if SUBLIST is a tail of LIST. + +\(fn SUBLIST LIST)" nil nil) + +(autoload (quote get*) "cl-extra" "\ +Return the value of SYMBOL's PROPNAME property, or DEFAULT if none. + +\(fn SYMBOL PROPNAME &optional DEFAULT)" nil nil) + +(autoload (quote getf) "cl-extra" "\ +Search PROPLIST for property PROPNAME; return its value or DEFAULT. +PROPLIST is a list of the sort returned by `symbol-plist'. + +\(fn PROPLIST PROPNAME &optional DEFAULT)" nil nil) + +(autoload (quote cl-set-getf) "cl-extra" "\ +Not documented + +\(fn PLIST TAG VAL)" nil nil) + +(autoload (quote cl-do-remf) "cl-extra" "\ +Not documented + +\(fn PLIST TAG)" nil nil) + +(autoload (quote cl-remprop) "cl-extra" "\ +Remove from SYMBOL's plist the property PROPNAME and its value. + +\(fn SYMBOL PROPNAME)" nil nil) + +(defalias (quote remprop) (quote cl-remprop)) + +(defalias (quote cl-gethash) (quote gethash)) + +(defalias (quote cl-puthash) (quote puthash)) + +(defalias (quote cl-remhash) (quote remhash)) + +(defalias (quote cl-clrhash) (quote clrhash)) + +(defalias (quote cl-maphash) (quote maphash)) + +(defalias (quote cl-make-hash-table) (quote make-hash-table)) + +(defalias (quote cl-hash-table-p) (quote hash-table-p)) + +(defalias (quote cl-hash-table-count) (quote hash-table-count)) + +(autoload (quote cl-macroexpand-all) "cl-extra" "\ +Expand all macro calls through a Lisp FORM. +This also does some trivial optimizations to make the form prettier. + +\(fn FORM &optional ENV)" nil nil) + +(autoload (quote cl-prettyexpand) "cl-extra" "\ +Not documented + +\(fn FORM &optional FULL)" nil nil) + +;;;*** + +;;;### (autoloads (compiler-macroexpand define-compiler-macro ignore-errors +;;;;;; assert check-type typep cl-struct-setf-expander defstruct +;;;;;; define-modify-macro callf2 callf letf* letf rotatef shiftf +;;;;;; remf cl-do-pop psetf setf get-setf-method defsetf define-setf-method +;;;;;; declare the locally multiple-value-setq multiple-value-bind +;;;;;; lexical-let* lexical-let symbol-macrolet macrolet labels +;;;;;; flet progv psetq do-all-symbols do-symbols dotimes dolist +;;;;;; do* do loop return-from return block etypecase typecase ecase +;;;;;; case load-time-value eval-when destructuring-bind function* +;;;;;; defmacro* defun* gentemp gensym cl-compile-time-init) "cl-macs" +;;;;;; "cl-macs.el" "7ccc827d272482ca276937ca18a7895a") +;;; Generated autoloads from cl-macs.el + +(autoload (quote cl-compile-time-init) "cl-macs" "\ +Not documented + +\(fn)" nil nil) + +(autoload (quote gensym) "cl-macs" "\ +Generate a new uninterned symbol. +The name is made by appending a number to PREFIX, default \"G\". + +\(fn &optional PREFIX)" nil nil) + +(autoload (quote gentemp) "cl-macs" "\ +Generate a new interned symbol with a unique name. +The name is made by appending a number to PREFIX, default \"G\". + +\(fn &optional PREFIX)" nil nil) + +(autoload (quote defun*) "cl-macs" "\ +Define NAME as a function. +Like normal `defun', except ARGLIST allows full Common Lisp conventions, +and BODY is implicitly surrounded by (block NAME ...). + +\(fn NAME ARGLIST [DOCSTRING] BODY...)" nil (quote macro)) + +(autoload (quote defmacro*) "cl-macs" "\ +Define NAME as a macro. +Like normal `defmacro', except ARGLIST allows full Common Lisp conventions, +and BODY is implicitly surrounded by (block NAME ...). + +\(fn NAME ARGLIST [DOCSTRING] BODY...)" nil (quote macro)) + +(autoload (quote function*) "cl-macs" "\ +Introduce a function. +Like normal `function', except that if argument is a lambda form, +its argument list allows full Common Lisp conventions. + +\(fn FUNC)" nil (quote macro)) + +(autoload (quote destructuring-bind) "cl-macs" "\ +Not documented + +\(fn ARGS EXPR &rest BODY)" nil (quote macro)) + +(autoload (quote eval-when) "cl-macs" "\ +Control when BODY is evaluated. +If `compile' is in WHEN, BODY is evaluated when compiled at top-level. +If `load' is in WHEN, BODY is evaluated when loaded after top-level compile. +If `eval' is in WHEN, BODY is evaluated when interpreted or at non-top-level. + +\(fn (WHEN...) BODY...)" nil (quote macro)) + +(autoload (quote load-time-value) "cl-macs" "\ +Like `progn', but evaluates the body at load time. +The result of the body appears to the compiler as a quoted constant. + +\(fn FORM &optional READ-ONLY)" nil (quote macro)) + +(autoload (quote case) "cl-macs" "\ +Eval EXPR and choose among clauses on that value. +Each clause looks like (KEYLIST BODY...). EXPR is evaluated and compared +against each key in each KEYLIST; the corresponding BODY is evaluated. +If no clause succeeds, case returns nil. A single atom may be used in +place of a KEYLIST of one atom. A KEYLIST of t or `otherwise' is +allowed only in the final clause, and matches if no other keys match. +Key values are compared by `eql'. + +\(fn EXPR (KEYLIST BODY...)...)" nil (quote macro)) + +(autoload (quote ecase) "cl-macs" "\ +Like `case', but error if no case fits. +`otherwise'-clauses are not allowed. + +\(fn EXPR (KEYLIST BODY...)...)" nil (quote macro)) + +(autoload (quote typecase) "cl-macs" "\ +Evals EXPR, chooses among clauses on that value. +Each clause looks like (TYPE BODY...). EXPR is evaluated and, if it +satisfies TYPE, the corresponding BODY is evaluated. If no clause succeeds, +typecase returns nil. A TYPE of t or `otherwise' is allowed only in the +final clause, and matches if no other keys match. + +\(fn EXPR (TYPE BODY...)...)" nil (quote macro)) + +(autoload (quote etypecase) "cl-macs" "\ +Like `typecase', but error if no case fits. +`otherwise'-clauses are not allowed. + +\(fn EXPR (TYPE BODY...)...)" nil (quote macro)) + +(autoload (quote block) "cl-macs" "\ +Define a lexically-scoped block named NAME. +NAME may be any symbol. Code inside the BODY forms can call `return-from' +to jump prematurely out of the block. This differs from `catch' and `throw' +in two respects: First, the NAME is an unevaluated symbol rather than a +quoted symbol or other form; and second, NAME is lexically rather than +dynamically scoped: Only references to it within BODY will work. These +references may appear inside macro expansions, but not inside functions +called from BODY. + +\(fn NAME &rest BODY)" nil (quote macro)) + +(autoload (quote return) "cl-macs" "\ +Return from the block named nil. +This is equivalent to `(return-from nil RESULT)'. + +\(fn &optional RESULT)" nil (quote macro)) + +(autoload (quote return-from) "cl-macs" "\ +Return from the block named NAME. +This jump out to the innermost enclosing `(block NAME ...)' form, +returning RESULT from that form (or nil if RESULT is omitted). +This is compatible with Common Lisp, but note that `defun' and +`defmacro' do not create implicit blocks as they do in Common Lisp. + +\(fn NAME &optional RESULT)" nil (quote macro)) + +(autoload (quote loop) "cl-macs" "\ +The Common Lisp `loop' macro. +Valid clauses are: + for VAR from/upfrom/downfrom NUM to/upto/downto/above/below NUM by NUM, + for VAR in LIST by FUNC, for VAR on LIST by FUNC, for VAR = INIT then EXPR, + for VAR across ARRAY, repeat NUM, with VAR = INIT, while COND, until COND, + always COND, never COND, thereis COND, collect EXPR into VAR, + append EXPR into VAR, nconc EXPR into VAR, sum EXPR into VAR, + count EXPR into VAR, maximize EXPR into VAR, minimize EXPR into VAR, + if COND CLAUSE [and CLAUSE]... else CLAUSE [and CLAUSE...], + unless COND CLAUSE [and CLAUSE]... else CLAUSE [and CLAUSE...], + do EXPRS..., initially EXPRS..., finally EXPRS..., return EXPR, + finally return EXPR, named NAME. + +\(fn CLAUSE...)" nil (quote macro)) + +(autoload (quote do) "cl-macs" "\ +The Common Lisp `do' loop. + +\(fn ((VAR INIT [STEP])...) (END-TEST [RESULT...]) BODY...)" nil (quote macro)) + +(autoload (quote do*) "cl-macs" "\ +The Common Lisp `do*' loop. + +\(fn ((VAR INIT [STEP])...) (END-TEST [RESULT...]) BODY...)" nil (quote macro)) + +(autoload (quote dolist) "cl-macs" "\ +Loop over a list. +Evaluate BODY with VAR bound to each `car' from LIST, in turn. +Then evaluate RESULT to get return value, default nil. + +\(fn (VAR LIST [RESULT]) BODY...)" nil (quote macro)) + +(autoload (quote dotimes) "cl-macs" "\ +Loop a certain number of times. +Evaluate BODY with VAR bound to successive integers from 0, inclusive, +to COUNT, exclusive. Then evaluate RESULT to get return value, default +nil. + +\(fn (VAR COUNT [RESULT]) BODY...)" nil (quote macro)) + +(autoload (quote do-symbols) "cl-macs" "\ +Loop over all symbols. +Evaluate BODY with VAR bound to each interned symbol, or to each symbol +from OBARRAY. + +\(fn (VAR [OBARRAY [RESULT]]) BODY...)" nil (quote macro)) + +(autoload (quote do-all-symbols) "cl-macs" "\ +Not documented + +\(fn SPEC &rest BODY)" nil (quote macro)) + +(autoload (quote psetq) "cl-macs" "\ +Set SYMs to the values VALs in parallel. +This is like `setq', except that all VAL forms are evaluated (in order) +before assigning any symbols SYM to the corresponding values. + +\(fn SYM VAL SYM VAL ...)" nil (quote macro)) + +(autoload (quote progv) "cl-macs" "\ +Bind SYMBOLS to VALUES dynamically in BODY. +The forms SYMBOLS and VALUES are evaluated, and must evaluate to lists. +Each symbol in the first list is bound to the corresponding value in the +second list (or made unbound if VALUES is shorter than SYMBOLS); then the +BODY forms are executed and their result is returned. This is much like +a `let' form, except that the list of symbols can be computed at run-time. + +\(fn SYMBOLS VALUES &rest BODY)" nil (quote macro)) + +(autoload (quote flet) "cl-macs" "\ +Make temporary function definitions. +This is an analogue of `let' that operates on the function cell of FUNC +rather than its value cell. The FORMs are evaluated with the specified +function definitions in place, then the definitions are undone (the FUNCs +go back to their previous definitions, or lack thereof). + +\(fn ((FUNC ARGLIST BODY...) ...) FORM...)" nil (quote macro)) + +(autoload (quote labels) "cl-macs" "\ +Make temporary function bindings. +This is like `flet', except the bindings are lexical instead of dynamic. +Unlike `flet', this macro is fully compliant with the Common Lisp standard. + +\(fn ((FUNC ARGLIST BODY...) ...) FORM...)" nil (quote macro)) + +(autoload (quote macrolet) "cl-macs" "\ +Make temporary macro definitions. +This is like `flet', but for macros instead of functions. + +\(fn ((NAME ARGLIST BODY...) ...) FORM...)" nil (quote macro)) + +(autoload (quote symbol-macrolet) "cl-macs" "\ +Make symbol macro definitions. +Within the body FORMs, references to the variable NAME will be replaced +by EXPANSION, and (setq NAME ...) will act like (setf EXPANSION ...). + +\(fn ((NAME EXPANSION) ...) FORM...)" nil (quote macro)) + +(autoload (quote lexical-let) "cl-macs" "\ +Like `let', but lexically scoped. +The main visible difference is that lambdas inside BODY will create +lexical closures as in Common Lisp. + +\(fn VARLIST BODY)" nil (quote macro)) + +(autoload (quote lexical-let*) "cl-macs" "\ +Like `let*', but lexically scoped. +The main visible difference is that lambdas inside BODY will create +lexical closures as in Common Lisp. + +\(fn VARLIST BODY)" nil (quote macro)) + +(autoload (quote multiple-value-bind) "cl-macs" "\ +Collect multiple return values. +FORM must return a list; the BODY is then executed with the first N elements +of this list bound (`let'-style) to each of the symbols SYM in turn. This +is analogous to the Common Lisp `multiple-value-bind' macro, using lists to +simulate true multiple return values. For compatibility, (values A B C) is +a synonym for (list A B C). + +\(fn (SYM...) FORM BODY)" nil (quote macro)) + +(autoload (quote multiple-value-setq) "cl-macs" "\ +Collect multiple return values. +FORM must return a list; the first N elements of this list are stored in +each of the symbols SYM in turn. This is analogous to the Common Lisp +`multiple-value-setq' macro, using lists to simulate true multiple return +values. For compatibility, (values A B C) is a synonym for (list A B C). + +\(fn (SYM...) FORM)" nil (quote macro)) + +(autoload (quote locally) "cl-macs" "\ +Not documented + +\(fn &rest BODY)" nil (quote macro)) + +(autoload (quote the) "cl-macs" "\ +Not documented + +\(fn TYPE FORM)" nil (quote macro)) + +(autoload (quote declare) "cl-macs" "\ +Not documented + +\(fn &rest SPECS)" nil (quote macro)) + +(autoload (quote define-setf-method) "cl-macs" "\ +Define a `setf' method. +This method shows how to handle `setf's to places of the form (NAME ARGS...). +The argument forms ARGS are bound according to ARGLIST, as if NAME were +going to be expanded as a macro, then the BODY forms are executed and must +return a list of five elements: a temporary-variables list, a value-forms +list, a store-variables list (of length one), a store-form, and an access- +form. See `defsetf' for a simpler way to define most setf-methods. + +\(fn NAME ARGLIST BODY...)" nil (quote macro)) + +(autoload (quote defsetf) "cl-macs" "\ +Define a `setf' method. +This macro is an easy-to-use substitute for `define-setf-method' that works +well for simple place forms. In the simple `defsetf' form, `setf's of +the form (setf (NAME ARGS...) VAL) are transformed to function or macro +calls of the form (FUNC ARGS... VAL). Example: + + (defsetf aref aset) + +Alternate form: (defsetf NAME ARGLIST (STORE) BODY...). +Here, the above `setf' call is expanded by binding the argument forms ARGS +according to ARGLIST, binding the value form VAL to STORE, then executing +BODY, which must return a Lisp form that does the necessary `setf' operation. +Actually, ARGLIST and STORE may be bound to temporary variables which are +introduced automatically to preserve proper execution order of the arguments. +Example: + + (defsetf nth (n x) (v) (list 'setcar (list 'nthcdr n x) v)) + +\(fn NAME [FUNC | ARGLIST (STORE) BODY...])" nil (quote macro)) + +(autoload (quote get-setf-method) "cl-macs" "\ +Return a list of five values describing the setf-method for PLACE. +PLACE may be any Lisp form which can appear as the PLACE argument to +a macro like `setf' or `incf'. + +\(fn PLACE &optional ENV)" nil nil) + +(autoload (quote setf) "cl-macs" "\ +Set each PLACE to the value of its VAL. +This is a generalized version of `setq'; the PLACEs may be symbolic +references such as (car x) or (aref x i), as well as plain symbols. +For example, (setf (cadar x) y) is equivalent to (setcar (cdar x) y). +The return value is the last VAL in the list. + +\(fn PLACE VAL PLACE VAL ...)" nil (quote macro)) + +(autoload (quote psetf) "cl-macs" "\ +Set PLACEs to the values VALs in parallel. +This is like `setf', except that all VAL forms are evaluated (in order) +before assigning any PLACEs to the corresponding values. + +\(fn PLACE VAL PLACE VAL ...)" nil (quote macro)) + +(autoload (quote cl-do-pop) "cl-macs" "\ +Not documented + +\(fn PLACE)" nil nil) + +(autoload (quote remf) "cl-macs" "\ +Remove TAG from property list PLACE. +PLACE may be a symbol, or any generalized variable allowed by `setf'. +The form returns true if TAG was found and removed, nil otherwise. + +\(fn PLACE TAG)" nil (quote macro)) + +(autoload (quote shiftf) "cl-macs" "\ +Shift left among PLACEs. +Example: (shiftf A B C) sets A to B, B to C, and returns the old A. +Each PLACE may be a symbol, or any generalized variable allowed by `setf'. + +\(fn PLACE... VAL)" nil (quote macro)) + +(autoload (quote rotatef) "cl-macs" "\ +Rotate left among PLACEs. +Example: (rotatef A B C) sets A to B, B to C, and C to A. It returns nil. +Each PLACE may be a symbol, or any generalized variable allowed by `setf'. + +\(fn PLACE...)" nil (quote macro)) + +(autoload (quote letf) "cl-macs" "\ +Temporarily bind to PLACEs. +This is the analogue of `let', but with generalized variables (in the +sense of `setf') for the PLACEs. Each PLACE is set to the corresponding +VALUE, then the BODY forms are executed. On exit, either normally or +because of a `throw' or error, the PLACEs are set back to their original +values. Note that this macro is *not* available in Common Lisp. +As a special case, if `(PLACE)' is used instead of `(PLACE VALUE)', +the PLACE is not modified before executing BODY. + +\(fn ((PLACE VALUE) ...) BODY...)" nil (quote macro)) + +(autoload (quote letf*) "cl-macs" "\ +Temporarily bind to PLACEs. +This is the analogue of `let*', but with generalized variables (in the +sense of `setf') for the PLACEs. Each PLACE is set to the corresponding +VALUE, then the BODY forms are executed. On exit, either normally or +because of a `throw' or error, the PLACEs are set back to their original +values. Note that this macro is *not* available in Common Lisp. +As a special case, if `(PLACE)' is used instead of `(PLACE VALUE)', +the PLACE is not modified before executing BODY. + +\(fn ((PLACE VALUE) ...) BODY...)" nil (quote macro)) + +(autoload (quote callf) "cl-macs" "\ +Set PLACE to (FUNC PLACE ARGS...). +FUNC should be an unquoted function name. PLACE may be a symbol, +or any generalized variable allowed by `setf'. + +\(fn FUNC PLACE ARGS...)" nil (quote macro)) + +(autoload (quote callf2) "cl-macs" "\ +Set PLACE to (FUNC ARG1 PLACE ARGS...). +Like `callf', but PLACE is the second argument of FUNC, not the first. + +\(fn FUNC ARG1 PLACE ARGS...)" nil (quote macro)) + +(autoload (quote define-modify-macro) "cl-macs" "\ +Define a `setf'-like modify macro. +If NAME is called, it combines its PLACE argument with the other arguments +from ARGLIST using FUNC: (define-modify-macro incf (&optional (n 1)) +) + +\(fn NAME ARGLIST FUNC &optional DOC)" nil (quote macro)) + +(autoload (quote defstruct) "cl-macs" "\ +Define a struct type. +This macro defines a new Lisp data type called NAME, which contains data +stored in SLOTs. This defines a `make-NAME' constructor, a `copy-NAME' +copier, a `NAME-p' predicate, and setf-able `NAME-SLOT' accessors. + +\(fn (NAME OPTIONS...) (SLOT SLOT-OPTS...)...)" nil (quote macro)) + +(autoload (quote cl-struct-setf-expander) "cl-macs" "\ +Not documented + +\(fn X NAME ACCESSOR PRED-FORM POS)" nil nil) + +(autoload (quote typep) "cl-macs" "\ +Check that OBJECT is of type TYPE. +TYPE is a Common Lisp-style type specifier. + +\(fn OBJECT TYPE)" nil nil) + +(autoload (quote check-type) "cl-macs" "\ +Verify that FORM is of type TYPE; signal an error if not. +STRING is an optional description of the desired type. + +\(fn FORM TYPE &optional STRING)" nil (quote macro)) + +(autoload (quote assert) "cl-macs" "\ +Verify that FORM returns non-nil; signal an error if not. +Second arg SHOW-ARGS means to include arguments of FORM in message. +Other args STRING and ARGS... are arguments to be passed to `error'. +They are not evaluated unless the assertion fails. If STRING is +omitted, a default message listing FORM itself is used. + +\(fn FORM &optional SHOW-ARGS STRING &rest ARGS)" nil (quote macro)) + +(autoload (quote ignore-errors) "cl-macs" "\ +Execute BODY; if an error occurs, return nil. +Otherwise, return result of last form in BODY. + +\(fn &rest BODY)" nil (quote macro)) + +(autoload (quote define-compiler-macro) "cl-macs" "\ +Define a compiler-only macro. +This is like `defmacro', but macro expansion occurs only if the call to +FUNC is compiled (i.e., not interpreted). Compiler macros should be used +for optimizing the way calls to FUNC are compiled; the form returned by +BODY should do the same thing as a call to the normal function called +FUNC, though possibly more efficiently. Note that, like regular macros, +compiler macros are expanded repeatedly until no further expansions are +possible. Unlike regular macros, BODY can decide to \"punt\" and leave the +original function call alone by declaring an initial `&whole foo' parameter +and then returning foo. + +\(fn FUNC ARGS &rest BODY)" nil (quote macro)) + +(autoload (quote compiler-macroexpand) "cl-macs" "\ +Not documented + +\(fn FORM)" nil nil) + +;;;*** + +;;;### (autoloads (tree-equal nsublis sublis nsubst-if-not nsubst-if +;;;;;; nsubst subst-if-not subst-if subsetp nset-exclusive-or set-exclusive-or +;;;;;; nset-difference set-difference nintersection intersection +;;;;;; nunion union rassoc-if-not rassoc-if rassoc* assoc-if-not +;;;;;; assoc-if assoc* cl-adjoin member-if-not member-if member* +;;;;;; merge stable-sort sort* search mismatch count-if-not count-if +;;;;;; count position-if-not position-if position find-if-not find-if +;;;;;; find nsubstitute-if-not nsubstitute-if nsubstitute substitute-if-not +;;;;;; substitute-if substitute delete-duplicates remove-duplicates +;;;;;; delete-if-not delete-if delete* remove-if-not remove-if remove* +;;;;;; replace fill reduce) "cl-seq" "cl-seq.el" "8805f76626399794931f5db36ddf855f") +;;; Generated autoloads from cl-seq.el + +(autoload (quote reduce) "cl-seq" "\ +Reduce two-argument FUNCTION across SEQ. + +Keywords supported: :start :end :from-end :initial-value :key + +\(fn FUNCTION SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote fill) "cl-seq" "\ +Fill the elements of SEQ with ITEM. + +Keywords supported: :start :end + +\(fn SEQ ITEM [KEYWORD VALUE]...)" nil nil) + +(autoload (quote replace) "cl-seq" "\ +Replace the elements of SEQ1 with the elements of SEQ2. +SEQ1 is destructively modified, then returned. + +Keywords supported: :start1 :end1 :start2 :end2 + +\(fn SEQ1 SEQ2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote remove*) "cl-seq" "\ +Remove all occurrences of ITEM in SEQ. +This is a non-destructive function; it makes a copy of SEQ if necessary +to avoid corrupting the original SEQ. + +Keywords supported: :test :test-not :key :count :start :end :from-end + +\(fn ITEM SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote remove-if) "cl-seq" "\ +Remove all items satisfying PREDICATE in SEQ. +This is a non-destructive function; it makes a copy of SEQ if necessary +to avoid corrupting the original SEQ. + +Keywords supported: :key :count :start :end :from-end + +\(fn PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote remove-if-not) "cl-seq" "\ +Remove all items not satisfying PREDICATE in SEQ. +This is a non-destructive function; it makes a copy of SEQ if necessary +to avoid corrupting the original SEQ. + +Keywords supported: :key :count :start :end :from-end + +\(fn PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote delete*) "cl-seq" "\ +Remove all occurrences of ITEM in SEQ. +This is a destructive function; it reuses the storage of SEQ whenever possible. + +Keywords supported: :test :test-not :key :count :start :end :from-end + +\(fn ITEM SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote delete-if) "cl-seq" "\ +Remove all items satisfying PREDICATE in SEQ. +This is a destructive function; it reuses the storage of SEQ whenever possible. + +Keywords supported: :key :count :start :end :from-end + +\(fn PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote delete-if-not) "cl-seq" "\ +Remove all items not satisfying PREDICATE in SEQ. +This is a destructive function; it reuses the storage of SEQ whenever possible. + +Keywords supported: :key :count :start :end :from-end + +\(fn PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote remove-duplicates) "cl-seq" "\ +Return a copy of SEQ with all duplicate elements removed. + +Keywords supported: :test :test-not :key :start :end :from-end + +\(fn SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote delete-duplicates) "cl-seq" "\ +Remove all duplicate elements from SEQ (destructively). + +Keywords supported: :test :test-not :key :start :end :from-end + +\(fn SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote substitute) "cl-seq" "\ +Substitute NEW for OLD in SEQ. +This is a non-destructive function; it makes a copy of SEQ if necessary +to avoid corrupting the original SEQ. + +Keywords supported: :test :test-not :key :count :start :end :from-end + +\(fn NEW OLD SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote substitute-if) "cl-seq" "\ +Substitute NEW for all items satisfying PREDICATE in SEQ. +This is a non-destructive function; it makes a copy of SEQ if necessary +to avoid corrupting the original SEQ. + +Keywords supported: :key :count :start :end :from-end + +\(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote substitute-if-not) "cl-seq" "\ +Substitute NEW for all items not satisfying PREDICATE in SEQ. +This is a non-destructive function; it makes a copy of SEQ if necessary +to avoid corrupting the original SEQ. + +Keywords supported: :key :count :start :end :from-end + +\(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nsubstitute) "cl-seq" "\ +Substitute NEW for OLD in SEQ. +This is a destructive function; it reuses the storage of SEQ whenever possible. + +Keywords supported: :test :test-not :key :count :start :end :from-end + +\(fn NEW OLD SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nsubstitute-if) "cl-seq" "\ +Substitute NEW for all items satisfying PREDICATE in SEQ. +This is a destructive function; it reuses the storage of SEQ whenever possible. + +Keywords supported: :key :count :start :end :from-end + +\(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nsubstitute-if-not) "cl-seq" "\ +Substitute NEW for all items not satisfying PREDICATE in SEQ. +This is a destructive function; it reuses the storage of SEQ whenever possible. + +Keywords supported: :key :count :start :end :from-end + +\(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote find) "cl-seq" "\ +Find the first occurrence of ITEM in SEQ. +Return the matching ITEM, or nil if not found. + +Keywords supported: :test :test-not :key :start :end :from-end + +\(fn ITEM SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote find-if) "cl-seq" "\ +Find the first item satisfying PREDICATE in SEQ. +Return the matching item, or nil if not found. + +Keywords supported: :key :start :end :from-end + +\(fn PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote find-if-not) "cl-seq" "\ +Find the first item not satisfying PREDICATE in SEQ. +Return the matching item, or nil if not found. + +Keywords supported: :key :start :end :from-end + +\(fn PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote position) "cl-seq" "\ +Find the first occurrence of ITEM in SEQ. +Return the index of the matching item, or nil if not found. + +Keywords supported: :test :test-not :key :start :end :from-end + +\(fn ITEM SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote position-if) "cl-seq" "\ +Find the first item satisfying PREDICATE in SEQ. +Return the index of the matching item, or nil if not found. + +Keywords supported: :key :start :end :from-end + +\(fn PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote position-if-not) "cl-seq" "\ +Find the first item not satisfying PREDICATE in SEQ. +Return the index of the matching item, or nil if not found. + +Keywords supported: :key :start :end :from-end + +\(fn PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote count) "cl-seq" "\ +Count the number of occurrences of ITEM in SEQ. + +Keywords supported: :test :test-not :key :start :end + +\(fn ITEM SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote count-if) "cl-seq" "\ +Count the number of items satisfying PREDICATE in SEQ. + +Keywords supported: :key :start :end + +\(fn PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote count-if-not) "cl-seq" "\ +Count the number of items not satisfying PREDICATE in SEQ. + +Keywords supported: :key :start :end + +\(fn PREDICATE SEQ [KEYWORD VALUE]...)" nil nil) + +(autoload (quote mismatch) "cl-seq" "\ +Compare SEQ1 with SEQ2, return index of first mismatching element. +Return nil if the sequences match. If one sequence is a prefix of the +other, the return value indicates the end of the shorter sequence. + +Keywords supported: :test :test-not :key :start1 :end1 :start2 :end2 :from-end + +\(fn SEQ1 SEQ2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote search) "cl-seq" "\ +Search for SEQ1 as a subsequence of SEQ2. +Return the index of the leftmost element of the first match found; +return nil if there are no matches. + +Keywords supported: :test :test-not :key :start1 :end1 :start2 :end2 :from-end + +\(fn SEQ1 SEQ2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote sort*) "cl-seq" "\ +Sort the argument SEQ according to PREDICATE. +This is a destructive function; it reuses the storage of SEQ if possible. + +Keywords supported: :key + +\(fn SEQ PREDICATE [KEYWORD VALUE]...)" nil nil) + +(autoload (quote stable-sort) "cl-seq" "\ +Sort the argument SEQ stably according to PREDICATE. +This is a destructive function; it reuses the storage of SEQ if possible. + +Keywords supported: :key + +\(fn SEQ PREDICATE [KEYWORD VALUE]...)" nil nil) + +(autoload (quote merge) "cl-seq" "\ +Destructively merge the two sequences to produce a new sequence. +TYPE is the sequence type to return, SEQ1 and SEQ2 are the two argument +sequences, and PREDICATE is a `less-than' predicate on the elements. + +Keywords supported: :key + +\(fn TYPE SEQ1 SEQ2 PREDICATE [KEYWORD VALUE]...)" nil nil) + +(autoload (quote member*) "cl-seq" "\ +Find the first occurrence of ITEM in LIST. +Return the sublist of LIST whose car is ITEM. + +Keywords supported: :test :test-not :key + +\(fn ITEM LIST [KEYWORD VALUE]...)" nil nil) + +(autoload (quote member-if) "cl-seq" "\ +Find the first item satisfying PREDICATE in LIST. +Return the sublist of LIST whose car matches. + +Keywords supported: :key + +\(fn PREDICATE LIST [KEYWORD VALUE]...)" nil nil) + +(autoload (quote member-if-not) "cl-seq" "\ +Find the first item not satisfying PREDICATE in LIST. +Return the sublist of LIST whose car matches. + +Keywords supported: :key + +\(fn PREDICATE LIST [KEYWORD VALUE]...)" nil nil) + +(autoload (quote cl-adjoin) "cl-seq" "\ +Not documented + +\(fn CL-ITEM CL-LIST &rest CL-KEYS)" nil nil) + +(autoload (quote assoc*) "cl-seq" "\ +Find the first item whose car matches ITEM in LIST. + +Keywords supported: :test :test-not :key + +\(fn ITEM LIST [KEYWORD VALUE]...)" nil nil) + +(autoload (quote assoc-if) "cl-seq" "\ +Find the first item whose car satisfies PREDICATE in LIST. + +Keywords supported: :key + +\(fn PREDICATE LIST [KEYWORD VALUE]...)" nil nil) + +(autoload (quote assoc-if-not) "cl-seq" "\ +Find the first item whose car does not satisfy PREDICATE in LIST. + +Keywords supported: :key + +\(fn PREDICATE LIST [KEYWORD VALUE]...)" nil nil) + +(autoload (quote rassoc*) "cl-seq" "\ +Find the first item whose cdr matches ITEM in LIST. + +Keywords supported: :test :test-not :key + +\(fn ITEM LIST [KEYWORD VALUE]...)" nil nil) + +(autoload (quote rassoc-if) "cl-seq" "\ +Find the first item whose cdr satisfies PREDICATE in LIST. + +Keywords supported: :key + +\(fn PREDICATE LIST [KEYWORD VALUE]...)" nil nil) + +(autoload (quote rassoc-if-not) "cl-seq" "\ +Find the first item whose cdr does not satisfy PREDICATE in LIST. + +Keywords supported: :key + +\(fn PREDICATE LIST [KEYWORD VALUE]...)" nil nil) + +(autoload (quote union) "cl-seq" "\ +Combine LIST1 and LIST2 using a set-union operation. +The result list contains all items that appear in either LIST1 or LIST2. +This is a non-destructive function; it makes a copy of the data if necessary +to avoid corrupting the original LIST1 and LIST2. + +Keywords supported: :test :test-not :key + +\(fn LIST1 LIST2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nunion) "cl-seq" "\ +Combine LIST1 and LIST2 using a set-union operation. +The result list contains all items that appear in either LIST1 or LIST2. +This is a destructive function; it reuses the storage of LIST1 and LIST2 +whenever possible. + +Keywords supported: :test :test-not :key + +\(fn LIST1 LIST2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote intersection) "cl-seq" "\ +Combine LIST1 and LIST2 using a set-intersection operation. +The result list contains all items that appear in both LIST1 and LIST2. +This is a non-destructive function; it makes a copy of the data if necessary +to avoid corrupting the original LIST1 and LIST2. + +Keywords supported: :test :test-not :key + +\(fn LIST1 LIST2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nintersection) "cl-seq" "\ +Combine LIST1 and LIST2 using a set-intersection operation. +The result list contains all items that appear in both LIST1 and LIST2. +This is a destructive function; it reuses the storage of LIST1 and LIST2 +whenever possible. + +Keywords supported: :test :test-not :key + +\(fn LIST1 LIST2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote set-difference) "cl-seq" "\ +Combine LIST1 and LIST2 using a set-difference operation. +The result list contains all items that appear in LIST1 but not LIST2. +This is a non-destructive function; it makes a copy of the data if necessary +to avoid corrupting the original LIST1 and LIST2. + +Keywords supported: :test :test-not :key + +\(fn LIST1 LIST2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nset-difference) "cl-seq" "\ +Combine LIST1 and LIST2 using a set-difference operation. +The result list contains all items that appear in LIST1 but not LIST2. +This is a destructive function; it reuses the storage of LIST1 and LIST2 +whenever possible. + +Keywords supported: :test :test-not :key + +\(fn LIST1 LIST2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote set-exclusive-or) "cl-seq" "\ +Combine LIST1 and LIST2 using a set-exclusive-or operation. +The result list contains all items that appear in exactly one of LIST1, LIST2. +This is a non-destructive function; it makes a copy of the data if necessary +to avoid corrupting the original LIST1 and LIST2. + +Keywords supported: :test :test-not :key + +\(fn LIST1 LIST2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nset-exclusive-or) "cl-seq" "\ +Combine LIST1 and LIST2 using a set-exclusive-or operation. +The result list contains all items that appear in exactly one of LIST1, LIST2. +This is a destructive function; it reuses the storage of LIST1 and LIST2 +whenever possible. + +Keywords supported: :test :test-not :key + +\(fn LIST1 LIST2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote subsetp) "cl-seq" "\ +Return true if LIST1 is a subset of LIST2. +I.e., if every element of LIST1 also appears in LIST2. + +Keywords supported: :test :test-not :key + +\(fn LIST1 LIST2 [KEYWORD VALUE]...)" nil nil) + +(autoload (quote subst-if) "cl-seq" "\ +Substitute NEW for elements matching PREDICATE in TREE (non-destructively). +Return a copy of TREE with all matching elements replaced by NEW. + +Keywords supported: :key + +\(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" nil nil) + +(autoload (quote subst-if-not) "cl-seq" "\ +Substitute NEW for elts not matching PREDICATE in TREE (non-destructively). +Return a copy of TREE with all non-matching elements replaced by NEW. + +Keywords supported: :key + +\(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nsubst) "cl-seq" "\ +Substitute NEW for OLD everywhere in TREE (destructively). +Any element of TREE which is `eql' to OLD is changed to NEW (via a call +to `setcar'). + +Keywords supported: :test :test-not :key + +\(fn NEW OLD TREE [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nsubst-if) "cl-seq" "\ +Substitute NEW for elements matching PREDICATE in TREE (destructively). +Any element of TREE which matches is changed to NEW (via a call to `setcar'). + +Keywords supported: :key + +\(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nsubst-if-not) "cl-seq" "\ +Substitute NEW for elements not matching PREDICATE in TREE (destructively). +Any element of TREE which matches is changed to NEW (via a call to `setcar'). + +Keywords supported: :key + +\(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" nil nil) + +(autoload (quote sublis) "cl-seq" "\ +Perform substitutions indicated by ALIST in TREE (non-destructively). +Return a copy of TREE with all matching elements replaced. + +Keywords supported: :test :test-not :key + +\(fn ALIST TREE [KEYWORD VALUE]...)" nil nil) + +(autoload (quote nsublis) "cl-seq" "\ +Perform substitutions indicated by ALIST in TREE (destructively). +Any matching element of TREE is changed via a call to `setcar'. + +Keywords supported: :test :test-not :key + +\(fn ALIST TREE [KEYWORD VALUE]...)" nil nil) + +(autoload (quote tree-equal) "cl-seq" "\ +Return t if trees TREE1 and TREE2 have `eql' leaves. +Atoms are compared by `eql'; cons cells are compared recursively. + +Keywords supported: :test :test-not :key + +\(fn TREE1 TREE2 [KEYWORD VALUE]...)" nil nil) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: + +;; arch-tag: 08cc5aab-e992-47f6-992e-12a7428c1a0e +;;; cl-loaddefs.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/cl-macs.el --- a/lisp/emacs-lisp/cl-macs.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/cl-macs.el Sun Jul 15 02:05:20 2007 +0000 @@ -58,8 +58,8 @@ (defvar cl-optimize-speed) -;;; This kludge allows macros which use cl-transform-function-property -;;; to be called at compile-time. +;; This kludge allows macros which use cl-transform-function-property +;; to be called at compile-time. (require (progn @@ -75,6 +75,7 @@ (defvar cl-old-bc-file-form nil) +;;;###autoload (defun cl-compile-time-init () (run-hooks 'cl-hack-bytecomp-hook)) @@ -165,6 +166,7 @@ ;;; Symbols. (defvar *gensym-counter*) +;;;###autoload (defun gensym (&optional prefix) "Generate a new uninterned symbol. The name is made by appending a number to PREFIX, default \"G\"." @@ -174,6 +176,7 @@ (setq *gensym-counter* (1+ *gensym-counter*)))))) (make-symbol (format "%s%d" pfix num)))) +;;;###autoload (defun gentemp (&optional prefix) "Generate a new interned symbol with a unique name. The name is made by appending a number to PREFIX, default \"G\"." @@ -186,6 +189,7 @@ ;;; Program structure. +;;;###autoload (defmacro defun* (name args &rest body) "Define NAME as a function. Like normal `defun', except ARGLIST allows full Common Lisp conventions, @@ -196,6 +200,7 @@ (form (list* 'defun name (cdr res)))) (if (car res) (list 'progn (car res) form) form))) +;;;###autoload (defmacro defmacro* (name args &rest body) "Define NAME as a macro. Like normal `defmacro', except ARGLIST allows full Common Lisp conventions, @@ -206,6 +211,7 @@ (form (list* 'defmacro name (cdr res)))) (if (car res) (list 'progn (car res) form) form))) +;;;###autoload (defmacro function* (func) "Introduce a function. Like normal `function', except that if argument is a lambda form, @@ -422,6 +428,7 @@ (setq res (nconc res (cl-arglist-args arg)))))) (nconc res (and args (list args)))))) +;;;###autoload (defmacro destructuring-bind (args expr &rest body) (let* ((bind-lets nil) (bind-forms nil) (bind-inits nil) (bind-defs nil) (bind-block 'cl-none)) @@ -435,6 +442,7 @@ (defvar cl-not-toplevel nil) +;;;###autoload (defmacro eval-when (when &rest body) "Control when BODY is evaluated. If `compile' is in WHEN, BODY is evaluated when compiled at top-level. @@ -466,6 +474,7 @@ form))) (t (eval form) form))) +;;;###autoload (defmacro load-time-value (form &optional read-only) "Like `progn', but evaluates the body at load time. The result of the body appears to the compiler as a quoted constant." @@ -488,6 +497,7 @@ ;;; Conditional control structures. +;;;###autoload (defmacro case (expr &rest clauses) "Eval EXPR and choose among clauses on that value. Each clause looks like (KEYLIST BODY...). EXPR is evaluated and compared @@ -522,12 +532,14 @@ (if (eq temp expr) body (list 'let (list (list temp expr)) body)))) +;;;###autoload (defmacro ecase (expr &rest clauses) "Like `case', but error if no case fits. `otherwise'-clauses are not allowed. \n(fn EXPR (KEYLIST BODY...)...)" (list* 'case expr (append clauses '((ecase-error-flag))))) +;;;###autoload (defmacro typecase (expr &rest clauses) "Evals EXPR, chooses among clauses on that value. Each clause looks like (TYPE BODY...). EXPR is evaluated and, if it @@ -554,6 +566,7 @@ (if (eq temp expr) body (list 'let (list (list temp expr)) body)))) +;;;###autoload (defmacro etypecase (expr &rest clauses) "Like `typecase', but error if no case fits. `otherwise'-clauses are not allowed. @@ -563,6 +576,7 @@ ;;; Blocks and exits. +;;;###autoload (defmacro block (name &rest body) "Define a lexically-scoped block named NAME. NAME may be any symbol. Code inside the BODY forms can call `return-from' @@ -598,11 +612,13 @@ (if cl-found (setcdr cl-found t))) (byte-compile-normal-call (cons 'throw (cdr cl-form)))) +;;;###autoload (defmacro return (&optional result) "Return from the block named nil. This is equivalent to `(return-from nil RESULT)'." (list 'return-from nil result)) +;;;###autoload (defmacro return-from (name &optional result) "Return from the block named NAME. This jump out to the innermost enclosing `(block NAME ...)' form, @@ -622,6 +638,7 @@ (defvar loop-result) (defvar loop-result-explicit) (defvar loop-result-var) (defvar loop-steps) (defvar loop-symbol-macs) +;;;###autoload (defmacro loop (&rest args) "The Common Lisp `loop' macro. Valid clauses are: @@ -1181,12 +1198,14 @@ ;;; Other iteration control structures. +;;;###autoload (defmacro do (steps endtest &rest body) "The Common Lisp `do' loop. \(fn ((VAR INIT [STEP])...) (END-TEST [RESULT...]) BODY...)" (cl-expand-do-loop steps endtest body nil)) +;;;###autoload (defmacro do* (steps endtest &rest body) "The Common Lisp `do*' loop. @@ -1214,6 +1233,7 @@ (apply 'append sets))))))) (or (cdr endtest) '(nil))))) +;;;###autoload (defmacro dolist (spec &rest body) "Loop over a list. Evaluate BODY with VAR bound to each `car' from LIST, in turn. @@ -1230,6 +1250,7 @@ (cons (list 'setq (car spec) nil) (cdr (cdr spec))) '(nil)))))) +;;;###autoload (defmacro dotimes (spec &rest body) "Loop a certain number of times. Evaluate BODY with VAR bound to successive integers from 0, inclusive, @@ -1244,6 +1265,7 @@ (append body (list (list 'incf (car spec))))) (or (cdr (cdr spec)) '(nil)))))) +;;;###autoload (defmacro do-symbols (spec &rest body) "Loop over all symbols. Evaluate BODY with VAR bound to each interned symbol, or to each symbol @@ -1258,12 +1280,14 @@ (and (cadr spec) (list (cadr spec)))) (caddr spec)))) +;;;###autoload (defmacro do-all-symbols (spec &rest body) (list* 'do-symbols (list (car spec) nil (cadr spec)) body)) ;;; Assignments. +;;;###autoload (defmacro psetq (&rest args) "Set SYMs to the values VALs in parallel. This is like `setq', except that all VAL forms are evaluated (in order) @@ -1275,6 +1299,7 @@ ;;; Binding control structures. +;;;###autoload (defmacro progv (symbols values &rest body) "Bind SYMBOLS to VALUES dynamically in BODY. The forms SYMBOLS and VALUES are evaluated, and must evaluate to lists. @@ -1288,6 +1313,7 @@ '(cl-progv-after)))) ;;; This should really have some way to shadow 'byte-compile properties, etc. +;;;###autoload (defmacro flet (bindings &rest body) "Make temporary function definitions. This is an analogue of `let' that operates on the function cell of FUNC @@ -1315,6 +1341,7 @@ bindings) body)) +;;;###autoload (defmacro labels (bindings &rest body) "Make temporary function bindings. This is like `flet', except the bindings are lexical instead of dynamic. @@ -1339,6 +1366,7 @@ ;; The following ought to have a better definition for use with newer ;; byte compilers. +;;;###autoload (defmacro macrolet (bindings &rest body) "Make temporary macro definitions. This is like `flet', but for macros instead of functions. @@ -1355,6 +1383,7 @@ (cons (list* name 'lambda (cdr res)) cl-macro-environment)))))) +;;;###autoload (defmacro symbol-macrolet (bindings &rest body) "Make symbol macro definitions. Within the body FORMs, references to the variable NAME will be replaced @@ -1371,6 +1400,7 @@ cl-macro-environment))))) (defvar cl-closure-vars nil) +;;;###autoload (defmacro lexical-let (bindings &rest body) "Like `let', but lexically scoped. The main visible difference is that lambdas inside BODY will create @@ -1414,6 +1444,7 @@ vars)) ebody)))) +;;;###autoload (defmacro lexical-let* (bindings &rest body) "Like `let*', but lexically scoped. The main visible difference is that lambdas inside BODY will create @@ -1434,6 +1465,7 @@ ;;; Multiple values. +;;;###autoload (defmacro multiple-value-bind (vars form &rest body) "Collect multiple return values. FORM must return a list; the BODY is then executed with the first N elements @@ -1451,6 +1483,7 @@ vars)) body))) +;;;###autoload (defmacro multiple-value-setq (vars form) "Collect multiple return values. FORM must return a list; the first N elements of this list are stored in @@ -1477,7 +1510,9 @@ ;;; Declarations. +;;;###autoload (defmacro locally (&rest body) (cons 'progn body)) +;;;###autoload (defmacro the (type form) form) (defvar cl-proclaim-history t) ; for future compilers @@ -1532,6 +1567,7 @@ (while p (cl-do-proclaim (pop p) t)) (setq cl-proclaims-deferred nil)) +;;;###autoload (defmacro declare (&rest specs) (if (cl-compiling-file) (while specs @@ -1543,6 +1579,7 @@ ;;; Generalized variables. +;;;###autoload (defmacro define-setf-method (func args &rest body) "Define a `setf' method. This method shows how to handle `setf's to places of the form (NAME ARGS...). @@ -1561,8 +1598,9 @@ func 'setf-method (cons args body))))) (defalias 'define-setf-expander 'define-setf-method) +;;;###autoload (defmacro defsetf (func arg1 &rest args) - "(defsetf NAME FUNC): define a `setf' method. + "Define a `setf' method. This macro is an easy-to-use substitute for `define-setf-method' that works well for simple place forms. In the simple `defsetf' form, `setf's of the form (setf (NAME ARGS...) VAL) are transformed to function or macro @@ -1836,6 +1874,7 @@ (list 'substring (nth 4 method) from-temp to-temp)))) ;;; Getting and optimizing setf-methods. +;;;###autoload (defun get-setf-method (place &optional env) "Return a list of five values describing the setf-method for PLACE. PLACE may be any Lisp form which can appear as the PLACE argument to @@ -1903,6 +1942,7 @@ (not (eq (car-safe (symbol-function (car form))) 'macro)))) ;;; The standard modify macros. +;;;###autoload (defmacro setf (&rest args) "Set each PLACE to the value of its VAL. This is a generalized version of `setq'; the PLACEs may be symbolic @@ -1921,6 +1961,7 @@ (store (cl-setf-do-store (nth 1 method) (nth 1 args)))) (if (car method) (list 'let* (car method) store) store))))) +;;;###autoload (defmacro psetf (&rest args) "Set PLACEs to the values VALs in parallel. This is like `setf', except that all VAL forms are evaluated (in order) @@ -1944,6 +1985,7 @@ (setq expr (list 'setf (cadr args) (list 'prog1 (car args) expr)))) (list 'progn expr nil))))) +;;;###autoload (defun cl-do-pop (place) (if (cl-simple-expr-p place) (list 'prog1 (list 'car place) (list 'setf place (list 'cdr place))) @@ -1956,6 +1998,7 @@ (list 'car temp) (cl-setf-do-store (nth 1 method) (list 'cdr temp))))))) +;;;###autoload (defmacro remf (place tag) "Remove TAG from property list PLACE. PLACE may be a symbol, or any generalized variable allowed by `setf'. @@ -1976,6 +2019,7 @@ t) (list 'cl-do-remf tval ttag))))) +;;;###autoload (defmacro shiftf (place &rest args) "Shift left among PLACEs. Example: (shiftf A B C) sets A to B, B to C, and returns the old A. @@ -1991,6 +2035,7 @@ (prog1 ,(nth 2 method) ,(cl-setf-do-store (nth 1 method) `(shiftf ,@args)))))))) +;;;###autoload (defmacro rotatef (&rest args) "Rotate left among PLACEs. Example: (rotatef A B C) sets A to B, B to C, and C to A. It returns nil. @@ -2016,6 +2061,7 @@ (list 'let* (append (car method) (list (list temp (nth 2 method)))) (cl-setf-do-store (nth 1 method) form) nil))))) +;;;###autoload (defmacro letf (bindings &rest body) "Temporarily bind to PLACEs. This is the analogue of `let', but with generalized variables (in the @@ -2072,6 +2118,7 @@ rev (cdr rev)))) (list* 'let* lets body)))) +;;;###autoload (defmacro letf* (bindings &rest body) "Temporarily bind to PLACEs. This is the analogue of `let*', but with generalized variables (in the @@ -2090,6 +2137,7 @@ (setq body (list (list* 'letf (list (pop bindings)) body)))) (car body))) +;;;###autoload (defmacro callf (func place &rest args) "Set PLACE to (FUNC PLACE ARGS...). FUNC should be an unquoted function name. PLACE may be a symbol, @@ -2104,6 +2152,7 @@ (list* 'funcall (list 'function func) rargs)))))) +;;;###autoload (defmacro callf2 (func arg1 place &rest args) "Set PLACE to (FUNC ARG1 PLACE ARGS...). Like `callf', but PLACE is the second argument of FUNC, not the first. @@ -2120,6 +2169,7 @@ (list* 'funcall (list 'function func) rargs))))))) +;;;###autoload (defmacro define-modify-macro (name arglist func &optional doc) "Define a `setf'-like modify macro. If NAME is called, it combines its PLACE argument with the other arguments @@ -2134,6 +2184,7 @@ ;;; Structures. +;;;###autoload (defmacro defstruct (struct &rest descs) "Define a struct type. This macro defines a new Lisp data type called NAME, which contains data @@ -2358,6 +2409,7 @@ forms) (cons 'progn (nreverse (cons (list 'quote name) forms))))) +;;;###autoload (defun cl-struct-setf-expander (x name accessor pred-form pos) (let* ((temp (make-symbol "--cl-x--")) (store (make-symbol "--cl-store--"))) (list (list temp) (list x) (list store) @@ -2426,11 +2478,13 @@ ((eq (car type) 'satisfies) (list (cadr type) val)) (t (error "Bad type spec: %s" type))))) +;;;###autoload (defun typep (object type) ; See compiler macro below. "Check that OBJECT is of type TYPE. TYPE is a Common Lisp-style type specifier." (eval (cl-make-type-test 'object type))) +;;;###autoload (defmacro check-type (form type &optional string) "Verify that FORM is of type TYPE; signal an error if not. STRING is an optional description of the desired type." @@ -2445,6 +2499,7 @@ (if (eq temp form) (list 'progn body nil) (list 'let (list (list temp form)) body nil))))) +;;;###autoload (defmacro assert (form &optional show-args string &rest args) "Verify that FORM returns non-nil; signal an error if not. Second arg SHOW-ARGS means to include arguments of FORM in message. @@ -2466,6 +2521,7 @@ (list* 'list (list 'quote form) sargs)))) nil)))) +;;;###autoload (defmacro ignore-errors (&rest body) "Execute BODY; if an error occurs, return nil. Otherwise, return result of last form in BODY." @@ -2474,6 +2530,7 @@ ;;; Compiler macros. +;;;###autoload (defmacro define-compiler-macro (func args &rest body) "Define a compiler-only macro. This is like `defmacro', but macro expansion occurs only if the call to @@ -2497,6 +2554,7 @@ (list 'put (list 'quote func) '(quote byte-compile) '(quote cl-byte-compile-compiler-macro))))) +;;;###autoload (defun compiler-macroexpand (form) (while (let ((func (car-safe form)) (handler nil)) @@ -2552,9 +2610,9 @@ (if lets (list 'let lets body) body)))) -;;; Compile-time optimizations for some functions defined in this package. -;;; Note that cl.el arranges to force cl-macs to be loaded at compile-time, -;;; mainly to make sure these macros will be present. +;; Compile-time optimizations for some functions defined in this package. +;; Note that cl.el arranges to force cl-macs to be loaded at compile-time, +;; mainly to make sure these macros will be present. (put 'eql 'byte-compile nil) (define-compiler-macro eql (&whole form a b) @@ -2665,9 +2723,10 @@ (run-hooks 'cl-macs-load-hook) -;;; Local variables: -;;; byte-compile-warnings: (redefine callargs free-vars unresolved obsolete noruntime) -;;; End: +;; Local variables: +;; byte-compile-warnings: (redefine callargs free-vars unresolved obsolete noruntime) +;; generated-autoload-file: "cl-loaddefs.el" +;; End: ;; arch-tag: afd947a6-b553-4df1-bba5-000be6388f46 ;;; cl-macs.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/cl-seq.el --- a/lisp/emacs-lisp/cl-seq.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/cl-seq.el Sun Jul 15 02:05:20 2007 +0000 @@ -125,6 +125,7 @@ (defvar cl-key) +;;;###autoload (defun reduce (cl-func cl-seq &rest cl-keys) "Reduce two-argument FUNCTION across SEQ. \nKeywords supported: :start :end :from-end :initial-value :key @@ -145,6 +146,7 @@ (cl-check-key (pop cl-seq)))))) cl-accum))) +;;;###autoload (defun fill (seq item &rest cl-keys) "Fill the elements of SEQ with ITEM. \nKeywords supported: :start :end @@ -164,6 +166,7 @@ (setq cl-start (1+ cl-start))))) seq)) +;;;###autoload (defun replace (cl-seq1 cl-seq2 &rest cl-keys) "Replace the elements of SEQ1 with the elements of SEQ2. SEQ1 is destructively modified, then returned. @@ -206,6 +209,7 @@ (setq cl-start2 (1+ cl-start2) cl-start1 (1+ cl-start1)))))) cl-seq1)) +;;;###autoload (defun remove* (cl-item cl-seq &rest cl-keys) "Remove all occurrences of ITEM in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary @@ -251,6 +255,7 @@ cl-seq)) cl-seq))))) +;;;###autoload (defun remove-if (cl-pred cl-list &rest cl-keys) "Remove all items satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary @@ -259,6 +264,7 @@ \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'remove* nil cl-list :if cl-pred cl-keys)) +;;;###autoload (defun remove-if-not (cl-pred cl-list &rest cl-keys) "Remove all items not satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary @@ -267,6 +273,7 @@ \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'remove* nil cl-list :if-not cl-pred cl-keys)) +;;;###autoload (defun delete* (cl-item cl-seq &rest cl-keys) "Remove all occurrences of ITEM in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. @@ -310,6 +317,7 @@ cl-seq) (apply 'remove* cl-item cl-seq cl-keys))))) +;;;###autoload (defun delete-if (cl-pred cl-list &rest cl-keys) "Remove all items satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. @@ -317,6 +325,7 @@ \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'delete* nil cl-list :if cl-pred cl-keys)) +;;;###autoload (defun delete-if-not (cl-pred cl-list &rest cl-keys) "Remove all items not satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. @@ -324,12 +333,14 @@ \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'delete* nil cl-list :if-not cl-pred cl-keys)) +;;;###autoload (defun remove-duplicates (cl-seq &rest cl-keys) "Return a copy of SEQ with all duplicate elements removed. \nKeywords supported: :test :test-not :key :start :end :from-end \n(fn SEQ [KEYWORD VALUE]...)" (cl-delete-duplicates cl-seq cl-keys t)) +;;;###autoload (defun delete-duplicates (cl-seq &rest cl-keys) "Remove all duplicate elements from SEQ (destructively). \nKeywords supported: :test :test-not :key :start :end :from-end @@ -376,6 +387,7 @@ (let ((cl-res (cl-delete-duplicates (append cl-seq nil) cl-keys nil))) (if (stringp cl-seq) (concat cl-res) (vconcat cl-res))))) +;;;###autoload (defun substitute (cl-new cl-old cl-seq &rest cl-keys) "Substitute NEW for OLD in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary @@ -397,6 +409,7 @@ (apply 'nsubstitute cl-new cl-old cl-seq :count cl-count :start cl-i cl-keys)))))) +;;;###autoload (defun substitute-if (cl-new cl-pred cl-list &rest cl-keys) "Substitute NEW for all items satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary @@ -405,6 +418,7 @@ \n(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'substitute cl-new nil cl-list :if cl-pred cl-keys)) +;;;###autoload (defun substitute-if-not (cl-new cl-pred cl-list &rest cl-keys) "Substitute NEW for all items not satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary @@ -413,6 +427,7 @@ \n(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'substitute cl-new nil cl-list :if-not cl-pred cl-keys)) +;;;###autoload (defun nsubstitute (cl-new cl-old cl-seq &rest cl-keys) "Substitute NEW for OLD in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. @@ -446,6 +461,7 @@ (setq cl-start (1+ cl-start)))))) cl-seq)) +;;;###autoload (defun nsubstitute-if (cl-new cl-pred cl-list &rest cl-keys) "Substitute NEW for all items satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. @@ -453,6 +469,7 @@ \n(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'nsubstitute cl-new nil cl-list :if cl-pred cl-keys)) +;;;###autoload (defun nsubstitute-if-not (cl-new cl-pred cl-list &rest cl-keys) "Substitute NEW for all items not satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. @@ -460,6 +477,7 @@ \n(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'nsubstitute cl-new nil cl-list :if-not cl-pred cl-keys)) +;;;###autoload (defun find (cl-item cl-seq &rest cl-keys) "Find the first occurrence of ITEM in SEQ. Return the matching ITEM, or nil if not found. @@ -468,6 +486,7 @@ (let ((cl-pos (apply 'position cl-item cl-seq cl-keys))) (and cl-pos (elt cl-seq cl-pos)))) +;;;###autoload (defun find-if (cl-pred cl-list &rest cl-keys) "Find the first item satisfying PREDICATE in SEQ. Return the matching item, or nil if not found. @@ -475,6 +494,7 @@ \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'find nil cl-list :if cl-pred cl-keys)) +;;;###autoload (defun find-if-not (cl-pred cl-list &rest cl-keys) "Find the first item not satisfying PREDICATE in SEQ. Return the matching item, or nil if not found. @@ -482,6 +502,7 @@ \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'find nil cl-list :if-not cl-pred cl-keys)) +;;;###autoload (defun position (cl-item cl-seq &rest cl-keys) "Find the first occurrence of ITEM in SEQ. Return the index of the matching item, or nil if not found. @@ -512,6 +533,7 @@ (setq cl-start (1+ cl-start))) (and (< cl-start cl-end) cl-start)))) +;;;###autoload (defun position-if (cl-pred cl-list &rest cl-keys) "Find the first item satisfying PREDICATE in SEQ. Return the index of the matching item, or nil if not found. @@ -519,6 +541,7 @@ \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'position nil cl-list :if cl-pred cl-keys)) +;;;###autoload (defun position-if-not (cl-pred cl-list &rest cl-keys) "Find the first item not satisfying PREDICATE in SEQ. Return the index of the matching item, or nil if not found. @@ -526,6 +549,7 @@ \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'position nil cl-list :if-not cl-pred cl-keys)) +;;;###autoload (defun count (cl-item cl-seq &rest cl-keys) "Count the number of occurrences of ITEM in SEQ. \nKeywords supported: :test :test-not :key :start :end @@ -540,18 +564,21 @@ (setq cl-start (1+ cl-start))) cl-count))) +;;;###autoload (defun count-if (cl-pred cl-list &rest cl-keys) "Count the number of items satisfying PREDICATE in SEQ. \nKeywords supported: :key :start :end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'count nil cl-list :if cl-pred cl-keys)) +;;;###autoload (defun count-if-not (cl-pred cl-list &rest cl-keys) "Count the number of items not satisfying PREDICATE in SEQ. \nKeywords supported: :key :start :end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (apply 'count nil cl-list :if-not cl-pred cl-keys)) +;;;###autoload (defun mismatch (cl-seq1 cl-seq2 &rest cl-keys) "Compare SEQ1 with SEQ2, return index of first mismatching element. Return nil if the sequences match. If one sequence is a prefix of the @@ -582,6 +609,7 @@ (and (or (< cl-start1 cl-end1) (< cl-start2 cl-end2)) cl-start1))))) +;;;###autoload (defun search (cl-seq1 cl-seq2 &rest cl-keys) "Search for SEQ1 as a subsequence of SEQ2. Return the index of the leftmost element of the first match found; @@ -608,6 +636,7 @@ (if cl-from-end (setq cl-end2 cl-pos) (setq cl-start2 (1+ cl-pos)))) (and (< cl-start2 cl-end2) cl-pos))))) +;;;###autoload (defun sort* (cl-seq cl-pred &rest cl-keys) "Sort the argument SEQ according to PREDICATE. This is a destructive function; it reuses the storage of SEQ if possible. @@ -622,6 +651,7 @@ (funcall cl-pred (funcall cl-key cl-x) (funcall cl-key cl-y))))))))) +;;;###autoload (defun stable-sort (cl-seq cl-pred &rest cl-keys) "Sort the argument SEQ stably according to PREDICATE. This is a destructive function; it reuses the storage of SEQ if possible. @@ -629,6 +659,7 @@ \n(fn SEQ PREDICATE [KEYWORD VALUE]...)" (apply 'sort* cl-seq cl-pred cl-keys)) +;;;###autoload (defun merge (cl-type cl-seq1 cl-seq2 cl-pred &rest cl-keys) "Destructively merge the two sequences to produce a new sequence. TYPE is the sequence type to return, SEQ1 and SEQ2 are the two argument @@ -647,6 +678,7 @@ (coerce (nconc (nreverse cl-res) cl-seq1 cl-seq2) cl-type)))) ;;; See compiler macro in cl-macs.el +;;;###autoload (defun member* (cl-item cl-list &rest cl-keys) "Find the first occurrence of ITEM in LIST. Return the sublist of LIST whose car is ITEM. @@ -661,6 +693,7 @@ (member cl-item cl-list) (memq cl-item cl-list)))) +;;;###autoload (defun member-if (cl-pred cl-list &rest cl-keys) "Find the first item satisfying PREDICATE in LIST. Return the sublist of LIST whose car matches. @@ -668,6 +701,7 @@ \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (apply 'member* nil cl-list :if cl-pred cl-keys)) +;;;###autoload (defun member-if-not (cl-pred cl-list &rest cl-keys) "Find the first item not satisfying PREDICATE in LIST. Return the sublist of LIST whose car matches. @@ -675,6 +709,7 @@ \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (apply 'member* nil cl-list :if-not cl-pred cl-keys)) +;;;###autoload (defun cl-adjoin (cl-item cl-list &rest cl-keys) (if (cl-parsing-keywords (:key) t (apply 'member* (cl-check-key cl-item) cl-list cl-keys)) @@ -682,6 +717,7 @@ (cons cl-item cl-list))) ;;; See compiler macro in cl-macs.el +;;;###autoload (defun assoc* (cl-item cl-alist &rest cl-keys) "Find the first item whose car matches ITEM in LIST. \nKeywords supported: :test :test-not :key @@ -697,18 +733,21 @@ (assoc cl-item cl-alist) (assq cl-item cl-alist)))) +;;;###autoload (defun assoc-if (cl-pred cl-list &rest cl-keys) "Find the first item whose car satisfies PREDICATE in LIST. \nKeywords supported: :key \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (apply 'assoc* nil cl-list :if cl-pred cl-keys)) +;;;###autoload (defun assoc-if-not (cl-pred cl-list &rest cl-keys) "Find the first item whose car does not satisfy PREDICATE in LIST. \nKeywords supported: :key \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (apply 'assoc* nil cl-list :if-not cl-pred cl-keys)) +;;;###autoload (defun rassoc* (cl-item cl-alist &rest cl-keys) "Find the first item whose cdr matches ITEM in LIST. \nKeywords supported: :test :test-not :key @@ -722,18 +761,21 @@ (and cl-alist (car cl-alist))) (rassq cl-item cl-alist))) +;;;###autoload (defun rassoc-if (cl-pred cl-list &rest cl-keys) "Find the first item whose cdr satisfies PREDICATE in LIST. \nKeywords supported: :key \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (apply 'rassoc* nil cl-list :if cl-pred cl-keys)) +;;;###autoload (defun rassoc-if-not (cl-pred cl-list &rest cl-keys) "Find the first item whose cdr does not satisfy PREDICATE in LIST. \nKeywords supported: :key \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (apply 'rassoc* nil cl-list :if-not cl-pred cl-keys)) +;;;###autoload (defun union (cl-list1 cl-list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-union operation. The result list contains all items that appear in either LIST1 or LIST2. @@ -754,6 +796,7 @@ (pop cl-list2)) cl-list1))) +;;;###autoload (defun nunion (cl-list1 cl-list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-union operation. The result list contains all items that appear in either LIST1 or LIST2. @@ -764,6 +807,7 @@ (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) (t (apply 'union cl-list1 cl-list2 cl-keys)))) +;;;###autoload (defun intersection (cl-list1 cl-list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-intersection operation. The result list contains all items that appear in both LIST1 and LIST2. @@ -786,6 +830,7 @@ (pop cl-list2)) cl-res))))) +;;;###autoload (defun nintersection (cl-list1 cl-list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-intersection operation. The result list contains all items that appear in both LIST1 and LIST2. @@ -795,6 +840,7 @@ \n(fn LIST1 LIST2 [KEYWORD VALUE]...)" (and cl-list1 cl-list2 (apply 'intersection cl-list1 cl-list2 cl-keys))) +;;;###autoload (defun set-difference (cl-list1 cl-list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-difference operation. The result list contains all items that appear in LIST1 but not LIST2. @@ -814,6 +860,7 @@ (pop cl-list1)) cl-res)))) +;;;###autoload (defun nset-difference (cl-list1 cl-list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-difference operation. The result list contains all items that appear in LIST1 but not LIST2. @@ -824,6 +871,7 @@ (if (or (null cl-list1) (null cl-list2)) cl-list1 (apply 'set-difference cl-list1 cl-list2 cl-keys))) +;;;###autoload (defun set-exclusive-or (cl-list1 cl-list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-exclusive-or operation. The result list contains all items that appear in exactly one of LIST1, LIST2. @@ -836,6 +884,7 @@ (t (append (apply 'set-difference cl-list1 cl-list2 cl-keys) (apply 'set-difference cl-list2 cl-list1 cl-keys))))) +;;;###autoload (defun nset-exclusive-or (cl-list1 cl-list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-exclusive-or operation. The result list contains all items that appear in exactly one of LIST1, LIST2. @@ -848,6 +897,7 @@ (t (nconc (apply 'nset-difference cl-list1 cl-list2 cl-keys) (apply 'nset-difference cl-list2 cl-list1 cl-keys))))) +;;;###autoload (defun subsetp (cl-list1 cl-list2 &rest cl-keys) "Return true if LIST1 is a subset of LIST2. I.e., if every element of LIST1 also appears in LIST2. @@ -862,6 +912,7 @@ (pop cl-list1)) (null cl-list1))))) +;;;###autoload (defun subst-if (cl-new cl-pred cl-tree &rest cl-keys) "Substitute NEW for elements matching PREDICATE in TREE (non-destructively). Return a copy of TREE with all matching elements replaced by NEW. @@ -869,6 +920,7 @@ \n(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" (apply 'sublis (list (cons nil cl-new)) cl-tree :if cl-pred cl-keys)) +;;;###autoload (defun subst-if-not (cl-new cl-pred cl-tree &rest cl-keys) "Substitute NEW for elts not matching PREDICATE in TREE (non-destructively). Return a copy of TREE with all non-matching elements replaced by NEW. @@ -876,6 +928,7 @@ \n(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" (apply 'sublis (list (cons nil cl-new)) cl-tree :if-not cl-pred cl-keys)) +;;;###autoload (defun nsubst (cl-new cl-old cl-tree &rest cl-keys) "Substitute NEW for OLD everywhere in TREE (destructively). Any element of TREE which is `eql' to OLD is changed to NEW (via a call @@ -884,6 +937,7 @@ \n(fn NEW OLD TREE [KEYWORD VALUE]...)" (apply 'nsublis (list (cons cl-old cl-new)) cl-tree cl-keys)) +;;;###autoload (defun nsubst-if (cl-new cl-pred cl-tree &rest cl-keys) "Substitute NEW for elements matching PREDICATE in TREE (destructively). Any element of TREE which matches is changed to NEW (via a call to `setcar'). @@ -891,6 +945,7 @@ \n(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" (apply 'nsublis (list (cons nil cl-new)) cl-tree :if cl-pred cl-keys)) +;;;###autoload (defun nsubst-if-not (cl-new cl-pred cl-tree &rest cl-keys) "Substitute NEW for elements not matching PREDICATE in TREE (destructively). Any element of TREE which matches is changed to NEW (via a call to `setcar'). @@ -898,6 +953,7 @@ \n(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" (apply 'nsublis (list (cons nil cl-new)) cl-tree :if-not cl-pred cl-keys)) +;;;###autoload (defun sublis (cl-alist cl-tree &rest cl-keys) "Perform substitutions indicated by ALIST in TREE (non-destructively). Return a copy of TREE with all matching elements replaced. @@ -920,6 +976,7 @@ (cons cl-a cl-d))) cl-tree)))) +;;;###autoload (defun nsublis (cl-alist cl-tree &rest cl-keys) "Perform substitutions indicated by ALIST in TREE (destructively). Any matching element of TREE is changed via a call to `setcar'. @@ -944,6 +1001,7 @@ (progn (setcdr cl-tree (cdr (car cl-p))) (setq cl-tree nil)) (setq cl-tree (cdr cl-tree)))))) +;;;###autoload (defun tree-equal (cl-x cl-y &rest cl-keys) "Return t if trees TREE1 and TREE2 have `eql' leaves. Atoms are compared by `eql'; cons cells are compared recursively. @@ -961,5 +1019,9 @@ (run-hooks 'cl-seq-load-hook) -;;; arch-tag: ec1cc072-9006-4225-b6ba-d6b07ed1710c +;; Local variables: +;; generated-autoload-file: "cl-loaddefs.el" +;; End: + +;; arch-tag: ec1cc072-9006-4225-b6ba-d6b07ed1710c ;;; cl-seq.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/cl.el --- a/lisp/emacs-lisp/cl.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/cl.el Sun Jul 15 02:05:20 2007 +0000 @@ -113,8 +113,9 @@ (defun cl-cannot-unload () (error "Cannot unload the feature `cl'")) -;;; Generalized variables. These macros are defined here so that they -;;; can safely be used in .emacs files. +;;; Generalized variables. +;; These macros are defined here so that they +;; can safely be used in .emacs files. (defmacro incf (place &optional x) "Increment PLACE by X (1 by default). @@ -185,8 +186,8 @@ ;;; Control structures. -;;; These macros are so simple and so often-used that it's better to have -;;; them all the time than to load them from cl-macs.el. +;; These macros are so simple and so often-used that it's better to have +;; them all the time than to load them from cl-macs.el. (defun cl-map-extents (&rest cl-args) (apply 'cl-map-overlays cl-args)) @@ -198,9 +199,10 @@ (defalias 'cl-block-throw 'throw) -;;; Multiple values. True multiple values are not supported, or even -;;; simulated. Instead, multiple-value-bind and friends simply expect -;;; the target form to return the values as a list. +;;; Multiple values. +;; True multiple values are not supported, or even +;; simulated. Instead, multiple-value-bind and friends simply expect +;; the target form to return the values as a list. (defsubst values (&rest values) "Return multiple values, Common Lisp style. @@ -321,7 +323,7 @@ (defvar *random-state* (vector 'cl-random-state-tag -1 30 (cl-random-time))) -;;; The following are actually set by cl-float-limits. +;; The following are actually set by cl-float-limits. (defconst most-positive-float nil) (defconst most-negative-float nil) (defconst least-positive-float nil) @@ -585,105 +587,55 @@ ;;; Miscellaneous. -(defvar cl-fake-autoloads nil - "Non-nil means don't make CL functions autoload.") +;; Define data for indentation and edebug. +(dolist (entry + '(((defun* defmacro*) 2) + ((function*) nil + (&or symbolp ([&optional 'macro] 'lambda (&rest sexp) &rest form))) + ((eval-when) 1 (sexp &rest form)) + ((declare) nil (&rest sexp)) + ((the) 1 (sexp &rest form)) + ((case ecase typecase etypecase) 1 (form &rest (sexp &rest form))) + ((block return-from) 1 (sexp &rest form)) + ((return) nil (&optional form)) + ((do do*) 2 ((&rest &or symbolp (symbolp &optional form form)) + (form &rest form) + &rest form)) + ((do-symbols) 1 ((symbolp form &optional form form) &rest form)) + ((do-all-symbols) 1 ((symbolp form &optional form) &rest form)) + ((psetq setf psetf) nil edebug-setq-form) + ((progv) 2 (&rest form)) + ((flet labels macrolet) 1 + ((&rest (sexp sexp &rest form)) &rest form)) + ((symbol-macrolet lexical-let lexical-let*) 1 + ((&rest &or symbolp (symbolp form)) &rest form)) + ((multiple-value-bind) 2 ((&rest symbolp) &rest form)) + ((multiple-value-setq) 1 ((&rest symbolp) &rest form)) + ((incf decf remf pushnew shiftf rotatef) nil (&rest form)) + ((letf letf*) 1 ((&rest (&rest form)) &rest form)) + ((callf destructuring-bind) 2 (sexp form &rest form)) + ((callf2) 3 (sexp form form &rest form)) + ((loop) nil (&rest &or symbolp form)) + ((ignore-errors) 0 (&rest form)))) + (dolist (func (car entry)) + (put func 'lisp-indent-function (nth 1 entry)) + (put func 'lisp-indent-hook (nth 1 entry)) + (or (get func 'edebug-form-spec) + (put func 'edebug-form-spec (nth 2 entry))))) -;;; Autoload the other portions of the package. +;; Autoload the other portions of the package. ;; We want to replace the basic versions of dolist, dotimes, declare below. (fmakunbound 'dolist) (fmakunbound 'dotimes) (fmakunbound 'declare) -(mapcar (function - (lambda (set) - (let ((file (if cl-fake-autoloads "" (car set)))) - (mapcar (function - (lambda (func) - (autoload func (car set) nil nil (nth 1 set)))) - (cddr set))))) - '(("cl-extra" nil - coerce equalp cl-map-keymap maplist mapc mapl mapcan mapcon - cl-map-keymap cl-map-keymap-recursively cl-map-intervals - cl-map-overlays cl-set-frame-visible-p cl-float-limits - gcd lcm isqrt floor* ceiling* truncate* round* - mod* rem* signum random* make-random-state random-state-p - subseq concatenate cl-mapcar-many map some every notany - notevery revappend nreconc list-length tailp copy-tree get* getf - cl-set-getf cl-do-remf remprop cl-make-hash-table cl-hash-lookup - cl-gethash cl-puthash cl-remhash cl-clrhash cl-maphash cl-hash-table-p - cl-hash-table-count cl-progv-before cl-prettyexpand - cl-macroexpand-all) - ("cl-seq" nil - reduce fill replace remove* remove-if remove-if-not - delete* delete-if delete-if-not remove-duplicates - delete-duplicates substitute substitute-if substitute-if-not - nsubstitute nsubstitute-if nsubstitute-if-not find find-if - find-if-not position position-if position-if-not count count-if - count-if-not mismatch search sort* stable-sort merge member* - member-if member-if-not cl-adjoin assoc* assoc-if assoc-if-not - rassoc* rassoc-if rassoc-if-not union nunion intersection - nintersection set-difference nset-difference set-exclusive-or - nset-exclusive-or subsetp subst-if subst-if-not nsubst nsubst-if - nsubst-if-not sublis nsublis tree-equal) - ("cl-macs" nil - gensym gentemp typep cl-do-pop get-setf-method - cl-struct-setf-expander compiler-macroexpand cl-compile-time-init) - ("cl-macs" t - defun* defmacro* function* destructuring-bind eval-when - load-time-value case ecase typecase etypecase - block return return-from loop do do* dolist dotimes do-symbols - do-all-symbols psetq progv flet labels macrolet symbol-macrolet - lexical-let lexical-let* multiple-value-bind multiple-value-setq - locally the declare define-setf-method defsetf define-modify-macro - setf psetf remf shiftf rotatef letf letf* callf callf2 defstruct - check-type assert ignore-errors define-compiler-macro))) +(load "cl-loaddefs" nil 'quiet) -;;; Define data for indentation and edebug. -(mapcar (function - (lambda (entry) - (mapcar (function - (lambda (func) - (put func 'lisp-indent-function (nth 1 entry)) - (put func 'lisp-indent-hook (nth 1 entry)) - (or (get func 'edebug-form-spec) - (put func 'edebug-form-spec (nth 2 entry))))) - (car entry)))) - '(((defun* defmacro*) 2) - ((function*) nil - (&or symbolp ([&optional 'macro] 'lambda (&rest sexp) &rest form))) - ((eval-when) 1 (sexp &rest form)) - ((declare) nil (&rest sexp)) - ((the) 1 (sexp &rest form)) - ((case ecase typecase etypecase) 1 (form &rest (sexp &rest form))) - ((block return-from) 1 (sexp &rest form)) - ((return) nil (&optional form)) - ((do do*) 2 ((&rest &or symbolp (symbolp &optional form form)) - (form &rest form) - &rest form)) - ((do-symbols) 1 ((symbolp form &optional form form) &rest form)) - ((do-all-symbols) 1 ((symbolp form &optional form) &rest form)) - ((psetq setf psetf) nil edebug-setq-form) - ((progv) 2 (&rest form)) - ((flet labels macrolet) 1 - ((&rest (sexp sexp &rest form)) &rest form)) - ((symbol-macrolet lexical-let lexical-let*) 1 - ((&rest &or symbolp (symbolp form)) &rest form)) - ((multiple-value-bind) 2 ((&rest symbolp) &rest form)) - ((multiple-value-setq) 1 ((&rest symbolp) &rest form)) - ((incf decf remf pushnew shiftf rotatef) nil (&rest form)) - ((letf letf*) 1 ((&rest (&rest form)) &rest form)) - ((callf destructuring-bind) 2 (sexp form &rest form)) - ((callf2) 3 (sexp form form &rest form)) - ((loop) nil (&rest &or symbolp form)) - ((ignore-errors) 0 (&rest form)))) - - -;;; This goes here so that cl-macs can find it if it loads right now. +;; This goes here so that cl-macs can find it if it loads right now. (provide 'cl-19) ; usage: (require 'cl-19 "cl") - -;;; Things to do after byte-compiler is loaded. -;;; As a side effect, we cause cl-macs to be loaded when compiling, so -;;; that the compiler-macros defined there will be present. +;; Things to do after byte-compiler is loaded. +;; As a side effect, we cause cl-macs to be loaded when compiling, so +;; that the compiler-macros defined there will be present. (defvar cl-hacked-flag nil) (defun cl-hack-byte-compiler () @@ -692,15 +644,15 @@ (setq cl-hacked-flag t) ; Do it first, to prevent recursion. (cl-compile-time-init)))) ; In cl-macs.el. -;;; Try it now in case the compiler has already been loaded. +;; Try it now in case the compiler has already been loaded. (cl-hack-byte-compiler) -;;; Also make a hook in case compiler is loaded after this file. +;; Also make a hook in case compiler is loaded after this file. (add-hook 'bytecomp-load-hook 'cl-hack-byte-compiler) -;;; The following ensures that packages which expect the old-style cl.el -;;; will be happy with this one. +;; The following ensures that packages which expect the old-style cl.el +;; will be happy with this one. (provide 'cl) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/copyright.el --- a/lisp/emacs-lisp/copyright.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/copyright.el Sun Jul 15 02:05:20 2007 +0000 @@ -79,7 +79,7 @@ ;; when modifying this, also modify the comment generated by autoinsert.el -(defconst copyright-current-gpl-version "2" +(defconst copyright-current-gpl-version "3" "String representing the current version of the GPL or nil.") (defvar copyright-update t) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/easymenu.el --- a/lisp/emacs-lisp/easymenu.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/easymenu.el Sun Jul 15 02:05:20 2007 +0000 @@ -152,6 +152,21 @@ ,(if symbol `(defvar ,symbol nil ,doc)) (easy-menu-do-define (quote ,symbol) ,maps ,doc ,menu))) +(defun easy-menu-binding (menu &optional item-name) + "Return a binding suitable to pass to `define-key'. +This is expected to be bound to a mouse event." + ;; Under Emacs this is almost trivial, whereas under XEmacs this may + ;; involve defining a function that calls popup-menu. + (let ((props (if (symbolp menu) + (prog1 (get menu 'menu-prop) + (setq menu (symbol-function menu)))))) + (cons 'menu-item + (cons (or item-name + (if (keymapp menu) + (keymap-prompt menu)) + "") + (cons menu props))))) + ;;;###autoload (defun easy-menu-do-define (symbol maps doc menu) ;; We can't do anything that might differ between Emacs dialects in @@ -173,15 +188,10 @@ 'identity) (symbol-function ,symbol))) ,symbol))))) - (mapcar (lambda (map) - (define-key map (vector 'menu-bar (easy-menu-intern (car menu))) - (cons 'menu-item - (cons (car menu) - (if (not (symbolp keymap)) - (list keymap) - (cons (symbol-function keymap) - (get keymap 'menu-prop))))))) - (if (keymapp maps) (list maps) maps)))) + (dolist (map (if (keymapp maps) (list maps) maps)) + (define-key map + (vector 'menu-bar (easy-menu-intern (car menu))) + (easy-menu-binding keymap (car menu)))))) (defun easy-menu-filter-return (menu &optional name) "Convert MENU to the right thing to return from a menu filter. @@ -249,10 +259,6 @@ (defvar easy-menu-button-prefix '((radio . :radio) (toggle . :toggle))) -(defun easy-menu-do-add-item (menu item &optional before) - (setq item (easy-menu-convert-item item)) - (easy-menu-define-key menu (easy-menu-intern (car item)) (cdr item) before)) - (defvar easy-menu-converted-items-table (make-hash-table :test 'equal)) (defun easy-menu-convert-item (item) @@ -269,7 +275,7 @@ (defun easy-menu-convert-item-1 (item) "Parse an item description and convert it to a menu keymap element. ITEM defines an item as in `easy-menu-define'." - (let (name command label prop remove help) + (let (name command label prop remove) (cond ((stringp item) ; An item or separator. (setq label item)) @@ -536,7 +542,8 @@ (setq item (symbol-value item)))) ;; Item is a keymap, find the prompt string and use as item name. (setq item (cons (keymap-prompt item) item))) - (easy-menu-do-add-item map item before))) + (setq item (easy-menu-convert-item item)) + (easy-menu-define-key map (easy-menu-intern (car item)) (cdr item) before))) (defun easy-menu-item-present-p (map path name) "In submenu of MAP with path PATH, return non-nil iff item NAME is present. @@ -615,7 +622,8 @@ (catch 'found (if (and map (symbolp map) (not (keymapp map))) (setq map (symbol-value map))) - (let ((maps (if map (list map) (current-active-maps)))) + (let ((maps (if map (if (keymapp map) (list map) map) + (current-active-maps)))) ;; Look for PATH in each map. (unless map (push 'menu-bar path)) (dolist (name path) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/eldoc.el --- a/lisp/emacs-lisp/eldoc.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/eldoc.el Sun Jul 15 02:05:20 2007 +0000 @@ -124,8 +124,8 @@ (defconst eldoc-last-data (make-vector 3 nil) "Bookkeeping; elements are as follows: 0 - contains the last symbol read from the buffer. - 1 - contains the string last displayed in the echo area for that - symbol, so it can be printed again if necessary without reconsing. + 1 - contains the string last displayed in the echo area for variables, + or argument string for functions. 2 - 'function if function args, 'variable if variable documentation.") (defvar eldoc-last-message nil) @@ -249,12 +249,16 @@ (let* ((current-symbol (eldoc-current-symbol)) (current-fnsym (eldoc-fnsym-in-current-sexp)) (doc (cond - ((eq current-symbol current-fnsym) - (or (eldoc-get-fnsym-args-string current-fnsym) + ((null current-fnsym) + nil) + ((eq current-symbol (car current-fnsym)) + (or (apply 'eldoc-get-fnsym-args-string + current-fnsym) (eldoc-get-var-docstring current-symbol))) (t (or (eldoc-get-var-docstring current-symbol) - (eldoc-get-fnsym-args-string current-fnsym)))))) + (apply 'eldoc-get-fnsym-args-string + current-fnsym)))))) (eldoc-message doc)))) ;; This is run from post-command-hook or some idle timer thing, ;; so we need to be careful that errors aren't ignored. @@ -263,24 +267,62 @@ ;; Return a string containing the function parameter list, or 1-line ;; docstring if function is a subr and no arglist is obtainable from the ;; docstring or elsewhere. -(defun eldoc-get-fnsym-args-string (sym) +(defun eldoc-get-fnsym-args-string (sym argument-index) (let ((args nil) (doc nil)) (cond ((not (and sym (symbolp sym) (fboundp sym)))) ((and (eq sym (aref eldoc-last-data 0)) (eq 'function (aref eldoc-last-data 2))) - (setq doc (aref eldoc-last-data 1))) + (setq args (aref eldoc-last-data 1))) ((setq doc (help-split-fundoc (documentation sym t) sym)) (setq args (car doc)) (string-match "\\`[^ )]* ?" args) - (setq args (concat "(" (substring args (match-end 0))))) + (setq args (concat "(" (substring args (match-end 0)))) + (eldoc-last-data-store sym args 'function)) (t (setq args (eldoc-function-argstring sym)))) - (cond (args - (setq doc (eldoc-docstring-format-sym-doc sym args)) - (eldoc-last-data-store sym doc 'function))) + (when args + (setq doc (eldoc-highlight-function-argument sym args argument-index))) doc)) +;; Highlight argument INDEX in ARGS list for SYM. +(defun eldoc-highlight-function-argument (sym args index) + (let ((start nil) + (end 0) + (argument-face 'bold)) + ;; Find the current argument in the argument string. We need to + ;; handle `&rest' and informal `...' properly. + ;; + ;; FIXME: What to do with optional arguments, like in + ;; (defun NAME ARGLIST [DOCSTRING] BODY...) case? + ;; The problem is there is no robust way to determine if + ;; the current argument is indeed a docstring. + (while (>= index 1) + (if (string-match "[^ ()]+" args end) + (progn + (setq start (match-beginning 0) + end (match-end 0)) + (let ((argument (match-string 0 args))) + (cond ((string= argument "&rest") + ;; All the rest arguments are the same. + (setq index 1)) + ((string= argument "&optional")) + ((string-match "\\.\\.\\.$" argument) + (setq index 0)) + (t + (setq index (1- index)))))) + (setq end (length args) + start (1- end) + argument-face 'font-lock-warning-face + index 0))) + (let ((doc args)) + (when start + (setq doc (copy-sequence args)) + (add-text-properties start end (list 'face argument-face) doc)) + (setq doc (eldoc-docstring-format-sym-doc + sym doc 'font-lock-function-name-face)) + doc))) + ;; Return a string containing a brief (one-line) documentation string for ;; the variable. (defun eldoc-get-var-docstring (sym) @@ -292,7 +334,8 @@ (let ((doc (documentation-property sym 'variable-documentation t))) (cond (doc (setq doc (eldoc-docstring-format-sym-doc - sym (eldoc-docstring-first-line doc))) + sym (eldoc-docstring-first-line doc) + 'font-lock-variable-name-face)) (eldoc-last-data-store sym doc 'variable))) doc))))) @@ -316,7 +359,7 @@ ;; If the entire line cannot fit in the echo area, the symbol name may be ;; truncated or eliminated entirely from the output to make room for the ;; description. -(defun eldoc-docstring-format-sym-doc (sym doc) +(defun eldoc-docstring-format-sym-doc (sym doc face) (save-match-data (let* ((name (symbol-name sym)) (ea-multi eldoc-echo-area-use-multiline-p) @@ -328,7 +371,7 @@ (cond ((or (<= strip 0) (eq ea-multi t) (and ea-multi (> (length doc) ea-width))) - (format "%s: %s" sym doc)) + (format "%s: %s" (propertize name 'face face) doc)) ((> (length doc) ea-width) (substring (format "%s" doc) 0 ea-width)) ((>= strip (length name)) @@ -338,27 +381,44 @@ ;; than the beginning, since the former is more likely ;; to be unique given package namespace conventions. (setq name (substring name strip)) - (format "%s: %s" name doc)))))) + (format "%s: %s" (propertize name 'face face) doc)))))) +;; Return a list of current function name and argument index. (defun eldoc-fnsym-in-current-sexp () - (let ((p (point))) - (eldoc-beginning-of-sexp) - (prog1 - ;; Don't do anything if current word is inside a string. - (if (= (or (char-after (1- (point))) 0) ?\") - nil - (eldoc-current-symbol)) - (goto-char p)))) + (save-excursion + (let ((argument-index (1- (eldoc-beginning-of-sexp)))) + ;; If we are at the beginning of function name, this will be -1. + (when (< argument-index 0) + (setq argument-index 0)) + ;; Don't do anything if current word is inside a string. + (if (= (or (char-after (1- (point))) 0) ?\") + nil + (list (eldoc-current-symbol) argument-index))))) +;; Move to the beginnig of current sexp. Return the number of nested +;; sexp the point was over or after. (defun eldoc-beginning-of-sexp () - (let ((parse-sexp-ignore-comments t)) + (let ((parse-sexp-ignore-comments t) + (num-skipped-sexps 0)) (condition-case err - (while (progn - (forward-sexp -1) - (or (= (char-before) ?\") - (> (point) (point-min))))) - (error nil)))) + (progn + ;; First account for the case the point is directly over a + ;; beginning of a nested sexp. + (condition-case err + (let ((p (point))) + (forward-sexp -1) + (forward-sexp 1) + (when (< (point) p) + (setq num-skipped-sexps 1))) + (error)) + (while + (let ((p (point))) + (forward-sexp -1) + (when (< (point) p) + (setq num-skipped-sexps (1+ num-skipped-sexps)))))) + (error)) + num-skipped-sexps)) ;; returns nil unless current word is an interned symbol. (defun eldoc-current-symbol () diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/lisp-mode.el --- a/lisp/emacs-lisp/lisp-mode.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/lisp-mode.el Sun Jul 15 02:05:20 2007 +0000 @@ -628,13 +628,13 @@ (interactive "P") (if (null eval-expression-debug-on-error) (eval-last-sexp-1 eval-last-sexp-arg-internal) - (let ((old-value eval-last-sexp-fake-value) new-value value) - (let ((debug-on-error old-value)) - (setq value (eval-last-sexp-1 eval-last-sexp-arg-internal)) - (setq new-value debug-on-error)) - (unless (eq old-value new-value) - (setq debug-on-error new-value)) - value))) + (let ((value + (let ((debug-on-error eval-last-sexp-fake-value)) + (cons (eval-last-sexp-1 eval-last-sexp-arg-internal) + debug-on-error)))) + (unless (eq (cdr value) eval-last-sexp-fake-value) + (setq debug-on-error (cdr value))) + (car value)))) (defun eval-defun-1 (form) "Treat some expressions specially. @@ -730,7 +730,9 @@ evaluating it this way resets the variable using its initial value expression even if the variable already has some other value. \(Normally `defvar' and `defcustom' do not alter the value if there -already is one.) +already is one.) In an analogous way, evaluating a `defface' +overrides any customizations of the face, so that it becomes +defined exactly as the `defface' expression says. If `eval-expression-debug-on-error' is non-nil, which is the default, this command arranges for all errors to enter the debugger. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/emacs-lisp/rx.el --- a/lisp/emacs-lisp/rx.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/emacs-lisp/rx.el Sun Jul 15 02:05:20 2007 +0000 @@ -120,7 +120,7 @@ (| . or) ; SRE (not-newline . ".") (nonl . not-newline) ; SRE - (anything . ".\\|\n") + (anything . "\\(?:.\\|\n\\)") (any . (rx-any 1 nil rx-check-any)) ; inconsistent with SRE (in . any) (char . any) ; sregex diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/ffap.el --- a/lisp/ffap.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/ffap.el Sun Jul 15 02:05:20 2007 +0000 @@ -1793,7 +1793,11 @@ ;; Extra complication for the temporary highlighting. (unwind-protect (ffap-read-file-or-url - (if ffap-url-regexp "Dired file or URL: " "Dired file: ") + (cond + ((eq ffap-directory-finder 'list-directory) + "List directory (brief): ") + (ffap-url-regexp "Dired file or URL: ") + (t "Dired file: ")) (prog1 (setq guess (or guess (let ((guess (ffap-guesser))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/files.el --- a/lisp/files.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/files.el Sun Jul 15 02:05:20 2007 +0000 @@ -162,7 +162,7 @@ both at the file level and at the levels of the containing directories." :type 'boolean :group 'find-file) -(put 'find-file-visit-truename 'safe-local-variable 'boolean) +(put 'find-file-visit-truename 'safe-local-variable 'booleanp) (defcustom revert-without-query nil "Specify which files should be reverted without query. @@ -727,17 +727,23 @@ (cons load-path (get-load-suffixes))))) (load library)) -(defun file-remote-p (file) +(defun file-remote-p (file &optional connected) "Test whether FILE specifies a location on a remote system. Return an identification of the system if the location is indeed remote. The identification of the system may comprise a method to access the system and its hostname, amongst other things. For example, the filename \"/user@host:/foo\" specifies a location -on the system \"/user@host:\"." +on the system \"/user@host:\". + +If CONNECTED is non-nil, the function returns an identification only +if FILE is located on a remote system, and a connection is established +to that remote system. + +`file-remote-p' will never open a connection on its own." (let ((handler (find-file-name-handler file 'file-remote-p))) (if handler - (funcall handler 'file-remote-p file) + (funcall handler 'file-remote-p file connected) nil))) (defun file-local-copy (file) @@ -1051,6 +1057,12 @@ ,@body) (remove-hook 'minibuffer-setup-hook ,hook))))) +(defcustom find-file-confirm-nonexistent-file nil + "If non-nil, `find-file' requires confirmation before visiting a new file." + :group 'find-file + :version "23.1" + :type 'boolean) + (defun find-file-read-args (prompt mustmatch) (list (let ((find-file-default (and buffer-file-name @@ -1074,7 +1086,9 @@ To visit a file without any kind of conversion and without automatically choosing a major mode, use \\[find-file-literally]." - (interactive (find-file-read-args "Find file: " nil)) + (interactive + (find-file-read-args "Find file: " + (if find-file-confirm-nonexistent-file 'confirm-only))) (let ((value (find-file-noselect filename nil nil wildcards))) (if (listp value) (mapcar 'switch-to-buffer (nreverse value)) @@ -1091,7 +1105,9 @@ Interactively, or if WILDCARDS is non-nil in a call from Lisp, expand wildcards (if any) and visit multiple files." - (interactive (find-file-read-args "Find file in other window: " nil)) + (interactive + (find-file-read-args "Find file in other window: " + (if find-file-confirm-nonexistent-file 'confirm-only))) (let ((value (find-file-noselect filename nil nil wildcards))) (if (listp value) (progn @@ -1111,7 +1127,9 @@ Interactively, or if WILDCARDS is non-nil in a call from Lisp, expand wildcards (if any) and visit multiple files." - (interactive (find-file-read-args "Find file in other frame: " nil)) + (interactive + (find-file-read-args "Find file in other frame: " + (if find-file-confirm-nonexistent-file 'confirm-only))) (let ((value (find-file-noselect filename nil nil wildcards))) (if (listp value) (progn @@ -1134,7 +1152,9 @@ "Edit file FILENAME but don't allow changes. Like \\[find-file] but marks buffer as read-only. Use \\[toggle-read-only] to permit editing." - (interactive (find-file-read-args "Find file read-only: " nil)) + (interactive + (find-file-read-args "Find file read-only: " + (if find-file-confirm-nonexistent-file 'confirm-only))) (unless (or (and wildcards find-file-wildcards (not (string-match "\\`/:" filename)) (string-match "[[*?]" filename)) @@ -1149,7 +1169,9 @@ "Edit file FILENAME in another window but don't allow changes. Like \\[find-file-other-window] but marks buffer as read-only. Use \\[toggle-read-only] to permit editing." - (interactive (find-file-read-args "Find file read-only other window: " nil)) + (interactive + (find-file-read-args "Find file read-only other window: " + (if find-file-confirm-nonexistent-file 'confirm-only))) (unless (or (and wildcards find-file-wildcards (not (string-match "\\`/:" filename)) (string-match "[[*?]" filename)) @@ -1164,7 +1186,9 @@ "Edit file FILENAME in another frame but don't allow changes. Like \\[find-file-other-frame] but marks buffer as read-only. Use \\[toggle-read-only] to permit editing." - (interactive (find-file-read-args "Find file read-only other frame: " nil)) + (interactive + (find-file-read-args "Find file read-only other frame: " + (if find-file-confirm-nonexistent-file 'confirm-only))) (unless (or (and wildcards find-file-wildcards (not (string-match "\\`/:" filename)) (string-match "[[*?]" filename)) @@ -4022,6 +4046,8 @@ (defun make-directory (dir &optional parents) "Create the directory DIR and any nonexistent parent dirs. +If DIR already exists as a directory, do nothing. + Interactively, the default choice of directory to create is the current default directory for file names. That is useful when you have visited a file in a nonexistent directory. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/follow.el --- a/lisp/follow.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/follow.el Sun Jul 15 02:05:20 2007 +0000 @@ -336,123 +336,45 @@ ;; the look and feel of Follow mode.) (define-key mainmap [remap end-of-buffer] 'follow-end-of-buffer) - ;; - ;; The menu. - ;; - - (if (not (featurep 'xemacs)) - - ;; - ;; Emacs - ;; - (let ((menumap (funcall (symbol-function 'make-sparse-keymap) - "Follow")) - (count 0) - id) - (mapcar - (function - (lambda (item) - (setq id - (or (cdr item) - (progn - (setq count (+ count 1)) - (intern (format "separator-%d" count))))) - (define-key menumap (vector id) item) - (or (eq id 'follow-mode) - (put id 'menu-enable 'follow-mode)))) - ;; In reverse order: - '(("Toggle Follow mode" . follow-mode) - ("--") - ("Recenter" . follow-recenter) - ("--") - ("Previous Window" . follow-previous-window) - ("Next Windows" . follow-next-window) - ("Last Window" . follow-last-window) - ("First Window" . follow-first-window) - ("--") - ("Switch To Buffer (all windows)" - . follow-switch-to-buffer-all) - ("Switch To Buffer" . follow-switch-to-buffer) - ("--") - ("Delete Other Windows and Split" - . follow-delete-other-windows-and-split) - ("--") - ("Scroll Down" . follow-scroll-down) - ("Scroll Up" . follow-scroll-up))) - - ;; If there is a `tools' menu, we use it. However, we can't add a - ;; minor-mode specific item to it (it's broken), so we make the - ;; contents ghosted when not in use, and add ourselves to the - ;; global map. If no `tools' menu is present, just make a - ;; top-level menu visible when the mode is activated. - - (let ((tools-map (lookup-key (current-global-map) [menu-bar tools])) - (last nil)) - (if (sequencep tools-map) - (progn - ;; Find the last entry in the menu and store it in `last'. - (mapcar (function - (lambda (x) - (setq last (or (cdr-safe - (cdr-safe - (cdr-safe x))) - last)))) - tools-map) - (if last - (progn - (funcall (symbol-function 'define-key-after) - tools-map [separator-follow] '("--") last) - (funcall (symbol-function 'define-key-after) - tools-map [follow] (cons "Follow" menumap) - 'separator-follow)) - ;; Didn't find the last item, Adding to the top of - ;; tools. (This will probably never happend...) - (define-key (current-global-map) [menu-bar tools follow] - (cons "Follow" menumap)))) - ;; No tools menu, add "Follow" to the menubar. - (define-key mainmap [menu-bar follow] - (cons "Follow" menumap))))) - - ;; - ;; XEmacs. - ;; - - ;; place the menu in the `Tools' menu. - (let ((menu '("Follow" - :filter follow-menu-filter - ["Scroll Up" follow-scroll-up t] - ["Scroll Down" follow-scroll-down t] - ["Delete Other Windows and Split" - follow-delete-other-windows-and-split t] - ["Switch To Buffer" follow-switch-to-buffer t] - ["Switch To Buffer (all windows)" - follow-switch-to-buffer-all t] - ["First Window" follow-first-window t] - ["Last Window" follow-last-window t] - ["Next Windows" follow-next-window t] - ["Previous Window" follow-previous-window t] - ["Recenter" follow-recenter t] - ["Deactivate" follow-mode t]))) - - ;; Why not just `(set-buffer-menubar current-menubar)'? The - ;; question is a very good question. The reason is that under - ;; Emacs, neither `set-buffer-menubar' nor - ;; `current-menubar' is defined, hence the byte-compiler will - ;; warn. - (funcall (symbol-function 'set-buffer-menubar) - (symbol-value 'current-menubar)) - (funcall (symbol-function 'add-submenu) '("Tools") menu)) - - ;; When the mode is not activated, only one item is visible: - ;; "Activate". - (defun follow-menu-filter (menu) - (if follow-mode - menu - '(["Activate " follow-mode t])))) - mainmap) "Minor mode keymap for Follow mode.") +;; When the mode is not activated, only one item is visible to activate +;; the mode. +(defun follow-menu-filter (menu) + (if (bound-and-true-p 'follow-mode) + menu + '(["Follow mode " follow-mode + :style toggle :selected follow-mode]))) + +;; If there is a `tools' menu, we use it. However, we can't add a +;; minor-mode specific item to it (it's broken), so we make the +;; contents ghosted when not in use, and add ourselves to the +;; global map. +(easy-menu-add-item nil '("Tools") + '("Follow" + ;; The Emacs code used to just grey out operations when follow-mode was + ;; not enabled, whereas the XEmacs code used to remove it altogether. + ;; Not sure which is preferable, but clearly the preference should not + ;; depend on the flavor. + :filter follow-menu-filter + ["Scroll Up" follow-scroll-up follow-mode] + ["Scroll Down" follow-scroll-down follow-mode] + "--" + ["Delete Other Windows and Split" follow-delete-other-windows-and-split follow-mode] + "--" + ["Switch To Buffer" follow-switch-to-buffer follow-mode] + ["Switch To Buffer (all windows)" follow-switch-to-buffer-all follow-mode] + "--" + ["First Window" follow-first-window follow-mode] + ["Last Window" follow-last-window follow-mode] + ["Next Window" follow-next-window follow-mode] + ["Previous Window" follow-previous-window follow-mode] + "--" + ["Recenter" follow-recenter follow-mode] + "--" + ["Follow mode" follow-mode :style toggle :selected follow-mode])) + ;;}}} (defcustom follow-mode-line-text " Follow" @@ -553,14 +475,12 @@ ;;;###autoload (defun turn-on-follow-mode () "Turn on Follow mode. Please see the function `follow-mode'." - (interactive) (follow-mode 1)) ;;;###autoload (defun turn-off-follow-mode () "Turn off Follow mode. Please see the function `follow-mode'." - (interactive) (follow-mode -1)) (put 'follow-mode 'permanent-local t) @@ -2084,8 +2004,8 @@ (defun follow-window-size-change (frame) "Redraw all windows in FRAME, when in Follow mode." - ;; Below, we call `post-command-hook'. This makes sure that we - ;; doesn't start a mutally recursive endless loop. + ;; Below, we call `post-command-hook'. This makes sure that we + ;; don't start a mutually recursive endless loop. (if follow-inside-post-command-hook nil (let ((buffers '()) @@ -2109,12 +2029,12 @@ (setq windows (follow-all-followers win)) (if (memq orig-window windows) (progn - ;; Make sure we're redrawing around the - ;; selected window. - ;; - ;; We must be really careful not to do this - ;; when we are (indirectly) called by - ;; `post-command-hook'. + ;; Make sure we're redrawing around the + ;; selected window. + ;; + ;; We must be really careful not to do this + ;; when we are (indirectly) called by + ;; `post-command-hook'. (select-window orig-window) (follow-post-command-hook) (setq orig-window (selected-window))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/font-lock.el --- a/lisp/font-lock.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/font-lock.el Sun Jul 15 02:05:20 2007 +0000 @@ -2287,7 +2287,7 @@ ;; that do not occur in strings. The associated regexp matches one ;; of `\\\\' `\\(' `\\(?:' `\\|' `\\)'. `\\\\' has been included to ;; avoid highlighting, for example, `\\(' in `\\\\('. - (while (re-search-forward "\\(\\\\\\\\\\)\\(?:\\(\\\\\\\\\\)\\|\\((\\(?:\\?:\\)?\\|[|)]\\)\\)" bound t) + (while (re-search-forward "\\(\\\\\\\\\\)\\(?:\\(\\\\\\\\\\)\\|\\((\\(?:\\?[0-9]*:\\)?\\|[|)]\\)\\)" bound t) (unless (match-beginning 2) (let ((face (get-text-property (1- (point)) 'face))) (when (or (and (listp face) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/generic-x.el --- a/lisp/generic-x.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/generic-x.el Sun Jul 15 02:05:20 2007 +0000 @@ -26,7 +26,7 @@ ;;; Commentary: ;; -;; This file contains a collection generic modes. +;; This file contains a collection of generic modes. ;; ;; INSTALLATION: ;; @@ -244,7 +244,7 @@ (memq system-type '(windows-nt ms-dos)) "*Non-nil means the modes in `generic-mswindows-modes' will be defined. This is a list of MS-Windows specific generic modes. This variable -only effects the default value of `generic-extras-enable-list'." +only affects the default value of `generic-extras-enable-list'." :group 'generic-x :type 'boolean :version "22.1") @@ -254,7 +254,7 @@ (not (memq system-type '(windows-nt ms-dos))) "*Non-nil means the modes in `generic-unix-modes' will be defined. This is a list of Unix specific generic modes. This variable only -effects the default value of `generic-extras-enable-list'." +affects the default value of `generic-extras-enable-list'." :group 'generic-x :type 'boolean :version "22.1") @@ -317,7 +317,7 @@ (2 font-lock-variable-name-face))) '("access_log\\'") nil - "Mode for Apache log files")) + "Mode for Apache log files.")) ;;; Samba (when (memq 'samba-generic-mode generic-extras-enable-list) @@ -522,7 +522,7 @@ "Syntax table in use in `bat-generic-mode' buffers.") (defvar bat-generic-mode-keymap (make-sparse-keymap) - "Keymap for bet-generic-mode.") + "Keymap for `bat-generic-mode'.") (defun bat-generic-mode-compile () "Run the current BAT file in a compilation buffer." @@ -784,7 +784,7 @@ (2 font-lock-constant-face))) '("[mM][aA][nN][iI][fF][eE][sS][tT]\\.[mM][fF]\\'") nil - "Mode for Java Manifest files")) + "Mode for Java Manifest files.")) ;; Java properties files (when (memq 'java-properties-generic-mode generic-extras-enable-list) @@ -1776,7 +1776,7 @@ nil ;; no auto-mode-alist ;; '(show-tabs-generic-mode-hook-fun) nil - "Generic mode to show tabs and trailing spaces")) + "Generic mode to show tabs and trailing spaces.")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; DNS modes diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/gnus/ChangeLog --- a/lisp/gnus/ChangeLog Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/gnus/ChangeLog Sun Jul 15 02:05:20 2007 +0000 @@ -1,3 +1,42 @@ +2007-07-14 David Kastrup + + * gnus-art.el (gnus-mime-delete-part): Don't go through article-edit + finishing actions if we did not edit the article. + +2007-07-13 Katsumi Yamaoka + + * gnus-srvr.el (gnus-server-agent-face, gnus-server-opened-face) + (gnus-server-closed-face, gnus-server-denied-face) + (gnus-server-offline-face): Remove variable. + (gnus-server-font-lock-keywords): Use faces that are not aliases. + + * mm-util.el (mm-decode-coding-string, mm-encode-coding-string) + (mm-decode-coding-region, mm-encode-coding-region): Don't modify string + if the coding-system argument is nil for XEmacs. + + * nnrss.el (nnrss-compatible-encoding-alist): Inherit the value of + mm-charset-override-alist. + + * rfc2047.el: Don't require base64; require rfc2045 for the function + rfc2045-encode-string. + (rfc2047-encode-parameter): Use rfc2045-encode-string to quote or not + to quote the parameter value. + +2007-07-04 Katsumi Yamaoka + + * gnus-sum.el (gnus-summary-catchup): Don't recognize cached articles + as unfetched articles. + +2007-07-02 Reiner Steib + + * gnus-start.el (gnus-level-unsubscribed): Improve doc string. + +2007-06-26 Katsumi Yamaoka + + * gnus-art.el (gnus-article-summary-command-nosave) + (gnus-article-read-summary-keys): Don't set the 3rd arg of + pop-to-buffer for XEmacs. + 2007-06-14 Katsumi Yamaoka * gnus-agent.el (gnus-agent-fetch-headers) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/gnus/gnus-art.el --- a/lisp/gnus/gnus-art.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/gnus/gnus-art.el Sun Jul 15 02:05:20 2007 +0000 @@ -4408,11 +4408,11 @@ (gnus-summary-edit-article-done ,(or (mail-header-references gnus-current-headers) "") ,(gnus-group-read-only-p) - ,gnus-summary-buffer no-highlight))))) - ;; Not in `gnus-mime-save-part-and-strip': - (gnus-article-edit-done) - (gnus-summary-expand-window) - (gnus-summary-show-article)) + ,gnus-summary-buffer no-highlight)))) + ;; Not in `gnus-mime-save-part-and-strip': + (gnus-article-edit-done) + (gnus-summary-expand-window) + (gnus-summary-show-article))) (defun gnus-mime-save-part () "Save the MIME part under point." @@ -5607,7 +5607,7 @@ "Execute the last keystroke in the summary buffer." (interactive) (let (func) - (pop-to-buffer gnus-article-current-summary nil 'norecord) + (pop-to-buffer gnus-article-current-summary nil (not (featurep 'xemacs))) (setq func (lookup-key (current-local-map) (this-command-keys))) (call-interactively func))) @@ -5646,7 +5646,8 @@ (member keys nosave-in-article)) (let (func) (save-window-excursion - (pop-to-buffer gnus-article-current-summary nil 'norecord) + (pop-to-buffer gnus-article-current-summary + nil (not (featurep 'xemacs))) ;; We disable the pick minor mode commands. (let (gnus-pick-mode) (setq func (lookup-key (current-local-map) keys)))) @@ -5658,14 +5659,16 @@ (call-interactively func) (setq new-sum-point (point))) (when (member keys nosave-but-article) - (pop-to-buffer gnus-article-buffer nil 'norecord))) + (pop-to-buffer gnus-article-buffer + nil (not (featurep 'xemacs))))) ;; These commands should restore window configuration. (let ((obuf (current-buffer)) (owin (current-window-configuration)) (opoint (point)) win func in-buffer selected new-sum-start new-sum-hscroll) (cond (not-restore-window - (pop-to-buffer gnus-article-current-summary nil 'norecord)) + (pop-to-buffer gnus-article-current-summary + nil (not (featurep 'xemacs)))) ((setq win (get-buffer-window gnus-article-current-summary)) (select-window win)) (t diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/gnus/gnus-srvr.el --- a/lisp/gnus/gnus-srvr.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/gnus/gnus-srvr.el Sun Jul 15 02:05:20 2007 +0000 @@ -214,43 +214,12 @@ ;; backward-compatibility alias (put 'gnus-server-offline-face 'face-alias 'gnus-server-offline) -(defcustom gnus-server-agent-face 'gnus-server-agent - "Face name to use on AGENTIZED servers." - :version "22.1" - :group 'gnus-server-visual - :type 'face) - -(defcustom gnus-server-opened-face 'gnus-server-opened - "Face name to use on OPENED servers." - :version "22.1" - :group 'gnus-server-visual - :type 'face) - -(defcustom gnus-server-closed-face 'gnus-server-closed - "Face name to use on CLOSED servers." - :version "22.1" - :group 'gnus-server-visual - :type 'face) - -(defcustom gnus-server-denied-face 'gnus-server-denied - "Face name to use on DENIED servers." - :version "22.1" - :group 'gnus-server-visual - :type 'face) - -(defcustom gnus-server-offline-face 'gnus-server-offline - "Face name to use on OFFLINE servers." - :version "22.1" - :group 'gnus-server-visual - :type 'face) - (defvar gnus-server-font-lock-keywords - (list - '("(\\(agent\\))" 1 gnus-server-agent-face) - '("(\\(opened\\))" 1 gnus-server-opened-face) - '("(\\(closed\\))" 1 gnus-server-closed-face) - '("(\\(offline\\))" 1 gnus-server-offline-face) - '("(\\(denied\\))" 1 gnus-server-denied-face))) + '(("(\\(agent\\))" 1 gnus-server-agent) + ("(\\(opened\\))" 1 gnus-server-opened) + ("(\\(closed\\))" 1 gnus-server-closed) + ("(\\(offline\\))" 1 gnus-server-offline) + ("(\\(denied\\))" 1 gnus-server-denied))) (defun gnus-server-mode () "Major mode for listing and editing servers. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/gnus/gnus-start.el --- a/lisp/gnus/gnus-start.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/gnus/gnus-start.el Sun Jul 15 02:05:20 2007 +0000 @@ -178,8 +178,13 @@ (defconst gnus-level-unsubscribed 7 "Groups with levels less than or equal to this variable are unsubscribed. -Groups with levels less than `gnus-level-subscribed', which should be -less than this variable, are subscribed.") + +Groups with levels less than `gnus-level-subscribed', which +should be less than this variable, are subscribed. Groups with +levels from `gnus-level-subscribed' (exclusive) upto this +variable (inclusive) are unsubscribed. See also +`gnus-level-zombie', `gnus-level-killed' and the Info node `Group +Levels' for details.") (defconst gnus-level-zombie 8 "Groups with this level are zombie groups.") diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/gnus/gnus-sum.el --- a/lisp/gnus/gnus-sum.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/gnus/gnus-sum.el Sun Jul 15 02:05:20 2007 +0000 @@ -10514,7 +10514,8 @@ (gnus-sorted-nunion (gnus-sorted-intersection gnus-newsgroup-unreads gnus-newsgroup-downloadable) - gnus-newsgroup-unfetched))) + (gnus-sorted-difference gnus-newsgroup-unfetched + gnus-newsgroup-cached)))) ;; We actually mark all articles as canceled, which we ;; have to do when using auto-expiry or adaptive scoring. (gnus-summary-show-all-threads) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/gnus/mm-util.el --- a/lisp/gnus/mm-util.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/gnus/mm-util.el Sun Jul 15 02:05:20 2007 +0000 @@ -36,11 +36,7 @@ (if (fboundp (car elem)) (defalias nfunc (car elem)) (defalias nfunc (cdr elem))))) - '((decode-coding-string . (lambda (s a) s)) - (encode-coding-string . (lambda (s a) s)) - (encode-coding-region . ignore) - (coding-system-list . ignore) - (decode-coding-region . ignore) + '((coding-system-list . ignore) (char-int . identity) (coding-system-equal . equal) (annotationp . ignore) @@ -97,6 +93,34 @@ (multibyte-char-to-unibyte . identity)))) (eval-and-compile + (if (featurep 'xemacs) + (if (featurep 'file-coding) + ;; Don't modify string if CODING-SYSTEM is nil. + (progn + (defun mm-decode-coding-string (str coding-system) + (if coding-system + (decode-coding-string str coding-system) + str)) + (defun mm-encode-coding-string (str coding-system) + (if coding-system + (encode-coding-string str coding-system) + str)) + (defun mm-decode-coding-region (start end coding-system) + (if coding-system + (decode-coding-region start end coding-system))) + (defun mm-encode-coding-region (start end coding-system) + (if coding-system + (encode-coding-region start end coding-system)))) + (defun mm-decode-coding-string (str coding-system) str) + (defun mm-encode-coding-string (str coding-system) str) + (defalias 'mm-decode-coding-region 'ignore) + (defalias 'mm-encode-coding-region 'ignore)) + (defalias 'mm-decode-coding-string 'decode-coding-string) + (defalias 'mm-encode-coding-string 'encode-coding-string) + (defalias 'mm-decode-coding-region 'decode-coding-region) + (defalias 'mm-encode-coding-region 'encode-coding-region))) + +(eval-and-compile (cond ((fboundp 'replace-in-string) (defalias 'mm-replace-in-string 'replace-in-string)) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/gnus/nnrss.el --- a/lisp/gnus/nnrss.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/gnus/nnrss.el Sun Jul 15 02:05:20 2007 +0000 @@ -85,7 +85,12 @@ (defvar nnrss-file-coding-system mm-universal-coding-system "Coding system used when reading and writing files.") -(defvar nnrss-compatible-encoding-alist '((iso-8859-1 . windows-1252)) +(defvar nnrss-compatible-encoding-alist + (delq nil (mapcar (lambda (elem) + (if (and (mm-coding-system-p (car elem)) + (mm-coding-system-p (cdr elem))) + elem)) + mm-charset-override-alist)) "Alist of encodings and those supersets. The cdr of each element is used to decode data if it is available when the car is what the data specify as the encoding. Or, the car is used diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/gnus/rfc2047.el --- a/lisp/gnus/rfc2047.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/gnus/rfc2047.el Sun Jul 15 02:05:20 2007 +0000 @@ -55,7 +55,7 @@ (require 'ietf-drums) ;; Fixme: Avoid this (used for mail-parse-charset) mm dependence on gnus. (require 'mail-prsvr) -(require 'base64) +(require 'rfc2045) ;; rfc2045-encode-string (autoload 'mm-body-7-or-8 "mm-bodies") (eval-and-compile @@ -832,12 +832,9 @@ \(defalias 'mail-header-encode-parameter 'rfc2047-encode-parameter) " - (let* ((rfc2047-encoding-type 'mime) - (rfc2047-encode-max-chars nil) - (string (rfc2047-encode-string value))) - (if (string-match (concat "[" ietf-drums-tspecials "]") string) - (format "%s=%S" param string) - (concat param "=" string)))) + (let ((rfc2047-encoding-type 'mime) + (rfc2047-encode-max-chars nil)) + (rfc2045-encode-string param (rfc2047-encode-string value)))) ;;; ;;; Functions for decoding RFC2047 messages diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/help-mode.el --- a/lisp/help-mode.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/help-mode.el Sun Jul 15 02:05:20 2007 +0000 @@ -487,7 +487,7 @@ ;; Skip a single blank line. (and (eolp) (forward-line)) (end-of-line) - (skip-chars-backward "^\t\n") + (skip-chars-backward "^ \t\n") (if (and (>= (current-column) col) (looking-at "\\(\\sw\\|-\\)+$")) (let ((sym (intern-soft (match-string 0)))) @@ -500,16 +500,19 @@ (while (and (not (bobp)) (bolp)) (delete-char -1)) (insert "\n") + (when (or help-xref-stack help-xref-forward-stack) + (insert "\n")) ;; Make a back-reference in this buffer if appropriate. (when help-xref-stack - (insert "\n") (help-insert-xref-button help-back-label 'help-back - (current-buffer)) - (insert "\t")) + (current-buffer))) ;; Make a forward-reference in this buffer if appropriate. (when help-xref-forward-stack + (when help-xref-stack + (insert "\t")) (help-insert-xref-button help-forward-label 'help-forward - (current-buffer)) + (current-buffer))) + (when (or help-xref-stack help-xref-forward-stack) (insert "\n"))) ;; View mode steals RET from us. (set (make-local-variable 'minor-mode-overriding-map-alist) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/ido.el --- a/lisp/ido.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/ido.el Sun Jul 15 02:05:20 2007 +0000 @@ -3994,8 +3994,7 @@ (defun ido-find-file-in-dir (dir) "Switch to another file starting from DIR." (interactive "DDir: ") - (if (not (equal (substring dir -1) "/")) - (setq dir (concat dir "/"))) + (setq dir (file-name-as-directory dir)) (ido-file-internal ido-default-file-method nil dir nil nil nil 'ignore)) ;;;###autoload diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/isearch.el --- a/lisp/isearch.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/isearch.el Sun Jul 15 02:05:20 2007 +0000 @@ -1069,6 +1069,7 @@ ;; Reinvoke the pending search. (isearch-search) + (isearch-push-state) (isearch-update) (if isearch-nonincremental (progn diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/log-edit.el --- a/lisp/log-edit.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/log-edit.el Sun Jul 15 02:05:20 2007 +0000 @@ -590,25 +590,23 @@ (LOGBUFFER (ENTRYSTART . ENTRYEND) ...) where LOGBUFFER is the name of the ChangeLog buffer, and each \(ENTRYSTART . ENTRYEND\) pair is a buffer region." - (save-excursion - (let ((changelog-file-name - (let ((default-directory - (file-name-directory (expand-file-name file))) - (visiting-buffer (find-buffer-visiting file))) - ;; If there is a buffer visiting FILE, and it has a local - ;; value for `change-log-default-name', use that. - (if (and visiting-buffer - (local-variable-p 'change-log-default-name - visiting-buffer)) - (save-excursion - (set-buffer visiting-buffer) - change-log-default-name) - ;; `find-change-log' uses `change-log-default-name' if set - ;; and sets it before exiting, so we need to work around - ;; that memoizing which is undesired here - (setq change-log-default-name nil) - (find-change-log))))) - (set-buffer (find-file-noselect changelog-file-name)) + (let ((changelog-file-name + (let ((default-directory + (file-name-directory (expand-file-name file))) + (visiting-buffer (find-buffer-visiting file))) + ;; If there is a buffer visiting FILE, and it has a local + ;; value for `change-log-default-name', use that. + (if (and visiting-buffer + (local-variable-p 'change-log-default-name + visiting-buffer)) + (with-current-buffer visiting-buffer + change-log-default-name) + ;; `find-change-log' uses `change-log-default-name' if set + ;; and sets it before exiting, so we need to work around + ;; that memoizing which is undesired here + (setq change-log-default-name nil) + (find-change-log))))) + (with-current-buffer (find-file-noselect changelog-file-name) (unless (eq major-mode 'change-log-mode) (change-log-mode)) (goto-char (point-min)) (if (looking-at "\\s-*\n") (goto-char (match-end 0))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/log-view.el --- a/lisp/log-view.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/log-view.el Sun Jul 15 02:05:20 2007 +0000 @@ -105,6 +105,20 @@ ;; or a minor-mode-map with lower precedence than the local map. :inherit (if (boundp 'cvs-mode-map) cvs-mode-map)) +(easy-menu-define log-view-mode-menu log-view-mode-map + "Log-View Display Menu" + `("Log-View" + ;; XXX Do we need menu entries for these? + ;; ["Quit" quit-window] + ;; ["Kill This Buffer" kill-this-buffer] + ["Mark Log Entry for Diff" set-mark-command] + ["Diff Revisions" log-view-diff] + ["Visit Version" log-view-find-version] + ["Next Log Entry" log-view-msg-next] + ["Previous Log Entry" log-view-msg-prev] + ["Next File" log-view-file-next] + ["Previous File" log-view-file-prev])) + (defvar log-view-mode-hook nil "Hook run at the end of `log-view-mode'.") @@ -128,13 +142,15 @@ (put 'log-view-message-face 'face-alias 'log-view-message) (defvar log-view-message-face 'log-view-message) -(defconst log-view-file-re +(defvar log-view-file-re (concat "^\\(?:Working file: \\(?1:.+\\)" ;RCS and CVS. ;; Subversion has no such thing?? "\\|\\(?:SCCS/s\\.\\|Changes to \\)\\(?1:.+\\):" ;SCCS and Darcs. - "\\)\n")) ;Include the \n for font-lock reasons. + "\\)\n") ;Include the \n for font-lock reasons. + "Regexp matching the text identifying the file. +The match group number 1 should match the file name itself.") -(defconst log-view-message-re +(defvar log-view-message-re (concat "^\\(?:revision \\(?1:[.0-9]+\\)\\(?:\t.*\\)?" ; RCS and CVS. "\\|r\\(?1:[0-9]+\\) | .* | .*" ; Subversion. "\\|D \\(?1:[.0-9]+\\) .*" ; SCCS. @@ -147,13 +163,17 @@ (concat "\\|[^ \n].*[^0-9\n][0-9][0-9]:[0-9][0-9][^0-9\n].*[^ \n]" ;;Email of user and finally Msg, used as revision name. " .*@.*\n\\(?: \\* \\(?1:.*\\)\\)?") - "\\)$")) + "\\)$") + "Regexp matching the text identifying a revision. +The match group number 1 should match the revision number itself.") -(defconst log-view-font-lock-keywords - `((,log-view-file-re - (1 (if (boundp 'cvs-filename-face) cvs-filename-face)) - (0 log-view-file-face append)) - (,log-view-message-re . log-view-message-face))) +(defvar log-view-font-lock-keywords + ;; We use `eval' so as to use the buffer-local value of log-view-file-re + ;; and log-view-message-re, if applicable. + '((eval . `(,log-view-file-re + (1 (if (boundp 'cvs-filename-face) cvs-filename-face)) + (0 log-view-file-face append))) + (eval . `(,log-view-message-re . log-view-message-face)))) (defconst log-view-font-lock-defaults '(log-view-font-lock-keywords t nil nil nil)) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/longlines.el --- a/lisp/longlines.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/longlines.el Sun Jul 15 02:05:20 2007 +0000 @@ -223,16 +223,18 @@ "Wrap each successive line, starting with the line before BEG. Stop when we reach lines after END that don't need wrapping, or the end of the buffer." - (setq longlines-wrap-point (point)) - (goto-char beg) - (forward-line -1) - ;; Two successful longlines-wrap-line's in a row mean successive - ;; lines don't need wrapping. - (while (null (and (longlines-wrap-line) - (or (eobp) - (and (>= (point) end) - (longlines-wrap-line)))))) - (goto-char longlines-wrap-point)) + (let ((mod (buffer-modified-p))) + (setq longlines-wrap-point (point)) + (goto-char beg) + (forward-line -1) + ;; Two successful longlines-wrap-line's in a row mean successive + ;; lines don't need wrapping. + (while (null (and (longlines-wrap-line) + (or (eobp) + (and (>= (point) end) + (longlines-wrap-line)))))) + (goto-char longlines-wrap-point) + (set-buffer-modified-p mod))) (defun longlines-wrap-line () "If the current line needs to be wrapped, wrap it and return nil. @@ -372,10 +374,9 @@ (> (prefix-numeric-value arg) 0) (not longlines-auto-wrap))) (if arg - (let ((mod (buffer-modified-p))) + (progn (setq longlines-auto-wrap t) (longlines-wrap-region (point-min) (point-max)) - (set-buffer-modified-p mod) (message "Auto wrap enabled.")) (setq longlines-auto-wrap nil) (message "Auto wrap disabled."))) @@ -410,9 +411,7 @@ This is called by `window-configuration-change-hook'." (when (/= fill-column (- (window-width) window-min-width)) (setq fill-column (- (window-width) window-min-width)) - (let ((mod (buffer-modified-p))) - (longlines-wrap-region (point-min) (point-max)) - (set-buffer-modified-p mod)))) + (longlines-wrap-region (point-min) (point-max)))) ;; Isearch diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/lpr.el --- a/lisp/lpr.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/lpr.el Sun Jul 15 02:05:20 2007 +0000 @@ -140,9 +140,10 @@ ;; Berkeley systems support -F, and GNU pr supports both -f and -F, ;; So it looks like -F is a better default. -(defcustom lpr-page-header-switches '("-h %s" "-F") +(defcustom lpr-page-header-switches '("-h" "%s" "-F") "*List of strings to use as options for the page-header-generating program. -If `%s' appears in one of the strings, it is substituted by the page title. +If `%s' appears in any of the strings, it is substituted by the page title. +Note that for correct quoting, `%s' should normally be a separate element. The variable `lpr-page-header-program' specifies the program to use." :type '(repeat string) :group 'lpr) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/ls-lisp.el --- a/lisp/ls-lisp.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/ls-lisp.el Sun Jul 15 02:05:20 2007 +0000 @@ -216,6 +216,7 @@ ;; We need the directory in order to find the right handler. (let ((handler (find-file-name-handler (expand-file-name file) 'insert-directory)) + (orig-file file) wildcard-regexp) (if handler (funcall handler 'insert-directory file switches @@ -229,7 +230,10 @@ ;; `ls' don't mind, we certainly do, because it makes us think ;; there is no wildcard, only a directory name. (if (and ls-lisp-support-shell-wildcards - (string-match "[[?*]" file)) + (string-match "[[?*]" file) + ;; Prefer an existing file to wildcards, like + ;; dired-noselect does. + (not (file-exists-p file))) (progn (or (not (eq (aref file (1- (length file))) ?/)) (setq file (substring file 0 (1- (length file))))) @@ -241,9 +245,21 @@ (file-name-nondirectory file)) file (file-name-directory file)) (if (memq ?B switches) (setq wildcard-regexp "[^~]\\'"))) - (ls-lisp-insert-directory - file switches (ls-lisp-time-index switches) - wildcard-regexp full-directory-p) + (condition-case err + (ls-lisp-insert-directory + file switches (ls-lisp-time-index switches) + wildcard-regexp full-directory-p) + (invalid-regexp + ;; Maybe they wanted a literal file that just happens to + ;; use characters special to shell wildcards. + (if (equal (cadr err) "Unmatched [ or [^") + (progn + (setq wildcard-regexp (if (memq ?B switches) "[^~]\\'") + file (file-relative-name orig-file)) + (ls-lisp-insert-directory + file switches (ls-lisp-time-index switches) + nil full-directory-p)) + (signal (car err) (cdr err))))) ;; Try to insert the amount of free space. (save-excursion (goto-char (point-min)) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/makefile.w32-in --- a/lisp/makefile.w32-in Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/makefile.w32-in Sun Jul 15 02:05:20 2007 +0000 @@ -408,7 +408,7 @@ - $(DEL) "$(INSTALL_DIR)/same-dir.tst" echo SameDirTest > "$(INSTALL_DIR)/same-dir.tst" #ifdef COPY_LISP_SOURCE - $(IFNOTSAMEDIR) $(CP_DIR) . "$(INSTALL_DIR)/lisp" $(ENDIF) + $(IFNOTSAMEDIR) $(MAKE) $(MFLAGS) install-lisp-$(SHELLTYPE) $(ENDIF) #else # $(IFNOTSAMEDIR) $(CP_DIR) *.elc "$(INSTALL_DIR)/lisp" $(ENDIF) # $(IFNOTSAMEDIR) $(CP) cus-load.el "$(INSTALL_DIR)/lisp" $(ENDIF) @@ -425,6 +425,19 @@ - $(DEL) ../same-dir.tst - $(DEL) "$(INSTALL_DIR)/same-dir.tst" +# Need to copy *.el files first, to avoid "source file is newer" annoyance +# since cp does not preserve time stamps +install-lisp-SH: + cp -f *.el "$(INSTALL_DIR)/lisp" + for dir in $(WINS); do mkdir "$(INSTALL_DIR)/lisp/$$dir" && cp -f $$dir/*.el "$(INSTALL_DIR)/lisp/$$dir"; done + for dir in . $(WINS); do cp $$dir/*.elc "$(INSTALL_DIR)/lisp/$$dir"; done + +install-lisp-CMD: + cp -f *.el "$(INSTALL_DIR)/lisp" + for %%f in ($(WINS)) do mkdir "$(INSTALL_DIR)/lisp/%%f" + for %%f in ($(WINS)) do cp -f %%f/*.el "$(INSTALL_DIR)/lisp/%%f" + for %%f in (. $(WINS)) do cp -f %%f/*.elc "$(INSTALL_DIR)/lisp/%%f" + # # Maintenance # diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/menu-bar.el --- a/lisp/menu-bar.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/menu-bar.el Sun Jul 15 02:05:20 2007 +0000 @@ -1161,6 +1161,7 @@ '("--")) (defvar vc-menu-map (make-sparse-keymap "Version Control")) +(defalias 'vc-menu-map vc-menu-map) (define-key menu-bar-tools-menu [pcl-cvs] '(menu-item "PCL-CVS" cvs-global-menu)) (define-key menu-bar-tools-menu [vc] diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/mh-e/ChangeLog --- a/lisp/mh-e/ChangeLog Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/mh-e/ChangeLog Sun Jul 15 02:05:20 2007 +0000 @@ -1,3 +1,8 @@ +2007-07-11 Bill Wohler + + * mh-compat.el (mh-display-color-cells): Fix on XEmacs 21.5b28. + Thanks to Henrique Martins for the help (closes SF #1749774). + 2007-06-06 Juanma Barranquero * mh-mime.el (mh-mh-directive-present-p): diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/mh-e/mh-compat.el --- a/lisp/mh-e/mh-compat.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/mh-e/mh-compat.el Sun Jul 15 02:05:20 2007 +0000 @@ -77,13 +77,17 @@ 'cancel-timer 'delete-itimer)) -(defun-mh mh-display-color-cells display-color-cells (&optional display) +(defun mh-display-color-cells (&optional display) "Return the number of color cells supported by DISPLAY. -This function is used by XEmacs to return 2 when -`device-color-cells' returns nil. This happens when compiling or +This function is used by XEmacs to return 2 when `device-color-cells' +or `display-color-cells' returns nil. This happens when compiling or running on a tty and causes errors since `display-color-cells' is expected to return an integer." - (or (device-color-cells display) 2)) + (cond ((fboundp 'display-color-cells) ; GNU Emacs, XEmacs 21.5b28 + (or (display-color-cells display) 2)) + ((fboundp 'device-color-cells) ; XEmacs 21.4 + (or (device-color-cells display) 2)) + (t 2))) (defmacro mh-display-completion-list (completions &optional common-substring) "Display the list of COMPLETIONS. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/mouse.el --- a/lisp/mouse.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/mouse.el Sun Jul 15 02:05:20 2007 +0000 @@ -433,9 +433,8 @@ ;; - there is a scroll-bar-movement event ;; (same as mouse movement for our purposes) ;; quit if - ;; - there is a keyboard event or some other unknown event - ;; unknown event. - (cond ((integerp event) + ;; - there is a keyboard event or some other unknown event. + (cond ((not (consp event)) (setq done t)) ((memq (car event) '(switch-frame select-window)) @@ -443,7 +442,11 @@ ((not (memq (car event) '(mouse-movement scroll-bar-movement))) (when (consp event) - (push event unread-command-events)) + ;; Do not unread a drag-mouse-1 event since it will cause the + ;; selection of the window above when dragging the modeline + ;; above the selected window. + (unless (eq (car event) 'drag-mouse-1) + (push event unread-command-events))) (setq done t)) ((not (eq (car mouse) start-event-frame)) @@ -498,7 +501,10 @@ (and (not should-enlarge-minibuffer) (> growth 0) mode-line-p - (/= top (nth 1 (window-edges))))) + (/= top + (nth 1 (window-edges + ;; Choose right window. + start-event-window))))) (set-window-configuration wconfig))))))))) (defun mouse-drag-mode-line (start-event) @@ -1007,6 +1013,11 @@ (overlay-start mouse-drag-overlay)) region-termination)) last-command this-command) + (when (eq transient-mark-mode 'identity) + ;; Reset `transient-mark-mode' to avoid expanding the region + ;; while scrolling (compare thread on "Erroneous selection + ;; extension ..." on bug-gnu-emacs from 2007-06-10). + (setq transient-mark-mode nil)) (push-mark region-commencement t t) (goto-char region-termination) (if (not do-mouse-drag-region-post-process) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/ange-ftp.el --- a/lisp/net/ange-ftp.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/net/ange-ftp.el Sun Jul 15 02:05:20 2007 +0000 @@ -4132,8 +4132,15 @@ (format "Getting %s" fn1)) tmp1)))) -(defun ange-ftp-file-remote-p (file) - (ange-ftp-replace-name-component file "")) +(defun ange-ftp-file-remote-p (file &optional connected) + (and (or (not connected) + (let* ((parsed (ange-ftp-ftp-name file)) + (host (nth 0 parsed)) + (user (nth 1 parsed)) + (proc (get-process (ange-ftp-ftp-process-buffer host user)))) + (and proc (processp proc) + (memq (process-status proc) '(run open))))) + (ange-ftp-replace-name-component file ""))) (defun ange-ftp-load (file &optional noerror nomessage nosuffix) (if (ange-ftp-ftp-name file) @@ -4360,7 +4367,10 @@ ;; This returns nil for any file name as argument. (put 'vc-registered 'ange-ftp 'null) -(put 'dired-call-process 'ange-ftp 'ange-ftp-dired-call-process) +;; We can handle process-file in a restricted way (just for chown). +;; Nothing possible for start-file-process. +(put 'process-file 'ange-ftp 'ange-ftp-process-file) +(put 'start-file-process 'ange-ftp 'ignore) (put 'shell-command 'ange-ftp 'ange-ftp-shell-command) ;;; Define ways of getting at unmodified Emacs primitives, @@ -4523,8 +4533,8 @@ ;; default-directory is in ange-ftp syntax for remote file names. (ange-ftp-real-shell-command command output-buffer error-buffer)))) -;;; This is the handler for call-process. -(defun ange-ftp-dired-call-process (program discard &rest arguments) +;;; This is the handler for process-file. +(defun ange-ftp-process-file (program infile buffer display &rest arguments) ;; PROGRAM is always one of those below in the cond in dired.el. ;; The ARGUMENTS are (nearly) always files. (if (ange-ftp-ftp-name default-directory) @@ -4544,7 +4554,7 @@ 1) (error (insert (format "%s\n" (nth 1 oops))) 1)) - (apply 'call-process program nil (not discard) nil arguments))) + (apply 'call-process program infile buffer display arguments))) ;; Handle an attempt to run chmod on a remote file ;; by using the ftp chmod command. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/rcirc.el --- a/lisp/net/rcirc.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/net/rcirc.el Sun Jul 15 02:05:20 2007 +0000 @@ -55,7 +55,7 @@ :link '(custom-manual "(rcirc)") :group 'applications) -(defcustom rcirc-connections +(defcustom rcirc-server-alist '(("irc.freenode.net" :channels ("#rcirc"))) "An alist of IRC connections to establish when running `rcirc'. Each element looks like (SERVER-NAME PARAMETERS). @@ -63,11 +63,36 @@ SERVER-NAME is a string describing the server to connect to. -PARAMETERS is a plist of optional connection parameters. Valid -properties are: nick (a string), port (number or string), -user-name (string), full-name (string), and channels (list of -strings)." - :type '(alist :key-type string +The optional PARAMETERS come in pairs PARAMETER VALUE. + +The following parameters are recognized: + +`:nick' + +VALUE must be a string. If absent, `rcirc-default-nick' is used +for this connection. + +`:port' + +VALUE must be a number or string. If absent, +`rcirc-default-port' is used. + +`:user-name' + +VALUE must be a string. If absent, `rcirc-default-user-name' is +used. + +`:full-name' + +VALUE must be a string. If absent, `rcirc-default-full-name' is +used. + +`:channels' + +VALUE must be a list of strings describing which channels to join +when connecting to this server. If absent, no channels will be +connected to automatically." + :type '(alist :key-type string :value-type (plist :options ((nick string) (port integer) (user-name string) @@ -90,9 +115,9 @@ :type 'string :group 'rcirc) -(defcustom rcirc-default-user-full-name (if (string= (user-full-name) "") - rcirc-default-user-name - (user-full-name)) +(defcustom rcirc-default-full-name (if (string= (user-full-name) "") + rcirc-default-user-name + (user-full-name)) "The full name sent to the server when connecting." :type 'string :group 'rcirc) @@ -335,19 +360,19 @@ ;;;###autoload (defun rcirc (arg) - "Connect to all servers in `rcirc-connections'. + "Connect to all servers in `rcirc-server-alist'. Do not connect to a server if it is already connected. If ARG is non-nil, instead prompt for connection parameters." (interactive "P") (if arg - (let* ((server (completing-read "IRC Server: " - rcirc-connections + (let* ((server (completing-read "IRC Server: " + rcirc-server-alist nil nil - (caar rcirc-connections))) - (server-plist (cdr (assoc-string server rcirc-connections))) - (port (read-string "IRC Port: " + (caar rcirc-server-alist))) + (server-plist (cdr (assoc-string server rcirc-server-alist))) + (port (read-string "IRC Port: " (number-to-string (or (plist-get server-plist 'port) rcirc-default-port)))) @@ -356,25 +381,25 @@ rcirc-default-nick))) (channels (split-string (read-string "IRC Channels: " - (mapconcat 'identity + (mapconcat 'identity (plist-get server-plist 'channels) " ")) "[, ]+" t))) (rcirc-connect server port nick rcirc-default-user-name - rcirc-default-user-full-name + rcirc-default-full-name channels)) - ;; connect to servers in `rcirc-connections' + ;; connect to servers in `rcirc-server-alist' (let (connected-servers) - (dolist (c rcirc-connections) + (dolist (c rcirc-server-alist) (let ((server (car c)) - (port (or (plist-get (cdr c) 'port) rcirc-default-port)) - (nick (or (plist-get (cdr c) 'nick) rcirc-default-nick)) - (user-name (or (plist-get (cdr c) 'user-name) + (nick (or (plist-get (cdr c) :nick) rcirc-default-nick)) + (port (or (plist-get (cdr c) :port) rcirc-default-port)) + (user-name (or (plist-get (cdr c) :user-name) rcirc-default-user-name)) - (full-name (or (plist-get (cdr c) 'full-name) - rcirc-default-user-full-name)) - (channels (plist-get (cdr c) 'channels))) + (full-name (or (plist-get (cdr c) :full-name) + rcirc-default-full-name)) + (channels (plist-get (cdr c) :channels))) (when server (let (connected) (dolist (p (rcirc-process-list)) @@ -382,9 +407,9 @@ (setq connected p))) (if (not connected) (condition-case e - (rcirc-connect server port nick user-name + (rcirc-connect server port nick user-name full-name channels) - (quit (message "Quit connecting to %s" server))) + (quit (message "Quit connecting to %s" server))) (with-current-buffer (process-buffer connected) (setq connected-servers (cons (process-contact (get-buffer-process @@ -411,7 +436,7 @@ (defvar rcirc-process nil) ;;;###autoload -(defun rcirc-connect (server &optional port nick user-name full-name +(defun rcirc-connect (server &optional port nick user-name full-name startup-channels) (save-excursion (message "Connecting to %s..." server) @@ -423,7 +448,7 @@ rcirc-default-port)) (nick (or nick rcirc-default-nick)) (user-name (or user-name rcirc-default-user-name)) - (full-name (or full-name rcirc-default-user-full-name)) + (full-name (or full-name rcirc-default-full-name)) (startup-channels startup-channels) (process (make-network-process :name server :host server :service port-number))) ;; set up process @@ -494,7 +519,7 @@ (mapc (lambda (process) (with-rcirc-process-buffer process (when (not rcirc-connecting) - (rcirc-send-string process + (rcirc-send-string process (format "PRIVMSG %s :\C-aKEEPALIVE %f\C-a" rcirc-nick (time-to-seconds @@ -550,7 +575,7 @@ ;; set rcirc-target to nil for each channel so cleanup ;; doesnt happen when we reconnect (setq rcirc-target nil) - (setq mode-line-process ":disconnected"))) + (setq mode-line-process ":disconnected"))) (defun rcirc-process-list () "Return a list of rcirc processes." @@ -590,7 +615,6 @@ process)))))) (defun rcirc-delete-process (process) - (message "delete process %S" process) (delete-process process)) (defvar rcirc-trap-errors-flag t) @@ -1162,7 +1186,7 @@ :value-type string) :group 'rcirc) -(defcustom rcirc-omit-responses +(defcustom rcirc-omit-responses '("JOIN" "PART" "QUIT") "Responses which will be hidden when `rcirc-omit-mode' is enabled." :type '(repeat string) @@ -1202,7 +1226,7 @@ (cond ((string= sender my-nick) 'rcirc-my-nick) ((and rcirc-bright-nicks - (string-match + (string-match (regexp-opt rcirc-bright-nicks 'words) sender)) @@ -1262,11 +1286,12 @@ Format based on SENDER and RESPONSE. If ACTIVITY is non-nil, record activity." (or text (setq text "")) - (unless (or (member sender rcirc-ignore-list) - (member (with-syntax-table rcirc-nick-syntax-table - (when (string-match "^\\([^/]\\w*\\)[:,]" text) - (match-string 1 text))) - rcirc-ignore-list)) + (unless (and (or (member sender rcirc-ignore-list) + (member (with-syntax-table rcirc-nick-syntax-table + (when (string-match "^\\([^/]\\w*\\)[:,]" text) + (match-string 1 text))) + rcirc-ignore-list)) + (not (string= sender (rcirc-nick process)))) (let* ((buffer (rcirc-target-buffer process sender response target text)) (inhibit-read-only t)) (with-current-buffer buffer @@ -1291,12 +1316,12 @@ (set-marker-insertion-type rcirc-prompt-end-marker t) (let ((start (point))) - (insert (rcirc-format-response-string process sender response nil + (insert (rcirc-format-response-string process sender response nil text) (propertize "\n" 'hard t)) ;; squeeze spaces out of text before rcirc-text - (fill-region fill-start + (fill-region fill-start (1- (or (next-single-property-change fill-start 'rcirc-text) rcirc-prompt-end-marker))) @@ -1549,7 +1574,7 @@ (defun rcirc-omit-mode () "Toggle the Rcirc-Omit mode. -If enabled, \"uninteresting\" lines are not shown. +If enabled, \"uninteresting\" lines are not shown. Uninteresting lines are those whose responses are listed in `rcirc-omit-responses'." (interactive) @@ -1635,7 +1660,7 @@ (defun rcirc-clear-activity (buffer) "Clear the BUFFER activity." - (setq rcirc-activity (delete buffer rcirc-activity)) + (setq rcirc-activity (remove buffer rcirc-activity)) (with-current-buffer buffer (setq rcirc-activity-types nil))) @@ -2065,7 +2090,7 @@ rcirc-markup-keywords rcirc-markup-bright-nicks rcirc-markup-fill) - + "List of functions used to manipulate text before it is printed. Each function takes two arguments, SENDER, RESPONSE. The buffer @@ -2074,7 +2099,7 @@ (defun rcirc-markup-timestamp (sender response) (goto-char (point-min)) - (insert (rcirc-facify (format-time-string rcirc-time-format) + (insert (rcirc-facify (format-time-string rcirc-time-format) 'rcirc-timestamp))) (defun rcirc-markup-attributes (sender response) @@ -2095,15 +2120,15 @@ (defun rcirc-markup-my-nick (sender response) (with-syntax-table rcirc-nick-syntax-table - (while (re-search-forward (concat "\\b" - (regexp-quote (rcirc-nick + (while (re-search-forward (concat "\\b" + (regexp-quote (rcirc-nick (rcirc-buffer-process))) "\\b") nil t) (rcirc-add-face (match-beginning 0) (match-end 0) 'rcirc-nick-in-message) (when (string= response "PRIVMSG") - (rcirc-add-face (point-min) (point-max) + (rcirc-add-face (point-min) (point-max) 'rcirc-nick-in-message-full-line) (rcirc-record-activity (current-buffer) 'nick))))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/rcompile.el --- a/lisp/net/rcompile.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/net/rcompile.el Sun Jul 15 02:05:20 2007 +0000 @@ -188,8 +188,7 @@ (when (featurep 'tramp) (set (make-local-variable 'comint-file-name-prefix) (funcall (symbol-function 'tramp-make-tramp-file-name) - nil ;; multi-method. To be removed with Tramp 2.1. - nil + nil ;; method. remote-compile-user remote-compile-host "")))))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/tramp-cache.el --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/net/tramp-cache.el Sun Jul 15 02:05:20 2007 +0000 @@ -0,0 +1,317 @@ +;;; -*- mode: Emacs-Lisp; coding: iso-2022-7bit; -*- +;;; tramp-cache.el --- file information caching for Tramp + +;; Copyright (C) 2000, 2005, 2006, 2007 by Free Software Foundation, Inc. + +;; Author: Daniel Pittman +;; Michael Albinus +;; Keywords: comm, processes + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, see +;; . + +;;; Commentary: + +;; An implementation of information caching for remote files. + +;; Each connection, identified by a vector [method user host +;; localname] or by a process, has a unique cache. We distinguish 3 +;; kind of caches, depending on the key: +;; +;; - localname is NIL. This are reusable properties. Examples: +;; "remote-shell" identifies the POSIX shell to be called on the +;; remote host, or "perl" is the command to be called on the remote +;; host, when starting a Perl script. These properties are saved in +;; the file `tramp-persistency-file-name'. +;; +;; - localname is a string. This are temporary properties, which are +;; related to the file localname is referring to. Examples: +;; "file-exists-p" is t or nile, depending on the file existence, or +;; "file-attributes" caches the result of the function +;; `file-attributes'. +;; +;; - The key is a process. This are temporary properties related to +;; an open connection. Examples: "scripts" keeps shell script +;; definitions already sent to the remote shell, "last-cmd-time" is +;; the time stamp a command has been sent to the remote process. + +;;; Code: + +;; Pacify byte-compiler. +(eval-when-compile + (require 'cl) + (autoload 'tramp-message "tramp") + (autoload 'tramp-tramp-file-p "tramp") + ;; We cannot autoload macro `with-parsed-tramp-file-name', it + ;; results in problems of byte-compiled code. + (autoload 'tramp-dissect-file-name "tramp") + (autoload 'tramp-file-name-method "tramp") + (autoload 'tramp-file-name-user "tramp") + (autoload 'tramp-file-name-host "tramp") + (autoload 'tramp-file-name-localname "tramp") + (autoload 'time-stamp-string "time-stamp")) + +;;; -- Cache -- + +(defvar tramp-cache-data (make-hash-table :test 'equal) + "Hash table for remote files properties.") + +(defcustom tramp-persistency-file-name + (cond + ;; GNU Emacs. + ((and (boundp 'user-emacs-directory) + (stringp (symbol-value 'user-emacs-directory)) + (file-directory-p (symbol-value 'user-emacs-directory))) + (expand-file-name "tramp" (symbol-value 'user-emacs-directory))) + ((and (not (featurep 'xemacs)) (file-directory-p "~/.emacs.d/")) + "~/.emacs.d/tramp") + ;; XEmacs. + ((and (boundp 'user-init-directory) + (stringp (symbol-value 'user-init-directory)) + (file-directory-p (symbol-value 'user-init-directory))) + (expand-file-name "tramp" (symbol-value 'user-init-directory))) + ((and (featurep 'xemacs) (file-directory-p "~/.xemacs/")) + "~/.xemacs/tramp") + ;; For users without `~/.emacs.d/' or `~/.xemacs/'. + (t "~/.tramp")) + "File which keeps connection history for Tramp connections." + :group 'tramp + :type 'file) + +(defun tramp-get-file-property (vec file property default) + "Get the PROPERTY of FILE from the cache context of VEC. +Returns DEFAULT if not set." + ;; Unify localname. + (setq vec (copy-sequence vec)) + (aset vec 3 (directory-file-name file)) + (let* ((hash (or (gethash vec tramp-cache-data) + (puthash vec (make-hash-table :test 'equal) + tramp-cache-data))) + (value (if (hash-table-p hash) + (gethash property hash default) + default))) + (tramp-message vec 8 "%s %s %s" file property value) + value)) + +(defun tramp-set-file-property (vec file property value) + "Set the PROPERTY of FILE to VALUE, in the cache context of VEC. +Returns VALUE." + ;; Unify localname. + (setq vec (copy-sequence vec)) + (aset vec 3 (directory-file-name file)) + (let ((hash (or (gethash vec tramp-cache-data) + (puthash vec (make-hash-table :test 'equal) + tramp-cache-data)))) + (puthash property value hash) + (tramp-message vec 8 "%s %s %s" file property value) + value)) + +(defun tramp-flush-file-property (vec file) + "Remove all properties of FILE in the cache context of VEC." + ;; Unify localname. + (setq vec (copy-sequence vec)) + (aset vec 3 (directory-file-name file)) + (tramp-message vec 8 "%s" file) + (remhash vec tramp-cache-data)) + +(defun tramp-flush-directory-property (vec directory) + "Remove all properties of DIRECTORY in the cache context of VEC. +Remove also properties of all files in subdirectories." + (let ((directory (directory-file-name directory))) + (tramp-message vec 8 "%s" directory) + (maphash + '(lambda (key value) + (when (and (stringp key) + (string-match directory (tramp-file-name-localname key))) + (remhash key tramp-cache-data))) + tramp-cache-data))) + +(defun tramp-cache-print (table) + "Prints hash table TABLE." + (when (hash-table-p table) + (let (result tmp) + (maphash + '(lambda (key value) + (setq tmp (format + "(%s %s)" + (if (processp key) + (prin1-to-string (prin1-to-string key)) + (prin1-to-string key)) + (if (hash-table-p value) + (tramp-cache-print value) + (if (bufferp value) + (prin1-to-string (prin1-to-string value)) + (prin1-to-string value)))) + result (if result (concat result " " tmp) tmp))) + table) + result))) + +;; Reverting or killing a buffer should also flush file properties. +;; They could have been changed outside Tramp. +(defun tramp-flush-file-function () + "Flush all Tramp cache properties from buffer-file-name." + (let ((bfn (buffer-file-name))) + (when (and (stringp bfn) (tramp-tramp-file-p bfn)) + (let* ((v (tramp-dissect-file-name bfn)) + (localname (tramp-file-name-localname v))) + (tramp-flush-file-property v localname))))) + +(add-hook 'before-revert-hook 'tramp-flush-file-function) +(add-hook 'kill-buffer-hook 'tramp-flush-file-function) +(add-hook 'tramp-cache-unload-hook + '(lambda () + (remove-hook 'before-revert-hook + 'tramp-flush-file-function) + (remove-hook 'kill-buffer-hook + 'tramp-flush-file-function))) + +;;; -- Properties -- + +(defun tramp-get-connection-property (key property default) + "Get the named PROPERTY for the connection. +KEY identifies the connection, it is either a process or a vector. +If the value is not set for the connection, returns DEFAULT." + ;; Unify key by removing localname from vector. Work with a copy in + ;; order to avoid side effects. + (when (vectorp key) + (setq key (copy-sequence key)) + (aset key 3 nil)) + (let* ((hash (gethash key tramp-cache-data)) + (value (if (hash-table-p hash) + (gethash property hash default) + default))) + (tramp-message key 7 "%s %s" property value) + value)) + +(defun tramp-set-connection-property (key property value) + "Set the named PROPERTY of a connection to VALUE. +KEY identifies the connection, it is either a process or a vector. +PROPERTY is set persistent when KEY is a vector." + ;; Unify key by removing localname from vector. Work with a copy in + ;; order to avoid side effects. + (when (vectorp key) + (setq key (copy-sequence key)) + (aset key 3 nil)) + (let ((hash (or (gethash key tramp-cache-data) + (puthash key (make-hash-table :test 'equal) + tramp-cache-data)))) + (puthash property value hash) + ;; This function is called also during initialization of + ;; tramp-cache.el. `tramp-message´ is not defined yet at this + ;; time, so we ignore the corresponding error. + (condition-case nil + (tramp-message key 7 "%s %s" property value) + (error nil)) + value)) + +(defun tramp-flush-connection-property (key event) + "Remove all properties identified by KEY. +KEY identifies the connection, it is either a process or a +vector. EVENT is not used, it is just applied because this +function is intended to run also as process sentinel." + ;; Unify key by removing localname from vector. Work with a copy in + ;; order to avoid side effects. + (when (vectorp key) + (setq key (copy-sequence key)) + (aset key 3 nil)) +; (tramp-message key 7 "%s" event) + (remhash key tramp-cache-data)) + +(defun tramp-dump-connection-properties () +"Writes persistent connection properties into file +`tramp-persistency-file-name'." + ;; We shouldn't fail, otherwise (X)Emacs might not be able to be closed. + (condition-case nil + (when (and (hash-table-p tramp-cache-data) + (not (zerop (hash-table-count tramp-cache-data))) + (stringp tramp-persistency-file-name)) + (let ((cache (copy-hash-table tramp-cache-data))) + ;; Remove temporary data. + (maphash + '(lambda (key value) + (if (and (vectorp key) (not (tramp-file-name-localname key))) + (progn + (remhash "process-name" value) + (remhash "process-buffer" value)) + (remhash key cache))) + cache) + ;; Dump it. + (with-temp-buffer + (insert + ";; -*- emacs-lisp -*-" + ;; `time-stamp-string' might not exist in all (X)Emacs flavors. + (condition-case nil + (progn + (format + " <%s %s>\n" + (time-stamp-string "%02y/%02m/%02d %02H:%02M:%02S") + tramp-persistency-file-name)) + (error "\n")) + ";; Tramp connection history. Don't change this file.\n" + ";; You can delete it, forcing Tramp to reapply the checks.\n\n" + (with-output-to-string + (pp (read (format "(%s)" (tramp-cache-print cache)))))) + (write-region + (point-min) (point-max) tramp-persistency-file-name)))) + (error nil))) + +(add-hook 'kill-emacs-hook 'tramp-dump-connection-properties) +(add-hook 'tramp-cache-unload-hook + '(lambda () + (remove-hook 'kill-emacs-hook + 'tramp-dump-connection-properties))) + +(defun tramp-parse-connection-properties (method) + "Return a list of (user host) tuples allowed to access for METHOD. +This function is added always in `tramp-get-completion-function' +for all methods. Resulting data are derived from connection +history." + (let (res) + (maphash + '(lambda (key value) + (if (and (vectorp key) + (string-equal method (tramp-file-name-method key)) + (not (tramp-file-name-localname key))) + (push (list (tramp-file-name-user key) + (tramp-file-name-host key)) + res))) + tramp-cache-data) + res)) + +;; Read persistent connection history. Applied with +;; `load-in-progress', because it shall be evaluated only once. +(when load-in-progress + (condition-case err + (with-temp-buffer + (insert-file-contents tramp-persistency-file-name) + (let ((list (read (current-buffer))) + element key item) + (while (setq element (pop list)) + (setq key (pop element)) + (while (setq item (pop element)) + (tramp-set-connection-property key (pop item) (car item)))))) + (file-error + ;; Most likely because the file doesn't exist yet. No message. + (clrhash tramp-cache-data)) + (error + ;; File is corrupted. + (message "%s" (error-message-string err)) + (clrhash tramp-cache-data)))) + +(provide 'tramp-cache) + +;; arch-tag: ee1739b7-7628-408c-9b96-d11a74b05d26 +;;; tramp-cache.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/tramp-fish.el --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/net/tramp-fish.el Sun Jul 15 02:05:20 2007 +0000 @@ -0,0 +1,1178 @@ +;;; -*- coding: iso-8859-1; -*- +;;; tramp-fish.el --- Tramp access functions for FISH protocol + +;; Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +;; Author: Michael Albinus +;; Keywords: comm, processes + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, see +;; . + +;;; Commentary: + +;; Access functions for FIles transferred over SHell protocol from Tramp. + +;; FISH is a protocol developped for the GNU Midnight Commander +;; . A client connects to a +;; remote host via ssh (or rsh, shall be configurable), and starts +;; there a fish server via the command "start_fish_server". All +;; commands from the client have the form "#FISH_COMMAND\n" (always +;; one line), followed by equivalent shell commands in case there is +;; no fish server running. + +;; The fish server (or the equivalent shell commands) must return the +;; response, which is finished by a line "### xxx \n". +;; "xxx" stands for 3 digits, representing a return code. Return +;; codes "# 000" and "# 001" are reserved for fallback implementation +;; with native shell commands; they are not used inside the server. See +;; +;; for details of original specification. + +;; The GNU Midnight Commander implements the original fish protocol +;; version 0.0.2. The KDE Konqueror has its own implementation, which +;; can be found at +;; . It +;; implements an extended protocol version 0.0.3. Additionally, it +;; provides a fish server implementation in Perl (which is the only +;; implementation I've heard of). The following command reference is +;; based on that implementation. + +;; All commands return either "### 2xx\n" (OK) or "### 5xx \n" +;; (NOK). Return codes are mentioned only if they are different from this. +;; Spaces in any parameter must be escaped by "\ ". + +;; Command/Return Code Comment +;; +;; #FISH initial connection, not used +;; in .fishsrv.pl +;; ### 100 transfer fish server missing server, or wrong checksum +;; version 0.0.3 only + +;; #VER a.b.c +;; VER x.y.z .fishsrv.pl response is not uptodate + +;; #PWD +;; /path/to/file + +;; #CWD /some/path + +;; #COPY /path/a /path/b version 0.0.3 only + +;; #RENAME /path/a /path/b + +;; #SYMLINK /path/a /path/b + +;; #LINK /path/a /path/b + +;; #DELE /some/path + +;; #MKD /some/path + +;; #RMD /some/path + +;; #CHOWN user /file/name + +;; #CHGRP group /file/name + +;; #CHMOD 1234 file + +;; #READ /path/and/filename +;; ### 291 successful exit when reading +;; ended at eof +;; ### 292 successful exit when reading +;; did not end at eof + +;; #WRITE /path/and/filename + +;; #APPEND /path/and/filename version 0.0.3 only + +;; #LIST /directory +;; version 0.0.3 only +;; ### 100 version 0.0.3 only +;; P . +;; S +;; d<3-letters month name> +;; D [.1234] +;; E, +;; : +;; L +;; M version 0.0.3 only +;; + +;; #STAT /file version 0.0.3 only +;; like #LIST except for directories +;; +;; ### 100 +;; P . +;; S +;; d<3-letters month name> +;; D [.1234] +;; E, +;; : +;; L +;; + +;; #RETR /some/name +;; +;; ### 100 +;; exactly filesize bytes +;; ### 200 with no preceding newline + +;; #STOR /file/name +;; ### 100 +;; exactly size bytes +;; ### 001 partial success + +;; #EXEC version 0.0.3 only +;; must not exists. It contains the output of . +;; It can be retrieved afterwards. Last line is +;; ###RESULT: + +;; This implementation is meant as proof of the concept, whether there +;; is a better performance compared with the native ssh method. It +;; looks like the file information retrieval is slower, especially the +;; #LIST command. On the other hand, the file contents transmission +;; seems to perform better than other inline methods, because there is +;; no need for data encoding/decoding, and it supports the APPEND +;; parameter of `write-region'. Transfer of binary data fails due to +;; Emacs' process input/output handling. + + +;;; Code: + +(require 'tramp) +(require 'tramp-cache) + +;; Pacify byte-compiler +(eval-when-compile + (require 'cl) + (require 'custom)) + +;; Avoid byte-compiler warnings if the byte-compiler supports this. +;; Currently, XEmacs supports this. +(eval-when-compile + (when (featurep 'xemacs) + (byte-compiler-options (warnings (- unused-vars))))) + +;; `directory-sep-char' is an obsolete variable in Emacs. But it is +;; used in XEmacs, so we set it here and there. The following is needed +;; to pacify Emacs byte-compiler. +(eval-when-compile + (unless (boundp 'byte-compile-not-obsolete-var) + (defvar byte-compile-not-obsolete-var nil)) + (setq byte-compile-not-obsolete-var 'directory-sep-char)) + +;; Define FISH method ... +(defcustom tramp-fish-method "fish" + "*Method to connect via FISH protocol." + :group 'tramp + :type 'string) + +;; ... and add it to the method list. +(add-to-list 'tramp-methods (cons tramp-fish-method nil)) + +;; Add a default for `tramp-default-user-alist'. Default is the local user. +(add-to-list 'tramp-default-user-alist + `(,tramp-fish-method nil ,(user-login-name))) + +;; Add completion function for FISH method. +(tramp-set-completion-function + tramp-fish-method tramp-completion-function-alist-ssh) + +(defconst tramp-fish-continue-prompt-regexp "^### 100.*\n" + "FISH return code OK.") + +;; It cannot be a defconst, occasionally we bind it locally. +(defvar tramp-fish-ok-prompt-regexp "^### 200\n" + "FISH return code OK.") + +(defconst tramp-fish-error-prompt-regexp "^### \\(4\\|5\\)[0-9]+.*\n" + "Regexp for possible error strings of FISH servers. +Used instead of analyzing error codes of commands.") + +(defcustom tramp-fish-start-fish-server-command + (concat "stty intr \"\" quit \"\" erase \"\" kill \"\" eof \"\" eol \"\" eol2 \"\" swtch \"\" start \"\" stop \"\" susp \"\" rprnt \"\" werase \"\" lnext \"\" flush \"\"; " + "perl .fishsrv.pl " + "`grep 'ARGV\\[0\\]' .fishsrv.pl | " + "sed -e 's/^[^\"]*\"//' -e 's/\"[^\"]*$//'`; " + "exit") + "*Command to connect via FISH protocol." + :group 'tramp + :type 'string) + +;; New handlers should be added here. +(defconst tramp-fish-file-name-handler-alist + '( + ;; `access-file' performed by default handler + (add-name-to-file . tramp-fish-handle-add-name-to-file) + ;; `byte-compiler-base-file-name' performed by default handler + (copy-file . tramp-fish-handle-copy-file) + (delete-directory . tramp-fish-handle-delete-directory) + (delete-file . tramp-fish-handle-delete-file) + ;; `diff-latest-backup-file' performed by default handler + (directory-file-name . tramp-handle-directory-file-name) + (directory-files . tramp-handle-directory-files) + (directory-files-and-attributes . tramp-fish-handle-directory-files-and-attributes) + ;; `dired-call-process' performed by default handler + ;; `dired-compress-file' performed by default handler + ;; `dired-uncache' performed by default handler + (expand-file-name . tramp-fish-handle-expand-file-name) + ;; `file-accessible-directory-p' performed by default handler + (file-attributes . tramp-fish-handle-file-attributes) + (file-directory-p . tramp-fish-handle-file-directory-p) + (file-executable-p . tramp-fish-handle-file-executable-p) + (file-exists-p . tramp-fish-handle-file-exists-p) + (file-local-copy . tramp-fish-handle-file-local-copy) + (file-remote-p . tramp-handle-file-remote-p) + (file-modes . tramp-handle-file-modes) + (file-name-all-completions . tramp-fish-handle-file-name-all-completions) + ;; `file-name-as-directory' performed by default handler + (file-name-completion . tramp-handle-file-name-completion) + (file-name-directory . tramp-handle-file-name-directory) + (file-name-nondirectory . tramp-handle-file-name-nondirectory) + ;; `file-name-sans-versions' performed by default handler + (file-newer-than-file-p . tramp-fish-handle-file-newer-than-file-p) + (file-ownership-preserved-p . ignore) + (file-readable-p . tramp-fish-handle-file-readable-p) + (file-regular-p . tramp-handle-file-regular-p) + (file-symlink-p . tramp-handle-file-symlink-p) + ;; `file-truename' performed by default handler + (file-writable-p . tramp-fish-handle-file-writable-p) + (find-backup-file-name . tramp-handle-find-backup-file-name) + ;; `find-file-noselect' performed by default handler + ;; `get-file-buffer' performed by default handler + (insert-directory . tramp-fish-handle-insert-directory) + (insert-file-contents . tramp-fish-handle-insert-file-contents) + (load . tramp-handle-load) + (make-directory . tramp-fish-handle-make-directory) + (make-directory-internal . tramp-fish-handle-make-directory-internal) + (make-symbolic-link . tramp-fish-handle-make-symbolic-link) + (rename-file . tramp-fish-handle-rename-file) + (set-file-modes . tramp-fish-handle-set-file-modes) + (set-visited-file-modtime . ignore) + (shell-command . tramp-handle-shell-command) + (substitute-in-file-name . tramp-handle-substitute-in-file-name) + (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory) + (vc-registered . ignore) + (verify-visited-file-modtime . ignore) + (write-region . tramp-fish-handle-write-region) + (executable-find . tramp-fish-handle-executable-find) + (start-process . ignore) + (call-process . tramp-fish-handle-call-process) + (process-file . tramp-handle-process-file) +) + "Alist of handler functions for Tramp FISH method. +Operations not mentioned here will be handled by the default Emacs primitives.") + +(defun tramp-fish-file-name-p (filename) + "Check if it's a filename for FISH protocol." + (let ((v (tramp-dissect-file-name filename))) + (string= (tramp-file-name-method v) tramp-fish-method))) + +(defun tramp-fish-file-name-handler (operation &rest args) + "Invoke the FISH related OPERATION. +First arg specifies the OPERATION, second arg is a list of arguments to +pass to the OPERATION." + (let ((fn (assoc operation tramp-fish-file-name-handler-alist))) + (if fn + (save-match-data (apply (cdr fn) args)) + (tramp-run-real-handler operation args)))) + +(add-to-list 'tramp-foreign-file-name-handler-alist + (cons 'tramp-fish-file-name-p 'tramp-fish-file-name-handler)) + + +;; File name primitives + +(defun tramp-fish-handle-add-name-to-file + (filename newname &optional ok-if-already-exists) + "Like `add-name-to-file' for Tramp files." + (unless (tramp-equal-remote filename newname) + (with-parsed-tramp-file-name + (if (tramp-tramp-file-p filename) filename newname) nil + (tramp-error + v 'file-error + "add-name-to-file: %s" + "only implemented for same method, same user, same host"))) + (with-parsed-tramp-file-name filename v1 + (with-parsed-tramp-file-name newname v2 + (when (and (not ok-if-already-exists) + (file-exists-p newname) + (not (numberp ok-if-already-exists)) + (y-or-n-p + (format + "File %s already exists; make it a new name anyway? " + newname))) + (tramp-error + v2 'file-error + "add-name-to-file: file %s already exists" newname)) + (tramp-flush-file-property v2 v2-localname) + (unless (tramp-fish-send-command-and-check + v1 (format "#LINK %s %s" v1-localname v2-localname)) + (tramp-error + v1 'file-error "Error with add-name-to-file %s" newname))))) + +(defun tramp-fish-handle-copy-file + (filename newname &optional ok-if-already-exists keep-date) + "Like `copy-file' for Tramp files." + (tramp-fish-do-copy-or-rename-file + 'copy filename newname ok-if-already-exists keep-date)) + +(defun tramp-fish-handle-delete-directory (directory) + "Like `delete-directory' for Tramp files." + (when (file-exists-p directory) + (with-parsed-tramp-file-name + (directory-file-name (expand-file-name directory)) nil + (tramp-flush-directory-property v localname) + (tramp-fish-send-command-and-check v (format "#RMD %s" localname))))) + +(defun tramp-fish-handle-delete-file (filename) + "Like `delete-file' for Tramp files." + (when (file-exists-p filename) + (with-parsed-tramp-file-name (expand-file-name filename) nil + (tramp-flush-file-property v localname) + (tramp-fish-send-command-and-check v (format "#DELE %s" localname))))) + +(defun tramp-fish-handle-directory-files-and-attributes + (directory &optional full match nosort id-format) + "Like `directory-files-and-attributes' for Tramp files." + (mapcar + (lambda (x) + ;; We cannot call `file-attributes' for backward compatibility reasons. + ;; Its optional parameter ID-FORMAT is introduced with Emacs 22. + (cons x (tramp-fish-handle-file-attributes + (if full x (expand-file-name x directory)) id-format))) + (directory-files directory full match nosort))) + +(defun tramp-fish-handle-expand-file-name (name &optional dir) + "Like `expand-file-name' for Tramp files." + ;; If DIR is not given, use DEFAULT-DIRECTORY or "/". + (setq dir (or dir default-directory "/")) + ;; Unless NAME is absolute, concat DIR and NAME. + (unless (file-name-absolute-p name) + (setq name (concat (file-name-as-directory dir) name))) + ;; If NAME is not a tramp file, run the real handler + (if (or (tramp-completion-mode) (not (tramp-tramp-file-p name))) + (tramp-drop-volume-letter + (tramp-run-real-handler 'expand-file-name (list name nil))) + ;; Dissect NAME. + (with-parsed-tramp-file-name name nil + (unless (file-name-absolute-p localname) + (setq localname (concat "~/" localname))) + ;; Tilde expansion if necessary. + (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname) + (let ((uname (match-string 1 localname)) + (fname (match-string 2 localname))) + ;; We cannot apply "~user/", because this is not supported + ;; by the FISH protocol. + (unless (string-equal uname "~") + (tramp-error + v 'file-error "Tilde expansion not supported for %s" name)) + (setq uname + (with-connection-property v uname + (tramp-fish-send-command-and-check v "#PWD") + (with-current-buffer (tramp-get-buffer v) + (goto-char (point-min)) + (buffer-substring (point) (tramp-line-end-position))))) + (setq localname (concat uname fname)))) + ;; There might be a double slash, for example when "~/" + ;; expands to "/". Remove this. + (while (string-match "//" localname) + (setq localname (replace-match "/" t t localname))) + ;; No tilde characters in file name, do normal + ;; expand-file-name (this does "/./" and "/../"). We bind + ;; `directory-sep-char' here for XEmacs on Windows, which + ;; would otherwise use backslash. `default-directory' is + ;; bound, because on Windows there would be problems with UNC + ;; shares or Cygwin mounts. + (tramp-let-maybe directory-sep-char ?/ + (let ((default-directory (tramp-temporary-file-directory))) + (tramp-make-tramp-file-name + method user host + (tramp-drop-volume-letter + (tramp-run-real-handler 'expand-file-name + (list localname))))))))) + +(defun tramp-fish-handle-file-attributes (filename &optional id-format) + "Like `file-attributes' for Tramp files." + (with-parsed-tramp-file-name (expand-file-name filename) nil + (with-file-property v localname (format "file-attributes-%s" id-format) + (cdr (car (tramp-fish-get-file-entries v localname nil)))))) + +(defun tramp-fish-handle-file-directory-p (filename) + "Like `file-directory-p' for Tramp files." + (let ((attributes (file-attributes filename))) + (and attributes + (or (string-match "d" (nth 8 attributes)) + (and (file-symlink-p filename) + (with-parsed-tramp-file-name filename nil + (file-directory-p + (tramp-make-tramp-file-name + method user host (nth 0 attributes)))))) + t))) + +(defun tramp-fish-handle-file-exists-p (filename) + "Like `file-exists-p' for Tramp files." + (and (file-attributes filename) t)) + +(defun tramp-fish-handle-file-executable-p (filename) + "Like `file-executable-p' for Tramp files." + (with-parsed-tramp-file-name (expand-file-name filename) nil + (with-file-property v localname "file-executable-p" + (when (file-exists-p filename) + (let ((mode-chars (string-to-vector (nth 8 (file-attributes filename)))) + (home-directory + (tramp-make-tramp-file-name + method user host + (tramp-get-connection-property v "home-directory" nil)))) + (or (and (char-equal (aref mode-chars 3) ?x) + (equal (nth 2 (file-attributes filename)) + (nth 2 (file-attributes home-directory)))) + (and (char-equal (aref mode-chars 6) ?x) + (equal (nth 3 (file-attributes filename)) + (nth 3 (file-attributes home-directory)))) + (char-equal (aref mode-chars 9) ?x))))))) + +(defun tramp-fish-handle-file-readable-p (filename) + "Like `file-readable-p' for Tramp files." + (with-parsed-tramp-file-name (expand-file-name filename) nil + (with-file-property v localname "file-readable-p" + (when (file-exists-p filename) + (let ((mode-chars (string-to-vector (nth 8 (file-attributes filename)))) + (home-directory + (tramp-make-tramp-file-name + method user host + (tramp-get-connection-property v "home-directory" nil)))) + (or (and (char-equal (aref mode-chars 1) ?r) + (equal (nth 2 (file-attributes filename)) + (nth 2 (file-attributes home-directory)))) + (and (char-equal (aref mode-chars 4) ?r) + (equal (nth 3 (file-attributes filename)) + (nth 3 (file-attributes home-directory)))) + (char-equal (aref mode-chars 7) ?r))))))) + +(defun tramp-fish-handle-file-writable-p (filename) + "Like `file-writable-p' for Tramp files." + (with-parsed-tramp-file-name (expand-file-name filename) nil + (with-file-property v localname "file-writable-p" + (if (not (file-exists-p filename)) + ;; If file doesn't exist, check if directory is writable. + (and (file-directory-p (file-name-directory filename)) + (file-writable-p (file-name-directory filename))) + ;; Existing files must be writable. + (let ((mode-chars (string-to-vector (nth 8 (file-attributes filename)))) + (home-directory + (tramp-make-tramp-file-name + method user host + (tramp-get-connection-property v "home-directory" nil)))) + (or (and (char-equal (aref mode-chars 2) ?w) + (equal (nth 2 (file-attributes filename)) + (nth 2 (file-attributes home-directory)))) + (and (char-equal (aref mode-chars 5) ?w) + (equal (nth 3 (file-attributes filename)) + (nth 3 (file-attributes home-directory)))) + (char-equal (aref mode-chars 8) ?w))))))) + +(defun tramp-fish-handle-file-local-copy (filename) + "Like `file-local-copy' for Tramp files." + (with-parsed-tramp-file-name (expand-file-name filename) nil + (unless (file-exists-p filename) + (tramp-error + v 'file-error + "Cannot make local copy of non-existing file `%s'" filename)) + (let ((tmpfil (tramp-make-temp-file filename))) + (tramp-message v 4 "Fetching %s to tmp file %s..." filename tmpfil) + (when (tramp-fish-retrieve-data v) + ;; Save file + (with-current-buffer (tramp-get-buffer v) + (write-region (point-min) (point-max) tmpfil)) + (tramp-message v 4 "Fetching %s to tmp file %s...done" filename tmpfil) + tmpfil)))) + +;; This function should return "foo/" for directories and "bar" for +;; files. +(defun tramp-fish-handle-file-name-all-completions (filename directory) + "Like `file-name-all-completions' for Tramp files." + (all-completions + filename + (with-parsed-tramp-file-name (expand-file-name directory) nil + (with-file-property v localname "file-name-all-completions" + (save-match-data + (let ((entries + (with-file-property v localname "file-entries" + (tramp-fish-get-file-entries v localname t)))) + (mapcar + (lambda (x) + (list + (if (string-match "d" (nth 9 x)) + (file-name-as-directory (nth 0 x)) + (nth 0 x)))) + entries))))))) + +(defun tramp-fish-handle-file-newer-than-file-p (file1 file2) + "Like `file-newer-than-file-p' for Tramp files." + (cond + ((not (file-exists-p file1)) nil) + ((not (file-exists-p file2)) t) + (t (tramp-time-less-p (nth 5 (file-attributes file2)) + (nth 5 (file-attributes file1)))))) + +(defun tramp-fish-handle-insert-directory + (filename switches &optional wildcard full-directory-p) + "Like `insert-directory' for Tramp files. +WILDCARD and FULL-DIRECTORY-P are not handled." + (setq filename (expand-file-name filename)) + (when (file-directory-p filename) + ;; This check is a little bit strange, but in `dired-add-entry' + ;; this function is called with a non-directory ... + (setq filename (file-name-as-directory filename))) + + (with-parsed-tramp-file-name filename nil + (tramp-flush-file-property v localname) + (save-match-data + (let ((entries + (with-file-property v localname "file-entries" + (tramp-fish-get-file-entries v localname t)))) + + ;; Sort entries + (setq entries + (sort + entries + (lambda (x y) + (if (string-match "t" switches) + ;; Sort by date. + (tramp-time-less-p (nth 6 y) (nth 6 x)) + ;; Sort by name. + (string-lessp (nth 0 x) (nth 0 y)))))) + + ;; Print entries. + (mapcar + (lambda (x) + (insert + (format + "%10s %3d %-8s %-8s %8s %s %s%s\n" + (nth 9 x) ; mode + 1 ; hardlinks + (nth 3 x) ; uid + (nth 4 x) ; gid + (nth 8 x) ; size + (format-time-string + (if (tramp-time-less-p + (tramp-time-subtract (current-time) (nth 6 x)) + tramp-half-a-year) + "%b %e %R" + "%b %e %Y") + (nth 6 x)) ; date + (nth 0 x) ; file name + (if (stringp (nth 1 x)) (format " -> %s" (nth 1 x)) ""))) + (forward-line) + (beginning-of-line)) + entries))))) + +(defun tramp-fish-handle-insert-file-contents + (filename &optional visit beg end replace) + "Like `insert-file-contents' for Tramp files." + (barf-if-buffer-read-only) + (when visit + (setq buffer-file-name (expand-file-name filename)) + (set-visited-file-modtime) + (set-buffer-modified-p nil)) + + (with-parsed-tramp-file-name filename nil + (if (not (file-exists-p filename)) + (tramp-error + v 'file-error "File %s not found on remote host" filename) + + (let ((point (point)) + size) + (tramp-message v 4 "Fetching file %s..." filename) + (when (tramp-fish-retrieve-data v) + ;; Insert file + (insert + (with-current-buffer (tramp-get-buffer v) + (let ((beg (or beg (point-min))) + (end (min (or end (point-max)) (point-max)))) + (setq size (- end beg)) + (buffer-substring beg end)))) + (goto-char point)) + (tramp-message v 4 "Fetching file %s...done" filename) + + (list (expand-file-name filename) size))))) + +(defun tramp-fish-handle-make-directory (dir &optional parents) + "Like `make-directory' for Tramp files." + (setq dir (directory-file-name (expand-file-name dir))) + (unless (file-name-absolute-p dir) + (setq dir (expand-file-name dir default-directory))) + (with-parsed-tramp-file-name dir nil + (save-match-data + (let ((ldir (file-name-directory dir))) + ;; Make missing directory parts + (when (and parents (not (file-directory-p ldir))) + (make-directory ldir parents)) + ;; Just do it + (when (file-directory-p ldir) + (make-directory-internal dir)) + (unless (file-directory-p dir) + (tramp-error v 'file-error "Couldn't make directory %s" dir)))))) + +(defun tramp-fish-handle-make-directory-internal (directory) + "Like `make-directory-internal' for Tramp files." + (setq directory (directory-file-name (expand-file-name directory))) + (unless (file-name-absolute-p directory) + (setq directory (expand-file-name directory default-directory))) + (when (file-directory-p (file-name-directory directory)) + (with-parsed-tramp-file-name directory nil + (save-match-data + (unless + (tramp-fish-send-command-and-check v (format "#MKD %s" localname)) + (tramp-error + v 'file-error "Couldn't make directory %s" directory)))))) + +(defun tramp-fish-handle-make-symbolic-link + (filename linkname &optional ok-if-already-exists) + "Like `make-symbolic-link' for Tramp files. +If LINKNAME is a non-Tramp file, it is used verbatim as the target of +the symlink. If LINKNAME is a Tramp file, only the localname component is +used as the target of the symlink. + +If LINKNAME is a Tramp file and the localname component is relative, then +it is expanded first, before the localname component is taken. Note that +this can give surprising results if the user/host for the source and +target of the symlink differ." + (with-parsed-tramp-file-name linkname nil + ;; Do the 'confirm if exists' thing. + (when (file-exists-p linkname) + ;; What to do? + (if (or (null ok-if-already-exists) ; not allowed to exist + (and (numberp ok-if-already-exists) + (not (yes-or-no-p + (format + "File %s already exists; make it a link anyway? " + localname))))) + (tramp-error + v 'file-already-exists "File %s already exists" localname) + (delete-file linkname))) + + ;; If FILENAME is a Tramp name, use just the localname component. + (when (tramp-tramp-file-p filename) + (setq filename (tramp-file-name-localname + (tramp-dissect-file-name (expand-file-name filename))))) + + ;; Right, they are on the same host, regardless of user, method, etc. + ;; We now make the link on the remote machine. This will occur as the user + ;; that FILENAME belongs to. + (unless + (tramp-fish-send-command-and-check + v (format "#SYMLINK %s %s" filename localname)) + (tramp-error v 'file-error "Error creating symbolic link %s" linkname)))) + +(defun tramp-fish-handle-rename-file + (filename newname &optional ok-if-already-exists) + "Like `rename-file' for Tramp files." + (tramp-fish-do-copy-or-rename-file + 'rename filename newname ok-if-already-exists t)) + +(defun tramp-fish-handle-set-file-modes (filename mode) + "Like `set-file-modes' for Tramp files." + (with-parsed-tramp-file-name filename nil + (tramp-flush-file-property v localname) + (unless (tramp-fish-send-command-and-check + v (format "#CHMOD %s %s" + (tramp-decimal-to-octal mode) + (tramp-shell-quote-argument localname))) + (tramp-error + v 'file-error "Error while changing file's mode %s" filename)))) + +(defun tramp-fish-handle-write-region + (start end filename &optional append visit lockname confirm) + "Like `write-region' for Tramp files." + (setq filename (expand-file-name filename)) + (with-parsed-tramp-file-name filename nil + ;; XEmacs takes a coding system as the seventh argument, not `confirm' + (when (and (not (featurep 'xemacs)) + confirm (file-exists-p filename)) + (unless (y-or-n-p (format "File %s exists; overwrite anyway? " + filename)) + (tramp-error v 'file-error "File not overwritten"))) + + (tramp-flush-file-property v localname) + + ;; Send command + (let ((tramp-fish-ok-prompt-regexp + (concat + tramp-fish-ok-prompt-regexp "\\|" + tramp-fish-continue-prompt-regexp))) + (tramp-fish-send-command + v (format "%s %d %s\n### 100" + (if append "#APPEND" "#STOR") (- end start) localname))) + + ;; Send data, if there are any. + (when (> end start) + (tramp-fish-send-command v (buffer-substring-no-properties start end))) + + (when (eq visit t) + (set-visited-file-modtime)))) + +(defun tramp-fish-handle-executable-find (command) + "Like `executable-find' for Tramp files." + (with-temp-buffer + (if (zerop (call-process "which" nil t nil command)) + (progn + (goto-char (point-min)) + (buffer-substring (point-min) (tramp-line-end-position)))))) + +(defun tramp-fish-handle-call-process + (program &optional infile destination display &rest args) + "Like `call-process' for Tramp files." + ;; The implementation is not complete yet. + (when (and (numberp destination) (zerop destination)) + (error "Implementation does not handle immediate return")) + + (with-parsed-tramp-file-name default-directory nil + (let ((temp-name-prefix (tramp-make-tramp-temp-file v)) + command input output stderr outbuf tmpfil ret) + ;; Compute command. + (setq command (mapconcat 'tramp-shell-quote-argument + (cons program args) " ")) + ;; Determine input. + (if (null infile) + (setq input "/dev/null") + (setq infile (expand-file-name infile)) + (if (tramp-equal-remote default-directory infile) + ;; INFILE is on the same remote host. + (setq input (with-parsed-tramp-file-name infile nil localname)) + ;; INFILE must be copied to remote host. + (setq input (concat temp-name-prefix ".in")) + (copy-file + infile + (tramp-make-tramp-file-name method user host input) + t))) + (when input (setq command (format "%s <%s" command input))) + + ;; Determine output. + (setq output (concat temp-name-prefix ".out")) + (cond + ;; Just a buffer + ((bufferp destination) + (setq outbuf destination)) + ;; A buffer name + ((stringp destination) + (setq outbuf (get-buffer-create destination))) + ;; (REAL-DESTINATION ERROR-DESTINATION) + ((consp destination) + ;; output + (cond + ((bufferp (car destination)) + (setq outbuf (car destination))) + ((stringp (car destination)) + (setq outbuf (get-buffer-create (car destination))))) + ;; stderr + (cond + ((stringp (cadr destination)) + (setcar (cdr destination) (expand-file-name (cadr destination))) + (if (tramp-equal-remote default-directory (cadr destination)) + ;; stderr is on the same remote host. + (setq stderr (with-parsed-tramp-file-name + (cadr destination) nil localname)) + ;; stderr must be copied to remote host. The temporary + ;; file must be deleted after execution. + (setq stderr (concat temp-name-prefix ".err")))) + ;; stderr to be discarded + ((null (cadr destination)) + (setq stderr "/dev/null")))) + ;; 't + (destination + (setq outbuf (current-buffer)))) + (when stderr (setq command (format "%s 2>%s" command stderr))) + + ;; If we have a temporary file, it must be removed after operation. + (when (and input (string-match temp-name-prefix input)) + (setq command (format "%s; rm %s" command input))) + ;; Goto working directory. + (unless + (tramp-fish-send-command-and-check + v (format "#CWD %s" (tramp-shell-quote-argument localname))) + (tramp-error v 'file-error "No such directory: %s" default-directory)) + ;; Send the command. It might not return in time, so we protect it. + (condition-case nil + (unwind-protect + (unless (tramp-fish-send-command-and-check + v (format + "#EXEC %s %s" + (tramp-shell-quote-argument command) output)) + (error)) + ;; Check return code. + (setq tmpfil (file-local-copy + (tramp-make-tramp-file-name method user host output))) + (with-temp-buffer + (insert-file-contents tmpfil) + (goto-char (point-max)) + (forward-line -1) + (looking-at "^###RESULT: \\([0-9]+\\)") + (setq ret (string-to-number (match-string 1))) + (delete-region (point) (point-max)) + (write-region (point-min) (point-max) tmpfil)) + ;; We should show the output anyway. + (when outbuf + (with-current-buffer outbuf (insert-file-contents tmpfil)) + (when display (display-buffer outbuf))) + ;; Remove output file. + (delete-file (tramp-make-tramp-file-name method user host output))) + ;; When the user did interrupt, we should do it also. + (error (setq ret 1))) + (unless ret + ;; Provide error file. + (when (and stderr (string-match temp-name-prefix stderr)) + (rename-file (tramp-make-tramp-file-name method user host stderr) + (cadr destination) t))) + ;; Return exit status. + ret))) + + +;; Internal file name functions + +(defun tramp-fish-do-copy-or-rename-file + (op filename newname &optional ok-if-already-exists keep-date) + "Copy or rename a remote file. +OP must be `copy' or `rename' and indicates the operation to +perform. FILENAME specifies the file to copy or rename, NEWNAME +is the name of the new file (for copy) or the new name of the +file (for rename). OK-IF-ALREADY-EXISTS means don't barf if +NEWNAME exists already. KEEP-DATE means to make sure that +NEWNAME has the same timestamp as FILENAME. + +This function is invoked by `tramp-fish-handle-copy-file' and +`tramp-fish-handle-rename-file'. It is an error if OP is neither +of `copy' and `rename'. FILENAME and NEWNAME must be absolute +file names." + (unless (memq op '(copy rename)) + (error "Unknown operation `%s', must be `copy' or `rename'" op)) + (let ((t1 (tramp-tramp-file-p filename)) + (t2 (tramp-tramp-file-p newname))) + + (unless ok-if-already-exists + (when (and t2 (file-exists-p newname)) + (with-parsed-tramp-file-name newname nil + (tramp-error + v 'file-already-exists "File %s already exists" newname)))) + + (prog1 + (cond + ;; Both are Tramp files. + ((and t1 t2) + (cond + ;; Shortcut: if method, host, user are the same for both + ;; files, we invoke `cp' or `mv' on the remote host + ;; directly. + ((tramp-equal-remote filename newname) + (tramp-fish-do-copy-or-rename-file-directly + op filename newname keep-date)) + ;; No shortcut was possible. So we copy the + ;; file first. If the operation was `rename', we go + ;; back and delete the original file (if the copy was + ;; successful). The approach is simple-minded: we + ;; create a new buffer, insert the contents of the + ;; source file into it, then write out the buffer to + ;; the target file. The advantage is that it doesn't + ;; matter which filename handlers are used for the + ;; source and target file. + (t + (tramp-do-copy-or-rename-file-via-buffer + op filename newname keep-date)))) + + ;; One file is a Tramp file, the other one is local. + ((or t1 t2) + ;; Use the generic method via a Tramp buffer. + (tramp-do-copy-or-rename-file-via-buffer + op filename newname keep-date)) + + (t + ;; One of them must be a Tramp file. + (error "Tramp implementation says this cannot happen"))) + ;; When newname did exist, we have wrong cached values. + (when t2 + (with-parsed-tramp-file-name newname nil + (tramp-flush-file-property v localname) + (tramp-flush-file-property v (file-name-directory localname))))))) + +(defun tramp-fish-do-copy-or-rename-file-directly + (op filename newname keep-date) + "Invokes `COPY' or `RENAME' on the remote system. +OP must be one of `copy' or `rename', indicating `cp' or `mv', +respectively. VEC specifies the connection. LOCALNAME1 and +LOCALNAME2 specify the two arguments of `cp' or `mv'. If +KEEP-DATE is non-nil, preserve the time stamp when copying." + (with-parsed-tramp-file-name filename v1 + (with-parsed-tramp-file-name newname v2 + (tramp-fish-send-command + v1 + (format "%s %s %s" + (if (eq op 'copy) "#COPY" "#RENAME") + (tramp-shell-quote-argument v1-localname) + (tramp-shell-quote-argument v2-localname))))) + ;; KEEP-DATE handling. + (when keep-date + (let ((modtime (nth 5 (file-attributes filename)))) + (when (and (not (null modtime)) + (not (equal modtime '(0 0)))) + (tramp-touch newname modtime)))) + ;; Set the mode. + (set-file-modes newname (file-modes filename))) + +(defun tramp-fish-get-file-entries (vec localname list) + "Read entries returned by FISH server. +When LIST is true, a #LIST command will be sent, including all entries +of a directory. Otherwise, #STAT is sent for just one entry. +Result is a list of (LOCALNAME LINK COUNT UID GID ATIME MTIME CTIME +SIZE MODE WEIRD INODE DEVICE)." + (block nil + (with-current-buffer (tramp-get-buffer vec) + ;; #LIST does not work properly with trailing "/", at least in .fishsrv.pl + (when (string-match "/$" localname) + (setq localname (concat localname "."))) + + (let ((command (format "%s %s" (if list "#LIST" "#STAT") localname)) + buffer-read-only num res) + + ;; Send command + (tramp-fish-send-command vec command) + + ;; Read number of entries + (goto-char (point-min)) + (condition-case nil + (unless (integerp (setq num (read (current-buffer)))) (error)) + (error (return nil))) + (forward-line) + (delete-region (point-min) (point)) + + ;; Read return code + (goto-char (point-min)) + (condition-case nil + (unless (looking-at tramp-fish-continue-prompt-regexp) (error)) + (error (return nil))) + (forward-line) + (delete-region (point-min) (point)) + + ;; Loop the listing + (dotimes (i num) + (let ((item (tramp-fish-read-file-entry))) + ;; Add inode and device. + (add-to-list + 'res (append item + (list (tramp-get-inode (car item)) + (tramp-get-device vec)))))) + + ;; Read return code + (goto-char (point-min)) + (condition-case nil + (unless (looking-at tramp-fish-ok-prompt-regexp) (error)) + (error (tramp-error + vec 'file-error + "`%s' does not return a valid Lisp expression: `%s'" + command (buffer-string)))) + (forward-line) + (delete-region (point-min) (point)) + + res)))) + +(defun tramp-fish-read-file-entry () + "Parse entry in output buffer. +Result is the list (LOCALNAME LINK COUNT UID GID ATIME MTIME CTIME +SIZE MODE WEIRD)." + ;; We are called from `tramp-fish-get-file-entries', which sets the + ;; current buffer. + (let (buffer-read-only localname link uid gid mtime size mode) + (block nil + (while t + (cond + ;; P . + ((looking-at "^P\\(.+\\)\\s-\\(.+\\)\\.\\(.+\\)$") + (setq mode (match-string 1)) + (setq uid (match-string 2)) + (setq gid (match-string 3)) + (when (string-match "^d" mode) (setq link t))) + ;; S + ((looking-at "^S\\([0-9]+\\)$") + (setq size (string-to-number (match-string 1)))) + ;; D [.1234] + ((looking-at + "^D\\([0-9]+\\)\\s-\\([0-9]+\\)\\s-\\([0-9]+\\)\\s-\\([0-9]+\\)\\s-\\([0-9]+\\)\\s-\\(\\S-+\\)$") + (setq mtime + (encode-time + (string-to-number (match-string 6)) + (string-to-number (match-string 5)) + (string-to-number (match-string 4)) + (string-to-number (match-string 3)) + (string-to-number (match-string 2)) + (string-to-number (match-string 1))))) + ;; d<3-letters month name> + ((looking-at "^d") nil) + ;; E, + ((looking-at "^E") nil) + ;; : + ((looking-at "^:\\(.+\\)$") + (setq localname (match-string 1))) + ;; L + ((looking-at "^L\\(.+\\)$") + (setq link (match-string 1))) + ;; M + ((looking-at "^M\\(.+\\)$") nil) + ;; last line + ((looking-at "^$") + (return))) + ;; delete line + (forward-line) + (delete-region (point-min) (point)))) + + ;; delete trailing empty line + (forward-line) + (delete-region (point-min) (point)) + + ;; Return entry in file-attributes format + (list localname link -1 uid gid '(0 0) mtime '(0 0) size mode nil))) + +(defun tramp-fish-retrieve-data (vec) + "Reads remote data for FISH protocol. +The data are left in the connection buffer of VEC for further processing. +Returns the size of the data." + (block nil + (with-current-buffer (tramp-get-buffer vec) + ;; The retrieved data might be in binary format, without + ;; trailing newline. Therefore, the OK prompt might not start + ;; at the beginning of a line. + (let ((tramp-fish-ok-prompt-regexp "### 200\n") + size) + + ;; Send command + (tramp-fish-send-command + vec (format "#RETR %s" (tramp-file-name-localname vec))) + + ;; Read filesize + (goto-char (point-min)) + (condition-case nil + (unless (integerp (setq size (read (current-buffer)))) (error)) + (error (return nil))) + (forward-line) + (delete-region (point-min) (point)) + + ;; Read return code + (goto-char (point-min)) + (condition-case nil + (unless (looking-at tramp-fish-continue-prompt-regexp) (error)) + (error (return nil))) + (forward-line) + (delete-region (point-min) (point)) + + ;; The received data might contain the OK prompt already, so + ;; there might be outstanding data. + (while (/= (+ size (length tramp-fish-ok-prompt-regexp)) + (- (point-max) (point-min))) + (tramp-wait-for-regexp + (tramp-get-connection-process vec) nil + (concat tramp-fish-ok-prompt-regexp "$"))) + + ;; Read return code + (goto-char (+ (point-min) size)) + (condition-case nil + (unless (looking-at tramp-fish-ok-prompt-regexp) (error)) + (error (return nil))) + (delete-region (+ (point-min) size) (point-max)) + size)))) + + +;; Connection functions + +(defun tramp-fish-maybe-open-connection (vec) + "Maybe open a connection VEC. +Does not do anything if a connection is already open, but re-opens the +connection if a previous connection has died for some reason." + (let ((process-connection-type tramp-process-connection-type) + (p (get-buffer-process (tramp-get-buffer vec)))) + + ;; New connection must be opened. + (unless (and p (processp p) (memq (process-status p) '(run open))) + + ;; Set variables for computing the prompt for reading password. + (setq tramp-current-method (tramp-file-name-method vec) + tramp-current-user (tramp-file-name-user vec) + tramp-current-host (tramp-file-name-host vec)) + + ;; Start new process. + (when (and p (processp p)) + (delete-process p)) + (setenv "TERM" tramp-terminal-type) + (setenv "PS1" "$ ") + (tramp-message + vec 3 "Opening connection for %s@%s using %s..." + tramp-current-user tramp-current-host tramp-current-method) + + (let* ((process-connection-type tramp-process-connection-type) + (inhibit-eol-conversion nil) + (coding-system-for-read 'binary) + (coding-system-for-write 'binary) + ;; This must be done in order to avoid our file name handler. + (p (let ((default-directory (tramp-temporary-file-directory))) + (start-process + (or (tramp-get-connection-property vec "process-name" nil) + (tramp-buffer-name vec)) + (tramp-get-connection-buffer vec) + "ssh" "-l" + (tramp-file-name-user vec) + (tramp-file-name-host vec))))) + (tramp-message vec 6 "%s" (mapconcat 'identity (process-command p) " ")) + + ;; Check whether process is alive. + (set-process-sentinel p 'tramp-flush-connection-property) + (tramp-set-process-query-on-exit-flag p nil) + + (tramp-process-actions p vec tramp-actions-before-shell 60) + (tramp-fish-send-command vec tramp-fish-start-fish-server-command) + (tramp-message + vec 3 + "Found remote shell prompt on `%s'" (tramp-file-name-host vec)))))) + +(defun tramp-fish-send-command (vec command) + "Send the COMMAND to connection VEC." + (tramp-fish-maybe-open-connection vec) + (tramp-message vec 6 "%s" command) + (tramp-send-string vec command) + (tramp-wait-for-regexp + (tramp-get-connection-process vec) nil + (concat tramp-fish-ok-prompt-regexp "\\|" tramp-fish-error-prompt-regexp))) + +(defun tramp-fish-send-command-and-check (vec command) + "Send the COMMAND to connection VEC. +Returns nil if there has been an error message." + + ;; Send command. + (tramp-fish-send-command vec command) + + ;; Read return code. + (with-current-buffer (tramp-get-buffer vec) + (goto-char (point-min)) + (looking-at tramp-fish-ok-prompt-regexp))) + +(provide 'tramp-fish) +; +;;;; TODO: +; +;; * Evaluate the MIME information with #LIST or #STAT. +; + +;; arch-tag: a66df7df-5f29-42a7-a921-643ceb29db49 +;;;; tramp-fish.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/tramp-ftp.el --- a/lisp/net/tramp-ftp.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/net/tramp-ftp.el Sun Jul 15 02:05:20 2007 +0000 @@ -10,8 +10,8 @@ ;; GNU Emacs 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 2, or (at your option) -;; any later version. +;; the Free Software Foundation; either version 3 of the License, or +;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -19,9 +19,8 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs; see the file COPYING. If not, see +;; . ;;; Commentary: @@ -110,10 +109,13 @@ (list "" "\\`\\(anonymous\\|ftp\\)\\'" tramp-ftp-method)) ;; Add completion function for FTP method. -(unless (memq system-type '(windows-nt)) - (tramp-set-completion-function - tramp-ftp-method - '((tramp-parse-netrc "~/.netrc")))) +(tramp-set-completion-function + tramp-ftp-method + '((tramp-parse-netrc "~/.netrc"))) + +;; If there is URL syntax, `substitute-in-file-name' needs special +;; handling. +(put 'substitute-in-file-name 'ange-ftp 'tramp-handle-substitute-in-file-name) (defun tramp-ftp-file-name-handler (operation &rest args) "Invoke the Ange-FTP handler for OPERATION. @@ -152,13 +154,7 @@ (defun tramp-ftp-file-name-p (filename) "Check if it's a filename that should be forwarded to Ange-FTP." (let ((v (tramp-dissect-file-name filename))) - (string= - (tramp-find-method - (tramp-file-name-multi-method v) - (tramp-file-name-method v) - (tramp-file-name-user v) - (tramp-file-name-host v)) - tramp-ftp-method))) + (string= (tramp-file-name-method v) tramp-ftp-method))) (add-to-list 'tramp-foreign-file-name-handler-alist (cons 'tramp-ftp-file-name-p 'tramp-ftp-file-name-handler)) @@ -172,8 +168,6 @@ ;; pretended in `tramp-file-name-handler' otherwise. ;; Furthermore, there are no backup files on FTP hosts. ;; Worth further investigations. -;; * Map /multi:ssh:out@gate:ftp:kai@real.host:/path/to.file -;; on Ange-FTP gateways. ;;; arch-tag: 759fb338-5c63-4b99-bd36-b4d59db91cff ;;; tramp-ftp.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/tramp-gw.el --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/net/tramp-gw.el Sun Jul 15 02:05:20 2007 +0000 @@ -0,0 +1,324 @@ +;;; -*- coding: iso-8859-1; -*- +;;; tramp-gw.el --- Tramp utility functions for HTTP tunnels and SOCKS gateways + +;; Copyright (C) 2007 Free Software Foundation, Inc. + +;; Author: Michael Albinus +;; Keywords: comm, processes + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, see +;; . + +;;; Commentary: + +;; Access functions for HTTP tunnels and SOCKS gateways from Tramp. +;; SOCKS functionality is implemented by socks.el from the w3 package. +;; HTTP tunnels are partly implemented in socks.el and url-http.el; +;; both implementations are not complete. Therefore, it is +;; implemented in this package. + +;;; Code: + +(require 'tramp) + +;; Pacify byte-compiler +(eval-when-compile + (require 'cl) + (require 'custom)) + +;; Autoload the socks library. It is used only when we access a SOCKS server. +(autoload 'socks-open-network-stream "socks") +(defvar socks-username (user-login-name)) +(defvar socks-server (list "Default server" "socks" 1080 5)) + +;; Avoid byte-compiler warnings if the byte-compiler supports this. +;; Currently, XEmacs supports this. +(eval-when-compile + (when (featurep 'xemacs) + (byte-compiler-options (warnings (- unused-vars))))) + +;; Define HTTP tunnel method ... +(defvar tramp-gw-tunnel-method "tunnel" + "*Method to connect HTTP gateways.") + +;; ... and port. +(defvar tramp-gw-default-tunnel-port 8080 + "*Default port for HTTP gateways.") + +;; Define SOCKS method ... +(defvar tramp-gw-socks-method "socks" + "*Method to connect SOCKS servers.") + +;; ... and port. +(defvar tramp-gw-default-socks-port 1080 + "*Default port for SOCKS servers.") + +;; Add a default for `tramp-default-user-alist'. Default is the local user. +(add-to-list 'tramp-default-user-alist + `(,tramp-gw-tunnel-method nil ,(user-login-name))) +(add-to-list 'tramp-default-user-alist + `(,tramp-gw-socks-method nil ,(user-login-name))) + +;; Internal file name functions and variables. + +(defvar tramp-gw-vector nil + "Keeps the remote host identification. Needed for Tramp messages.") + +(defvar tramp-gw-gw-vector nil + "Current gateway identification vector.") + +(defvar tramp-gw-gw-proc nil + "Current gateway process.") + +;; This variable keeps the listening process, in order to reuse it for +;; new processes. +(defvar tramp-gw-aux-proc nil + "Process listening on local port, as mediation between SSH and the gateway.") + +(defun tramp-gw-gw-proc-sentinel (proc event) + "Delete auxiliary process when we are deleted." + (unless (memq (process-status proc) '(run open)) + (tramp-message + tramp-gw-vector 4 "Deleting auxiliary process `%s'" tramp-gw-gw-proc) + (let* (tramp-verbose + (p (tramp-get-connection-property proc "process" nil))) + (when (processp p) (delete-process p))))) + +(defun tramp-gw-aux-proc-sentinel (proc event) + "Activate the different filters for involved gateway and auxiliary processes." + (when (memq (process-status proc) '(run open)) + ;; A new process has been spawned from `tramp-gw-aux-proc'. + (tramp-message + tramp-gw-vector 4 + "Opening auxiliary process `%s', speaking with process `%s'" + proc tramp-gw-gw-proc) + (tramp-set-process-query-on-exit-flag proc nil) + ;; We don't want debug messages, because the corresponding debug + ;; buffer might be undecided. + (let (tramp-verbose) + (tramp-set-connection-property tramp-gw-gw-proc "process" proc) + (tramp-set-connection-property proc "process" tramp-gw-gw-proc)) + ;; Set the process-filter functions for both processes. + (set-process-filter proc 'tramp-gw-process-filter) + (set-process-filter tramp-gw-gw-proc 'tramp-gw-process-filter) + ;; There might be already some output from the gateway process. + (with-current-buffer (process-buffer tramp-gw-gw-proc) + (unless (= (point-min) (point-max)) + (let ((s (buffer-string))) + (delete-region (point) (point-max)) + (tramp-gw-process-filter tramp-gw-gw-proc s)))))) + +(defun tramp-gw-process-filter (proc string) + (let (tramp-verbose) + (process-send-string + (tramp-get-connection-property proc "process" nil) string))) + +(defun tramp-gw-open-connection (vec gw-vec target-vec) + "Open a remote connection to VEC (see `tramp-file-name' structure). +Take GW-VEC as SOCKS or HTTP gateway, i.e. its method must be a +gateway method. TARGET-VEC identifies where to connect to via +the gateway, it can be different from VEC when there are more +hops to be applied. + +It returns a string like \"localhost#port\", which must be used +instead of the host name declared in TARGET-VEC." + + ;; Remember vectors for property retrieval. + (setq tramp-gw-vector vec + tramp-gw-gw-vector gw-vec) + + ;; Start listening auxiliary process. + (unless (and (processp tramp-gw-aux-proc) + (memq (process-status tramp-gw-aux-proc) '(listen))) + (let ((aux-vec + (vector "aux" (tramp-file-name-user gw-vec) + (tramp-file-name-host gw-vec) nil))) + (setq tramp-gw-aux-proc + (make-network-process + :name (tramp-buffer-name aux-vec) :buffer nil :host 'local + :server t :noquery t :service t :coding 'binary)) + (set-process-sentinel tramp-gw-aux-proc 'tramp-gw-aux-proc-sentinel) + (tramp-set-process-query-on-exit-flag tramp-gw-aux-proc nil) + (tramp-message + vec 4 "Opening auxiliary process `%s', listening on port %d" + tramp-gw-aux-proc (process-contact tramp-gw-aux-proc :service)))) + + (let* ((gw-method + (intern + (tramp-find-method + (tramp-file-name-method gw-vec) + (tramp-file-name-user gw-vec) + (tramp-file-name-host gw-vec)))) + (socks-username + (tramp-find-user + (tramp-file-name-method gw-vec) + (tramp-file-name-user gw-vec) + (tramp-file-name-host gw-vec))) + ;; Declare the SOCKS server to be used. + (socks-server + (list "Tramp tempory socks server list" + ;; Host name. + (tramp-file-name-real-host gw-vec) + ;; Port number. + (or (tramp-file-name-port gw-vec) + (case gw-method + (tunnel tramp-gw-default-tunnel-port) + (socks tramp-gw-default-socks-port))) + ;; Type. We support only http and socks5, NO socks4. + ;; 'http could be used when HTTP tunnel works in socks.el. + 5)) + ;; The function to be called. + (socks-function + (case gw-method + (tunnel 'tramp-gw-open-network-stream) + (socks 'socks-open-network-stream))) + socks-noproxy) + + ;; Open SOCKS process. + (setq tramp-gw-gw-proc + (funcall + socks-function + (tramp-buffer-name gw-vec) + (tramp-get-buffer gw-vec) + (tramp-file-name-real-host target-vec) + (tramp-file-name-port target-vec))) + (set-process-sentinel tramp-gw-gw-proc 'tramp-gw-gw-proc-sentinel) + (tramp-set-process-query-on-exit-flag tramp-gw-gw-proc nil) + (tramp-message + vec 4 "Opened %s process `%s'" + (case gw-method ('tunnel "HTTP tunnel") ('socks "SOCKS")) + tramp-gw-gw-proc) + + ;; Return the new host for gateway access. + (format "localhost#%d" (process-contact tramp-gw-aux-proc :service)))) + +(defun tramp-gw-open-network-stream (name buffer host service) + "Open stream to proxy server HOST:SERVICE. +Resulting process has name NAME and buffer BUFFER. If +authentication is requested from proxy server, provide it." + (let ((command (format (concat + "CONNECT %s:%d HTTP/1.1\r\n" + "Host: %s:%d\r\n" + "Connection: keep-alive\r\n" + "User-Agent: Tramp/%s\r\n") + host service host service tramp-version)) + (authentication "") + (first t) + found proc) + + (while (not found) + ;; Clean up. + (when (processp proc) (delete-process proc)) + (with-current-buffer buffer (erase-buffer)) + ;; Open network stream. + (setq proc (open-network-stream + name buffer (nth 1 socks-server) (nth 2 socks-server))) + (set-process-coding-system proc 'binary 'binary) + (tramp-set-process-query-on-exit-flag proc nil) + ;; Send CONNECT command. + (process-send-string proc (format "%s%s\r\n" command authentication)) + (tramp-message + tramp-gw-vector 6 "\n%s" + (format + "%s%s\r\n" command + (replace-regexp-in-string ;; no password in trace! + "Basic [^\r\n]+" "Basic xxxxx" authentication t))) + (with-current-buffer buffer + ;; Trap errors to be traced in the right trace buffer. Often, + ;; proxies have a timeout of 60". We wait 65" in order to + ;; receive an answer this case. + (condition-case nil + (let (tramp-verbose) + (tramp-wait-for-regexp proc 65 "\r?\n\r?\n")) + (error nil)) + ;; Check return code. + (goto-char (point-min)) + (narrow-to-region + (point-min) + (or (search-forward-regexp "\r?\n\r?\n" nil t) (point-max))) + (tramp-message tramp-gw-vector 6 "\n%s" (buffer-string)) + (goto-char (point-min)) + (search-forward-regexp "^HTTP/[1-9]\\.[0-9]" nil t) + (case (condition-case nil (read (current-buffer)) (error)) + ;; Connected. + (200 (setq found t)) + ;; We need basic authentication. + (401 (setq authentication (tramp-gw-basic-authentication nil first))) + ;; Target host not found. + (404 (tramp-error-with-buffer + (current-buffer) tramp-gw-vector 'file-error + "Host %s not found." host)) + ;; We need basic proxy authentication. + (407 (setq authentication (tramp-gw-basic-authentication t first))) + ;; Connection failed. + (503 (tramp-error-with-buffer + (current-buffer) tramp-gw-vector 'file-error + "Connection to %s:%d failed." host service)) + ;; That doesn't work at all. + (t (tramp-error-with-buffer + (current-buffer) tramp-gw-vector 'file-error + "Access to HTTP server %s:%d failed." + (nth 1 socks-server) (nth 2 socks-server)))) + ;; Remove HTTP headers. + (delete-region (point-min) (point-max)) + (widen) + (setq first nil))) + ;; Return the process. + proc)) + +(defun tramp-gw-basic-authentication (proxy pw-cache) + "Return authentication header for CONNECT, based on server request. +PROXY is an indication whether we need a Proxy-Authorization header +or an Authorization header. If PW-CACHE is non-nil, check for +password in password cache. This is done for the first try only." + + ;; `tramp-current-*' must be set for `tramp-read-passwd' and + ;; `tramp-clear-passwd'. + (let ((tramp-current-method (tramp-file-name-method tramp-gw-gw-vector)) + (tramp-current-user (tramp-file-name-user tramp-gw-gw-vector)) + (tramp-current-host (tramp-file-name-host tramp-gw-gw-vector))) + (unless pw-cache (tramp-clear-passwd)) + ;; We are already in the right buffer. + (tramp-message + tramp-gw-vector 5 "%s required" + (if proxy "Proxy authentication" "Authentication")) + ;; Search for request header. We accept only basic authentication. + (goto-char (point-min)) + (search-forward-regexp + "^\\(Proxy\\|WWW\\)-Authenticate:\\s-*Basic\\s-+realm=") + ;; Return authentication string. + (format + "%s: Basic %s\r\n" + (if proxy "Proxy-Authorization" "Authorization") + (base64-encode-string + (format + "%s:%s" + socks-username + (tramp-read-passwd + proc + (format + "Password for %s@[%s]: " socks-username (read (current-buffer))))))))) + + +(provide 'tramp-gw) + +;;; TODO: + +;; * Provide descriptive Commentary. +;; * Enable it for several gateway processes in parallel. + +;; arch-tag: 277e3a81-fdee-40cf-9e6b-59626292a5e0 +;;; tramp-gw.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/tramp-smb.el --- a/lisp/net/tramp-smb.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/net/tramp-smb.el Sun Jul 15 02:05:20 2007 +0000 @@ -1,6 +1,7 @@ ;;; tramp-smb.el --- Tramp access functions for SMB servers -*- coding: iso-8859-1; -*- -;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2002, 2003, 2004, 2005, 2006, +;; 2007 Free Software Foundation, Inc. ;; Author: Michael Albinus ;; Keywords: comm, processes @@ -9,8 +10,8 @@ ;; GNU Emacs 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 2, or (at your option) -;; any later version. +;; the Free Software Foundation; either version 3 of the License, or +;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,9 +19,8 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs; see the file COPYING. If not, see +;; . ;;; Commentary: @@ -29,6 +29,7 @@ ;;; Code: (require 'tramp) +(require 'tramp-cache) ;; Pacify byte-compiler (eval-when-compile (require 'custom)) @@ -36,10 +37,8 @@ ;; Avoid byte-compiler warnings if the byte-compiler supports this. ;; Currently, XEmacs supports this. (eval-when-compile - (when (fboundp 'byte-compiler-options) - (let (unused-vars) ; Pacify Emacs byte-compiler - (defalias 'warnings 'identity) ; Pacify Emacs byte-compiler - (byte-compiler-options (warnings (- unused-vars)))))) + (when (featurep 'xemacs) + (byte-compiler-options (warnings (- unused-vars))))) ;; Define SMB method ... (defcustom tramp-smb-method "smb" @@ -53,7 +52,12 @@ ;; Add a default for `tramp-default-method-alist'. Rule: If there is ;; a domain in USER, it must be the SMB method. (add-to-list 'tramp-default-method-alist - (list "" "%" tramp-smb-method)) + `(nil "%" ,tramp-smb-method)) + +;; Add a default for `tramp-default-user-alist'. Rule: For the SMB method, +;; the anonymous user is chosen. +(add-to-list 'tramp-default-user-alist + `(,tramp-smb-method nil "")) ;; Add completion function for SMB method. (tramp-set-completion-function @@ -69,11 +73,13 @@ "Regexp used as prompt in smbclient.") (defconst tramp-smb-errors + ;; `regexp-opt' not possible because of first string. (mapconcat 'identity - '(; Connection error + '(;; Connection error / timeout "Connection to \\S-+ failed" - ; Samba + "Read from server failed, maybe it closed the connection" + ;; Samba "ERRDOS" "ERRSRV" "ERRbadfile" @@ -82,34 +88,48 @@ "ERRnoaccess" "ERRnomem" "ERRnosuchshare" - ; Windows NT 4.0, Windows 5.0 (Windows 2000), Windows 5.1 (Windows XP) + ;; Windows 4.0 (Windows NT), Windows 5.0 (Windows 2000), + ;; Windows 5.1 (Windows XP), Windows 5.2 (Windows Server 2003) "NT_STATUS_ACCESS_DENIED" "NT_STATUS_ACCOUNT_LOCKED_OUT" "NT_STATUS_BAD_NETWORK_NAME" "NT_STATUS_CANNOT_DELETE" + "NT_STATUS_DIRECTORY_NOT_EMPTY" + "NT_STATUS_DUPLICATE_NAME" + "NT_STATUS_FILE_IS_A_DIRECTORY" "NT_STATUS_LOGON_FAILURE" "NT_STATUS_NETWORK_ACCESS_DENIED" "NT_STATUS_NO_SUCH_FILE" + "NT_STATUS_OBJECT_NAME_COLLISION" "NT_STATUS_OBJECT_NAME_INVALID" "NT_STATUS_OBJECT_NAME_NOT_FOUND" "NT_STATUS_SHARING_VIOLATION" + "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE" "NT_STATUS_WRONG_PASSWORD") "\\|") "Regexp for possible error strings of SMB servers. Used instead of analyzing error codes of commands.") -(defvar tramp-smb-share nil - "Holds the share name for the current buffer. -This variable is local to each buffer.") -(make-variable-buffer-local 'tramp-smb-share) +(defconst tramp-smb-actions-with-share + '((tramp-smb-prompt tramp-action-succeed) + (tramp-password-prompt-regexp tramp-action-password) + (tramp-wrong-passwd-regexp tramp-action-permission-denied) + (tramp-smb-errors tramp-action-permission-denied) + (tramp-process-alive-regexp tramp-action-process-alive)) + "List of pattern/action pairs. +This list is used for login to SMB servers. -(defvar tramp-smb-share-cache nil - "Caches the share names accessible to host related to the current buffer. -This variable is local to each buffer.") -(make-variable-buffer-local 'tramp-smb-share-cache) +See `tramp-actions-before-shell' for more info.") -(defvar tramp-smb-inodes nil - "Keeps virtual inodes numbers for SMB files.") +(defconst tramp-smb-actions-without-share + '((tramp-password-prompt-regexp tramp-action-password) + (tramp-wrong-passwd-regexp tramp-action-permission-denied) + (tramp-smb-errors tramp-action-permission-denied) + (tramp-process-alive-regexp tramp-action-out-of-band)) + "List of pattern/action pairs. +This list is used for login to SMB servers. + +See `tramp-actions-before-shell' for more info.") ;; New handlers should be added here. (defconst tramp-smb-file-name-handler-alist @@ -124,8 +144,8 @@ (directory-file-name . tramp-handle-directory-file-name) (directory-files . tramp-smb-handle-directory-files) (directory-files-and-attributes . tramp-smb-handle-directory-files-and-attributes) - (dired-call-process . tramp-smb-not-handled) - (dired-compress-file . tramp-smb-not-handled) + (dired-call-process . ignore) + (dired-compress-file . ignore) ;; `dired-uncache' performed by default handler ;; `expand-file-name' not necessary because we cannot expand "~/" (file-accessible-directory-p . tramp-smb-handle-file-directory-p) @@ -143,10 +163,10 @@ (file-name-nondirectory . tramp-handle-file-name-nondirectory) ;; `file-name-sans-versions' performed by default handler (file-newer-than-file-p . tramp-smb-handle-file-newer-than-file-p) - (file-ownership-preserved-p . tramp-smb-not-handled) + (file-ownership-preserved-p . ignore) (file-readable-p . tramp-smb-handle-file-exists-p) (file-regular-p . tramp-handle-file-regular-p) - (file-symlink-p . tramp-smb-not-handled) + (file-symlink-p . tramp-handle-file-symlink-p) ;; `file-truename' performed by default handler (file-writable-p . tramp-smb-handle-file-writable-p) (find-backup-file-name . tramp-handle-find-backup-file-name) @@ -157,15 +177,15 @@ (load . tramp-handle-load) (make-directory . tramp-smb-handle-make-directory) (make-directory-internal . tramp-smb-handle-make-directory-internal) - (make-symbolic-link . tramp-smb-not-handled) + (make-symbolic-link . ignore) (rename-file . tramp-smb-handle-rename-file) - (set-file-modes . tramp-smb-not-handled) - (set-visited-file-modtime . tramp-smb-not-handled) - (shell-command . tramp-smb-not-handled) + (set-file-modes . ignore) + (set-visited-file-modtime . ignore) + (shell-command . ignore) (substitute-in-file-name . tramp-smb-handle-substitute-in-file-name) (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory) - (vc-registered . tramp-smb-not-handled) - (verify-visited-file-modtime . tramp-smb-not-handled) + (vc-registered . ignore) + (verify-visited-file-modtime . ignore) (write-region . tramp-smb-handle-write-region) ) "Alist of handler functions for Tramp SMB method. @@ -174,13 +194,7 @@ (defun tramp-smb-file-name-p (filename) "Check if it's a filename for SMB servers." (let ((v (tramp-dissect-file-name filename))) - (string= - (tramp-find-method - (tramp-file-name-multi-method v) - (tramp-file-name-method v) - (tramp-file-name-user v) - (tramp-file-name-host v)) - tramp-smb-method))) + (string= (tramp-file-name-method v) tramp-smb-method))) (defun tramp-smb-file-name-handler (operation &rest args) "Invoke the SMB related OPERATION. @@ -188,9 +202,7 @@ pass to the OPERATION." (let ((fn (assoc operation tramp-smb-file-name-handler-alist))) (if fn - (if (eq (cdr fn) 'tramp-smb-not-handled) - (apply (cdr fn) operation args) - (save-match-data (apply (cdr fn) args))) + (save-match-data (apply (cdr fn) args)) (tramp-run-real-handler operation args)))) (add-to-list 'tramp-foreign-file-name-handler-alist @@ -199,14 +211,9 @@ ;; File name primitives -(defun tramp-smb-not-handled (operation &rest args) - "Default handler for all functions which are disrecarded." - (tramp-message 10 "Won't be handled: %s %s" operation args) - nil) - (defun tramp-smb-handle-copy-file (filename newname &optional ok-if-already-exists keep-date) - "Like `copy-file' for tramp files. + "Like `copy-file' for Tramp files. KEEP-DATE is not handled in case NEWNAME resides on an SMB server." (setq filename (expand-file-name filename) newname (expand-file-name newname)) @@ -214,199 +221,187 @@ (let ((tmpfile (file-local-copy filename))) (if tmpfile - ;; remote filename + ;; Remote filename. (rename-file tmpfile newname ok-if-already-exists) - ;; remote newname + ;; Remote newname. (when (file-directory-p newname) (setq newname (expand-file-name (file-name-nondirectory filename) newname))) - (when (and (not ok-if-already-exists) - (file-exists-p newname)) - (error "copy-file: file %s already exists" newname)) (with-parsed-tramp-file-name newname nil - (save-excursion - (let ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname t))) - (unless share - (error "Target `%s' must contain a share name" filename)) - (tramp-smb-maybe-open-connection user host share) - (tramp-message-for-buffer - nil tramp-smb-method user host - 5 "Copying file %s to file %s..." filename newname) - (if (tramp-smb-send-command - user host (format "put %s \"%s\"" filename file)) - (tramp-message-for-buffer - nil tramp-smb-method user host - 5 "Copying file %s to file %s...done" filename newname) - (error "Cannot copy `%s'" filename)))))))) + (when (and (not ok-if-already-exists) + (file-exists-p newname)) + (tramp-error v 'file-already-exists newname)) + + ;; We must also flush the cache of the directory, because + ;; file-attributes reads the values from there. + (tramp-flush-file-property v (file-name-directory localname)) + (tramp-flush-file-property v localname) + (let ((share (tramp-smb-get-share localname)) + (file (tramp-smb-get-localname localname t))) + (unless share + (tramp-error + v 'file-error "Target `%s' must contain a share name" newname)) + (tramp-message v 0 "Copying file %s to file %s..." filename newname) + (if (tramp-smb-send-command + v (format "put %s \"%s\"" filename file)) + (tramp-message + v 0 "Copying file %s to file %s...done" filename newname) + (tramp-error v 'file-error "Cannot copy `%s'" filename))))))) (defun tramp-smb-handle-delete-directory (directory) - "Like `delete-directory' for tramp files." + "Like `delete-directory' for Tramp files." (setq directory (directory-file-name (expand-file-name directory))) (when (file-exists-p directory) (with-parsed-tramp-file-name directory nil - (save-excursion - (let ((share (tramp-smb-get-share localname)) - (dir (tramp-smb-get-localname (file-name-directory localname) t)) - (file (file-name-nondirectory localname))) - (tramp-smb-maybe-open-connection user host share) - (if (and - (tramp-smb-send-command user host (format "cd \"%s\"" dir)) - (tramp-smb-send-command user host (format "rmdir \"%s\"" file))) - ;; Go Home - (tramp-smb-send-command user host (format "cd \\")) - ;; Error - (tramp-smb-send-command user host (format "cd \\")) - (error "Cannot delete directory `%s'" directory))))))) + ;; We must also flush the cache of the directory, because + ;; file-attributes reads the values from there. + (tramp-flush-file-property v (file-name-directory localname)) + (tramp-flush-directory-property v localname) + (let ((dir (tramp-smb-get-localname (file-name-directory localname) t)) + (file (file-name-nondirectory localname))) + (unwind-protect + (unless (and + (tramp-smb-send-command v (format "cd \"%s\"" dir)) + (tramp-smb-send-command v (format "rmdir \"%s\"" file))) + ;; Error + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (search-forward-regexp tramp-smb-errors nil t) + (tramp-error + v 'file-error "%s `%s'" (match-string 0) directory))) + ;; Always go home + (tramp-smb-send-command v (format "cd \\"))))))) (defun tramp-smb-handle-delete-file (filename) - "Like `delete-file' for tramp files." + "Like `delete-file' for Tramp files." (setq filename (expand-file-name filename)) (when (file-exists-p filename) (with-parsed-tramp-file-name filename nil - (save-excursion - (let ((share (tramp-smb-get-share localname)) - (dir (tramp-smb-get-localname (file-name-directory localname) t)) - (file (file-name-nondirectory localname))) - (tramp-smb-maybe-open-connection user host share) - (if (and - (tramp-smb-send-command user host (format "cd \"%s\"" dir)) - (tramp-smb-send-command user host (format "rm \"%s\"" file))) - ;; Go Home - (tramp-smb-send-command user host (format "cd \\")) - ;; Error - (tramp-smb-send-command user host (format "cd \\")) - (error "Cannot delete file `%s'" filename))))))) + ;; We must also flush the cache of the directory, because + ;; file-attributes reads the values from there. + (tramp-flush-file-property v (file-name-directory localname)) + (tramp-flush-file-property v localname) + (let ((dir (tramp-smb-get-localname (file-name-directory localname) t)) + (file (file-name-nondirectory localname))) + (unwind-protect + (unless (and + (tramp-smb-send-command v (format "cd \"%s\"" dir)) + (tramp-smb-send-command v (format "rm \"%s\"" file))) + ;; Error + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (search-forward-regexp tramp-smb-errors nil t) + (tramp-error + v 'file-error "%s `%s'" (match-string 0) filename))) + ;; Always go home + (tramp-smb-send-command v (format "cd \\"))))))) (defun tramp-smb-handle-directory-files (directory &optional full match nosort) - "Like `directory-files' for tramp files." - (setq directory (directory-file-name (expand-file-name directory))) - (with-parsed-tramp-file-name directory nil - (save-excursion - (let* ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname nil)) - (entries (tramp-smb-get-file-entries user host share file))) - ;; Just the file names are needed - (setq entries (mapcar 'car entries)) - ;; Discriminate with regexp - (when match - (setq entries - (delete nil - (mapcar (lambda (x) (when (string-match match x) x)) - entries)))) - ;; Make absolute localnames if necessary - (when full - (setq entries - (mapcar (lambda (x) - (concat (file-name-as-directory directory) x)) - entries))) - ;; Sort them if necessary - (unless nosort (setq entries (sort entries 'string-lessp))) - ;; That's it - entries)))) + "Like `directory-files' for Tramp files." + (let ((result (mapcar 'directory-file-name + (file-name-all-completions "" directory)))) + ;; Discriminate with regexp + (when match + (setq result + (delete nil + (mapcar (lambda (x) (when (string-match match x) x)) + result)))) + ;; Append directory + (when full + (setq result + (mapcar + (lambda (x) (expand-file-name x directory)) + result))) + ;; Sort them if necessary + (unless nosort (setq result (sort result 'string-lessp))) + ;; That's it + result)) (defun tramp-smb-handle-directory-files-and-attributes (directory &optional full match nosort id-format) - "Like `directory-files-and-attributes' for tramp files." + "Like `directory-files-and-attributes' for Tramp files." (mapcar (lambda (x) ;; We cannot call `file-attributes' for backward compatibility reasons. ;; Its optional parameter ID-FORMAT is introduced with Emacs 22. (cons x (tramp-smb-handle-file-attributes - (if full x (concat (file-name-as-directory directory) x)) id-format))) + (if full x (expand-file-name x directory)) id-format))) (directory-files directory full match nosort))) (defun tramp-smb-handle-file-attributes (filename &optional id-format) - "Like `file-attributes' for tramp files." + "Like `file-attributes' for Tramp files." + ;; Reading just the filename entry via "dir localname" is not + ;; possible, because when filename is a directory, some smbclient + ;; versions return the content of the directory, and other versions + ;; don't. Therefore, the whole content of the upper directory is + ;; retrieved, and the entry of the filename is extracted from. (with-parsed-tramp-file-name filename nil - (save-excursion - (let* ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname nil)) - (entries (tramp-smb-get-file-entries user host share file)) + (with-file-property v localname (format "file-attributes-%s" id-format) + (let* ((entries (tramp-smb-get-file-entries + (file-name-directory filename))) (entry (and entries - (assoc (file-name-nondirectory file) entries))) + (assoc (file-name-nondirectory filename) entries))) (uid (if (and id-format (equal id-format 'string)) "nobody" -1)) (gid (if (and id-format (equal id-format 'string)) "nogroup" -1)) - (inode (tramp-smb-get-inode share file)) - (device (tramp-get-device nil tramp-smb-method user host))) + (inode (tramp-get-inode filename)) + (device (tramp-get-device v))) - ; check result + ;; Check result. (when entry (list (and (string-match "d" (nth 1 entry)) - t) ;0 file type - -1 ;1 link count - uid ;2 uid - gid ;3 gid - '(0 0) ;4 atime - (nth 3 entry) ;5 mtime - '(0 0) ;6 ctime - (nth 2 entry) ;7 size - (nth 1 entry) ;8 mode - nil ;9 gid weird - inode ;10 inode number - device)))))) ;11 file system number + t) ;0 file type + -1 ;1 link count + uid ;2 uid + gid ;3 gid + '(0 0) ;4 atime + (nth 3 entry) ;5 mtime + '(0 0) ;6 ctime + (nth 2 entry) ;7 size + (nth 1 entry) ;8 mode + nil ;9 gid weird + inode ;10 inode number + device)))))) ;11 file system number (defun tramp-smb-handle-file-directory-p (filename) - "Like `file-directory-p' for tramp files." - (with-parsed-tramp-file-name filename nil - (save-excursion - (let* ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname nil)) - (entries (tramp-smb-get-file-entries user host share file)) - (entry (and entries - (assoc (file-name-nondirectory file) entries)))) - (and entry - (string-match "d" (nth 1 entry)) - t))))) + "Like `file-directory-p' for Tramp files." + (and (file-exists-p filename) + (eq ?d (aref (nth 8 (file-attributes filename)) 0)))) (defun tramp-smb-handle-file-exists-p (filename) - "Like `file-exists-p' for tramp files." - (with-parsed-tramp-file-name filename nil - (save-excursion - (let* ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname nil)) - (entries (tramp-smb-get-file-entries user host share file))) - (and entries - (member (file-name-nondirectory file) (mapcar 'car entries)) - t))))) + "Like `file-exists-p' for Tramp files." + (not (null (file-attributes filename)))) (defun tramp-smb-handle-file-local-copy (filename) - "Like `file-local-copy' for tramp files." + "Like `file-local-copy' for Tramp files." (with-parsed-tramp-file-name filename nil - (save-excursion - (let ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname t)) - (tmpfil (tramp-make-temp-file filename))) - (unless (file-exists-p filename) - (error "Cannot make local copy of non-existing file `%s'" filename)) - (tramp-message-for-buffer - nil tramp-smb-method user host - 5 "Fetching %s to tmp file %s..." filename tmpfil) - (tramp-smb-maybe-open-connection user host share) - (if (tramp-smb-send-command - user host (format "get \"%s\" %s" file tmpfil)) - (tramp-message-for-buffer - nil tramp-smb-method user host - 5 "Fetching %s to tmp file %s...done" filename tmpfil) - (error "Cannot make local copy of file `%s'" filename)) - tmpfil)))) + (let ((file (tramp-smb-get-localname localname t)) + (tmpfil (tramp-make-temp-file filename))) + (unless (file-exists-p filename) + (tramp-error + v 'file-error + "Cannot make local copy of non-existing file `%s'" filename)) + (tramp-message v 4 "Fetching %s to tmp file %s..." filename tmpfil) + (if (tramp-smb-send-command v (format "get \"%s\" %s" file tmpfil)) + (tramp-message + v 4 "Fetching %s to tmp file %s...done" filename tmpfil) + (tramp-error + v 'file-error + "Cannot make local copy of file `%s'" filename)) + tmpfil))) ;; This function should return "foo/" for directories and "bar" for ;; files. (defun tramp-smb-handle-file-name-all-completions (filename directory) - "Like `file-name-all-completions' for tramp files." - (with-parsed-tramp-file-name directory nil - (save-match-data - (save-excursion - (let* ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname nil)) - (entries (tramp-smb-get-file-entries user host share file))) - - (all-completions - filename + "Like `file-name-all-completions' for Tramp files." + (all-completions + filename + (with-parsed-tramp-file-name directory nil + (with-file-property v localname "file-name-all-completions" + (save-match-data + (let ((entries (tramp-smb-get-file-entries directory))) (mapcar (lambda (x) (list @@ -416,51 +411,59 @@ entries))))))) (defun tramp-smb-handle-file-newer-than-file-p (file1 file2) - "Like `file-newer-than-file-p' for tramp files." + "Like `file-newer-than-file-p' for Tramp files." (cond ((not (file-exists-p file1)) nil) ((not (file-exists-p file2)) t) - (t (tramp-smb-time-less-p (file-attributes file2) - (file-attributes file1))))) + (t (tramp-time-less-p (nth 5 (file-attributes file2)) + (nth 5 (file-attributes file1)))))) (defun tramp-smb-handle-file-writable-p (filename) - "Like `file-writable-p' for tramp files." - (if (not (file-exists-p filename)) - (let ((dir (file-name-directory filename))) - (and (file-exists-p dir) - (file-writable-p dir))) - (with-parsed-tramp-file-name filename nil - (save-excursion - (let* ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname nil)) - (entries (tramp-smb-get-file-entries user host share file)) - (entry (and entries - (assoc (file-name-nondirectory file) entries)))) - (and share entry - (string-match "w" (nth 1 entry)) - t)))))) + "Like `file-writable-p' for Tramp files." + (if (file-exists-p filename) + (string-match "w" (or (nth 8 (file-attributes filename)) "")) + (let ((dir (file-name-directory filename))) + (and (file-exists-p dir) + (file-writable-p dir))))) (defun tramp-smb-handle-insert-directory (filename switches &optional wildcard full-directory-p) - "Like `insert-directory' for tramp files. -WILDCARD and FULL-DIRECTORY-P are not handled." + "Like `insert-directory' for Tramp files." (setq filename (expand-file-name filename)) - (when (file-directory-p filename) - ;; This check is a little bit strange, but in `dired-add-entry' - ;; this function is called with a non-directory ... + (when full-directory-p + ;; Called from `dired-add-entry'. (setq filename (file-name-as-directory filename))) (with-parsed-tramp-file-name filename nil + (tramp-flush-file-property v (file-name-directory localname)) (save-match-data - (let* ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname nil)) - (entries (tramp-smb-get-file-entries user host share file))) + (let ((base (file-name-nondirectory filename)) + ;; We should not destroy the cache entry. + (entries (copy-sequence + (tramp-smb-get-file-entries + (file-name-directory filename))))) - ;; Delete dummy "" entry, useless entries + (when wildcard + (string-match "\\." base) + (setq base (replace-match "\\\\." nil nil base)) + (string-match "\\*" base) + (setq base (replace-match ".*" nil nil base)) + (string-match "\\?" base) + (setq base (replace-match ".?" nil nil base))) + + ;; Filter entries. (setq entries - (if (file-directory-p filename) - (delq (assoc "" entries) entries) - ;; We just need the only and only entry FILENAME. - (list (assoc (file-name-nondirectory filename) entries)))) + (delq + nil + (if (or wildcard (zerop (length base))) + ;; Check for matching entries. + (mapcar + (lambda (x) + (when (string-match + (format "^%s" base) (nth 0 x)) + x)) + entries) + ;; We just need the only and only entry FILENAME. + (list (assoc base entries))))) ;; Sort entries (setq entries @@ -468,37 +471,38 @@ entries (lambda (x y) (if (string-match "t" switches) - ; sort by date - (tramp-smb-time-less-p (nth 3 y) (nth 3 x)) - ; sort by name + ;; Sort by date. + (tramp-time-less-p (nth 3 y) (nth 3 x)) + ;; Sort by name. (string-lessp (nth 0 x) (nth 0 y)))))) - ;; Print entries + ;; Print entries. (mapcar (lambda (x) - (insert - (format - "%10s %3d %-8s %-8s %8s %s %s\n" - (nth 1 x) ; mode - 1 "nobody" "nogroup" - (nth 2 x) ; size - (format-time-string - (if (tramp-smb-time-less-p - (tramp-smb-time-subtract (current-time) (nth 3 x)) - tramp-smb-half-a-year) - "%b %e %R" - "%b %e %Y") - (nth 3 x)) ; date - (nth 0 x))) ; file name - (forward-line) - (beginning-of-line)) - entries))))) + (when (not (zerop (length (nth 0 x)))) + (insert + (format + "%10s %3d %-8s %-8s %8s %s %s\n" + (nth 1 x) ; mode + 1 "nobody" "nogroup" + (nth 2 x) ; size + (format-time-string + (if (tramp-time-less-p + (tramp-time-subtract (current-time) (nth 3 x)) + tramp-half-a-year) + "%b %e %R" + "%b %e %Y") + (nth 3 x)) ; date + (nth 0 x))) ; file name + (forward-line) + (beginning-of-line))) + entries))))) (defun tramp-smb-handle-make-directory (dir &optional parents) - "Like `make-directory' for tramp files." + "Like `make-directory' for Tramp files." (setq dir (directory-file-name (expand-file-name dir))) (unless (file-name-absolute-p dir) - (setq dir (concat default-directory dir))) + (setq dir (expand-file-name dir default-directory))) (with-parsed-tramp-file-name dir nil (save-match-data (let* ((share (tramp-smb-get-share localname)) @@ -510,26 +514,28 @@ (when (file-directory-p ldir) (make-directory-internal dir)) (unless (file-directory-p dir) - (error "Couldn't make directory %s" dir)))))) + (tramp-error v 'file-error "Couldn't make directory %s" dir)))))) (defun tramp-smb-handle-make-directory-internal (directory) - "Like `make-directory-internal' for tramp files." + "Like `make-directory-internal' for Tramp files." (setq directory (directory-file-name (expand-file-name directory))) (unless (file-name-absolute-p directory) - (setq directory (concat default-directory directory))) + (setq directory (expand-file-name directory default-directory))) (with-parsed-tramp-file-name directory nil (save-match-data - (let* ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname nil))) + (let* ((file (tramp-smb-get-localname localname t))) (when (file-directory-p (file-name-directory directory)) - (tramp-smb-maybe-open-connection user host share) - (tramp-smb-send-command user host (format "mkdir \"%s\"" file))) + (tramp-smb-send-command v (format "mkdir \"%s\"" file)) + ;; We must also flush the cache of the directory, because + ;; file-attributes reads the values from there. + (tramp-flush-file-property v (file-name-directory localname))) (unless (file-directory-p directory) - (error "Couldn't make directory %s" directory)))))) + (tramp-error + v 'file-error "Couldn't make directory %s" directory)))))) (defun tramp-smb-handle-rename-file (filename newname &optional ok-if-already-exists) - "Like `rename-file' for tramp files." + "Like `rename-file' for Tramp files." (setq filename (expand-file-name filename) newname (expand-file-name newname)) @@ -543,29 +549,26 @@ (when (file-directory-p newname) (setq newname (expand-file-name (file-name-nondirectory filename) newname))) - (when (and (not ok-if-already-exists) - (file-exists-p newname)) - (error "rename-file: file %s already exists" newname)) (with-parsed-tramp-file-name newname nil - (save-excursion - (let ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname t))) - (tramp-smb-maybe-open-connection user host share) - (tramp-message-for-buffer - nil tramp-smb-method user host - 5 "Copying file %s to file %s..." filename newname) - (if (tramp-smb-send-command - user host (format "put %s \"%s\"" filename file)) - (tramp-message-for-buffer - nil tramp-smb-method user host - 5 "Copying file %s to file %s...done" filename newname) - (error "Cannot rename `%s'" filename))))))) + (when (and (not ok-if-already-exists) + (file-exists-p newname)) + (tramp-error v 'file-already-exists newname)) + ;; We must also flush the cache of the directory, because + ;; file-attributes reads the values from there. + (tramp-flush-file-property v (file-name-directory localname)) + (tramp-flush-file-property v localname) + (let ((file (tramp-smb-get-localname localname t))) + (tramp-message v 0 "Copying file %s to file %s..." filename newname) + (if (tramp-smb-send-command v (format "put %s \"%s\"" filename file)) + (tramp-message + v 0 "Copying file %s to file %s...done" filename newname) + (tramp-error v 'file-error "Cannot rename `%s'" filename)))))) (delete-file filename)) (defun tramp-smb-handle-substitute-in-file-name (filename) - "Like `handle-substitute-in-file-name' for tramp files. + "Like `handle-substitute-in-file-name' for Tramp files. Catches errors for shares like \"C$/\", which are common in Microsoft Windows." (condition-case nil (tramp-run-real-handler 'substitute-in-file-name (list filename)) @@ -573,50 +576,49 @@ (defun tramp-smb-handle-write-region (start end filename &optional append visit lockname confirm) - "Like `write-region' for tramp files." - (unless (eq append nil) - (error "Cannot append to file using tramp (`%s')" filename)) + "Like `write-region' for Tramp files." (setq filename (expand-file-name filename)) - ;; XEmacs takes a coding system as the seventh argument, not `confirm' - (when (and (not (featurep 'xemacs)) - confirm (file-exists-p filename)) - (unless (y-or-n-p (format "File %s exists; overwrite anyway? " - filename)) - (error "File not overwritten"))) (with-parsed-tramp-file-name filename nil - (save-excursion - (let ((share (tramp-smb-get-share localname)) - (file (tramp-smb-get-localname localname t)) - (curbuf (current-buffer)) - tmpfil) - ;; Write region into a tmp file. - (setq tmpfil (tramp-make-temp-file filename)) - ;; We say `no-message' here because we don't want the visited file - ;; modtime data to be clobbered from the temp file. We call - ;; `set-visited-file-modtime' ourselves later on. - (tramp-run-real-handler - 'write-region - (if confirm ; don't pass this arg unless defined for backward compat. - (list start end tmpfil append 'no-message lockname confirm) - (list start end tmpfil append 'no-message lockname))) + (unless (eq append nil) + (tramp-error + v 'file-error "Cannot append to file using tramp (`%s')" filename)) + ;; XEmacs takes a coding system as the seventh argument, not `confirm' + (when (and (not (featurep 'xemacs)) + confirm (file-exists-p filename)) + (unless (y-or-n-p (format "File %s exists; overwrite anyway? " + filename)) + (tramp-error v 'file-error "File not overwritten"))) + ;; We must also flush the cache of the directory, because + ;; file-attributes reads the values from there. + (tramp-flush-file-property v (file-name-directory localname)) + (tramp-flush-file-property v localname) + (let ((file (tramp-smb-get-localname localname t)) + (curbuf (current-buffer)) + tmpfil) + ;; Write region into a tmp file. + (setq tmpfil (tramp-make-temp-file filename)) + ;; We say `no-message' here because we don't want the visited file + ;; modtime data to be clobbered from the temp file. We call + ;; `set-visited-file-modtime' ourselves later on. + (tramp-run-real-handler + 'write-region + (if confirm ; don't pass this arg unless defined for backward compat. + (list start end tmpfil append 'no-message lockname confirm) + (list start end tmpfil append 'no-message lockname))) - (tramp-smb-maybe-open-connection user host share) - (tramp-message-for-buffer - nil tramp-smb-method user host - 5 "Writing tmp file %s to file %s..." tmpfil filename) - (if (tramp-smb-send-command - user host (format "put %s \"%s\"" tmpfil file)) - (tramp-message-for-buffer - nil tramp-smb-method user host - 5 "Writing tmp file %s to file %s...done" tmpfil filename) - (error "Cannot write `%s'" filename)) + (tramp-message v 5 "Writing tmp file %s to file %s..." tmpfil filename) + (if (tramp-smb-send-command v (format "put %s \"%s\"" tmpfil file)) + (tramp-message + v 5 "Writing tmp file %s to file %s...done" tmpfil filename) + (tramp-error v 'file-error "Cannot write `%s'" filename)) - (delete-file tmpfil) - (unless (equal curbuf (current-buffer)) - (error "Buffer has changed from `%s' to `%s'" - curbuf (current-buffer))) - (when (eq visit t) - (set-visited-file-modtime)))))) + (delete-file tmpfil) + (unless (equal curbuf (current-buffer)) + (tramp-error + v 'file-error + "Buffer has changed from `%s' to `%s'" curbuf (current-buffer))) + (when (eq visit t) + (set-visited-file-modtime))))) ;; Internal file name functions @@ -652,51 +654,53 @@ ;; Share names of a host are cached. It is very unlikely that the ;; shares do change during connection. -(defun tramp-smb-get-file-entries (user host share localname) - "Read entries which match LOCALNAME. +(defun tramp-smb-get-file-entries (directory) + "Read entries which match DIRECTORY. Either the shares are listed, or the `dir' command is executed. -Only entries matching the localname are returned. Result is a list of (LOCALNAME MODE SIZE MONTH DAY TIME YEAR)." - (save-excursion - (save-match-data - (let ((base (or (and (> (length localname) 0) - (string-match "\\([^/]+\\)$" localname) - (regexp-quote (match-string 1 localname))) - "")) - res entry) - (set-buffer (tramp-get-buffer nil tramp-smb-method user host)) - (if (and (not share) tramp-smb-share-cache) - ;; Return cached shares - (setq res tramp-smb-share-cache) - ;; Read entries - (tramp-smb-maybe-open-connection user host share) - (when share - (tramp-smb-send-command - user host - (format "dir %s" - (if (zerop (length localname)) "" (concat "\"" localname "*\""))))) - (goto-char (point-min)) - ;; Loop the listing - (unless (re-search-forward tramp-smb-errors nil t) - (while (not (eobp)) - (setq entry (tramp-smb-read-file-entry share)) - (forward-line) - (when entry (add-to-list 'res entry)))) - (unless share + (with-parsed-tramp-file-name directory nil + (setq localname (or localname "/")) + (with-file-property v localname "file-entries" + (with-current-buffer (tramp-get-buffer v) + (let* ((share (tramp-smb-get-share localname)) + (file (tramp-smb-get-localname localname nil)) + (cache (tramp-get-connection-property v "share-cache" nil)) + res entry) + + (if (and (not share) cache) + ;; Return cached shares + (setq res cache) + + ;; Read entries + (setq file (file-name-as-directory file)) + (when (string-match "^\\./" file) + (setq file (substring file 1))) + (if share + (tramp-smb-send-command v (format "dir \"%s*\"" file)) + ;; `tramp-smb-maybe-open-connection' lists also the share names + (tramp-smb-maybe-open-connection v)) + + ;; Loop the listing + (goto-char (point-min)) + (unless (re-search-forward tramp-smb-errors nil t) + (while (not (eobp)) + (setq entry (tramp-smb-read-file-entry share)) + (forward-line) + (when entry (add-to-list 'res entry)))) + ;; Cache share entries - (setq tramp-smb-share-cache res))) + (unless share + (tramp-set-connection-property v "share-cache" res))) - ;; Add directory itself - (add-to-list 'res '("" "drwxrwxrwx" 0 (0 0))) + ;; Add directory itself + (add-to-list 'res '("" "drwxrwxrwx" 0 (0 0))) - ;; There's a very strange error (debugged with XEmacs 21.4.14) - ;; If there's no short delay, it returns nil. No idea about - (when (featurep 'xemacs) (sleep-for 0.01)) + ;; There's a very strange error (debugged with XEmacs 21.4.14) + ;; If there's no short delay, it returns nil. No idea about. + (when (featurep 'xemacs) (sleep-for 0.01)) - ;; Check for matching entries - (delq nil (mapcar - (lambda (x) (and (string-match base (nth 0 x)) x)) - res)))))) + ;; Return entries + (delq nil res)))))) ;; Return either a share name (if SHARE is nil), or a file name ;; @@ -721,7 +725,7 @@ ;; \s- - space delimeter ;; \w\{3,3\} - month ;; \s- - space delimeter -;; [ 19][0-9] - day +;; [ 12][0-9] - day ;; \s- - space delimeter ;; [0-9]\{2,2\}:[0-9]\{2,2\}:[0-9]\{2,2\} - time ;; \s- - space delimeter @@ -756,18 +760,20 @@ "Parse entry in SMB output buffer. If SHARE is result, entries are of type dir. Otherwise, shares are listed. Result is the list (LOCALNAME MODE SIZE MTIME)." - (let ((line (buffer-substring (point) (tramp-point-at-eol))) +;; We are called from `tramp-smb-get-file-entries', which sets the +;; current buffer. + (let ((line (buffer-substring (point) (tramp-line-end-position))) localname mode size month day hour min sec year mtime) (if (not share) - ; Read share entries - (when (string-match "^\\s-+\\(\\S-+\\)\\s-+Disk" line) + ;; Read share entries. + (when (string-match "^\\s-+\\(\\S-\\(.*\\S-\\)?\\)\\s-+Disk" line) (setq localname (match-string 1 line) mode "dr-xr-xr-x" size 0)) - ; Real listing + ;; Real listing. (block nil ;; year @@ -833,219 +839,186 @@ (if (and sec min hour day month year) (encode-time sec min hour day - (cdr (assoc (downcase month) tramp-smb-parse-time-months)) + (cdr (assoc (downcase month) tramp-parse-time-months)) year) '(0 0))) (list localname mode size mtime)))) -;; Inodes don't exist for SMB files. Therefore we must generate virtual ones. -;; Used in `find-buffer-visiting'. -;; The method applied might be not so efficient (Ange-FTP uses hashes). But -;; performance isn't the major issue given that file transfer will take time. - -(defun tramp-smb-get-inode (share file) - "Returns the virtual inode number. -If it doesn't exist, generate a new one." - (let ((string (concat share "/" (directory-file-name file)))) - (unless (assoc string tramp-smb-inodes) - (add-to-list 'tramp-smb-inodes - (list string (length tramp-smb-inodes)))) - (nth 1 (assoc string tramp-smb-inodes)))) - ;; Connection functions -(defun tramp-smb-send-command (user host command) - "Send the COMMAND to USER at HOST (logged into an SMB session). -Erases temporary buffer before sending the command. Returns nil if -there has been an error message from smbclient." - (save-excursion - (set-buffer (tramp-get-buffer nil tramp-smb-method user host)) - (erase-buffer) - (tramp-send-command nil tramp-smb-method user host command nil t) - (tramp-smb-wait-for-output user host))) +(defun tramp-smb-send-command (vec command) + "Send the COMMAND to connection VEC. +Returns nil if there has been an error message from smbclient." + (tramp-smb-maybe-open-connection vec) + (tramp-message vec 6 "%s" command) + (tramp-send-string vec command) + (tramp-smb-wait-for-output vec)) -(defun tramp-smb-maybe-open-connection (user host share) - "Maybe open a connection to HOST, logging in as USER, using `tramp-smb-program'. +(defun tramp-smb-maybe-open-connection (vec) + "Maybe open a connection to HOST, log in as USER, using `tramp-smb-program'. Does not do anything if a connection is already open, but re-opens the connection if a previous connection has died for some reason." - (let ((process-connection-type tramp-process-connection-type) - (p (get-buffer-process - (tramp-get-buffer nil tramp-smb-method user host)))) - (save-excursion - (set-buffer (tramp-get-buffer nil tramp-smb-method user host)) - ;; Check whether it is still the same share - (unless (and p (processp p) (string-equal tramp-smb-share share)) - (when (and p (processp p)) - (delete-process p) - (setq p nil))) - ;; If too much time has passed since last command was sent, look - ;; whether process is still alive. If it isn't, kill it. - (when (and tramp-last-cmd-time - (> (tramp-time-diff (current-time) tramp-last-cmd-time) 60) - p (processp p) (memq (process-status p) '(run open))) - (unless (and p (processp p) (memq (process-status p) '(run open))) - (delete-process p) - (setq p nil)))) - (unless (and p (processp p) (memq (process-status p) '(run open))) - (when (and p (processp p)) - (delete-process p)) - (tramp-smb-open-connection user host share)))) + (let* ((share (tramp-smb-get-share (tramp-file-name-localname vec))) + (buf (tramp-get-buffer vec)) + (p (get-buffer-process buf))) + + ;; If too much time has passed since last command was sent, look + ;; whether has been an error message; maybe due to connection timeout. + (with-current-buffer buf + (goto-char (point-min)) + (when (and (> (tramp-time-diff + (current-time) + (tramp-get-connection-property + p "last-cmd-time" '(0 0 0))) + 60) + p (processp p) (memq (process-status p) '(run open)) + (re-search-forward tramp-smb-errors nil t)) + (delete-process p) + (setq p nil))) + + ;; Check whether it is still the same share. + (unless + (and p (processp p) (memq (process-status p) '(run open)) + (string-equal + share + (tramp-get-connection-property p "smb-share" ""))) -(defun tramp-smb-open-connection (user host share) - "Open a connection using `tramp-smb-program'. -This starts the command `smbclient //HOST/SHARE -U USER', then waits -for a remote password prompt. It queries the user for the password, -then sends the password to the remote host. + (save-match-data + ;; There might be unread output from checking for share names. + (when buf (with-current-buffer buf (erase-buffer))) + (when (and p (processp p)) (delete-process p)) -Domain names in USER and port numbers in HOST are acknowledged." + (unless (let ((default-directory + (tramp-temporary-file-directory))) + (executable-find tramp-smb-program)) + (error "Cannot find command %s in %s" tramp-smb-program exec-path)) - (when (and (fboundp 'executable-find) - (not (funcall 'executable-find tramp-smb-program))) - (error "Cannot find command %s in %s" tramp-smb-program exec-path)) + (let* ((user (tramp-file-name-user vec)) + (host (tramp-file-name-host vec)) + (real-user user) + (real-host host) + domain port args) - (save-match-data - (let* ((buffer (tramp-get-buffer nil tramp-smb-method user host)) - (real-user user) - (real-host host) - domain port args) + ;; Check for domain ("user%domain") and port ("host#port"). + (when (and user (string-match "\\(.+\\)%\\(.+\\)" user)) + (setq real-user (or (match-string 1 user) user) + domain (match-string 2 user))) - ; Check for domain ("user%domain") and port ("host#port") - (when (and user (string-match "\\(.+\\)%\\(.+\\)" user)) - (setq real-user (or (match-string 1 user) user) - domain (match-string 2 user))) + (when (and host (string-match "\\(.+\\)#\\(.+\\)" host)) + (setq real-host (or (match-string 1 host) host) + port (match-string 2 host))) - (when (and host (string-match "\\(.+\\)#\\(.+\\)" host)) - (setq real-host (or (match-string 1 host) host) - port (match-string 2 host))) + (if share + (setq args (list (concat "//" real-host "/" share))) + (setq args (list "-L" real-host ))) - (if share - (setq args (list (concat "//" real-host "/" share))) - (setq args (list "-L" real-host ))) + (if (not (zerop (length real-user))) + (setq args (append args (list "-U" real-user))) + (setq args (append args (list "-N")))) + + (when domain (setq args (append args (list "-W" domain)))) + (when port (setq args (append args (list "-p" port)))) + (setq args (append args (list "-s" "/dev/null"))) - (if real-user - (setq args (append args (list "-U" real-user))) - (setq args (append args (list "-N")))) + ;; OK, let's go. + (tramp-message + vec 3 "Opening connection for //%s%s/%s..." + (if (not (zerop (length user))) (concat user "@") "") + host (or share "")) - (when domain (setq args (append args (list "-W" domain)))) - (when port (setq args (append args (list "-p" port)))) - - ; OK, let's go - (tramp-pre-connection nil tramp-smb-method user host tramp-chunksize) - (tramp-message 7 "Opening connection for //%s@%s/%s..." - user host (or share "")) + (let* ((coding-system-for-read nil) + (process-connection-type tramp-process-connection-type) + (p (let ((default-directory (tramp-temporary-file-directory))) + (apply #'start-process + (tramp-buffer-name vec) (tramp-get-buffer vec) + tramp-smb-program args)))) - (let* ((default-directory (tramp-temporary-file-directory)) - ;; If we omit the conditional here, then we would use - ;; `undecided-dos' in some cases. With the conditional, - ;; we use nil in these cases. Which one is right? - (coding-system-for-read (unless (and (not (featurep 'xemacs)) - (> emacs-major-version 20)) - tramp-dos-coding-system)) - (p (apply #'start-process (buffer-name buffer) buffer - tramp-smb-program args))) + (tramp-message + vec 6 "%s" (mapconcat 'identity (process-command p) " ")) + (set-process-sentinel p 'tramp-flush-connection-property) + (tramp-set-process-query-on-exit-flag p nil) + (tramp-set-connection-property p "smb-share" share) + + ;; Set variables for computing the prompt for reading password. + (setq tramp-current-method tramp-smb-method + tramp-current-user user + tramp-current-host host) - (tramp-message 9 "Started process %s" (process-command p)) - (tramp-set-process-query-on-exit-flag p nil) - (set-buffer buffer) - (setq tramp-smb-share share) + ;; Set chunksize. Otherwise, `tramp-send-string' might + ;; try it itself. + (tramp-set-connection-property p "chunksize" tramp-chunksize) - ; send password - (when real-user - (let ((pw-prompt "Password:")) - (tramp-message 9 "Sending password") - (tramp-enter-password p pw-prompt user host))) + ;; Play login scenario. + (tramp-process-actions + p vec + (if share + tramp-smb-actions-with-share + tramp-smb-actions-without-share)) - (unless (tramp-smb-wait-for-output user host) - (tramp-clear-passwd user host) - (error "Cannot open connection //%s@%s/%s" - user host (or share ""))))))) + (tramp-message + vec 3 "Opening connection for //%s%s/%s...done" + (if (not (zerop (length user))) (concat user "@") "") + host (or share "")))))))) ;; We don't use timeouts. If needed, the caller shall wrap around. -(defun tramp-smb-wait-for-output (user host) +(defun tramp-smb-wait-for-output (vec) "Wait for output from smbclient command. Returns nil if an error message has appeared." - (let ((proc (get-buffer-process (current-buffer))) - (found (progn (goto-char (point-min)) - (re-search-forward tramp-smb-prompt nil t))) - (err (progn (goto-char (point-min)) - (re-search-forward tramp-smb-errors nil t)))) - - ;; Algorithm: get waiting output. See if last line contains - ;; tramp-smb-prompt sentinel or tramp-smb-errors strings. - ;; If not, wait a bit and again get waiting output. - (while (not found) - - ;; Accept pending output. - (tramp-accept-process-output proc) + (with-current-buffer (tramp-get-buffer vec) + (let ((p (get-buffer-process (current-buffer))) + (found (progn (goto-char (point-min)) + (re-search-forward tramp-smb-prompt nil t))) + (err (progn (goto-char (point-min)) + (re-search-forward tramp-smb-errors nil t)))) - ;; Search for prompt. - (goto-char (point-min)) - (setq found (re-search-forward tramp-smb-prompt nil t)) + ;; Algorithm: get waiting output. See if last line contains + ;; tramp-smb-prompt sentinel or tramp-smb-errors strings. + ;; If not, wait a bit and again get waiting output. + (while (and (not found) (not err)) - ;; Search for errors. - (goto-char (point-min)) - (setq err (re-search-forward tramp-smb-errors nil t))) - - ;; Add output to debug buffer if appropriate. - (when tramp-debug-buffer - (append-to-buffer - (tramp-get-debug-buffer nil tramp-smb-method user host) - (point-min) (point-max))) + ;; Accept pending output. + (tramp-accept-process-output p) - ;; Return value is whether no error message has appeared. - (not err))) - - -;; Snarfed code from time-date.el and parse-time.el + ;; Search for prompt. + (goto-char (point-min)) + (setq found (re-search-forward tramp-smb-prompt nil t)) -(defconst tramp-smb-half-a-year '(241 17024) -"Evaluated by \"(days-to-time 183)\".") + ;; Search for errors. + (goto-char (point-min)) + (setq err (re-search-forward tramp-smb-errors nil t))) -(defconst tramp-smb-parse-time-months '(("jan" . 1) ("feb" . 2) ("mar" . 3) - ("apr" . 4) ("may" . 5) ("jun" . 6) - ("jul" . 7) ("aug" . 8) ("sep" . 9) - ("oct" . 10) ("nov" . 11) ("dec" . 12)) -"Alist mapping month names to integers.") + ;; When the process is still alive, read pending output. + (while (and (not found) (memq (process-status p) '(run open))) -(defun tramp-smb-time-less-p (t1 t2) - "Say whether time value T1 is less than time value T2." - (unless t1 (setq t1 '(0 0))) - (unless t2 (setq t2 '(0 0))) - (or (< (car t1) (car t2)) - (and (= (car t1) (car t2)) - (< (nth 1 t1) (nth 1 t2))))) + ;; Accept pending output. + (tramp-accept-process-output p) -(defun tramp-smb-time-subtract (t1 t2) - "Subtract two time values. -Return the difference in the format of a time value." - (unless t1 (setq t1 '(0 0))) - (unless t2 (setq t2 '(0 0))) - (let ((borrow (< (cadr t1) (cadr t2)))) - (list (- (car t1) (car t2) (if borrow 1 0)) - (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))) + ;; Search for prompt. + (goto-char (point-min)) + (setq found (re-search-forward tramp-smb-prompt nil t))) + + ;; Return value is whether no error message has appeared. + (tramp-message vec 6 "\n%s" (buffer-string)) + (not err)))) (provide 'tramp-smb) ;;; TODO: -;; * Provide a local smb.conf. The default one might not be readable. ;; * Error handling in case password is wrong. ;; * Read password from "~/.netrc". ;; * Return more comprehensive file permission string. Think whether it is ;; possible to implement `set-file-modes'. -;; * Handle WILDCARD and FULL-DIRECTORY-P in -;; `tramp-smb-handle-insert-directory'. ;; * Handle links (FILENAME.LNK). ;; * Maybe local tmp files should have the same extension like the original ;; files. Strange behaviour with jka-compr otherwise? -;; * Copy files in dired from SMB to another method doesn't work. ;; * Try to remove the inclusion of dummy "" directory. Seems to be at ;; several places, especially in `tramp-smb-handle-insert-directory'. -;; * Provide variables for debug. ;; * (RMS) Use unwind-protect to clean up the state so as to make the state ;; regular again. +;; * Make it multi-hop capable. ;;; arch-tag: fcc9dbec-7503-4d73-b638-3c8aa59575f5 ;;; tramp-smb.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/tramp-util.el --- a/lisp/net/tramp-util.el Sun Jul 08 11:35:01 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,138 +0,0 @@ -;;; -*- coding: iso-2022-7bit; -*- -;;; tramp-util.el --- Misc utility functions to use with Tramp - -;; Copyright (C) 2001, 2002, 2003, 2004, 2005, -;; 2006, 2007 Free Software Foundation, Inc. - -;; Author: kai.grossjohann@gmx.net -;; Keywords: comm, extensions, processes - -;; This file 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 2, or (at your option) -;; any later version. - -;; This file 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 GNU Emacs; see the file COPYING. If not, write to -;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. - -;;; Commentary: - -;; Some misc. utility functions that might go nicely with Tramp. -;; Mostly, these are kluges awaiting real solutions later on. - -;;; Code: - -(require 'compile) -(require 'tramp) -(add-hook 'tramp-util-unload-hook - '(lambda () - (when (featurep 'tramp) - (unload-feature 'tramp 'force)))) - -;; Define a Tramp minor mode. It's intention is to redefine some keys for Tramp -;; specific functions, like compilation. -;; The key remapping works since Emacs 22 only. Unknown for XEmacs. - -;; Pacify byte-compiler -(eval-when-compile - (unless (fboundp 'define-minor-mode) - (defalias 'define-minor-mode 'identity) - (defvar tramp-minor-mode)) - (unless (featurep 'xemacs) - (defalias 'add-menu-button 'ignore))) - -(defvar tramp-minor-mode-map (make-sparse-keymap) - "Keymap for Tramp minor mode.") - -(define-minor-mode tramp-minor-mode "Tramp minor mode for utility functions." - :group 'tramp - :global nil - :init-value nil - :lighter " Tramp" - :keymap tramp-minor-mode-map - (setq tramp-minor-mode - (and tramp-minor-mode (tramp-tramp-file-p default-directory)))) - -(add-hook 'find-file-hooks 'tramp-minor-mode t) -(add-hook 'tramp-util-unload-hook - '(lambda () - (remove-hook 'find-file-hooks 'tramp-minor-mode))) - -(add-hook 'dired-mode-hook 'tramp-minor-mode t) -(add-hook 'tramp-util-unload-hook - '(lambda () - (remove-hook 'dired-mode-hook 'tramp-minor-mode))) - -(defun tramp-remap-command (old-command new-command) - "Replaces bindings of OLD-COMMAND by NEW-COMMAND. -If remapping functionality for keymaps is defined, this happens for all -bindings. Otherwise, only bindings active during invocation are taken -into account. XEmacs menubar bindings are not changed by this." - (if (functionp 'command-remapping) - ;; Emacs 22 - (eval - `(define-key tramp-minor-mode-map [remap ,old-command] new-command)) - ;; previous Emacs versions. - (mapcar - '(lambda (x) - (define-key tramp-minor-mode-map x new-command)) - (where-is-internal old-command)))) - -(tramp-remap-command 'compile 'tramp-compile) -(tramp-remap-command 'recompile 'tramp-recompile) - -;; XEmacs has an own mimic for menu entries -(when (fboundp 'add-menu-button) - (funcall 'add-menu-button - '("Tools" "Compile") - ["Compile..." - (command-execute (if tramp-minor-mode 'tramp-compile 'compile)) - :active (fboundp 'compile)]) - (funcall 'add-menu-button - '("Tools" "Compile") - ["Repeat Compilation" - (command-execute (if tramp-minor-mode 'tramp-recompile 'recompile)) - :active (fboundp 'compile)])) - -;; Utility functions. - -(defun tramp-compile (command) - "Compile on remote host." - (interactive - (if (or compilation-read-command current-prefix-arg) - (list (read-from-minibuffer "Compile command: " - compile-command nil nil - '(compile-history . 1))) - (list compile-command))) - (setq compile-command command) - (save-some-buffers (not compilation-ask-about-save) nil) - (let ((d default-directory)) - (save-excursion - (pop-to-buffer (get-buffer-create "*Compilation*") t) - (erase-buffer) - (setq default-directory d))) - (tramp-handle-shell-command command (get-buffer "*Compilation*")) - (pop-to-buffer (get-buffer "*Compilation*")) - (tramp-minor-mode 1) - (compilation-minor-mode 1)) - -(defun tramp-recompile () - "Re-compile on remote host." - (interactive) - (save-some-buffers (not compilation-ask-about-save) nil) - (tramp-handle-shell-command compile-command (get-buffer "*Compilation*")) - (pop-to-buffer (get-buffer "*Compilation*")) - (tramp-minor-mode 1) - (compilation-minor-mode 1)) - -(provide 'tramp-util) - -;;; arch-tag: 500f9992-a44e-46d0-83a7-980799251808 -;;; tramp-util.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/tramp-uu.el --- a/lisp/net/tramp-uu.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/net/tramp-uu.el Sun Jul 15 02:05:20 2007 +0000 @@ -9,8 +9,8 @@ ;; This file 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 2, or (at your option) -;; any later version. +;; the Free Software Foundation; either version 3 of the License, or +;; (at your option) any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,9 +18,8 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to -;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs; see the file COPYING. If not, see +;; . ;;; Commentary: diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/tramp-vc.el --- a/lisp/net/tramp-vc.el Sun Jul 08 11:35:01 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,536 +0,0 @@ -;;; tramp-vc.el --- Version control integration for TRAMP.el - -;; Copyright (C) 2000, 2001, 2002, 2003, 2004, -;; 2005, 2006, 2007 Free Software Foundation, Inc. - -;; Author: Daniel Pittman -;; Keywords: comm, processes - -;; This file is part of GNU Emacs. - -;; GNU Emacs 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 2, or (at your option) -;; any later version. - -;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. - -;;; Commentary: - -;; See the main module, 'tramp.el' for discussion of the purpose of TRAMP. -;; This module provides integration between remote files accessed by TRAMP and -;; the Emacs version control system. - -;;; Code: - -(require 'vc) -;; Old VC defines vc-rcs-release in vc.el, new VC requires extra module. -(unless (boundp 'vc-rcs-release) - (require 'vc-rcs)) -(require 'tramp) - -;; Avoid byte-compiler warnings if the byte-compiler supports this. -;; Currently, XEmacs supports this. -(eval-when-compile - (when (fboundp 'byte-compiler-options) - (let (unused-vars) ; Pacify Emacs byte-compiler - (defalias 'warnings 'identity) ; Pacify Emacs byte-compiler - (byte-compiler-options (warnings (- unused-vars)))))) - -;; -- vc -- - -;; This used to blow away the file-name-handler-alist and reinstall -;; TRAMP into it. This was intended to let VC work remotely. It didn't, -;; at least not in my XEmacs 21.2 install. -;; -;; In any case, tramp-run-real-handler now deals correctly with disabling -;; the things that should be, making this a no-op. -;; -;; I have removed it from the tramp-file-name-handler-alist because the -;; shortened version does nothing. This is for reference only now. -;; -;; Daniel Pittman -;; -;; (defun tramp-handle-vc-registered (file) -;; "Like `vc-registered' for tramp files." -;; (tramp-run-real-handler 'vc-registered (list file))) - -;; `vc-do-command' -;; This function does not deal well with remote files, so we define -;; our own version and make a backup of the original function and -;; call our version for tramp files and the original version for -;; normal files. - -;; The following function is pretty much copied from vc.el, but -;; the part that actually executes a command is changed. -;; CCC: this probably works for Emacs 21, too. -(defun tramp-vc-do-command (buffer okstatus command file last &rest flags) - "Like `vc-do-command' but invoked for tramp files. -See `vc-do-command' for more information." - (save-match-data - (and file (setq file (expand-file-name file))) - (if (not buffer) (setq buffer "*vc*")) - (if vc-command-messages - (message "Running `%s' on `%s'..." command file)) - (let ((obuf (current-buffer)) (camefrom (current-buffer)) - (squeezed nil) - (olddir default-directory) - vc-file status) - (let* ((v (tramp-dissect-file-name (expand-file-name file))) - (multi-method (tramp-file-name-multi-method v)) - (method (tramp-file-name-method v)) - (user (tramp-file-name-user v)) - (host (tramp-file-name-host v)) - (localname (tramp-file-name-localname v))) - (set-buffer (get-buffer-create buffer)) - (set (make-local-variable 'vc-parent-buffer) camefrom) - (set (make-local-variable 'vc-parent-buffer-name) - (concat " from " (buffer-name camefrom))) - (setq default-directory olddir) - - (erase-buffer) - - (mapcar - (function - (lambda (s) (and s (setq squeezed (append squeezed (list s)))))) - flags) - (if (and (eq last 'MASTER) file - (setq vc-file (vc-name file))) - (setq squeezed - (append squeezed - (list (tramp-file-name-localname - (tramp-dissect-file-name vc-file)))))) - (if (and file (eq last 'WORKFILE)) - (progn - (let* ((pwd (expand-file-name default-directory)) - (preflen (length pwd))) - (if (string= (substring file 0 preflen) pwd) - (setq file (substring file preflen)))) - (setq squeezed (append squeezed (list file))))) - ;; Unless we (save-window-excursion) the layout of windows in - ;; the current frame changes. This is painful, at best. - ;; - ;; As a point of note, (save-excursion) is still here only because - ;; it preserves (point) in the current buffer. (save-window-excursion) - ;; does not, at least under XEmacs 21.2. - ;; - ;; I trust that the FSF support this as well. I can't find useful - ;; documentation to check :( - ;; - ;; Daniel Pittman - (save-excursion - (save-window-excursion - ;; Actually execute remote command - ;; `shell-command' cannot be used; it isn't magic in XEmacs. - (tramp-handle-shell-command - (mapconcat 'tramp-shell-quote-argument - (cons command squeezed) " ") t) - ;;(tramp-wait-for-output) - ;; Get status from command - (tramp-send-command multi-method method user host "echo $?") - (tramp-wait-for-output) - ;; Make sure to get status from last line of output. - (goto-char (point-max)) (forward-line -1) - (setq status (read (current-buffer))) - (message "Command %s returned status %d." command status))) - (goto-char (point-max)) - (set-buffer-modified-p nil) - (forward-line -1) - (if (or (not (integerp status)) - (and (integerp okstatus) (< okstatus status))) - (progn - (pop-to-buffer buffer) - (goto-char (point-min)) - (shrink-window-if-larger-than-buffer) - (error "Running `%s'...FAILED (%s)" command - (if (integerp status) - (format "status %d" status) - status)) - ) - (if vc-command-messages - (message "Running %s...OK" command)) - ) - (set-buffer obuf) - status)) - )) - -;; Following code snarfed from Emacs 21 vc.el and slightly tweaked. -(defun tramp-vc-do-command-new (buffer okstatus command file &rest flags) - "Like `vc-do-command' but for TRAMP files. -This function is for the new VC which comes with Emacs 21. -Since TRAMP doesn't do async commands yet, this function doesn't, either." - (and file (setq file (expand-file-name file))) - (if vc-command-messages - (message "Running %s on %s..." command file)) - (save-current-buffer - (unless (eq buffer t) - ; Pacify byte-compiler - (funcall (symbol-function 'vc-setup-buffer) buffer)) - (let ((squeezed nil) - (inhibit-read-only t) - (status 0)) - (let* ((v (when file (tramp-dissect-file-name file))) - (multi-method (when file (tramp-file-name-multi-method v))) - (method (when file (tramp-file-name-method v))) - (user (when file (tramp-file-name-user v))) - (host (when file (tramp-file-name-host v))) - (localname (when file (tramp-file-name-localname v)))) - (setq squeezed (delq nil (copy-sequence flags))) - (when file - (setq squeezed (append squeezed (list (file-relative-name - file default-directory))))) - (let ((w32-quote-process-args t)) - (when (eq okstatus 'async) - (message "Tramp doesn't do async commands, running synchronously.")) - ;; `shell-command' cannot be used; it isn't magic in XEmacs. - (setq status (tramp-handle-shell-command - (mapconcat 'tramp-shell-quote-argument - (cons command squeezed) " ") t)) - (when (or (not (integerp status)) - (and (integerp okstatus) (< okstatus status))) - (pop-to-buffer (current-buffer)) - (goto-char (point-min)) - (shrink-window-if-larger-than-buffer) - (error "Running %s...FAILED (%s)" command - (if (integerp status) (format "status %d" status) status)))) - (if vc-command-messages - (message "Running %s...OK" command)) - ; Pacify byte-compiler - (funcall (symbol-function 'vc-exec-after) - `(run-hook-with-args - 'vc-post-command-functions ',command ',localname ',flags)) - status)))) - - -;; The context for a VC command is the current buffer. -;; That makes a test on the buffers file more reliable than a test on the -;; arguments. -;; This is needed to handle remote VC correctly - else we test against the -;; local VC system and get things wrong... -;; Daniel Pittman -;;-(if (fboundp 'vc-call-backend) -;;- () ;; This is the new VC for which we don't have an appropriate advice yet -;;-) -(unless (fboundp 'process-file) - (if (fboundp 'vc-call-backend) - (defadvice vc-do-command - (around tramp-advice-vc-do-command - (buffer okstatus command file &rest flags) - activate) - "Invoke tramp-vc-do-command for tramp files." - (let ((file (symbol-value 'file))) ;pacify byte-compiler - (if (or (and (stringp file) (tramp-tramp-file-p file)) - (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name)))) - (setq ad-return-value - (apply 'tramp-vc-do-command-new buffer okstatus command - file ;(or file (buffer-file-name)) - flags)) - ad-do-it))) - (defadvice vc-do-command - (around tramp-advice-vc-do-command - (buffer okstatus command file last &rest flags) - activate) - "Invoke tramp-vc-do-command for tramp files." - (let ((file (symbol-value 'file))) ;pacify byte-compiler - (if (or (and (stringp file) (tramp-tramp-file-p file)) - (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name)))) - (setq ad-return-value - (apply 'tramp-vc-do-command buffer okstatus command - (or file (buffer-file-name)) last flags)) - ad-do-it)))) - - (add-hook 'tramp-unload-hook - '(lambda () (ad-unadvise 'vc-do-command)))) - - -;; XEmacs uses this to do some of its work. Like vc-do-command, we -;; need to enhance it to make VC work via TRAMP-mode. -;; -;; Like the previous function, this is a cut-and-paste job from the VC -;; file. It's based on the vc-do-command code. -;; CCC: this isn't used in Emacs 21, so do as before. -(defun tramp-vc-simple-command (okstatus command file &rest args) - ;; Simple version of vc-do-command, for use in vc-hooks only. - ;; Don't switch to the *vc-info* buffer before running the - ;; command, because that would change its default directory - (save-match-data - (let* ((v (tramp-dissect-file-name (expand-file-name file))) - (multi-method (tramp-file-name-multi-method v)) - (method (tramp-file-name-method v)) - (user (tramp-file-name-user v)) - (host (tramp-file-name-host v)) - (localname (tramp-file-name-localname v))) - (save-excursion (set-buffer (get-buffer-create "*vc-info*")) - (erase-buffer)) - (let ((exec-path (append vc-path exec-path)) exec-status - ;; Add vc-path to PATH for the execution of this command. - (process-environment - (cons (concat "PATH=" (getenv "PATH") - path-separator - (mapconcat 'identity vc-path path-separator)) - process-environment))) - ;; Call the actual process. See tramp-vc-do-command for discussion of - ;; why this does both (save-window-excursion) and (save-excursion). - ;; - ;; As a note, I don't think that the process-environment stuff above - ;; has any effect on the remote system. This is a hard one though as - ;; there is no real reason to expect local and remote paths to be - ;; identical... - ;; - ;; Daniel Pittman - (save-excursion - (save-window-excursion - ;; Actually execute remote command - ;; `shell-command' cannot be used; it isn't magic in XEmacs. - (tramp-handle-shell-command - (mapconcat 'tramp-shell-quote-argument - (append (list command) args (list localname)) " ") - (get-buffer-create"*vc-info*")) - ;(tramp-wait-for-output) - ;; Get status from command - (tramp-send-command multi-method method user host "echo $?") - (tramp-wait-for-output) - (setq exec-status (read (current-buffer))) - (message "Command %s returned status %d." command exec-status))) - - ;; Maybe okstatus can be `async' here. But then, maybe the - ;; async thing is new in Emacs 21, but this function is only - ;; used in Emacs 20. - (cond ((> exec-status okstatus) - (switch-to-buffer (get-file-buffer file)) - (shrink-window-if-larger-than-buffer - (display-buffer "*vc-info*")) - (error "Couldn't find version control information"))) - exec-status)))) - -;; This function does not exist any more in Emacs-21's VC -(defadvice vc-simple-command - (around tramp-advice-vc-simple-command - (okstatus command file &rest args) - activate) - "Invoke tramp-vc-simple-command for tramp files." - (let ((file (symbol-value 'file))) ;pacify byte-compiler - (if (or (and (stringp file) (tramp-tramp-file-p file)) - (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name)))) - (setq ad-return-value - (apply 'tramp-vc-simple-command okstatus command - (or file (buffer-file-name)) args)) - ad-do-it))) - -(add-hook 'tramp-unload-hook - '(lambda () (ad-unadvise 'vc-simple-command))) - - -;; `vc-workfile-unchanged-p' -;; This function does not deal well with remote files, so we do the -;; same as for `vc-do-command'. - -;; `vc-workfile-unchanged-p' checks the modification time, we cannot -;; do that for remote files, so here's a version which relies on diff. -;; CCC: this one probably works for Emacs 21, too. -(defun tramp-vc-workfile-unchanged-p - (filename &optional want-differences-if-changed) - (if (fboundp 'vc-backend-diff) - ;; Old VC. Call `vc-backend-diff'. - (let ((status (funcall (symbol-function 'vc-backend-diff) - filename nil nil - (not want-differences-if-changed)))) - (zerop status)) - ;; New VC. Call `vc-default-workfile-unchanged-p'. - (funcall (symbol-function 'vc-default-workfile-unchanged-p) - (vc-backend filename) filename))) - -(defadvice vc-workfile-unchanged-p - (around tramp-advice-vc-workfile-unchanged-p - (filename &optional want-differences-if-changed) - activate) - "Invoke tramp-vc-workfile-unchanged-p for tramp files." - (if (and (stringp filename) - (tramp-tramp-file-p filename) - (not - (let ((v (tramp-dissect-file-name filename))) - ;; The following check is probably to test whether - ;; file-attributes returns correct last modification - ;; times. This check needs to be changed. - (tramp-get-remote-perl (tramp-file-name-multi-method v) - (tramp-file-name-method v) - (tramp-file-name-user v) - (tramp-file-name-host v))))) - (setq ad-return-value - (tramp-vc-workfile-unchanged-p filename want-differences-if-changed)) - ad-do-it)) - -(add-hook 'tramp-unload-hook - '(lambda () (ad-unadvise 'vc-workfile-unchanged-p))) - - -;; Redefine a function from vc.el -- allow tramp files. -;; `save-match-data' seems not to be required -- it isn't in -;; the original version, either. -;; CCC: this might need some work -- how does the Emacs 21 version -;; work, anyway? Does it work over ange-ftp? Hm. -(if (not (fboundp 'vc-backend-checkout)) - () ;; our replacement won't work and is unnecessary anyway -(defun vc-checkout (filename &optional writable rev) - "Retrieve a copy of the latest version of the given file." - ;; If ftp is on this system and the name matches the ange-ftp format - ;; for a remote file, the user is trying something that won't work. - (funcall (symbol-function 'vc-backend-checkout) filename writable rev) - (vc-resynch-buffer filename t t)) -) - - -;; Do we need to advise the vc-user-login-name function anyway? -;; This will return the correct login name for the owner of a -;; file. It does not deal with the default remote user name... -;; -;; That is, when vc calls (vc-user-login-name), we return the -;; local login name, something that may be different to the remote -;; default. -;; -;; The remote VC operations will occur as the user that we logged -;; in with however - not always the same as the local user. -;; -;; In the end, I did advise the function. This is because, well, -;; the thing didn't work right otherwise ;) -;; -;; Daniel Pittman - -(defun tramp-handle-vc-user-login-name (&optional uid) - "Return the default user name on the remote machine. -Whenever VC calls this function, `file' is bound to the file name -in question. If no uid is provided or the uid is equal to the uid -owning the file, then we return the user name given in the file name. - -This should only be called when `file' is bound to the -filename we are thinking about..." - ;; Pacify byte-compiler; this symbol is bound in the calling - ;; function. CCC: Maybe it would be better to move the - ;; boundness-checking into this function? - (let* ((file (symbol-value 'file)) - (remote-uid - ;; With Emacs 22, `file-attributes' has got an optional parameter - ;; ID-FORMAT. Handle this case backwards compatible. - (if (and (functionp 'subr-arity) - (= 2 (cdr (funcall (symbol-function 'subr-arity) - (symbol-function 'file-attributes))))) - (nth 2 (file-attributes file 'integer)) - (nth 2 (file-attributes file))))) - (if (and uid (/= uid remote-uid)) - (error "tramp-handle-vc-user-login-name cannot map a uid to a name") - (let* ((v (tramp-dissect-file-name (expand-file-name file))) - (u (tramp-file-name-user v))) - (cond ((stringp u) u) - ((vectorp u) (elt u (1- (length u)))) - ((null u) (user-login-name)) - (t (error "tramp-handle-vc-user-login-name cannot cope!"))))))) - - -;; The following defadvice is no longer necessary after changes in VC -;; on 2006-01-25, Andre. - -(unless (fboundp 'process-file) - (defadvice vc-user-login-name - (around tramp-vc-user-login-name activate) - "Support for files on remote machines accessed by TRAMP." - ;; We rely on the fact that `file' is bound when this is called. - ;; This appears to be the case everywhere in vc.el and vc-hooks.el - ;; as of Emacs 20.5. - ;; - ;; With Emacs 22, the definition of `vc-user-login-name' has been - ;; changed. It doesn't need to be adviced any longer. - (let ((file (when (boundp 'file) - (symbol-value 'file)))) ;pacify byte-compiler - (or (and (stringp file) - (tramp-tramp-file-p file) ; tramp file - (setq ad-return-value - (save-match-data - (tramp-handle-vc-user-login-name uid)))) ; get the owner name - ad-do-it))) ; else call the original - - (add-hook 'tramp-unload-hook - '(lambda () (ad-unadvise 'vc-user-login-name)))) - - -;; Determine the name of the user owning a file. -(defun tramp-file-owner (filename) - "Return who owns FILE (user name, as a string)." - (let ((v (tramp-dissect-file-name - (expand-file-name filename)))) - (if (not (file-exists-p filename)) - nil ; file cannot be opened - ;; file exists, find out stuff - (save-excursion - (tramp-send-command - (tramp-file-name-multi-method v) (tramp-file-name-method v) - (tramp-file-name-user v) (tramp-file-name-host v) - (format "%s -Lld %s" - (tramp-get-ls-command (tramp-file-name-multi-method v) - (tramp-file-name-method v) - (tramp-file-name-user v) - (tramp-file-name-host v)) - (tramp-shell-quote-argument (tramp-file-name-localname v)))) - (tramp-wait-for-output) - ;; parse `ls -l' output ... - ;; ... file mode flags - (read (current-buffer)) - ;; ... number links - (read (current-buffer)) - ;; ... uid (as a string) - (symbol-name (read (current-buffer))))))) - -;; Wire ourselves into the VC infrastructure... -;; This function does not exist any more in Emacs-21's VC -;; CCC: it appears that no substitute is needed for Emacs 21. -(defadvice vc-file-owner - (around tramp-vc-file-owner activate) - "Support for files on remote machines accessed by TRAMP." - (let ((filename (ad-get-arg 0))) - (or (and (tramp-file-name-p filename) ; tramp file - (setq ad-return-value - (save-match-data - (tramp-file-owner filename)))) ; get the owner name - ad-do-it))) ; else call the original - -(add-hook 'tramp-unload-hook - '(lambda () (ad-unadvise 'vc-file-owner))) - - -;; We need to make the version control software backend version -;; information local to the current buffer. This is because each TRAMP -;; buffer can (theoretically) have a different VC version and I am -;; *way* too lazy to try and push the correct value into each new -;; buffer. -;; -;; Remote VC costs will just have to be paid, at least for the moment. -;; Well, at least, they will right until I feel guilty about doing a -;; botch job here and fix it. :/ -;; -;; Daniel Pittman -;; CCC: this is probably still needed for Emacs 21. -(defun tramp-vc-setup-for-remote () - "Make the backend release variables buffer local. -This makes remote VC work correctly at the cost of some processing time." - (when (and (buffer-file-name) - (tramp-tramp-file-p (buffer-file-name))) - (make-local-variable 'vc-rcs-release) - (setq vc-rcs-release nil))) - -(add-hook 'find-file-hooks 'tramp-vc-setup-for-remote t) -(add-hook 'tramp-unload-hook - '(lambda () - (remove-hook 'find-file-hooks 'tramp-vc-setup-for-remote))) - -;; No need to load this again if anyone asks. -(provide 'tramp-vc) - -;;; arch-tag: 27cc42ce-da19-468d-ad5c-a2690558db60 -;;; tramp-vc.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/tramp.el --- a/lisp/net/tramp.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/net/tramp.el Sun Jul 15 02:05:20 2007 +0000 @@ -14,8 +14,8 @@ ;; GNU Emacs 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 2, or (at your option) -;; any later version. +;; the Free Software Foundation; either version 3 of the License, or +;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,9 +23,8 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs; see the file COPYING. If not, see +;; . ;;; Commentary: @@ -39,10 +38,9 @@ ;; Notes: ;; ----- ;; -;; This package only works for Emacs 20 and higher, and for XEmacs 21 -;; and higher. (XEmacs 20 is missing the `with-timeout' macro. Emacs -;; 19 is reported to have other problems. For XEmacs 21, you need the -;; package `fsf-compat' for the `with-timeout' macro.) +;; This package only works for Emacs 21.1 and higher, and for XEmacs 21.4 +;; and higher. For XEmacs 21, you need the package `fsf-compat' for +;; the `with-timeout' macro.) ;; ;; This version might not work with pre-Emacs 21 VC unless VC is ;; loaded before tramp.el. Could you please test this and tell me about @@ -74,6 +72,8 @@ (when (featurep 'trampver) (unload-feature 'trampver 'force)))) +(require 'custom) + (if (featurep 'xemacs) (require 'timer-funcs) (require 'timer)) @@ -85,15 +85,24 @@ (load "password" 'noerror) (require 'password nil 'noerror)) ;from No Gnus, also in tar ball -;; The explicit check is not necessary in Emacs, which provides the -;; feature even if implemented in C, but it appears to be necessary -;; in XEmacs. -(unless (and (fboundp 'base64-encode-region) - (fboundp 'base64-decode-region)) - (require 'base64)) ;for the mimencode methods (require 'shell) (require 'advice) +;; Requiring 'tramp-cache results in an endless loop. +(autoload 'tramp-get-file-property "tramp-cache") +(autoload 'tramp-set-file-property "tramp-cache") +(autoload 'tramp-flush-file-property "tramp-cache") +(autoload 'tramp-flush-directory-property "tramp-cache") +(autoload 'tramp-cache-print "tramp-cache") +(autoload 'tramp-get-connection-property "tramp-cache") +(autoload 'tramp-set-connection-property "tramp-cache") +(autoload 'tramp-flush-connection-property "tramp-cache") +(autoload 'tramp-parse-connection-properties "tramp-cache") +(add-hook 'tramp-unload-hook + '(lambda () + (when (featurep 'tramp-cache) + (unload-feature 'tramp-cache 'force)))) + (autoload 'tramp-uuencode-region "tramp-uu" "Implementation of `uuencode' in Lisp.") (add-hook 'tramp-unload-hook @@ -101,75 +110,85 @@ (when (featurep 'tramp-uu) (unload-feature 'tramp-uu 'force)))) -(unless (fboundp 'uudecode-decode-region) - (autoload 'uudecode-decode-region "uudecode")) - -;; XEmacs is distributed with few Lisp packages. Further packages are -;; installed using EFS. If we use a unified filename format, then -;; Tramp is required in addition to EFS. (But why can't Tramp just -;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS -;; just like before.) Another reason for using a separate filename -;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but -;; Tramp only knows how to deal with `file-name-handler-alist', not -;; the other places. -;;;###autoload -(defvar tramp-unified-filenames (not (featurep 'xemacs)) - "Non-nil means to use unified Ange-FTP/Tramp filename syntax. -Otherwise, use a separate filename syntax for Tramp.") - -;; Load foreign methods. Because they do require Tramp internally, this -;; must be done with the `eval-after-load' trick. - -;; tramp-ftp supports Ange-FTP only. Not suited for XEmacs therefore. -(unless (featurep 'xemacs) - (eval-after-load "tramp" - '(progn - (require 'tramp-ftp) +(autoload 'uudecode-decode-region "uudecode") + +;; The following Tramp packages must be loaded after Tramp, because +;; they require Tramp as well. +(eval-after-load "tramp" + '(progn + + ;; Load foreign FTP method. + (let ((feature (if (featurep 'xemacs) 'tramp-efs 'tramp-ftp))) + (require feature) (add-hook 'tramp-unload-hook - '(lambda () - (when (featurep 'tramp-ftp) - (unload-feature 'tramp-ftp 'force))))))) -(when (and tramp-unified-filenames (featurep 'xemacs)) - (eval-after-load "tramp" - '(progn - (require 'tramp-efs) - (add-hook 'tramp-unload-hook - '(lambda () - (when (featurep 'tramp-efs) - (unload-feature 'tramp-efs 'force))))))) - -;; tramp-smb uses "smbclient" from Samba. -;; Not available under Cygwin and Windows, because they don't offer -;; "smbclient". And even not necessary there, because Emacs supports -;; UNC file names like "//host/share/localname". -(unless (memq system-type '(cygwin windows-nt)) - (eval-after-load "tramp" - '(progn + `(lambda () + (when (featurep ,feature) + (unload-feature ,feature 'force))))) + + ;; tramp-smb uses "smbclient" from Samba. Not available under + ;; Cygwin and Windows, because they don't offer "smbclient". And + ;; even not necessary there, because Emacs supports UNC file names + ;; like "//host/share/localname". + (unless (memq system-type '(cygwin windows-nt)) (require 'tramp-smb) (add-hook 'tramp-unload-hook '(lambda () (when (featurep 'tramp-smb) - (unload-feature 'tramp-smb 'force))))))) - -(require 'custom) - -(unless (boundp 'custom-print-functions) - (defvar custom-print-functions nil)) ; not autoloaded before Emacs 20.4 + (unload-feature 'tramp-smb 'force))))) + + ;; Load foreign FISH method. + (require 'tramp-fish) + (add-hook 'tramp-unload-hook + '(lambda () + (when (featurep 'tramp-fish) + (unload-feature 'tramp-fish 'force)))) + + ;; Load gateways. It needs `make-network-process' from Emacs 22. + (if (functionp 'make-network-process) + (progn + (require 'tramp-gw) + (add-hook 'tramp-unload-hook + '(lambda () + (when (featurep 'tramp-gw) + (unload-feature 'tramp-gw 'force))))) + ;; We need to declare used tramp-gw-* symbols at least. + (setq tramp-gw-tunnel-method "" + tramp-gw-socks-method "") + (defalias 'tramp-gw-open-connection 'ignore)) + + ;; tramp-util offers integration into other (X)Emacs packages like + ;; compile.el, gud.el etc. Not necessary in Emacs 23. + (unless (functionp 'start-file-process) + (require 'tramp-util) + (add-hook 'tramp-unload-hook + '(lambda () + (when (featurep 'tramp-util) + (unload-feature 'tramp-util 'force))))))) ;; Avoid byte-compiler warnings if the byte-compiler supports this. ;; Currently, XEmacs supports this. (eval-when-compile (when (featurep 'xemacs) - (let (unused-vars) ; Pacify Emacs byte-compiler - (defalias 'warnings 'identity) ; Pacify Emacs byte-compiler - (byte-compiler-options (warnings (- unused-vars)))))) + (byte-compiler-options (warnings (- unused-vars))))) + +;; `last-coding-system-used' is unknown in XEmacs. +(eval-when-compile + (unless (boundp 'last-coding-system-used) + (defvar last-coding-system-used nil))) ;; `directory-sep-char' is an obsolete variable in Emacs. But it is ;; used in XEmacs, so we set it here and there. The following is needed ;; to pacify Emacs byte-compiler. (eval-when-compile - (when (boundp 'byte-compile-not-obsolete-var) - (setq byte-compile-not-obsolete-var 'directory-sep-char))) + (unless (boundp 'byte-compile-not-obsolete-var) + (defvar byte-compile-not-obsolete-var nil)) + (setq byte-compile-not-obsolete-var 'directory-sep-char)) + +;; `with-temp-message' does not exists in XEmacs. +(eval-and-compile + (condition-case nil + (with-temp-message (current-message) nil) + (error (defmacro with-temp-message (message &rest body) `(progn ,@body))))) ;; `set-buffer-multibyte' comes from Emacs Leim. (eval-and-compile @@ -183,16 +202,23 @@ :group 'files :version "22.1") -(defcustom tramp-verbose 9 - "*Verbosity level for tramp.el. 0 means be silent, 10 is most verbose." +(defcustom tramp-verbose 3 + "*Verbosity level for tramp. +Any level x includes messages for all levels 1 .. x-1. The levels are + + 0 silent (no tramp messages at all) + 1 errors + 2 warnings + 3 connection to remote hosts (default level) + 4 activities + 5 internal + 6 sent and received strings + 7 file caching + 8 connection properties +10 traces (huge)." :group 'tramp :type 'integer) -(defcustom tramp-debug-buffer nil - "*Whether to send all commands and responses to a debug buffer." - :group 'tramp - :type 'boolean) - ;; Emacs case (eval-and-compile (when (boundp 'backup-directory-alist) @@ -201,7 +227,7 @@ Each element looks like (REGEXP . DIRECTORY), with the same meaning like in `backup-directory-alist'. If a Tramp file is backed up, and DIRECTORY is a local file name, the backup directory is prepended with Tramp file -name prefix \(multi-method, method, user, host\) of file. +name prefix \(method, user, host\) of file. \(setq tramp-backup-directory-alist backup-directory-alist\) @@ -220,7 +246,7 @@ It has the same meaning like `bkup-backup-directory-info' from package `backup-dir'. If a Tramp file is backed up, and BACKUP-DIR is a local file name, the backup directory is prepended with Tramp file name prefix -\(multi-method, method, user, host\) of file. +\(method, user, host\) of file. \(setq tramp-bkup-backup-directory-info bkup-backup-directory-info\) @@ -240,8 +266,7 @@ "*Put auto-save files in this directory, if set. The idea is to use a local directory so that auto-saving is faster." :group 'tramp - :type '(choice (const nil) - string)) + :type '(choice (const nil) string)) (defcustom tramp-encoding-shell (if (memq system-type '(windows-nt)) @@ -258,9 +283,7 @@ /bin/sh -c COMMAND < INPUT > OUTPUT This variable can be used to change the \"/bin/sh\" part. See the -variable `tramp-encoding-command-switch' for the \"-c\" part. Also, see the -variable `tramp-encoding-reads-stdin' to specify whether the commands read -standard input or a file. +variable `tramp-encoding-command-switch' for the \"-c\" part. Note that this variable is not used for remote commands. There are mechanisms in tramp.el which automatically determine the right shell to @@ -277,286 +300,313 @@ :group 'tramp :type 'string) -(defcustom tramp-encoding-reads-stdin t - "*If non-nil, encoding commands read from standard input. -If nil, the filename is the last argument. - -Note that the commands always must write to standard output." +(defcustom tramp-copy-size-limit 10240 + "*The maximum file size where inline copying is preferred over an out-of-the-band copy." :group 'tramp - :type 'boolean) - -(defcustom tramp-multi-sh-program - tramp-encoding-shell - "*Use this program for bootstrapping multi-hop connections. -This variable is similar to `tramp-encoding-shell', but it is only used -when initializing a multi-hop connection. Therefore, the set of -commands sent to this shell is quite restricted, and if you are -careful it works to use CMD.EXE under Windows (instead of a Bourne-ish -shell which does not normally exist on Windows anyway). - -To use multi-hop methods from Windows, you also need suitable entries -in `tramp-multi-connection-function-alist' for the first hop. - -This variable defaults to the value of `tramp-encoding-shell'." + :type 'integer) + +(defcustom tramp-terminal-type "dumb" + "*Value of TERM environment variable for logging in to remote host. +Because Tramp wants to parse the output of the remote shell, it is easily +confused by ANSI color escape sequences and suchlike. Often, shell init +files conditionalize this setup based on the TERM environment variable." :group 'tramp - :type '(file :must-match t)) - -;; CCC I have changed all occurrences of comint-quote-filename with -;; tramp-shell-quote-argument, except in tramp-handle-expand-many-files. -;; There, comint-quote-filename was removed altogether. If it turns -;; out to be necessary there, something will need to be done. -;;-(defcustom tramp-file-name-quote-list -;;- '(?] ?[ ?\| ?& ?< ?> ?\( ?\) ?\; ?\ ?\* ?\? ?\! ?\" ?\' ?\` ?# ?\@ ?\+ ) -;;- "*Protect these characters from the remote shell. -;;-Any character in this list is quoted (preceded with a backslash) -;;-because it means something special to the shell. This takes effect -;;-when sending file and directory names to the remote shell. -;;- -;;-See `comint-file-name-quote-list' for details." -;;- :group 'tramp -;;- :type '(repeat character)) - -(defcustom tramp-methods - '( ("rcp" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "rsh") - (tramp-copy-program "rcp") - (tramp-remote-sh "/bin/sh") - (tramp-login-args nil) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line nil)) - ("scp" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh") - (tramp-copy-program "scp") - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-e" "none")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line nil)) - ("scp1" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh") - (tramp-copy-program "scp") - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-1" "-e" "none")) - (tramp-copy-args ("-1")) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line nil)) - ("scp2" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh") - (tramp-copy-program "scp") - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-2" "-e" "none")) - (tramp-copy-args ("-2")) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line nil)) - ("scp1_old" - (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh1") - (tramp-copy-program "scp1") - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-e" "none")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line nil)) - ("scp2_old" - (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh2") - (tramp-copy-program "scp2") - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-e" "none")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line nil)) - ("rsync" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh") - (tramp-copy-program "rsync") - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-e" "none")) - (tramp-copy-args ("-e" "ssh")) - (tramp-copy-keep-date-arg "-t") - (tramp-password-end-of-line nil)) - ("remcp" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "remsh") - (tramp-copy-program "rcp") - (tramp-remote-sh "/bin/sh") - (tramp-login-args nil) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line nil)) - ("rsh" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "rsh") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args nil) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("ssh" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-e" "none")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("ssh1" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-1" "-e" "none")) - (tramp-copy-args ("-1")) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("ssh2" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-2" "-e" "none")) - (tramp-copy-args ("-2")) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("ssh1_old" - (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh1") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-e" "none")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("ssh2_old" - (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh2") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-e" "none")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("remsh" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "remsh") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args nil) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("telnet" - (tramp-connection-function tramp-open-connection-telnet) - (tramp-login-program "telnet") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args nil) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("su" (tramp-connection-function tramp-open-connection-su) - (tramp-login-program "su") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-" "%u")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("sudo" (tramp-connection-function tramp-open-connection-su) - (tramp-login-program "sudo") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-u" "%u" "-s" - "-p" "Password:")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("multi" (tramp-connection-function tramp-open-connection-multi) - (tramp-login-program nil) - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args nil) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("scpc" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh") - (tramp-copy-program "scp") - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-o" "ControlPath=%t.%%r@%%h:%%p" - "-o" "ControlMaster=yes" - "-e" "none")) - (tramp-copy-args ("-o" "ControlPath=%t.%%r@%%h:%%p" - "-o" "ControlMaster=auto")) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line nil)) - ("scpx" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh") - (tramp-copy-program "scp") - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-e" "none" "-t" "-t" "/bin/sh")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line nil)) - ("sshx" (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "ssh") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-e" "none" "-t" "-t" "/bin/sh")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("krlogin" - (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "krlogin") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-x")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line nil)) - ("plink" - (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "plink") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-ssh")) ;optionally add "-v" - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line "xy")) ;see docstring for "xy" - ("plink1" - (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "plink") - (tramp-copy-program nil) - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-1" "-ssh")) ;optionally add "-v" - (tramp-copy-args nil) - (tramp-copy-keep-date-arg nil) - (tramp-password-end-of-line "xy")) ;see docstring for "xy" - ("pscp" - (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "plink") - (tramp-copy-program "pscp") - (tramp-remote-sh "/bin/sh") - (tramp-login-args ("-ssh")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line "xy")) ;see docstring for "xy" - ("fcp" - (tramp-connection-function tramp-open-connection-rsh) - (tramp-login-program "fsh") - (tramp-copy-program "fcp") - (tramp-remote-sh "/bin/sh -i") - (tramp-login-args ("sh" "-i")) - (tramp-copy-args nil) - (tramp-copy-keep-date-arg "-p") - (tramp-password-end-of-line nil)) - ) + :type 'string) + +(defvar tramp-methods + `(("rcp" (tramp-login-program "rsh") + (tramp-login-args (("%h") ("-l" "%u"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "rcp") + (tramp-copy-args (("-p" "%k"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil)) + ("scp" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "scp") + (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil) + (tramp-gw-args (("-o" + "GlobalKnownHostsFile=/dev/null") + ("-o" "UserKnownHostsFile=/dev/null") + ("-o" "StrictHostKeyChecking=no"))) + (tramp-default-port 22)) + ("scp1" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-1" "-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "scp") + (tramp-copy-args (("-1") ("-P" "%p") ("-p" "%k") + ("-q"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil) + (tramp-gw-args (("-o" + "GlobalKnownHostsFile=/dev/null") + ("-o" "UserKnownHostsFile=/dev/null") + ("-o" "StrictHostKeyChecking=no"))) + (tramp-default-port 22)) + ("scp2" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-2" "-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "scp") + (tramp-copy-args (("-2") ("-P" "%p") ("-p" "%k") + ("-q"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil) + (tramp-gw-args (("-o" + "GlobalKnownHostsFile=/dev/null") + ("-o" "UserKnownHostsFile=/dev/null") + ("-o" "StrictHostKeyChecking=no"))) + (tramp-default-port 22)) + ("scp1_old" + (tramp-login-program "ssh1") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "scp1") + (tramp-copy-args (("-p" "%k"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil)) + ("scp2_old" + (tramp-login-program "ssh2") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "scp2") + (tramp-copy-args (("-p" "%k"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil)) + ("sftp" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "sftp") + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil)) + ("rsync" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "rsync") + (tramp-copy-args (("-e" "ssh") ("-t" "%k"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil)) + ("remcp" (tramp-login-program "remsh") + (tramp-login-args (("%h") ("-l" "%u"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "rcp") + (tramp-copy-args (("-p" "%k"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil)) + ("rsh" (tramp-login-program "rsh") + (tramp-login-args (("%h") ("-l" "%u"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil)) + ("ssh" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil) + (tramp-gw-args (("-o" + "GlobalKnownHostsFile=/dev/null") + ("-o" "UserKnownHostsFile=/dev/null") + ("-o" "StrictHostKeyChecking=no"))) + (tramp-default-port 22)) + ("ssh1" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-1" "-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil) + (tramp-gw-args (("-o" + "GlobalKnownHostsFile=/dev/null") + ("-o" "UserKnownHostsFile=/dev/null") + ("-o" "StrictHostKeyChecking=no"))) + (tramp-default-port 22)) + ("ssh2" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-2" "-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil) + (tramp-gw-args (("-o" + "GlobalKnownHostsFile=/dev/null") + ("-o" "UserKnownHostsFile=/dev/null") + ("-o" "StrictHostKeyChecking=no"))) + (tramp-default-port 22)) + ("ssh1_old" + (tramp-login-program "ssh1") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil)) + ("ssh2_old" + (tramp-login-program "ssh2") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil)) + ("remsh" (tramp-login-program "remsh") + (tramp-login-args (("%h") ("-l" "%u"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil)) + ("telnet" + (tramp-login-program "telnet") + (tramp-login-args (("%h") ("%p"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil) + (tramp-default-port 23)) + ("su" (tramp-login-program "su") + (tramp-login-args (("-") ("%u"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil)) + ("sudo" (tramp-login-program "sudo") + (tramp-login-args (("-u" "%u") + ("-s" "-p" "Password:"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil)) + ("scpc" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-o" "ControlPath=%t.%%r@%%h:%%p") + ("-o" "ControlMaster=yes") + ("-e" "none"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "scp") + (tramp-copy-args (("-P" "%p") ("-p" "%k") ("-q") + ("-o" "ControlPath=%t.%%r@%%h:%%p") + ("-o" "ControlMaster=auto"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil) + (tramp-gw-args (("-o" + "GlobalKnownHostsFile=/dev/null") + ("-o" "UserKnownHostsFile=/dev/null") + ("-o" "StrictHostKeyChecking=no"))) + (tramp-default-port 22)) + ("scpx" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-e" "none" "-t" "-t" "/bin/sh"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "scp") + (tramp-copy-args (("-p" "%k"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil) + (tramp-gw-args (("-o" + "GlobalKnownHostsFile=/dev/null") + ("-o" "UserKnownHostsFile=/dev/null") + ("-o" "StrictHostKeyChecking=no"))) + (tramp-default-port 22)) + ("sshx" (tramp-login-program "ssh") + (tramp-login-args (("%h") ("-l" "%u") ("-p" "%p") + ("-e" "none" "-t" "-t" "/bin/sh"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil) + (tramp-gw-args (("-o" + "GlobalKnownHostsFile=/dev/null") + ("-o" "UserKnownHostsFile=/dev/null") + ("-o" "StrictHostKeyChecking=no"))) + (tramp-default-port 22)) + ("krlogin" + (tramp-login-program "krlogin") + (tramp-login-args (("%h") ("-l" "%u") ("-x"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil)) + ("plink" (tramp-login-program "plink") + (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p") + ("-ssh"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line "xy") ;see docstring for "xy" + (tramp-default-port 22)) + ("plink1" + (tramp-login-program "plink") + (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p") + ("-1" "-ssh"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line "xy") ;see docstring for "xy" + (tramp-default-port 22)) + ("plinkx" + (tramp-login-program "plink") + (tramp-login-args (("-load" "%h") ("-t") + (,(format "env 'TERM=%s' 'PS1=$ '" + tramp-terminal-type)) + ("/bin/sh"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program nil) + (tramp-copy-args nil) + (tramp-copy-keep-date nil) + (tramp-password-end-of-line nil)) + ("pscp" (tramp-login-program "plink") + (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p") + ("-ssh"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "pscp") + (tramp-copy-args (("-scp") ("-p" "%k"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line "xy") ;see docstring for "xy" + (tramp-default-port 22)) + ("psftp" (tramp-login-program "plink") + (tramp-login-args (("%h") ("-l" "%u") ("-P" "%p") + ("-ssh"))) + (tramp-remote-sh "/bin/sh") + (tramp-copy-program "pscp") + (tramp-copy-args (("-psftp") ("-p" "%k"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line "xy")) ;see docstring for "xy" + ("fcp" (tramp-login-program "fsh") + (tramp-login-args (("%h") ("-l" "%u") ("sh" "-i"))) + (tramp-remote-sh "/bin/sh -i") + (tramp-copy-program "fcp") + (tramp-copy-args (("-p" "%k"))) + (tramp-copy-keep-date t) + (tramp-password-end-of-line nil))) "*Alist of methods for remote files. This is a list of entries of the form (NAME PARAM1 PARAM2 ...). Each NAME stands for a remote access method. Each PARAM is a pair of the form (KEY VALUE). The following KEYs are defined: - * `tramp-connection-function' - This specifies the function to use to connect to the remote host. - Currently, `tramp-open-connection-rsh', `tramp-open-connection-telnet' - and `tramp-open-connection-su' are defined. See the documentation - of these functions for more details. * `tramp-remote-sh' This specifies the Bourne shell to use on the remote host. This MUST be a Bourne-like shell. It is normally not necessary to set @@ -566,21 +616,22 @@ the value that you decide to use. You Have Been Warned. * `tramp-login-program' This specifies the name of the program to use for logging in to the - remote host. Depending on `tramp-connection-function', this may be - the name of rsh or a workalike program (when - `tramp-connection-function' is `tramp-open-connection-rsh'), or the - name of telnet or a workalike (for `tramp-open-connection-telnet'), - or the name of su or a workalike (for `tramp-open-connection-su'). + remote host. This may be the name of rsh or a workalike program, + or the name of telnet or a workalike, or the name of su or a workalike. * `tramp-login-args' This specifies the list of arguments to pass to the above - mentioned program. Please note that this is a list of arguments, + mentioned program. Please note that this is a list of list of arguments, that is, normally you don't want to put \"-a -b\" or \"-f foo\" - here. Instead, you want two list elements, one for \"-a\" and one - for \"-b\", or one for \"-f\" and one for \"foo\". - If `tramp-connection-function' is `tramp-open-connection-su', then - \"%u\" in this list is replaced by the user name, and \"%%\" can - be used to obtain a literal percent character. - \"%t\" is replaced by the temporary file name for `scp'-like methods. + here. Instead, you want a list (\"-a\" \"-b\"), or (\"-f\" \"foo\"). + There are some patterns: \"%h\" in this list is replaced by the host + name, \"%u\" is replaced by the user name, \"%p\" is replaced by the + port number, and \"%%\" can be used to obtain a literal percent character. + If a list containing \"%h\", \"%u\" or \"%p\" is unchanged during + expansion (i.e. no host or no user specified), this list is not used as + argument. By this, arguments like (\"-l\" \"%u\") are optional. + \"%t\" is replaced by the temporary file name produced with + `tramp-make-tramp-temp-file'. \"%k\" indicates the keep-date + parameter of a program, if exists. * `tramp-copy-program' This specifies the name of the program to use for remotely copying the file; this might be the absolute filename of rcp or the name of @@ -588,10 +639,16 @@ * `tramp-copy-args' This specifies the list of parameters to pass to the above mentioned program, the hints for `tramp-login-args' also apply here. - * `tramp-copy-keep-date-arg' - This specifies the parameter to use for the copying program when the - timestamp of the original file should be kept. For `rcp', use `-p', for - `rsync', use `-t'. + * `tramp-copy-keep-date' + This specifies whether the copying program when the preserves the + timestamp of the original file. + * `tramp-default-port' + The default port of a method is needed in case of gateway connections. + Additionally, it is used as indication which method is prepared for + passing gateways. + * `tramp-gw-args' + As the attribute name says, additional arguments are specified here + when a method is applied via a gateway. * `tramp-password-end-of-line' This specifies the string to use for terminating the line after submitting the password. If this method parameter is nil, then the @@ -613,78 +670,22 @@ this case, the file contents need to be protected since the `tramp-login-program' might use escape codes or the connection might not be eight-bit clean. Therefore, file contents are encoded for transit. -See the variable `tramp-coding-commands' for details. +See the variables `tramp-local-coding-commands' and +`tramp-remote-coding-commands' for details. So, to summarize: if the method is an out-of-band method, then you must specify `tramp-copy-program' and `tramp-copy-args'. If it is an -inline method, then these two parameters should be nil. Every method, -inline or out of band, must specify `tramp-connection-function' plus -the associated arguments (for example, the login program if you chose -`tramp-open-connection-telnet'). +inline method, then these two parameters should be nil. Methods which +are fit for gateways must have `tramp-default-port' at least. Notes: -When using `tramp-open-connection-su' the phrase `open connection to a -remote host' sounds strange, but it is used nevertheless, for -consistency. No connection is opened to a remote host, but `su' is -started on the local host. You are not allowed to specify a remote -host other than `localhost' or the name of the local host." - :group 'tramp - :type '(repeat - (cons string - (set (list (const tramp-connection-function) function) - (list (const tramp-login-program) - (choice (const nil) string)) - (list (const tramp-copy-program) - (choice (const nil) string)) - (list (const tramp-remote-sh) - (choice (const nil) string)) - (list (const tramp-login-args) (repeat string)) - (list (const tramp-copy-args) (repeat string)) - (list (const tramp-copy-keep-date-arg) - (choice (const nil) string)) - (list (const tramp-encoding-command) - (choice (const nil) string)) - (list (const tramp-decoding-command) - (choice (const nil) string)) - (list (const tramp-encoding-function) - (choice (const nil) function)) - (list (const tramp-decoding-function) - (choice (const nil) function)) - (list (const tramp-password-end-of-line) - (choice (const nil) string)))))) - -(defcustom tramp-multi-methods '("multi" "multiu") - "*List of multi-hop methods. -Each entry in this list should be a method name as mentioned in the -variable `tramp-methods'." - :group 'tramp - :type '(repeat string)) - -(defcustom tramp-multi-connection-function-alist - '(("telnet" tramp-multi-connect-telnet "telnet %h%n") - ("rsh" tramp-multi-connect-rlogin "rsh %h -l %u%n") - ("remsh" tramp-multi-connect-rlogin "remsh %h -l %u%n") - ("ssh" tramp-multi-connect-rlogin "ssh %h -l %u%n") - ("ssht" tramp-multi-connect-rlogin "ssh %h -e none -t -t -l %u%n") - ("su" tramp-multi-connect-su "su - %u%n") - ("sudo" tramp-multi-connect-su "sudo -u %u -s -p Password:%n")) - "*List of connection functions for multi-hop methods. -Each list item is a list of three items (METHOD FUNCTION COMMAND), -where METHOD is the name as used in the file name, FUNCTION is the -function to be executed, and COMMAND is the shell command used for -connecting. - -COMMAND may contain percent escapes. `%u' will be replaced with the -user name, `%h' will be replaced with the host name, and `%n' will be -replaced with an end-of-line character, as specified in the variable -`tramp-rsh-end-of-line'. Use `%%' for a literal percent character. -Note that the interpretation of the percent escapes also depends on -the FUNCTION. For example, the `%u' escape is forbidden with the -function `tramp-multi-connect-telnet'. See the documentation of the -various functions for details." - :group 'tramp - :type '(repeat (list string function string))) +When using `su' or `sudo' the phrase `open connection to a remote +host' sounds strange, but it is used nevertheless, for consistency. +No connection is opened to a remote host, but `su' or `sudo' is +started on the local host. You should specify a remote host +`localhost' or the name of the local host. Another host name is +useful only in combination with `tramp-default-proxies-alist'.") (defcustom tramp-default-method ;; An external copy method seems to be preferred, because it is much @@ -696,30 +697,26 @@ ;; another good choice because of the "ControlMaster" option, but ;; this is a more modern alternative in OpenSSH 4, which cannot be ;; taken as default. - (let ((e-f (fboundp 'executable-find))) - (cond - ;; PuTTY is installed. - ((and e-f (funcall 'executable-find "pscp")) - (if (or (fboundp 'password-read) - ;; Pageant is running. - (and (fboundp 'w32-window-exists-p) - (funcall 'w32-window-exists-p "Pageant" "Pageant"))) - "pscp" - "plink")) - ;; There is an ssh installation. - ((and e-f (funcall 'executable-find "scp")) - (if (or (fboundp 'password-read) - ;; ssh-agent is running. - (getenv "SSH_AUTH_SOCK") - (getenv "SSH_AGENT_PID")) - "scp" - "ssh")) - ;; Under Emacs 20, `executable-find' does not exists. So we - ;; couldn't check whether there is an ssh implementation. Let's - ;; hope the best. - ((not e-f) "ssh") - ;; Fallback. - (t "ftp"))) + (cond + ;; PuTTY is installed. + ((executable-find "pscp") + (if (or (fboundp 'password-read) + ;; Pageant is running. + (and (fboundp 'w32-window-exists-p) + (funcall (symbol-function 'w32-window-exists-p) + "Pageant" "Pageant"))) + "pscp" + "plink")) + ;; There is an ssh installation. + ((executable-find "scp") + (if (or (fboundp 'password-read) + ;; ssh-agent is running. + (getenv "SSH_AUTH_SOCK") + (getenv "SSH_AGENT_PID")) + "scp" + "ssh")) + ;; Fallback. + (t "ftp")) "*Default method to use for transferring files. See `tramp-methods' for possibilities. Also see `tramp-default-method-alist'." @@ -728,7 +725,7 @@ (defcustom tramp-default-method-alist '(("\\`localhost\\'" "\\`root\\'" "su")) - "*Default method to use for specific user/host pairs. + "*Default method to use for specific host/user pairs. This is an alist of items (HOST USER METHOD). The first matching item specifies the method to use for a file name which does not specify a method. HOST and USER are regular expressions or nil, which is @@ -744,42 +741,90 @@ (regexp :tag "User regexp") (string :tag "Method")))) -;; Default values for non-Unices seeked +(defcustom tramp-default-user + nil + "*Default user to use for transferring files. +It is nil by default; otherwise settings in configuration files like +\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'. + +This variable is regarded as obsolete, and will be removed soon." + :group 'tramp + :type '(choice (const nil) string)) + +(defcustom tramp-default-user-alist + `(("\\`su\\(do\\)?\\'" nil "root") + ("\\`r\\(em\\)?\\(cp\\|sh\\)\\|telnet\\|plink1?\\'" + nil ,(user-login-name))) + "*Default user to use for specific method/host pairs. +This is an alist of items (METHOD HOST USER). The first matching item +specifies the user to use for a file name which does not specify a +user. METHOD and USER are regular expressions or nil, which is +interpreted as a regular expression which always matches. If no entry +matches, the variable `tramp-default-user' takes effect. + +If the file name does not specify the method, lookup is done using the +empty string for the method name." + :group 'tramp + :type '(repeat (list (regexp :tag "Method regexp") + (regexp :tag "Host regexp") + (string :tag "User")))) + +(defcustom tramp-default-host + (system-name) + "*Default host to use for transferring files. +Useful for su and sudo methods mostly." + :group 'tramp + :type 'string) + +(defcustom tramp-default-proxies-alist nil + "*Route to be followed for specific host/user pairs. +This is an alist of items (HOST USER PROXY). The first matching +item specifies the proxy to be passed for a file name located on +a remote target matching USER@HOST. HOST and USER are regular +expressions or nil, which is interpreted as a regular expression +which always matches. PROXY must be a Tramp filename without a +localname part. Method and user name on PROXY are optional, +which is interpreted with the default values. PROXY can contain +the patterns %h and %u, which are replaced by the strings +matching HOST or USER, respectively." + :group 'tramp + :type '(repeat (list (regexp :tag "Host regexp") + (regexp :tag "User regexp") + (string :tag "Proxy remote name")))) + (defconst tramp-completion-function-alist-rsh - (unless (memq system-type '(windows-nt)) - '((tramp-parse-rhosts "/etc/hosts.equiv") - (tramp-parse-rhosts "~/.rhosts"))) + '((tramp-parse-rhosts "/etc/hosts.equiv") + (tramp-parse-rhosts "~/.rhosts")) "Default list of (FUNCTION FILE) pairs to be examined for rsh methods.") -;; Default values for non-Unices seeked (defconst tramp-completion-function-alist-ssh - (unless (memq system-type '(windows-nt)) - '((tramp-parse-rhosts "/etc/hosts.equiv") - (tramp-parse-rhosts "/etc/shosts.equiv") - (tramp-parse-shosts "/etc/ssh_known_hosts") - (tramp-parse-sconfig "/etc/ssh_config") - (tramp-parse-shostkeys "/etc/ssh2/hostkeys") - (tramp-parse-sknownhosts "/etc/ssh2/knownhosts") - (tramp-parse-rhosts "~/.rhosts") - (tramp-parse-rhosts "~/.shosts") - (tramp-parse-shosts "~/.ssh/known_hosts") - (tramp-parse-sconfig "~/.ssh/config") - (tramp-parse-shostkeys "~/.ssh2/hostkeys") - (tramp-parse-sknownhosts "~/.ssh2/knownhosts"))) + '((tramp-parse-rhosts "/etc/hosts.equiv") + (tramp-parse-rhosts "/etc/shosts.equiv") + (tramp-parse-shosts "/etc/ssh_known_hosts") + (tramp-parse-sconfig "/etc/ssh_config") + (tramp-parse-shostkeys "/etc/ssh2/hostkeys") + (tramp-parse-sknownhosts "/etc/ssh2/knownhosts") + (tramp-parse-rhosts "~/.rhosts") + (tramp-parse-rhosts "~/.shosts") + (tramp-parse-shosts "~/.ssh/known_hosts") + (tramp-parse-sconfig "~/.ssh/config") + (tramp-parse-shostkeys "~/.ssh2/hostkeys") + (tramp-parse-sknownhosts "~/.ssh2/knownhosts")) "Default list of (FUNCTION FILE) pairs to be examined for ssh methods.") -;; Default values for non-Unices seeked (defconst tramp-completion-function-alist-telnet - (unless (memq system-type '(windows-nt)) - '((tramp-parse-hosts "/etc/hosts"))) + '((tramp-parse-hosts "/etc/hosts")) "Default list of (FUNCTION FILE) pairs to be examined for telnet methods.") -;; Default values for non-Unices seeked (defconst tramp-completion-function-alist-su - (unless (memq system-type '(windows-nt)) - '((tramp-parse-passwd "/etc/passwd"))) + '((tramp-parse-passwd "/etc/passwd")) "Default list of (FUNCTION FILE) pairs to be examined for su methods.") +(defconst tramp-completion-function-alist-putty + '((tramp-parse-putty + "HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions")) + "Default list of (FUNCTION REGISTRY) pairs to be examined for putty methods.") + (defvar tramp-completion-function-alist nil "*Alist of methods for remote files. This is a list of entries of the form (NAME PAIR1 PAIR2 ...). @@ -795,6 +840,7 @@ * `tramp-parse-hosts' for \"/etc/hosts\" like files, * `tramp-parse-passwd' for \"/etc/passwd\" like files. * `tramp-parse-netrc' for \"~/.netrc\" like files. + * `tramp-parse-putty' for PuTTY registry keys. FUNCTION can also be a customer defined function. For more details see the info pages.") @@ -838,8 +884,6 @@ (tramp-set-completion-function "sudo" tramp-completion-function-alist-su) (tramp-set-completion-function - "multi" nil) - (tramp-set-completion-function "scpx" tramp-completion-function-alist-ssh) (tramp-set-completion-function "sshx" tramp-completion-function-alist-ssh) @@ -850,10 +894,26 @@ (tramp-set-completion-function "plink1" tramp-completion-function-alist-ssh) (tramp-set-completion-function + "plinkx" tramp-completion-function-alist-putty) + (tramp-set-completion-function "pscp" tramp-completion-function-alist-ssh) (tramp-set-completion-function "fcp" tramp-completion-function-alist-ssh))) +(defconst tramp-echo-mark "_echo\b\b\b\b\b" + "String mark to be transmitted around shell commands. +Used to separate their echo from the output they produce. This +will only be used if we cannot disable remote echo via stty. +This string must have no effect on the remote shell except for +producing some echo which can later be detected by +`tramp-echoed-echo-mark-regexp'. Using some characters followed +by an equal number of backspaces to erase them will usually +suffice.") + +(defconst tramp-echoed-echo-mark-regexp "_echo\\(\b\\( \b\\)?\\)\\{5\\}" + "Regexp which matches `tramp-echo-mark' as it gets echoed by +the remote shell.") + (defcustom tramp-rsh-end-of-line "\n" "*String used for end of line in rsh connections. I don't think this ever needs to be changed, so please tell me about it @@ -878,17 +938,53 @@ :group 'tramp :type 'string) +;; "getconf PATH" yields: +;; HP-UX: /usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin +;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin +;; Linux (Debian, Suse): /bin:/usr/bin +;; FreeBSD: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"! (defcustom tramp-remote-path - ;; "/usr/xpg4/bin" has been placed first, because on Solaris a POSIX - ;; compatible "id" is needed. - '("/usr/xpg4/bin" "/bin" "/usr/bin" "/usr/sbin" "/usr/local/bin" - "/usr/ccs/bin" "/local/bin" "/local/freeware/bin" "/local/gnu/bin" + '(tramp-default-remote-path "/usr/sbin" "/usr/local/bin" + "/local/bin" "/local/freeware/bin" "/local/gnu/bin" "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin") "*List of directories to search for executables on remote host. -Please notify me about other semi-standard directories to include here. +For every remote host, this variable will be set buffer local, +keeping the list of existing directories on that host. You can use `~' in this list, but when searching for a shell which groks -tilde expansion, all directory names starting with `~' will be ignored." +tilde expansion, all directory names starting with `~' will be ignored. + +`Default Directories' represent the list of directories given by +the command \"getconf PATH\". It is recommended to use this +entry on top of this list, because these are the default +directories for POSIX compatible commands." + :group 'tramp + :type '(repeat (choice + (const :tag "Default Directories" tramp-default-remote-path) + (string :tag "Directory")))) + +(defcustom tramp-terminal-type "dumb" + "*Value of TERM environment variable for logging in to remote host. +Because Tramp wants to parse the output of the remote shell, it is easily +confused by ANSI color escape sequences and suchlike. Often, shell init +files conditionalize this setup based on the TERM environment variable." + :group 'tramp + :type 'string) + +(defcustom tramp-remote-process-environment + `("HISTFILE=$HOME/.tramp_history" "HISTSIZE=1" "LC_TIME=C" + ,(concat "TERM=" tramp-terminal-type) + "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH=" + "autocorrect=" "correct=") + + "*List of environment variables to be set on the remote host. + +Each element should be a string of the form ENVVARNAME=VALUE. An +entry ENVVARNAME= diables the corresponding environment variable, +which might have been set in the init files like ~/.profile. + +Special handling is applied to the PATH environment, which should +not be set here. Instead of, it should be set via `tramp-remote-path'." :group 'tramp :type '(repeat string)) @@ -915,7 +1011,7 @@ :type 'regexp) (defcustom tramp-password-prompt-regexp - "^.*\\([pP]assword\\|passphrase\\).*:\^@? *" + "^.*\\([pP]assword\\|[pP]assphrase\\).*:\^@? *" "*Regexp matching password-like prompts. The regexp should match at end of buffer. @@ -930,10 +1026,12 @@ "Login incorrect" "Login Incorrect" "Connection refused" - "Connection closed" + "Connection closed by foreign host." "Sorry, try again." "Name or service not known" - "Host key verification failed.") t) + "Host key verification failed." + "No supported authentication methods left to try!" + "Tramp connection closed") t) ".*" "\\|" "^.*\\(" @@ -1006,7 +1104,7 @@ In fact this expression is empty by intention, it will be used only to check regularly the status of the associated process. The answer will be provided by `tramp-action-process-alive', -`tramp-multi-action-process-alive' and`tramp-action-out-of-band', which see." +`tramp-action-out-of-band', which see." :group 'tramp :type 'regexp) @@ -1020,12 +1118,6 @@ :group 'tramp :type 'string) -(defcustom tramp-discard-garbage nil - "*If non-nil, try to discard garbage sent by remote shell. -Some shells send such garbage upon connection setup." - :group 'tramp - :type 'boolean) - (defcustom tramp-sh-extra-args '(("/bash\\'" . "-norc -noprofile")) "*Alist specifying extra arguments to pass to the remote shell. Entries are (REGEXP . ARGS) where REGEXP is a regular expression @@ -1042,139 +1134,134 @@ '(alist :key-type string :value-type string) '(repeat (cons string string)))) -(defcustom tramp-prefix-format - (if tramp-unified-filenames "/" "/[") +;; XEmacs is distributed with few Lisp packages. Further packages are +;; installed using EFS. If we use a unified filename format, then +;; Tramp is required in addition to EFS. (But why can't Tramp just +;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS +;; just like before.) Another reason for using a separate filename +;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but +;; Tramp only knows how to deal with `file-name-handler-alist', not +;; the other places. + +;; Currently, we have the choice between 'ftp, 'sep, and 'url. +;;;###autoload +(defcustom tramp-syntax + (if (featurep 'xemacs) 'sep 'ftp) + "Tramp filename syntax to be used. + +It can have the following values: + + 'ftp -- Ange-FTP respective EFS like syntax (GNU Emacs default) + 'sep -- Syntax as defined for XEmacs (not available yet for GNU Emacs) + 'url -- URL-like syntax." + :group 'tramp + :type (if (featurep 'xemacs) + '(choice (const :tag "EFS" ftp) + (const :tag "XEmacs" sep) + (const :tag "URL" url)) + '(choice (const :tag "Ange-FTP" ftp) + (const :tag "URL" url)))) + +(defconst tramp-prefix-format + (cond ((equal tramp-syntax 'ftp) "/") + ((equal tramp-syntax 'sep) "/[") + ((equal tramp-syntax 'url) "/") + (t (error "Wrong `tramp-syntax' defined"))) "*String matching the very beginning of tramp file names. -Used in `tramp-make-tramp-file-name' and `tramp-make-tramp-multi-file-name'." - :group 'tramp - :type 'string) - -(defcustom tramp-prefix-regexp +Used in `tramp-make-tramp-file-name'.") + +(defconst tramp-prefix-regexp (concat "^" (regexp-quote tramp-prefix-format)) "*Regexp matching the very beginning of tramp file names. -Should always start with \"^\". Derived from `tramp-prefix-format'." - :group 'tramp - :type 'regexp) - -(defcustom tramp-method-regexp +Should always start with \"^\". Derived from `tramp-prefix-format'.") + +(defconst tramp-method-regexp "[a-zA-Z_0-9-]+" - "*Regexp matching methods identifiers." - :group 'tramp - :type 'regexp) - -;; It is a little bit annoying that in XEmacs case this delimeter is different -;; for single-hop and multi-hop cases. -(defcustom tramp-postfix-single-method-format - (if tramp-unified-filenames ":" "/") - "*String matching delimeter between method and user or host names. -Applicable for single-hop methods. -Used in `tramp-make-tramp-file-name'." - :group 'tramp - :type 'string) - -(defcustom tramp-postfix-single-method-regexp - (regexp-quote tramp-postfix-single-method-format) - "*Regexp matching delimeter between method and user or host names. -Applicable for single-hop methods. -Derived from `tramp-postfix-single-method-format'." - :group 'tramp - :type 'regexp) - -(defcustom tramp-postfix-multi-method-format - ":" + "*Regexp matching methods identifiers.") + +(defconst tramp-postfix-method-format + (cond ((equal tramp-syntax 'ftp) ":") + ((equal tramp-syntax 'sep) "/") + ((equal tramp-syntax 'url) "://") + (t (error "Wrong `tramp-syntax' defined"))) "*String matching delimeter between method and user or host names. -Applicable for multi-hop methods. -Used in `tramp-make-tramp-multi-file-name'." - :group 'tramp - :type 'string) - -(defcustom tramp-postfix-multi-method-regexp - (regexp-quote tramp-postfix-multi-method-format) +Used in `tramp-make-tramp-file-name'.") + +(defconst tramp-postfix-method-regexp + (regexp-quote tramp-postfix-method-format) "*Regexp matching delimeter between method and user or host names. -Applicable for multi-hop methods. -Derived from `tramp-postfix-multi-method-format'." - :group 'tramp - :type 'regexp) - -(defcustom tramp-postfix-multi-hop-format - (if tramp-unified-filenames ":" "/") - "*String matching delimeter between host and next method. -Applicable for multi-hop methods. -Used in `tramp-make-tramp-multi-file-name'." - :group 'tramp - :type 'string) - -(defcustom tramp-postfix-multi-hop-regexp - (regexp-quote tramp-postfix-multi-hop-format) - "*Regexp matching delimeter between host and next method. -Applicable for multi-hop methods. -Derived from `tramp-postfix-multi-hop-format'." - :group 'tramp - :type 'regexp) - -(defcustom tramp-user-regexp - "[^:/ \t]*" - "*Regexp matching user names." - :group 'tramp - :type 'regexp) - -(defcustom tramp-postfix-user-format +Derived from `tramp-postfix-method-format'.") + +(defconst tramp-user-regexp + "[^:/ \t]+" + "*Regexp matching user names.") + +(defconst tramp-postfix-user-format "@" "*String matching delimeter between user and host names. -Used in `tramp-make-tramp-file-name' and `tramp-make-tramp-multi-file-name'." - :group 'tramp - :type 'string) - -(defcustom tramp-postfix-user-regexp +Used in `tramp-make-tramp-file-name'.") + +(defconst tramp-postfix-user-regexp (regexp-quote tramp-postfix-user-format) "*Regexp matching delimeter between user and host names. -Derived from `tramp-postfix-user-format'." - :group 'tramp - :type 'regexp) - -(defcustom tramp-host-regexp - "[a-zA-Z0-9_.-]*" - "*Regexp matching host names." - :group 'tramp - :type 'regexp) - -(defcustom tramp-host-with-port-regexp - "[a-zA-Z0-9_.#-]*" - "*Regexp matching host names." - :group 'tramp - :type 'regexp) - -(defcustom tramp-postfix-host-format - (if tramp-unified-filenames ":" "]") +Derived from `tramp-postfix-user-format'.") + +(defconst tramp-host-regexp + "[a-zA-Z0-9_.-]+" + "*Regexp matching host names.") + +(defconst tramp-prefix-port-format + (cond ((equal tramp-syntax 'ftp) "#") + ((equal tramp-syntax 'sep) "#") + ((equal tramp-syntax 'url) ":") + (t (error "Wrong `tramp-syntax' defined"))) + "*String matching delimeter between host names and port numbers.") + +(defconst tramp-prefix-port-regexp + (regexp-quote tramp-prefix-port-format) + "*Regexp matching delimeter between host names and port numbers. +Derived from `tramp-prefix-port-format'.") + +(defconst tramp-port-regexp + "[0-9]+" + "*Regexp matching port numbers.") + +(defconst tramp-host-with-port-regexp + (concat "\\(" tramp-host-regexp "\\)" + tramp-prefix-port-regexp + "\\(" tramp-port-regexp "\\)") + "*Regexp matching host names with port numbers.") + +(defconst tramp-postfix-host-format + (cond ((equal tramp-syntax 'ftp) ":") + ((equal tramp-syntax 'sep) "]") + ((equal tramp-syntax 'url) "") + (t (error "Wrong `tramp-syntax' defined"))) "*String matching delimeter between host names and localnames. -Used in `tramp-make-tramp-file-name' and `tramp-make-tramp-multi-file-name'." - :group 'tramp - :type 'string) - -(defcustom tramp-postfix-host-regexp +Used in `tramp-make-tramp-file-name'.") + +(defconst tramp-postfix-host-regexp (regexp-quote tramp-postfix-host-format) "*Regexp matching delimeter between host names and localnames. -Derived from `tramp-postfix-host-format'." - :group 'tramp - :type 'regexp) - -(defcustom tramp-localname-regexp +Derived from `tramp-postfix-host-format'.") + +(defconst tramp-localname-regexp ".*$" - "*Regexp matching localnames." - :group 'tramp - :type 'regexp) + "*Regexp matching localnames.") ;; File name format. -(defcustom tramp-file-name-structure +(defconst tramp-file-name-structure (list (concat tramp-prefix-regexp - "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp "\\)?" - "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?" - "\\(" tramp-host-with-port-regexp "\\)" tramp-postfix-host-regexp - "\\(" tramp-localname-regexp "\\)") - 2 4 5 6) + "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\)?" + "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?" + "\\(" tramp-host-regexp + "\\(" tramp-prefix-port-regexp tramp-port-regexp "\\)?" "\\)?" + tramp-postfix-host-regexp + "\\(" tramp-localname-regexp "\\)") + 2 4 5 7) "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \ the tramp file name structure. @@ -1190,69 +1277,81 @@ These numbers are passed directly to `match-string', which see. That means the opening parentheses are counted to identify the pair. -See also `tramp-file-name-regexp'." - :group 'tramp - :type '(list (regexp :tag "File name regexp") - (integer :tag "Paren pair for method name") - (integer :tag "Paren pair for user name ") - (integer :tag "Paren pair for host name ") - (integer :tag "Paren pair for file name "))) +See also `tramp-file-name-regexp'.") ;;;###autoload (defconst tramp-file-name-regexp-unified "\\`/[^/:]+:" "Value for `tramp-file-name-regexp' for unified remoting. Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and -Tramp. See `tramp-file-name-structure-unified' for more explanations.") +Tramp. See `tramp-file-name-structure' for more explanations.") ;;;###autoload (defconst tramp-file-name-regexp-separate "\\`/\\[.*\\]" "Value for `tramp-file-name-regexp' for separate remoting. XEmacs uses a separate filename syntax for Tramp and EFS. -See `tramp-file-name-structure-separate' for more explanations.") +See `tramp-file-name-structure' for more explanations.") ;;;###autoload -(defcustom tramp-file-name-regexp - (if tramp-unified-filenames - tramp-file-name-regexp-unified - tramp-file-name-regexp-separate) +(defconst tramp-file-name-regexp-url + "\\`/[^/:]+://" + "Value for `tramp-file-name-regexp' for URL-like remoting. +See `tramp-file-name-structure' for more explanations.") + +;;;###autoload +(defconst tramp-file-name-regexp + (cond ((equal tramp-syntax 'ftp) tramp-file-name-regexp-unified) + ((equal tramp-syntax 'sep) tramp-file-name-regexp-separate) + ((equal tramp-syntax 'url) tramp-file-name-regexp-url) + (t (error "Wrong `tramp-syntax' defined"))) "*Regular expression matching file names handled by tramp. This regexp should match tramp file names but no other file names. \(When tramp.el is loaded, this regular expression is prepended to `file-name-handler-alist', and that is searched sequentially. Thus, if the tramp entry appears rather early in the `file-name-handler-alist' and is a bit too general, then some files might be considered tramp -files which are not really tramp files. +files which are not really Tramp files. Please note that the entry in `file-name-handler-alist' is made when this file (tramp.el) is loaded. This means that this variable must be set before loading tramp.el. Alternatively, `file-name-handler-alist' can be updated after changing this variable. -Also see `tramp-file-name-structure'." - :group 'tramp - :type 'regexp) +Also see `tramp-file-name-structure'.") ;;;###autoload (defconst tramp-completion-file-name-regexp-unified - "^/$\\|^/[^/:][^/]*$" + (if (memq system-type '(cygwin windows-nt)) + "^\\([a-zA-Z]:\\)?/$\\|^\\([a-zA-Z]:\\)?/[^/:][^/]*$" + "^/$\\|^/[^/:][^/]*$") "Value for `tramp-completion-file-name-regexp' for unified remoting. Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and -Tramp. See `tramp-file-name-structure-unified' for more explanations.") +Tramp. See `tramp-file-name-structure' for more explanations.") ;;;###autoload (defconst tramp-completion-file-name-regexp-separate - "^/\\([[][^]]*\\)?$" + (if (memq system-type '(cygwin windows-nt)) + "^\\([a-zA-Z]:\\)?/\\([[][^]]*\\)?$" + "^/\\([[][^]]*\\)?$") "Value for `tramp-completion-file-name-regexp' for separate remoting. XEmacs uses a separate filename syntax for Tramp and EFS. -See `tramp-file-name-structure-separate' for more explanations.") +See `tramp-file-name-structure' for more explanations.") ;;;###autoload -(defcustom tramp-completion-file-name-regexp - (if tramp-unified-filenames - tramp-completion-file-name-regexp-unified - tramp-completion-file-name-regexp-separate) +(defconst tramp-completion-file-name-regexp-url + (if (memq system-type '(cygwin windows-nt)) + "^\\([a-zA-Z]:\\)?/$\\|^\\([a-zA-Z]:\\)?/[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?$" + "^/$\\|^/[^/:]+\\(:\\(/\\(/[^/]*\\)?\\)?\\)?$") + "Value for `tramp-completion-file-name-regexp' for URL-like remoting. +See `tramp-file-name-structure' for more explanations.") + +;;;###autoload +(defconst tramp-completion-file-name-regexp + (cond ((equal tramp-syntax 'ftp) tramp-completion-file-name-regexp-unified) + ((equal tramp-syntax 'sep) tramp-completion-file-name-regexp-separate) + ((equal tramp-syntax 'url) tramp-completion-file-name-regexp-url) + (t (error "Wrong `tramp-syntax' defined"))) "*Regular expression matching file names handled by tramp completion. This regexp should match partial tramp file names only. @@ -1261,121 +1360,14 @@ before loading tramp.el. Alternatively, `file-name-handler-alist' can be updated after changing this variable. -Also see `tramp-file-name-structure'." - :group 'tramp - :type 'regexp) - -(defcustom tramp-multi-file-name-structure - (list - (concat - tramp-prefix-regexp - "\\(" "\\(" tramp-method-regexp "\\)" "\\)?" - "\\(" "\\(" tramp-postfix-multi-hop-regexp "%s" "\\)+" "\\)?" - tramp-postfix-host-regexp "\\(" tramp-localname-regexp "\\)") - 2 3 -1) - "*Describes the file name structure of `multi' files. -Multi files allow you to contact a remote host in several hops. -This is a list of four elements (REGEXP METHOD HOP LOCALNAME). - -The first element, REGEXP, gives a regular expression to match against -the file name. In this regular expression, `%s' is replaced with the -value of `tramp-multi-file-name-hop-structure'. (Note: in order to -allow multiple hops, you normally want to use something like -\"\\\\(\\\\(%s\\\\)+\\\\)\" in the regular expression. The outer pair -of parentheses is used for the HOP element, see below.) - -All remaining elements are numbers. METHOD gives the number of the -paren pair which matches the method name. HOP gives the number of the -paren pair which matches the hop sequence. LOCALNAME gives the number of -the paren pair which matches the localname (pathname) on the remote host. - -LOCALNAME can also be negative, which means to count from the end. Ie, a -value of -1 means the last paren pair. - -I think it would be good if the regexp matches the whole of the -string, but I haven't actually tried what happens if it doesn't..." - :group 'tramp - :type '(list (regexp :tag "File name regexp") - (integer :tag "Paren pair for method name") - (integer :tag "Paren pair for hops") - (integer :tag "Paren pair to match localname"))) - -(defcustom tramp-multi-file-name-hop-structure - (list - (concat - "\\(" tramp-method-regexp "\\)" tramp-postfix-multi-method-regexp - "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp - "\\(" tramp-host-with-port-regexp "\\)") - 1 2 3) - "*Describes the structure of a hop in multi files. -This is a list of four elements (REGEXP METHOD USER HOST). First -element REGEXP is used to match against the hop. Pair number METHOD -matches the method of one hop, pair number USER matches the user of -one hop, pair number HOST matches the host of one hop. - -This regular expression should match exactly all of one hop." - :group 'tramp - :type '(list (regexp :tag "Hop regexp") - (integer :tag "Paren pair for method name") - (integer :tag "Paren pair for user name") - (integer :tag "Paren pair for host name"))) - -(defcustom tramp-make-multi-tramp-file-format - (list - (concat tramp-prefix-format "%m") - (concat tramp-postfix-multi-hop-format - "%m" tramp-postfix-multi-method-format - "%u" tramp-postfix-user-format - "%h") - (concat tramp-postfix-host-format "%p")) - "*Describes how to construct a `multi' file name. -This is a list of three elements PREFIX, HOP and LOCALNAME. - -The first element PREFIX says how to construct the prefix, the second -element HOP specifies what each hop looks like, and the final element -LOCALNAME says how to construct the localname (pathname). - -In PREFIX, `%%' means `%' and `%m' means the method name. - -In HOP, `%%' means `%' and `%m', `%u', `%h' mean the hop method, hop -user and hop host, respectively. - -In LOCALNAME, `%%' means `%' and `%p' means the localname. - -The resulting file name always contains one copy of PREFIX and one -copy of LOCALNAME, but there is one copy of HOP for each hop in the file -name. - -Note: the current implementation requires the prefix to contain the -method name, followed by all the hops, and the localname must come -last." - :group 'tramp - :type '(list string string string)) - -(defcustom tramp-terminal-type "dumb" - "*Value of TERM environment variable for logging in to remote host. -Because Tramp wants to parse the output of the remote shell, it is easily -confused by ANSI color escape sequences and suchlike. Often, shell init -files conditionalize this setup based on the TERM environment variable." - :group 'tramp - :type 'string) - -(defcustom tramp-completion-without-shell-p nil - "*If nil, use shell wildcards for completion, else rely on Lisp only. -Using shell wildcards for completions has the advantage that it can be -fast even in large directories, but completion is always -case-sensitive. Relying on Lisp only means that case-insensitive -completion is possible (subject to the variable `completion-ignore-case'), -but it might be slow on large directories." - :group 'tramp - :type 'boolean) - -(defcustom tramp-actions-before-shell - '((tramp-password-prompt-regexp tramp-action-password) - (tramp-login-prompt-regexp tramp-action-login) +Also see `tramp-file-name-structure'.") + +(defconst tramp-actions-before-shell + '((tramp-login-prompt-regexp tramp-action-login) + (tramp-password-prompt-regexp tramp-action-password) + (tramp-wrong-passwd-regexp tramp-action-permission-denied) (shell-prompt-pattern tramp-action-succeed) (tramp-shell-prompt-pattern tramp-action-succeed) - (tramp-wrong-passwd-regexp tramp-action-permission-denied) (tramp-yesno-prompt-regexp tramp-action-yesno) (tramp-yn-prompt-regexp tramp-action-yn) (tramp-terminal-prompt-regexp tramp-action-terminal) @@ -1390,51 +1382,19 @@ appended to it. The ACTION should also be a symbol, but a function. When the -corresponding PATTERN matches, the ACTION function is called." - :group 'tramp - :type '(repeat (list variable function))) - -(defcustom tramp-actions-copy-out-of-band +corresponding PATTERN matches, the ACTION function is called.") + +(defconst tramp-actions-copy-out-of-band '((tramp-password-prompt-regexp tramp-action-password) (tramp-wrong-passwd-regexp tramp-action-permission-denied) - (tramp-copy-failed-regexp tramp-action-copy-failed) + (tramp-copy-failed-regexp tramp-action-permission-denied) (tramp-process-alive-regexp tramp-action-out-of-band)) "List of pattern/action pairs. This list is used for copying/renaming with out-of-band methods. -See `tramp-actions-before-shell' for more info." - :group 'tramp - :type '(repeat (list variable function))) - -(defcustom tramp-multi-actions - '((tramp-password-prompt-regexp tramp-multi-action-password) - (tramp-login-prompt-regexp tramp-multi-action-login) - (shell-prompt-pattern tramp-multi-action-succeed) - (tramp-shell-prompt-pattern tramp-multi-action-succeed) - (tramp-wrong-passwd-regexp tramp-multi-action-permission-denied) - (tramp-process-alive-regexp tramp-multi-action-process-alive)) - "List of pattern/action pairs. -This list is used for each hop in multi-hop connections. -See `tramp-actions-before-shell' for more info." - :group 'tramp - :type '(repeat (list variable function))) - -(defcustom tramp-initial-commands - '("unset HISTORY" - "unset correct" - "unset autocorrect") - "List of commands to send to the first remote shell that we see. -These commands will be sent to any shell, and thus they should be -designed to work in such circumstances. Also, restrict the commands -to the bare necessity for getting the remote shell into a state -where it is possible to execute the Bourne-ish shell. - -At the moment, the command to execute the Bourne-ish shell uses strange -quoting which `tcsh' tries to correct, so we send the command \"unset -autocorrect\" to the remote host." - :group 'tramp - :type '(repeat string)) - -;; Chunked sending kluge. We set this to 500 for black-listed constellations + +See `tramp-actions-before-shell' for more info.") + +;; Chunked sending kludge. We set this to 500 for black-listed constellations ;; known to have a bug in `process-send-string'; some ssh connections appear ;; to drop bytes when data is sent too quickly. There is also a connection ;; buffer local variable, which is computed depending on remote host properties @@ -1490,16 +1450,16 @@ If that number exceeds 1000, you can stop the execution by hitting C-g, because your Emacs is likely clean. +When it is necessary to set `tramp-chunksize', you might consider to +use an out-of-the-band method (like \"scp\") instead of an internal one +\(like \"ssh\"), because setting `tramp-chunksize' to non-nil decreases +performance. + If your Emacs is buggy, the code stops and gives you an indication about the value `tramp-chunksize' should be set. Maybe you could just experiment a bit, e.g. changing the values of `init' and `step' in the third line of the code. -When it is necessary to set `tramp-chunksize', you might consider to -use an out-of-the-band method (like \"scp\") instead of an internal one -\(like \"ssh\"), because setting `tramp-chunksize' to non-nil decreases -performance. - Please raise a bug report via \"M-x tramp-bug\" if your system needs this variable to be set as well." :group 'tramp @@ -1518,144 +1478,25 @@ ;;; Internal Variables: -(defvar tramp-buffer-file-attributes nil - "Holds the `ls -ild' output for the current buffer. -This variable is local to each buffer. It is not used if the remote -machine groks Perl. If it is used, it's used as an emulation for -the visited file modtime.") -(make-variable-buffer-local 'tramp-buffer-file-attributes) - -(defvar tramp-md5-function - (cond ((and (require 'md5) (fboundp 'md5)) 'md5) - ((fboundp 'md5-encode) - (lambda (x) (base64-encode-string - (funcall (symbol-function 'md5-encode) x)))) - (t (error "Couldn't find an `md5' function"))) - "Function to call for running the MD5 algorithm.") - (defvar tramp-end-of-output - (concat "///" - (funcall tramp-md5-function - (concat - (prin1-to-string process-environment) - (current-time-string) -;; (prin1-to-string -;; (if (fboundp 'directory-files-and-attributes) -;; (funcall 'directory-files-and-attributes -;; (or (getenv "HOME") -;; (tramp-temporary-file-directory))) -;; (mapcar -;; (lambda (x) -;; (cons x (file-attributes x))) -;; (directory-files (or (getenv "HOME") -;; (tramp-temporary-file-directory)) -;; t)))) - ))) + (concat + "///" (md5 (concat + (prin1-to-string process-environment) (current-time-string)))) "String used to recognize end of output.") -(defvar tramp-connection-function nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-remote-sh nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-login-program nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-login-args nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-copy-program nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-copy-args nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-copy-keep-date-arg nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-encoding-command nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-decoding-command nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-encoding-function nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-decoding-function nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -(defvar tramp-password-end-of-line nil - "This internal variable holds a parameter for `tramp-methods'. -In the connection buffer, this variable has the value of the like-named -method parameter, as specified in `tramp-methods' (which see).") - -;; CCC `local in each buffer'? -(defvar tramp-ls-command nil - "This command is used to get a long listing with numeric user and group ids. -This variable is automatically made buffer-local to each rsh process buffer -upon opening the connection.") - -(defvar tramp-current-multi-method nil - "Name of `multi' connection method for this *tramp* buffer, or nil if not multi. -This variable is automatically made buffer-local to each rsh process buffer -upon opening the connection.") - (defvar tramp-current-method nil - "Connection method for this *tramp* buffer. -This variable is automatically made buffer-local to each rsh process buffer -upon opening the connection.") + "Connection method for this *tramp* buffer.") (defvar tramp-current-user nil - "Remote login name for this *tramp* buffer. -This variable is automatically made buffer-local to each rsh process buffer -upon opening the connection.") + "Remote login name for this *tramp* buffer.") (defvar tramp-current-host nil - "Remote host for this *tramp* buffer. -This variable is automatically made buffer-local to each rsh process buffer -upon opening the connection.") - -(defvar tramp-test-groks-nt nil - "Whether the `test' command groks the `-nt' switch. -\(`test A -nt B' tests if file A is newer than file B.) -This variable is automatically made buffer-local to each rsh process buffer -upon opening the connection.") - -(defvar tramp-file-exists-command nil - "Command to use for checking if a file exists. -This variable is automatically made buffer-local to each rsh process buffer -upon opening the connection.") - -(defconst tramp-uudecode "\ -tramp_uudecode () { -\(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode + "Remote host for this *tramp* buffer.") + +(defconst tramp-uudecode + "(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode cat /tmp/tramp.$$ -rm -f /tmp/tramp.$$ -}" +rm -f /tmp/tramp.$$" "Shell function to implement `uudecode' to standard output. Many systems support `uudecode -o /dev/stdout' or `uudecode -o -' for this or `uudecode -p', but some systems don't, and for them @@ -1667,7 +1508,8 @@ ;; end. ;; The device number is returned as "-1", because there will be a virtual ;; device number set in `tramp-handle-file-attributes' -(defconst tramp-perl-file-attributes "\ +(defconst tramp-perl-file-attributes + "%s -e ' @stat = lstat($ARGV[0]); if (($stat[2] & 0170000) == 0120000) { @@ -1685,7 +1527,7 @@ $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\"; $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\"; printf( - \"(%s %u %s %s (%u %u) (%u %u) (%u %u) %u %u t (%u . %u) -1)\\n\", + \"(%%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u %%u t (%%u . %%u) -1)\\n\", $type, $stat[3], $uid, @@ -1700,11 +1542,14 @@ $stat[2], $stat[1] >> 16 & 0xffff, $stat[1] & 0xffff -);" +);' \"$1\" \"$2\" \"$3\" 2>/dev/null" "Perl script to produce output suitable for use with `file-attributes' -on the remote file system.") - -(defconst tramp-perl-directory-files-and-attributes "\ +on the remote file system. +Escape sequence %s is replaced with name of Perl binary. +This string is passed to `format', so percent characters need to be doubled.") + +(defconst tramp-perl-directory-files-and-attributes + "%s -e ' chdir($ARGV[0]) or printf(\"\\\"Cannot change to $ARGV[0]: $''!''\\\"\\n\"), exit(); opendir(DIR,\".\") or printf(\"\\\"Cannot open directory $ARGV[0]: $''!''\\\"\\n\"), exit(); @list = readdir(DIR); @@ -1731,7 +1576,7 @@ $uid = ($ARGV[1] eq \"integer\") ? $stat[4] : \"\\\"\" . getpwuid($stat[4]) . \"\\\"\"; $gid = ($ARGV[1] eq \"integer\") ? $stat[5] : \"\\\"\" . getgrgid($stat[5]) . \"\\\"\"; printf( - \"(\\\"%s\\\" %s %u %s %s (%u %u) (%u %u) (%u %u) %u %u t (%u . %u) (%u %u))\\n\", + \"(\\\"%%s\\\" %%s %%u %%s %%s (%%u %%u) (%%u %%u) (%%u %%u) %%u %%u t (%%u . %%u) (%%u %%u))\\n\", $filename, $type, $stat[3], @@ -1750,9 +1595,11 @@ $stat[0] >> 16 & 0xffff, $stat[0] & 0xffff); } -printf(\")\\n\");" +printf(\")\\n\");' \"$1\" \"$2\" \"$3\" 2>/dev/null" "Perl script implementing `directory-files-attributes' as Lisp `read'able -output.") +output. +Escape sequence %s is replaced with name of Perl binary. +This string is passed to `format', so percent characters need to be doubled.") ;; ;; These two use uu encoding. ;; (defvar tramp-perl-encode "%s -e'\ @@ -1775,25 +1622,25 @@ ;; Escape sequence %s is replaced with name of Perl binary.") ;; These two use base64 encoding. -(defvar tramp-perl-encode-with-module - "perl -MMIME::Base64 -0777 -ne 'print encode_base64($_)'" +(defconst tramp-perl-encode-with-module + "%s -MMIME::Base64 -0777 -ne 'print encode_base64($_)' 2>/dev/null" "Perl program to use for encoding a file. Escape sequence %s is replaced with name of Perl binary. This string is passed to `format', so percent characters need to be doubled. This implementation requires the MIME::Base64 Perl module to be installed on the remote host.") -(defvar tramp-perl-decode-with-module - "perl -MMIME::Base64 -0777 -ne 'print decode_base64($_)'" +(defconst tramp-perl-decode-with-module + "%s -MMIME::Base64 -0777 -ne 'print decode_base64($_)' 2>/dev/null" "Perl program to use for decoding a file. Escape sequence %s is replaced with name of Perl binary. This string is passed to `format', so percent characters need to be doubled. This implementation requires the MIME::Base64 Perl module to be installed on the remote host.") -(defvar tramp-perl-encode +(defconst tramp-perl-encode "%s -e ' -# This script contributed by Juanma Barranquero . +# This script is contributed by Juanma Barranquero . # Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 # Free Software Foundation, Inc. use strict; @@ -1828,15 +1675,14 @@ (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)), $pad, qq(\\n); -} -'" +}' 2>/dev/null" "Perl program to use for encoding a file. Escape sequence %s is replaced with name of Perl binary. This string is passed to `format', so percent characters need to be doubled.") -(defvar tramp-perl-decode +(defconst tramp-perl-decode "%s -e ' -# This script contributed by Juanma Barranquero . +# This script is contributed by Juanma Barranquero . # Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 # Free Software Foundation, Inc. use strict; @@ -1874,8 +1720,7 @@ ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g); last if $finished; -} -'" +}' 2>/dev/null" "Perl program to use for decoding a file. Escape sequence %s is replaced with name of Perl binary. This string is passed to `format', so percent characters need to be doubled.") @@ -1898,44 +1743,12 @@ "A list of file types returned from the `stat' system call. This is used to map a mode number to a permission string.") -(defvar tramp-dos-coding-system - (if (and (fboundp 'coding-system-p) - (funcall 'coding-system-p '(dos))) - 'dos - 'undecided-dos) - "Some Emacsen know the `dos' coding system, others need `undecided-dos'.") - -(defvar tramp-last-cmd nil - "Internal Tramp variable recording the last command sent. -This variable is buffer-local in every buffer.") -(make-variable-buffer-local 'tramp-last-cmd) - -(defvar tramp-process-echoes nil - "Whether to process echoes from the remote shell.") - -(defvar tramp-last-cmd-time nil - "Internal Tramp variable recording the time when the last cmd was sent. -This variable is buffer-local in every buffer.") -(make-variable-buffer-local 'tramp-last-cmd-time) - -;; This variable does not have the right value in XEmacs. What should -;; I use instead of find-operation-coding-system in XEmacs? -(defvar tramp-feature-write-region-fix - (when (fboundp 'find-operation-coding-system) - (let ((file-coding-system-alist '(("test" emacs-mule)))) - (funcall (symbol-function 'find-operation-coding-system) - 'write-region 0 0 "" nil "test"))) - "Internal variable to say if `write-region' chooses the right coding. -Older versions of Emacs chose the coding system for `write-region' based -on the FILENAME argument, even if VISIT was a string.") - ;; New handlers should be added here. The following operations can be ;; handled using the normal primitives: file-name-as-directory, ;; file-name-directory, file-name-nondirectory, ;; file-name-sans-versions, get-file-buffer. (defconst tramp-file-name-handler-alist - '( - (load . tramp-handle-load) + '((load . tramp-handle-load) (make-symbolic-link . tramp-handle-make-symbolic-link) (file-name-directory . tramp-handle-file-name-directory) (file-name-nondirectory . tramp-handle-file-name-nondirectory) @@ -1943,7 +1756,6 @@ (file-exists-p . tramp-handle-file-exists-p) (file-directory-p . tramp-handle-file-directory-p) (file-executable-p . tramp-handle-file-executable-p) - (file-accessible-directory-p . tramp-handle-file-accessible-directory-p) (file-readable-p . tramp-handle-file-readable-p) (file-regular-p . tramp-handle-file-regular-p) (file-symlink-p . tramp-handle-file-symlink-p) @@ -1964,10 +1776,14 @@ (delete-directory . tramp-handle-delete-directory) (delete-file . tramp-handle-delete-file) (directory-file-name . tramp-handle-directory-file-name) + ;; `executable-find' is not official yet. + (executable-find . tramp-handle-executable-find) + (start-file-process . tramp-handle-start-file-process) + (process-file . tramp-handle-process-file) (shell-command . tramp-handle-shell-command) - (process-file . tramp-handle-process-file) (insert-directory . tramp-handle-insert-directory) (expand-file-name . tramp-handle-expand-file-name) + (substitute-in-file-name . tramp-handle-substitute-in-file-name) (file-local-copy . tramp-handle-file-local-copy) (file-remote-p . tramp-handle-file-remote-p) (insert-file-contents . tramp-handle-insert-file-contents) @@ -1976,7 +1792,6 @@ (make-auto-save-file-name . tramp-handle-make-auto-save-file-name) (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory) (dired-compress-file . tramp-handle-dired-compress-file) - (dired-call-process . tramp-handle-dired-call-process) (dired-recursive-delete-directory . tramp-handle-dired-recursive-delete-directory) (set-visited-file-modtime . tramp-handle-set-visited-file-modtime) @@ -2006,37 +1821,115 @@ ;;; Internal functions which must come first. -(defsubst tramp-message (level fmt-string &rest args) +(defsubst tramp-debug-message (vec fmt-string &rest args) + "Append message to debug buffer. +Message is formatted with FMT-STRING as control string and the remaining +ARGS to actually emit the message (if applicable)." + (when (get-buffer (tramp-buffer-name vec)) + (with-current-buffer (tramp-get-debug-buffer vec) + (goto-char (point-max)) + (unless (bolp) + (insert "\n")) + ;; Timestamp + (insert (format-time-string "%T ")) + ;; Calling function + (let ((btn 1) btf fn) + (while (not fn) + (setq btf (nth 1 (backtrace-frame btn))) + (if (not btf) + (setq fn "") + (when (symbolp btf) + (setq fn (symbol-name btf)) + (unless (and (string-match "^tramp" fn) + (not (string-match + "^tramp\\(-debug\\)?\\(-message\\|-error\\)$" + fn))) + (setq fn nil))) + (setq btn (1+ btn)))) + ;; The following code inserts filename and line number. + ;; Should be deactivated by default, because it is time + ;; consuming. +; (let ((ffn (find-function-noselect (intern fn)))) +; (insert +; (format +; "%s:%d: " +; (file-name-nondirectory (buffer-file-name (car ffn))) +; (with-current-buffer (car ffn) +; (1+ (count-lines (point-min) (cdr ffn))))))) + (insert (format "%s " fn))) + ;; The message + (insert (apply 'format fmt-string args))))) + +(defsubst tramp-message (vec-or-proc level fmt-string &rest args) "Emit a message depending on verbosity level. -First arg LEVEL says to be quiet if `tramp-verbose' is less than LEVEL. The -message is emitted only if `tramp-verbose' is greater than or equal to LEVEL. -Calls function `message' with FMT-STRING as control string and the remaining -ARGS to actually emit the message (if applicable). - -This function expects to be called from the tramp buffer only!" - (when (<= level tramp-verbose) - (apply #'message (concat "tramp: " fmt-string) args) - (when tramp-debug-buffer - (save-excursion - (set-buffer - (tramp-get-debug-buffer - tramp-current-multi-method tramp-current-method - tramp-current-user tramp-current-host)) - (goto-char (point-max)) - (unless (bolp) - (insert "\n")) - (tramp-insert-with-face - 'italic - (concat "# " (apply #'format fmt-string args) "\n")))))) - -(defun tramp-message-for-buffer - (multi-method method user host level fmt-string &rest args) - "Like `tramp-message' but temporarily switches to the tramp buffer. -First three args METHOD, USER, and HOST identify the tramp buffer to use, -remaining args passed to `tramp-message'." - (save-excursion - (set-buffer (tramp-get-buffer multi-method method user host)) - (apply 'tramp-message level fmt-string args))) +VEC-OR-PROC identifies the tramp buffer to use. It can be either a +vector or a process. LEVEL says to be quiet if `tramp-verbose' is +less than LEVEL. The message is emitted only if `tramp-verbose' is +greater than or equal to LEVEL. + +The message is also logged into the debug buffer when `tramp-verbose' +is greater than or equal 4. + +Calls functions `message' and `tramp-debug-message' with FMT-STRING as +control string and the remaining ARGS to actually emit the message (if +applicable)." + (condition-case nil + (when (<= level tramp-verbose) + ;; Match data must be preserved! + (save-match-data + ;; Display only when there is a minimum level. + (when (<= level 3) + (apply 'message + (concat + (cond + ((= level 0) "") + ((= level 1) "") + ((= level 2) "Warning: ") + (t "Tramp: ")) + fmt-string) + args)) + ;; Log only when there is a minimum level. + (when (>= tramp-verbose 4) + (when (and vec-or-proc + (processp vec-or-proc) + (buffer-name (process-buffer vec-or-proc))) + (with-current-buffer (process-buffer vec-or-proc) + ;; Translate proc to vec. + (setq vec-or-proc (tramp-dissect-file-name default-directory)))) + (when (and vec-or-proc (vectorp vec-or-proc)) + (apply 'tramp-debug-message + vec-or-proc + (concat (format "(%d) # " level) fmt-string) + args))))) + ;; Suppress all errors. + (error nil))) + +(defsubst tramp-error (vec-or-proc signal fmt-string &rest args) + "Emit an error. +VEC-OR-PROC identifies the connection to use, SIGNAL is the +signal identifier to be raised, remaining args passed to +`tramp-message'. Finally, signal SIGNAL is raised." + (tramp-message + vec-or-proc 1 "%s" + (error-message-string + (list signal (get signal 'error-message) (apply 'format fmt-string args)))) + (signal signal (list (apply 'format fmt-string args)))) + +(defsubst tramp-error-with-buffer + (buffer vec-or-proc signal fmt-string &rest args) + "Emit an error, and show BUFFER. +If BUFFER is nil, show the connection buffer. Wait for 30\", or until +an input event arrives. The other arguments are passed to `tramp-error'." + (save-window-excursion + (unwind-protect + (apply 'tramp-error vec-or-proc signal fmt-string args) + (when (and vec-or-proc (not (zerop tramp-verbose))) + (let ((enable-recursive-minibuffers t)) + (pop-to-buffer + (or (and (bufferp buffer) buffer) + (and (processp vec-or-proc) (process-buffer vec-or-proc)) + (tramp-get-buffer vec-or-proc))) + (sit-for 30)))))) (defsubst tramp-line-end-position nil "Return point at end of line. @@ -2054,18 +1947,15 @@ Second arg VAR is a symbol. It is used as a variable name to hold the filename structure. It is also used as a prefix for the variables holding the components. For example, if VAR is the symbol `foo', then -`foo' will be bound to the whole structure, `foo-multi-method' will -be bound to the multi-method component, and so on for `foo-method', -`foo-user', `foo-host', `foo-localname'. +`foo' will be bound to the whole structure, `foo-method' will be bound to +the method component, and so on for `foo-user', `foo-host', `foo-localname'. Remaining args are Lisp expressions to be evaluated (inside an implicit `progn'). -If VAR is nil, then we bind `v' to the structure and `multi-method', -`method', `user', `host', `localname' to the components." +If VAR is nil, then we bind `v' to the structure and `method', `user', +`host', `localname' to the components." `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename)) - (,(if var (intern (concat (symbol-name var) "-multi-method")) 'multi-method) - (tramp-file-name-multi-method ,(or var 'v))) (,(if var (intern (concat (symbol-name var) "-method")) 'method) (tramp-file-name-method ,(or var 'v))) (,(if var (intern (concat (symbol-name var) "-user")) 'user) @@ -2077,15 +1967,45 @@ ,@body)) (put 'with-parsed-tramp-file-name 'lisp-indent-function 2) +(put 'with-parsed-tramp-file-name 'edebug-form-spec '(form symbolp body)) ;; Enable debugging. -(eval-and-compile - (when (featurep 'edebug) - (def-edebug-spec with-parsed-tramp-file-name (form symbolp body)))) +;(eval-and-compile +; (when (featurep 'edebug) +; (def-edebug-spec with-parsed-tramp-file-name (form symbolp body)))) ;; Highlight as keyword. (when (functionp 'font-lock-add-keywords) (funcall 'font-lock-add-keywords 'emacs-lisp-mode '("\\"))) +(defmacro with-file-property (vec file property &rest body) + "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache. +FILE must be a local file name on a connection identified via VEC." + `(if (file-name-absolute-p ,file) + (let ((value (tramp-get-file-property ,vec ,file ,property 'undef))) + (when (eq value 'undef) + ;; We cannot pass @body as parameter to + ;; `tramp-set-file-property' because it mangles our + ;; debug messages. + (setq value (progn ,@body)) + (tramp-set-file-property ,vec ,file ,property value)) + value) + ,@body)) +(put 'with-file-property 'lisp-indent-function 3) +(put 'with-file-property 'edebug-form-spec t) + +(defmacro with-connection-property (key property &rest body) + "Checks in Tramp for property PROPERTY, otherwise executes BODY and set." + `(let ((value (tramp-get-connection-property ,key ,property 'undef))) + (when (eq value 'undef) + ;; We cannot pass ,@body as parameter to + ;; `tramp-set-connection-property' because it mangles our debug + ;; messages. + (setq value (progn ,@body)) + (tramp-set-connection-property ,key ,property value)) + value)) +(put 'with-connection-property 'lisp-indent-function 2) +(put 'with-connection-property 'edebug-form-spec t) + (defmacro tramp-let-maybe (variable value &rest body) "Let-bind VARIABLE to VALUE in BODY, but only if VARIABLE is not obsolete. BODY is executed whether or not the variable is obsolete. @@ -2122,12 +2042,17 @@ tramp-completion-function-alist)) (while v - ;; Remove double entries + ;; Remove double entries. (when (member (car v) (cdr v)) (setcdr v (delete (car v) (cdr v)))) - ;; Check for function and file + ;; Check for function and file or registry key. (unless (and (functionp (nth 0 (car v))) - (file-exists-p (nth 1 (car v)))) + (if (string-match "^HKEY_CURRENT_USER" (nth 1 (car v))) + ;; Windows registry. + (and (memq system-type '(cygwin windows-nt)) + (zerop (call-process "reg" nil nil nil "query" (nth 1 (car v))))) + ;; Configuration file. + (file-exists-p (nth 1 (car v))))) (setq r (delete (car v) r))) (setq v (cdr v))) @@ -2136,15 +2061,19 @@ (cons method r))))) (defun tramp-get-completion-function (method) - "Returns list of completion functions for METHOD. + "Returns a list of completion functions for METHOD. For definition of that list see `tramp-set-completion-function'." - (cdr (assoc method tramp-completion-function-alist))) + (cons + ;; Hosts visited once shall be remembered. + `(tramp-parse-connection-properties ,method) + ;; The method related defaults. + (cdr (assoc method tramp-completion-function-alist)))) ;;; File Name Handler Functions: (defun tramp-handle-make-symbolic-link (filename linkname &optional ok-if-already-exists) - "Like `make-symbolic-link' for tramp files. + "Like `make-symbolic-link' for Tramp files. If LINKNAME is a non-Tramp file, it is used verbatim as the target of the symlink. If LINKNAME is a Tramp file, only the localname component is used as the target of the symlink. @@ -2154,12 +2083,12 @@ this can give surprising results if the user/host for the source and target of the symlink differ." (with-parsed-tramp-file-name linkname l - (let ((ln (tramp-get-remote-ln l-multi-method l-method l-user l-host)) + (let ((ln (tramp-get-remote-ln l)) (cwd (file-name-directory l-localname))) (unless ln - (signal 'file-error - (list "Making a symbolic link." - "ln(1) does not exist on the remote host."))) + (tramp-error + l 'file-error + "Making a symbolic link. ln(1) does not exist on the remote host.")) ;; Do the 'confirm if exists' thing. (when (file-exists-p linkname) @@ -2170,7 +2099,8 @@ (format "File %s already exists; make it a link anyway? " l-localname))))) - (signal 'file-already-exists (list "File already exists" l-localname)) + (tramp-error + l 'file-already-exists "File %s already exists" l-localname) (delete-file linkname))) ;; If FILENAME is a Tramp name, use just the localname component. @@ -2184,19 +2114,12 @@ ;; that FILENAME belongs to. (zerop (tramp-send-command-and-check - l-multi-method l-method l-user l-host - (format "cd %s && %s -sf %s %s" - cwd ln - filename - l-localname) - t))))) + l (format "cd %s && %s -sf %s %s" cwd ln filename l-localname) t))))) (defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix) - "Like `load' for tramp files. Not implemented!" - (unless (file-name-absolute-p file) - (error "Tramp cannot `load' files without absolute file name")) - (with-parsed-tramp-file-name file nil + "Like `load' for Tramp files." + (with-parsed-tramp-file-name (expand-file-name file) nil (unless nosuffix (cond ((file-exists-p (concat file ".elc")) (setq file (concat file ".elc"))) @@ -2207,138 +2130,138 @@ ;; Included for safety's sake. (unless (or (file-name-directory file) (string-match "\\.elc?\\'" file)) - (error "File `%s' does not include a `.el' or `.elc' suffix" - file))) + (tramp-error + v 'file-error + "File `%s' does not include a `.el' or `.elc' suffix" file))) (unless noerror (when (not (file-exists-p file)) - (error "Cannot load nonexistent file `%s'" file))) + (tramp-error v 'file-error "Cannot load nonexistent file `%s'" file))) (if (not (file-exists-p file)) nil - (unless nomessage - (message "Loading %s..." file)) + (unless nomessage (tramp-message v 0 "Loading %s..." file)) (let ((local-copy (file-local-copy file))) ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil. (load local-copy noerror t t) (delete-file local-copy)) - (unless nomessage - (message "Loading %s...done" file)) + (unless nomessage (tramp-message v 0 "Loading %s...done" file)) t))) ;; Localname manipulation functions that grok TRAMP localnames... (defun tramp-handle-file-name-directory (file) - "Like `file-name-directory' but aware of TRAMP files." + "Like `file-name-directory' but aware of Tramp files." ;; Everything except the last filename thing is the directory. (with-parsed-tramp-file-name file nil ;; Run the command on the localname portion only. (tramp-make-tramp-file-name - multi-method method user host (file-name-directory (or localname ""))))) + method user host (file-name-directory (or localname ""))))) (defun tramp-handle-file-name-nondirectory (file) - "Like `file-name-nondirectory' but aware of TRAMP files." + "Like `file-name-nondirectory' but aware of Tramp files." (with-parsed-tramp-file-name file nil (file-name-nondirectory localname))) (defun tramp-handle-file-truename (filename &optional counter prev-dirs) - "Like `file-truename' for tramp files." + "Like `file-truename' for Tramp files." (with-parsed-tramp-file-name (expand-file-name filename) nil - (let* ((steps (tramp-split-string localname "/")) - (localnamedir (tramp-let-maybe directory-sep-char ?/ ;for XEmacs - (file-name-as-directory localname))) - (is-dir (string= localname localnamedir)) - (thisstep nil) - (numchase 0) - ;; Don't make the following value larger than necessary. - ;; People expect an error message in a timely fashion when - ;; something is wrong; otherwise they might think that Emacs - ;; is hung. Of course, correctness has to come first. - (numchase-limit 20) - (result nil) ;result steps in reverse order - symlink-target) - (tramp-message-for-buffer - multi-method method user host - 10 "Finding true name for `%s'" filename) - (while (and steps (< numchase numchase-limit)) - (setq thisstep (pop steps)) - (tramp-message-for-buffer - multi-method method user host - 10 "Check %s" - (mapconcat 'identity - (append '("") (reverse result) (list thisstep)) - "/")) - (setq symlink-target - (nth 0 (file-attributes - (tramp-make-tramp-file-name - multi-method method user host - (mapconcat 'identity - (append '("") - (reverse result) - (list thisstep)) - "/"))))) - (cond ((string= "." thisstep) - (tramp-message-for-buffer multi-method method user host - 10 "Ignoring step `.'")) - ((string= ".." thisstep) - (tramp-message-for-buffer multi-method method user host - 10 "Processing step `..'") - (pop result)) - ((stringp symlink-target) - ;; It's a symlink, follow it. - (tramp-message-for-buffer - multi-method method user host - 10 "Follow symlink to %s" symlink-target) - (setq numchase (1+ numchase)) - (when (file-name-absolute-p symlink-target) - (setq result nil)) - ;; If the symlink was absolute, we'll get a string like - ;; "/user@host:/some/target"; extract the - ;; "/some/target" part from it. - (when (tramp-tramp-file-p symlink-target) - (with-parsed-tramp-file-name symlink-target sym - (unless (equal (list multi-method method user host) - (list sym-multi-method sym-method - sym-user sym-host)) - (error "Symlink target `%s' on wrong host" - symlink-target)) - (setq symlink-target localname))) - (setq steps - (append (tramp-split-string symlink-target "/") steps))) - (t - ;; It's a file. - (setq result (cons thisstep result))))) - (when (>= numchase numchase-limit) - (error "Maximum number (%d) of symlinks exceeded" numchase-limit)) - (setq result (reverse result)) - ;; Combine list to form string. - (setq result - (if result - (mapconcat 'identity (cons "" result) "/") - "/")) - (when (and is-dir (or (string= "" result) - (not (string= (substring result -1) "/")))) - (setq result (concat result "/"))) - (tramp-message-for-buffer - multi-method method user host - 10 "True name of `%s' is `%s'" filename result) - (tramp-make-tramp-file-name - multi-method method user host result)))) + (with-file-property v localname "file-truename" + (let* ((steps (tramp-split-string localname "/")) + (localnamedir (tramp-let-maybe directory-sep-char ?/ ;for XEmacs + (file-name-as-directory localname))) + (is-dir (string= localname localnamedir)) + (thisstep nil) + (numchase 0) + ;; Don't make the following value larger than necessary. + ;; People expect an error message in a timely fashion when + ;; something is wrong; otherwise they might think that Emacs + ;; is hung. Of course, correctness has to come first. + (numchase-limit 20) + (result nil) ;result steps in reverse order + symlink-target) + (tramp-message v 4 "Finding true name for `%s'" filename) + (while (and steps (< numchase numchase-limit)) + (setq thisstep (pop steps)) + (tramp-message + v 5 "Check %s" + (mapconcat 'identity + (append '("") (reverse result) (list thisstep)) + "/")) + (setq symlink-target + (nth 0 (file-attributes + (tramp-make-tramp-file-name + method user host + (mapconcat 'identity + (append '("") + (reverse result) + (list thisstep)) + "/"))))) + (cond ((string= "." thisstep) + (tramp-message v 5 "Ignoring step `.'")) + ((string= ".." thisstep) + (tramp-message v 5 "Processing step `..'") + (pop result)) + ((stringp symlink-target) + ;; It's a symlink, follow it. + (tramp-message v 5 "Follow symlink to %s" symlink-target) + (setq numchase (1+ numchase)) + (when (file-name-absolute-p symlink-target) + (setq result nil)) + ;; If the symlink was absolute, we'll get a string like + ;; "/user@host:/some/target"; extract the + ;; "/some/target" part from it. + (when (tramp-tramp-file-p symlink-target) + (unless (tramp-equal-remote filename symlink-target) + (tramp-error + v 'file-error + "Symlink target `%s' on wrong host" symlink-target)) + (setq symlink-target localname)) + (setq steps + (append (tramp-split-string symlink-target "/") + steps))) + (t + ;; It's a file. + (setq result (cons thisstep result))))) + (when (>= numchase numchase-limit) + (tramp-error + v 'file-error + "Maximum number (%d) of symlinks exceeded" numchase-limit)) + (setq result (reverse result)) + ;; Combine list to form string. + (setq result + (if result + (mapconcat 'identity (cons "" result) "/") + "/")) + (when (and is-dir (or (string= "" result) + (not (string= (substring result -1) "/")))) + (setq result (concat result "/"))) + (tramp-message v 4 "True name of `%s' is `%s'" filename result) + (tramp-make-tramp-file-name method user host result))))) ;; Basic functions. (defun tramp-handle-file-exists-p (filename) - "Like `file-exists-p' for tramp files." + "Like `file-exists-p' for Tramp files." (with-parsed-tramp-file-name filename nil - (save-excursion + (with-file-property v localname "file-exists-p" (zerop (tramp-send-command-and-check - multi-method method user host + v (format - (tramp-get-file-exists-command multi-method method user host) + "%s %s" + (tramp-get-file-exists-command v) (tramp-shell-quote-argument localname))))))) +;; Inodes don't exist for some file systems. Therefore we must +;; generate virtual ones. Used in `find-buffer-visiting'. The method +;; applied might be not so efficient (Ange-FTP uses hashes). But +;; performance isn't the major issue given that file transfer will +;; take time. +(defvar tramp-inodes nil + "Keeps virtual inodes numbers.") + ;; Devices must distinguish physical file systems. The device numbers ;; provided by "lstat" aren't unique, because we operate on different hosts. ;; So we use virtual device numbers, generated by Tramp. Both Ange-FTP and ;; EFS use device number "-1". In order to be different, we use device number -;; (-1 x), whereby "x" is unique for a given (multi-method method user host). +;; (-1 x), whereby "x" is unique for a given (method user host). (defvar tramp-devices nil "Keeps virtual device numbers.") @@ -2346,123 +2269,133 @@ ;; when something goes wrong. ;; Daniel Pittman (defun tramp-handle-file-attributes (filename &optional id-format) - "Like `file-attributes' for tramp files." - (when (file-exists-p filename) - ;; file exists, find out stuff - (unless id-format (setq id-format 'integer)) - (with-parsed-tramp-file-name filename nil - (save-excursion - (tramp-convert-file-attributes - multi-method method user host - (if (tramp-get-remote-perl multi-method method user host) - (tramp-handle-file-attributes-with-perl multi-method method user host - localname id-format) - (tramp-handle-file-attributes-with-ls multi-method method user host - localname id-format))))))) - -(defun tramp-handle-file-attributes-with-ls - (multi-method method user host localname &optional id-format) - "Implement `file-attributes' for tramp files using the ls(1) command." + "Like `file-attributes' for Tramp files." + (unless id-format (setq id-format 'integer)) + (with-parsed-tramp-file-name (expand-file-name filename) nil + (with-file-property v localname (format "file-attributes-%s" id-format) + (when (file-exists-p filename) + ;; file exists, find out stuff + (save-excursion + (tramp-convert-file-attributes + v + (if (tramp-get-remote-stat v) + (tramp-handle-file-attributes-with-stat v localname id-format) + (if (tramp-get-remote-perl v) + (tramp-handle-file-attributes-with-perl v localname id-format) + (tramp-handle-file-attributes-with-ls + v localname id-format))))))))) + +(defun tramp-handle-file-attributes-with-ls (vec localname &optional id-format) + "Implement `file-attributes' for Tramp files using the ls(1) command." (let (symlinkp dirp res-inode res-filemodes res-numlinks res-uid res-gid res-size res-symlink-target) - (tramp-message-for-buffer multi-method method user host 10 - "file attributes with ls: %s" - (tramp-make-tramp-file-name - multi-method method user host localname)) + (tramp-message vec 5 "file attributes with ls: %s" localname) (tramp-send-command - multi-method method user host + vec (format "%s %s %s" - (tramp-get-ls-command multi-method method user host) + (tramp-get-ls-command vec) (if (eq id-format 'integer) "-ildn" "-ild") (tramp-shell-quote-argument localname))) - (tramp-wait-for-output) ;; parse `ls -l' output ... - ;; ... inode - (setq res-inode - (condition-case err - (read (current-buffer)) - (invalid-read-syntax - (when (and (equal (cadr err) - "Integer constant overflow in reader") - (string-match - "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'" - (car (cddr err)))) - (let* ((big (read (substring (car (cddr err)) 0 - (match-beginning 1)))) - (small (read (match-string 1 (car (cddr err))))) - (twiddle (/ small 65536))) - (cons (+ big twiddle) - (- small (* twiddle 65536)))))))) - ;; ... file mode flags - (setq res-filemodes (symbol-name (read (current-buffer)))) - ;; ... number links - (setq res-numlinks (read (current-buffer))) - ;; ... uid and gid - (setq res-uid (read (current-buffer))) - (setq res-gid (read (current-buffer))) - (when (eq id-format 'integer) - (unless (numberp res-uid) (setq res-uid -1)) - (unless (numberp res-gid) (setq res-gid -1))) - ;; ... size - (setq res-size (read (current-buffer))) - ;; From the file modes, figure out other stuff. - (setq symlinkp (eq ?l (aref res-filemodes 0))) - (setq dirp (eq ?d (aref res-filemodes 0))) - ;; if symlink, find out file name pointed to - (when symlinkp - (search-forward "-> ") - (setq res-symlink-target - (buffer-substring (point) - (tramp-line-end-position)))) - ;; return data gathered - (list - ;; 0. t for directory, string (name linked to) for symbolic - ;; link, or nil. - (or dirp res-symlink-target nil) - ;; 1. Number of links to file. - res-numlinks - ;; 2. File uid. - res-uid - ;; 3. File gid. - res-gid - ;; 4. Last access time, as a list of two integers. First - ;; integer has high-order 16 bits of time, second has low 16 - ;; bits. - ;; 5. Last modification time, likewise. - ;; 6. Last status change time, likewise. - '(0 0) '(0 0) '(0 0) ;CCC how to find out? - ;; 7. Size in bytes (-1, if number is out of range). - res-size - ;; 8. File modes, as a string of ten letters or dashes as in ls -l. - res-filemodes - ;; 9. t iff file's gid would change if file were deleted and - ;; recreated. Will be set in `tramp-convert-file-attributes' - t - ;; 10. inode number. - res-inode - ;; 11. Device number. Will be replaced by a virtual device number. - -1 - ))) + (with-current-buffer (tramp-get-buffer vec) + (goto-char (point-min)) + ;; ... inode + (setq res-inode + (condition-case err + (read (current-buffer)) + (invalid-read-syntax + (when (and (equal (cadr err) + "Integer constant overflow in reader") + (string-match + "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'" + (car (cddr err)))) + (let* ((big (read (substring (car (cddr err)) 0 + (match-beginning 1)))) + (small (read (match-string 1 (car (cddr err))))) + (twiddle (/ small 65536))) + (cons (+ big twiddle) + (- small (* twiddle 65536)))))))) + ;; ... file mode flags + (setq res-filemodes (symbol-name (read (current-buffer)))) + ;; ... number links + (setq res-numlinks (read (current-buffer))) + ;; ... uid and gid + (setq res-uid (read (current-buffer))) + (setq res-gid (read (current-buffer))) + (if (eq id-format 'integer) + (progn + (unless (numberp res-uid) (setq res-uid -1)) + (unless (numberp res-gid) (setq res-gid -1))) + (progn + (unless (stringp res-uid) (setq res-uid (symbol-name res-uid))) + (unless (stringp res-gid) (setq res-gid (symbol-name res-gid))))) + ;; ... size + (setq res-size (read (current-buffer))) + ;; From the file modes, figure out other stuff. + (setq symlinkp (eq ?l (aref res-filemodes 0))) + (setq dirp (eq ?d (aref res-filemodes 0))) + ;; if symlink, find out file name pointed to + (when symlinkp + (search-forward "-> ") + (setq res-symlink-target + (buffer-substring (point) (tramp-line-end-position)))) + ;; return data gathered + (list + ;; 0. t for directory, string (name linked to) for symbolic + ;; link, or nil. + (or dirp res-symlink-target) + ;; 1. Number of links to file. + res-numlinks + ;; 2. File uid. + res-uid + ;; 3. File gid. + res-gid + ;; 4. Last access time, as a list of two integers. First + ;; integer has high-order 16 bits of time, second has low 16 + ;; bits. + ;; 5. Last modification time, likewise. + ;; 6. Last status change time, likewise. + '(0 0) '(0 0) '(0 0) ;CCC how to find out? + ;; 7. Size in bytes (-1, if number is out of range). + res-size + ;; 8. File modes, as a string of ten letters or dashes as in ls -l. + res-filemodes + ;; 9. t iff file's gid would change if file were deleted and + ;; recreated. Will be set in `tramp-convert-file-attributes' + t + ;; 10. inode number. + res-inode + ;; 11. Device number. Will be replaced by a virtual device number. + -1 + )))) (defun tramp-handle-file-attributes-with-perl - (multi-method method user host localname &optional id-format) - "Implement `file-attributes' for tramp files using a Perl script." - (tramp-message-for-buffer multi-method method user host 10 - "file attributes with perl: %s" - (tramp-make-tramp-file-name - multi-method method user host localname)) - (tramp-maybe-send-perl-script multi-method method user host - tramp-perl-file-attributes - "tramp_file_attributes") - (tramp-send-command multi-method method user host - (format "tramp_file_attributes %s %s" - (tramp-shell-quote-argument localname) id-format)) - (tramp-wait-for-output) - (read (current-buffer))) + (vec localname &optional id-format) + "Implement `file-attributes' for Tramp files using a Perl script." + (tramp-message vec 5 "file attributes with perl: %s" localname) + (tramp-maybe-send-script + vec tramp-perl-file-attributes "tramp_perl_file_attributes") + (tramp-send-command-and-read + vec + (format "tramp_perl_file_attributes %s %s" + (tramp-shell-quote-argument localname) id-format))) + +(defun tramp-handle-file-attributes-with-stat + (vec localname &optional id-format) + "Implement `file-attributes' for Tramp files using stat(1) command." + (tramp-message vec 5 "file attributes with stat: %s" localname) + (tramp-send-command-and-read + vec + (format + "%s -c '((\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s \"%%A\" t %%i.0 -1)' %s" + (tramp-get-remote-stat vec) + (if (eq id-format 'integer) "%u" "\"%U\"") + (if (eq id-format 'integer) "%g" "\"%G\"") + (tramp-shell-quote-argument localname)))) (defun tramp-handle-set-visited-file-modtime (&optional time-list) - "Like `set-visited-file-modtime' for tramp files." + "Like `set-visited-file-modtime' for Tramp files." (unless (buffer-file-name) (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file" (buffer-name))) @@ -2480,16 +2413,16 @@ ;; `tramp-handle-file-attributes-with-ls'. (if (not (equal modtime '(0 0))) (tramp-run-real-handler 'set-visited-file-modtime (list modtime)) - (save-excursion + (progn (tramp-send-command - multi-method method user host + v (format "%s -ild %s" - (tramp-get-ls-command multi-method method user host) + (tramp-get-ls-command v) (tramp-shell-quote-argument localname))) - (tramp-wait-for-output) (setq attr (buffer-substring (point) (progn (end-of-line) (point))))) - (setq tramp-buffer-file-attributes attr)) + (tramp-set-file-property + v localname "visited-file-modtime-ild" attr)) (when (boundp 'last-coding-system-used) (set 'last-coding-system-used coding-system-used)) nil))))) @@ -2499,7 +2432,7 @@ ;; This function makes the same assumption as ;; `tramp-handle-set-visited-file-modtime'. (defun tramp-handle-verify-visited-file-modtime (buf) - "Like `verify-visited-file-modtime' for tramp files. + "Like `verify-visited-file-modtime' for Tramp files. At the time `verify-visited-file-modtime' calls this function, we already know that the buffer is visiting a file and that `visited-file-modtime' does not return 0. Do not call this @@ -2531,53 +2464,48 @@ 2)) ;; modtime has the don't know value. (attr - (save-excursion - (tramp-send-command - multi-method method user host - (format "%s -ild %s" - (tramp-get-ls-command multi-method method user host) - (tramp-shell-quote-argument localname))) - (tramp-wait-for-output) + (tramp-send-command + v + (format "%s -ild %s" + (tramp-get-ls-command v) + (tramp-shell-quote-argument localname))) + (with-current-buffer (tramp-get-buffer v) (setq attr (buffer-substring (point) (progn (end-of-line) (point))))) - (equal tramp-buffer-file-attributes attr)) + (equal + attr + (tramp-get-file-property + v localname "visited-file-modtime-ild" ""))) ;; If file does not exist, say it is not modified ;; if and only if that agrees with the buffer's record. (t (equal mt '(-1 65535)))))))))) (defun tramp-handle-set-file-modes (filename mode) - "Like `set-file-modes' for tramp files." + "Like `set-file-modes' for Tramp files." (with-parsed-tramp-file-name filename nil - (save-excursion - (unless (zerop (tramp-send-command-and-check - multi-method method user host - (format "chmod %s %s" - (tramp-decimal-to-octal mode) - (tramp-shell-quote-argument localname)))) - (signal 'file-error - (list "Doing chmod" - ;; FIXME: extract the proper text from chmod's stderr. - "error while changing file's mode" - filename)))))) + (tramp-flush-file-property v localname) + (unless (zerop (tramp-send-command-and-check + v + (format "chmod %s %s" + (tramp-decimal-to-octal mode) + (tramp-shell-quote-argument localname)))) + ;; FIXME: extract the proper text from chmod's stderr. + (tramp-error + v 'file-error "Error while changing file's mode %s" filename)))) ;; Simple functions using the `test' command. (defun tramp-handle-file-executable-p (filename) - "Like `file-executable-p' for tramp files." + "Like `file-executable-p' for Tramp files." (with-parsed-tramp-file-name filename nil - (zerop (tramp-run-test "-x" filename)))) + (with-file-property v localname "file-executable-p" + (zerop (tramp-run-test "-x" filename))))) (defun tramp-handle-file-readable-p (filename) - "Like `file-readable-p' for tramp files." + "Like `file-readable-p' for Tramp files." (with-parsed-tramp-file-name filename nil - (zerop (tramp-run-test "-r" filename)))) - -(defun tramp-handle-file-accessible-directory-p (filename) - "Like `file-accessible-directory-p' for tramp files." - (with-parsed-tramp-file-name filename nil - (and (zerop (tramp-run-test "-d" filename)) - (zerop (tramp-run-test "-r" filename)) - (zerop (tramp-run-test "-x" filename))))) + (with-file-property v localname "file-readable-p" + (zerop (tramp-run-test "-r" filename))))) ;; When the remote shell is started, it looks for a shell which groks ;; tilde expansion. Here, we assume that all shells which grok tilde @@ -2585,7 +2513,7 @@ ;; newer than). If this breaks, tell me about it and I'll try to do ;; something smarter about it. (defun tramp-handle-file-newer-than-file-p (file1 file2) - "Like `file-newer-than-file-p' for tramp files." + "Like `file-newer-than-file-p' for Tramp files." (cond ((not (file-exists-p file1)) nil) ((not (file-exists-p file2)) @@ -2606,44 +2534,27 @@ ;; However, this only works if both files are Tramp ;; files and both have the same method, same user, same ;; host. - (unless (and (tramp-tramp-file-p file1) - (tramp-tramp-file-p file2)) - (signal - 'file-error - (list - "Cannot check if Tramp file is newer than non-Tramp file" - file1 file2))) - (with-parsed-tramp-file-name file1 v1 - (with-parsed-tramp-file-name file2 v2 - (unless (and (equal v1-multi-method v2-multi-method) - (equal v1-method v2-method) - (equal v1-user v2-user) - (equal v1-host v2-host)) - (signal 'file-error - (list "Files must have same method, user, host" - file1 file2))) - (unless (and (tramp-tramp-file-p file1) - (tramp-tramp-file-p file2)) - (signal 'file-error - (list "Files must be tramp files on same host" - file1 file2))) - (if (tramp-get-test-groks-nt - v1-multi-method v1-method v1-user v1-host) - (zerop (tramp-run-test2 "test" file1 file2 "-nt")) - (zerop (tramp-run-test2 - "tramp_test_nt" file1 file2))))))))))) + (unless (tramp-equal-remote file1 file2) + (with-parsed-tramp-file-name + (if (tramp-tramp-file-p file1) file1 file2) nil + (tramp-error + v 'file-error + "Files %s and %s must have same method, user, host" + file1 file2))) + (with-parsed-tramp-file-name file1 nil + (zerop (tramp-run-test2 + (tramp-get-test-nt-command v) file1 file2))))))))) ;; Functions implemented using the basic functions above. (defun tramp-handle-file-modes (filename) - "Like `file-modes' for tramp files." - (with-parsed-tramp-file-name filename nil - (when (file-exists-p filename) - (tramp-mode-string-to-int - (nth 8 (file-attributes filename)))))) + "Like `file-modes' for Tramp files." + (when (file-exists-p filename) + (tramp-mode-string-to-int + (nth 8 (file-attributes filename))))) (defun tramp-handle-file-directory-p (filename) - "Like `file-directory-p' for tramp files." + "Like `file-directory-p' for Tramp files." ;; Care must be taken that this function returns `t' for symlinks ;; pointing to directories. Surely the most obvious implementation ;; would be `test -d', but that returns false for such symlinks. @@ -2653,78 +2564,52 @@ ;; ;; Alternatives: `cd %s', `test -d %s' (with-parsed-tramp-file-name filename nil - (save-excursion - (zerop - (tramp-send-command-and-check - multi-method method user host - (format "test -d %s" - (tramp-shell-quote-argument localname)) - t))))) ;run command in subshell + (with-file-property v localname "file-directory-p" + (zerop (tramp-run-test "-d" filename))))) (defun tramp-handle-file-regular-p (filename) - "Like `file-regular-p' for tramp files." - (with-parsed-tramp-file-name filename nil - (and (file-exists-p filename) - (eq ?- (aref (nth 8 (file-attributes filename)) 0))))) + "Like `file-regular-p' for Tramp files." + (and (file-exists-p filename) + (eq ?- (aref (nth 8 (file-attributes filename)) 0)))) (defun tramp-handle-file-symlink-p (filename) - "Like `file-symlink-p' for tramp files." + "Like `file-symlink-p' for Tramp files." (with-parsed-tramp-file-name filename nil (let ((x (car (file-attributes filename)))) (when (stringp x) ;; When Tramp is running on VMS, then `file-name-absolute-p' ;; might do weird things. (if (file-name-absolute-p x) - (tramp-make-tramp-file-name - multi-method method user host x) + (tramp-make-tramp-file-name method user host x) x))))) (defun tramp-handle-file-writable-p (filename) - "Like `file-writable-p' for tramp files." + "Like `file-writable-p' for Tramp files." (with-parsed-tramp-file-name filename nil - (if (file-exists-p filename) - ;; Existing files must be writable. - (zerop (tramp-run-test "-w" filename)) - ;; If file doesn't exist, check if directory is writable. - (and (zerop (tramp-run-test - "-d" (file-name-directory filename))) - (zerop (tramp-run-test - "-w" (file-name-directory filename))))))) + (with-file-property v localname "file-writable-p" + (if (file-exists-p filename) + ;; Existing files must be writable. + (zerop (tramp-run-test "-w" filename)) + ;; If file doesn't exist, check if directory is writable. + (and (zerop (tramp-run-test + "-d" (file-name-directory filename))) + (zerop (tramp-run-test + "-w" (file-name-directory filename)))))))) (defun tramp-handle-file-ownership-preserved-p (filename) - "Like `file-ownership-preserved-p' for tramp files." + "Like `file-ownership-preserved-p' for Tramp files." (with-parsed-tramp-file-name filename nil - (let ((attributes (file-attributes filename))) - ;; Return t if the file doesn't exist, since it's true that no - ;; information would be lost by an (attempted) delete and create. - (or (null attributes) - (= (nth 2 attributes) - (tramp-get-remote-uid multi-method method user host)))))) + (with-file-property v localname "file-ownership-preserved-p" + (let ((attributes (file-attributes filename))) + ;; Return t if the file doesn't exist, since it's true that no + ;; information would be lost by an (attempted) delete and create. + (or (null attributes) + (= (nth 2 attributes) (tramp-get-remote-uid v 'integer))))))) ;; Other file name ops. -;; ;; Matthias K,Av(Bppe -;; (defun tramp-handle-directory-file-name (directory) -;; "Like `directory-file-name' for tramp files." -;; (if (and (eq (aref directory (- (length directory) 1)) ?/) -;; (not (eq (aref directory (- (length directory) 2)) ?:))) -;; (substring directory 0 (- (length directory) 1)) -;; directory)) - -;; ;; Philippe Troin -;; (defun tramp-handle-directory-file-name (directory) -;; "Like `directory-file-name' for tramp files." -;; (with-parsed-tramp-file-name directory nil -;; (let ((directory-length-1 (1- (length directory)))) -;; (save-match-data -;; (if (and (eq (aref directory directory-length-1) ?/) -;; (eq (string-match tramp-file-name-regexp directory) 0) -;; (/= (match-end 0) directory-length-1)) -;; (substring directory 0 directory-length-1) -;; directory))))) - (defun tramp-handle-directory-file-name (directory) - "Like `directory-file-name' for tramp files." + "Like `directory-file-name' for Tramp files." ;; If localname component of filename is "/", leave it unchanged. ;; Otherwise, remove any trailing slash from localname component. ;; Method, host, etc, are unchanged. Does it make sense to try @@ -2738,145 +2623,137 @@ ;; Directory listings. -(defun tramp-handle-directory-files (directory - &optional full match nosort files-only) - "Like `directory-files' for tramp files." - (with-parsed-tramp-file-name directory nil - (let (result x) - (save-excursion - (tramp-barf-unless-okay - multi-method method user host - (concat "cd " (tramp-shell-quote-argument localname)) - nil - 'file-error - "tramp-handle-directory-files: couldn't `cd %s'" - (tramp-shell-quote-argument localname)) - (tramp-send-command - multi-method method user host - (concat (tramp-get-ls-command multi-method method user host) - " -a | cat")) - (tramp-wait-for-output) - (goto-char (point-max)) - (while (zerop (forward-line -1)) - (setq x (buffer-substring (point) - (tramp-line-end-position))) - (when (or (not match) (string-match match x)) - (if full - (push (concat (file-name-as-directory directory) - x) - result) - (push x result)))) - (tramp-send-command multi-method method user host "cd") - (tramp-wait-for-output) - ;; Remove non-files or non-directories if necessary. Using - ;; the remote shell for this would probably be way faster. - ;; Maybe something could be adapted from - ;; tramp-handle-file-name-all-completions. - (when files-only - (let ((temp (nreverse result)) - item) - (setq result nil) - (if (equal files-only t) - ;; files only - (while temp - (setq item (pop temp)) - (when (file-regular-p item) - (push item result))) - ;; directories only - (while temp - (setq item (pop temp)) - (when (file-directory-p item) - (push item result))))))) +(defun tramp-handle-directory-files + (directory &optional full match nosort files-only) + "Like `directory-files' for Tramp files." + ;; FILES-ONLY is valid for XEmacs only. + (when (file-directory-p directory) + (setq directory (expand-file-name directory)) + (let ((temp (nreverse (file-name-all-completions "" directory))) + result item) + + (while temp + (setq item (directory-file-name (pop temp))) + (when (and (or (null match) (string-match match item)) + (or (null files-only) + ;; files only + (and (equal files-only t) (file-regular-p item)) + ;; directories only + (file-directory-p item))) + (push (if full (expand-file-name item directory) item) + result))) result))) (defun tramp-handle-directory-files-and-attributes (directory &optional full match nosort id-format) - "Like `directory-files-and-attributes' for tramp files." - (when (tramp-handle-file-exists-p directory) - (save-excursion - (setq directory (tramp-handle-expand-file-name directory)) - (with-parsed-tramp-file-name directory nil - (tramp-maybe-send-perl-script multi-method method user host - tramp-perl-directory-files-and-attributes - "tramp_directory_files_and_attributes") - (tramp-send-command multi-method method user host - (format "tramp_directory_files_and_attributes %s %s" - (tramp-shell-quote-argument localname) - (or id-format 'integer))) - (tramp-wait-for-output) - (let* ((root (cons nil (let ((object (read (current-buffer)))) - (when (stringp object) - (error object)) - object))) - (cell root)) - (while (cdr cell) - (if (and match (not (string-match match (car (cadr cell))))) - ;; Remove from list - (setcdr cell (cddr cell)) - ;; Include in list - (setq cell (cdr cell)) - (let ((l (car cell))) - (tramp-convert-file-attributes multi-method method user host - (cdr l)) - ;; If FULL, make file name absolute - (when full (setcar l (concat directory "/" (car l))))))) - (if nosort - (cdr root) - (sort (cdr root) (lambda (x y) (string< (car x) (car y)))))))))) + "Like `directory-files-and-attributes' for Tramp files." + (unless id-format (setq id-format 'integer)) + (when (file-directory-p directory) + (setq directory (expand-file-name directory)) + (let* ((temp + (copy-tree + (with-parsed-tramp-file-name directory nil + (with-file-property + v localname + (format "directory-files-and-attributes-%s" id-format) + (save-excursion + (mapcar + '(lambda (x) + (cons (car x) + (tramp-convert-file-attributes v (cdr x)))) + (if (tramp-get-remote-stat v) + (tramp-handle-directory-files-and-attributes-with-stat + v localname id-format) + (if (tramp-get-remote-perl v) + (tramp-handle-directory-files-and-attributes-with-perl + v localname id-format))))))))) + result item) + + (while temp + (setq item (pop temp)) + (when (or (null match) (string-match match (car item))) + (when full + (setcar item (expand-file-name (car item) directory))) + (push item result))) + + (if nosort + result + (sort result (lambda (x y) (string< (car x) (car y)))))))) + +(defun tramp-handle-directory-files-and-attributes-with-perl + (vec localname &optional id-format) + "Implement `directory-files-and-attributes' for Tramp files using a Perl script." + (tramp-message vec 5 "directory-files-and-attributes with perl: %s" localname) + (tramp-maybe-send-script + vec tramp-perl-directory-files-and-attributes + "tramp_perl_directory_files_and_attributes") + (let ((object + (tramp-send-command-and-read + vec + (format "tramp_perl_directory_files_and_attributes %s %s" + (tramp-shell-quote-argument localname) id-format)))) + (when (stringp object) (tramp-error vec 'file-error object)) + object)) + +(defun tramp-handle-directory-files-and-attributes-with-stat + (vec localname &optional id-format) + "Implement `directory-files-and-attributes' for Tramp files using stat(1) command." + (tramp-message vec 5 "directory-files-and-attributes with stat: %s" localname) + (tramp-send-command-and-read + vec + (format + (concat + "cd %s; echo \"(\"; (%s -ab | xargs " + "%s -c '(\"%%n\" (\"%%N\") %%h %s %s %%X.0 %%Y.0 %%Z.0 %%s \"%%A\" t %%i.0 -1)'); " + "echo \")\"") + (tramp-shell-quote-argument localname) + (tramp-get-ls-command vec) + (tramp-get-remote-stat vec) + (if (eq id-format 'integer) "%u" "\"%U\"") + (if (eq id-format 'integer) "%g" "\"%G\"")))) ;; This function should return "foo/" for directories and "bar" for -;; files. We use `ls -ad' to get a list of files (including -;; directories), and `find . -type d \! -name . -prune' to get a list -;; of directories. +;; files. (defun tramp-handle-file-name-all-completions (filename directory) - "Like `file-name-all-completions' for tramp files." - (with-parsed-tramp-file-name directory nil - (unless (save-match-data (string-match "/" filename)) - (let* ((nowild tramp-completion-without-shell-p) - result) - (save-excursion - (tramp-barf-unless-okay - multi-method method user host - (format "cd %s" (tramp-shell-quote-argument localname)) - nil 'file-error - "tramp-handle-file-name-all-completions: Couldn't `cd %s'" - (tramp-shell-quote-argument localname)) - - ;; Get a list of directories and files, including reliably - ;; tagging the directories with a trailing '/'. Because I - ;; rock. --daniel@danann.net - (tramp-send-command - multi-method method user host - (format (concat "%s -a %s 2>/dev/null | while read f; do " - "if test -d \"$f\" 2>/dev/null; " - "then echo \"$f/\"; else echo \"$f\"; fi; done") - (tramp-get-ls-command multi-method method user host) - (if (or nowild (zerop (length filename))) - "" - (format "-d %s*" - (tramp-shell-quote-argument filename))))) - - ;; Now grab the output. - (tramp-wait-for-output) - (goto-char (point-max)) - (while (zerop (forward-line -1)) - (push (buffer-substring (point) - (tramp-line-end-position)) - result)) - - (tramp-send-command multi-method method user host "cd") - (tramp-wait-for-output) - - ;; Return the list. - (if nowild - (all-completions filename (mapcar 'list result)) - result)))))) - + "Like `file-name-all-completions' for Tramp files." + (unless (save-match-data (string-match "/" filename)) + (with-parsed-tramp-file-name directory nil + (all-completions + filename + (mapcar + 'list + (with-file-property v localname "file-name-all-completions" + (let (result) + (tramp-barf-unless-okay + v + (format "cd %s" (tramp-shell-quote-argument localname)) + "tramp-handle-file-name-all-completions: Couldn't `cd %s'" + (tramp-shell-quote-argument localname)) + + ;; Get a list of directories and files, including reliably + ;; tagging the directories with a trailing '/'. Because I + ;; rock. --daniel@danann.net + (tramp-send-command + v + (format (concat "%s -ab 2>/dev/null | while read f; do " + "if %s -d \"$f\" 2>/dev/null; " + "then echo \"$f/\"; else echo \"$f\"; fi; done") + (tramp-get-ls-command v) + (tramp-get-test-command v))) + + ;; Now grab the output. + (with-current-buffer (tramp-get-buffer v) + (goto-char (point-max)) + (while (zerop (forward-line -1)) + (push (buffer-substring (point) (tramp-line-end-position)) + result))) + + result))))))) ;; The following isn't needed for Emacs 20 but for 19.34? (defun tramp-handle-file-name-completion (filename directory &optional predicate) - "Like `file-name-completion' for tramp files." + "Like `file-name-completion' for Tramp files." (unless (tramp-tramp-file-p directory) (error "tramp-handle-file-name-completion invoked on non-tramp directory `%s'" @@ -2891,18 +2768,17 @@ (defun tramp-handle-add-name-to-file (filename newname &optional ok-if-already-exists) - "Like `add-name-to-file' for tramp files." + "Like `add-name-to-file' for Tramp files." + (unless (tramp-equal-remote filename newname) + (with-parsed-tramp-file-name + (if (tramp-tramp-file-p filename) filename newname) nil + (tramp-error + v 'file-error + "add-name-to-file: %s" + "only implemented for same method, same user, same host"))) (with-parsed-tramp-file-name filename v1 (with-parsed-tramp-file-name newname v2 - (let ((ln (when v1 (tramp-get-remote-ln - v1-multi-method v1-method v1-user v1-host)))) - (unless (and v1-method v2-method v1-user v2-user v1-host v2-host - (equal v1-multi-method v2-multi-method) - (equal v1-method v2-method) - (equal v1-user v2-user) - (equal v1-host v2-host)) - (error "add-name-to-file: %s" - "only implemented for same method, same user, same host")) + (let ((ln (when v1 (tramp-get-remote-ln v1)))) (when (and (not ok-if-already-exists) (file-exists-p newname) (not (numberp ok-if-already-exists)) @@ -2910,18 +2786,20 @@ (format "File %s already exists; make it a new name anyway? " newname))) - (error "add-name-to-file: file %s already exists" newname)) + (tramp-error + v2 'file-error + "add-name-to-file: file %s already exists" newname)) + (tramp-flush-file-property v2 v2-localname) (tramp-barf-unless-okay - v1-multi-method v1-method v1-user v1-host + v1 (format "%s %s %s" ln (tramp-shell-quote-argument v1-localname) (tramp-shell-quote-argument v2-localname)) - nil 'file-error "error with add-name-to-file, see buffer `%s' for details" (buffer-name)))))) (defun tramp-handle-copy-file (filename newname &optional ok-if-already-exists keep-date) - "Like `copy-file' for tramp files." + "Like `copy-file' for Tramp files." ;; Check if both files are local -- invoke normal copy-file. ;; Otherwise, use tramp from local system. (setq filename (expand-file-name filename)) @@ -2932,12 +2810,11 @@ (tramp-do-copy-or-rename-file 'copy filename newname ok-if-already-exists keep-date) (tramp-run-real-handler - 'copy-file - (list filename newname ok-if-already-exists keep-date)))) + 'copy-file (list filename newname ok-if-already-exists keep-date)))) (defun tramp-handle-rename-file (filename newname &optional ok-if-already-exists) - "Like `rename-file' for tramp files." + "Like `rename-file' for Tramp files." ;; Check if both files are local -- invoke normal rename-file. ;; Otherwise, use tramp from local system. (setq filename (expand-file-name filename)) @@ -2946,9 +2823,9 @@ (if (or (tramp-tramp-file-p filename) (tramp-tramp-file-p newname)) (tramp-do-copy-or-rename-file - 'rename filename newname ok-if-already-exists) - (tramp-run-real-handler 'rename-file - (list filename newname ok-if-already-exists)))) + 'rename filename newname ok-if-already-exists t) + (tramp-run-real-handler + 'rename-file (list filename newname ok-if-already-exists)))) (defun tramp-do-copy-or-rename-file (op filename newname &optional ok-if-already-exists keep-date) @@ -2965,169 +2842,148 @@ and `rename'. FILENAME and NEWNAME must be absolute file names." (unless (memq op '(copy rename)) (error "Unknown operation `%s', must be `copy' or `rename'" op)) - (unless ok-if-already-exists - (when (file-exists-p newname) - (signal 'file-already-exists - (list "File already exists" newname)))) (let ((t1 (tramp-tramp-file-p filename)) - (t2 (tramp-tramp-file-p newname)) - v1-multi-method v1-method v1-user v1-host v1-localname - v2-multi-method v2-method v2-user v2-host v2-localname) - - ;; Check which ones of source and target are Tramp files. - ;; We cannot invoke `with-parsed-tramp-file-name'; - ;; it fails if the file isn't a Tramp file name. - (if t1 - (with-parsed-tramp-file-name filename l - (setq v1-multi-method l-multi-method - v1-method l-method - v1-user l-user - v1-host l-host - v1-localname l-localname)) - (setq v1-localname filename)) - (if t2 - (with-parsed-tramp-file-name newname l - (setq v2-multi-method l-multi-method - v2-method l-method - v2-user l-user - v2-host l-host - v2-localname l-localname)) - (setq v2-localname newname)) - - (cond - ;; Both are Tramp files. - ((and t1 t2) - (cond - ;; Shortcut: if method, host, user are the same for both - ;; files, we invoke `cp' or `mv' on the remote host - ;; directly. - ((and (equal v1-multi-method v2-multi-method) - (equal v1-method v2-method) - (equal v1-user v2-user) - (equal v1-host v2-host)) - (tramp-do-copy-or-rename-file-directly - op v1-multi-method v1-method v1-user v1-host - v1-localname v2-localname keep-date)) - ;; If both source and target are Tramp files, - ;; both are using the same copy-program, then we - ;; can invoke rcp directly. Note that - ;; default-directory should point to a local - ;; directory if we want to invoke rcp. - ((and (not v1-multi-method) - (not v2-multi-method) - (equal v1-method v2-method) - (tramp-method-out-of-band-p - v1-multi-method v1-method v1-user v1-host) - (not (string-match "\\([^#]*\\)#\\(.*\\)" v1-host)) - (not (string-match "\\([^#]*\\)#\\(.*\\)" v2-host))) - (tramp-do-copy-or-rename-file-out-of-band - op filename newname keep-date)) - ;; No shortcut was possible. So we copy the - ;; file first. If the operation was `rename', we go - ;; back and delete the original file (if the copy was - ;; successful). The approach is simple-minded: we - ;; create a new buffer, insert the contents of the - ;; source file into it, then write out the buffer to - ;; the target file. The advantage is that it doesn't - ;; matter which filename handlers are used for the - ;; source and target file. - (t - (tramp-do-copy-or-rename-file-via-buffer - op filename newname keep-date)))) - - ;; One file is a Tramp file, the other one is local. - ((or t1 t2) - ;; If the Tramp file has an out-of-band method, the corresponding - ;; copy-program can be invoked. - (if (and (not v1-multi-method) - (not v2-multi-method) - (or (and t1 (tramp-method-out-of-band-p - v1-multi-method v1-method v1-user v1-host)) - (and t2 (tramp-method-out-of-band-p - v2-multi-method v2-method v2-user v2-host)))) - (tramp-do-copy-or-rename-file-out-of-band - op filename newname keep-date) - ;; Use the generic method via a Tramp buffer. - (tramp-do-copy-or-rename-file-via-buffer - op filename newname keep-date))) - - (t - ;; One of them must be a Tramp file. - (error "Tramp implementation says this cannot happen"))))) + (t2 (tramp-tramp-file-p newname))) + + (unless ok-if-already-exists + (when (and t2 (file-exists-p newname)) + (with-parsed-tramp-file-name newname nil + (tramp-error + v 'file-already-exists "File %s already exists" newname)))) + + (prog1 + (cond + ;; Both are Tramp files. + ((and t1 t2) + (with-parsed-tramp-file-name filename v1 + (with-parsed-tramp-file-name newname v2 + (cond + ;; Shortcut: if method, host, user are the same for both + ;; files, we invoke `cp' or `mv' on the remote host + ;; directly. + ((tramp-equal-remote filename newname) + (tramp-do-copy-or-rename-file-directly + op v1 v1-localname v2-localname keep-date)) + ;; If both source and target are Tramp files, + ;; both are using the same copy-program, then we + ;; can invoke rcp directly. Note that + ;; default-directory should point to a local + ;; directory if we want to invoke rcp. + ((and (equal v1-method v2-method) + (tramp-method-out-of-band-p v1) + (> (nth 7 (file-attributes filename)) + tramp-copy-size-limit)) + (tramp-do-copy-or-rename-file-out-of-band + op filename newname keep-date)) + ;; No shortcut was possible. So we copy the + ;; file first. If the operation was `rename', we go + ;; back and delete the original file (if the copy was + ;; successful). The approach is simple-minded: we + ;; create a new buffer, insert the contents of the + ;; source file into it, then write out the buffer to + ;; the target file. The advantage is that it doesn't + ;; matter which filename handlers are used for the + ;; source and target file. + (t + (tramp-do-copy-or-rename-file-via-buffer + op filename newname keep-date)))))) + + ;; One file is a Tramp file, the other one is local. + ((or t1 t2) + (with-parsed-tramp-file-name (if t1 filename newname) nil + ;; If the Tramp file has an out-of-band method, the corresponding + ;; copy-program can be invoked. + (if (and (tramp-method-out-of-band-p v) + (> (nth 7 (file-attributes filename)) + tramp-copy-size-limit)) + (tramp-do-copy-or-rename-file-out-of-band + op filename newname keep-date) + ;; Use the generic method via a Tramp buffer. + (tramp-do-copy-or-rename-file-via-buffer + op filename newname keep-date)))) + + (t + ;; One of them must be a Tramp file. + (error "Tramp implementation says this cannot happen"))) + ;; When newname did exist, we have wrong cached values. + (when t2 + (with-parsed-tramp-file-name newname nil + (tramp-flush-file-property v localname)))))) (defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date) "Use an Emacs buffer to copy or rename a file. First arg OP is either `copy' or `rename' and indicates the operation. FILENAME is the source file, NEWNAME the target file. KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME." - (let ((trampbuf (get-buffer-create "*tramp output*")) - (modtime (nth 5 (file-attributes filename)))) - (when (and keep-date (or (null modtime) (equal modtime '(0 0)))) - (tramp-message - 1 (concat "Warning: cannot preserve file time stamp" - " with inline copying across machines"))) - (save-excursion - (set-buffer trampbuf) (erase-buffer) - (insert-file-contents-literally filename) - ;; We don't want the target file to be compressed, so we let-bind - ;; `jka-compr-inhibit' to t. - (let ((coding-system-for-write 'binary) - (jka-compr-inhibit t)) - (write-region (point-min) (point-max) newname)) - ;; KEEP-DATE handling. - (when keep-date - (when (and (not (null modtime)) - (not (equal modtime '(0 0)))) - (tramp-touch newname modtime))) - ;; Set the mode. - (set-file-modes newname (file-modes filename))) + (let ((modtime (nth 5 (file-attributes filename)))) + (unwind-protect + (with-temp-buffer + (let ((coding-system-for-read 'binary)) + (insert-file-contents-literally filename)) + ;; We don't want the target file to be compressed, so we + ;; let-bind `jka-compr-inhibit' to t. + (let ((coding-system-for-write 'binary) + (jka-compr-inhibit t)) + (write-region (point-min) (point-max) newname)))) + ;; KEEP-DATE handling. + (when keep-date + (when (and (not (null modtime)) + (not (equal modtime '(0 0)))) + (tramp-touch newname modtime))) + ;; Set the mode. + (set-file-modes newname (file-modes filename)) ;; If the operation was `rename', delete the original file. (unless (eq op 'copy) (delete-file filename)))) (defun tramp-do-copy-or-rename-file-directly - (op multi-method method user host localname1 localname2 keep-date) + (op vec localname1 localname2 keep-date) "Invokes `cp' or `mv' on the remote system. OP must be one of `copy' or `rename', indicating `cp' or `mv', -respectively. METHOD, USER, and HOST specify the connection. -LOCALNAME1 and LOCALNAME2 specify the two arguments of `cp' or `mv'. -If KEEP-DATE is non-nil, preserve the time stamp when copying." +respectively. VEC specifies the connection. LOCALNAME1 and +LOCALNAME2 specify the two arguments of `cp' or `mv'. If +KEEP-DATE is non-nil, preserve the time stamp when copying." ;; CCC: What happens to the timestamp when renaming? (let ((cmd (cond ((and (eq op 'copy) keep-date) "cp -f -p") ((eq op 'copy) "cp -f") ((eq op 'rename) "mv -f") - (t (error + (t (tramp-error + vec 'file-error "Unknown operation `%s', must be `copy' or `rename'" op))))) - (save-excursion - (tramp-send-command - multi-method method user host - (format "%s %s %s" - cmd - (tramp-shell-quote-argument localname1) - (tramp-shell-quote-argument localname2))) - (tramp-wait-for-output) + (tramp-send-command + vec + (format "%s %s %s" + cmd + (tramp-shell-quote-argument localname1) + (tramp-shell-quote-argument localname2))) + (with-current-buffer (tramp-get-buffer vec) (goto-char (point-min)) (unless (or (and (eq op 'copy) keep-date ;; Mask cp -f error. (re-search-forward tramp-operation-not-permitted-regexp nil t)) - (zerop (tramp-send-command-and-check - multi-method method user host nil nil))) - (pop-to-buffer (current-buffer)) - (signal 'file-error - (format "Copying directly failed, see buffer `%s' for details." - (buffer-name))))) + (zerop (tramp-send-command-and-check vec nil))) + (tramp-error-with-buffer + nil vec 'file-error + "Copying directly failed, see buffer `%s' for details." + (buffer-name)))) ;; Set the mode. ;; CCC: Maybe `chmod --reference=localname1 localname2' could be used ;; where available? (unless (or (eq op 'rename) keep-date) (set-file-modes - (tramp-make-tramp-file-name multi-method method user host localname2) - (file-modes - (tramp-make-tramp-file-name - multi-method method user host localname1)))))) + (tramp-make-tramp-file-name + (tramp-file-name-method vec) + (tramp-file-name-user vec) + (tramp-file-name-host vec) + localname2) + (file-modes (tramp-make-tramp-file-name + (tramp-file-name-method vec) + (tramp-file-name-user vec) + (tramp-file-name-host vec) + localname1)))))) (defun tramp-do-copy-or-rename-file-out-of-band (op filename newname keep-date) "Invoke rcp program to copy. @@ -3135,176 +2991,137 @@ be a local filename. The method used must be an out-of-band method." (let ((t1 (tramp-tramp-file-p filename)) (t2 (tramp-tramp-file-p newname)) - v1-multi-method v1-method v1-user v1-host v1-localname - v2-multi-method v2-method v2-user v2-host v2-localname - multi-method method user host copy-program copy-args - source target trampbuf) - - ;; Check which ones of source and target are Tramp files. - ;; We cannot invoke `with-parsed-tramp-file-name'; - ;; it fails if the file isn't a Tramp file name. - (if t1 - (with-parsed-tramp-file-name filename l - (setq v1-multi-method l-multi-method - v1-method l-method - v1-user l-user - v1-host l-host - v1-localname l-localname - multi-method l-multi-method - method (tramp-find-method - v1-multi-method v1-method v1-user v1-host) - user l-user - host l-host - copy-program (tramp-get-method-parameter - v1-multi-method method - v1-user v1-host 'tramp-copy-program) - copy-args (tramp-get-method-parameter - v1-multi-method method - v1-user v1-host 'tramp-copy-args))) - (setq v1-localname filename)) - - (if t2 - (with-parsed-tramp-file-name newname l - (setq v2-multi-method l-multi-method - v2-method l-method - v2-user l-user - v2-host l-host - v2-localname l-localname - multi-method l-multi-method - method (tramp-find-method - v2-multi-method v2-method v2-user v2-host) - user l-user - host l-host - copy-program (tramp-get-method-parameter - v2-multi-method method - v2-user v2-host 'tramp-copy-program) - copy-args (tramp-get-method-parameter - v2-multi-method method - v2-user v2-host 'tramp-copy-args))) - (setq v2-localname newname)) - - ;; The following should be changed. We need a more general - ;; mechanism to parse extra host args. - (if (not t1) - (setq source v1-localname) - (when (string-match "\\([^#]*\\)#\\(.*\\)" v1-host) - (setq copy-args (cons "-P" (cons (match-string 2 v1-host) copy-args))) - (setq v1-host (match-string 1 v1-host))) - (setq source - (tramp-make-copy-program-file-name - v1-user v1-host - (tramp-shell-quote-argument v1-localname)))) - - (if (not t2) - (setq target v2-localname) - (when (string-match "\\([^#]*\\)#\\(.*\\)" v2-host) - (setq copy-args (cons "-P" (cons (match-string 2 v2-host) copy-args))) - (setq v2-host (match-string 1 v2-host))) - (setq target - (tramp-make-copy-program-file-name - v2-user v2-host - (tramp-shell-quote-argument v2-localname)))) - - ;; Handle ControlMaster/ControlPath - (setq copy-args - (mapcar - (lambda (x) - (format-spec - x `((?t . ,(format "/tmp/%s" tramp-temp-name-prefix))))) - copy-args)) - - ;; Handle keep-date argument - (when keep-date - (if t1 - (setq copy-args - (cons (tramp-get-method-parameter - v1-multi-method method - v1-user v1-host 'tramp-copy-keep-date-arg) - copy-args)) - (setq copy-args - (cons (tramp-get-method-parameter - v2-multi-method method - v2-user v2-host 'tramp-copy-keep-date-arg) - copy-args)))) - - (setq copy-args (append copy-args (list source target)) - trampbuf (generate-new-buffer - (tramp-buffer-name multi-method method user host))) - - ;; Use an asynchronous process. By this, password can be handled. - (save-excursion + copy-program copy-args copy-keep-date port spec + source target) + + (with-parsed-tramp-file-name (if t1 filename newname) nil + + ;; Expand hops. Might be necessary for gateway methods. + (setq v (car (tramp-compute-multi-hops v))) + (aset v 3 localname) + + ;; Check which ones of source and target are Tramp files. + (setq source (if t1 (tramp-make-copy-program-file-name v) filename) + target (if t2 (tramp-make-copy-program-file-name v) newname)) + + ;; Check for port number. Until now, there's no need for handling + ;; like method, user, host. + (setq host (tramp-file-name-real-host v) + port (tramp-file-name-port v) + port (or (and port (number-to-string port)) "")) + + ;; Compose copy command. + (setq spec `((?h . ,host) (?u . ,user) (?p . ,port) + (?t . ,(tramp-make-tramp-temp-file v)) + (?k . ,(if keep-date " " ""))) + copy-program (tramp-get-method-parameter + method 'tramp-copy-program) + copy-keep-date (tramp-get-method-parameter + method 'tramp-copy-keep-date) + copy-args + (delq + nil + (mapcar + '(lambda (x) + (setq + ;; " " is indication for keep-date argument. + x (delete " " (mapcar '(lambda (y) (format-spec y spec)) x))) + (unless (member "" x) (mapconcat 'identity x " "))) + (tramp-get-method-parameter + method 'tramp-copy-args)))) ;; Check for program. (when (and (fboundp 'executable-find) - (not (executable-find copy-program))) - (error "Cannot find copy program: %s" copy-program)) - - (set-buffer trampbuf) - (setq tramp-current-multi-method multi-method - tramp-current-method method - tramp-current-user user - tramp-current-host host) - (message "Transferring %s to %s..." filename newname) - - ;; Use rcp-like program for file transfer. + (not (let ((default-directory + (tramp-temporary-file-directory))) + (executable-find copy-program)))) + (tramp-error + v 'file-error "Cannot find copy program: %s" copy-program)) + + (tramp-message v 0 "Transferring %s to %s..." filename newname) + (unwind-protect - (let* ((default-directory - (if (and (stringp default-directory) - (file-accessible-directory-p default-directory)) - default-directory - (tramp-temporary-file-directory))) - (p (apply 'start-process (buffer-name trampbuf) trampbuf - copy-program copy-args))) - (tramp-set-process-query-on-exit-flag p nil) - (tramp-process-actions p multi-method method user host - tramp-actions-copy-out-of-band)) - (kill-buffer trampbuf)) - (message "Transferring %s to %s...done" filename newname) + (with-temp-buffer + ;; The default directory must be remote. + (let ((default-directory + (file-name-directory (if t1 filename newname)))) + ;; Set the transfer process properties. + (tramp-set-connection-property + v "process-name" (buffer-name (current-buffer))) + (tramp-set-connection-property + v "process-buffer" (current-buffer)) + + ;; Use an asynchronous process. By this, password can + ;; be handled. The default directory must be local, in + ;; order to apply the correct `copy-program'. We don't + ;; set a timeout, because the copying of large files can + ;; last longer than 60 secs. + (let ((p (let ((default-directory + (tramp-temporary-file-directory))) + (apply 'start-process + (tramp-get-connection-property + v "process-name" nil) + (tramp-get-connection-property + v "process-buffer" nil) + copy-program + (append copy-args (list source target)))))) + (tramp-message + v 6 "%s" (mapconcat 'identity (process-command p) " ")) + (set-process-sentinel p 'tramp-flush-connection-property) + (tramp-set-process-query-on-exit-flag p nil) + (tramp-process-actions p v tramp-actions-copy-out-of-band)))) + + ;; Reset the transfer process properties. + (tramp-set-connection-property v "process-name" nil) + (tramp-set-connection-property v "process-buffer" nil)) + + (tramp-message v 0 "Transferring %s to %s...done" filename newname) + + ;; Handle KEEP-DATE argument. + (when (and keep-date (not copy-keep-date)) + (set-file-times newname (nth 5 (file-attributes filename)))) ;; Set the mode. - (unless keep-date + (unless (and keep-date copy-keep-date) (set-file-modes newname (file-modes filename)))) ;; If the operation was `rename', delete the original file. (unless (eq op 'copy) (delete-file filename)))) -;; mkdir (defun tramp-handle-make-directory (dir &optional parents) - "Like `make-directory' for tramp files." + "Like `make-directory' for Tramp files." (setq dir (expand-file-name dir)) (with-parsed-tramp-file-name dir nil (save-excursion (tramp-barf-unless-okay - multi-method method user host + v (format " %s %s" (if parents "mkdir -p" "mkdir") (tramp-shell-quote-argument localname)) - nil 'file-error "Couldn't make directory %s" dir)))) -;; CCC error checking? (defun tramp-handle-delete-directory (directory) - "Like `delete-directory' for tramp files." + "Like `delete-directory' for Tramp files." (setq directory (expand-file-name directory)) (with-parsed-tramp-file-name directory nil - (save-excursion - (tramp-send-command - multi-method method user host - (format "rmdir %s ; echo ok" - (tramp-shell-quote-argument localname))) - (tramp-wait-for-output)))) + (tramp-flush-directory-property v localname) + (unless (zerop (tramp-send-command-and-check + v + (format "rmdir %s" + (tramp-shell-quote-argument localname)))) + (tramp-error v 'file-error "Couldn't delete %s" directory)))) (defun tramp-handle-delete-file (filename) - "Like `delete-file' for tramp files." + "Like `delete-file' for Tramp files." (setq filename (expand-file-name filename)) (with-parsed-tramp-file-name filename nil - (save-excursion - (unless (zerop (tramp-send-command-and-check - multi-method method user host - (format "rm -f %s" - (tramp-shell-quote-argument localname)))) - (signal 'file-error "Couldn't delete Tramp file"))))) + (tramp-flush-file-property v localname) + (unless (zerop (tramp-send-command-and-check + v + (format "rm -f %s" + (tramp-shell-quote-argument localname)))) + (tramp-error v 'file-error "Couldn't delete %s" filename)))) ;; Dired. @@ -3312,57 +3129,33 @@ ;; we try and delete two directories under TRAMP :/ (defun tramp-handle-dired-recursive-delete-directory (filename) "Recursively delete the directory given. -This is like `dired-recursive-delete-directory' for tramp files." +This is like `dired-recursive-delete-directory' for Tramp files." (with-parsed-tramp-file-name filename nil - ;; run a shell command 'rm -r ' + (tramp-flush-directory-property v filename) + ;; Run a shell command 'rm -r ' ;; Code shamelessly stolen for the dired implementation and, um, hacked :) - (or (file-exists-p filename) - (signal - 'file-error - (list "Removing old file name" "no such directory" filename))) + (unless (file-exists-p filename) + (tramp-error v 'file-error "No such directory: %s" filename)) ;; Which is better, -r or -R? (-r works for me ) - (tramp-send-command multi-method method user host - (format "rm -r %s" (tramp-shell-quote-argument localname))) + (tramp-send-command + v + (format "rm -r %s" (tramp-shell-quote-argument localname)) + ;; Don't read the output, do it explicitely. + nil t) ;; Wait for the remote system to return to us... ;; This might take a while, allow it plenty of time. - (tramp-wait-for-output 120) + (tramp-wait-for-output (tramp-get-connection-process v) 120) ;; Make sure that it worked... (and (file-exists-p filename) - (error "Failed to recursively delete %s" filename)))) - -(defun tramp-handle-dired-call-process (program discard &rest arguments) - "Like `dired-call-process' for tramp files." - (with-parsed-tramp-file-name default-directory nil - (save-excursion - (tramp-barf-unless-okay - multi-method method user host - (format "cd %s" (tramp-shell-quote-argument localname)) - nil 'file-error - "tramp-handle-dired-call-process: Couldn't `cd %s'" - (tramp-shell-quote-argument localname)) - (tramp-send-command - multi-method method user host - (mapconcat #'tramp-shell-quote-argument (cons program arguments) " ")) - (tramp-wait-for-output)) - (unless discard - ;; We cannot use `insert-buffer' because the tramp buffer - ;; changes its contents before insertion due to calling - ;; `expand-file' and alike. - (insert - (with-current-buffer - (tramp-get-buffer multi-method method user host) - (buffer-string)))) - (save-excursion - (prog1 - (tramp-send-command-and-check multi-method method user host nil) - (tramp-send-command multi-method method user host "cd") - (tramp-wait-for-output))))) + (tramp-error + v 'file-error "Failed to recursively delete %s" filename)))) (defun tramp-handle-dired-compress-file (file &rest ok-flag) - "Like `dired-compress-file' for tramp files." + "Like `dired-compress-file' for Tramp files." ;; OK-FLAG is valid for XEmacs only, but not implemented. ;; Code stolen mainly from dired-aux.el. (with-parsed-tramp-file-name file nil + (tramp-flush-file-property v localname) (save-excursion (let ((suffixes (if (not (featurep 'xemacs)) @@ -3388,11 +3181,10 @@ nil) ((and suffix (nth 2 suffix)) ;; We found an uncompression rule. - (message "Uncompressing %s..." file) + (tramp-message v 0 "Uncompressing %s..." file) (when (zerop (tramp-send-command-and-check - multi-method method user host - (concat (nth 2 suffix) " " localname))) - (message "Uncompressing %s...done" file) + v (concat (nth 2 suffix) " " localname))) + (tramp-message v 0 "Uncompressing %s...done" file) ;; `dired-remove-file' is not defined in XEmacs (funcall (symbol-function 'dired-remove-file) file) (string-match (car suffix) file) @@ -3400,11 +3192,10 @@ (t ;; We don't recognize the file as compressed, so compress it. ;; Try gzip. - (message "Compressing %s..." file) + (tramp-message v 0 "Compressing %s..." file) (when (zerop (tramp-send-command-and-check - multi-method method user host - (concat "gzip -f " localname))) - (message "Compressing %s...done" file) + v (concat "gzip -f " localname))) + (tramp-message v 0 "Compressing %s...done" file) ;; `dired-remove-file' is not defined in XEmacs (funcall (symbol-function 'dired-remove-file) file) (cond ((file-exists-p (concat file ".gz")) @@ -3428,21 +3219,21 @@ (defun tramp-handle-insert-directory (filename switches &optional wildcard full-directory-p) - "Like `insert-directory' for tramp files." - (if (and (featurep 'ls-lisp) - (not (symbol-value 'ls-lisp-use-insert-directory-program))) - (tramp-run-real-handler - 'insert-directory (list filename switches wildcard full-directory-p)) - ;; For the moment, we assume that the remote "ls" program does not - ;; grok "--dired". In the future, we should detect this on - ;; connection setup. - (when (string-match "^--dired\\s-+" switches) - (setq switches (replace-match "" nil t switches))) - (setq filename (expand-file-name filename)) - (with-parsed-tramp-file-name filename nil - (tramp-message-for-buffer - multi-method method user host 10 - "Inserting directory `ls %s %s', wildcard %s, fulldir %s" + "Like `insert-directory' for Tramp files." + (setq filename (expand-file-name filename)) + (with-parsed-tramp-file-name filename nil + (tramp-flush-file-property v localname) + (if (and (featurep 'ls-lisp) + (not (symbol-value 'ls-lisp-use-insert-directory-program))) + (tramp-run-real-handler + 'insert-directory (list filename switches wildcard full-directory-p)) + ;; For the moment, we assume that the remote "ls" program does not + ;; grok "--dired". In the future, we should detect this on + ;; connection setup. + (when (string-match "^--dired\\s-+" switches) + (setq switches (replace-match "" nil t switches))) + (tramp-message + v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s" switches filename (if wildcard "yes" "no") (if full-directory-p "yes" "no")) (when wildcard @@ -3454,80 +3245,45 @@ (setq switches (concat "-d " switches))) (when wildcard (setq switches (concat switches " " wildcard))) - (save-excursion - ;; If `full-directory-p', we just say `ls -l FILENAME'. - ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'. - (if full-directory-p - (tramp-send-command - multi-method method user host - (format "%s %s %s" - (tramp-get-ls-command multi-method method user host) - switches - (if wildcard - localname - (tramp-shell-quote-argument (concat localname "."))))) - (tramp-barf-unless-okay - multi-method method user host - (format "cd %s" (tramp-shell-quote-argument - (file-name-directory localname))) - nil 'file-error - "Couldn't `cd %s'" - (tramp-shell-quote-argument (file-name-directory localname))) - (tramp-send-command - multi-method method user host - (format "%s %s %s" - (tramp-get-ls-command multi-method method user host) - switches - (if wildcard - localname - (if (zerop (length (file-name-nondirectory localname))) - "" - (tramp-shell-quote-argument - (file-name-nondirectory localname))))))) - (sit-for 1) ;needed for rsh but not ssh? - (tramp-wait-for-output)) - ;; The following let-binding is used by code that's commented - ;; out. Let's leave the let-binding in for a while to see - ;; that the commented-out code is really not needed. Commenting-out - ;; happened on 2003-03-13. - (let ((old-pos (point))) - ;; We cannot use `insert-buffer' because the tramp buffer - ;; changes its contents before insertion due to calling - ;; `expand-file' and alike. - (insert - (with-current-buffer - (tramp-get-buffer multi-method method user host) - (buffer-string))) - ;; On XEmacs, we want to call (exchange-point-and-mark t), but - ;; that doesn't exist on Emacs, so we use this workaround instead. - ;; Since zmacs-region-stays doesn't exist in Emacs, this ought to - ;; be safe. Thanks to Daniel Pittman . - ;; (let ((zmacs-region-stays t)) - ;; (exchange-point-and-mark)) - (save-excursion - (tramp-send-command multi-method method user host "cd") - (tramp-wait-for-output)) - ;; For the time being, the XEmacs kludge is commented out. - ;; Please test it on various XEmacs versions to see if it works. - ;; ;; Another XEmacs specialty follows. What's the right way to do - ;; ;; it? - ;; (when (and (featurep 'xemacs) - ;; (eq major-mode 'dired-mode)) - ;; (save-excursion - ;; (require 'dired) - ;; (dired-insert-set-properties old-pos (point)))) - )))) - -;; Continuation of kluge to pacify byte-compiler. -;;(eval-when-compile -;; (when (eq (symbol-function 'dired-insert-set-properties) 'ignore) -;; (fmakunbound 'dired-insert-set-properties))) + ;; If `full-directory-p', we just say `ls -l FILENAME'. + ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'. + (if full-directory-p + (tramp-send-command + v + (format "%s %s %s" + (tramp-get-ls-command v) + switches + (if wildcard + localname + (tramp-shell-quote-argument (concat localname "."))))) + (tramp-barf-unless-okay + v + (format "cd %s" (tramp-shell-quote-argument + (file-name-directory localname))) + "Couldn't `cd %s'" + (tramp-shell-quote-argument (file-name-directory localname))) + (tramp-send-command + v + (format "%s %s %s" + (tramp-get-ls-command v) + switches + (if (or wildcard + (zerop (length (file-name-nondirectory localname)))) + "" + (tramp-shell-quote-argument + (file-name-nondirectory localname)))))) + ;; We cannot use `insert-buffer-substring' because the tramp buffer + ;; changes its contents before insertion due to calling + ;; `expand-file' and alike. + (insert + (with-current-buffer (tramp-get-buffer v) + (buffer-string)))))) ;; CCC is this the right thing to do? (defun tramp-handle-unhandled-file-name-directory (filename) - "Like `unhandled-file-name-directory' for tramp files." + "Like `unhandled-file-name-directory' for Tramp files." (with-parsed-tramp-file-name filename nil - (expand-file-name "~/"))) + (expand-file-name (tramp-make-tramp-file-name method user host "~/")))) ;; Canonicalization of file names. @@ -3548,7 +3304,7 @@ name)) (defun tramp-handle-expand-file-name (name &optional dir) - "Like `expand-file-name' for tramp files. + "Like `expand-file-name' for Tramp files. If the localname part of the given filename starts with \"/../\" then the result will be a local, non-Tramp, filename." ;; If DIR is not given, use DEFAULT-DIRECTORY or "/". @@ -3556,223 +3312,107 @@ ;; Unless NAME is absolute, concat DIR and NAME. (unless (file-name-absolute-p name) (setq name (concat (file-name-as-directory dir) name))) - ;; If NAME is not a tramp file, run the real handler + ;; If NAME is not a Tramp file, run the real handler. (if (not (tramp-tramp-file-p name)) - (tramp-run-real-handler 'expand-file-name - (list name nil)) + (tramp-run-real-handler 'expand-file-name (list name nil)) ;; Dissect NAME. (with-parsed-tramp-file-name name nil (unless (file-name-absolute-p localname) (setq localname (concat "~/" localname))) - (save-excursion - ;; Tilde expansion if necessary. This needs a shell which - ;; groks tilde expansion! The function `tramp-find-shell' is - ;; supposed to find such a shell on the remote host. Please - ;; tell me about it when this doesn't work on your system. - (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname) - (let ((uname (match-string 1 localname)) - (fname (match-string 2 localname))) - ;; We cannot simply apply "~/", because under sudo "~/" is - ;; expanded to the local user home directory but to the - ;; root home directory. On the other hand, using always - ;; the default user name for tilde expansion is not - ;; appropriate either, because ssh and companions might - ;; use a user name from the config file. - (when (and (string-equal uname "~") - (string-match - "\\`su\\(do\\)?\\'" - (tramp-find-method multi-method method user host))) - (setq uname (concat uname (or user "root")))) - ;; CCC fanatic error checking? - (set-buffer (tramp-get-buffer multi-method method user host)) - (erase-buffer) - (tramp-send-command - multi-method method user host - (format "cd %s; pwd" uname) - t) - (tramp-wait-for-output) - (goto-char (point-min)) - (setq uname (buffer-substring (point) (tramp-line-end-position))) - (setq localname (concat uname fname)) - (erase-buffer))) - ;; There might be a double slash, for example when "~/" - ;; expands to "/". Remove this. - (while (string-match "//" localname) - (setq localname (replace-match "/" t t localname))) - ;; No tilde characters in file name, do normal - ;; expand-file-name (this does "/./" and "/../"). We bind - ;; directory-sep-char here for XEmacs on Windows, which would - ;; otherwise use backslash. `default-directory' is bound to - ;; "/", because on Windows there would be problems with UNC - ;; shares or Cygwin mounts. - (tramp-let-maybe directory-sep-char ?/ - (let ((default-directory "/")) - (tramp-make-tramp-file-name - multi-method (or method (tramp-find-default-method user host)) - user host - (tramp-drop-volume-letter - (tramp-run-real-handler 'expand-file-name - (list localname)))))))))) - -;; old version follows. it uses ".." to cross file handler -;; boundaries. -;; ;; Look if localname starts with "/../" construct. If this is -;; ;; the case, then we return a local name instead of a remote name. -;; (if (string-match "^/\\.\\./" localname) -;; (expand-file-name (substring localname 3)) -;; ;; No tilde characters in file name, do normal -;; ;; expand-file-name (this does "/./" and "/../"). We bind -;; ;; directory-sep-char here for XEmacs on Windows, which -;; ;; would otherwise use backslash. -;; (let ((directory-sep-char ?/)) -;; (tramp-make-tramp-file-name -;; multi-method method user host -;; (tramp-drop-volume-letter -;; (tramp-run-real-handler 'expand-file-name -;; (list localname)))))))))) - -;; Remote commands. - -(defvar tramp-async-proc nil - "Global variable keeping asynchronous process object. -Used in `tramp-handle-shell-command'") - -(defvar tramp-display-shell-command-buffer t - "Whether to display output buffer of `shell-command'. -This is necessary for handling DISPLAY of `process-file'.") - -(defun tramp-handle-shell-command (command &optional output-buffer error-buffer) - "Like `shell-command' for tramp files. -This will break if COMMAND prints a newline, followed by the value of -`tramp-end-of-output', followed by another newline." - ;; Asynchronous processes are far from being perfect. But it works at least - ;; for `find-grep-dired' and `find-name-dired' in Emacs 22. - (if (tramp-tramp-file-p default-directory) - (with-parsed-tramp-file-name default-directory nil - (let ((curbuf (current-buffer)) - (asynchronous (string-match "[ \t]*&[ \t]*\\'" command)) - status) - (unless output-buffer - (setq output-buffer - (get-buffer-create - (if asynchronous - "*Async Shell Command*" - "*Shell Command Output*"))) - (set-buffer output-buffer) - (erase-buffer)) - (unless (bufferp output-buffer) - (setq output-buffer (current-buffer))) - (set-buffer output-buffer) - ;; Tramp doesn't handle the asynchronous case by an asynchronous - ;; process. Instead of, another asynchronous process is opened - ;; which gets the output of the (synchronous) Tramp process - ;; via process-filter. ERROR-BUFFER is disabled. - (when asynchronous - (setq command (substring command 0 (match-beginning 0)) - error-buffer nil - tramp-async-proc (start-process (buffer-name output-buffer) - output-buffer "cat"))) - (save-excursion - (tramp-barf-unless-okay - multi-method method user host - (format "cd %s" (tramp-shell-quote-argument localname)) - nil 'file-error - "tramp-handle-shell-command: Couldn't `cd %s'" - (tramp-shell-quote-argument localname)) - ;; Define the process filter - (when asynchronous - (set-process-filter - (get-buffer-process - (tramp-get-buffer multi-method method user host)) - '(lambda (process string) - ;; Write the output into the Tramp Process - (save-current-buffer - (set-buffer (process-buffer process)) - (goto-char (point-max)) - (insert string)) - ;; Hand-over output to asynchronous process. - (let ((end - (string-match - (regexp-quote tramp-end-of-output) string))) - (when end - (setq string - (substring string 0 (1- (match-beginning 0))))) - (process-send-string tramp-async-proc string) - (when end - (set-process-filter process nil) - (process-send-eof tramp-async-proc)))))) - ;; Send the command - (tramp-send-command - multi-method method user host - (if error-buffer - (format "( %s ) 2>/tmp/tramp.$$.err; tramp_old_status=$?" - command) - (format "%s; tramp_old_status=$?" command))) - (unless asynchronous - (tramp-wait-for-output))) - (unless asynchronous - ;; We cannot use `insert-buffer' because the tramp buffer - ;; changes its contents before insertion due to calling - ;; `expand-file' and alike. - (insert - (with-current-buffer - (tramp-get-buffer multi-method method user host) - (buffer-string)))) - (when error-buffer - (save-excursion - (unless (bufferp error-buffer) - (setq error-buffer (get-buffer-create error-buffer))) - (tramp-send-command - multi-method method user host - "cat /tmp/tramp.$$.err") - (tramp-wait-for-output) - (set-buffer error-buffer) - ;; Same comment as above - (insert - (with-current-buffer - (tramp-get-buffer multi-method method user host) - (buffer-string))) - (tramp-send-command-and-check - multi-method method user host "rm -f /tmp/tramp.$$.err"))) - (save-excursion - (tramp-send-command multi-method method user host "cd") - (unless asynchronous - (tramp-wait-for-output)) - (tramp-send-command - multi-method method user host - (concat "tramp_set_exit_status $tramp_old_status;" - " echo tramp_exit_status $?")) - (unless asynchronous - (tramp-wait-for-output) - (goto-char (point-max)) - (unless (search-backward "tramp_exit_status " nil t) - (error "Couldn't find exit status of `%s'" command)) - (skip-chars-forward "^ ") - (setq status (read (current-buffer))))) - (unless (zerop (buffer-size)) - (when tramp-display-shell-command-buffer - (display-buffer output-buffer))) - (set-buffer curbuf) - status)) - ;; The following is only executed if something strange was - ;; happening. Emit a helpful message and do it anyway. - (message "tramp-handle-shell-command called with non-tramp directory: `%s'" - default-directory) - (tramp-run-real-handler 'shell-command - (list command output-buffer error-buffer)))) - -(defun tramp-handle-process-file (program &optional infile buffer display &rest args) - "Like `process-file' for Tramp files." - (when infile (error "Implementation does not handle input from file")) - (when (and (numberp buffer) (zerop buffer)) - (error "Implementation does not handle immediate return")) - (when (consp buffer) (error "Implementation does not handle error files")) - (let ((tramp-display-shell-command-buffer display)) - (shell-command - (mapconcat 'tramp-shell-quote-argument (cons program args) " ") - buffer))) - -;; File Editing. + ;; Tilde expansion if necessary. This needs a shell which + ;; groks tilde expansion! The function `tramp-find-shell' is + ;; supposed to find such a shell on the remote host. Please + ;; tell me about it when this doesn't work on your system. + (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" localname) + (let ((uname (match-string 1 localname)) + (fname (match-string 2 localname))) + ;; We cannot simply apply "~/", because under sudo "~/" is + ;; expanded to the local user home directory but to the + ;; root home directory. On the other hand, using always + ;; the default user name for tilde expansion is not + ;; appropriate either, because ssh and companions might + ;; use a user name from the config file. + (when (and (string-equal uname "~") + (string-match "\\`su\\(do\\)?\\'" method)) + (setq uname (concat uname user))) + (setq uname + (with-connection-property v uname + (tramp-send-command v (format "cd %s; pwd" uname)) + (with-current-buffer (tramp-get-buffer v) + (goto-char (point-min)) + (buffer-substring (point) (tramp-line-end-position))))) + (setq localname (concat uname fname)))) + ;; There might be a double slash, for example when "~/" + ;; expands to "/". Remove this. + (while (string-match "//" localname) + (setq localname (replace-match "/" t t localname))) + ;; No tilde characters in file name, do normal + ;; expand-file-name (this does "/./" and "/../"). We bind + ;; `directory-sep-char' here for XEmacs on Windows, which + ;; would otherwise use backslash. `default-directory' is + ;; bound, because on Windows there would be problems with UNC + ;; shares or Cygwin mounts. + (tramp-let-maybe directory-sep-char ?/ + (let ((default-directory (tramp-temporary-file-directory))) + (tramp-make-tramp-file-name + method user host + (tramp-drop-volume-letter + (tramp-run-real-handler 'expand-file-name + (list localname))))))))) + +(defun tramp-handle-substitute-in-file-name (filename) + "Like `substitute-in-file-name' for Tramp files. +\"//\" and \"/~\" substitute only in the local filename part. +If the URL Tramp syntax is chosen, \"//\" as method delimeter and \"/~\" at +beginning of local filename are not substituted." + (with-parsed-tramp-file-name filename nil + (if (equal tramp-syntax 'url) + ;; We need to check localname only. The other parts cannot contain + ;; "//" or "/~". + (if (and (> (length localname) 1) + (or (string-match "//" localname) + (string-match "/~" localname 1))) + (tramp-run-real-handler 'substitute-in-file-name (list filename)) + (tramp-make-tramp-file-name + (when method (substitute-in-file-name method)) + (when user (substitute-in-file-name user)) + (when host (substitute-in-file-name host)) + (when localname (substitute-in-file-name localname)))) + ;; Ignore in LOCALNAME everything before "//" or "/~". + (when (and (stringp localname) (string-match ".+?/\\(/\\|~\\)" localname)) + (setq filename + (tramp-make-tramp-file-name + method user host (replace-match "\\1" nil nil localname))) + ;; "/m:h:~" does not work for completion. We use "/m:h:~/". + (when (string-match "~$" filename) + (setq filename (concat filename "/")))) + (tramp-run-real-handler 'substitute-in-file-name (list filename))))) + +;; In XEmacs, electricity is implemented via a key map for ?/ and ?~, +;; which calls corresponding functions (see minibuf.el). +(when (fboundp 'minibuffer-electric-separator) + (mapcar + '(lambda (x) + (eval + `(defadvice ,x + (around ,(intern (format "tramp-advice-%s" x)) activate) + "Invoke `substitute-in-file-name' for Tramp files." + (if (and (symbol-value 'minibuffer-electric-file-name-behavior) + (tramp-tramp-file-p (buffer-substring))) + ;; We don't need to handle `last-input-event', because + ;; due to the key map we know it must be ?/ or ?~. + (let ((s (concat (buffer-substring (point-min) (point)) + (string last-command-char)))) + (delete-region (point-min) (point)) + (insert (substitute-in-file-name s)) + (setq ad-return-value last-command-char)) + ad-do-it)))) + + '(minibuffer-electric-separator + minibuffer-electric-tilde))) + + +;;; Remote commands. (defsubst tramp-make-temp-file (filename) (concat @@ -3781,102 +3421,254 @@ (tramp-temporary-file-directory))) (file-name-extension filename t))) +(defsubst tramp-make-tramp-temp-file (vec) + (format + "/tmp/%s%s" + tramp-temp-name-prefix + (if (get-buffer-process (tramp-get-connection-buffer vec)) + (process-id (get-buffer-process (tramp-get-connection-buffer vec))) + (emacs-pid)))) + +(defun tramp-handle-executable-find (command) + "Like `executable-find' for Tramp files." + (with-parsed-tramp-file-name default-directory nil + (tramp-find-executable v command tramp-remote-path t))) + +;; We use BUFFER also as connection buffer during setup. Because of +;; this, its original contents must be saved, and restored once +;; connection has been setup. +(defun tramp-handle-start-file-process (name buffer program &rest args) + "Like `start-file-process' for Tramp files." + (with-parsed-tramp-file-name default-directory nil + (unwind-protect + (progn + ;; Set the new process properties. + (tramp-set-connection-property v "process-name" name) + (tramp-set-connection-property + v "process-buffer" + (get-buffer-create + ;; BUFFER can be nil. + (or buffer (generate-new-buffer-name (tramp-buffer-name v))))) + ;; Activate narrowing in order to save BUFFER contents. + (with-current-buffer (tramp-get-connection-buffer v) + (narrow-to-region (point-max) (point-max))) + ;; Goto working directory. `tramp-send-command' opens a new + ;; connection. + (tramp-send-command + v (format "cd %s" (tramp-shell-quote-argument localname))) + ;; Send the command. + (tramp-send-command + v + (format "%s; exit" + (mapconcat 'tramp-shell-quote-argument + (cons program args) " ")) + nil t) ; nooutput + ;; Return process. + (tramp-get-connection-process v)) + ;; Save exit. + (with-current-buffer (tramp-get-connection-buffer v) (widen)) + (tramp-set-connection-property v "process-name" nil) + (tramp-set-connection-property v "process-buffer" nil)))) + +(defun tramp-handle-process-file + (program &optional infile destination display &rest args) + "Like `process-file' for Tramp files." + ;; The implementation is not complete yet. + (when (and (numberp destination) (zerop destination)) + (error "Implementation does not handle immediate return")) + + (with-parsed-tramp-file-name default-directory nil + (let ((temp-name-prefix (tramp-make-tramp-temp-file v)) + command input stderr outbuf ret) + ;; Compute command. + (setq command (mapconcat 'tramp-shell-quote-argument + (cons program args) " ")) + ;; Determine input. + (if (null infile) + (setq input "/dev/null") + (setq infile (expand-file-name infile)) + (if (tramp-equal-remote default-directory infile) + ;; INFILE is on the same remote host. + (setq input (with-parsed-tramp-file-name infile nil localname)) + ;; INFILE must be copied to remote host. + (setq input (concat temp-name-prefix ".in")) + (copy-file + infile + (tramp-make-tramp-file-name method user host input) + t))) + (when input (setq command (format "%s <%s" command input))) + + ;; Determine output. + (cond + ;; Just a buffer + ((bufferp destination) + (setq outbuf destination)) + ;; A buffer name + ((stringp destination) + (setq outbuf (get-buffer-create destination))) + ;; (REAL-DESTINATION ERROR-DESTINATION) + ((consp destination) + ;; output + (cond + ((bufferp (car destination)) + (setq outbuf (car destination))) + ((stringp (car destination)) + (setq outbuf (get-buffer-create (car destination))))) + ;; stderr + (cond + ((stringp (cadr destination)) + (setcar (cdr destination) (expand-file-name (cadr destination))) + (if (tramp-equal-remote default-directory (cadr destination)) + ;; stderr is on the same remote host. + (setq stderr (with-parsed-tramp-file-name + (cadr destination) nil localname)) + ;; stderr must be copied to remote host. The temporary + ;; file must be deleted after execution. + (setq stderr (concat temp-name-prefix ".err")))) + ;; stderr to be discarded + ((null (cadr destination)) + (setq stderr "/dev/null")))) + ;; 't + (destination + (setq outbuf (current-buffer)))) + (when stderr (setq command (format "%s 2>%s" command stderr))) + + ;; If we have a temporary file, it must be removed after operation. + (when (and input (string-match temp-name-prefix input)) + (setq command (format "%s; rm %s" command input))) + ;; Goto working directory. + (tramp-send-command + v (format "cd %s" (tramp-shell-quote-argument localname))) + ;; Send the command. It might not return in time, so we protect it. + (condition-case nil + (unwind-protect + (tramp-send-command v command) + ;; We should show the output anyway. + (when outbuf + (with-current-buffer outbuf + (insert-buffer-substring (tramp-get-connection-buffer v))) + (when display (display-buffer outbuf)))) + ;; When the user did interrupt, we should do it also. + (error + (kill-buffer (tramp-get-connection-buffer v)) + (setq ret 1))) + (unless ret + ;; Check return code. + (setq ret (tramp-send-command-and-check v nil)) + ;; Provide error file. + (when (and stderr (string-match temp-name-prefix stderr)) + (rename-file (tramp-make-tramp-file-name method user host stderr) + (cadr destination) t))) + ;; Return exit status. + ret))) + +(defun tramp-handle-call-process-region + (start end program &optional delete buffer display &rest args) + "Like `call-process-region' for Tramp files." + (let ((tmpfile (tramp-make-temp-file ""))) + (write-region start end tmpfile) + (when delete (delete-region start end)) + (unwind-protect + (apply 'call-process program tmpfile buffer display args) + (delete-file tmpfile)))) + +(defun tramp-handle-shell-command + (command &optional output-buffer error-buffer) + "Like `shell-command' for Tramp files." + (with-parsed-tramp-file-name default-directory nil + (let ((shell-file-name + (tramp-get-connection-property v "remote-shell" "/bin/sh")) + (shell-command-switch "-c")) + (tramp-run-real-handler + 'shell-command (list command output-buffer error-buffer))))) + +;; File Editing. + +(defvar tramp-handle-file-local-copy-hook nil + "Normal hook to be run at the end of `tramp-handle-file-local-copy'.") + (defun tramp-handle-file-local-copy (filename) - "Like `file-local-copy' for tramp files." + "Like `file-local-copy' for Tramp files." (with-parsed-tramp-file-name filename nil - (let ((tramp-buf (tramp-get-buffer multi-method method user host)) - ;; We used to bind the following as late as possible. - ;; loc-enc and loc-dec were bound directly before the if - ;; statement that checks them. But the functions - ;; tramp-get-* might invoke the "are you awake" check in - ;; tramp-maybe-open-connection, which is an unfortunate time - ;; since we rely on the buffer contents at that spot. - (rem-enc (tramp-get-remote-encoding multi-method method user host)) - (rem-dec (tramp-get-remote-decoding multi-method method user host)) - (loc-enc (tramp-get-local-encoding multi-method method user host)) - (loc-dec (tramp-get-local-decoding multi-method method user host)) + (let (;; We used to bind the following as late as possible. + ;; loc-dec was bound directly before the if statement that + ;; checks them. But the functions tramp-get-* might invoke + ;; the "are you awake" check in `tramp-maybe-open-connection', + ;; which is an unfortunate time since we rely on the buffer + ;; contents at that spot. + (rem-enc (tramp-get-remote-coding v "remote-encoding")) + (loc-dec (tramp-get-local-coding v "local-decoding")) tmpfil) (unless (file-exists-p filename) - (error "Cannot make local copy of non-existing file `%s'" - filename)) + (tramp-error + v 'file-error + "Cannot make local copy of non-existing file `%s'" filename)) (setq tmpfil (tramp-make-temp-file filename)) - (cond ((tramp-method-out-of-band-p multi-method method user host) + (cond ((and (tramp-method-out-of-band-p v) + (> (nth 7 (file-attributes filename)) + tramp-copy-size-limit)) ;; `copy-file' handles out-of-band methods (copy-file filename tmpfil t t)) - ((and rem-enc rem-dec) + (rem-enc ;; Use inline encoding for file transfer. (save-excursion - ;; Following line for setting tramp-current-method, - ;; tramp-current-user, tramp-current-host. - (set-buffer tramp-buf) - (tramp-message 5 "Encoding remote file %s..." filename) + (tramp-message v 5 "Encoding remote file %s..." filename) (tramp-barf-unless-okay - multi-method method user host + v (concat rem-enc " < " (tramp-shell-quote-argument localname)) - nil 'file-error - "Encoding remote file failed, see buffer `%s' for details" - tramp-buf) - ;; Remove trailing status code - (goto-char (point-max)) - (delete-region (point) (progn (forward-line -1) (point))) - - (tramp-message 5 "Decoding remote file %s..." filename) - - ;; Here is where loc-enc and loc-dec used to be let-bound. + "Encoding remote file failed") + + (tramp-message v 5 "Decoding remote file %s..." filename) + ;; Here is where loc-dec used to be let-bound. (if (and (symbolp loc-dec) (fboundp loc-dec)) ;; If local decoding is a function, we call it. We ;; must disable multibyte, because ;; `uudecode-decode-region' doesn't handle it ;; correctly. - (let ((tmpbuf (get-buffer-create " *tramp tmp*"))) - (set-buffer tmpbuf) - (erase-buffer) - (set-buffer-multibyte nil) - (insert-buffer-substring tramp-buf) - (tramp-message-for-buffer - multi-method method user host - 6 "Decoding remote file %s with function %s..." - filename loc-dec) - (set-buffer tmpbuf) - ;; Douglas Gray Stephens - ;; says that we need to strip tramp_exit_status - ;; line from the output here. Go to point-max, - ;; search backward for tramp_exit_status, delete - ;; between point and point-max if found. - (let ((coding-system-for-write 'binary)) - (funcall loc-dec (point-min) (point-max)) - (write-region (point-min) (point-max) tmpfil)) - (kill-buffer tmpbuf)) + (unwind-protect + (with-temp-buffer + (set-buffer-multibyte nil) + (insert-buffer-substring (tramp-get-buffer v)) + (tramp-message + v 5 "Decoding remote file %s with function %s..." + filename loc-dec) + (funcall loc-dec (point-min) (point-max)) + (let ((coding-system-for-write 'binary)) + (write-region (point-min) (point-max) tmpfil)))) ;; If tramp-decoding-function is not defined for this ;; method, we invoke tramp-decoding-command instead. (let ((tmpfil2 (tramp-make-temp-file filename))) - (write-region (point-min) (point-max) tmpfil2) + (let ((coding-system-for-write 'binary)) + (write-region (point-min) (point-max) tmpfil2)) (tramp-message - 6 "Decoding remote file %s with command %s..." + v 5 "Decoding remote file %s with command %s..." filename loc-dec) (tramp-call-local-coding-command loc-dec tmpfil2 tmpfil) (delete-file tmpfil2))) - (tramp-message-for-buffer - multi-method method user host - 5 "Decoding remote file %s...done" filename) + (tramp-message v 5 "Decoding remote file %s...done" filename) ;; Set proper permissions. (set-file-modes tmpfil (file-modes filename)))) - (t (error "Wrong method specification for `%s'" method))) + (t (tramp-error + v 'file-error "Wrong method specification for `%s'" method))) + (run-hooks 'tramp-handle-file-local-copy-hook) tmpfil))) -(defun tramp-handle-file-remote-p (filename) - "Like `file-remote-p' for tramp files." +(defun tramp-handle-file-remote-p (filename &optional connected) + "Like `file-remote-p' for Tramp files." (when (tramp-tramp-file-p filename) (with-parsed-tramp-file-name filename nil - (vector multi-method method user host "")))) + (and (or (not connected) + (let ((p (tramp-get-connection-process v))) + (and p (processp p) (memq (process-status p) '(run open))))) + (tramp-make-tramp-file-name method user host ""))))) (defun tramp-handle-insert-file-contents (filename &optional visit beg end replace) - "Like `insert-file-contents' for tramp files." + "Like `insert-file-contents' for Tramp files." (barf-if-buffer-read-only) (setq filename (expand-file-name filename)) (with-parsed-tramp-file-name filename nil @@ -3886,8 +3678,8 @@ (setq buffer-file-name filename) (set-visited-file-modtime) (set-buffer-modified-p nil)) - (signal 'file-error - (format "File `%s' not found on remote host" filename)) + (tramp-error + v 'file-error "File %s not found on remote host" filename) (list (expand-file-name filename) 0)) ;; `insert-file-contents-literally' takes care to avoid calling ;; jka-compr. By let-binding inhibit-file-name-operation, we @@ -3899,20 +3691,16 @@ 'file-local-copy))) (file-local-copy filename))) coding-system-used result) + (tramp-message v 4 "Inserting local temp file `%s'..." local-copy) + (setq result (insert-file-contents local-copy nil beg end replace)) (when visit (setq buffer-file-name filename) (set-visited-file-modtime) (set-buffer-modified-p nil)) - (tramp-message-for-buffer - multi-method method user host - 9 "Inserting local temp file `%s'..." local-copy) - (setq result (insert-file-contents local-copy nil beg end replace)) ;; Now `last-coding-system-used' has right value. Remember it. (when (boundp 'last-coding-system-used) (setq coding-system-used (symbol-value 'last-coding-system-used))) - (tramp-message-for-buffer - multi-method method user host - 9 "Inserting local temp file `%s'...done" local-copy) + (tramp-message v 4 "Inserting local temp file `%s'...done" local-copy) (delete-file local-copy) (when (boundp 'last-coding-system-used) (set 'last-coding-system-used coding-system-used)) @@ -3921,7 +3709,7 @@ (defun tramp-handle-find-backup-file-name (filename) - "Like `find-backup-file-name' for tramp files." + "Like `find-backup-file-name' for Tramp files." (with-parsed-tramp-file-name filename nil ;; We set both variables. It doesn't matter whether it is ;; Emacs or XEmacs @@ -3936,8 +3724,7 @@ (if (and (stringp (cdr x)) (file-name-absolute-p (cdr x)) (not (tramp-file-name-p (cdr x)))) - (tramp-make-tramp-file-name - multi-method method user host (cdr x)) + (tramp-make-tramp-file-name method user host (cdr x)) (cdr x)))) (symbol-value 'tramp-backup-directory-alist)) (symbol-value 'backup-directory-alist)))) @@ -3955,7 +3742,7 @@ (file-name-absolute-p (car (cdr x))) (not (tramp-file-name-p (car (cdr x))))) (tramp-make-tramp-file-name - multi-method method user host (car (cdr x))) + method user host (car (cdr x))) (car (cdr x)))) (cdr (cdr x)))) (symbol-value 'tramp-bkup-backup-directory-info)) @@ -3964,9 +3751,18 @@ (tramp-run-real-handler 'find-backup-file-name (list filename))))) (defun tramp-handle-make-auto-save-file-name () - "Like `make-auto-save-file-name' for tramp files. + "Like `make-auto-save-file-name' for Tramp files. Returns a file name in `tramp-auto-save-directory' for autosaving this file." - (let ((tramp-auto-save-directory tramp-auto-save-directory)) + (let ((tramp-auto-save-directory tramp-auto-save-directory) + (buffer-file-name + (tramp-subst-strs-in-string + '(("_" . "|") + ("/" . "_a") + (":" . "_b") + ("|" . "__") + ("[" . "_l") + ("]" . "_r")) + (buffer-file-name)))) ;; File name must be unique. This is ensured with Emacs 22 (see ;; UNIQUIFY element of `auto-save-file-name-transforms'); but for ;; all other cases we must do it ourselves. @@ -3981,68 +3777,49 @@ (symbol-value 'auto-save-file-name-transforms))) ;; Create directory. (when tramp-auto-save-directory + (setq buffer-file-name + (expand-file-name buffer-file-name tramp-auto-save-directory)) (unless (file-exists-p tramp-auto-save-directory) (make-directory tramp-auto-save-directory t))) - ;; jka-compr doesn't like auto-saving, so by appending "~" to the - ;; file name we make sure that jka-compr isn't used for the - ;; auto-save file. - (let ((buffer-file-name - (if tramp-auto-save-directory - (expand-file-name - (tramp-subst-strs-in-string - '(("_" . "|") - ("/" . "_a") - (":" . "_b") - ("|" . "__") - ("[" . "_l") - ("]" . "_r")) - (buffer-file-name)) - tramp-auto-save-directory) - (buffer-file-name)))) - ;; Run plain `make-auto-save-file-name'. There might be an advice when - ;; it is not a magic file name operation (since Emacs 22). - ;; We must deactivate it temporarily. - (if (not (ad-is-active 'make-auto-save-file-name)) - (tramp-run-real-handler - 'make-auto-save-file-name nil) - ;; else - (ad-deactivate 'make-auto-save-file-name) - (prog1 - (tramp-run-real-handler - 'make-auto-save-file-name nil) - (ad-activate 'make-auto-save-file-name)))))) - - -;; CCC grok APPEND, LOCKNAME, CONFIRM + ;; Run plain `make-auto-save-file-name'. There might be an advice when + ;; it is not a magic file name operation (since Emacs 22). + ;; We must deactivate it temporarily. + (if (not (ad-is-active 'make-auto-save-file-name)) + (tramp-run-real-handler 'make-auto-save-file-name nil) + ;; else + (ad-deactivate 'make-auto-save-file-name) + (prog1 + (tramp-run-real-handler 'make-auto-save-file-name nil) + (ad-activate 'make-auto-save-file-name))))) + +(defvar tramp-handle-write-region-hook nil + "Normal hook to be run at the end of `tramp-handle-write-region'.") + +;; CCC grok APPEND, LOCKNAME (defun tramp-handle-write-region (start end filename &optional append visit lockname confirm) - "Like `write-region' for tramp files." - (unless (eq append nil) - (error "Cannot append to file using tramp (`%s')" filename)) + "Like `write-region' for Tramp files." (setq filename (expand-file-name filename)) - ;; Following part commented out because we don't know what to do about - ;; file locking, and it does not appear to be a problem to ignore it. - ;; Ange-ftp ignores it, too. - ;; (when (and lockname (stringp lockname)) - ;; (setq lockname (expand-file-name lockname))) - ;; (unless (or (eq lockname nil) - ;; (string= lockname filename)) - ;; (error - ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME")) - ;; XEmacs takes a coding system as the seventh argument, not `confirm' - (when (and (not (featurep 'xemacs)) - confirm (file-exists-p filename)) - (unless (y-or-n-p (format "File %s exists; overwrite anyway? " - filename)) - (error "File not overwritten"))) (with-parsed-tramp-file-name filename nil - (let ((curbuf (current-buffer)) - (rem-enc (tramp-get-remote-encoding multi-method method user host)) - (rem-dec (tramp-get-remote-decoding multi-method method user host)) - (loc-enc (tramp-get-local-encoding multi-method method user host)) - (loc-dec (tramp-get-local-decoding multi-method method user host)) - (trampbuf (get-buffer-create "*tramp output*")) - (modes (file-modes filename)) + (unless (null append) + (tramp-error + v 'file-error "Cannot append to file using Tramp (`%s')" filename)) + ;; Following part commented out because we don't know what to do about + ;; file locking, and it does not appear to be a problem to ignore it. + ;; Ange-ftp ignores it, too. + ;; (when (and lockname (stringp lockname)) + ;; (setq lockname (expand-file-name lockname))) + ;; (unless (or (eq lockname nil) + ;; (string= lockname filename)) + ;; (error + ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME")) + ;; XEmacs takes a coding system as the seventh argument, not `confirm' + (when (and (not (featurep 'xemacs)) confirm (file-exists-p filename)) + (unless (y-or-n-p (format "File %s exists; overwrite anyway? " filename)) + (tramp-error v 'file-error "File not overwritten"))) + (let ((rem-dec (tramp-get-remote-coding v "remote-decoding")) + (loc-enc (tramp-get-local-coding v "local-encoding")) + (modes (save-excursion (file-modes filename))) ;; We use this to save the value of `last-coding-system-used' ;; after writing the tmp file. At the end of the function, ;; we set `last-coding-system-used' to this saved value. @@ -4050,14 +3827,10 @@ ;; talking to the remote shell or suchlike won't hose this ;; variable. This approach was snarfed from ange-ftp.el. coding-system-used - tmpfil) - ;; Write region into a tmp file. This isn't really needed if we - ;; use an encoding function, but currently we use it always - ;; because this makes the logic simpler. - (setq tmpfil (tramp-make-temp-file filename)) - ;; Set current buffer. If connection wasn't open, `file-modes' has - ;; changed it accidently. - (set-buffer curbuf) + ;; Write region into a tmp file. This isn't really needed if we + ;; use an encoding function, but currently we use it always + ;; because this makes the logic simpler. + (tmpfil (tramp-make-temp-file filename))) ;; We say `no-message' here because we don't want the visited file ;; modtime data to be clobbered from the temp file. We call ;; `set-visited-file-modtime' ourselves later on. @@ -4080,96 +3853,106 @@ ;; decoding command must be specified. However, if the method ;; _also_ specifies an encoding function, then that is used for ;; encoding the contents of the tmp file. - (cond ((tramp-method-out-of-band-p multi-method method user host) + (cond ((and (tramp-method-out-of-band-p v) + (integerp start) + (> (- end start) tramp-copy-size-limit)) ;; `copy-file' handles out-of-band methods (copy-file tmpfil filename t t)) - ((and rem-enc rem-dec) + (rem-dec ;; Use inline file transfer - (let ((tmpbuf (get-buffer-create " *tramp file transfer*"))) - (save-excursion - ;; Encode tmpfil into tmpbuf - (tramp-message-for-buffer multi-method method user host - 5 "Encoding region...") - (set-buffer tmpbuf) - (erase-buffer) - ;; Use encoding function or command. - (if (and (symbolp loc-enc) (fboundp loc-enc)) - (progn - (tramp-message-for-buffer - multi-method method user host - 6 "Encoding region using function `%s'..." - (symbol-name loc-enc)) - (insert-file-contents-literally tmpfil) - ;; CCC. The following `let' is a workaround for - ;; the base64.el that comes with pgnus-0.84. If - ;; both of the following conditions are - ;; satisfied, it tries to write to a local file - ;; in default-directory, but at this point, - ;; default-directory is remote. - ;; (CALL-PROCESS-REGION can't write to remote - ;; files, it seems.) The file in question is a - ;; tmp file anyway. - (let ((default-directory - (tramp-temporary-file-directory))) - (funcall loc-enc (point-min) (point-max))) - (goto-char (point-max)) - (unless (bolp) - (newline))) - (tramp-message-for-buffer - multi-method method user host - 6 "Encoding region using command `%s'..." loc-enc) - (unless (equal 0 (tramp-call-local-coding-command - loc-enc tmpfil t)) - (pop-to-buffer trampbuf) - (error (concat "Cannot write to `%s', local encoding" - " command `%s' failed") - filename loc-enc))) - ;; Send tmpbuf into remote decoding command which - ;; writes to remote file. Because this happens on the - ;; remote host, we cannot use the function. - (tramp-message-for-buffer - multi-method method user host - 5 "Decoding region into remote file %s..." filename) - (tramp-send-command - multi-method method user host - (format "%s >%s <<'EOF'" - rem-dec - (tramp-shell-quote-argument localname))) - (set-buffer tmpbuf) - (tramp-message-for-buffer - multi-method method user host - 6 "Sending data to remote host...") - (tramp-send-string multi-method method user host - (buffer-string)) - ;; wait for remote decoding to complete - (tramp-message-for-buffer - multi-method method user host - 6 "Sending end of data token...") - (tramp-send-command - multi-method method user host "EOF" nil t) - (tramp-message-for-buffer - multi-method method user host 6 - "Waiting for remote host to process data...") - (set-buffer (tramp-get-buffer multi-method method user host)) - (tramp-wait-for-output) - (tramp-barf-unless-okay - multi-method method user host nil nil 'file-error - (concat "Couldn't write region to `%s'," - " decode using `%s' failed") - filename rem-dec) - (tramp-message 5 "Decoding region into remote file %s...done" - filename) - (kill-buffer tmpbuf)))) + ;; Encode tmpfil + (tramp-message v 5 "Encoding region...") + (unwind-protect + (with-temp-buffer + ;; Use encoding function or command. + (if (and (symbolp loc-enc) (fboundp loc-enc)) + (progn + (tramp-message + v 5 "Encoding region using function `%s'..." + (symbol-name loc-enc)) + (let ((coding-system-for-read 'binary)) + (insert-file-contents-literally tmpfil)) + ;; CCC. The following `let' is a workaround for + ;; the base64.el that comes with pgnus-0.84. If + ;; both of the following conditions are + ;; satisfied, it tries to write to a local file + ;; in default-directory, but at this point, + ;; default-directory is remote. + ;; (CALL-PROCESS-REGION can't write to remote + ;; files, it seems.) The file in question is a + ;; tmp file anyway. + (let ((default-directory + (tramp-temporary-file-directory))) + (funcall loc-enc (point-min) (point-max)))) + + (tramp-message + v 5 "Encoding region using command `%s'..." loc-enc) + (unless (equal 0 (tramp-call-local-coding-command + loc-enc tmpfil t)) + (tramp-error + v 'file-error + (concat "Cannot write to `%s', local encoding" + " command `%s' failed") + filename loc-enc))) + + ;; Send buffer into remote decoding command which + ;; writes to remote file. Because this happens on the + ;; remote host, we cannot use the function. + (goto-char (point-max)) + (unless (bolp) (newline)) + (tramp-message + v 5 "Decoding region into remote file %s..." filename) + (tramp-send-command + v + (format + "%s >%s <<'EOF'\n%sEOF" + rem-dec + (tramp-shell-quote-argument localname) + (buffer-string))) + (tramp-barf-unless-okay + v nil + (concat "Couldn't write region to `%s'," + " decode using `%s' failed") + filename rem-dec) + ;; When `file-precious-flag' is set, the region is + ;; written to a temporary file. Check that the + ;; checksum is equal to that from the local tmpfil. + (when file-precious-flag + (erase-buffer) + (and + ;; cksum runs locally + (let ((default-directory + (tramp-temporary-file-directory))) + (zerop (call-process "cksum" tmpfil t))) + ;; cksum runs remotely + (zerop + (tramp-send-command-and-check + v + (format + "cksum <%s" + (tramp-shell-quote-argument localname)))) + ;; ... they are different + (not + (string-equal + (buffer-string) + (with-current-buffer (tramp-get-buffer v) + (buffer-string)))) + (tramp-error + v 'file-error + (concat "Couldn't write region to `%s'," + " decode using `%s' failed") + filename rem-dec))) + (tramp-message + v 5 "Decoding region into remote file %s...done" filename) + (tramp-flush-file-property v localname)))) (t - (error + (tramp-error + v 'file-error (concat "Method `%s' should specify both encoding and " "decoding command or an rcp program") method))) (delete-file tmpfil) - (unless (equal curbuf (current-buffer)) - (error "Buffer has changed from `%s' to `%s'" - curbuf (current-buffer))) (when (or (eq visit t) (stringp visit)) (set-visited-file-modtime ;; We must pass modtime explicitely, because filename can be different @@ -4178,41 +3961,9 @@ ;; Make `last-coding-system-used' have the right value. (when (boundp 'last-coding-system-used) (set 'last-coding-system-used coding-system-used)) - (when (or (eq visit t) - (eq visit nil) - (stringp visit)) - (message "Wrote %s" filename))))) - -;; Call down to the real handler. -;; Because EFS does not play nicely with TRAMP (both systems match a -;; TRAMP file name) it is needed to disable efs as well as tramp for the -;; operation. -;; -;; Other than that, this is the canon file-handler code that the doco -;; says should be used here. Which is nice. -;; -;; Under XEmacs current, EFS also hooks in as -;; efs-sifn-handler-function to handle any filename with environment -;; variables. This has two implications: -;; 1) That EFS may not be completely dead (yet) for TRAMP filenames -;; 2) That TRAMP might want to do the same thing. -;; Details as they come in. -;; -;; Daniel Pittman - -;; (defun tramp-run-real-handler (operation args) -;; "Invoke normal file name handler for OPERATION. -;; This inhibits EFS and Ange-FTP, too, because they conflict with tramp. -;; First arg specifies the OPERATION, remaining ARGS are passed to the -;; OPERATION." -;; (let ((inhibit-file-name-handlers -;; (list 'tramp-file-name-handler -;; 'efs-file-handler-function -;; 'ange-ftp-hook-function -;; (and (eq inhibit-file-name-operation operation) -;; inhibit-file-name-handlers))) -;; (inhibit-file-name-operation operation)) -;; (apply operation args))) + (when (or (eq visit t) (null visit) (stringp visit)) + (tramp-message v 0 "Wrote %s" filename)) + (run-hooks 'tramp-handle-write-region-hook)))) ;;;###autoload (progn (defun tramp-run-real-handler (operation args) @@ -4230,10 +3981,6 @@ (inhibit-file-name-operation operation)) (apply operation args)))) -;; This function is used from `tramp-completion-file-name-handler' functions -;; only, if `tramp-completion-mode' is true. But this cannot be checked here -;; because the check is based on a full filename, not available for all -;; basic I/O operations. ;;;###autoload (progn (defun tramp-completion-run-real-handler (operation args) "Invoke `tramp-file-name-handler' for OPERATION. @@ -4306,28 +4053,37 @@ (nth 2 args)) ; BUF ((member operation - (list 'make-auto-save-file-name - 'set-visited-file-modtime 'verify-visited-file-modtime - ; XEmacs only + (list 'set-visited-file-modtime 'verify-visited-file-modtime + ; Emacs 22 only + 'make-auto-save-file-name + ; XEmacs only 'backup-buffer)) (buffer-file-name (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer)))) ; COMMAND ((member operation - (list 'dired-call-process + (list ; not in Emacs 23 + 'dired-call-process ; Emacs only 'shell-command - ; Emacs 22 only + ; since Emacs 22 only 'process-file + ; since Emacs 23 only + 'start-file-process ; XEmacs only - 'dired-print-file 'dired-shell-call-process)) + 'dired-print-file 'dired-shell-call-process + ; nowhere yet + 'executable-find 'start-process 'call-process)) default-directory) ; unknown file primitive (t (error "unknown file I/O primitive: %s" operation)))) (defun tramp-find-foreign-file-name-handler (filename) "Return foreign file name handler if exists." - (when (tramp-tramp-file-p filename) + (when (and (stringp filename) (tramp-tramp-file-p filename) + (or (not (tramp-completion-mode)) + (not (string-match + tramp-completion-file-name-regexp filename)))) (let (elt res (handler-alist tramp-foreign-file-name-handler-alist)) @@ -4344,27 +4100,25 @@ (defun tramp-file-name-handler (operation &rest args) "Invoke Tramp file name handler. Falls back to normal file name handler if no tramp file name handler exists." -;; (setq edebug-trace t) -;; (edebug-trace "%s" (with-output-to-string (backtrace))) (save-match-data (let* ((filename (apply 'tramp-file-name-for-operation operation args)) - (completion (tramp-completion-mode filename)) + (completion (tramp-completion-mode)) (foreign (tramp-find-foreign-file-name-handler filename))) (with-parsed-tramp-file-name filename nil (cond - ;; When we are in completion mode, some operations shouldn' be + ;; When we are in completion mode, some operations shouldn't be ;; handled by backend. - ((and completion (memq operation '(expand-file-name))) - (tramp-run-real-handler operation args)) ((and completion (zerop (length localname)) (memq operation '(file-exists-p file-directory-p))) t) + ((and completion (zerop (length localname)) + (memq operation '(file-name-as-directory))) + filename) ;; Call the backend function. (foreign (apply foreign operation args)) ;; Nothing to do for us. (t (tramp-run-real-handler operation args))))))) - ;; In Emacs, there is some concurrency due to timers. If a timer ;; interrupts Tramp and wishes to use the same connection buffer as ;; the "main" Emacs, then garbage might occur in the connection @@ -4396,7 +4150,7 @@ "Invoke remote-shell Tramp file name handler. Fall back to normal file name handler if no Tramp handler exists." (when (and tramp-locked (not tramp-locker)) - (signal 'file-error "Forbidden reentrant call of Tramp")) + (signal 'file-error (list "Forbidden reentrant call of Tramp"))) (let ((tl tramp-locked)) (unwind-protect (progn @@ -4415,6 +4169,11 @@ Falls back to normal file name handler if no tramp file name handler exists." ;; (setq edebug-trace t) ;; (edebug-trace "%s" (with-output-to-string (backtrace))) + +;; (mapcar 'trace-function-background +;; (mapcar 'intern +;; (all-completions "tramp-" obarray 'functionp))) + (let ((fn (assoc operation tramp-completion-file-name-handler-alist))) (if fn (save-match-data (apply (cdr fn) args)) @@ -4423,6 +4182,11 @@ ;;;###autoload (defsubst tramp-register-file-name-handler () "Add tramp file name handler to `file-name-handler-alist'." + ;; Remove autoloaded handler from file name handler alist. Useful, + ;; if `tramp-syntax' has been changed. + (let ((a1 (rassq 'tramp-file-name-handler file-name-handler-alist))) + (setq file-name-handler-alist (delete a1 file-name-handler-alist))) + ;; Add the handler. (add-to-list 'file-name-handler-alist (cons tramp-file-name-regexp 'tramp-file-name-handler)) ;; If jka-compr is already loaded, move it to the front of @@ -4432,9 +4196,20 @@ (setq file-name-handler-alist (cons jka (delete jka file-name-handler-alist)))))) +;; `tramp-file-name-handler' must be registered before evaluation of +;; site-start and init files, because there might exist remote files +;; already, f.e. files kept via recentf-mode. +;;;###autoload(tramp-register-file-name-handler) +(tramp-register-file-name-handler) + ;;;###autoload (defsubst tramp-register-completion-file-name-handler () "Add tramp completion file name handler to `file-name-handler-alist'." + ;; Remove autoloaded handler from file name handler alist. Useful, + ;; if `tramp-syntax' has been changed. + (let ((a1 (rassq + 'tramp-completion-file-name-handler file-name-handler-alist))) + (setq file-name-handler-alist (delete a1 file-name-handler-alist))) ;; `partial-completion-mode' is unknown in XEmacs. So we should ;; load it unconditionally there. In the GNU Emacs case, method/ ;; user/host name completion shall be bound to `partial-completion-mode'. @@ -4452,17 +4227,12 @@ (setq file-name-handler-alist (cons jka (delete jka file-name-handler-alist)))))) -;; `tramp-file-name-handler' must be registered before evaluation of -;; site-start and init files, because there might exist remote files -;; already, f.e. files kept via recentf-mode. -;;;###autoload(tramp-register-file-name-handler) ;; During autoload, it shall be checked whether ;; `partial-completion-mode' is active. Therefore registering of ;; `tramp-completion-file-name-handler' will be delayed. ;;;###autoload(add-hook ;;;###autoload 'after-init-hook ;;;###autoload '(lambda () (tramp-register-completion-file-name-handler))) -(tramp-register-file-name-handler) (tramp-register-completion-file-name-handler) ;;;###autoload @@ -4476,20 +4246,19 @@ (add-hook 'tramp-unload-hook 'tramp-unload-file-name-handlers) - ;;; Interactions with other packages: ;; -- complete.el -- ;; This function contributed by Ed Sabol (defun tramp-handle-expand-many-files (name) - "Like `PC-expand-many-files' for tramp files." + "Like `PC-expand-many-files' for Tramp files." (with-parsed-tramp-file-name name nil (save-match-data (if (or (string-match "\\*" name) (string-match "\\?" name) (string-match "\\[.*\\]" name)) - (save-excursion + (progn (let (bufstr) ;; CCC: To do it right, we should quote certain characters ;; in the file name, but since the echo command is going to @@ -4499,37 +4268,34 @@ ;;- (set-difference tramp-file-name-quote-list ;;- '(?\* ?\? ?[ ?])))) ;;- (tramp-send-command - ;;- multi-method method user host - ;;- (format "echo %s" (comint-quote-filename localname))) - ;;- (tramp-wait-for-output)) - (tramp-send-command multi-method method user host - (format "echo %s" localname)) - (tramp-wait-for-output) + ;;- method user host + ;;- (format "echo %s" (comint-quote-filename localname)))) + (tramp-send-command v (format "echo %s" localname)) (setq bufstr (buffer-substring (point-min) (tramp-line-end-position))) - (goto-char (point-min)) - (if (string-equal localname bufstr) - nil - (insert "(\"") - (while (search-forward " " nil t) + (with-current-buffer (tramp-get-buffer v) + (goto-char (point-min)) + (if (string-equal localname bufstr) + nil + (insert "(\"") + (while (search-forward " " nil t) + (delete-backward-char 1) + (insert "\" \"")) + (goto-char (point-max)) (delete-backward-char 1) - (insert "\" \"")) - (goto-char (point-max)) - (delete-backward-char 1) - (insert "\")") - (goto-char (point-min)) - (mapcar - (function (lambda (x) - (tramp-make-tramp-file-name multi-method method - user host x))) - (read (current-buffer)))))) + (insert "\")") + (goto-char (point-min)) + (mapcar + (function (lambda (x) + (tramp-make-tramp-file-name method user host x))) + (read (current-buffer))))))) (list (expand-file-name name)))))) (eval-after-load "complete" '(progn (defadvice PC-expand-many-files (around tramp-advice-PC-expand-many-files (name) activate) - "Invoke `tramp-handle-expand-many-files' for tramp files." + "Invoke `tramp-handle-expand-many-files' for Tramp files." (if (tramp-tramp-file-p name) (setq ad-return-value (tramp-handle-expand-many-files name)) ad-do-it)) @@ -4538,142 +4304,118 @@ ;;; File name handler functions for completion mode -(defvar tramp-completion-mode nil - "If non-nil, we are in file name completion mode.") - ;; Necessary because `tramp-file-name-regexp-unified' and -;; `tramp-completion-file-name-regexp-unified' aren't different. -;; If nil, `tramp-completion-run-real-handler' is called (i.e. forwarding to -;; `tramp-file-name-handler'). Otherwise, it takes `tramp-run-real-handler'. -;; Using `last-input-event' is a little bit risky, because completing a file -;; might require loading other files, like "~/.netrc", and for them it -;; shouldn't be decided based on that variable. On the other hand, those files -;; shouldn't have partial tramp file name syntax. Maybe another variable should -;; be introduced overwriting this check in such cases. Or we change tramp -;; file name syntax in order to avoid ambiguities, like in XEmacs ... -;; In case of non unified file names it can be always true (and wouldn't be -;; necessary, because there are different regexp). -(defun tramp-completion-mode (file) +;; `tramp-completion-file-name-regexp-unified' aren't different. If +;; nil, `tramp-completion-run-real-handler' is called (i.e. forwarding +;; to `tramp-file-name-handler'). Otherwise, it takes +;; `tramp-run-real-handler'. Using `last-input-event' is a little bit +;; risky, because completing a file might require loading other files, +;; like "~/.netrc", and for them it shouldn't be decided based on that +;; variable. On the other hand, those files shouldn't have partial +;; tramp file name syntax. Maybe another variable should be introduced +;; overwriting this check in such cases. Or we change tramp file name +;; syntax in order to avoid ambiguities, like in XEmacs ... +(defun tramp-completion-mode () "Checks whether method / user name / host name completion is active." - (cond - (tramp-completion-mode t) - ((string-match "^/.*:.*:$" file) nil) - ((string-match - (concat tramp-prefix-regexp - "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp "$") - file) - (member (match-string 1 file) (mapcar 'car tramp-methods))) - ((or (equal last-input-event 'tab) - ;; Emacs - (and (natnump last-input-event) - (or - ;; ?\t has event-modifier 'control - (char-equal last-input-event ?\t) - (and (not (event-modifiers last-input-event)) - (or (char-equal last-input-event ?\?) - (char-equal last-input-event ?\ ))))) - ;; XEmacs - (and (featurep 'xemacs) - ;; `last-input-event' might be nil. - (not (null last-input-event)) - ;; `last-input-event' may have no character approximation. - (funcall (symbol-function 'event-to-character) last-input-event) - (or - ;; ?\t has event-modifier 'control - (char-equal - (funcall (symbol-function 'event-to-character) - last-input-event) ?\t) - (and (not (event-modifiers last-input-event)) - (or (char-equal - (funcall (symbol-function 'event-to-character) - last-input-event) ?\?) - (char-equal - (funcall (symbol-function 'event-to-character) - last-input-event) ?\ )))))) - t))) + (or (equal last-input-event 'tab) + ;; Emacs + (and (natnump last-input-event) + (or + ;; ?\t has event-modifier 'control + (char-equal last-input-event ?\t) + (and (not (event-modifiers last-input-event)) + (or (char-equal last-input-event ?\?) + (char-equal last-input-event ?\ ))))) + ;; XEmacs + (and (featurep 'xemacs) + ;; `last-input-event' might be nil. + (not (null last-input-event)) + ;; `last-input-event' may have no character approximation. + (funcall (symbol-function 'event-to-character) last-input-event) + (or + ;; ?\t has event-modifier 'control + (char-equal + (funcall (symbol-function 'event-to-character) + last-input-event) ?\t) + (and (not (event-modifiers last-input-event)) + (or (char-equal + (funcall (symbol-function 'event-to-character) + last-input-event) ?\?) + (char-equal + (funcall (symbol-function 'event-to-character) + last-input-event) ?\ ))))))) ;; Method, host name and user name completion. ;; `tramp-completion-dissect-file-name' returns a list of ;; tramp-file-name structures. For all of them we return possible completions. ;;;###autoload (defun tramp-completion-handle-file-name-all-completions (filename directory) - "Like `file-name-all-completions' for partial tramp files." - - (unwind-protect - ;; We need to reset `tramp-completion-mode'. - (progn - (setq tramp-completion-mode t) - (let* - ((fullname (concat directory filename)) - ;; possible completion structures - (v (tramp-completion-dissect-file-name fullname)) - result result1) - - (while v - (let* ((car (car v)) - (multi-method (tramp-file-name-multi-method car)) - (method (tramp-file-name-method car)) - (user (tramp-file-name-user car)) - (host (tramp-file-name-host car)) - (localname (tramp-file-name-localname car)) - (m (tramp-find-method multi-method method user host)) - (tramp-current-user user) ; see `tramp-parse-passwd' - all-user-hosts) - - (unless (or multi-method ;; Not handled (yet). - localname) ;; Nothing to complete - - (if (or user host) - - ;; Method dependent user / host combinations - (progn - (mapcar - (lambda (x) - (setq all-user-hosts - (append all-user-hosts - (funcall (nth 0 x) (nth 1 x))))) - (tramp-get-completion-function m)) - - (setq result (append result - (mapcar - (lambda (x) - (tramp-get-completion-user-host - method user host (nth 0 x) (nth 1 x))) - (delq nil all-user-hosts))))) - - ;; Possible methods - (setq result - (append result (tramp-get-completion-methods m))))) - - (setq v (cdr v)))) - - ;; unify list, remove nil elements - (while result - (let ((car (car result))) - (when car (add-to-list - 'result1 (substring car (length directory)))) - (setq result (cdr result)))) - - ;; Complete local parts - (append - result1 - (condition-case nil - (if result1 - ;; "/ssh:" does not need to be expanded as hostname. - (tramp-run-real-handler - 'file-name-all-completions (list filename directory)) - ;; No method/user/host found to be expanded. - (tramp-completion-run-real-handler - 'file-name-all-completions (list filename directory))) - (error nil))))) - ;; unwindform - (setq tramp-completion-mode nil))) + "Like `file-name-all-completions' for partial Tramp files." + + (let* ((fullname (tramp-drop-volume-letter + (expand-file-name filename directory))) + ;; Possible completion structures. + (v (tramp-completion-dissect-file-name fullname)) + result result1) + + (while v + (let* ((car (car v)) + (method (tramp-file-name-method car)) + (user (tramp-file-name-user car)) + (host (tramp-file-name-host car)) + (localname (tramp-file-name-localname car)) + (m (tramp-find-method method user host)) + (tramp-current-user user) ; see `tramp-parse-passwd' + all-user-hosts) + + (unless localname ;; Nothing to complete. + + (if (or user host) + + ;; Method dependent user / host combinations. + (progn + (mapcar + (lambda (x) + (setq all-user-hosts + (append all-user-hosts + (funcall (nth 0 x) (nth 1 x))))) + (tramp-get-completion-function m)) + + (setq result (append result + (mapcar + (lambda (x) + (tramp-get-completion-user-host + method user host (nth 0 x) (nth 1 x))) + (delq nil all-user-hosts))))) + + ;; Possible methods. + (setq result + (append result (tramp-get-completion-methods m))))) + + (setq v (cdr v)))) + + ;; Unify list, remove nil elements. + (while result + (let ((car (car result))) + (when car + (add-to-list + 'result1 + (substring car (length (tramp-drop-volume-letter directory))))) + (setq result (cdr result)))) + + ;; Complete local parts. + (append + result1 + (condition-case nil + (tramp-completion-run-real-handler + 'file-name-all-completions (list filename directory)) + (error nil))))) ;; Method, host name and user name completion for a file. ;;;###autoload (defun tramp-completion-handle-file-name-completion (filename directory &optional predicate) - "Like `file-name-completion' for tramp files." + "Like `file-name-completion' for Tramp files." (try-completion filename (mapcar 'list (file-name-all-completions filename directory)) @@ -4683,26 +4425,26 @@ ;; I misuse a little bit the tramp-file-name structure in order to handle ;; completion possibilities for partial methods / user names / host names. ;; Return value is a list of tramp-file-name structures according to possible -;; completions. If "multi-method" or "localname" is non-nil it means there +;; completions. If "localname" is non-nil it means there ;; shouldn't be a completion anymore. ;; Expected results: -;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y" -;; [nil nil nil "x" nil] [nil nil "x" nil nil] [nil nil "x" "y" nil] -;; [nil nil "x" nil nil] -;; [nil "x" nil nil nil] - -;; "/x:" "/x:y" "/x:y:" -;; [nil nil nil "x" ""] [nil nil nil "x" "y"] [nil "x" nil "y" ""] -;; "/[x/" "/[x/y" -;; [nil "x" nil "" nil] [nil "x" nil "y" nil] -;; [nil "x" "" nil nil] [nil "x" "y" nil nil] - -;; "/x:y@" "/x:y@z" "/x:y@z:" -;; [nil nil nil "x" "y@"] [nil nil nil "x" "y@z"] [nil "x" "y" "z" ""] -;; "/[x/y@" "/[x/y@z" -;; [nil "x" nil "y" nil] [nil "x" "y" "z" nil] +;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y" +;; [nil nil "x" nil] [nil "x" nil nil] [nil "x" "y" nil] +;; [nil "x" nil nil] +;; ["x" nil nil nil] + +;; "/x:" "/x:y" "/x:y:" +;; [nil nil "x" ""] [nil nil "x" "y"] ["x" nil "y" ""] +;; "/[x/" "/[x/y" +;; ["x" nil "" nil] ["x" nil "y" nil] +;; ["x" "" nil nil] ["x" "y" nil nil] + +;; "/x:y@" "/x:y@z" "/x:y@z:" +;; [nil nil "x" "y@"] [nil nil "x" "y@z"] ["x" "y" "z" ""] +;; "/[x/y@" "/[x/y@z" +;; ["x" nil "y" nil] ["x" "y" "z" nil] (defun tramp-completion-dissect-file-name (name) "Returns a list of `tramp-file-name' structures. They are collected by `tramp-completion-dissect-file-name1'." @@ -4727,25 +4469,49 @@ "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\(" tramp-host-regexp x-nil "\\)$") nil 1 2 nil)) - ;; "/method:user" "/[method/user" + ;; "/method:user" "/[method/user" "/method://user" (tramp-completion-file-name-structure5 (list (concat tramp-prefix-regexp - "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp + "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\(" tramp-user-regexp x-nil "\\)$") 1 2 nil nil)) - ;; "/method:host" "/[method/host" + ;; "/method:host" "/[method/host" "/method://host" (tramp-completion-file-name-structure6 (list (concat tramp-prefix-regexp - "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp + "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\(" tramp-host-regexp x-nil "\\)$") 1 nil 2 nil)) - ;; "/method:user@host" "/[method/user@host" + ;; "/method:user@host" "/[method/user@host" "/method://user@host" (tramp-completion-file-name-structure7 (list (concat tramp-prefix-regexp - "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp + "\\(" tramp-method-regexp "\\)" tramp-postfix-method-regexp "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\(" tramp-host-regexp x-nil "\\)$") - 1 2 3 nil))) + 1 2 3 nil)) + ;; "/method: "/method:/" + (tramp-completion-file-name-structure8 + (list + (if (equal tramp-syntax 'url) + (concat tramp-prefix-regexp + "\\(" tramp-method-regexp "\\)" + "\\(" (substring tramp-postfix-method-regexp 0 1) + "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)" + "\\(" "\\)$") + ;; Should not match if not URL syntax. + (concat tramp-prefix-regexp "/$")) + 1 3 nil nil)) + ;; "/method: "/method:/" + (tramp-completion-file-name-structure9 + (list + (if (equal tramp-syntax 'url) + (concat tramp-prefix-regexp + "\\(" tramp-method-regexp "\\)" + "\\(" (substring tramp-postfix-method-regexp 0 1) + "\\|" (substring tramp-postfix-method-regexp 1 2) "\\)" + "\\(" "\\)$") + ;; Should not match if not URL syntax. + (concat tramp-prefix-regexp "/$")) + 1 nil 3 nil))) (mapcar (lambda (regexp) (add-to-list 'result @@ -4758,30 +4524,28 @@ tramp-completion-file-name-structure5 tramp-completion-file-name-structure6 tramp-completion-file-name-structure7 + tramp-completion-file-name-structure8 + tramp-completion-file-name-structure9 tramp-file-name-structure)) (delq nil result))) (defun tramp-completion-dissect-file-name1 (structure name) "Returns a `tramp-file-name' structure matching STRUCTURE. -The structure consists of multi-method, remote method, remote user, +The structure consists of remote method, remote user, remote host and localname (filename on remote host)." - (let (method) - (save-match-data - (when (string-match (nth 0 structure) name) - (setq method (and (nth 1 structure) - (match-string (nth 1 structure) name))) - (if (and method (member method tramp-multi-methods)) - ;; Not handled (yet). - (vector method nil nil nil nil) - (let ((user (and (nth 2 structure) - (match-string (nth 2 structure) name))) - (host (and (nth 3 structure) - (match-string (nth 3 structure) name))) - (localname (and (nth 4 structure) - (match-string (nth 4 structure) name)))) - (vector nil method user host localname))))))) + (save-match-data + (when (string-match (nth 0 structure) name) + (let ((method (and (nth 1 structure) + (match-string (nth 1 structure) name))) + (user (and (nth 2 structure) + (match-string (nth 2 structure) name))) + (host (and (nth 3 structure) + (match-string (nth 3 structure) name))) + (localname (and (nth 4 structure) + (match-string (nth 4 structure) name)))) + (vector method user host localname))))) ;; This function returns all possible method completions, adding the ;; trailing method delimeter. @@ -4791,8 +4555,8 @@ (lambda (method) (and method (string-match (concat "^" (regexp-quote partial-method)) method) - (tramp-make-tramp-file-name nil method nil nil nil))) - (delete "multi" (mapcar 'car tramp-methods)))) + (tramp-completion-make-tramp-file-name method nil nil nil))) + (mapcar 'car tramp-methods))) ;; Compares partial user and host names with possible completions. (defun tramp-get-completion-user-host (method partial-user partial-host user host) @@ -4824,13 +4588,15 @@ host nil))) (unless (zerop (+ (length user) (length host))) - (tramp-make-tramp-file-name nil method user host nil))) + (tramp-completion-make-tramp-file-name method user host nil))) (defun tramp-parse-rhosts (filename) "Return a list of (user host) tuples allowed to access. Either user or host may be nil." - - (let (res) + ;; On Windows, there are problems in completion when + ;; `default-directory' is remote. + (let ((default-directory (tramp-temporary-file-directory)) + res) (when (file-readable-p filename) (with-temp-buffer (insert-file-contents filename) @@ -4839,24 +4605,15 @@ (push (tramp-parse-rhosts-group) res)))) res)) -;; Taken from gnus/netrc.el -(eval-and-compile - (defalias 'tramp-point-at-eol - (if (fboundp 'point-at-eol) - 'point-at-eol - 'line-end-position))) - (defun tramp-parse-rhosts-group () "Return a (user host) tuple allowed to access. Either user or host may be nil." - (let ((result) (regexp (concat "^\\(" tramp-host-regexp "\\)" "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?"))) - - (narrow-to-region (point) (tramp-point-at-eol)) + (narrow-to-region (point) (tramp-line-end-position)) (when (re-search-forward regexp nil t) (setq result (append (list (match-string 3) (match-string 1))))) (widen) @@ -4866,8 +4623,10 @@ (defun tramp-parse-shosts (filename) "Return a list of (user host) tuples allowed to access. User is always nil." - - (let (res) + ;; On Windows, there are problems in completion when + ;; `default-directory' is remote. + (let ((default-directory (tramp-temporary-file-directory)) + res) (when (file-readable-p filename) (with-temp-buffer (insert-file-contents filename) @@ -4879,11 +4638,9 @@ (defun tramp-parse-shosts-group () "Return a (user host) tuple allowed to access. User is always nil." - (let ((result) (regexp (concat "^\\(" tramp-host-regexp "\\)"))) - - (narrow-to-region (point) (tramp-point-at-eol)) + (narrow-to-region (point) (tramp-line-end-position)) (when (re-search-forward regexp nil t) (setq result (list nil (match-string 1)))) (widen) @@ -4895,8 +4652,10 @@ (defun tramp-parse-sconfig (filename) "Return a list of (user host) tuples allowed to access. User is always nil." - - (let (res) + ;; On Windows, there are problems in completion when + ;; `default-directory' is remote. + (let ((default-directory (tramp-temporary-file-directory)) + res) (when (file-readable-p filename) (with-temp-buffer (insert-file-contents filename) @@ -4908,11 +4667,9 @@ (defun tramp-parse-sconfig-group () "Return a (user host) tuple allowed to access. User is always nil." - (let ((result) (regexp (concat "^[ \t]*Host[ \t]+" "\\(" tramp-host-regexp "\\)"))) - - (narrow-to-region (point) (tramp-point-at-eol)) + (narrow-to-region (point) (tramp-line-end-position)) (when (re-search-forward regexp nil t) (setq result (list nil (match-string 1)))) (widen) @@ -4924,11 +4681,12 @@ (defun tramp-parse-shostkeys (dirname) "Return a list of (user host) tuples allowed to access. User is always nil." - - (let ((regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$")) - (files (when (file-directory-p dirname) (directory-files dirname))) - result) - + ;; On Windows, there are problems in completion when + ;; `default-directory' is remote. + (let* ((default-directory (tramp-temporary-file-directory)) + (regexp (concat "^key_[0-9]+_\\(" tramp-host-regexp "\\)\\.pub$")) + (files (when (file-directory-p dirname) (directory-files dirname))) + result) (while files (when (string-match regexp (car files)) (push (list nil (match-string 1 (car files))) result)) @@ -4938,12 +4696,13 @@ (defun tramp-parse-sknownhosts (dirname) "Return a list of (user host) tuples allowed to access. User is always nil." - - (let ((regexp (concat "^\\(" tramp-host-regexp - "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$")) - (files (when (file-directory-p dirname) (directory-files dirname))) - result) - + ;; On Windows, there are problems in completion when + ;; `default-directory' is remote. + (let* ((default-directory (tramp-temporary-file-directory)) + (regexp (concat "^\\(" tramp-host-regexp + "\\)\\.ssh-\\(dss\\|rsa\\)\\.pub$")) + (files (when (file-directory-p dirname) (directory-files dirname))) + result) (while files (when (string-match regexp (car files)) (push (list nil (match-string 1 (car files))) result)) @@ -4953,8 +4712,10 @@ (defun tramp-parse-hosts (filename) "Return a list of (user host) tuples allowed to access. User is always nil." - - (let (res) + ;; On Windows, there are problems in completion when + ;; `default-directory' is remote. + (let ((default-directory (tramp-temporary-file-directory)) + res) (when (file-readable-p filename) (with-temp-buffer (insert-file-contents filename) @@ -4966,11 +4727,9 @@ (defun tramp-parse-hosts-group () "Return a (user host) tuple allowed to access. User is always nil." - (let ((result) (regexp (concat "^\\(" tramp-host-regexp "\\)"))) - - (narrow-to-region (point) (tramp-point-at-eol)) + (narrow-to-region (point) (tramp-line-end-position)) (when (re-search-forward regexp nil t) (unless (char-equal (or (char-after) ?\n) ?:) ; no IPv6 (setq result (list nil (match-string 1))))) @@ -4982,13 +4741,15 @@ ;; For su-alike methods it would be desirable to return "root@localhost" ;; as default. Unfortunately, we have no information whether any user name -;; has been typed already. So we (mis-)use tramp-current-user as indication, +;; has been typed already. So we use `tramp-current-user' as indication, ;; assuming it is set in `tramp-completion-handle-file-name-all-completions'. (defun tramp-parse-passwd (filename) "Return a list of (user host) tuples allowed to access. Host is always \"localhost\"." - - (let (res) + ;; On Windows, there are problems in completion when + ;; `default-directory' is remote. + (let ((default-directory (tramp-temporary-file-directory)) + res) (if (zerop (length tramp-current-user)) '(("root" nil)) (when (file-readable-p filename) @@ -5002,11 +4763,9 @@ (defun tramp-parse-passwd-group () "Return a (user host) tuple allowed to access. Host is always \"localhost\"." - (let ((result) (regexp (concat "^\\(" tramp-user-regexp "\\):"))) - - (narrow-to-region (point) (tramp-point-at-eol)) + (narrow-to-region (point) (tramp-line-end-position)) (when (re-search-forward regexp nil t) (setq result (list (match-string 1) "localhost"))) (widen) @@ -5016,8 +4775,10 @@ (defun tramp-parse-netrc (filename) "Return a list of (user host) tuples allowed to access. User may be nil." - - (let (res) + ;; On Windows, there are problems in completion when + ;; `default-directory' is remote. + (let ((default-directory (tramp-temporary-file-directory)) + res) (when (file-readable-p filename) (with-temp-buffer (insert-file-contents filename) @@ -5029,49 +4790,63 @@ (defun tramp-parse-netrc-group () "Return a (user host) tuple allowed to access. User may be nil." - (let ((result) (regexp (concat "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)" "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?"))) - - (narrow-to-region (point) (tramp-point-at-eol)) + (narrow-to-region (point) (tramp-line-end-position)) (when (re-search-forward regexp nil t) (setq result (list (match-string 3) (match-string 1)))) (widen) (forward-line 1) result)) +(defun tramp-parse-putty (registry) + "Return a list of (user host) tuples allowed to access. +User is always nil." + ;; On Windows, there are problems in completion when + ;; `default-directory' is remote. + (let ((default-directory (tramp-temporary-file-directory)) + res) + (with-temp-buffer + (when (zerop (call-process "reg" nil t nil "query" registry)) + (goto-char (point-min)) + (while (not (eobp)) + (push (tramp-parse-putty-group registry) res)))) + res)) + +(defun tramp-parse-putty-group (registry) + "Return a (user host) tuple allowed to access. +User is always nil." + (let ((result) + (regexp (concat (regexp-quote registry) "\\\\\\(.+\\)"))) + (narrow-to-region (point) (tramp-line-end-position)) + (when (re-search-forward regexp nil t) + (setq result (list nil (match-string 1)))) + (widen) + (forward-line 1) + result)) + ;;; Internal Functions: -(defun tramp-maybe-send-perl-script (multi-method method user host script name) - "Define in remote shell function NAME implemented as perl SCRIPT. -Only send the definition if it has not already been done. -Function may have 0-3 parameters." - (let ((remote-perl (tramp-get-remote-perl multi-method method user host))) - (unless remote-perl (error "No remote perl")) - (let ((perl-scripts (tramp-get-connection-property "perl-scripts" nil - multi-method method user host))) - (unless (memq name perl-scripts) - (with-current-buffer (tramp-get-buffer multi-method method user host) - (tramp-message 5 (concat "Sending the Perl script `" name "'...")) - (tramp-send-string multi-method method user host - (concat name - " () {\n" - remote-perl - " -e '" - script - "' \"$1\" \"$2\" \"$3\" 2>/dev/null\n}")) - (tramp-wait-for-output) - (tramp-set-connection-property "perl-scripts" (cons name perl-scripts) - multi-method method user host) - (tramp-message 5 (concat "Sending the Perl script `" name "'...done."))))))) +(defun tramp-maybe-send-script (vec script name) + "Define in remote shell function NAME implemented as SCRIPT. +Only send the definition if it has not already been done." + (let* ((p (tramp-get-connection-process vec)) + (scripts (tramp-get-connection-property p "scripts" nil))) + (unless (memq name scripts) + (tramp-message vec 5 "Sending script `%s'..." name) + ;; The script could contain a call of Perl. This is masked with `%s'. + (tramp-send-command-and-check + vec + (format "%s () {\n%s\n}" name + (format script (tramp-get-remote-perl vec)))) + (tramp-set-connection-property p "scripts" (cons name scripts)) + (tramp-message vec 5 "Sending script `%s'...done." name)))) (defun tramp-set-auto-save () - (when (and (buffer-file-name) - (tramp-tramp-file-p (buffer-file-name)) - ;; ange-ftp has its own auto-save mechanism + (when (and ;; ange-ftp has its own auto-save mechanism (eq (tramp-find-foreign-file-name-handler (buffer-file-name)) 'tramp-sh-file-name-handler) auto-save-default) @@ -5084,46 +4859,32 @@ (defun tramp-run-test (switch filename) "Run `test' on the remote system, given a SWITCH and a FILENAME. Returns the exit code of the `test' program." - (let ((v (tramp-dissect-file-name filename))) - (save-excursion - (tramp-send-command-and-check - (tramp-file-name-multi-method v) (tramp-file-name-method v) - (tramp-file-name-user v) (tramp-file-name-host v) - (format "test %s %s" switch - (tramp-shell-quote-argument (tramp-file-name-localname v))))))) - -(defun tramp-run-test2 (program file1 file2 &optional switch) - "Run `test'-like PROGRAM on the remote system, given FILE1, FILE2. -The optional SWITCH is inserted between the two files. -Returns the exit code of the `test' PROGRAM. Barfs if the methods, + (with-parsed-tramp-file-name filename nil + (tramp-send-command-and-check + v + (format + "%s %s %s" + (tramp-get-test-command v) + switch + (tramp-shell-quote-argument localname))))) + +(defun tramp-run-test2 (format-string file1 file2) + "Run `test'-like program on the remote system, given FILE1, FILE2. +FORMAT-STRING contains the program name, switches, and place holders. +Returns the exit code of the `test' program. Barfs if the methods, hosts, or files, disagree." - (let* ((v1 (tramp-dissect-file-name file1)) - (v2 (tramp-dissect-file-name file2)) - (mmethod1 (tramp-file-name-multi-method v1)) - (mmethod2 (tramp-file-name-multi-method v2)) - (method1 (tramp-file-name-method v1)) - (method2 (tramp-file-name-method v2)) - (user1 (tramp-file-name-user v1)) - (user2 (tramp-file-name-user v2)) - (host1 (tramp-file-name-host v1)) - (host2 (tramp-file-name-host v2)) - (localname1 (tramp-file-name-localname v1)) - (localname2 (tramp-file-name-localname v2))) - (unless (and method1 method2 host1 host2 - (equal mmethod1 mmethod2) - (equal method1 method2) - (equal user1 user2) - (equal host1 host2)) - (error "tramp-run-test2: %s" - "only implemented for same method, same user, same host")) - (save-excursion + (unless (tramp-equal-remote file1 file2) + (with-parsed-tramp-file-name (if (tramp-tramp-file-p file1) file1 file2) nil + (tramp-error + v 'file-error + "tramp-run-test2 only implemented for same method, user, host"))) + (with-parsed-tramp-file-name file1 v1 + (with-parsed-tramp-file-name file1 v2 (tramp-send-command-and-check - mmethod1 method1 user1 host1 - (format "%s %s %s %s" - program - (tramp-shell-quote-argument localname1) - (or switch "") - (tramp-shell-quote-argument localname2)))))) + v1 + (format format-string + (tramp-shell-quote-argument v1-localname) + (tramp-shell-quote-argument v2-localname)))))) (defun tramp-touch (file time) "Set the last-modified timestamp of the given file. @@ -5132,291 +4893,313 @@ ;; With GNU Emacs, `format-time-string' has an optional ;; parameter UNIVERSAL. This is preferred. (and (functionp 'subr-arity) + (subrp (symbol-function 'format-time-string)) (= 3 (cdr (funcall (symbol-function 'subr-arity) (symbol-function 'format-time-string)))))) (touch-time (if utc (format-time-string "%Y%m%d%H%M.%S" time t) - (format-time-string "%Y%m%d%H%M.%S" time)))) - (if (tramp-tramp-file-p file) + (format-time-string "%Y%m%d%H%M.%S" time))) + (default-directory (file-name-directory file))) + + (if (eq (tramp-find-foreign-file-name-handler file) + 'tramp-sh-file-name-handler) (with-parsed-tramp-file-name file nil - (let ((buf (tramp-get-buffer multi-method method user host))) - (unless (zerop (tramp-send-command-and-check - multi-method method user host - (format "%s touch -t %s %s" - (if utc "TZ=UTC; export TZ;" "") - touch-time - (tramp-shell-quote-argument localname)) - t)) - (pop-to-buffer buf) - (error "tramp-touch: touch failed, see buffer `%s' for details" - buf)))) - ;; It's a local file + (tramp-send-command + v (format "%s touch -t %s %s" + (if utc "TZ=UTC; export TZ;" "") + touch-time + (tramp-shell-quote-argument localname)))) (with-temp-buffer - (unless (zerop (call-process - "touch" nil (current-buffer) nil "-t" touch-time file)) - (pop-to-buffer (current-buffer)) - (error "tramp-touch: touch failed")))))) - -(defun tramp-buffer-name (multi-method method user host) - "A name for the connection buffer for USER at HOST using METHOD." - (if multi-method - (tramp-buffer-name-multi-method "tramp" multi-method method user host) - (let ((method (tramp-find-method multi-method method user host))) - (if user - (format "*tramp/%s %s@%s*" method user host) - (format "*tramp/%s %s*" method host))))) - -(defun tramp-buffer-name-multi-method (prefix multi-method method user host) - "A name for the multi method connection buffer. -MULTI-METHOD gives the multi method, METHOD the array of methods, -USER the array of user names, HOST the array of host names." - (unless (and (= (length method) (length user)) - (= (length method) (length host))) - (error "Syntax error in multi method (implementation error)")) - (let ((len (length method)) - (i 0) - string-list) - (while (< i len) - (setq string-list - (cons (if (aref user i) - (format "%s#%s@%s:" (aref method i) - (aref user i) (aref host i)) - (format "%s@%s:" (aref method i) (aref host i))) - string-list)) - (setq i (1+ i))) - (format "*%s/%s %s*" - prefix multi-method - (apply 'concat (reverse string-list))))) - -(defun tramp-get-buffer (multi-method method user host) - "Get the connection buffer to be used for USER at HOST using METHOD." + (shell-command + (format "%s touch -t %s %s" + (if utc "TZ=UTC; export TZ;" "") + touch-time + (tramp-shell-quote-argument + (if (tramp-tramp-file-p file) + (with-parsed-tramp-file-name file nil localname) file))) + (current-buffer)))))) + +(defun tramp-buffer-name (vec) + "A name for the connection buffer VEC." + ;; We must use `tramp-file-name-real-host', because for gateway + ;; methods the default port will be expanded later on, which would + ;; tamper the name. + (let ((method (tramp-file-name-method vec)) + (user (tramp-file-name-user vec)) + (host (tramp-file-name-real-host vec))) + (if (not (zerop (length user))) + (format "*tramp/%s %s@%s*" method user host) + (format "*tramp/%s %s*" method host)))) + +(defun tramp-get-buffer (vec) + "Get the connection buffer to be used for VEC." + (or (get-buffer (tramp-buffer-name vec)) + (with-current-buffer (get-buffer-create (tramp-buffer-name vec)) + (setq buffer-undo-list t) + (setq default-directory + (tramp-make-tramp-file-name + (tramp-file-name-method vec) + (tramp-file-name-user vec) + (tramp-file-name-host vec) + "/")) + (current-buffer)))) + +(defun tramp-get-connection-buffer (vec) + "Get the connection buffer to be used for VEC. +In case a second asynchronous communication has been started, it is different +from `tramp-get-buffer'." + (or (tramp-get-connection-property vec "process-buffer" nil) + (tramp-get-buffer vec))) + +(defun tramp-get-connection-process (vec) + "Get the connection process to be used for VEC. +In case a second asynchronous communication has been started, it is different +from the default one." + (get-process + (or (tramp-get-connection-property vec "process-name" nil) + (tramp-buffer-name vec)))) + +(defun tramp-debug-buffer-name (vec) + "A name for the debug buffer for VEC." + ;; We must use `tramp-file-name-real-host', because for gateway + ;; methods the default port will be expanded later on, which would + ;; tamper the name. + (let ((method (tramp-file-name-method vec)) + (user (tramp-file-name-user vec)) + (host (tramp-file-name-real-host vec))) + (if (not (zerop (length user))) + (format "*debug tramp/%s %s@%s*" method user host) + (format "*debug tramp/%s %s*" method host)))) + +(defun tramp-get-debug-buffer (vec) + "Get the debug buffer for VEC." (with-current-buffer - (get-buffer-create (tramp-buffer-name multi-method method user host)) - (setq buffer-undo-list t) + (get-buffer-create (tramp-debug-buffer-name vec)) + (when (bobp) + (setq buffer-undo-list t) + ;; Activate outline-mode + (make-local-variable 'outline-regexp) + (make-local-variable 'outline-level) + ;; This runs `text-mode-hook' and `outline-mode-hook'. We must + ;; prevent that local processes die. Yes: I've seen + ;; `flyspell-mode', which starts "ispell" ... + (let ((default-directory (tramp-temporary-file-directory))) + (outline-mode)) + (setq outline-regexp "[0-9]+:[0-9]+:[0-9]+ [a-z0-9-]+ (\\([0-9]+\\)) #") +; (setq outline-regexp "[a-z.-]+:[0-9]+: [a-z0-9-]+ (\\([0-9]+\\)) #") + (setq outline-level 'tramp-outline-level)) (current-buffer))) -(defun tramp-debug-buffer-name (multi-method method user host) - "A name for the debug buffer for USER at HOST using METHOD." - (if multi-method - (tramp-buffer-name-multi-method "debug tramp" - multi-method method user host) - (let ((method (tramp-find-method multi-method method user host))) - (if user - (format "*debug tramp/%s %s@%s*" method user host) - (format "*debug tramp/%s %s*" method host))))) - -(defun tramp-get-debug-buffer (multi-method method user host) - "Get the debug buffer for USER at HOST using METHOD." - (with-current-buffer - (get-buffer-create - (tramp-debug-buffer-name multi-method method user host)) - (setq buffer-undo-list t) - (current-buffer))) - -(defun tramp-find-executable (multi-method method user host - progname dirlist ignore-tilde) - "Searches for PROGNAME in all directories mentioned in DIRLIST. -First args METHOD, USER and HOST specify the connection, PROGNAME -is the program to search for, and DIRLIST gives the list of directories -to search. If IGNORE-TILDE is non-nil, directory names starting -with `~' will be ignored. +(defun tramp-outline-level () + "Return the depth to which a statement is nested in the outline. +Point must be at the beginning of a header line. + +The outline level is equal to the verbosity of the Tramp message." + (1+ (string-to-number (match-string 1)))) + +(defun tramp-find-executable + (vec progname dirlist &optional ignore-tilde ignore-path) + "Searches for PROGNAME in $PATH and all directories mentioned in DIRLIST. +First arg VEC specifies the connection, PROGNAME is the program +to search for, and DIRLIST gives the list of directories to +search. If IGNORE-TILDE is non-nil, directory names starting +with `~' will be ignored. If IGNORE-PATH is non-nil, searches +only in DIRLIST. Returns the absolute file name of PROGNAME, if found, and nil otherwise. This function expects to be in the right *tramp* buffer." - (let (result) - (when ignore-tilde - ;; Remove all ~/foo directories from dirlist. In Emacs 20, - ;; `remove' is in CL, and we want to avoid CL dependencies. - (let (newdl d) - (while dirlist - (setq d (car dirlist)) - (setq dirlist (cdr dirlist)) - (unless (char-equal ?~ (aref d 0)) - (setq newdl (cons d newdl)))) - (setq dirlist (nreverse newdl)))) + (with-current-buffer (tramp-get-buffer vec) + (let (result) + ;; Check whether the executable is in $PATH. "which(1)" does not + ;; report always a correct error code; therefore we check the + ;; number of words it returns. + (unless ignore-path + (tramp-send-command vec (format "which \\%s | wc -w" progname)) + (goto-char (point-min)) + (if (looking-at "^1$") + (setq result (concat "\\" progname)))) + (unless result + (when ignore-tilde + ;; Remove all ~/foo directories from dirlist. In Emacs 20, + ;; `remove' is in CL, and we want to avoid CL dependencies. + (let (newdl d) + (while dirlist + (setq d (car dirlist)) + (setq dirlist (cdr dirlist)) + (unless (char-equal ?~ (aref d 0)) + (setq newdl (cons d newdl)))) + (setq dirlist (nreverse newdl)))) + (tramp-send-command + vec + (format (concat "while read d; " + "do if test -x $d/%s -a -f $d/%s; " + "then echo tramp_executable $d/%s; " + "break; fi; done <<'EOF'\n" + "%s\nEOF") + progname progname progname (mapconcat 'identity dirlist "\n"))) + (goto-char (point-max)) + (when (search-backward "tramp_executable " nil t) + (skip-chars-forward "^ ") + (skip-chars-forward " ") + (setq result (buffer-substring (point) (tramp-line-end-position))))) + result))) + +(defun tramp-set-remote-path (vec) + "Sets the remote environment PATH to existing directories. +I.e., for each directory in `tramp-remote-path', it is tested +whether it exists and if so, it is added to the environment +variable PATH." + (tramp-message vec 5 (format "Setting $PATH environment variable")) + + (with-current-buffer (tramp-get-connection-buffer vec) + (set (make-local-variable 'tramp-remote-path) + (copy-tree tramp-remote-path)) + (let* ((elt (memq 'tramp-default-remote-path tramp-remote-path)) + (tramp-default-remote-path + (with-connection-property vec "default-remote-path" + (when elt + (condition-case nil + (symbol-name + (tramp-send-command-and-read vec "getconf PATH")) + ;; Default if "getconf" is not available. + (error + (tramp-message + vec 3 + "`getconf PATH' not successful, using default value \"%s\"." + "/bin:/usr/bin") + "/bin:/usr/bin")))))) + (when elt + ;; Replace place holder `tramp-default-remote-path'. + (setcdr elt + (append + (tramp-split-string tramp-default-remote-path ":") + (cdr elt))) + (setq tramp-remote-path + (delq 'tramp-default-remote-path tramp-remote-path)))) + + ;; Check for existence of directories. + (setq tramp-remote-path + (delq + nil + (mapcar + (lambda (x) + (and + (with-connection-property vec x + (file-directory-p + (tramp-make-tramp-file-name + (tramp-file-name-method vec) + (tramp-file-name-user vec) + (tramp-file-name-host vec) + x))) + x)) + tramp-remote-path))) (tramp-send-command - multi-method method user host - (format (concat "while read d; " - "do if test -x $d/%s -a -f $d/%s; " - "then echo tramp_executable $d/%s; " - "break; fi; done <<'EOF'") - progname progname progname)) - (mapcar (lambda (d) - (tramp-send-command multi-method method user host d)) - dirlist) - (tramp-send-command multi-method method user host "EOF") - (tramp-wait-for-output) - (goto-char (point-max)) - (when (search-backward "tramp_executable " nil t) - (skip-chars-forward "^ ") - (skip-chars-forward " ") - (buffer-substring (point) (tramp-line-end-position))))) - -(defun tramp-set-remote-path (multi-method method user host var dirlist) - "Sets the remote environment VAR to existing directories from DIRLIST. -I.e., for each directory in DIRLIST, it is tested whether it exists and if -so, it is added to the environment variable VAR." - (let ((existing-dirs - (mapcar - (lambda (x) - (when (and - (file-exists-p - (tramp-make-tramp-file-name multi-method method user host x)) - (file-directory-p - (tramp-make-tramp-file-name multi-method method user host x))) - x)) - dirlist))) - (tramp-send-command - multi-method method user host - (concat var "=" - (mapconcat 'identity (delq nil existing-dirs) ":") - "; export " var)) - (tramp-wait-for-output))) + vec + (format "PATH=%s; export PATH" + (mapconcat 'identity tramp-remote-path ":"))))) ;; -- communication with external shell -- -(defun tramp-find-file-exists-command (multi-method method user host) +(defun tramp-find-file-exists-command (vec) "Find a command on the remote host for checking if a file exists. Here, we are looking for a command which has zero exit status if the file exists and nonzero exit status otherwise." - (make-local-variable 'tramp-file-exists-command) - (tramp-message 9 "Finding command to check if file exists") - (let ((existing - (tramp-make-tramp-file-name - multi-method method user host - "/")) ;assume this file always exists + (let ((existing "/") (nonexisting - (tramp-make-tramp-file-name - multi-method method user host - "/ this file does not exist "))) ;assume this never exists + (tramp-shell-quote-argument "/ this file does not exist ")) + result) ;; The algorithm is as follows: we try a list of several commands. ;; For each command, we first run `$cmd /' -- this should return ;; true, as the root directory always exists. And then we run - ;; `$cmd /this\ file\ does\ not\ exist', hoping that the file indeed + ;; `$cmd /this\ file\ does\ not\ exist ', hoping that the file indeed ;; does not exist. This should return false. We use the first ;; command we find that seems to work. ;; The list of commands to try is as follows: - ;; `ls -d' This works on most systems, but NetBSD 1.4 - ;; has a bug: `ls' always returns zero exit - ;; status, even for files which don't exist. - ;; `test -e' Some Bourne shells have a `test' builtin - ;; which does not know the `-e' option. - ;; `/bin/test -e' For those, the `test' binary on disk normally - ;; provides the option. Alas, the binary - ;; is sometimes `/bin/test' and sometimes it's - ;; `/usr/bin/test'. - ;; `/usr/bin/test -e' In case `/bin/test' does not exist. + ;; `ls -d' This works on most systems, but NetBSD 1.4 + ;; has a bug: `ls' always returns zero exit + ;; status, even for files which don't exist. + ;; `test -e' Some Bourne shells have a `test' builtin + ;; which does not know the `-e' option. + ;; `/bin/test -e' For those, the `test' binary on disk normally + ;; provides the option. Alas, the binary + ;; is sometimes `/bin/test' and sometimes it's + ;; `/usr/bin/test'. + ;; `/usr/bin/test -e' In case `/bin/test' does not exist. (unless (or - (and (setq tramp-file-exists-command "test -e %s") - (file-exists-p existing) - (not (file-exists-p nonexisting))) - (and (setq tramp-file-exists-command "/bin/test -e %s") - (file-exists-p existing) - (not (file-exists-p nonexisting))) - (and (setq tramp-file-exists-command "/usr/bin/test -e %s") - (file-exists-p existing) - (not (file-exists-p nonexisting))) - (and (setq tramp-file-exists-command "ls -d %s") - (file-exists-p existing) - (not (file-exists-p nonexisting)))) - (error "Couldn't find command to check if file exists")))) + (and (setq result (format "%s -e" (tramp-get-test-command vec))) + (zerop (tramp-send-command-and-check + vec (format "%s %s" result existing))) + (not (zerop (tramp-send-command-and-check + vec (format "%s %s" result nonexisting))))) + (and (setq result "/bin/test -e") + (zerop (tramp-send-command-and-check + vec (format "%s %s" result existing))) + (not (zerop (tramp-send-command-and-check + vec (format "%s %s" result nonexisting))))) + (and (setq result "/usr/bin/test -e") + (zerop (tramp-send-command-and-check + vec (format "%s %s" result existing))) + (not (zerop (tramp-send-command-and-check + vec (format "%s %s" result nonexisting))))) + (and (setq result (format "%s -d" (tramp-get-ls-command vec))) + (zerop (tramp-send-command-and-check + vec (format "%s %s" result existing))) + (not (zerop (tramp-send-command-and-check + vec (format "%s %s" result nonexisting)))))) + (tramp-error + vec 'file-error "Couldn't find command to check if file exists")) + result)) ;; CCC test ksh or bash found for tilde expansion? -(defun tramp-find-shell (multi-method method user host) - "Find a shell on the remote host which groks tilde expansion." - (let ((shell nil)) - (tramp-send-command multi-method method user host "echo ~root") - (tramp-wait-for-output) - (cond - ((string-match "^~root$" (buffer-string)) - (setq shell - (or (tramp-find-executable multi-method method user host - "bash" tramp-remote-path t) - (tramp-find-executable multi-method method user host - "ksh" tramp-remote-path t))) - (unless shell - (error "Couldn't find a shell which groks tilde expansion")) - ;; Find arguments for this shell. - (let ((alist tramp-sh-extra-args) - item extra-args) - (while (and alist (null extra-args)) - (setq item (pop alist)) - (when (string-match (car item) shell) - (setq extra-args (cdr item)))) - (when extra-args (setq shell (concat shell " " extra-args)))) - (tramp-message - 5 "Starting remote shell `%s' for tilde expansion..." shell) - (tramp-send-command - multi-method method user host - (concat "PS1='$ ' exec " shell)) ; - (tramp-barf-if-no-shell-prompt - (get-buffer-process (current-buffer)) - 60 "Couldn't find remote `%s' prompt" shell) - (tramp-message - 9 "Setting remote shell prompt...") - ;; Douglas Gray Stephens says that we - ;; must use "\n" here, not tramp-rsh-end-of-line. Kai left the - ;; last tramp-rsh-end-of-line, Douglas wanted to replace that, - ;; as well. - (process-send-string nil (format "PS1='%s%s%s'; PS2=''; PS3=''%s" - tramp-rsh-end-of-line - tramp-end-of-output - tramp-rsh-end-of-line - tramp-rsh-end-of-line)) - (tramp-wait-for-output) - (tramp-message - 9 "Setting remote shell prompt...done") - ) - (t (tramp-message 5 "Remote `%s' groks tilde expansion, good" - (tramp-get-method-parameter - multi-method method user host 'tramp-remote-sh)))))) - -(defun tramp-check-ls-command (multi-method method user host cmd) - "Checks whether the given `ls' executable groks `-n'. -METHOD, USER and HOST specify the connection, CMD (the absolute file name of) -the `ls' executable. Returns t if CMD supports the `-n' option, nil -otherwise." - (tramp-message 9 "Checking remote `%s' command for `-n' option" cmd) - (when (file-executable-p - (tramp-make-tramp-file-name multi-method method user host cmd)) - (let ((result nil)) - (tramp-message 7 "Testing remote command `%s' for -n..." cmd) - (setq result - (tramp-send-command-and-check - multi-method method user host - (format "%s -lnd / >/dev/null" - cmd))) - (tramp-message 7 "Testing remote command `%s' for -n...%s" - cmd - (if (zerop result) "okay" "failed")) - (zerop result)))) - -(defun tramp-check-ls-commands (multi-method method user host cmd dirlist) - "Checks whether the given `ls' executable in one of the dirs groks `-n'. -Returns nil if none was found, else the command is returned." - (let ((dl dirlist) - (result nil)) - (tramp-let-maybe directory-sep-char ?/ ;for XEmacs - ;; It would be better to use the CL function `find', but - ;; we don't want run-time dependencies on CL. - (while (and dl (not result)) - (let ((x (concat (file-name-as-directory (car dl)) cmd))) - (when (tramp-check-ls-command multi-method method user host x) - (setq result x))) - (setq dl (cdr dl))) - result))) - -(defun tramp-find-ls-command (multi-method method user host) - "Finds an `ls' command which groks the `-n' option, returning nil if failed. -\(This option prints numeric user and group ids in a long listing.)" - (tramp-message 9 "Finding a suitable `ls' command") - (or - (tramp-check-ls-commands multi-method method user host "ls" tramp-remote-path) - (tramp-check-ls-commands multi-method method user host "gnuls" tramp-remote-path) - (tramp-check-ls-commands multi-method method user host "gls" tramp-remote-path))) +(defun tramp-find-shell (vec) + "Opens a shell on the remote host which groks tilde expansion." + (unless (tramp-get-connection-property vec "remote-shell" nil) + (let (shell) + (with-current-buffer (tramp-get-buffer vec) + (tramp-send-command vec "echo ~root") + (cond + ((string-match "^~root$" (buffer-string)) + (setq shell + (or (tramp-find-executable vec "bash" tramp-remote-path t) + (tramp-find-executable vec "ksh" tramp-remote-path t))) + (unless shell + (tramp-error + vec 'file-error + "Couldn't find a shell which groks tilde expansion")) + ;; Find arguments for this shell. + (let ((alist tramp-sh-extra-args) + item extra-args) + (while (and alist (null extra-args)) + (setq item (pop alist)) + (when (string-match (car item) shell) + (setq extra-args (cdr item)))) + (when extra-args (setq shell (concat shell " " extra-args)))) + (tramp-message + vec 5 "Starting remote shell `%s' for tilde expansion..." shell) + (tramp-send-command-internal vec (concat "PS1='$ ' exec " shell)) + (tramp-message vec 5 "Setting remote shell prompt...") + ;; Douglas Gray Stephens says that we + ;; must use "\n" here, not tramp-rsh-end-of-line. Kai left the + ;; last tramp-rsh-end-of-line, Douglas wanted to replace that, + ;; as well. + (tramp-send-command + vec + (format "PS1='%s%s%s'; PS2=''; PS3=''" + tramp-rsh-end-of-line + tramp-end-of-output + tramp-rsh-end-of-line)) + (tramp-message vec 5 "Setting remote shell prompt...done")) + (t (tramp-message + vec 5 "Remote `%s' groks tilde expansion, good" + (tramp-get-method-parameter + (tramp-file-name-method vec) 'tramp-remote-sh)) + (tramp-set-connection-property + vec "remote-shell" + (tramp-get-method-parameter + (tramp-file-name-method vec) 'tramp-remote-sh)))))))) ;; ------------------------------------------------------------ ;; -- Functions for establishing connection -- @@ -5426,635 +5209,208 @@ ;; prompts from the remote host. See the variable ;; `tramp-actions-before-shell' for usage of these functions. -(defun tramp-action-login (p multi-method method user host) +(defun tramp-action-login (proc vec) "Send the login name." - (tramp-message 9 "Sending login name `%s'" - (or user (user-login-name))) - (erase-buffer) - (process-send-string nil (concat (or user (user-login-name)) - tramp-rsh-end-of-line))) - -(defun tramp-action-password (p multi-method method user host) + (when (not (stringp tramp-current-user)) + (save-window-excursion + (let ((enable-recursive-minibuffers t)) + (pop-to-buffer (tramp-get-connection-buffer vec)) + (setq tramp-current-user (read-string (match-string 0)))))) + (tramp-message vec 3 "Sending login name `%s'" tramp-current-user) + (with-current-buffer (tramp-get-connection-buffer vec) + (tramp-message vec 6 "\n%s" (buffer-string))) + (tramp-send-string vec tramp-current-user)) + +(defun tramp-action-password (proc vec) "Query the user for a password." - (let ((pw-prompt - (format "Password for %s " - (tramp-make-tramp-file-name - nil method user host "")))) - (tramp-message 9 "Sending password") - (tramp-enter-password p pw-prompt user host))) - -(defun tramp-action-succeed (p multi-method method user host) + (tramp-message vec 3 "Sending password") + (tramp-enter-password proc)) + +(defun tramp-action-succeed (proc vec) "Signal success in finding shell prompt." - (tramp-message 9 "Found remote shell prompt.") - (erase-buffer) (throw 'tramp-action 'ok)) -(defun tramp-action-permission-denied (p multi-method method user host) +(defun tramp-action-permission-denied (proc vec) "Signal permission denied." - (pop-to-buffer (tramp-get-buffer multi-method method user host)) - (tramp-message 9 "Permission denied by remote host.") - (kill-process p) + (kill-process proc) (throw 'tramp-action 'permission-denied)) -(defun tramp-action-copy-failed (p multi-method method user host) - "Signal copy failed." - (kill-process p) - (error "%s" (match-string 1))) - -(defun tramp-action-yesno (p multi-method method user host) +(defun tramp-action-yesno (proc vec) "Ask the user for confirmation using `yes-or-no-p'. Send \"yes\" to remote process on confirmation, abort otherwise. See also `tramp-action-yn'." (save-window-excursion - (pop-to-buffer (tramp-get-buffer multi-method method user host)) - (unless (yes-or-no-p (match-string 0)) - (kill-process p) - (erase-buffer) - (throw 'tramp-action 'permission-denied)) - (process-send-string p (concat "yes" tramp-rsh-end-of-line)) - (erase-buffer))) - -(defun tramp-action-yn (p multi-method method user host) + (let ((enable-recursive-minibuffers t)) + (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec))) + (unless (yes-or-no-p (match-string 0)) + (kill-process proc) + (throw 'tramp-action 'permission-denied)) + (with-current-buffer (tramp-get-connection-buffer vec) + (tramp-message vec 6 "\n%s" (buffer-string))) + (tramp-send-string vec "yes")))) + +(defun tramp-action-yn (proc vec) "Ask the user for confirmation using `y-or-n-p'. Send \"y\" to remote process on confirmation, abort otherwise. See also `tramp-action-yesno'." (save-window-excursion - (pop-to-buffer (tramp-get-buffer multi-method method user host)) - (unless (y-or-n-p (match-string 0)) - (kill-process p) - (throw 'tramp-action 'permission-denied)) - (erase-buffer) - (process-send-string p (concat "y" tramp-rsh-end-of-line)))) - -(defun tramp-action-terminal (p multi-method method user host) + (let ((enable-recursive-minibuffers t)) + (save-match-data (pop-to-buffer (tramp-get-connection-buffer vec))) + (unless (y-or-n-p (match-string 0)) + (kill-process proc) + (throw 'tramp-action 'permission-denied)) + (with-current-buffer (tramp-get-connection-buffer vec) + (tramp-message vec 6 "\n%s" (buffer-string))) + (tramp-send-string vec "y")))) + +(defun tramp-action-terminal (proc vec) "Tell the remote host which terminal type to use. The terminal type can be configured with `tramp-terminal-type'." - (tramp-message 9 "Setting `%s' as terminal type." - tramp-terminal-type) - (erase-buffer) - (process-send-string nil (concat tramp-terminal-type - tramp-rsh-end-of-line))) - -(defun tramp-action-process-alive (p multi-method method user host) + (tramp-message vec 5 "Setting `%s' as terminal type." tramp-terminal-type) + (tramp-send-string vec tramp-terminal-type)) + +(defun tramp-action-process-alive (proc vec) "Check whether a process has finished." - (unless (memq (process-status p) '(run open)) + (unless (memq (process-status proc) '(run open)) (throw 'tramp-action 'process-died))) -(defun tramp-action-out-of-band (p multi-method method user host) +(defun tramp-action-out-of-band (proc vec) "Check whether an out-of-band copy has finished." - (cond ((and (memq (process-status p) '(stop exit)) - (zerop (process-exit-status p))) - (tramp-message 9 "Process has finished.") + (cond ((and (memq (process-status proc) '(stop exit)) + (zerop (process-exit-status proc))) + (tramp-message vec 3 "Process has finished.") (throw 'tramp-action 'ok)) - ((or (and (memq (process-status p) '(stop exit)) - (not (zerop (process-exit-status p)))) - (memq (process-status p) '(signal))) + ((or (and (memq (process-status proc) '(stop exit)) + (not (zerop (process-exit-status proc)))) + (memq (process-status proc) '(signal))) ;; `scp' could have copied correctly, but set modes could have failed. ;; This can be ignored. - (goto-char (point-min)) - (if (re-search-forward tramp-operation-not-permitted-regexp nil t) - (progn - (tramp-message 10 "'set mode' error ignored.") - (tramp-message 9 "Process has finished.") - (throw 'tramp-action 'ok)) - (tramp-message 9 "Process has died.") - (throw 'tramp-action 'process-died))) + (with-current-buffer (process-buffer proc) + (goto-char (point-min)) + (if (re-search-forward tramp-operation-not-permitted-regexp nil t) + (progn + (tramp-message vec 5 "'set mode' error ignored.") + (tramp-message vec 3 "Process has finished.") + (throw 'tramp-action 'ok)) + (tramp-message vec 3 "Process has died.") + (throw 'tramp-action 'process-died)))) (t nil))) -;; The following functions are specifically for multi connections. - -(defun tramp-multi-action-login (p method user host) - "Send the login name." - (tramp-message 9 "Sending login name `%s'" user) - (erase-buffer) - (process-send-string p (concat user tramp-rsh-end-of-line))) - -(defun tramp-multi-action-password (p method user host) - "Query the user for a password." - (let ((pw-prompt - (format "Password for %s " - (tramp-make-tramp-file-name - nil method user host "")))) - (tramp-message 9 "Sending password") - (tramp-enter-password p pw-prompt user host))) - -(defun tramp-multi-action-succeed (p method user host) - "Signal success in finding shell prompt." - (tramp-message 9 "Found shell prompt on `%s'" host) - (erase-buffer) - (throw 'tramp-action 'ok)) - -(defun tramp-multi-action-permission-denied (p method user host) - "Signal permission denied." - (tramp-message 9 "Permission denied by remote host `%s'" host) - (kill-process p) - (erase-buffer) - (throw 'tramp-action 'permission-denied)) - -(defun tramp-multi-action-process-alive (p method user host) - "Check whether a process has finished." - (unless (memq (process-status p) '(run open)) - (throw 'tramp-action 'process-died))) - ;; Functions for processing the actions. -(defun tramp-process-one-action (p multi-method method user host actions) +(defun tramp-process-one-action (proc vec actions) "Wait for output from the shell and perform one action." - (let (found item pattern action todo) - (erase-buffer) - (tramp-message 9 "Waiting 60s for prompt from remote shell") + (let (found todo item pattern action) (while (not found) - (tramp-accept-process-output p 1) - (goto-char (point-min)) + ;; Reread output once all actions have been performed. + ;; Obviously, the output was not complete. + (tramp-accept-process-output proc 1) (setq todo actions) (while todo - (goto-char (point-min)) (setq item (pop todo)) - (setq pattern (symbol-value (nth 0 item))) + (setq pattern (concat (symbol-value (nth 0 item)) "\\'")) (setq action (nth 1 item)) - (tramp-message 10 "Looking for regexp \"%s\" from remote shell" - pattern) - (when (re-search-forward (concat pattern "\\'") nil t) - (setq found (funcall action p multi-method method user host))))) + (tramp-message + vec 5 "Looking for regexp \"%s\" from remote shell" pattern) + (when (tramp-check-for-regexp proc pattern) + (tramp-message vec 5 "Call `%s'" (symbol-name action)) + (setq found (funcall action proc vec))))) found)) -(defun tramp-process-actions - (p multi-method method user host actions &optional timeout) +(defun tramp-process-actions (proc vec actions &optional timeout) "Perform actions until success or TIMEOUT." - (tramp-message 10 "%s" (mapconcat 'identity (process-command p) " ")) (let (exit) (while (not exit) - (tramp-message 9 "Waiting for prompts from remote shell") + (tramp-message proc 3 "Waiting for prompts from remote shell") (setq exit (catch 'tramp-action (if timeout (with-timeout (timeout) - (tramp-process-one-action - p multi-method method user host actions)) - (tramp-process-one-action - p multi-method method user host actions)) - nil))) - (unless (eq exit 'ok) - (tramp-clear-passwd user host) - (error "Login failed")))) - -;; For multi-actions. - -(defun tramp-process-one-multi-action (p method user host actions) - "Wait for output from the shell and perform one action." - (let (found item pattern action todo) - (erase-buffer) - (tramp-message 9 "Waiting 60s for prompt from remote shell") - (with-timeout (60 (throw 'tramp-action 'timeout)) - (while (not found) - (tramp-accept-process-output p 1) - (setq todo actions) - (goto-char (point-min)) - (while todo - (goto-char (point-min)) - (setq item (pop todo)) - (setq pattern (symbol-value (nth 0 item))) - (setq action (nth 1 item)) - (tramp-message 10 "Looking for regexp \"%s\" from remote shell" - pattern) - (when (re-search-forward (concat pattern "\\'") nil t) - (setq found (funcall action p method user host))))) - found))) - -(defun tramp-process-multi-actions (p method user host actions) - "Perform actions until success." - (let (exit) - (while (not exit) - (tramp-message 9 "Waiting for prompts from remote shell") - (setq exit - (catch 'tramp-action - (tramp-process-one-multi-action p method user host actions) - nil))) + (tramp-process-one-action proc vec actions)) + (tramp-process-one-action proc vec actions))))) + (with-current-buffer (tramp-get-connection-buffer vec) + (tramp-message vec 6 "\n%s" (buffer-string))) (unless (eq exit 'ok) - (tramp-clear-passwd user host) - (error "Login failed")))) - -;; Functions to execute when we have seen the remote shell prompt but -;; before we exec the Bourne-ish shell. Note that these commands -;; might be sent to any shell, not just a Bourne-ish shell. This -;; means that the commands need to work in all shells. (It is also -;; okay for some commands to just fail with an error message, but -;; please make sure that they at least don't crash the odd shell people -;; might be running...) -(defun tramp-process-initial-commands (p - multi-method method user host - commands) - "Send list of commands to remote host, in order." - (let (cmd) - (while commands - (setq cmd (pop commands)) - (erase-buffer) - (tramp-message 10 "Sending command to remote shell: %s" - cmd) - (tramp-send-command multi-method method user host cmd nil t) - (tramp-barf-if-no-shell-prompt - p 60 "Remote shell command failed: %s" cmd)) - (erase-buffer))) - -;; The actual functions for opening connections. - -(defun tramp-open-connection-telnet (multi-method method user host) - "Open a connection using a telnet METHOD. -This starts the command `telnet HOST ARGS'[*], then waits for a remote -login prompt, then sends the user name USER, then waits for a remote -password prompt. It queries the user for the password, then sends the -password to the remote host. - -If USER is nil, uses value returned by `(user-login-name)' instead. - -Recognition of the remote shell prompt is based on the variables -`shell-prompt-pattern' and `tramp-shell-prompt-pattern' which must be -set up correctly. - -Please note that it is NOT possible to use this connection method -together with an out-of-band transfer method! You must use an inline -transfer method. - -Maybe the different regular expressions need to be tuned. - -* Actually, the telnet program as well as the args to be used can be - specified in the method parameters, see the variable `tramp-methods'." - (save-match-data - (when (tramp-method-out-of-band-p multi-method method user host) - (error "Cannot use out-of-band method `%s' with telnet connection method" - method)) - (when multi-method - (error "Cannot multi-connect using telnet connection method")) - (tramp-pre-connection multi-method method user host tramp-chunksize) - (tramp-message 7 "Opening connection for %s@%s using %s..." - (or user (user-login-name)) host method) - (let ((process-environment (copy-sequence process-environment))) - (setenv "TERM" tramp-terminal-type) - (setenv "PS1" "$ ") - (let* ((default-directory (tramp-temporary-file-directory)) - ;; If we omit the conditional here, then we would use - ;; `undecided-dos' in some cases. With the conditional, - ;; we use nil in these cases. Which one is right? - (coding-system-for-read (unless (and (not (featurep 'xemacs)) - (> emacs-major-version 20)) - tramp-dos-coding-system)) - (p (apply 'start-process - (tramp-buffer-name multi-method method user host) - (tramp-get-buffer multi-method method user host) - (tramp-get-method-parameter - multi-method - (tramp-find-method multi-method method user host) - user host 'tramp-login-program) - host - (tramp-get-method-parameter - multi-method - (tramp-find-method multi-method method user host) - user host 'tramp-login-args))) - (found nil) - (pw nil)) - (tramp-set-process-query-on-exit-flag p nil) - (set-buffer (tramp-get-buffer multi-method method user host)) - (erase-buffer) - (tramp-process-actions p multi-method method user host - tramp-actions-before-shell 60) - (tramp-open-connection-setup-interactive-shell - p multi-method method user host) - (tramp-post-connection multi-method method user host))))) - - -(defun tramp-open-connection-rsh (multi-method method user host) - "Open a connection using an rsh METHOD. -This starts the command `rsh HOST -l USER'[*], then waits for a remote -password or shell prompt. If a password prompt is seen, the user is -queried for a password, this function sends the password to the remote -host and waits for a shell prompt. - -If USER is nil, start the command `rsh HOST'[*] instead - -Recognition of the remote shell prompt is based on the variables -`shell-prompt-pattern' and `tramp-shell-prompt-pattern' which must be -set up correctly. - -Kludgy feature: if HOST has the form \"xx#yy\", then yy is assumed to -be a port number for ssh, and \"-p yy\" will be added to the list of -arguments, and xx will be used as the host name to connect to. - -* Actually, the rsh program to be used can be specified in the - method parameters, see the variable `tramp-methods'." - (save-match-data - (when multi-method - (error "Cannot multi-connect using rsh connection method")) - (tramp-pre-connection multi-method method user host tramp-chunksize) - (if (and user (not (string= user ""))) - (tramp-message 7 "Opening connection for %s@%s using %s..." - user host method) - (tramp-message 7 "Opening connection at %s using %s..." host method)) - (let ((process-environment (copy-sequence process-environment)) - (bufnam (tramp-buffer-name multi-method method user host)) - (buf (tramp-get-buffer multi-method method user host)) - (login-program (tramp-get-method-parameter - multi-method - (tramp-find-method multi-method method user host) - user host 'tramp-login-program)) - (login-args (mapcar - (lambda (x) - (format-spec - x `((?t . ,(format "/tmp/%s" tramp-temp-name-prefix))))) - (tramp-get-method-parameter - multi-method - (tramp-find-method multi-method method user host) - user host 'tramp-login-args))) - (real-host host)) - ;; The following should be changed. We need a more general - ;; mechanism to parse extra host args. - (when (string-match "\\([^#]*\\)#\\(.*\\)" host) - (setq login-args (cons "-p" (cons (match-string 2 host) login-args))) - (setq real-host (match-string 1 host))) - (setenv "TERM" tramp-terminal-type) - (setenv "PS1" "$ ") - (let* ((default-directory (tramp-temporary-file-directory)) - ;; If we omit the conditional, we would use - ;; `undecided-dos' in some cases. With the conditional, - ;; we use nil in these cases. Which one is right? - (coding-system-for-read (unless (and (not (featurep 'xemacs)) - (> emacs-major-version 20)) - tramp-dos-coding-system)) - (p (if (and user (not (string= user ""))) - (apply #'start-process bufnam buf login-program - real-host "-l" user login-args) - (apply #'start-process bufnam buf login-program - real-host login-args))) - (found nil)) - (tramp-set-process-query-on-exit-flag p nil) - - (set-buffer buf) - (tramp-process-actions p multi-method method user host - tramp-actions-before-shell 60) - (tramp-message 7 "Initializing remote shell") - (tramp-open-connection-setup-interactive-shell - p multi-method method user host) - (tramp-post-connection multi-method method user host))))) - -(defun tramp-open-connection-su (multi-method method user host) - "Open a connection using the `su' program with METHOD. -This starts `su - USER', then waits for a password prompt. The HOST -name must be equal to the local host name or to `localhost'. - -If USER is nil, uses value returned by user-login-name instead. - -Recognition of the remote shell prompt is based on the variables -`shell-prompt-pattern' and `tramp-shell-prompt-pattern' which must be -set up correctly. Note that the other user may have a different shell -prompt than you do, so it is not at all unlikely that the variable -`shell-prompt-pattern' is set up wrongly!" - (save-match-data - (when (tramp-method-out-of-band-p multi-method method user host) - (error "Cannot use out-of-band method `%s' with `su' connection method" - method)) - (unless (or (string-match (concat "^" (regexp-quote host)) - (system-name)) - (string= "localhost" host) - (string= "" host)) - (error - "Cannot connect to different host `%s' with `su' connection method" - host)) - (tramp-pre-connection multi-method method user host tramp-chunksize) - (tramp-message 7 "Opening connection for `%s' using `%s'..." - (or user "") method) - (let ((process-environment (copy-sequence process-environment))) - (setenv "TERM" tramp-terminal-type) - (setenv "PS1" "$ ") - (let* ((default-directory (tramp-temporary-file-directory)) - ;; If we omit the conditional, we use `undecided-dos' in - ;; some cases. With the conditional, we use nil in these - ;; cases. What's the difference? Which one is right? - (coding-system-for-read (unless (and (not (featurep 'xemacs)) - (> emacs-major-version 20)) - tramp-dos-coding-system)) - (p (apply 'start-process - (tramp-buffer-name multi-method method user host) - (tramp-get-buffer multi-method method user host) - (tramp-get-method-parameter - multi-method - (tramp-find-method multi-method method user host) - user host 'tramp-login-program) - (mapcar - (lambda (x) - (format-spec x `((?u . ,(or user "root"))))) - (tramp-get-method-parameter - multi-method - (tramp-find-method multi-method method user host) - user host 'tramp-login-args)))) - (found nil) - (pw nil)) - (tramp-set-process-query-on-exit-flag p nil) - (set-buffer (tramp-get-buffer multi-method method user host)) - (tramp-process-actions p multi-method method user host - tramp-actions-before-shell 60) - (tramp-open-connection-setup-interactive-shell - p multi-method method user host) - (tramp-post-connection multi-method method - user host))))) - -;; HHH: Not Changed. Multi method. It is not clear to me how this can -;; handle not giving a user name in the "file name". -;; -;; This is more difficult than for the single-hop method. In the -;; multi-hop-method, the desired behaviour should be that the -;; user must specify names for the telnet hops of which the user -;; name is different than the "original" name (or different from -;; the previous hop. -(defun tramp-open-connection-multi (multi-method method user host) - "Open a multi-hop connection using METHOD. -This uses a slightly changed file name syntax. The idea is to say - [multi/telnet:u1@h1/rsh:u2@h2]/path/to/file -This will use telnet to log in as u1 to h1, then use rsh from there to -log in as u2 to h2." - (save-match-data - (unless multi-method - (error "Multi-hop open connection function called on non-multi method")) - (when (tramp-method-out-of-band-p multi-method method user host) - (error "No out of band multi-hop connections")) - (unless (and (arrayp method) (not (stringp method))) - (error "METHOD must be an array of strings for multi methods")) - (unless (and (arrayp user) (not (stringp user))) - (error "USER must be an array of strings for multi methods")) - (unless (and (arrayp host) (not (stringp host))) - (error "HOST must be an array of strings for multi methods")) - (unless (and (= (length method) (length user)) - (= (length method) (length host))) - (error "Arrays METHOD, USER, HOST must have equal length")) - (tramp-pre-connection multi-method method user host tramp-chunksize) - (tramp-message 7 "Opening `%s' connection..." multi-method) - (let ((process-environment (copy-sequence process-environment))) - (setenv "TERM" tramp-terminal-type) - (setenv "PS1" "$ ") - (let* ((default-directory (tramp-temporary-file-directory)) - ;; If we omit the conditional, we use `undecided-dos' in - ;; some cases. With the conditional, we use nil in these - ;; cases. What's the difference? Which one is right? - (coding-system-for-read (unless (and (not (featurep 'xemacs)) - (> emacs-major-version 20)) - tramp-dos-coding-system)) - (p (start-process (tramp-buffer-name multi-method method user host) - (tramp-get-buffer multi-method method user host) - tramp-multi-sh-program)) - (num-hops (length method)) - (i 0)) - (tramp-set-process-query-on-exit-flag p nil) - (tramp-message 9 "Waiting 60s for local shell to come up...") - (unless (tramp-wait-for-regexp - p 60 (format "\\(%s\\)\\'\\|\\(%s\\)\\'" - shell-prompt-pattern tramp-shell-prompt-pattern)) - (pop-to-buffer (buffer-name)) - (kill-process p) - (error "Couldn't find local shell prompt")) - ;; Now do all the connections as specified. - (while (< i num-hops) - (let* ((m (aref method i)) - (u (aref user i)) - (h (aref host i)) - (entry (assoc m tramp-multi-connection-function-alist)) - (multi-func (nth 1 entry)) - (command (nth 2 entry))) - ;; The multi-funcs don't need to do save-match-data, as that - ;; is done here. - (funcall multi-func p m u h command) - (erase-buffer) - (setq i (1+ i)))) - (tramp-open-connection-setup-interactive-shell - p multi-method method user host) - (tramp-post-connection multi-method method user host))))) - -;; HHH: Changed. Multi method. Don't know how to handle this in the case -;; of no user name provided. Hack to make it work as it did before: -;; changed `user' to `(or user (user-login-name))' in the places where -;; the value is actually used. -(defun tramp-multi-connect-telnet (p method user host command) - "Issue `telnet' command. -Uses shell COMMAND to issue a `telnet' command to log in as USER to -HOST. You can use percent escapes in COMMAND: `%h' is replaced with -the host name, and `%n' is replaced with an end of line character, as -set in `tramp-rsh-end-of-line'. Use `%%' if you want a literal percent -character. - -If USER is nil, uses the return value of (user-login-name) instead." - (let ((cmd (format-spec command - `((?h . ,host) (?n . ,tramp-rsh-end-of-line)))) - (cmd1 (format-spec command `((?h . ,host) (?n . "")))) - found pw) - (erase-buffer) - (tramp-message 9 "Sending telnet command `%s'" cmd1) - (process-send-string p cmd) - (tramp-process-multi-actions p method user host - tramp-multi-actions))) - -;; HHH: Changed. Multi method. Don't know how to handle this in the case -;; of no user name provided. Hack to make it work as it did before: -;; changed `user' to `(or user (user-login-name))' in the places where -;; the value is actually used. -(defun tramp-multi-connect-rlogin (p method user host command) - "Issue `rlogin' command. -Uses shell COMMAND to issue an `rlogin' command to log in as USER to -HOST. You can use percent escapes in COMMAND. `%u' will be replaced -with the user name, `%h' will be replaced with the host name, and `%n' -will be replaced with the value of `tramp-rsh-end-of-line'. You can use -`%%' if you want to use a literal percent character. - -If USER is nil, uses the return value of (user-login-name) instead." - (let ((cmd (format-spec command `((?h . ,host) - (?u . ,(or user (user-login-name))) - (?n . ,tramp-rsh-end-of-line)))) - (cmd1 (format-spec command `((?h . ,host) - (?u . ,(or user (user-login-name))) - (?n . "")))) - found) - (erase-buffer) - (tramp-message 9 "Sending rlogin command `%s'" cmd1) - (process-send-string p cmd) - (tramp-process-multi-actions p method user host - tramp-multi-actions))) - -;; HHH: Changed. Multi method. Don't know how to handle this in the case -;; of no user name provided. Hack to make it work as it did before: -;; changed `user' to `(or user (user-login-name))' in the places where -;; the value is actually used. -(defun tramp-multi-connect-su (p method user host command) - "Issue `su' command. -Uses shell COMMAND to issue a `su' command to log in as USER on -HOST. The HOST name is ignored, this just changes the user id on the -host currently logged in to. - -If USER is nil, uses the return value of (user-login-name) instead. - -You can use percent escapes in the COMMAND. `%u' is replaced with the -user name, and `%n' is replaced with the value of -`tramp-rsh-end-of-line'. Use `%%' if you want a literal percent -character." - (let ((cmd (format-spec command `((?u . ,(or user (user-login-name))) - (?n . ,tramp-rsh-end-of-line)))) - (cmd1 (format-spec command `((?u . ,(or user (user-login-name))) - (?n . "")))) - found) - (erase-buffer) - (tramp-message 9 "Sending su command `%s'" cmd1) - (process-send-string p cmd) - (tramp-process-multi-actions p method user host - tramp-multi-actions))) + (tramp-clear-passwd) + (tramp-error-with-buffer + nil vec 'file-error + (cond + ((eq exit 'permission-denied) "Permission denied") + ((eq exit 'process-died) "Process died") + (t "Login failed")))))) ;; Utility functions. -(defun tramp-accept-process-output - (&optional process timeout timeout-msecs) +(defun tramp-accept-process-output (&optional proc timeout timeout-msecs) "Like `accept-process-output' for Tramp processes. This is needed in order to hide `last-coding-system-used', which is set for process communication also." - (let (last-coding-system-used) - (accept-process-output process timeout timeout-msecs))) + (with-current-buffer (process-buffer proc) + (tramp-message proc 10 "%s %s" proc (process-status proc)) + (let (buffer-read-only last-coding-system-used) + ;; Under Windows XP, accept-process-output doesn't return + ;; sometimes. So we add an additional timeout. + (with-timeout ((or timeout 1)) + (accept-process-output proc timeout timeout-msecs))) + (tramp-message proc 10 "\n%s" (buffer-string)))) + +(defun tramp-check-for-regexp (proc regexp) + "Check whether REGEXP is contained in process buffer of PROC. +Erase echoed commands if exists." + (with-current-buffer (process-buffer proc) + (goto-char (point-min)) + ;; Check whether we need to remove echo output. + (when (and (tramp-get-connection-property proc "check-remote-echo" nil) + (re-search-forward tramp-echoed-echo-mark-regexp nil t)) + (let ((begin (match-beginning 0))) + (when (re-search-forward tramp-echoed-echo-mark-regexp nil t) + ;; Discard echo from remote output. + (tramp-set-connection-property proc "check-remote-echo" nil) + (tramp-message proc 5 "echo-mark found") + (forward-line) + (delete-region begin (point)) + (goto-char (point-min))))) + ;; No echo to be handled, now we can look for the regexp. + (when (not (tramp-get-connection-property proc "check-remote-echo" nil)) + (re-search-forward regexp nil t)))) (defun tramp-wait-for-regexp (proc timeout regexp) "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds. Expects the output of PROC to be sent to the current buffer. Returns the string that matched, or nil. Waits indefinitely if TIMEOUT is nil." - (let ((found nil) - (start-time (current-time))) - (cond (timeout - ;; Work around a bug in XEmacs 21, where the timeout - ;; expires faster than it should. This degenerates - ;; to polling for buggy XEmacsen, but oh, well. - (while (and (not found) - (< (tramp-time-diff (current-time) start-time) - timeout)) - (with-timeout (timeout) - (while (not found) - (tramp-accept-process-output proc 1) - (unless (memq (process-status proc) '(run open)) - (error "Process has died")) - (goto-char (point-min)) - (setq found (re-search-forward regexp nil t)))))) - (t - (while (not found) - (tramp-accept-process-output proc 1) - (unless (memq (process-status proc) '(run open)) - (error "Process has died")) - (goto-char (point-min)) - (setq found (re-search-forward regexp nil t))))) - (when tramp-debug-buffer - (append-to-buffer - (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method - tramp-current-user tramp-current-host) - (point-min) (point-max)) + (with-current-buffer (process-buffer proc) + (let ((found (tramp-check-for-regexp proc regexp)) + (start-time (current-time))) + (cond (timeout + ;; Work around a bug in XEmacs 21, where the timeout + ;; expires faster than it should. This degenerates + ;; to polling for buggy XEmacsen, but oh, well. + (while (and (not found) + (< (tramp-time-diff (current-time) start-time) + timeout)) + (with-timeout (timeout) + (while (not found) + (tramp-accept-process-output proc 1) + (unless (memq (process-status proc) '(run open)) + (tramp-error-with-buffer + nil proc 'file-error "Process has died")) + (setq found (tramp-check-for-regexp proc regexp)))))) + (t + (while (not found) + (tramp-accept-process-output proc 1) + (unless (memq (process-status proc) '(run open)) + (tramp-error-with-buffer + nil proc 'file-error "Process has died")) + (setq found (tramp-check-for-regexp proc regexp))))) + (tramp-message proc 6 "\n%s" (buffer-string)) (when (not found) - (save-excursion - (set-buffer - (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method - tramp-current-user tramp-current-host)) - (goto-char (point-max)) - (insert "[[Regexp `" regexp "' not found" - (if timeout (format " in %d secs" timeout) "") - "]]")))) - found)) + (if timeout + (tramp-error + proc 'file-error "[[Regexp `%s' not found in %d secs]]" + regexp timeout) + (tramp-error proc 'file-error "[[Regexp `%s' not found]]" regexp))) + found))) (defun tramp-wait-for-shell-prompt (proc timeout) "Wait for the shell prompt to appear from process PROC within TIMEOUT seconds. @@ -6071,51 +5427,23 @@ Looks at process PROC to see if a shell prompt appears in TIMEOUT seconds. If not, it produces an error message with the given ERROR-ARGS." (unless (tramp-wait-for-shell-prompt proc timeout) - (pop-to-buffer (buffer-name)) - (apply 'error error-args))) - -(defun tramp-enter-password (p prompt user host) - "Prompt for a password and send it to the remote end. -Uses PROMPT as a prompt and sends the password to process P." - (let ((pw (tramp-read-passwd user host prompt))) - (erase-buffer) - (process-send-string - p (concat pw - (or (tramp-get-method-parameter - tramp-current-multi-method - tramp-current-method - tramp-current-user - tramp-current-host - 'tramp-password-end-of-line) - tramp-default-password-end-of-line))))) - -;; HHH: Not Changed. This might handle the case where USER is not -;; given in the "File name" very poorly. Then, the local -;; variable tramp-current-user will be set to nil. -(defun tramp-pre-connection (multi-method method user host chunksize) - "Do some setup before actually logging in. -METHOD, USER and HOST specify the connection." - (set-buffer (tramp-get-buffer multi-method method user host)) - (set (make-local-variable 'tramp-current-multi-method) multi-method) - (set (make-local-variable 'tramp-current-method) method) - (set (make-local-variable 'tramp-current-user) user) - (set (make-local-variable 'tramp-current-host) host) - (set (make-local-variable 'tramp-chunksize) chunksize) - (set (make-local-variable 'inhibit-eol-conversion) nil) - (erase-buffer)) - -(defun tramp-open-connection-setup-interactive-shell - (p multi-method method user host) + (apply 'tramp-error-with-buffer nil proc 'file-error error-args))) + +;; We don't call `tramp-send-string' in order to hide the password from the +;; debug buffer, and because end-of-line handling of the string. +(defun tramp-enter-password (p) + "Prompt for a password and send it to the remote end." + (process-send-string + p (concat (tramp-read-passwd p) + (or (tramp-get-method-parameter + tramp-current-method + 'tramp-password-end-of-line) + tramp-default-password-end-of-line)))) + +(defun tramp-open-connection-setup-interactive-shell (proc vec) "Set up an interactive shell. -Mainly sets the prompt and the echo correctly. P is the shell process -to set up. METHOD, USER and HOST specify the connection." - ;; Wait a bit in case the remote end feels like sending a little - ;; junk first. It seems that fencepost.gnu.org does this when doing - ;; a Kerberos login. - (sit-for 1) - (tramp-discard-garbage-erase-buffer p multi-method method user host) - (tramp-process-initial-commands p multi-method method user host - tramp-initial-commands) +Mainly sets the prompt and the echo correctly. PROC is the shell +process to set up. VEC specifies the connection." ;; It is useful to set the prompt in the following command because ;; some people have a setting for $PS1 which /bin/sh doesn't know ;; about and thus /bin/sh will display a strange prompt. For @@ -6129,116 +5457,84 @@ ;; called as sh) on startup; this way, we avoid the startup file ;; clobbering $PS1. (tramp-send-command-internal - multi-method method user host + vec (format "exec env 'ENV=' 'PS1=$ ' %s" (tramp-get-method-parameter - multi-method method user host 'tramp-remote-sh)) - (format "remote `%s' to come up" - (tramp-get-method-parameter - multi-method method user host 'tramp-remote-sh))) - (tramp-barf-if-no-shell-prompt - p 30 - "Remote `%s' didn't come up. See buffer `%s' for details" - (tramp-get-method-parameter multi-method method user host 'tramp-remote-sh) - (buffer-name)) - (tramp-message 8 "Setting up remote shell environment") - (tramp-discard-garbage-erase-buffer p multi-method method user host) - (tramp-send-command-internal multi-method method user host - "stty -inlcr -echo kill '^U'") - (erase-buffer) - ;; Ignore garbage after stty command. - (tramp-send-command-internal multi-method method user host - "echo foo") - (erase-buffer) - (tramp-send-command-internal multi-method method user host - "TERM=dumb; export TERM") - (erase-buffer) + (tramp-file-name-method vec) 'tramp-remote-sh))) + (tramp-message vec 5 "Setting up remote shell environment") + (tramp-send-command-internal vec "stty -inlcr -echo kill '^U' erase '^H'") + ;; Check whether the echo has really been disabled. Some + ;; implementations, like busybox of embedded GNU/Linux, don't + ;; support disabling. + (tramp-send-command-internal vec "echo foo") + (with-current-buffer (process-buffer proc) + (goto-char (point-min)) + (when (looking-at "echo foo") + (tramp-set-connection-property vec "remote-echo" t) + (tramp-message vec 5 "Remote echo still on. Ok.") + ;; Make sure backspaces and their echo are enabled and no line + ;; width magic interferes with them. + (tramp-send-command-internal vec "stty icanon erase ^H cols 32767"))) + ;; Try to set up the coding system correctly. + ;; CCC this can't be the right way to do it. Hm. + (tramp-message vec 5 "Determining coding system") + (tramp-send-command-internal vec "echo foo ; echo bar") + (with-current-buffer (process-buffer proc) + (goto-char (point-min)) + (if (featurep 'mule) + ;; Use MULE to select the right EOL convention for communicating + ;; with the process. + (let* ((cs (or (process-coding-system proc) + (cons 'undecided 'undecided))) + cs-decode cs-encode) + (when (symbolp cs) (setq cs (cons cs cs))) + (setq cs-decode (car cs)) + (setq cs-encode (cdr cs)) + (unless cs-decode (setq cs-decode 'undecided)) + (unless cs-encode (setq cs-encode 'undecided)) + (setq cs-encode (tramp-coding-system-change-eol-conversion + cs-encode 'unix)) + (when (search-forward "\r" nil t) + (setq cs-decode (tramp-coding-system-change-eol-conversion + cs-decode 'dos))) + (set-buffer-process-coding-system cs-decode cs-encode)) + ;; Look for ^M and do something useful if found. + (when (search-forward "\r" nil t) + ;; We have found a ^M but cannot frob the process coding system + ;; because we're running on a non-MULE Emacs. Let's try + ;; stty, instead. + (tramp-send-command-internal vec "stty -onlcr")))) + (tramp-send-command-internal vec "set +o vi +o emacs") + (tramp-message vec 5 "Setting shell prompt") + ;; Douglas Gray Stephens says that we must + ;; use "\n" here, not tramp-rsh-end-of-line. We also manually frob + ;; the last time we sent a command, to avoid `tramp-send-command' to + ;; send "echo are you awake". + (tramp-send-command + vec + (format "PS1='%s%s%s'; PS2=''; PS3=''" + tramp-rsh-end-of-line + tramp-end-of-output + tramp-rsh-end-of-line)) ;; Check whether the remote host suffers from buggy `send-process-string'. ;; This is known for FreeBSD (see comment in `send_process', file process.c). ;; I've tested sending 624 bytes successfully, sending 625 bytes failed. ;; Emacs makes a hack when this host type is detected locally. It cannot ;; handle remote hosts, though. - (when (or (not tramp-chunksize) (zerop tramp-chunksize)) - (tramp-message 9 "Checking remote host type for `send-process-string' bug") - (tramp-send-command-internal multi-method method user host - "(uname -sr) 2>/dev/null") - (goto-char (point-min)) - (when (looking-at "FreeBSD") - (setq tramp-chunksize 500))) - - ;; Try to set up the coding system correctly. - ;; CCC this can't be the right way to do it. Hm. - (save-excursion - (erase-buffer) - (tramp-message 9 "Determining coding system") - (tramp-send-command-internal multi-method method user host - "echo foo ; echo bar") - (goto-char (point-min)) - (if (featurep 'mule) - ;; Use MULE to select the right EOL convention for communicating - ;; with the process. - (let* ((cs (or (process-coding-system p) (cons 'undecided 'undecided))) - cs-decode cs-encode) - (when (symbolp cs) (setq cs (cons cs cs))) - (setq cs-decode (car cs)) - (setq cs-encode (cdr cs)) - (unless cs-decode (setq cs-decode 'undecided)) - (unless cs-encode (setq cs-encode 'undecided)) - (setq cs-encode (tramp-coding-system-change-eol-conversion - cs-encode 'unix)) - (when (search-forward "\r" nil t) - (setq cs-decode (tramp-coding-system-change-eol-conversion - cs-decode 'dos))) - (set-buffer-process-coding-system cs-decode cs-encode)) - ;; Look for ^M and do something useful if found. - (when (search-forward "\r" nil t) - ;; We have found a ^M but cannot frob the process coding system - ;; because we're running on a non-MULE Emacs. Let's try - ;; stty, instead. - (erase-buffer) - (tramp-message 9 "Trying `stty -onlcr'") - (tramp-send-command-internal multi-method method user host - "stty -onlcr")))) - (erase-buffer) - (tramp-message - 9 "Waiting 30s for `HISTFILE=$HOME/.tramp_history; HISTSIZE=1; export HISTFILE; export HISTSIZE'") - (tramp-send-command-internal - multi-method method user host - "HISTFILE=$HOME/.tramp_history; HISTSIZE=1; export HISTFILE; export HISTSIZE") - (erase-buffer) - (tramp-message 9 "Waiting 30s for `set +o vi +o emacs'") - (tramp-send-command-internal multi-method method user host - "set +o vi +o emacs") - (erase-buffer) - (tramp-message 9 "Waiting 30s for `unset MAIL MAILCHECK MAILPATH'") - (tramp-send-command-internal - multi-method method user host - "unset MAIL MAILCHECK MAILPATH 1>/dev/null 2>/dev/null") - (erase-buffer) - (tramp-message 9 "Waiting 30s for `unset CDPATH'") - (tramp-send-command-internal multi-method method user host - "unset CDPATH") - (erase-buffer) - (tramp-message 9 "Setting shell prompt") - ;; Douglas Gray Stephens says that we must - ;; use "\n" here, not tramp-rsh-end-of-line. We also manually frob - ;; the last time we sent a command, to avoid tramp-send-command to send - ;; "echo are you awake". - (setq tramp-last-cmd-time (current-time)) - (tramp-send-command - multi-method method user host - (format "PS1='%s%s%s'; PS2=''; PS3=''" - tramp-rsh-end-of-line - tramp-end-of-output - tramp-rsh-end-of-line)) - (tramp-wait-for-output)) - -(defun tramp-post-connection (multi-method method user host) - "Prepare a remote shell before being able to work on it. -METHOD, USER and HOST specify the connection. -Among other things, this finds a shell which groks tilde expansion, -tries to find an `ls' command which groks the `-n' option, sets the -locale to C and sets up the remote shell search path." + (with-connection-property proc "chunksize" + (cond + ((and (integerp tramp-chunksize) (> tramp-chunksize 0)) + tramp-chunksize) + (t + (tramp-message + vec 5 "Checking remote host type for `send-process-string' bug") + (if (string-match + "^FreeBSD" + (with-connection-property vec "uname" + (tramp-send-command-and-read vec "echo \\\"`uname -sr`\\\""))) + 500 0)))) + ;; Set remote PATH variable. + (tramp-set-remote-path vec) ;; Search for a good shell before searching for a command which ;; checks if a file exists. This is done because Tramp wants to use ;; "test foo; echo $?" to check if various conditions hold, and @@ -6247,168 +5543,23 @@ ;; the Solaris /bin/sh is a problem. I'm betting that all systems ;; with buggy /bin/sh implementations will have a working bash or ;; ksh. Whee... - (tramp-find-shell multi-method method user host) - ;; Without (sit-for 0.1) at least, my machine will almost always blow - ;; up on 'not numberp /root' - a race that causes the 'echo ~root' - ;; output of (tramp-find-shell) to show up along with the output of - ;; (tramp-find-ls-command) testing. - ;; - ;; I can't work out why this is a problem though. The (tramp-wait-for-output) - ;; call in (tramp-find-shell) *should* make this not happen, I thought. - ;; - ;; After much debugging I couldn't find any problem with the implementation - ;; of that function though. The workaround stays for me at least. :/ - ;; - ;; Daniel Pittman - (sleep-for 1) - (erase-buffer) - (tramp-find-file-exists-command multi-method method user host) - (make-local-variable 'tramp-ls-command) - (setq tramp-ls-command (tramp-find-ls-command multi-method method user host)) - (unless tramp-ls-command - (tramp-message - 1 - "Danger! Couldn't find ls which groks -n. Muddling through anyway") - (setq tramp-ls-command - (tramp-find-executable multi-method method user host - "ls" tramp-remote-path nil))) - (unless tramp-ls-command - (error "Fatal error: Couldn't find remote executable `ls'")) - (tramp-message 5 "Using remote command `%s' for getting directory listings" - tramp-ls-command) - (tramp-send-command multi-method method user host - (concat "tramp_set_exit_status () {" tramp-rsh-end-of-line - "return $1" tramp-rsh-end-of-line - "}")) - (tramp-wait-for-output) - ;; Set remote PATH variable. - (tramp-set-remote-path multi-method method user host "PATH" tramp-remote-path) - ;; Tell remote shell to use standard time format, needed for - ;; parsing `ls -l' output. - (tramp-send-command multi-method method user host - "LC_TIME=C; export LC_TIME; echo huhu") - (tramp-wait-for-output) - (tramp-send-command multi-method method user host - "mesg n; echo huhu") - (tramp-wait-for-output) - (tramp-send-command multi-method method user host - "biff n ; echo huhu") - (tramp-wait-for-output) - ;; Unalias ls(1) to work around issues with those silly people who make it - ;; spit out ANSI escapes or whatever. - (tramp-send-command multi-method method user host - "unalias ls; echo huhu") - (tramp-wait-for-output) - ;; Does `test A -nt B' work? Use abominable `find' construct if it - ;; doesn't. BSD/OS 4.0 wants the parentheses around the command, - ;; for otherwise the shell crashes. - (erase-buffer) - (make-local-variable 'tramp-test-groks-nt) - (tramp-send-command multi-method method user host - "( test / -nt / )") - (tramp-wait-for-output) - (goto-char (point-min)) - (setq tramp-test-groks-nt - (looking-at (format "\n%s\r?\n" (regexp-quote tramp-end-of-output)))) - (unless tramp-test-groks-nt - (tramp-send-command - multi-method method user host - (concat "tramp_test_nt () {" tramp-rsh-end-of-line - "test -n \"`find $1 -prune -newer $2 -print`\"" tramp-rsh-end-of-line - "}"))) - (tramp-wait-for-output) - ;; Send the fallback `uudecode' script. - (erase-buffer) - (tramp-send-string multi-method method user host tramp-uudecode) - (tramp-wait-for-output) - ;; Find a `perl'. - (erase-buffer) - (tramp-set-connection-property "perl-scripts" nil multi-method method user host) - (let ((tramp-remote-perl - (or (tramp-find-executable multi-method method user host - "perl5" tramp-remote-path nil) - (tramp-find-executable multi-method method user host - "perl" tramp-remote-path nil)))) - (when tramp-remote-perl - (tramp-set-connection-property "perl" tramp-remote-perl - multi-method method user host) - (unless (tramp-method-out-of-band-p multi-method method user host) - (tramp-message 5 "Sending the Perl `mime-encode' implementations.") - (tramp-send-string - multi-method method user host - (concat "tramp_encode () {\n" - (format tramp-perl-encode tramp-remote-perl) - " 2>/dev/null" - "\n}")) - (tramp-wait-for-output) - (tramp-send-string - multi-method method user host - (concat "tramp_encode_with_module () {\n" - (format tramp-perl-encode-with-module tramp-remote-perl) - " 2>/dev/null" - "\n}")) - (tramp-wait-for-output) - (tramp-message 5 "Sending the Perl `mime-decode' implementations.") - (tramp-send-string - multi-method method user host - (concat "tramp_decode () {\n" - (format tramp-perl-decode tramp-remote-perl) - " 2>/dev/null" - "\n}")) - (tramp-wait-for-output) - (tramp-send-string - multi-method method user host - (concat "tramp_decode_with_module () {\n" - (format tramp-perl-decode-with-module tramp-remote-perl) - " 2>/dev/null" - "\n}")) - (tramp-wait-for-output)))) - ;; Find ln(1) - (erase-buffer) - (let ((ln (tramp-find-executable multi-method method user host - "ln" tramp-remote-path nil))) - (when ln - (tramp-set-connection-property "ln" ln multi-method method user host))) - ;; Set uid and gid. - (erase-buffer) - (tramp-send-command multi-method method user host "id -u; id -g") - (tramp-wait-for-output) - (goto-char (point-min)) - (tramp-set-connection-property - "uid" (read (current-buffer)) multi-method method user host) - (tramp-set-connection-property - "gid" (read (current-buffer)) multi-method method user host) - ;; Find the right encoding/decoding commands to use. - (erase-buffer) - (unless (tramp-method-out-of-band-p multi-method method user host) - (tramp-find-inline-encoding multi-method method user host)) - ;; If encoding/decoding command are given, test to see if they work. - ;; CCC: Maybe it would be useful to run the encoder both locally and - ;; remotely to see if they produce the same result. - (let ((rem-enc (tramp-get-remote-encoding multi-method method user host)) - (rem-dec (tramp-get-remote-decoding multi-method method user host)) - (magic-string "xyzzy")) - (when (and (or rem-dec rem-enc) (not (and rem-dec rem-enc))) - (tramp-kill-process multi-method method user host) - ;; Improve error message and/or error check. - (error - "Must give both decoding and encoding command in method definition")) - (when (and rem-enc rem-dec) - (tramp-message - 5 - "Checking to see if encoding/decoding commands work on remote host...") + (tramp-find-shell vec) + ;; Disable unexpected output. + (tramp-send-command vec "mesg n; biff n") + ;; Set the environment. + (tramp-message vec 5 "Setting default environment") + (let ((env (copy-sequence tramp-remote-process-environment)) + unset item) + (while env + (setq item (split-string (car env) "=")) + (if (and (stringp (cadr item)) (not (string-equal (cadr item) ""))) + (tramp-send-command + vec (format "%s=%s; export %s" (car item) (cadr item) (car item))) + (push (car item) unset)) + (setq env (cdr env))) + (when unset (tramp-send-command - multi-method method user host - (format "echo %s | %s | %s" - (tramp-shell-quote-argument magic-string) rem-enc rem-dec)) - (tramp-wait-for-output) - (unless (looking-at (regexp-quote magic-string)) - (tramp-kill-process multi-method method user host) - (error "Remote host cannot execute de/encoding commands. See buffer `%s' for details" - (buffer-name))) - (erase-buffer) - (tramp-message - 5 "Checking to see if encoding/decoding commands work on remote host...done")))) + vec (format "unset %s" (mapconcat 'identity unset " ")))))) ;; CCC: We should either implement a Perl version of base64 encoding ;; and decoding. Then we just use that in the last item. The other @@ -6428,38 +5579,22 @@ ;; ;; For Irix, no solution is known yet. -(defvar tramp-coding-commands - '(("mimencode -b" "mimencode -u -b" - base64-encode-region base64-decode-region) - ("mmencode -b" "mmencode -u -b" - base64-encode-region base64-decode-region) - ("recode data..base64" "recode base64..data" - base64-encode-region base64-decode-region) - ("uuencode xxx" "uudecode -o /dev/stdout" - tramp-uuencode-region uudecode-decode-region) - ("uuencode xxx" "uudecode -o -" - tramp-uuencode-region uudecode-decode-region) - ("uuencode xxx" "uudecode -p" - tramp-uuencode-region uudecode-decode-region) - ("uuencode xxx" "tramp_uudecode" - tramp-uuencode-region uudecode-decode-region) - ("tramp_encode_with_module" "tramp_decode_with_module" - base64-encode-region base64-decode-region) - ("tramp_encode" "tramp_decode" - base64-encode-region base64-decode-region)) - "List of coding commands for inline transfer. +(defconst tramp-local-coding-commands + '((b64 base64-encode-region base64-decode-region) + (uu tramp-uuencode-region uudecode-decode-region) + (pack + "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'" + "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'")) + "List of local coding commands for inline transfer. Each item is a list that looks like this: -\(REMOTE-ENCODING REMOTE-DECODING LOCAL-ENCODING LOCAL-DECODING) - -The REMOTE-ENCODING should be a string, giving a command accepting a -plain file on standard input and writing the encoded file to standard -output. The REMOTE-DECODING should also be a string, giving a command -accepting an encoded file on standard input and writing the decoded -file to standard output. - -LOCAL-ENCODING and LOCAL-DECODING can be strings, giving commands, or -symbols, giving functions. If they are strings, then they can contain +\(FORMAT ENCODING DECODING) + +FORMAT is symbol describing the encoding/decoding format. It can be +`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing. + +ENCODING and DECODING can be strings, giving commands, or symbols, +giving functions. If they are strings, then they can contain the \"%s\" format specifier. If that specifier is present, the input filename will be put into the command line at that spot. If the specifier is not present, the input should be read from standard @@ -6469,83 +5604,139 @@ and end of region, and are expected to replace the region contents with the encoded or decoded results, respectively.") -(defun tramp-find-inline-encoding (multi-method method user host) +(defconst tramp-remote-coding-commands + '((b64 "mimencode -b" "mimencode -u -b") + (b64 "mmencode -b" "mmencode -u -b") + (b64 "recode data..base64" "recode base64..data") + (b64 tramp-perl-encode-with-module tramp-perl-decode-with-module) + (b64 tramp-perl-encode tramp-perl-decode) + (uu "uuencode xxx" "uudecode -o /dev/stdout") + (uu "uuencode xxx" "uudecode -o -") + (uu "uuencode xxx" "uudecode -p") + (uu "uuencode xxx" tramp-uudecode) + (pack + "perl -e 'binmode STDIN; binmode STDOUT; print pack(q{u*}, join q{}, <>)'" + "perl -e 'binmode STDIN; binmode STDOUT; print unpack(q{u*}, join q{}, <>)'")) + "List of remote coding commands for inline transfer. +Each item is a list that looks like this: + +\(FORMAT ENCODING DECODING) + +FORMAT is symbol describing the encoding/decoding format. It can be +`b64' for base64 encoding, `uu' for uu encoding, or `pack' for simple packing. + +ENCODING and DECODING can be strings, giving commands, or symbols, +giving variables. If they are strings, then they can contain +the \"%s\" format specifier. If that specifier is present, the input +filename will be put into the command line at that spot. If the +specifier is not present, the input should be read from standard +input. + +If they are variables, this variable is a string containing a Perl +implementation for this functionality. This Perl program will be transferred +to the remote host, and it is avalible as shell function with the same name.") + +(defun tramp-find-inline-encoding (vec) "Find an inline transfer encoding that works. -Goes through the list `tramp-coding-commands'." - (let ((commands tramp-coding-commands) - (magic "xyzzy") - item found) - (while (and commands (null found)) - (setq item (pop commands)) - (catch 'wont-work - (let ((rem-enc (nth 0 item)) - (rem-dec (nth 1 item)) - (loc-enc (nth 2 item)) - (loc-dec (nth 3 item))) - ;; Check if remote encoding and decoding commands can be - ;; called remotely with null input and output. This makes - ;; sure there are no syntax errors and the command is really - ;; found. Note that we do not redirect stdout to /dev/null, - ;; for two reaons: when checking the decoding command, we - ;; actually check the output it gives. And also, when - ;; redirecting "mimencode" output to /dev/null, then as root - ;; it might change the permissions of /dev/null! - (tramp-message-for-buffer - multi-method method user host 9 - "Checking remote encoding command `%s' for sanity" rem-enc) - (unless (zerop (tramp-send-command-and-check - multi-method method user host - (format "%s " output) "")))) - -(defun tramp-maybe-open-connection (multi-method method user host) - "Maybe open a connection to HOST, logging in as USER, using METHOD. + (let ((default-directory (tramp-temporary-file-directory))) + (call-process + tramp-encoding-shell ;program + (when (and input (not (string-match "%s" cmd))) + input) ;input + (if (eq output t) t nil) ;output + nil ;redisplay + tramp-encoding-command-switch + ;; actual shell command + (concat + (if (string-match "%s" cmd) (format cmd input) cmd) + (if (stringp output) (concat "> " output) ""))))) + +(defun tramp-compute-multi-hops (vec) + "Expands VEC according to `tramp-default-proxies-alist'. +Gateway hops are already opened." + (let ((target-alist `(,vec)) + (choices tramp-default-proxies-alist) + item proxy) + + ;; Look for proxy hosts to be passed. + (while choices + (setq item (pop choices) + proxy (nth 2 item)) + (when (and + ;; host + (string-match (or (nth 0 item) "") + (or (tramp-file-name-host (car target-alist)) "")) + ;; user + (string-match (or (nth 1 item) "") + (or (tramp-file-name-user (car target-alist)) ""))) + (if (null proxy) + ;; No more hops needed. + (setq choices nil) + ;; Replace placeholders. + (setq proxy + (format-spec + proxy + `((?u . ,(or (tramp-file-name-user (car target-alist)) "")) + (?h . ,(or (tramp-file-name-host (car target-alist)) ""))))) + (with-parsed-tramp-file-name proxy l + ;; Add the hop. + (add-to-list 'target-alist l) + ;; Start next search. + (setq choices tramp-default-proxies-alist))))) + + ;; Handle gateways. + (when (string-match (format + "^\\(%s\\|%s\\)$" + tramp-gw-tunnel-method tramp-gw-socks-method) + (tramp-file-name-method (car target-alist))) + (let ((gw (pop target-alist)) + (hop (pop target-alist))) + ;; Is the method prepared for gateways? + (unless (tramp-get-method-parameter + (tramp-file-name-method hop) 'tramp-default-port) + (tramp-error + vec 'file-error + "Method `%s' is not supported for gateway access." + (tramp-file-name-method hop))) + ;; Add default port if needed. + (unless + (string-match + tramp-host-with-port-regexp (tramp-file-name-host hop)) + (aset hop 2 + (concat + (tramp-file-name-host hop) tramp-prefix-port-format + (number-to-string + (tramp-get-method-parameter + (tramp-file-name-method hop) 'tramp-default-port))))) + ;; Open the gateway connection. + (add-to-list + 'target-alist + (vector + (tramp-file-name-method hop) (tramp-file-name-user hop) + (tramp-gw-open-connection vec gw hop) nil)) + ;; For the password prompt, we need the correct values. + ;; Therefore, we must remember the gateway vector. But we + ;; cannot do it as connection property, because it shouldn't + ;; be persistent. And we have no started process yet either. + (tramp-set-file-property (car target-alist) "" "gateway" hop))) + + ;; Foreign and out-of-band methods are not supported for multi-hops. + (when (cdr target-alist) + (setq choices target-alist) + (while choices + (setq item (pop choices)) + (when + (or + (not + (tramp-get-method-parameter + (tramp-file-name-method item) 'tramp-login-program)) + (tramp-get-method-parameter + (tramp-file-name-method item) 'tramp-copy-program)) + (tramp-error + vec 'file-error + "Method `%s' is not supported for multi-hops." + (tramp-file-name-method item))))) + + ;; Result. + target-alist)) + +(defun tramp-maybe-open-connection (vec) + "Maybe open a connection VEC. Does not do anything if a connection is already open, but re-opens the connection if a previous connection has died for some reason." - (let ((p (get-buffer-process - (tramp-get-buffer multi-method method user host))) - last-cmd-time) + (let ((p (tramp-get-connection-process vec))) + ;; If too much time has passed since last command was sent, look ;; whether process is still alive. If it isn't, kill it. When ;; using ssh, it can sometimes happen that the remote end has hung @@ -6581,239 +5861,276 @@ ;; tries to send some data to the remote end. So that's why we ;; try to send a command from time to time, then look again ;; whether the process is really alive. - (save-excursion - (set-buffer (tramp-get-buffer multi-method method user host)) - (when (and tramp-last-cmd-time - (> (tramp-time-diff (current-time) tramp-last-cmd-time) 60) - p (processp p) (memq (process-status p) '(run open))) - (tramp-send-command - multi-method method user host "echo are you awake" nil t) - (unless (and (memq (process-status p) '(run open)) - (tramp-wait-for-output 10)) - (delete-process p) - (setq p nil)) - (erase-buffer))) + (when (and (> (tramp-time-diff + (current-time) + (tramp-get-connection-property p "last-cmd-time" '(0 0 0))) + 60) + p (processp p) (memq (process-status p) '(run open))) + (tramp-send-command vec "echo are you awake" t t) + (unless (and (memq (process-status p) '(run open)) + (tramp-wait-for-output p 10)) + (delete-process p) + (setq p nil))) + + ;; New connection must be opened. (unless (and p (processp p) (memq (process-status p) '(run open))) + + ;; We call `tramp-get-buffer' in order to get a debug buffer for + ;; messages from the beginning. + (tramp-get-buffer vec) + (if (zerop (length (tramp-file-name-user vec))) + (tramp-message + vec 3 "Opening connection for %s using %s..." + (tramp-file-name-host vec) + (tramp-file-name-method vec)) + (tramp-message + vec 3 "Opening connection for %s@%s using %s..." + (tramp-file-name-user vec) + (tramp-file-name-host vec) + (tramp-file-name-method vec))) + + ;; Start new process. (when (and p (processp p)) - (delete-process p)) - (let ((process-connection-type tramp-process-connection-type)) - (funcall (tramp-get-method-parameter - multi-method - (tramp-find-method multi-method method user host) - user host 'tramp-connection-function) - multi-method method user host))))) - -(defun tramp-send-command - (multi-method method user host command &optional noerase neveropen) - "Send the COMMAND to USER at HOST (logged in using METHOD). -Erases temporary buffer before sending the command (unless NOERASE -is true). -If optional seventh arg NEVEROPEN is non-nil, never try to open the -connection. This is meant to be used from -`tramp-maybe-open-connection' only." - (or neveropen - (tramp-maybe-open-connection multi-method method user host)) - (setq tramp-last-cmd-time (current-time)) - (setq tramp-last-cmd command) - (when tramp-debug-buffer - (save-excursion - (set-buffer (tramp-get-debug-buffer multi-method method user host)) - (goto-char (point-max)) - (tramp-insert-with-face 'bold (format "$ %s\n" command)))) - (let ((proc nil)) - (set-buffer (tramp-get-buffer multi-method method user host)) - (unless noerase (erase-buffer)) - (setq proc (get-buffer-process (current-buffer))) - (process-send-string proc - (concat command tramp-rsh-end-of-line)))) - -(defun tramp-send-command-internal - (multi-method method user host command &optional msg) + (delete-process p)) + (setenv "TERM" tramp-terminal-type) + (setenv "PS1" "$ ") + (let* ((target-alist (tramp-compute-multi-hops vec)) + (process-environment (copy-sequence process-environment)) + (process-connection-type tramp-process-connection-type) + (coding-system-for-read nil) + ;; This must be done in order to avoid our file name handler. + (p (let ((default-directory (tramp-temporary-file-directory))) + (start-process + (or (tramp-get-connection-property vec "process-name" nil) + (tramp-buffer-name vec)) + (tramp-get-connection-buffer vec) + tramp-encoding-shell))) + (first-hop t)) + + (tramp-message + vec 6 "%s" (mapconcat 'identity (process-command p) " ")) + + ;; Check whether process is alive. + (set-process-sentinel p 'tramp-flush-connection-property) + (tramp-set-process-query-on-exit-flag p nil) + (tramp-message vec 3 "Waiting 60s for local shell to come up...") + (tramp-barf-if-no-shell-prompt + p 60 "Couldn't find local shell prompt %s" tramp-encoding-shell) + + ;; Now do all the connections as specified. + (while target-alist + (let* ((hop (car target-alist)) + (l-method (tramp-file-name-method hop)) + (l-user (tramp-file-name-user hop)) + (l-host (tramp-file-name-host hop)) + (l-port nil) + (login-program + (tramp-get-method-parameter l-method 'tramp-login-program)) + (login-args + (tramp-get-method-parameter l-method 'tramp-login-args)) + (gw-args + (tramp-get-method-parameter l-method 'tramp-gw-args)) + (gw (tramp-get-file-property hop "" "gateway" nil)) + (g-method (and gw (tramp-file-name-method gw))) + (g-user (and gw (tramp-file-name-user gw))) + (g-host (and gw (tramp-file-name-host gw))) + (command login-program) + spec) + + ;; Add gateway arguments if necessary. + (when (and gw gw-args) + (setq login-args (append login-args gw-args))) + + ;; Check for port number. Until now, there's no need for handling + ;; like method, user, host. + (when (string-match tramp-host-with-port-regexp l-host) + (setq l-port (match-string 2 l-host) + l-host (match-string 1 l-host))) + + ;; Set variables for computing the prompt for reading password. + ;; They can also be derived from a gatewy. + (setq tramp-current-method (or g-method l-method) + tramp-current-user (or g-user l-user) + tramp-current-host (or g-host l-host)) + + ;; Replace login-args place holders. + (setq + l-host (or l-host "") + l-user (or l-user "") + l-port (or l-port "") + spec `((?h . ,l-host) (?u . ,l-user) (?p . ,l-port) + (?t . ,(tramp-make-tramp-temp-file vec))) + command + (concat + command " " + (mapconcat + '(lambda (x) + (setq x (mapcar '(lambda (y) (format-spec y spec)) x)) + (unless (member "" x) (mapconcat 'identity x " "))) + login-args " ") + ;; String to detect failed connection. Every single word must + ;; be enclosed with '\"'; otherwise it is detected + ;; during connection setup. + ;; Local shell could be a Windows COMSPEC. It doesn't know + ;; the ";" syntax, but we must exit always for `start-process'. + ;; "exec" does not work either. + (if first-hop + " && exit || exit" + "; echo \"Tramp\" \"connection\" \"closed\"; sleep 1")) + ;; We don't reach a Windows shell. Could be initial only. + first-hop nil) + + ;; Send the command. + (tramp-message vec 3 "Sending command `%s'" command) + (tramp-send-command vec command t t) + (tramp-process-actions p vec tramp-actions-before-shell 60) + (tramp-message vec 3 "Found remote shell prompt on `%s'" l-host)) + ;; Next hop. + (setq target-alist (cdr target-alist))) + + ;; Make initial shell settings. + (tramp-open-connection-setup-interactive-shell p vec))))) + +(defun tramp-send-command (vec command &optional neveropen nooutput) + "Send the COMMAND to connection VEC. +Erases temporary buffer before sending the command. If optional +arg NEVEROPEN is non-nil, never try to open the connection. This +is meant to be used from `tramp-maybe-open-connection' only. The +function waits for output unless NOOUTPUT is set." + (unless neveropen (tramp-maybe-open-connection vec)) + (let ((p (tramp-get-connection-process vec))) + (when (tramp-get-connection-property vec "remote-echo" nil) + ;; We mark the command string that it can be erased in the output buffer. + (tramp-set-connection-property p "check-remote-echo" t) + (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark))) + (tramp-message vec 6 "%s" command) + (tramp-send-string vec command) + (unless nooutput (tramp-wait-for-output p)))) + +(defun tramp-send-command-internal (vec command) "Send command to remote host and wait for success. Sends COMMAND, then waits 30 seconds for shell prompt." - (tramp-send-command multi-method method user host command t t) - (when msg - (tramp-message 9 "Waiting 30s for %s..." msg)) - (tramp-barf-if-no-shell-prompt - nil 30 - "Couldn't `%s', see buffer `%s'" command (buffer-name))) - -(defun tramp-wait-for-output (&optional timeout) + (let ((p (tramp-get-connection-process vec))) + (when (tramp-get-connection-property vec "remote-echo" nil) + ;; We mark the command string that it can be erased in the output buffer. + (tramp-set-connection-property p "check-remote-echo" t) + (setq command (format "%s%s%s" tramp-echo-mark command tramp-echo-mark))) + (tramp-message vec 6 "%s" command) + (tramp-send-string vec command) + (tramp-barf-if-no-shell-prompt + p 30 "Couldn't `%s', see buffer `%s'" command (buffer-name)))) + +(defun tramp-wait-for-output (proc &optional timeout) "Wait for output from remote rsh command." - (let ((proc (get-buffer-process (current-buffer))) - (found nil) - (start-time (current-time)) - (start-point (point)) - (end-of-output (concat "^" - (regexp-quote tramp-end-of-output) - "\r?$"))) - ;; Algorithm: get waiting output. See if last line contains - ;; end-of-output sentinel. If not, wait a bit and again get - ;; waiting output. Repeat until timeout expires or end-of-output - ;; sentinel is seen. Will hang if timeout is nil and - ;; end-of-output sentinel never appears. - (save-match-data - (cond (timeout - ;; Work around an XEmacs bug, where the timeout expires - ;; faster than it should. This degenerates into polling - ;; for buggy XEmacsen, but oh, well. - (while (and (not found) - (< (tramp-time-diff (current-time) start-time) - timeout)) - (with-timeout (timeout) - (while (not found) - (tramp-accept-process-output proc 1) - (unless (memq (process-status proc) '(run open)) - (error "Process has died")) - (goto-char (point-max)) - (forward-line -1) - (setq found (looking-at end-of-output)))))) - (t - (while (not found) - (tramp-accept-process-output proc 1) - (unless (memq (process-status proc) '(run open)) - (error "Process has died")) - (goto-char (point-max)) - (forward-line -1) - (setq found (looking-at end-of-output)))))) - ;; At this point, either the timeout has expired or we have found - ;; the end-of-output sentinel. - (when found - (goto-char (point-max)) - (forward-line -2) - (delete-region (point) (point-max))) - ;; If processing echoes, look for it in the first line and delete. - (when tramp-process-echoes - (save-excursion - (goto-char start-point) - (when (looking-at (regexp-quote tramp-last-cmd)) - (delete-region (point) (progn (forward-line 1) (point)))))) - ;; Add output to debug buffer if appropriate. - (when tramp-debug-buffer - (append-to-buffer - (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method - tramp-current-user tramp-current-host) - (point-min) (point-max)) - (when (not found) - (save-excursion - (set-buffer - (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method - tramp-current-user tramp-current-host)) - (goto-char (point-max)) - (insert "[[Remote prompt `" end-of-output "' not found" - (if timeout (format " in %d secs" timeout) "") - "]]")))) - (goto-char (point-min)) - ;; Return value is whether end-of-output sentinel was found. - found)) - -(defun tramp-send-command-and-check (multi-method method user host command - &optional subshell) + (with-current-buffer (process-buffer proc) + (let ((found + (tramp-wait-for-regexp + proc timeout + (format "^%s\r?$" (regexp-quote tramp-end-of-output))))) + (if found + (let (buffer-read-only) + (goto-char (point-max)) + (forward-line -2) + (delete-region (point) (point-max))) + (if timeout + (tramp-error + proc 'file-error + "[[Remote prompt `%s' not found in %d secs]]" + tramp-end-of-output timeout) + (tramp-error + proc 'file-error + "[[Remote prompt `%s' not found]]" tramp-end-of-output))) + ;; Return value is whether end-of-output sentinel was found. + found))) + +(defun tramp-send-command-and-check (vec command &optional subshell) "Run COMMAND and check its exit status. -MULTI-METHOD and METHOD specify how to log in (as USER) to the remote HOST. Sends `echo $?' along with the COMMAND for checking the exit status. If COMMAND is nil, just sends `echo $?'. Returns the exit status found. If the optional argument SUBSHELL is non-nil, the command is executed in a subshell, ie surrounded by parentheses." - (tramp-send-command multi-method method user host - (concat (if subshell "( " "") - command - (if command " 2>/dev/null; " "") - "echo tramp_exit_status $?" - (if subshell " )" " "))) - (tramp-wait-for-output) - (goto-char (point-max)) - (unless (search-backward "tramp_exit_status " nil t) - (error "Couldn't find exit status of `%s'" command)) - (skip-chars-forward "^ ") - (read (current-buffer))) - -(defun tramp-barf-unless-okay (multi-method method user host command subshell - signal fmt &rest args) + (tramp-send-command + vec + (concat (if subshell "( " "") + command + (if command " 2>/dev/null; " "") + "echo tramp_exit_status $?" + (if subshell " )" " "))) + (with-current-buffer (tramp-get-connection-buffer vec) + (goto-char (point-max)) + (unless (re-search-backward "tramp_exit_status [0-9]+" nil t) + (tramp-error + vec 'file-error "Couldn't find exit status of `%s'" command)) + (skip-chars-forward "^ ") + (prog1 + (read (current-buffer)) + (let (buffer-read-only) (delete-region (match-beginning 0) (point-max)))))) + +(defun tramp-barf-unless-okay (vec command fmt &rest args) "Run COMMAND, check exit status, throw error if exit status not okay. Similar to `tramp-send-command-and-check' but accepts two more arguments FMT and ARGS which are passed to `error'." - (unless (zerop (tramp-send-command-and-check - multi-method method user host command subshell)) - ;; CCC: really pop-to-buffer? Maybe it's appropriate to be more - ;; silent. - (pop-to-buffer (current-buffer)) - (funcall 'signal signal (apply 'format fmt args)))) + (unless (zerop (tramp-send-command-and-check vec command)) + (apply 'tramp-error vec 'file-error fmt args))) + +(defun tramp-send-command-and-read (vec command) + "Run COMMAND and return the output, which must be a Lisp expression. +In case there is no valid Lisp expression, it raises an error" + (tramp-barf-unless-okay vec command "`%s' returns with error" command) + (with-current-buffer (tramp-get-connection-buffer vec) + ;; Read the expression. + (goto-char (point-min)) + (condition-case nil + (prog1 (read (current-buffer)) + ;; Error handling. + (when (re-search-forward "\\S-" nil t) (error))) + (error (tramp-error + vec 'file-error + "`%s' does not return a valid Lisp expression: `%s'" + command (buffer-string)))))) ;; It seems that Tru64 Unix does not like it if long strings are sent ;; to it in one go. (This happens when sending the Perl ;; `file-attributes' implementation, for instance.) Therefore, we ;; have this function which waits a bit at each line. -(defun tramp-send-string - (multi-method method user host string) - "Send the STRING to USER at HOST using METHOD. +(defun tramp-send-string (vec string) + "Send the STRING via connection VEC. The STRING is expected to use Unix line-endings, but the lines sent to the remote host use line-endings as defined in the variable -`tramp-rsh-end-of-line'." - (let ((proc (get-buffer-process - (tramp-get-buffer multi-method method user host)))) - (unless proc - (error "Can't send string to remote host -- not logged in")) - ;; debug message - (when tramp-debug-buffer - (save-excursion - (set-buffer (tramp-get-debug-buffer multi-method method user host)) - (goto-char (point-max)) - (tramp-insert-with-face 'bold (format "$ %s\n" string)))) - ;; replace "\n" by `tramp-rsh-end-of-line' - (setq string - (mapconcat 'identity - (split-string string "\n") - tramp-rsh-end-of-line)) - (unless (or (string= string "") - (string-equal (substring string -1) tramp-rsh-end-of-line)) - (setq string (concat string tramp-rsh-end-of-line))) - ;; send the string - (if (and tramp-chunksize (not (zerop tramp-chunksize))) - (let ((pos 0) - (end (length string))) - (while (< pos end) - (tramp-message-for-buffer - multi-method method user host 10 - "Sending chunk from %s to %s" - pos (min (+ pos tramp-chunksize) end)) - (process-send-string - proc (substring string pos (min (+ pos tramp-chunksize) end))) - (setq pos (+ pos tramp-chunksize)) - (sleep-for 0.1))) - (process-send-string proc string)))) - -(defun tramp-send-eof (multi-method method user host) - "Send EOF to the remote end. -METHOD, HOST and USER specify the connection." - (let ((proc (get-buffer-process - (tramp-get-buffer multi-method method user host)))) - (unless proc - (error "Can't send EOF to remote host -- not logged in")) - (process-send-eof proc))) -; (process-send-string proc "\^D"))) - -(defun tramp-kill-process (multi-method method user host) - "Kill the connection process used by Tramp. -MULTI-METHOD, METHOD, USER, and HOST specify the connection." - (let ((proc (get-buffer-process - (tramp-get-buffer multi-method method user host)))) - (kill-process proc))) - -(defun tramp-discard-garbage-erase-buffer (p multi-method method user host) - "Erase buffer, then discard subsequent garbage. -If `tramp-discard-garbage' is nil, just erase buffer." - (if (not tramp-discard-garbage) - (erase-buffer) - (while (prog1 (erase-buffer) (tramp-accept-process-output p 0.25)) - (when tramp-debug-buffer - (save-excursion - (set-buffer (tramp-get-debug-buffer multi-method method user host)) - (goto-char (point-max)) - (tramp-insert-with-face - 'bold (format "Additional characters detected\n"))))))) +`tramp-rsh-end-of-line'. The communication buffer is erased before sending." + (let* ((p (tramp-get-connection-process vec)) + (chunksize (tramp-get-connection-property p "chunksize" nil))) + (unless p + (tramp-error + vec 'file-error "Can't send string to remote host -- not logged in")) + (tramp-set-connection-property p "last-cmd-time" (current-time)) + (tramp-message vec 10 "%s" string) + (with-current-buffer (tramp-get-connection-buffer vec) + ;; Clean up the buffer. We cannot call `erase-buffer' because + ;; narrowing might be in effect. + (let (buffer-read-only) (delete-region (point-min) (point-max))) + ;; replace "\n" by `tramp-rsh-end-of-line' + (setq string + (mapconcat 'identity + (split-string string "\n") + tramp-rsh-end-of-line)) + (unless (or (string= string "") + (string-equal (substring string -1) tramp-rsh-end-of-line)) + (setq string (concat string tramp-rsh-end-of-line))) + ;; send the string + (if (and chunksize (not (zerop chunksize))) + (let ((pos 0) + (end (length string))) + (while (< pos end) + (tramp-message + vec 10 "Sending chunk from %s to %s" + pos (min (+ pos chunksize) end)) + (process-send-string + p (substring string pos (min (+ pos chunksize) end))) + (setq pos (+ pos chunksize)))) + (process-send-string p string))))) (defun tramp-mode-string-to-int (mode-string) "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits." @@ -6886,27 +6203,70 @@ (t (error "Tenth char `%c' must be one of `xtT-'" other-execute-or-sticky))))))) -(defun tramp-convert-file-attributes (multi-method method user host attr) - "Convert file-attributes ATTR generated by perl script or ls. +(defun tramp-convert-file-attributes (vec attr) + "Convert file-attributes ATTR generated by perl script, stat or ls. Convert file mode bits to string and set virtual device number. Return ATTR." + ;; Convert last access time. + (unless (listp (nth 4 attr)) + (setcar (nthcdr 4 attr) + (list (floor (nth 4 attr) 65536) + (floor (mod (nth 4 attr) 65536))))) + ;; Convert last modification time. + (unless (listp (nth 5 attr)) + (setcar (nthcdr 5 attr) + (list (floor (nth 5 attr) 65536) + (floor (mod (nth 5 attr) 65536))))) + ;; Convert last status change time. + (unless (listp (nth 6 attr)) + (setcar (nthcdr 6 attr) + (list (floor (nth 6 attr) 65536) + (floor (mod (nth 6 attr) 65536))))) ;; Convert file mode bits to string. (unless (stringp (nth 8 attr)) (setcar (nthcdr 8 attr) (tramp-file-mode-from-int (nth 8 attr)))) - ;; Set file's gid change bit. Possible only when id-format is 'integer. - (when (numberp (nth 3 attr)) - (setcar (nthcdr 9 attr) - (not (eql (nth 3 attr) - (tramp-get-remote-gid multi-method method user host))))) + ;; Convert directory indication bit. + (if (string-match "^d" (nth 8 attr)) + (setcar attr t) + (if (and (listp (car attr)) (stringp (caar attr)) + (string-match ".+ -> .\\(.+\\)." (caar attr))) + (setcar attr (match-string 1 (caar attr))) + (setcar attr nil))) + ;; Set file's gid change bit. + (setcar (nthcdr 9 attr) + (if (numberp (nth 3 attr)) + (not (= (nth 3 attr) + (tramp-get-remote-gid vec 'integer))) + (not (string-equal + (nth 3 attr) + (tramp-get-remote-gid vec 'string))))) + ;; Convert inode. + (unless (listp (nth 10 attr)) + (setcar (nthcdr 10 attr) + (list (floor (nth 10 attr) 65536) + (floor (mod (nth 10 attr) 65536))))) ;; Set virtual device number. (setcar (nthcdr 11 attr) - (tramp-get-device multi-method method user host)) + (tramp-get-device vec)) attr) -(defun tramp-get-device (multi-method method user host) +(defun tramp-get-inode (file) + "Returns the virtual inode number. +If it doesn't exist, generate a new one." + (let ((string (directory-file-name file))) + (unless (assoc string tramp-inodes) + (add-to-list 'tramp-inodes + (list string (length tramp-inodes)))) + (nth 1 (assoc string tramp-inodes)))) + +(defun tramp-get-device (vec) "Returns the virtual device number. If it doesn't exist, generate a new one." - (let ((string (tramp-make-tramp-file-name multi-method method user host ""))) + (let ((string (tramp-make-tramp-file-name + (tramp-file-name-method vec) + (tramp-file-name-user vec) + (tramp-file-name-host vec) + ""))) (unless (assoc string tramp-devices) (add-to-list 'tramp-devices (list string (length tramp-devices)))) @@ -6926,7 +6286,6 @@ (setq other (tramp-file-mode-permissions other sticky "t")) (concat type user group other))) - (defun tramp-file-mode-permissions (perm suid suid-text) "Convert a permission bitset into a string. This is used internally by `tramp-file-mode-from-int'." @@ -6939,7 +6298,6 @@ (and suid (upcase suid-text)) ; suid, !execute (and x "x") "-")))) ; !suid - (defun tramp-decimal-to-octal (i) "Return a string consisting of the octal digits of I. Not actually used. Use `(format \"%o\" i)' instead?" @@ -6950,16 +6308,6 @@ (number-to-string (% i 8)))))) -;;(defun tramp-octal-to-decimal (ostr) -;; "Given a string of octal digits, return a decimal number." -;; (cond ((null ostr) 0) -;; ((string= "" ostr) 0) -;; (t (let ((last (aref ostr (1- (length ostr)))) -;; (rest (substring ostr 0 (1- (length ostr))))) -;; (unless (and (>= last ?0) -;; (<= last ?7)) -;; (error "Not an octal digit: %c" last)) -;; (+ (- last ?0) (* 8 (tramp-octal-to-decimal rest))))))) ;; Kudos to Gerd Moellmann for this suggestion. (defun tramp-octal-to-decimal (ostr) "Given a string of octal digits, return a decimal number." @@ -6987,289 +6335,368 @@ ;; internal data structure. Convenience functions for internal ;; data structure. -(defun tramp-file-name-p (obj) - "Check whether TRAMP-FILE-NAME is a Tramp object." - (and (vectorp obj) (= 5 (length obj)))) - -(defun tramp-file-name-multi-method (obj) - "Return MULTI-METHOD component of TRAMP-FILE-NAME." - (and (tramp-file-name-p obj) (aref obj 0))) - -(defun tramp-file-name-method (obj) - "Return METHOD component of TRAMP-FILE-NAME." - (and (tramp-file-name-p obj) (aref obj 1))) - -(defun tramp-file-name-user (obj) - "Return USER component of TRAMP-FILE-NAME." - (and (tramp-file-name-p obj) (aref obj 2))) - -(defun tramp-file-name-host (obj) - "Return HOST component of TRAMP-FILE-NAME." - (and (tramp-file-name-p obj) (aref obj 3))) - -(defun tramp-file-name-localname (obj) - "Return LOCALNAME component of TRAMP-FILE-NAME." - (and (tramp-file-name-p obj) (aref obj 4))) +(defun tramp-file-name-p (vec) + "Check whether VEC is a Tramp object." + (and (vectorp vec) (= 4 (length vec)))) + +(defun tramp-file-name-method (vec) + "Return method component of VEC." + (and (tramp-file-name-p vec) (aref vec 0))) + +(defun tramp-file-name-user (vec) + "Return user component of VEC." + (and (tramp-file-name-p vec) (aref vec 1))) + +(defun tramp-file-name-host (vec) + "Return host component of VEC." + (and (tramp-file-name-p vec) (aref vec 2))) + +(defun tramp-file-name-localname (vec) + "Return localname component of VEC." + (and (tramp-file-name-p vec) (aref vec 3))) + +;; The host part of a Tramp file name vector can be of kind +;; "host#port". Sometimes, we must extract these parts. +(defsubst tramp-file-name-real-host (vec) + "Return the host name of VEC without port." + (let ((host (tramp-file-name-host vec))) + (if (and (stringp host) + (string-match tramp-host-with-port-regexp host)) + (match-string 1 host) + host))) + +(defsubst tramp-file-name-port (vec) + "Return the port number of VEC." + (let ((host (tramp-file-name-host vec))) + (and (stringp host) + (string-match tramp-host-with-port-regexp host) + (string-to-number (match-string 2 host))))) (defun tramp-tramp-file-p (name) "Return t iff NAME is a tramp file." (save-match-data (string-match tramp-file-name-regexp name))) -;; HHH: Changed. Used to assign the return value of (user-login-name) -;; to the `user' part of the structure if a user name was not -;; provided, now it assigns nil. +(defsubst tramp-find-method (method user host) + "Return the right method string to use. +This is METHOD, if non-nil. Otherwise, do a lookup in +`tramp-default-method-alist'." + (or method + (let ((choices tramp-default-method-alist) + lmethod item) + (while choices + (setq item (pop choices)) + (when (and (string-match (or (nth 0 item) "") (or host "")) + (string-match (or (nth 1 item) "") (or user ""))) + (setq lmethod (nth 2 item)) + (setq choices nil))) + lmethod) + tramp-default-method)) + +(defsubst tramp-find-user (method user host) + "Return the right user string to use. +This is USER, if non-nil. Otherwise, do a lookup in +`tramp-default-user-alist'." + (or user + (let ((choices tramp-default-user-alist) + luser item) + (while choices + (setq item (pop choices)) + (when (and (string-match (or (nth 0 item) "") (or method "")) + (string-match (or (nth 1 item) "") (or host ""))) + (setq luser (nth 2 item)) + (setq choices nil))) + luser) + tramp-default-user)) + +(defsubst tramp-find-host (method user host) + "Return the right host string to use. +This is HOST, if non-nil. Otherwise, it is `tramp-default-host'." + (or (and (> (length host) 0) host) + tramp-default-host)) + (defun tramp-dissect-file-name (name) - "Return an `tramp-file-name' structure. + "Return a `tramp-file-name' structure. The structure consists of remote method, remote user, remote host and localname (file name on remote host)." (save-match-data - (let* ((match (string-match (nth 0 tramp-file-name-structure) name)) - (method - ; single-hop - (if match (match-string (nth 1 tramp-file-name-structure) name) - ; maybe multi-hop - (string-match - (format (nth 0 tramp-multi-file-name-structure) - (nth 0 tramp-multi-file-name-hop-structure)) name) - (match-string (nth 1 tramp-multi-file-name-structure) name)))) - (if (and method (member method tramp-multi-methods)) - ;; If it's a multi method, the file name structure contains - ;; arrays of method, user and host. - (tramp-dissect-multi-file-name name) - ;; Normal method. First, find out default method. - (unless match (error "Not a tramp file name: %s" name)) - (let ((user (match-string (nth 2 tramp-file-name-structure) name)) - (host (match-string (nth 3 tramp-file-name-structure) name)) - (localname (match-string (nth 4 tramp-file-name-structure) name))) - (vector nil method (or user nil) host localname)))))) - -(defun tramp-find-default-method (user host) - "Look up the right method to use in `tramp-default-method-alist'." - (let ((choices tramp-default-method-alist) - (method tramp-default-method) - item) - (while choices - (setq item (pop choices)) - (when (and (string-match (or (nth 0 item) "") (or host "")) - (string-match (or (nth 1 item) "") (or user ""))) - (setq method (nth 2 item)) - (setq choices nil))) - method)) - -(defun tramp-find-method (multi-method method user host) - "Return the right method string to use. -This is MULTI-METHOD, if non-nil. Otherwise, it is METHOD, if non-nil. -If both MULTI-METHOD and METHOD are nil, do a lookup in -`tramp-default-method-alist'." - (or multi-method method (tramp-find-default-method user host))) - -;; HHH: Not Changed. Multi method. Will probably not handle the case where -;; a user name is not provided in the "file name" very well. -(defun tramp-dissect-multi-file-name (name) - "Not implemented yet." - (let ((regexp (nth 0 tramp-multi-file-name-structure)) - (method-index (nth 1 tramp-multi-file-name-structure)) - (hops-index (nth 2 tramp-multi-file-name-structure)) - (localname-index (nth 3 tramp-multi-file-name-structure)) - (hop-regexp (nth 0 tramp-multi-file-name-hop-structure)) - (hop-method-index (nth 1 tramp-multi-file-name-hop-structure)) - (hop-user-index (nth 2 tramp-multi-file-name-hop-structure)) - (hop-host-index (nth 3 tramp-multi-file-name-hop-structure)) - method hops len hop-methods hop-users hop-hosts localname) - (unless (string-match (format regexp hop-regexp) name) - (error "Not a multi tramp file name: %s" name)) - (setq method (match-string method-index name)) - (setq hops (match-string hops-index name)) - (setq len (/ (length (match-data t)) 2)) - (when (< localname-index 0) (setq localname-index (+ localname-index len))) - (setq localname (match-string localname-index name)) - (let ((index 0)) - (while (string-match hop-regexp hops index) - (setq index (match-end 0)) - (setq hop-methods - (cons (match-string hop-method-index hops) hop-methods)) - (setq hop-users - (cons (match-string hop-user-index hops) hop-users)) - (setq hop-hosts - (cons (match-string hop-host-index hops) hop-hosts)))) - (vector - method - (apply 'vector (reverse hop-methods)) - (apply 'vector (reverse hop-users)) - (apply 'vector (reverse hop-hosts)) - localname))) - -(defun tramp-make-tramp-file-name (multi-method method user host localname) - "Constructs a tramp file name from METHOD, USER, HOST and LOCALNAME." - (if multi-method - (tramp-make-tramp-multi-file-name multi-method method user host localname) - (format-spec - (concat tramp-prefix-format - (when method (concat "%m" tramp-postfix-single-method-format)) - (when user (concat "%u" tramp-postfix-user-format)) - (when host (concat "%h" tramp-postfix-host-format)) - (when localname (concat "%p"))) - `((?m . ,method) (?u . ,user) (?h . ,host) (?p . ,localname))))) - -;; CCC: Henrik Holm: Not Changed. Multi Method. What should be done -;; with this when USER is nil? -(defun tramp-make-tramp-multi-file-name (multi-method method user host localname) - "Constructs a tramp file name for a multi-hop method." - (unless tramp-make-multi-tramp-file-format - (error "`tramp-make-multi-tramp-file-format' is nil")) - (let* ((prefix-format (nth 0 tramp-make-multi-tramp-file-format)) - (hop-format (nth 1 tramp-make-multi-tramp-file-format)) - (localname-format (nth 2 tramp-make-multi-tramp-file-format)) - (prefix (format-spec prefix-format `((?m . ,multi-method)))) - (hops "") - (localname (format-spec localname-format `((?p . ,localname)))) - (i 0) - (len (length method))) - (while (< i len) - (let ((m (aref method i)) (u (aref user i)) (h (aref host i))) - (setq hops (concat hops (format-spec hop-format - `((?m . ,m) (?u . ,u) (?h . ,h))))) - (setq i (1+ i)))) - (concat prefix hops localname))) - -(defun tramp-make-copy-program-file-name (user host localname) + (let ((match (string-match (nth 0 tramp-file-name-structure) name))) + (unless match (error "Not a tramp file name: %s" name)) + (let ((method (match-string (nth 1 tramp-file-name-structure) name)) + (user (match-string (nth 2 tramp-file-name-structure) name)) + (host (match-string (nth 3 tramp-file-name-structure) name)) + (localname (match-string (nth 4 tramp-file-name-structure) name))) + (vector + (tramp-find-method method user host) + (tramp-find-user method user host) + (tramp-find-host method user host) + localname))))) + +(defun tramp-equal-remote (file1 file2) + "Checks, whether the remote parts of FILE1 and FILE2 are identical. +The check depends on method, user and host name of the files. If +one of the components is missing, the default values are used. +The local file name parts of FILE1 and FILE2 are not taken into +account. + +Example: + + (tramp-equal-remote \"/ssh::/etc\" \"/:/home\") + +would yield `t'. On the other hand, the following check results in nil: + + (tramp-equal-remote \"/sudo::/etc\" \"/su::/etc\")" + (and (stringp (file-remote-p file1)) + (stringp (file-remote-p file2)) + (string-equal (file-remote-p file1) (file-remote-p file2)))) + +(defun tramp-make-tramp-file-name (method user host localname) + "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME." + (concat tramp-prefix-format + (when (not (zerop (length method))) + (concat method tramp-postfix-method-format)) + (when (not (zerop (length user))) + (concat user tramp-postfix-user-format)) + (when host host) tramp-postfix-host-format + (when localname localname))) + +(defun tramp-completion-make-tramp-file-name (method user host localname) + "Constructs a Tramp file name from METHOD, USER, HOST and LOCALNAME. +It must not be a complete Tramp file name, but as long as there are +necessary only. This function will be used in file name completion." + (concat tramp-prefix-format + (when (not (zerop (length method))) + (concat method tramp-postfix-method-format)) + (when (not (zerop (length user))) + (concat user tramp-postfix-user-format)) + (when (not (zerop (length host))) + (concat host tramp-postfix-host-format)) + (when localname localname))) + +(defun tramp-make-copy-program-file-name (vec) "Create a file name suitable to be passed to `rcp' and workalikes." - (if user - (format "%s@%s:%s" user host localname) - (format "%s:%s" host localname))) - -(defun tramp-method-out-of-band-p (multi-method method user host) + (let ((user (tramp-file-name-user vec)) + (host (car (split-string + (tramp-file-name-host vec) tramp-prefix-port-regexp))) + (localname (tramp-shell-quote-argument + (tramp-file-name-localname vec)))) + (if (not (zerop (length user))) + (format "%s@%s:%s" user host localname) + (format "%s:%s" host localname)))) + +(defun tramp-method-out-of-band-p (vec) "Return t if this is an out-of-band method, nil otherwise." - (tramp-get-method-parameter - multi-method - (tramp-find-method multi-method method user host) - user host 'tramp-copy-program)) + (tramp-get-method-parameter (tramp-file-name-method vec) 'tramp-copy-program)) ;; Variables local to connection. -(defun tramp-get-ls-command (multi-method method user host) - (or - (save-excursion - (tramp-maybe-open-connection multi-method method user host) - (set-buffer (tramp-get-buffer multi-method method user host)) - tramp-ls-command) - (error "Couldn't find remote `ls' command"))) - -(defun tramp-get-test-groks-nt (multi-method method user host) - (save-excursion - (tramp-maybe-open-connection multi-method method user host) - (set-buffer (tramp-get-buffer multi-method method user host)) - tramp-test-groks-nt)) - -(defun tramp-get-file-exists-command (multi-method method user host) - (or - (save-excursion - (tramp-maybe-open-connection multi-method method user host) - (set-buffer (tramp-get-buffer multi-method method user host)) - tramp-file-exists-command) - (error "Couldn't find remote `test -e' command"))) - -(defun tramp-get-remote-perl (multi-method method user host) - (tramp-get-connection-property "perl" nil multi-method method user host)) - -(defun tramp-get-remote-ln (multi-method method user host) - (or - (tramp-get-connection-property "ln" nil multi-method method user host) - (error "Couldn't find remote `ln' command"))) - -(defun tramp-get-remote-uid (multi-method method user host) - (tramp-get-connection-property "uid" nil multi-method method user host)) - -(defun tramp-get-remote-gid (multi-method method user host) - (tramp-get-connection-property "gid" nil multi-method method user host)) - -;; Get a property of a TRAMP connection. -(defun tramp-get-connection-property - (property default multi-method method user host) - "Get the named property for the connection. -If the value is not set for the connection, return `default'" - (tramp-maybe-open-connection multi-method method user host) - (with-current-buffer (tramp-get-buffer multi-method method user host) - (let (error) - (condition-case nil - (symbol-value (intern (concat "tramp-connection-property-" property))) - (error default))))) - -;; Set a property of a TRAMP connection. -(defun tramp-set-connection-property - (property value multi-method method user host) - "Set the named property of a TRAMP connection." - (tramp-maybe-open-connection multi-method method user host) - (with-current-buffer (tramp-get-buffer multi-method method user host) - (set (make-local-variable - (intern (concat "tramp-connection-property-" property))) - value))) +(defun tramp-get-ls-command (vec) + (with-connection-property vec "ls" + (with-current-buffer (tramp-get-buffer vec) + (tramp-message vec 5 "Finding a suitable `ls' command") + (or + (catch 'ls-found + (dolist (cmd '("ls" "gnuls" "gls")) + (let ((dl tramp-remote-path) + result) + (while + (and + dl + (setq result + (tramp-find-executable vec cmd dl t t))) + ;; Check parameter. + (when (zerop (tramp-send-command-and-check + vec (format "%s -lnd /" result))) + (throw 'ls-found result)) + ;; Remove unneeded directories from path. + (while + (and + dl + (not + (string-equal + result (expand-file-name-as-directory cmd (car dl))))) + (setq dl (cdr dl))) + (setq dl (cdr dl)))))) + (tramp-error vec 'file-error "Couldn't find a proper `ls' command"))))) + +(defun tramp-get-test-command (vec) + (with-connection-property vec "test" + (with-current-buffer (tramp-get-buffer vec) + (tramp-message vec 5 "Finding a suitable `test' command") + (if (zerop (tramp-send-command-and-check vec "test 0")) + "test" + (tramp-find-executable vec "test" tramp-remote-path))))) + +(defun tramp-get-test-nt-command (vec) + ;; Does `test A -nt B' work? Use abominable `find' construct if it + ;; doesn't. BSD/OS 4.0 wants the parentheses around the command, + ;; for otherwise the shell crashes. + (with-connection-property vec "test-nt" + (or + (progn + (tramp-send-command + vec (format "( %s / -nt / )" (tramp-get-test-command vec))) + (with-current-buffer (tramp-get-buffer vec) + (goto-char (point-min)) + (when (looking-at + (format "\n%s\r?\n" (regexp-quote tramp-end-of-output))) + (format "%s %%s -nt %%s" (tramp-get-test-command vec))))) + (progn + (tramp-send-command + vec + (format + "tramp_test_nt () {\n%s -n \"`find $1 -prune -newer $2 -print`\"\n}" + (tramp-get-test-command vec))) + "tramp_test_nt %s %s")))) + +(defun tramp-get-file-exists-command (vec) + (with-connection-property vec "file-exists" + (with-current-buffer (tramp-get-buffer vec) + (tramp-message vec 5 "Finding command to check if file exists") + (tramp-find-file-exists-command vec)))) + +(defun tramp-get-remote-ln (vec) + (with-connection-property vec "ln" + (with-current-buffer (tramp-get-buffer vec) + (tramp-message vec 5 "Finding a suitable `ln' command") + (tramp-find-executable vec "ln" tramp-remote-path)))) + +(defun tramp-get-remote-perl (vec) + (with-connection-property vec "perl" + (with-current-buffer (tramp-get-buffer vec) + (tramp-message vec 5 "Finding a suitable `perl' command") + (or (tramp-find-executable vec "perl5" tramp-remote-path) + (tramp-find-executable vec "perl" tramp-remote-path))))) + +(defun tramp-get-remote-stat (vec) + (with-connection-property vec "stat" + (with-current-buffer (tramp-get-buffer vec) + (tramp-message vec 5 "Finding a suitable `stat' command") + (let ((result (tramp-find-executable vec "stat" tramp-remote-path)) + tmp) + ;; Check whether stat(1) returns usable syntax. + (when result + (setq tmp + ;; We don't want to display an error message. + (with-temp-message (or (current-message) "") + (condition-case nil + (tramp-send-command-and-read + vec (format "%s -c '(\"%%N\")' /" result)) + (error nil)))) + (unless (and (listp tmp) (stringp (car tmp)) + (string-match "^./.$" (car tmp))) + (setq result nil))) + result)))) + +(defun tramp-get-remote-id (vec) + (with-connection-property vec "id" + (with-current-buffer (tramp-get-buffer vec) + (tramp-message vec 5 "Finding POSIX `id' command") + (or + (catch 'id-found + (let ((dl tramp-remote-path) + result) + (while + (and + dl + (setq result + (tramp-find-executable vec "id" dl t t))) + ;; Check POSIX parameter. + (when (zerop (tramp-send-command-and-check + vec (format "%s -u" result))) + (throw 'id-found result)) + ;; Remove unneeded directories from path. + (while + (and + dl + (not + (string-equal + result + (concat (file-name-as-directory (car dl)) "id")))) + (setq dl (cdr dl))) + (setq dl (cdr dl))))) + (tramp-error vec 'file-error "Couldn't find a POSIX `id' command"))))) + +(defun tramp-get-remote-uid (vec id-format) + (with-connection-property vec (format "uid-%s" id-format) + (let ((res (tramp-send-command-and-read + vec + (format "%s -u%s %s" + (tramp-get-remote-id vec) + (if (equal id-format 'integer) "" "n") + (if (equal id-format 'integer) + "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/"))))) + ;; The command might not always return a number. + (if (and (equal id-format 'integer) (not (integerp res))) -1 res)))) + +(defun tramp-get-remote-gid (vec id-format) + (with-connection-property vec (format "gid-%s" id-format) + (let ((res (tramp-send-command-and-read + vec + (format "%s -g%s %s" + (tramp-get-remote-id vec) + (if (equal id-format 'integer) "" "n") + (if (equal id-format 'integer) + "" "| sed -e s/^/\\\"/ -e s/\$/\\\"/"))))) + ;; The command might not always return a number. + (if (and (equal id-format 'integer) (not (integerp res))) -1 res)))) ;; Some predefined connection properties. -(defun tramp-set-remote-encoding (multi-method method user host rem-enc) - (tramp-set-connection-property "remote-encoding" rem-enc - multi-method method user host)) -(defun tramp-get-remote-encoding (multi-method method user host) - (tramp-get-connection-property "remote-encoding" nil - multi-method method user host)) - -(defun tramp-set-remote-decoding (multi-method method user host rem-dec) - (tramp-set-connection-property "remote-decoding" rem-dec - multi-method method user host)) -(defun tramp-get-remote-decoding (multi-method method user host) - (tramp-get-connection-property "remote-decoding" nil - multi-method method user host)) - -(defun tramp-set-local-encoding (multi-method method user host loc-enc) - (tramp-set-connection-property "local-encoding" loc-enc - multi-method method user host)) -(defun tramp-get-local-encoding (multi-method method user host) - (tramp-get-connection-property "local-encoding" nil - multi-method method user host)) - -(defun tramp-set-local-decoding (multi-method method user host loc-dec) - (tramp-set-connection-property "local-decoding" loc-dec - multi-method method user host)) -(defun tramp-get-local-decoding (multi-method method user host) - (tramp-get-connection-property "local-decoding" nil - multi-method method user host)) - -(defun tramp-get-method-parameter (multi-method method user host param) +(defun tramp-get-remote-coding (vec prop) + ;; Local coding handles properties like remote coding. So we could + ;; call it without pain. + (let ((ret (tramp-get-local-coding vec prop))) + ;; The connection property might have been cached. So we must send + ;; the script - maybe. + (when (not (stringp ret)) + (let ((name (symbol-name ret))) + (while (string-match (regexp-quote "-") name) + (setq name (replace-match "_" nil t name))) + (tramp-maybe-send-script vec (symbol-value ret) name) + (setq ret name))) + ;; Return the value. + ret)) + +(defun tramp-get-local-coding (vec prop) + (or + (tramp-get-connection-property vec prop nil) + (progn + (tramp-find-inline-encoding vec) + (tramp-get-connection-property vec prop nil)))) + +(defun tramp-get-method-parameter (method param) "Return the method parameter PARAM. -If the `tramp-methods' entry does not exist, use the variable PARAM -as default." - (unless (boundp param) - (error "Non-existing method parameter `%s'" param)) - (let ((entry (assoc param - (assoc (tramp-find-method multi-method method user host) - tramp-methods)))) - (if entry - (cadr entry) - (symbol-value param)))) - +If the `tramp-methods' entry does not exist, return NIL." + (let ((entry (assoc param (assoc method tramp-methods)))) + (when entry (cadr entry)))) ;; Auto saving to a special directory. (defun tramp-exists-file-name-handler (operation &rest args) - (let ((buffer-file-name "/") - (fnha file-name-handler-alist) - (check-file-name-operation operation) - (file-name-handler-alist - (list - (cons "/" - '(lambda (operation &rest args) - "Returns OPERATION if it is the one to be checked" - (if (equal check-file-name-operation operation) - operation - (let ((file-name-handler-alist fnha)) - (apply operation args)))))))) - (eq (apply operation args) operation))) + "Checks whether OPERATION runs a file name handler." + ;; The file name handler is determined on base of either an + ;; argument, `buffer-file-name', or `default-directory'. + (condition-case nil + (let* ((buffer-file-name "/") + (default-directory "/") + (fnha file-name-handler-alist) + (check-file-name-operation operation) + (file-name-handler-alist + (list + (cons "/" + '(lambda (operation &rest args) + "Returns OPERATION if it is the one to be checked." + (if (equal check-file-name-operation operation) + operation + (let ((file-name-handler-alist fnha)) + (apply operation args)))))))) + (equal (apply operation args) operation)) + (error nil))) (unless (tramp-exists-file-name-handler 'make-auto-save-file-name) (defadvice make-auto-save-file-name (around tramp-advice-make-auto-save-file-name () activate) - "Invoke `tramp-handle-make-auto-save-file-name' for tramp files." + "Invoke `tramp-handle-make-auto-save-file-name' for Tramp files." (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name))) (setq ad-return-value (tramp-handle-make-auto-save-file-name)) ad-do-it)) @@ -7316,12 +6743,6 @@ (setq alist (cdr alist)))) string)) -(defun tramp-insert-with-face (face string) - "Insert text with a specific face." - (let ((start (point))) - (insert string) - (add-text-properties start (point) (list 'face face)))) - ;; ------------------------------------------------------------ ;; -- Compatibility functions section -- ;; ------------------------------------------------------------ @@ -7345,28 +6766,63 @@ "`temp-directory' is defined -- using /tmp.")) (file-name-as-directory "/tmp")))) -(defun tramp-read-passwd (user host prompt) +(defun tramp-read-passwd (proc &optional prompt) "Read a password from user (compat function). Invokes `password-read' if available, `read-passwd' else." - (if (functionp 'password-read) - (let* ((key (concat (or user (user-login-name)) "@" host)) - (password (apply #'password-read (list prompt key)))) - (apply #'password-cache-add (list key password)) - password) - (read-passwd prompt))) - -(defun tramp-clear-passwd (&optional user host) - "Clear password cache for connection related to current-buffer." + (let* ((key (tramp-make-tramp-file-name + tramp-current-method tramp-current-user + tramp-current-host "")) + (pw-prompt + (or prompt + (with-current-buffer (process-buffer proc) + (tramp-check-for-regexp proc tramp-password-prompt-regexp) + (format "%s for %s " (capitalize (match-string 1)) key))))) + (if (functionp 'password-read) + (let ((password (apply #'password-read (list pw-prompt key)))) + (apply #'password-cache-add (list key password)) + password) + (read-passwd pw-prompt)))) + +(defun tramp-clear-passwd () + "Clear password cache for connection related to current-buffer. +If METHOD, USER or HOST is given, take then for computing the key." (interactive) - (let ((filename (or buffer-file-name list-buffers-directory ""))) - (when (and (functionp 'password-cache-remove) - (or (and user host) (tramp-tramp-file-p filename))) - (let* ((v (when (tramp-tramp-file-p filename) - (tramp-dissect-file-name filename))) - (luser (or user (tramp-file-name-user v) (user-login-name))) - (lhost (or host (tramp-file-name-host v) (system-name))) - (key (concat luser "@" lhost))) - (apply #'password-cache-remove (list key)))))) + (when (functionp 'password-cache-remove) + (apply #'password-cache-remove + (list (tramp-make-tramp-file-name + tramp-current-method + tramp-current-user + tramp-current-host + ""))))) + +;; Snarfed code from time-date.el and parse-time.el + +(defconst tramp-half-a-year '(241 17024) +"Evaluated by \"(days-to-time 183)\".") + +(defconst tramp-parse-time-months + '(("jan" . 1) ("feb" . 2) ("mar" . 3) + ("apr" . 4) ("may" . 5) ("jun" . 6) + ("jul" . 7) ("aug" . 8) ("sep" . 9) + ("oct" . 10) ("nov" . 11) ("dec" . 12)) + "Alist mapping month names to integers.") + +(defun tramp-time-less-p (t1 t2) + "Say whether time value T1 is less than time value T2." + (unless t1 (setq t1 '(0 0))) + (unless t2 (setq t2 '(0 0))) + (or (< (car t1) (car t2)) + (and (= (car t1) (car t2)) + (< (nth 1 t1) (nth 1 t2))))) + +(defun tramp-time-subtract (t1 t2) + "Subtract two time values. +Return the difference in the format of a time value." + (unless t1 (setq t1 '(0 0))) + (unless t2 (setq t2 '(0 0))) + (let ((borrow (< (cadr t1) (cadr t2)))) + (list (- (car t1) (car t2) (if borrow 1 0)) + (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))) (defun tramp-time-diff (t1 t2) "Return the difference between the two times, in seconds. @@ -7385,11 +6841,7 @@ (if (< (length t1) 3) (append t1 '(0)) t1) (if (< (length t2) 3) (append t2 '(0)) t2))) (t - ;; snarfed from Emacs 21 time-date.el; combining - ;; time-to-seconds and subtract-time - (let ((time (let ((borrow (< (cadr t1) (cadr t2)))) - (list (- (car t1) (car t2) (if borrow 1 0)) - (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))) + (let ((time (tramp-time-subtract t1 t2))) (+ (* (car time) 65536.0) (cadr time) (/ (or (nth 2 time) 0) 1000000.0)))))) @@ -7428,11 +6880,9 @@ "Specify if query is needed for process when Emacs is exited. If the second argument flag is non-nil, Emacs will query the user before exiting if process is running." - (funcall (if (fboundp 'set-process-query-on-exit-flag) - (symbol-function 'set-process-query-on-exit-flag) - (symbol-function 'process-kill-without-query)) - process flag)) + (funcall (symbol-function 'set-process-query-on-exit-flag) process flag) + (funcall (symbol-function 'process-kill-without-query) process flag))) ;; ------------------------------------------------------------ @@ -7479,29 +6929,6 @@ t t result))) result)))) -;; ;; EFS hooks itself into the file name handling stuff in more places -;; ;; than just `file-name-handler-alist'. The following tells EFS to stay -;; ;; away from tramp.el file names. -;; ;; -;; ;; This is needed because EFS installs (efs-dired-before-readin) into -;; ;; 'dired-before-readin-hook'. This prevents EFS from opening an FTP -;; ;; connection to help it's dired process. Not that I have any real -;; ;; idea *why* this is helpful to dired. -;; ;; -;; ;; Anyway, this advice fixes the problem (with a sledgehammer :) -;; ;; -;; ;; Daniel Pittman -;; ;; -;; ;; CCC: when the other defadvice calls have disappeared, make sure -;; ;; not to call defadvice unless it's necessary. How do we find out whether -;; ;; it is necessary? (featurep 'efs) is surely the wrong way -- -;; ;; EFS might nicht be loaded yet. -;; (defadvice efs-ftp-path (around dont-match-tramp-localname activate protect) -;; "Cause efs-ftp-path to fail when the path is a TRAMP localname." -;; (if (tramp-tramp-file-p (ad-get-arg 0)) -;; nil -;; ad-do-it)) - ;; We currently (sometimes) use "[" and "]" in the filename format. ;; This means that Emacs wants to expand wildcards if ;; `find-file-wildcards' is non-nil, and then barfs because no @@ -7552,10 +6979,6 @@ (format "tramp (%s)" tramp-version) ; package name and version (delq nil `(;; Current state - tramp-ls-command - tramp-test-groks-nt - tramp-file-exists-command - tramp-current-multi-method tramp-current-method tramp-current-user tramp-current-host @@ -7563,6 +6986,11 @@ ;; System defaults tramp-auto-save-directory ; vars to dump tramp-default-method + tramp-default-method-alist + tramp-default-host + tramp-default-proxies-alist + tramp-default-user + tramp-default-user-alist tramp-rsh-end-of-line tramp-default-password-end-of-line tramp-remote-path @@ -7576,24 +7004,21 @@ tramp-temp-name-prefix tramp-file-name-structure tramp-file-name-regexp - tramp-multi-file-name-structure - tramp-multi-file-name-hop-structure - tramp-multi-methods - tramp-multi-connection-function-alist tramp-methods tramp-end-of-output - tramp-coding-commands + tramp-local-coding-commands + tramp-remote-coding-commands tramp-actions-before-shell tramp-actions-copy-out-of-band - tramp-multi-actions tramp-terminal-type ;; Mask non-7bit characters (tramp-shell-prompt-pattern . tramp-reporter-dump-variable) - tramp-chunksize ,(when (boundp 'tramp-backup-directory-alist) 'tramp-backup-directory-alist) ,(when (boundp 'tramp-bkup-backup-directory-info) 'tramp-bkup-backup-directory-info) + ;; Dump cache. + (tramp-cache-data . tramp-reporter-dump-variable) ;; Non-tramp variables of interest ;; Mask non-7bit characters @@ -7616,18 +7041,21 @@ 'tramp-load-report-modules ; pre-hook 'tramp-append-tramp-buffers ; post-hook "\ -Enter your bug report in this message, including as much detail as you -possibly can about the problem, what you did to cause it and what the -local and remote machines are. - -If you can give a simple set of instructions to make this bug happen -reliably, please include those. Thank you for helping kill bugs in -TRAMP. - -Another useful thing to do is to put (setq tramp-debug-buffer t) in -the ~/.emacs file and to repeat the bug. Then, include the contents -of the *tramp/foo* buffer and the *debug tramp/foo* buffer in your bug -report. +Enter your bug report in this message, including as much detail +as you possibly can about the problem, what you did to cause it +and what the local and remote machines are. + +If you can give a simple set of instructions to make this bug +happen reliably, please include those. Thank you for helping +kill bugs in TRAMP. + +Another useful thing to do is to put + + (setq tramp-verbose 8) + +in the ~/.emacs file and to repeat the bug. Then, include the +contents of the *tramp/foo* buffer and the *debug tramp/foo* +buffer in your bug report. --bug report follows this line-- ")))) @@ -7639,29 +7067,32 @@ (val (with-current-buffer reporter-eval-buffer (symbol-value varsym)))) - ;; There are characters to be masked. - (when (and (boundp 'mm-7bit-chars) - (string-match - (concat "[^" (symbol-value 'mm-7bit-chars) "]") val)) - (with-current-buffer reporter-eval-buffer - (set varsym (concat "(base64-decode-string \"" - (base64-encode-string val) - "\")")))) + (if (hash-table-p val) + ;; Pretty print the cache. + (set varsym (read (format "(%s)" (tramp-cache-print val)))) + ;; There are characters to be masked. + (when (and (boundp 'mm-7bit-chars) + (string-match + (concat "[^" (symbol-value 'mm-7bit-chars) "]") val)) + (with-current-buffer reporter-eval-buffer + (set varsym (format "(base64-decode-string \"%s\"" + (base64-encode-string val)))))) ;; Dump variable. (funcall (symbol-function 'reporter-dump-variable) varsym mailbuf) - ;; Remove string quotation. - (forward-line -1) - (when (looking-at - (concat "\\(^.*\\)" "\"" ;; \1 " - "\\((base64-decode-string \\)" "\\\\" ;; \2 \ - "\\(\".*\\)" "\\\\" ;; \3 \ - "\\(\")\\)" "\"$")) ;; \4 " - (replace-match "\\1\\2\\3\\4") - (beginning-of-line) - (insert " ;; variable encoded due to non-printable characters\n")) - (forward-line 1) + (unless (hash-table-p val) + ;; Remove string quotation. + (forward-line -1) + (when (looking-at + (concat "\\(^.*\\)" "\"" ;; \1 " + "\\((base64-decode-string \\)" "\\\\" ;; \2 \ + "\\(\".*\\)" "\\\\" ;; \3 \ + "\\(\")\\)" "\"$")) ;; \4 " + (replace-match "\\1\\2\\3\\4") + (beginning-of-line) + (insert " ;; variable encoded due to non-printable characters\n")) + (forward-line 1)) ;; Reset VARSYM to old value. (with-current-buffer reporter-eval-buffer @@ -7683,8 +7114,39 @@ (funcall (symbol-function 'mml-mode) t))) (defun tramp-append-tramp-buffers () - "Append Tramp buffers into the bug report." - + "Append Tramp buffers and buffer local variables into the bug report." + + (goto-char (point-max)) + + ;; Dump buffer local variables. + (dolist (buffer + (delq nil + (mapcar + '(lambda (b) + (when (string-match "\\*tramp/" (buffer-name b)) b)) + (buffer-list)))) + (let ((reporter-eval-buffer buffer) + (buffer-name (buffer-name buffer)) + (elbuf (get-buffer-create " *tmp-reporter-buffer*"))) + (with-current-buffer elbuf + (emacs-lisp-mode) + (erase-buffer) + (insert "\n(setq\n") + (lisp-indent-line) + (funcall (symbol-function 'reporter-dump-variable) + 'buffer-name (current-buffer)) + (dolist (varsym-or-cons-cell (buffer-local-variables buffer)) + (let ((varsym (or (car-safe varsym-or-cons-cell) + varsym-or-cons-cell))) + (when (string-match "tramp" (symbol-name varsym)) + (funcall + (symbol-function 'reporter-dump-variable) + varsym (current-buffer))))) + (lisp-indent-line) + (insert ")\n")) + (insert-buffer-substring elbuf))) + + ;; Append buffers only when we are in message mode. (when (and (eq major-mode 'message-mode) (boundp 'mml-mode) @@ -7705,24 +7167,26 @@ (setq buffer-read-only nil) (goto-char (point-min)) (while (not (eobp)) - (if (re-search-forward tramp-buf-regexp (tramp-point-at-eol) t) + (if (re-search-forward tramp-buf-regexp (tramp-line-end-position) t) (forward-line 1) (forward-line 0) (let ((start (point))) (forward-line 1) (kill-region start (point))))) (insert " -The buffer(s) above will be appended to this message. If you don't want -to append a buffer because it contains sensible data, or because the buffer -is too large, you should delete the respective buffer. The buffer(s) will -contain user and host names. Passwords will never be included there.") - - (when (and tramp-debug-buffer (> tramp-verbose 9)) +The buffer(s) above will be appended to this message. If you +don't want to append a buffer because it contains sensitive data, +or because the buffer is too large, you should delete the +respective buffer. The buffer(s) will contain user and host +names. Passwords will never be included there.") + + (when (>= tramp-verbose 6) (insert "\n\n") (let ((start (point))) (insert "\ -Please note that you have set `tramp-verbose' to a value greater than 9. -Therefore, the contents of files might be included in the debug buffer(s).") +Please note that you have set `tramp-verbose' to a value of at +least 6. Therefore, the contents of files might be included in +the debug buffer(s).") (add-text-properties start (point) (list 'face 'italic)))) (set-buffer-modified-p nil) @@ -7735,7 +7199,10 @@ (kill-buffer nil) (switch-to-buffer curbuf) (goto-char (point-max)) - (insert "\n\n") + (insert "\n\ +This is a special notion of the `gnus/message' package. If you +use another mail agent (by copying the contents of this buffer) +please ensure that the buffers are attached to your email.\n\n") (dolist (buffer buffer-list) (funcall (symbol-function 'mml-insert-empty-tag) 'part 'type "text/plain" 'encoding "base64" @@ -7766,9 +7233,9 @@ ;; ange-ftp settings must be enabled. (when (functionp 'tramp-ftp-enable-ange-ftp) (funcall (symbol-function 'tramp-ftp-enable-ange-ftp))) - ;; `tramp-util' unloads also `tramp'. - (condition-case nil ;; maybe its not loaded yet. - (unload-feature (if (featurep 'tramp-util) 'tramp-util 'tramp) 'force) + ;; Maybe its not loaded yet. + (condition-case nil + (unload-feature 'tramp 'force) (error nil))) (provide 'tramp) @@ -7776,9 +7243,9 @@ ;; Make sure that we get integration with the VC package. ;; When it is loaded, we need to pull in the integration module. ;; This must come after (provide 'tramp) because tramp-vc.el -;; requires tramp. +;; requires tramp. Not necessary in Emacs 23. (eval-after-load "vc" - '(progn + '(unless (functionp 'start-file-process) (require 'tramp-vc) (add-hook 'tramp-unload-hook '(lambda () @@ -7795,6 +7262,12 @@ ;; Another approach is to read a netrc file like ~/.authinfo ;; from Gnus. ;; * Handle nonlocal exits such as C-g. +;; * But it would probably be better to use with-local-quit at the +;; place where it's actually needed: around any potentially +;; indefinitely blocking piece of code. In this case it would be +;; within Tramp around one of its calls to accept-process-output (or +;; around one of the loops that calls accept-process-output) +;; (Stefann Monnier). ;; * Autodetect if remote `ls' groks the "--dired" switch. ;; * Add fallback for inline encodings. This should be used ;; if the remote end doesn't support mimencode or a similar program. @@ -7808,9 +7281,6 @@ ;; two commands to write a null byte: ;; dd if=/dev/zero bs=1 count=1 ;; echo | tr '\n' '\000' -;; * Separate local `tramp-coding-commands' from remote ones. Connect -;; the two via a format which can be `uu' or `b64'. Then we can search -;; for the right local commands and the right remote commands separately. ;; * Cooperate with PCL-CVS. It uses start-process, which doesn't ;; work for remote files. ;; * Rewrite `tramp-shell-quote-argument' to abstain from using @@ -7830,43 +7300,27 @@ ;; * Don't use globbing for directories with many files, as this is ;; likely to produce long command lines, and some shells choke on ;; long command lines. -;; * Find out about the new auto-save mechanism in Emacs 21 and -;; do the right thing. ;; * `vc-directory' does not work. It never displays any files, even ;; if it does show files when run locally. ;; * Allow correction of passwords, if the remote end allows this. ;; (Mark Hershberger) ;; * How to deal with MULE in `insert-file-contents' and `write-region'? -;; * Do asynchronous `shell-command's. ;; * Grok `append' parameter for `write-region'. ;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'? ;; * abbreviate-file-name ;; * grok ~ in tramp-remote-path (Henrik Holm ) -;; * Also allow to omit user names when doing multi-hop. Not sure yet -;; what the user names should default to, though. ;; * better error checking. At least whenever we see something ;; strange when doing zerop, we should kill the process and start ;; again. (Greg Stark) -;; * Add caching for filename completion. (Greg Stark) -;; Of course, this has issues with usability (stale cache bites) -;; -- ;; * Provide a local cache of old versions of remote files for the rsync ;; transfer method to use. (Greg Stark) ;; * Remove unneeded parameters from methods. ;; * Invoke rsync once for copying a whole directory hierarchy. ;; (Francesco Potort,Al(B) -;; * Should we set PATH ourselves or should we rely on the remote end -;; to do it? -;; * Make it work for XEmacs 20, which is missing `with-timeout'. ;; * Make it work for different encodings, and for different file name ;; encodings, too. (Daniel Pittman) -;; * Change applicable functions to pass a struct tramp-file-name rather -;; than the individual items MULTI-METHOD, METHOD, USER, HOST, LOCALNAME. -;; * Implement asynchronous shell commands. ;; * Clean up unused *tramp/foo* buffers after a while. (Pete Forman) ;; * Progress reports while copying files. (Michael Kifer) -;; * `Smart' connection method that uses inline for small and out of -;; band for large files. (Michael Kifer) ;; * Don't search for perl5 and perl. Instead, only search for perl and ;; then look if it's the right version (with `perl -v'). ;; * When editing a remote CVS controlled file as a different user, VC @@ -7879,19 +7333,49 @@ ;; about Tramp, it does not do the right thing if the target file ;; name is a Tramp name. ;; * Username and hostname completion. -;; ** If `partial-completion-mode' isn't loaded, "/foo:bla" tries to -;; connect to host "blabla" already if that host is unique. No idea -;; how to suppress. Maybe not an essential problem. ;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode'. -;; ** Extend `tramp-get-completion-su' for NIS and shadow passwords. ;; ** Unify `tramp-parse-{rhosts,shosts,sconfig,hosts,passwd,netrc}'. ;; Code is nearly identical. -;; ** Decide whiche files to take for searching user/host names depending on -;; operating system (windows-nt) in `tramp-completion-function-alist'. -;; ** Enhance variables for debug. -;; ** Implement "/multi:" completion. -;; ** Add a learning mode for completion. Make results persistent. ;; * Allow out-of-band methods as _last_ multi-hop. +;; * WIBNI if we had a command "trampclient"? If I was editing in +;; some shell with root priviledges, it would be nice if I could +;; just call +;; trampclient filename.c +;; as an editor, and the _current_ shell would connect to an Emacs +;; server and would be used in an existing non-priviledged Emacs +;; session for doing the editing in question. +;; That way, I need not tell Emacs my password again and be afraid +;; that it makes it into core dumps or other ugly stuff (I had Emacs +;; once display a just typed password in the context of a keyboard +;; sequence prompt for a question immediately following in a shell +;; script run within Emacs -- nasty). +;; And if I have some ssh session running to a different computer, +;; having the possibility of passing a local file there to a local +;; Emacs session (in case I can arrange for a connection back) would +;; be nice. +;; Likely the corresponding tramp server should not allow the +;; equivalent of the emacsclient -eval option in order to make this +;; reasonably unproblematic. And maybe trampclient should have some +;; way of passing credentials, like by using an SSL socket or +;; something. (David Kastrup) +;; * Could Tramp reasonably look for a prompt after ^M rather than +;; only after ^J ? (Stefan Monnier) +;; * WIBNI there was an interactive command prompting for tramp +;; method, hostname, username and filename and translates the user +;; input into the correct filename syntax (depending on the Emacs +;; flavor) (Reiner Steib) +;; * Let the user edit the connection properties interactively. +;; Something like `gnus-server-edit-server' in Gnus' *Server* buffer. +;; * Reconnect directly to a compliant shell without first going +;; through the user's default shell. (Pete Forman) +;; * It's just that when I come to Customize `tramp-default-user-alist' +;; I'm presented with a mismatch and raw lisp for a value. It is my +;; understanding that a variable declared with defcustom is a User +;; Option and should not be modified by the code. add-to-list is +;; called in several places. One way to handle that is to have a new +;; ordinary variable that gets its initial value from +;; tramp-default-user-alist and then is added to. (Pete Forman) +;; * Make `tramp-default-user' obsolete. ;; Functions for file-name-handler-alist: ;; diff-latest-backup-file -- in diff.el diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/net/trampver.el --- a/lisp/net/trampver.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/net/trampver.el Sun Jul 15 02:05:20 2007 +0000 @@ -11,8 +11,8 @@ ;; GNU Emacs 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 2, or (at your option) -;; any later version. +;; the Free Software Foundation; either version 3 of the License, or +;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -20,22 +20,26 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs; see the file COPYING. If not, see +;; . ;;; Code: ;; In the Tramp CVS repository, the version numer and the bug report address ;; are auto-frobbed from configure.ac, so you should edit that file and run -;; "autoconf && ./configure" to change them. +;; "autoconf && ./configure" to change them. (X)Emacs version check is defined +;; in macro AC_EMACS_INFO of aclocal.m4; should be changed only there. -(defconst tramp-version "2.0.56" +(defconst tramp-version "2.1.10-pre" "This version of Tramp.") (defconst tramp-bug-report-address "tramp-devel@gnu.org" "Email address to send bug reports to.") +;; Check for (X)Emacs version. +(let ((x (if (or (< emacs-major-version 21) (and (featurep 'xemacs) (< emacs-minor-version 4))) (format "Tramp 2.1.10-pre is not fit for %s" (when (string-match "^.*$" (emacs-version)) (match-string 0 (emacs-version)))) "ok"))) + (unless (string-match "\\`ok\\'" x) (error x))) + (provide 'trampver) ;;; arch-tag: 443576ca-f8f1-4bb1-addc-5c70861e93b1 diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/novice.el --- a/lisp/novice.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/novice.el Sun Jul 15 02:05:20 2007 +0000 @@ -88,8 +88,9 @@ SPC to try the command just this once, but leave it disabled. ! to try it, and enable all disabled commands for this session only.") (save-excursion - (set-buffer standard-output) - (help-mode))) + (set-buffer standard-output) + (help-mode))) + (fit-window-to-buffer (get-buffer-window "*Disabled Command*")) (message "Type y, n, ! or SPC (the space bar): ") (let ((cursor-in-echo-area t)) (while (progn (setq char (read-event)) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/pcomplete.el --- a/lisp/pcomplete.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/pcomplete.el Sun Jul 15 02:05:20 2007 +0000 @@ -711,6 +711,7 @@ If no directory information can be extracted from the completed component, `default-directory' is used as the basis for completion." (let* ((name (substitute-env-vars pcomplete-stub)) + (completion-ignore-case pcomplete-ignore-case) (default-directory (expand-file-name (or (file-name-directory name) default-directory))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/pcvs-info.el --- a/lisp/pcvs-info.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/pcvs-info.el Sun Jul 15 02:05:20 2007 +0000 @@ -85,9 +85,9 @@ (defface cvs-unknown '((((class color) (background dark)) - (:foreground "red")) + (:foreground "red1")) (((class color) (background light)) - (:foreground "red")) + (:foreground "red1")) (t (:slant italic))) "PCL-CVS face used to highlight unknown file status." :group 'pcl-cvs) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/pcvs-util.el --- a/lisp/pcvs-util.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/pcvs-util.el Sun Jul 15 02:05:20 2007 +0000 @@ -186,35 +186,6 @@ "Tell whether STR1 is a prefix of STR2." (eq t (compare-strings str2 nil (length str1) str1 nil nil))) -;; (string->strings (strings->string X)) == X -(defun cvs-strings->string (strings &optional separator) - "Concatenate the STRINGS, adding the SEPARATOR (default \" \"). -This tries to quote the strings to avoid ambiguity such that - (cvs-string->strings (cvs-strings->string strs)) == strs -Only some SEPARATORs will work properly." - (let ((sep (or separator " "))) - (mapconcat - (lambda (str) - (if (string-match "[\\\"]" str) - (concat "\"" (replace-regexp-in-string "[\\\"]" "\\\\\\&" str) "\"") - str)) - strings sep))) - -;; (string->strings (strings->string X)) == X -(defun cvs-string->strings (string &optional separator) - "Split the STRING into a list of strings. -It understands elisp style quoting within STRING such that - (cvs-string->strings (cvs-strings->string strs)) == strs -The SEPARATOR regexp defaults to \"\\s-+\"." - (let ((sep (or separator "\\s-+")) - (i (string-match "[\"]" string))) - (if (null i) (split-string string sep t) ; no quoting: easy - (append (unless (eq i 0) (split-string (substring string 0 i) sep t)) - (let ((rfs (read-from-string string i))) - (cons (car rfs) - (cvs-string->strings (substring string (cdr rfs)) - sep))))))) - ;;;; ;;;; file names ;;;; @@ -240,7 +211,7 @@ (defconst cvs-qtypedesc-string1 (cvs-qtypedesc-create 'identity 'identity t)) (defconst cvs-qtypedesc-string (cvs-qtypedesc-create 'identity 'identity)) (defconst cvs-qtypedesc-strings - (cvs-qtypedesc-create 'cvs-string->strings 'cvs-strings->string nil)) + (cvs-qtypedesc-create 'string->strings 'strings->string nil)) (defun cvs-query-read (default prompt qtypedesc &optional hist-sym) (let* ((qtypedesc (or qtypedesc cvs-qtypedesc-strings)) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/pcvs.el --- a/lisp/pcvs.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/pcvs.el Sun Jul 15 02:05:20 2007 +0000 @@ -182,7 +182,7 @@ (when (re-search-forward (concat "^" cmd "\\(\\s-+\\(.*\\)\\)?$") nil t) (let* ((sym (intern (concat "cvs-" cmd "-flags"))) - (val (cvs-string->strings (or (match-string 2) "")))) + (val (string->strings (or (match-string 2) "")))) (cvs-flags-set sym 0 val)))) ;; ensure that cvs doesn't have -q or -Q (cvs-flags-set 'cvs-cvs-flags 0 @@ -607,7 +607,7 @@ (t arg))) args))) (concat cvs-program " " - (cvs-strings->string + (strings->string (append (cvs-flags-query 'cvs-cvs-flags nil 'noquery) (if cvs-cvsroot (list "-d" cvs-cvsroot)) args @@ -936,7 +936,7 @@ (let ((root (cvs-get-cvsroot))) (if (or (null root) current-prefix-arg) (setq root (read-string "CVS Root: "))) - (list (cvs-string->strings (read-string "Module(s): " (cvs-get-module))) + (list (string->strings (read-string "Module(s): " (cvs-get-module))) (read-directory-name "CVS Checkout Directory: " nil default-directory nil) (cvs-add-branch-prefix @@ -959,7 +959,7 @@ (if branch (format " (branch: %s)" branch) "")))) (list (read-directory-name prompt nil default-directory nil)))) - (let ((modules (cvs-string->strings (cvs-get-module))) + (let ((modules (string->strings (cvs-get-module))) (flags (cvs-add-branch-prefix (cvs-flags-query 'cvs-checkout-flags "cvs checkout flags"))) (cvs-cvsroot (cvs-get-cvsroot))) @@ -2244,7 +2244,7 @@ (let* ((args (append constant-args arg-list))) (insert (format "=== %s %s\n\n" - program (cvs-strings->string args))) + program (strings->string args))) ;; FIXME: return the exit status? (apply 'call-process program nil t t args) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/progmodes/cc-mode.el --- a/lisp/progmodes/cc-mode.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/progmodes/cc-mode.el Sun Jul 15 02:05:20 2007 +0000 @@ -790,7 +790,8 @@ ;; If the buffer specifies `mode' or `eval' in its File Local Variable list ;; or on the first line, remove all occurrences. See ;; `c-postprocess-file-styles' for justification. There is no need to save - ;; point here, or even bother too much about the buffer contents. + ;; point here, or even bother too much about the buffer contents. However, + ;; DON'T mess up the kill-ring. ;; ;; Most of the code here is derived from Emacs 21.3's `hack-local-variables' ;; in files.el. @@ -819,8 +820,8 @@ (regexp-quote suffix) "$") nil t) - (beginning-of-line) - (delete-region (point) (progn (end-of-line) (point))))) + (forward-line 0) + (delete-region (point) (progn (forward-line) (point))))) ;; Delete the first line, if we've got one, in case it contains a mode spec. (unless (and lv-point @@ -828,7 +829,8 @@ (forward-line 0) (bobp))) (goto-char (point-min)) - (delete-region (point) (progn (end-of-line) (point)))))) + (unless (eobp) + (delete-region (point) (progn (forward-line) (point))))))) (defun c-postprocess-file-styles () "Function that post processes relevant file local variables in CC Mode. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/progmodes/compile.el --- a/lisp/progmodes/compile.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/progmodes/compile.el Sun Jul 15 02:05:20 2007 +0000 @@ -87,13 +87,13 @@ ;;;###autoload (defcustom compilation-mode-hook nil - "*List of hook functions run by `compilation-mode' (see `run-mode-hooks')." + "List of hook functions run by `compilation-mode' (see `run-mode-hooks')." :type 'hook :group 'compilation) ;;;###autoload (defcustom compilation-window-height nil - "*Number of lines in a compilation window. If nil, use Emacs default." + "Number of lines in a compilation window. If nil, use Emacs default." :type '(choice (const :tag "Default" nil) integer) :group 'compilation) @@ -442,7 +442,7 @@ "Overlay used to temporarily highlight compilation matches.") (defcustom compilation-error-screen-columns t - "*If non-nil, column numbers in error messages are screen columns. + "If non-nil, column numbers in error messages are screen columns. Otherwise they are interpreted as character positions, with each character occupying one column. The default is to use screen columns, which requires that the compilation @@ -453,21 +453,21 @@ :version "20.4") (defcustom compilation-read-command t - "*Non-nil means \\[compile] reads the compilation command to use. + "Non-nil means \\[compile] reads the compilation command to use. Otherwise, \\[compile] just uses the value of `compile-command'." :type 'boolean :group 'compilation) ;;;###autoload (defcustom compilation-ask-about-save t - "*Non-nil means \\[compile] asks which buffers to save before compiling. + "Non-nil means \\[compile] asks which buffers to save before compiling. Otherwise, it saves all modified buffers without asking." :type 'boolean :group 'compilation) ;;;###autoload (defcustom compilation-search-path '(nil) - "*List of directories to search for source files named in error messages. + "List of directories to search for source files named in error messages. Elements should be directory names, not file names of directories. The value nil as an element means to try the default directory." :type '(repeat (choice (const :tag "Default" nil) @@ -476,7 +476,7 @@ ;;;###autoload (defcustom compile-command "make -k " - "*Last shell command used to do a compilation; default for next compilation. + "Last shell command used to do a compilation; default for next compilation. Sometimes it is useful for files to supply local values for this variable. You might also use mode hooks to specify it in certain modes, like this: @@ -494,7 +494,7 @@ ;;;###autoload (defcustom compilation-disable-input nil - "*If non-nil, send end-of-file as compilation process input. + "If non-nil, send end-of-file as compilation process input. This only affects platforms that support asynchronous processes (see `start-process'); synchronous compilation processes never accept input." :type 'boolean @@ -605,6 +605,14 @@ (defvar compilation-error-list nil) (defvar compilation-old-error-list nil) +(defcustom compilation-auto-jump-to-first-error nil + "If non-nil, automatically jump to the first error after `compile'." + :type 'boolean) + +(defvar compilation-auto-jump-to-next nil + "If non-nil, automatically jump to the next error encountered.") +(make-variable-buffer-local 'compilation-auto-jump-to-next) + (defun compilation-face (type) (or (and (car type) (match-end (car type)) compilation-warning-face) (and (cdr type) (match-end (cdr type)) compilation-info-face) @@ -652,13 +660,18 @@ l2 (setcdr l1 (cons (list ,key) l2))))))) +(defun compilation-auto-jump (buffer pos) + (with-current-buffer buffer + (goto-char pos) + (compile-goto-error))) ;; This function is the central driver, called when font-locking to gather ;; all information needed to later jump to corresponding source code. ;; Return a property list with all meta information on this error location. (defun compilation-error-properties (file line end-line col end-col type fmt) - (unless (< (next-single-property-change (match-beginning 0) 'directory nil (point)) + (unless (< (next-single-property-change (match-beginning 0) + 'directory nil (point)) (point)) (if file (if (functionp file) @@ -710,6 +723,13 @@ (setq type (or (and (car type) (match-end (car type)) 1) (and (cdr type) (match-end (cdr type)) 0) 2))) + + (when (and compilation-auto-jump-to-next + (>= type compilation-skip-threshold)) + (kill-local-variable 'compilation-auto-jump-to-next) + (run-with-timer 0 nil 'compilation-auto-jump + (current-buffer) (match-beginning 0))) + (compilation-internal-error-properties file line end-line col end-col type fmt))) (defun compilation-move-to-column (col screen) @@ -932,7 +952,7 @@ `(,(eval compile-command)))))) (defcustom compilation-scroll-output nil - "*Non-nil to scroll the *compilation* buffer window as output appears. + "Non-nil to scroll the *compilation* buffer window as output appears. Setting it causes the Compilation mode commands to put point at the end of their output window so that the end of the output is always @@ -1026,8 +1046,9 @@ ;; Clear out the compilation buffer. (let ((inhibit-read-only t) (default-directory thisdir)) - ;; Then evaluate a cd command if any, but don't perform it yet, else start-command - ;; would do it again through the shell: (cd "..") AND sh -c "cd ..; make" + ;; Then evaluate a cd command if any, but don't perform it yet, else + ;; start-command would do it again through the shell: (cd "..") AND + ;; sh -c "cd ..; make" (cd (if (string-match "^\\s *cd\\(?:\\s +\\(\\S +?\\)\\)?\\s *[;&\n]" command) (if (match-end 1) (substitute-env-vars (match-string 1 command)) @@ -1043,6 +1064,8 @@ (if highlight-regexp (set (make-local-variable 'compilation-highlight-regexp) highlight-regexp)) + (if compilation-auto-jump-to-first-error + (set (make-local-variable 'compilation-auto-jump-to-next) t)) ;; Output a mode setter, for saving and later reloading this buffer. (insert "-*- mode: " name-of-mode "; default-directory: " (prin1-to-string default-directory) @@ -1075,7 +1098,8 @@ (unless (getenv "EMACS") (list "EMACS=t")) (list "INSIDE_EMACS=t") - (copy-sequence process-environment)))) + (copy-sequence process-environment))) + (start-process (symbol-function 'start-process))) (set (make-local-variable 'compilation-arguments) (list command mode name-function highlight-regexp)) (set (make-local-variable 'revert-buffer-function) @@ -1091,53 +1115,39 @@ (funcall compilation-process-setup-function)) (compilation-set-window-height outwin) ;; Start the compilation. - (if (fboundp 'start-process) - (let ((proc (if (eq mode t) - (get-buffer-process - (with-no-warnings - (comint-exec outbuf (downcase mode-name) - shell-file-name nil `("-c" ,command)))) - (start-process-shell-command (downcase mode-name) - outbuf command)))) - ;; Make the buffer's mode line show process state. - (setq mode-line-process '(":%s")) - (set-process-sentinel proc 'compilation-sentinel) - (set-process-filter proc 'compilation-filter) - (set-marker (process-mark proc) (point) outbuf) - (when compilation-disable-input - (condition-case nil - (process-send-eof proc) - ;; The process may have exited already. - (error nil))) - (setq compilation-in-progress - (cons proc compilation-in-progress))) - ;; No asynchronous processes available. - (message "Executing `%s'..." command) - ;; Fake modeline display as if `start-process' were run. - (setq mode-line-process ":run") - (force-mode-line-update) - (sit-for 0) ; Force redisplay - (let* ((buffer-read-only nil) ; call-process needs to modify outbuf - (status (call-process shell-file-name nil outbuf nil "-c" - command))) - (cond ((numberp status) - (compilation-handle-exit 'exit status - (if (zerop status) - "finished\n" - (format "\ -exited abnormally with code %d\n" - status)))) - ((stringp status) - (compilation-handle-exit 'signal status - (concat status "\n"))) - (t - (compilation-handle-exit 'bizarre status status)))) - ;; Without async subprocesses, the buffer is not yet - ;; fontified, so fontify it now. - (let ((font-lock-verbose nil)) ; shut up font-lock messages - (font-lock-fontify-buffer)) - (set-buffer-modified-p nil) - (message "Executing `%s'...done" command))) + (let ((proc + (if (eq mode t) + ;; comint uses `start-file-process'. + (get-buffer-process + (with-no-warnings + (comint-exec outbuf (downcase mode-name) + shell-file-name nil `("-c" ,command)))) + ;; Redefine temporarily `start-process' in order to + ;; handle remote compilation. + (fset 'start-process + (lambda (name buffer program &rest program-args) + (apply + (if (file-remote-p default-directory) + 'start-file-process + start-process) + name buffer program program-args))) + (unwind-protect + (start-process-shell-command (downcase mode-name) + outbuf command) + ;; Unwindform: Reset original definition of `start-process'. + (fset 'start-process start-process))))) + ;; Make the buffer's mode line show process state. + (setq mode-line-process '(":%s")) + (set-process-sentinel proc 'compilation-sentinel) + (set-process-filter proc 'compilation-filter) + (set-marker (process-mark proc) (point) outbuf) + (when compilation-disable-input + (condition-case nil + (process-send-eof proc) + ;; The process may have exited already. + (error nil))) + (setq compilation-in-progress + (cons proc compilation-in-progress)))) ;; Now finally cd to where the shell started make/grep/... (setq default-directory thisdir)) (if (buffer-local-value 'compilation-scroll-output outbuf) @@ -1258,7 +1268,7 @@ "*If non-nil, skip multiple error messages for the same source location.") (defcustom compilation-skip-threshold 1 - "*Compilation motion commands skip less important messages. + "Compilation motion commands skip less important messages. The value can be either 2 -- skip anything less than error, 1 -- skip anything less than warning or 0 -- don't skip any messages. Note that all messages not positively identified as warning or @@ -1270,7 +1280,7 @@ :version "22.1") (defcustom compilation-skip-visited nil - "*Compilation motion commands skip visited messages if this is t. + "Compilation motion commands skip visited messages if this is t. Visited messages are ones for which the file, line and column have been jumped to from the current content in the current compilation buffer, even if it was from a different message." @@ -1371,6 +1381,8 @@ ;; with the next-error function in simple.el, and it's only ;; coincidentally named similarly to compilation-next-error. (setq next-error-function 'compilation-next-error-function) + (set (make-local-variable 'comint-file-name-prefix) + (or (file-remote-p default-directory) "")) (set (make-local-variable 'font-lock-extra-managed-props) '(directory message help-echo mouse-face debug)) (set (make-local-variable 'compilation-locs) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/progmodes/gdb-ui.el --- a/lisp/progmodes/gdb-ui.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/progmodes/gdb-ui.el Sun Jul 15 02:05:20 2007 +0000 @@ -1765,7 +1765,7 @@ (defface breakpoint-enabled '((t - :foreground "red" + :foreground "red1" :weight bold)) "Face for enabled breakpoint icon in fringe." :group 'gud) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/progmodes/gud.el --- a/lisp/progmodes/gud.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/progmodes/gud.el Sun Jul 15 02:05:20 2007 +0000 @@ -237,7 +237,7 @@ ([menu-bar run] menu-item ,(propertize "run" 'face 'font-lock-doc-face) gud-run :visible (memq gud-minor-mode '(gdbmi gdb dbx jdb))) - ([menu-bar go] menu-item + ([menu-bar go] menu-item ,(propertize " go " 'face 'font-lock-doc-face) gud-go :visible (and (not gud-running) (eq gud-minor-mode 'gdba))) @@ -292,6 +292,11 @@ (defun gud-file-name (f) "Transform a relative file name to an absolute file name. Uses `gud--directories' to find the source files." + ;; When `default-directory' is a remote file name, prepend its + ;; remote part to f, which is the local file name. Fortunately, + ;; `file-remote-p' returns exactly this remote file name part (or + ;; nil otherwise). + (setq f (concat (or (file-remote-p default-directory) "") f)) (if (file-exists-p f) (expand-file-name f) (let ((directories (gud-val 'directories)) (result nil)) @@ -2462,7 +2467,7 @@ ;; for local variables in the debugger buffer. (defun gud-common-init (command-line massage-args marker-filter &optional find-file) - (let* ((words (split-string command-line)) + (let* ((words (string->strings command-line)) (program (car words)) (dir default-directory) ;; Extract the file name from WORDS @@ -2510,7 +2515,10 @@ (while (and w (not (eq (car w) t))) (setq w (cdr w))) (if w - (setcar w file))) + (setcar w + (if (file-remote-p default-directory) + (setq file (file-name-nondirectory file)) + file)))) (apply 'make-comint (concat "gud" filepart) program nil (if massage-args (funcall massage-args file args) args)) ;; Since comint clobbered the mode, we don't set it until now. @@ -3114,7 +3122,7 @@ 'syntax-table (eval-when-compile (string-to-syntax "> b"))) ;; Make sure that rehighlighting the previous line won't erase our - ;; syntax-table property. + ;; syntax-table property. (put-text-property (1- (match-beginning 0)) (match-end 0) 'font-lock-multiline t) nil))))) @@ -3193,8 +3201,12 @@ (goto-char (point-max))) t) +;; Besides .gdbinit, gdb documents other names to be usable for init +;; files, cross-debuggers can use something like +;; .PROCESSORNAME-gdbinit so that the host and target gdbinit files +;; don't interfere with each other. ;;;###autoload -(add-to-list 'auto-mode-alist '("/\\.gdbinit" . gdb-script-mode)) +(add-to-list 'auto-mode-alist '("/\\.[a-z0-9-]*gdbinit" . gdb-script-mode)) ;;;###autoload (define-derived-mode gdb-script-mode nil "GDB-Script" diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/progmodes/hideshow.el --- a/lisp/progmodes/hideshow.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/progmodes/hideshow.el Sun Jul 15 02:05:20 2007 +0000 @@ -508,8 +508,8 @@ (defun hs-hide-comment-region (beg end &optional repos-end) "Hide a region from BEG to END, marking it as a comment. Optional arg REPOS-END means reposition at end." - (let ((beg-eol (progn (goto-char beg) (end-of-line) (point))) - (end-eol (progn (goto-char end) (end-of-line) (point)))) + (let ((beg-eol (progn (goto-char beg) (line-end-position))) + (end-eol (progn (goto-char end) (line-end-position)))) (hs-discard-overlays beg-eol end-eol) (hs-make-overlay beg-eol end-eol 'comment beg end)) (goto-char (if repos-end end beg))) @@ -536,8 +536,7 @@ 'identity) pure-p)) ;; whatever the adjustment, we move to eol - (end-of-line) - (point))) + (line-end-position))) (q ;; `q' is the point at the end of the block (progn (hs-forward-sexp mdata 1) @@ -705,7 +704,7 @@ (if (and c-reg (nth 0 c-reg)) ;; point is inside a comment, and that comment is hidable (goto-char (nth 0 c-reg)) - (end-of-line) + (end-of-line) (when (and (not c-reg) (hs-find-block-beginning) (looking-at hs-block-start-regexp)) @@ -734,12 +733,12 @@ If `hs-hide-comments-when-hiding-all' is non-nil, also hide the comments." (interactive) (hs-life-goes-on - (message "Hiding all blocks ...") (save-excursion (unless hs-allow-nesting (hs-discard-overlays (point-min) (point-max))) (goto-char (point-min)) - (let ((count 0) + (let ((spew (make-progress-reporter "Hiding all blocks..." + (point-min) (point-max))) (re (concat "\\(" hs-block-start-regexp "\\)" @@ -765,9 +764,9 @@ (if (> (count-lines (car c-reg) (nth 1 c-reg)) 1) (hs-hide-block-at-point t c-reg) (goto-char (nth 1 c-reg)))))) - (message "Hiding ... %d" (setq count (1+ count)))))) + (progress-reporter-update spew (point))) + (progress-reporter-done spew))) (beginning-of-line) - (message "Hiding all blocks ... done") (run-hooks 'hs-hide-hook))) (defun hs-show-all () @@ -806,7 +805,7 @@ (hs-life-goes-on (or ;; first see if we have something at the end of the line - (let ((ov (hs-overlay-at (save-excursion (end-of-line) (point)))) + (let ((ov (hs-overlay-at (line-end-position))) (here (point))) (when ov (goto-char @@ -906,9 +905,9 @@ (progn (hs-grok-mode-type) ;; Turn off this mode if we change major modes. - (add-hook 'change-major-mode-hook - 'turn-off-hideshow - nil t) + (add-hook 'change-major-mode-hook + 'turn-off-hideshow + nil t) (easy-menu-add hs-minor-mode-menu) (set (make-local-variable 'line-move-ignore-invisible) t) (add-to-invisibility-spec '(hs . t))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/progmodes/python.el --- a/lisp/progmodes/python.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/progmodes/python.el Sun Jul 15 02:05:20 2007 +0000 @@ -996,7 +996,16 @@ (throw 'done t))))))) (setq arg (1- arg))) (zerop arg))) - + +(defvar python-which-func-length-limit 40 + "Non-strict length limit for `python-which-func' output.") + +(defun python-which-func () + (let ((function-name (python-current-defun python-which-func-length-limit))) + (set-text-properties 0 (length function-name) nil function-name) + function-name)) + + ;;;; Imenu. (defvar python-recursing) @@ -1814,22 +1823,30 @@ (1+ (/ (current-indentation) python-indent))) ;; Fixme: Consider top-level assignments, imports, &c. -(defun python-current-defun () +(defun python-current-defun (&optional length-limit) "`add-log-current-defun-function' for Python." (save-excursion ;; Move up the tree of nested `class' and `def' blocks until we ;; get to zero indentation, accumulating the defined names. (let ((start t) - accum) - (while (or start (> (current-indentation) 0)) + (accum) + (length -1)) + (while (and (or start (> (current-indentation) 0)) + (or (null length-limit) + (null (cdr accum)) + (< length length-limit))) (setq start nil) (python-beginning-of-block) (end-of-line) (beginning-of-defun) - (if (looking-at (rx (0+ space) (or "def" "class") (1+ space) - (group (1+ (or word (syntax symbol)))))) - (push (match-string 1) accum))) - (if accum (mapconcat 'identity accum "."))))) + (when (looking-at (rx (0+ space) (or "def" "class") (1+ space) + (group (1+ (or word (syntax symbol)))))) + (push (match-string 1) accum) + (setq length (+ length 1 (length (car accum)))))) + (when accum + (when (and length-limit (> length length-limit)) + (setcar accum "..")) + (mapconcat 'identity accum "."))))) (defun python-mark-block () "Mark the block around point. @@ -2248,6 +2265,7 @@ (set (make-local-variable 'beginning-of-defun-function) 'python-beginning-of-defun) (set (make-local-variable 'end-of-defun-function) 'python-end-of-defun) + (add-hook 'which-func-functions 'python-which-func nil t) (setq imenu-create-index-function #'python-imenu-create-index) (set (make-local-variable 'eldoc-documentation-function) #'python-eldoc-function) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/progmodes/sh-script.el --- a/lisp/progmodes/sh-script.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/progmodes/sh-script.el Sun Jul 15 02:05:20 2007 +0000 @@ -171,10 +171,6 @@ ;; disadvantages: ;; 1. We need to scan the buffer to find which ")" symbols belong to a ;; case alternative, to find any here documents, and handle "$#". -;; 2. Setting the text property makes the buffer modified. If the -;; buffer is read-only buffer we have to cheat and bypass the read-only -;; status. This is for cases where the buffer started read-only buffer -;; but the user issued `toggle-read-only'. ;; ;; Bugs ;; ---- @@ -183,6 +179,16 @@ ;; ;; - `sh-learn-buffer-indent' is extremely slow. ;; +;; - "case $x in y) echo ;; esac)" the last ) is mis-identified as being +;; part of a case-pattern. You need to add a semi-colon after "esac" to +;; coerce sh-script into doing the right thing. +;; +;; - "echo $z in ps | head)" the last ) is mis-identified as being part of +;; a case-pattern. You need to put the "in" between quotes to coerce +;; sh-script into doing the right thing. +;; +;; - A line starting with "}>foo" is not indented like "} >foo". +;; ;; Richard Sharman June 1999. ;;; Code: @@ -1052,7 +1058,18 @@ (backward-char 1)) (when (eq (char-before) ?|) (backward-char 1) t))) - (when (save-excursion (backward-char 2) (looking-at ";;\\|in")) + ;; FIXME: ";; esac )" is a case that looks like a case-pattern but it's + ;; really just a close paren after a case statement. I.e. if we skipped + ;; over `esac' just now, we're not looking at a case-pattern. + (when (progn (backward-char 2) + (if (> start (line-end-position)) + (put-text-property (point) (1+ start) + 'font-lock-multiline t)) + ;; FIXME: The `in' may just be a random argument to + ;; a normal command rather than the real `in' keyword. + ;; I.e. we should look back to try and find the + ;; corresponding `case'. + (looking-at ";;\\|in")) sh-st-punc))) (defun sh-font-lock-backslash-quote () diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/progmodes/vera-mode.el --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/progmodes/vera-mode.el Sun Jul 15 02:05:20 2007 +0000 @@ -0,0 +1,1487 @@ +;;; vera-mode.el --- major mode for editing Vera files. + +;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, +;; 2006, 2007 Free Software Foundation, Inc. + +;; Author: Reto Zimmermann +;; Maintainer: Reto Zimmermann +;; Version: 2.28 +;; Keywords: languages vera +;; WWW: http://www.iis.ee.ethz.ch/~zimmi/emacs/vera-mode.html + +(defconst vera-version "2.18" + "Vera Mode version number.") + +(defconst vera-time-stamp "2007-06-21" + "Vera Mode time stamp for last update.") + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 2, or (at your option) +;; any later version. + +;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Commentary: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; This package provides a simple Emacs major mode for editing Vera code. +;; It includes the following features: + +;; - Syntax highlighting +;; - Indentation +;; - Word/keyword completion +;; - Block commenting +;; - Works under GNU Emacs and XEmacs + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Documentation + +;; See comment string of function `vera-mode' or type `C-c C-h' in Emacs. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Installation + +;; Prerequisites: GNU Emacs 20.X/21.X, XEmacs 20.X/21.X + +;; Put `vera-mode.el' into the `site-lisp' directory of your Emacs installation +;; or into an arbitrary directory that is added to the load path by the +;; following line in your Emacs start-up file (`.emacs'): + +;; (setq load-path (cons (expand-file-name "") load-path)) + +;; If you already have the compiled `vera-mode.elc' file, put it in the same +;; directory. Otherwise, byte-compile the source file: +;; Emacs: M-x byte-compile-file -> vera-mode.el +;; Unix: emacs -batch -q -no-site-file -f batch-byte-compile vera-mode.el + +;; Add the following lines to the `site-start.el' file in the `site-lisp' +;; directory of your Emacs installation or to your Emacs start-up file +;; (`.emacs'): + +;; (autoload 'vera-mode "vera-mode" "Vera Mode" t) +;; (setq auto-mode-alist (cons '("\\.vr[hi]?\\'" . vera-mode) auto-mode-alist)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; Code: + +;; XEmacs handling +(defconst vera-xemacs (string-match "XEmacs" emacs-version) + "Non-nil if XEmacs is used.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Variables +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defgroup vera nil + "Customizations for Vera Mode." + :prefix "vera-" + :version "22.2" + :group 'languages) + +(defcustom vera-basic-offset 2 + "*Amount of basic offset used for indentation." + :type 'integer + :group 'vera) + +(defcustom vera-underscore-is-part-of-word nil + "*Non-nil means consider the underscore character `_' as part of word. +An identifier containing underscores is then treated as a single word in +select and move operations. All parts of an identifier separated by underscore +are treated as single words otherwise." + :type 'boolean + :group 'vera) + +(defcustom vera-intelligent-tab t + "*Non-nil means `TAB' does indentation, word completion and tab insertion. +That is, if preceding character is part of a word then complete word, +else if not at beginning of line then insert tab, +else if last command was a `TAB' or `RET' then dedent one step, +else indent current line. +If nil, TAB always indents current line." + :type 'boolean + :group 'vera) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mode definitions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Key bindings + +(defvar vera-mode-map () + "Keymap for Vera Mode.") + +(setq vera-mode-map (make-sparse-keymap)) +;; backspace/delete key bindings +(define-key vera-mode-map [backspace] 'backward-delete-char-untabify) +(unless (boundp 'delete-key-deletes-forward) ; XEmacs variable + (define-key vera-mode-map [delete] 'delete-char) + (define-key vera-mode-map [(meta delete)] 'kill-word)) +;; standard key bindings +(define-key vera-mode-map "\M-e" 'vera-forward-statement) +(define-key vera-mode-map "\M-a" 'vera-backward-statement) +(define-key vera-mode-map "\M-\C-e" 'vera-forward-same-indent) +(define-key vera-mode-map "\M-\C-a" 'vera-backward-same-indent) +;; mode specific key bindings +(define-key vera-mode-map "\C-c\t" 'indent-according-to-mode) +(define-key vera-mode-map "\M-\C-\\" 'vera-indent-region) +(define-key vera-mode-map "\C-c\C-c" 'vera-comment-uncomment-region) +(define-key vera-mode-map "\C-c\C-f" 'vera-fontify-buffer) +(define-key vera-mode-map "\C-c\C-v" 'vera-version) +(define-key vera-mode-map "\M-\t" 'tab-to-tab-stop) +;; electric key bindings +(define-key vera-mode-map "\t" 'vera-electric-tab) +(define-key vera-mode-map "\r" 'vera-electric-return) +(define-key vera-mode-map " " 'vera-electric-space) +(define-key vera-mode-map "{" 'vera-electric-opening-brace) +(define-key vera-mode-map "}" 'vera-electric-closing-brace) +(define-key vera-mode-map "#" 'vera-electric-pound) +(define-key vera-mode-map "*" 'vera-electric-star) +(define-key vera-mode-map "/" 'vera-electric-slash) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Menu + +(require 'easymenu) + +(easy-menu-define vera-mode-menu vera-mode-map + "Menu keymap for Vera Mode." + '("Vera" + ["(Un)Comment Out Region" vera-comment-uncomment-region (mark)] + "--" + ["Move Forward Statement" vera-forward-statement t] + ["Move Backward Statement" vera-backward-statement t] + ["Move Forward Same Indent" vera-forward-same-indent t] + ["Move Backward Same Indent" vera-backward-same-indent t] + "--" + ["Indent Line" indent-according-to-mode t] + ["Indent Region" vera-indent-region (mark)] + ["Indent Buffer" vera-indent-buffer t] + "--" + ["Fontify Buffer" vera-fontify-buffer t] + "--" + ["Documentation" describe-mode] + ["Version" vera-version t] + ["Bug Report..." vera-submit-bug-report t] + "--" + ("Options" + ["Indentation Offset..." (customize-option 'vera-basic-offset) t] + ["Underscore is Part of Word" + (customize-set-variable 'vera-underscore-is-part-of-word + (not vera-underscore-is-part-of-word)) + :style toggle :selected vera-underscore-is-part-of-word] + ["Use Intelligent Tab" + (customize-set-variable 'vera-intelligent-tab + (not vera-intelligent-tab)) + :style toggle :selected vera-intelligent-tab] + "--" + ["Save Options" customize-save-customized t] + "--" + ["Customize..." vera-customize t]))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Syntax table + +(defvar vera-mode-syntax-table + (let ((syntax-table (make-syntax-table))) + ;; punctuation + (modify-syntax-entry ?\# "." syntax-table) + (modify-syntax-entry ?\$ "." syntax-table) + (modify-syntax-entry ?\% "." syntax-table) + (modify-syntax-entry ?\& "." syntax-table) + (modify-syntax-entry ?\' "." syntax-table) + (modify-syntax-entry ?\* "." syntax-table) + (modify-syntax-entry ?\- "." syntax-table) + (modify-syntax-entry ?\+ "." syntax-table) + (modify-syntax-entry ?\. "." syntax-table) + (modify-syntax-entry ?\/ "." syntax-table) + (modify-syntax-entry ?\: "." syntax-table) + (modify-syntax-entry ?\; "." syntax-table) + (modify-syntax-entry ?\< "." syntax-table) + (modify-syntax-entry ?\= "." syntax-table) + (modify-syntax-entry ?\> "." syntax-table) + (modify-syntax-entry ?\\ "." syntax-table) + (modify-syntax-entry ?\| "." syntax-table) + ;; string + (modify-syntax-entry ?\" "\"" syntax-table) + ;; underscore + (when vera-underscore-is-part-of-word + (modify-syntax-entry ?\_ "w" syntax-table)) + ;; escape + (modify-syntax-entry ?\\ "\\" syntax-table) + ;; parentheses to match + (modify-syntax-entry ?\( "()" syntax-table) + (modify-syntax-entry ?\) ")(" syntax-table) + (modify-syntax-entry ?\[ "(]" syntax-table) + (modify-syntax-entry ?\] ")[" syntax-table) + (modify-syntax-entry ?\{ "(}" syntax-table) + (modify-syntax-entry ?\} "){" syntax-table) + ;; comment + (if vera-xemacs + (modify-syntax-entry ?\/ ". 1456" syntax-table) ; XEmacs + (modify-syntax-entry ?\/ ". 124b" syntax-table)) ; Emacs + (modify-syntax-entry ?\* ". 23" syntax-table) + ;; newline and CR + (modify-syntax-entry ?\n "> b" syntax-table) + (modify-syntax-entry ?\^M "> b" syntax-table) + syntax-table) + "Syntax table used in `vera-mode' buffers.") + +(defvar vera-mode-ext-syntax-table + (let ((syntax-table (copy-syntax-table vera-mode-syntax-table))) + ;; extended syntax table including '_' (for simpler search regexps) + (modify-syntax-entry ?_ "w" syntax-table) + syntax-table) + "Syntax table extended by `_' used in `vera-mode' buffers.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Mode definition + +;;;###autoload (add-to-list 'auto-mode-alist '("\\.vr[hi]?\\'" . vera-mode)) + +;;;###autoload +(defun vera-mode () + "Major mode for editing Vera code. + +Usage: +------ + + INDENTATION: Typing `TAB' at the beginning of a line indents the line. + The amount of indentation is specified by option `vera-basic-offset'. + Indentation can be done for an entire region \(`M-C-\\') or buffer (menu). + `TAB' always indents the line if option `vera-intelligent-tab' is nil. + + WORD/COMMAND COMPLETION: Typing `TAB' after a (not completed) word looks + for a word in the buffer or a Vera keyword that starts alike, inserts it + and adjusts case. Re-typing `TAB' toggles through alternative word + completions. + + Typing `TAB' after a non-word character inserts a tabulator stop (if not + at the beginning of a line). `M-TAB' always inserts a tabulator stop. + + COMMENTS: `C-c C-c' comments out a region if not commented out, and + uncomments a region if already commented out. + + HIGHLIGHTING (fontification): Vera keywords, predefined types and + constants, function names, declaration names, directives, as well as + comments and strings are highlighted using different colors. + + VERA VERSION: OpenVera 1.4 and Vera version 6.2.8. + + +Maintenance: +------------ + +To submit a bug report, use the corresponding menu entry within Vera Mode. +Add a description of the problem and include a reproducible test case. + +Feel free to send questions and enhancement requests to . + +Official distribution is at +. + + + The Vera Mode Maintainer + Reto Zimmermann + +Key bindings: +------------- + +\\{vera-mode-map}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'vera-mode) + (setq mode-name "Vera") + ;; set maps and tables + (use-local-map vera-mode-map) + (set-syntax-table vera-mode-syntax-table) + ;; set local variables + (require 'cc-cmds) + (set (make-local-variable 'comment-start) "//") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'comment-column) 40) + (set (make-local-variable 'comment-start-skip) "/\\*+ *\\|//+ *") + (set (make-local-variable 'comment-end-skip) " *\\*+/\\| *\n") + (set (make-local-variable 'comment-indent-function) 'c-comment-indent) + (set (make-local-variable 'paragraph-start) "^$") + (set (make-local-variable 'paragraph-separate) paragraph-start) + (set (make-local-variable 'require-final-newline) t) + (set (make-local-variable 'indent-tabs-mode) nil) + (set (make-local-variable 'indent-line-function) 'vera-indent-line) + (set (make-local-variable 'parse-sexp-ignore-comments) t) + ;; initialize font locking + (set (make-local-variable 'font-lock-defaults) + '(vera-font-lock-keywords nil nil ((?\_ . "w")))) + ;; add menu (XEmacs) + (easy-menu-add vera-mode-menu) + ;; miscellaneous + (message "Vera Mode %s. Type C-c C-h for documentation." vera-version) + ;; run hooks + (run-hooks 'vera-mode-hook)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Vera definitions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Keywords + +(defconst vera-keywords + '( + "after" "all" "any" "around" "assoc_index" "assoc_size" "async" + "bad_state" "bad_trans" "before" "begin" "big_endian" "bind" + "bin_activation" "bit_normal" "bit_reverse" "break" "breakpoint" + "case" "casex" "casez" "class" "constraint" "continue" + "coverage" "coverage_block" "coverage_def" "coverage_depth" + "coverage_goal" "coverage_group" "coverage_option" "coverage_val" + "cross_num_print_missing" "cross_auto_bin_max" "cov_comment" + "default" "depth" "dist" "do" + "else" "end" "enum" "exhaustive" "export" "extends" "extern" + "for" "foreach" "fork" "function" + "hdl_task" "hdl_node" "hide" + "if" "illegal_self_transition" "illegal_state" "illegal_transition" + "in" "interface" "invisible" + "join" + "little_endian" "local" + "m_bad_state" "m_bad_trans" "m_state" "m_trans" + "negedge" "new" "newcov" "non_rand" "none" "not" "null" + "or" "ordered" + "packed" "port" "posedge" "proceed" "prod" "prodget" "prodset" + "program" "protected" "public" + "rand" "randc" "randcase" "randseq" "repeat" "return" "rules" + "sample" "sample_event" "shadow" "soft" "state" "static" "super" + "task" "terminate" "this" "trans" "typedef" + "unpacked" + "var" "vca" "vector" "verilog_node" "verilog_task" + "vhdl_node" "vhdl_task" "virtual" "virtuals" "visible" "void" + "while" "wildcard" "with" + ) + "List of Vera keywords.") + +(defconst vera-types + '( + "integer" "bit" "reg" "string" "bind_var" "event" + "inout" "input" "output" + "ASYNC" "CLOCK" + "NDRIVE" "NHOLD" "NRX" "NRZ" "NR0" "NR1" "NSAMPLE" + "PDRIVE" "PHOLD" "PRX" "PRZ" "PR0" "PR1" "PSAMPLE" + ) + "List of Vera predefined types.") + +(defconst vera-q-values + '( + "gnr" "grx" "grz" "gr0" "gr1" + "nr" "rx" "rz" "r0" "r1" + "snr" "srx" "srz" "sr0" "sr1" + ) + "List of Vera predefined VCA q_values.") + +(defconst vera-functions + '( + ;; system functions and tasks + "alloc" + "call_func" "call_task" "cast_assign" "close_conn" "cm_coverage" + "cm_get_coverage" "cm_get_limit" + "coverage_backup_database_file" "coverage_save_database" + "delay" + "error" "error_mode" "error_wait" "exit" + "fclose" "feof" "ferror" "fflush" "flag" "fopen" "fprintf" "freadb" + "freadb" "freadh" "freadstr" + "get_bind" "get_bind_id" "get_conn_err" "get_cycle" "get_env" + "get_memsize" "get_plus_arg" "get_systime" "get_time" "get_time_unit" + "getstate" + "initstate" + "lock_file" + "mailbox_get" "mailbox_put" "mailbox_receive" "mailbox_send" + "make_client" "make_server" + "os_command" + "printf" "psprintf" + "query" "query_str" "query_x" + "rand48" "random" "region_enter" "region_exit" "rewind" + "semaphore_get" "semaphore_put" "setstate" "signal_connect" "simwave_plot" + "srandom" "sprintf" "sscanf" "stop" "suspend_thread" "sync" + "timeout" "trace" "trigger" + "unit_delay" "unlock_file" "up_connections" + "urand48" "urandom" "urandom_range" + "vera_bit_reverse" "vera_crc" "vera_pack" "vera_pack_big_endian" + "vera_plot" "vera_report_profile" "vera_unpack" "vera_unpack_big_endian" + "vsv_call_func" "vsv_call_task" "vsv_close_conn" "vsv_get_conn_err" + "vsv_make_client" "vsv_make_server" "vsv_up_connections" + "vsv_wait_for_done" "vsv_wait_for_input" + "wait_child" "wait_var" + ;; class methods + "Configure" "DisableTrigger" "DoAction" "EnableCount" "EnableTrigger" + "Event" "GetAssert" "GetCount" "GetFirstAssert" "GetName" "GetNextAssert" + "Wait" + "atobin" "atohex" "atoi" "atooct" + "backref" "bittostr" "capacity" "compare" "constraint_mode" + "delete" + "empty" + "find" "find_index" "first" "first_index" + "get_at_least" "get_auto_bin" "get_cov_weight" "get_coverage_goal" + "get_cross_bin_max" "get_status" "get_status_msg" "getc" + "hash" + "icompare" "insert" "inst_get_at_least" "inst_get_auto_bin_max" + "inst_get_collect" "inst_get_cov_weight" "inst_get_coverage_goal" + "inst_getcross_bin_max" "inst_query" "inst_set_at_least" + "inst_set_auto_bin_max" "inst_set_bin_activiation" "inst_set_collect" + "inst_set_cov_weight" "inst_set_coverage_goal" "inst_set_cross_bin_max" + "itoa" + "last" "last_index" "len" "load" + "match" "max" "max_index" "min" "min_index" + "object_compare" "object_copy" "object_print" + "pack" "pick_index" "pop_back" "pop_front" "post_pack" "post_randomize" + "post_unpack" "postmatch" "pre_pack" "pre_randomize" "prematch" "push_back" + "push_front" "putc" + "query" "query_str" + "rand_mode" "randomize" "reserve" "reverse" "rsort" + "search" "set_at_least" "set_auto_bin_max" "set_bin_activiation" + "set_cov_weight" "set_coverage_goal" "set_cross_bin_max" "set_name" "size" + "sort" "substr" "sum" + "thismatch" "tolower" "toupper" + "unique_index" "unpack" + ;; empty methods + "new" "object_compare" + "post_boundary" "post_pack" "post_randomize" "post_unpack" "pre-randomize" + "pre_boundary" "pre_pack" "pre_unpack" + ) + "List of Vera predefined system functions, tasks and class methods.") + +(defconst vera-constants + '( + "ALL" "ANY" + "BAD_STATE" "BAD_TRANS" + "CALL" "CHECK" "CHGEDGE" "CLEAR" "COPY_NO_WAIT" "COPY_WAIT" + "CROSS" "CROSS_TRANS" + "DEBUG" "DELETE" + "EC_ARRAYX" "EC_CODE_END" "EC_CONFLICT" "EC_EVNTIMOUT" "EC_EXPECT" + "EC_FULLEXPECT" "EC_MBXTMOUT" "EC_NEXPECT" "EC_RETURN" "EC_RGNTMOUT" + "EC_SCONFLICT" "EC_SEMTMOUT" "EC_SEXPECT" "EC_SFULLEXPECT" "EC_SNEXTPECT" + "EC_USERSET" "EQ" "EVENT" + "FAIL" "FIRST" "FORK" + "GE" "GOAL" "GT" "HAND_SHAKE" "HI" "HIGH" "HNUM" + "LE" "LIC_EXIT" "LIC_PRERR" "LIC_PRWARN" "LIC_WAIT" "LO" "LOAD" "LOW" "LT" + "MAILBOX" "MAX_COM" + "NAME" "NE" "NEGEDGE" "NEXT" "NO_OVERLAP" "NO_OVERLAP_STATE" + "NO_OVERLAP_TRANS" "NO_VARS" "NO_WAIT" "NUM" "NUM_BIN" "NUM_DET" + "OFF" "OK" "OK_LAST" "ON" "ONE_BLAST" "ONE_SHOT" "ORDER" + "PAST_IT" "PERCENT" "POSEDGE" "PROGRAM" + "RAWIN" "REGION" "REPORT" + "SAMPLE" "SAVE" "SEMAPHORE" "SET" "SILENT" "STATE" "STR" + "STR_ERR_OUT_OF_RANGE" "STR_ERR_REGEXP_SYNTAX" "SUM" + "TRANS" + "VERBOSE" + "WAIT" + "stderr" "stdin" "stdout" + ) + "List of Vera predefined constants.") + +(defconst vera-rvm-types + '( + "VeraListIterator_VeraListIterator_rvm_log" + "VeraListIterator_rvm_data" "VeraListIterator_rvm_log" + "VeraListNodeVeraListIterator_rvm_log" "VeraListNodervm_data" + "VeraListNodervm_log" "VeraList_VeraListIterator_rvm_log" + "VeraList_rvm_data" "VeraList_rvm_log" + "rvm_broadcast" "rvm_channel_class" "rvm_data" "rvm_data" "rvm_env" + "rvm_log" "rvm_log_modifier" "rvm_log_msg" "rvm_log_msg" "rvm_log_msg_info" + "rvm_log_watchpoint" "rvm_notify" "rvm_notify_event" + "rvm_notify_event_config" "rvm_scheduler" "rvm_scheduler_election" + "rvm_watchdog" "rvm_watchdog_port" "rvm_xactor" "rvm_xactor_callbacks" + ) + "List of Vera-RVM keywords.") + +(defconst vera-rvm-functions + '( + "extern_rvm_atomic_gen" "extern_rvm_channel" "extern_rvm_scenario_gen" + "rvm_OO_callback" "rvm_atomic_gen" "rvm_atomic_gen_callbacks_decl" + "rvm_atomic_gen_decl" "rvm_atomic_scenario_decl" "rvm_channel" + "rvm_channel_" "rvm_channel_decl" "rvm_command" "rvm_cycle" "rvm_debug" + "rvm_error" "rvm_fatal" "rvm_note" "rvm_protocol" "rvm_report" + "rvm_scenario_decl" "rvm_scenario_election_decl" "rvm_scenario_gen" + "rvm_scenario_gen_callbacks_decl" "rvm_scenario_gen_decl" + "rvm_trace" "rvm_transaction" "rvm_user" "rvm_verbose" "rvm_warning" + ) + "List of Vera-RVM functions.") + +(defconst vera-rvm-constants + '( + "RVM_NUMERIC_VERSION_MACROS" "RVM_VERSION" "RVM_MINOR" "RVM_PATCH" + "rvm_channel__SOURCE" "rvm_channel__SINK" "rvm_channel__NO_ACTIVE" + "rvm_channel__ACT_PENDING" "rvm_channel__ACT_STARTED" + "rvm_channel__ACT_COMPLETED" "rvm_channel__FULL" "rvm_channel__EMPTY" + "rvm_channel__PUT" "rvm_channel__GOT" "rvm_channel__PEEKED" + "rvm_channel__ACTIVATED" "rvm_channel__STARTED" "rvm_channel__COMPLETED" + "rvm_channel__REMOVED" "rvm_channel__LOCKED" "rvm_channel__UNLOCKED" + "rvm_data__EXECUTE" "rvm_data__STARTED" "rvm_data__ENDED" + "rvm_env__CFG_GENED" "rvm_env__BUILT" "rvm_env__DUT_CFGED" + "rvm_env__STARTED" "rvm_env__RESTARTED" "rvm_env__ENDED" "rvm_env__STOPPED" + "rvm_env__CLEANED" "rvm_env__DONE" "rvm_log__DEFAULT" "rvm_log__UNCHANGED" + "rvm_log__FAILURE_TYP" "rvm_log__NOTE_TYP" "rvm_log__DEBUG_TYP" + "rvm_log__REPORT_TYP" "rvm_log__NOTIFY_TYP" "rvm_log__TIMING_TYP" + "rvm_log__XHANDLING_TYP" "rvm_log__PROTOCOL_TYP" "rvm_log__TRANSACTION_TYP" + "rvm_log__COMMAND_TYP" "rvm_log__CYCLE_TYP" "rvm_log__USER_TYP_0" + "rvm_log__USER_TYP_1" "rvm_log__USER_TYP_2" "rvm_log__USER_TYP_3" + "rvm_log__DEFAULT_TYP" "rvm_log__ALL_TYPES" "rvm_log__FATAL_SEV" + "rvm_log__ERROR_SEV" "rvm_log__WARNING_SEV" "rvm_log__NORMAL_SEV" + "rvm_log__TRACE_SEV" "rvm_log__DEBUG_SEV" "rvm_log__VERBOSE_SEV" + "rvm_log__HIDDEN_SEV" "rvm_log__IGNORE_SEV" "rvm_log__DEFAULT_SEV" + "rvm_log__ALL_SEVERITIES" "rvm_log__CONTINUE" "rvm_log__COUNT_AS_ERROR" + "rvm_log__DEBUGGER" "rvm_log__DUMP" "rvm_log__STOP" "rvm_log__ABORT" + "rvm_notify__ONE_SHOT_TRIGGER" "rvm_notify__ONE_BLAST_TRIGGER" + "rvm_notify__HAND_SHAKE_TRIGGER" "rvm_notify__ON_OFF_TRIGGER" + "rvm_xactor__XACTOR_IDLE" "rvm_xactor__XACTOR_BUSY" + "rvm_xactor__XACTOR_STARTED" "rvm_xactor__XACTOR_STOPPED" + "rvm_xactor__XACTOR_RESET" "rvm_xactor__XACTOR_SOFT_RST" + "rvm_xactor__XACTOR_FIRM_RST" "rvm_xactor__XACTOR_HARD_RST" + "rvm_xactor__XACTOR_PROTOCOL_RST" "rvm_broadcast__AFAP" + "rvm_broadcast__ALAP" "rvm_watchdog__TIMEOUT" + "rvm_env__DUT_RESET" "rvm_log__INTERNAL_TYP" + "RVM_SCHEDULER_IS_XACTOR" "RVM_BROADCAST_IS_XACTOR" + ) + "List of Vera-RVM predefined constants.") + +;; `regexp-opt' undefined (`xemacs-devel' not installed) +(unless (fboundp 'regexp-opt) + (defun regexp-opt (strings &optional paren) + (let ((open (if paren "\\(" "")) (close (if paren "\\)" ""))) + (concat open (mapconcat 'regexp-quote strings "\\|") close)))) + +(defconst vera-keywords-regexp + (concat "\\<\\(" (regexp-opt vera-keywords) "\\)\\>") + "Regexp for Vera keywords.") + +(defconst vera-types-regexp + (concat "\\<\\(" (regexp-opt vera-types) "\\)\\>") + "Regexp for Vera predefined types.") + +(defconst vera-q-values-regexp + (concat "\\<\\(" (regexp-opt vera-q-values) "\\)\\>") + "Regexp for Vera predefined VCA q_values.") + +(defconst vera-functions-regexp + (concat "\\<\\(" (regexp-opt vera-functions) "\\)\\>") + "Regexp for Vera predefined system functions, tasks and class methods.") + +(defconst vera-constants-regexp + (concat "\\<\\(" (regexp-opt vera-constants) "\\)\\>") + "Regexp for Vera predefined constants.") + +(defconst vera-rvm-types-regexp + (concat "\\<\\(" (regexp-opt vera-rvm-types) "\\)\\>") + "Regexp for Vera-RVM keywords.") + +(defconst vera-rvm-functions-regexp + (concat "\\<\\(" (regexp-opt vera-rvm-functions) "\\)\\>") + "Regexp for Vera-RVM predefined system functions, tasks and class methods.") + +(defconst vera-rvm-constants-regexp + (concat "\\<\\(" (regexp-opt vera-rvm-constants) "\\)\\>") + "Regexp for Vera-RVM predefined constants.") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Font locking +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; XEmacs compatibility +(when vera-xemacs + (require 'font-lock) + (copy-face 'font-lock-reference-face 'font-lock-constant-face) + (copy-face 'font-lock-preprocessor-face 'font-lock-builtin-face)) + +(defun vera-font-lock-match-item (limit) + "Match, and move over, any declaration item after point. +Adapted from `font-lock-match-c-style-declaration-item-and-skip-to-next'." + (condition-case nil + (save-restriction + (narrow-to-region (point-min) limit) + ;; match item + (when (looking-at "\\s-*\\(\\w+\\)") + (save-match-data + (goto-char (match-end 1)) + ;; move to next item + (if (looking-at "\\(\\s-*\\(\\[[^]]*\\]\\s-*\\)?,\\)") + (goto-char (match-end 1)) + (end-of-line) t)))) + (error t))) + +(defvar vera-font-lock-keywords + (list + ;; highlight keywords + (list vera-keywords-regexp 1 'font-lock-keyword-face) + ;; highlight types + (list vera-types-regexp 1 'font-lock-type-face) + ;; highlight RVM types + (list vera-rvm-types-regexp 1 'font-lock-type-face) + ;; highlight constants + (list vera-constants-regexp 1 'font-lock-constant-face) + ;; highlight RVM constants + (list vera-rvm-constants-regexp 1 'font-lock-constant-face) + ;; highlight q_values + (list vera-q-values-regexp 1 'font-lock-constant-face) + ;; highlight predefined functions, tasks and methods + (list vera-functions-regexp 1 'vera-font-lock-function) + ;; highlight predefined RVM functions + (list vera-rvm-functions-regexp 1 'vera-font-lock-function) + ;; highlight functions + '("\\<\\(\\w+\\)\\s-*(" 1 font-lock-function-name-face) + ;; highlight various declaration names + '("^\\s-*\\(port\\|program\\|task\\)\\s-+\\(\\w+\\)\\>" + 2 font-lock-function-name-face) + '("^\\s-*bind\\s-+\\(\\w+\\)\\s-+\\(\\w+\\)\\>" + (1 font-lock-function-name-face) (2 font-lock-function-name-face)) + ;; highlight interface declaration names + '("^\\s-*\\(class\\|interface\\)\\s-+\\(\\w+\\)\\>" + 2 vera-font-lock-interface) + ;; highlight variable name definitions + (list (concat "^\\s-*" vera-types-regexp "\\s-*\\(\\[[^]]+\\]\\s-+\\)?") + '(vera-font-lock-match-item nil nil (1 font-lock-variable-name-face))) + (list (concat "^\\s-*" vera-rvm-types-regexp "\\s-*\\(\\[[^]]+\\]\\s-+\\)?") + '(vera-font-lock-match-item nil nil (1 font-lock-variable-name-face))) + ;; highlight numbers + '("\\([0-9]*'[bdoh][0-9a-fA-FxXzZ_]+\\)" 1 vera-font-lock-number) + ;; highlight filenames in #include directives + '("^#\\s-*include\\s-*\\(<[^>\"\n]*>?\\)" + 1 font-lock-string-face) + ;; highlight directives and directive names + '("^#\\s-*\\(\\w+\\)\\>[ \t!]*\\(\\w+\\)?" + (1 font-lock-builtin-face) (2 font-lock-variable-name-face nil t)) + ;; highlight `@', `$' and `#' + '("\\([@$#]\\)" 1 font-lock-keyword-face) + ;; highlight @ and # definitions + '("@\\s-*\\(\\w*\\)\\(\\s-*,\\s-*\\(\\w+\\)\\)?\\>[^.]" + (1 vera-font-lock-number) (3 vera-font-lock-number nil t)) + ;; highlight interface signal name + '("\\(\\w+\\)\\.\\w+" 1 vera-font-lock-interface) + ) + "Regular expressions to highlight in Vera Mode.") + +(defvar vera-font-lock-number 'vera-font-lock-number + "Face name to use for @ definitions.") + +(defvar vera-font-lock-function 'vera-font-lock-function + "Face name to use for predefined functions and tasks.") + +(defvar vera-font-lock-interface 'vera-font-lock-interface + "Face name to use for interface names.") + +(defface vera-font-lock-number + '((((class color) (background light)) (:foreground "Gold4")) + (((class color) (background dark)) (:foreground "BurlyWood1")) + (t (:italic t :bold t))) + "Font lock mode face used to highlight @ definitions." + :group 'font-lock-highlighting-faces) + +(defface vera-font-lock-function + '((((class color) (background light)) (:foreground "DarkCyan")) + (((class color) (background dark)) (:foreground "Orchid1")) + (t (:italic t :bold t))) + "Font lock mode face used to highlight predefined functions and tasks." + :group 'font-lock-highlighting-faces) + +(defface vera-font-lock-interface + '((((class color) (background light)) (:foreground "Grey40")) + (((class color) (background dark)) (:foreground "Grey80")) + (t (:italic t :bold t))) + "Font lock mode face used to highlight interface names." + :group 'font-lock-highlighting-faces) + +(defalias 'vera-fontify-buffer 'font-lock-fontify-buffer) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Indentation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar vera-echo-syntactic-information-p nil + "If non-nil, syntactic info is echoed when the line is indented.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; offset functions + +(defconst vera-offsets-alist + '((comment . vera-lineup-C-comments) + (comment-intro . vera-lineup-comment) + (string . -1000) + (directive . -1000) + (block-open . 0) + (block-intro . +) + (block-close . 0) + (arglist-intro . +) + (arglist-cont . +) + (arglist-cont-nonempty . 0) + (arglist-close . 0) + (statement . 0) + (statement-cont . +) + (substatement . +) + (else-clause . 0)) + "Association list of syntactic element symbols and indentation offsets. +Adapted from `c-offsets-alist'.") + +(defun vera-evaluate-offset (offset langelem symbol) + "OFFSET can be a number, a function, a variable, a list, or one of +the symbols + or -." + (cond + ((eq offset '+) (setq offset vera-basic-offset)) + ((eq offset '-) (setq offset (- vera-basic-offset))) + ((eq offset '++) (setq offset (* 2 vera-basic-offset))) + ((eq offset '--) (setq offset (* 2 (- vera-basic-offset)))) + ((eq offset '*) (setq offset (/ vera-basic-offset 2))) + ((eq offset '/) (setq offset (/ (- vera-basic-offset) 2))) + ((functionp offset) (setq offset (funcall offset langelem))) + ((listp offset) + (setq offset + (let (done) + (while (and (not done) offset) + (setq done (vera-evaluate-offset (car offset) langelem symbol) + offset (cdr offset))) + (if (not done) + 0 + done)))) + ((not (numberp offset)) (setq offset (symbol-value offset)))) + offset) + +(defun vera-get-offset (langelem) + "Get offset from LANGELEM which is a cons cell of the form: +\(SYMBOL . RELPOS). The symbol is matched against +vera-offsets-alist and the offset found there is either returned, +or added to the indentation at RELPOS. If RELPOS is nil, then +the offset is simply returned." + (let* ((symbol (car langelem)) + (relpos (cdr langelem)) + (match (assq symbol vera-offsets-alist)) + (offset (cdr-safe match))) + (if (not match) + (setq offset 0 + relpos 0) + (setq offset (vera-evaluate-offset offset langelem symbol))) + (+ (if (and relpos + (< relpos (save-excursion (beginning-of-line) (point)))) + (save-excursion + (goto-char relpos) + (current-column)) + 0) + (vera-evaluate-offset offset langelem symbol)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; help functions + +(defsubst vera-point (position) + "Return the value of point at certain commonly referenced POSITIONs. +POSITION can be one of the following symbols: + bol -- beginning of line + eol -- end of line + boi -- back to indentation + ionl -- indentation of next line + iopl -- indentation of previous line + bonl -- beginning of next line + bopl -- beginning of previous line +This function does not modify point or mark." + (save-excursion + (cond + ((eq position 'bol) (beginning-of-line)) + ((eq position 'eol) (end-of-line)) + ((eq position 'boi) (back-to-indentation)) + ((eq position 'bonl) (forward-line 1)) + ((eq position 'bopl) (forward-line -1)) + ((eq position 'iopl) (forward-line -1) (back-to-indentation)) + ((eq position 'ionl) (forward-line 1) (back-to-indentation)) + (t (error "Unknown buffer position requested: %s" position))) + (point))) + +(defun vera-in-literal (&optional lim) + "Determine if point is in a Vera literal." + (save-excursion + (let ((state (parse-partial-sexp (or lim (point-min)) (point)))) + (cond + ((nth 3 state) 'string) + ((nth 4 state) 'comment) + (t nil))))) + +(defun vera-skip-forward-literal () + "Skip forward literal and return t if within one." + (let ((state (save-excursion + (if (fboundp 'syntax-ppss) + (syntax-ppss) + (parse-partial-sexp (point-min) (point)))))) + (when (nth 8 state) + ;; Inside a string or comment. + (goto-char (nth 8 state)) + (if (nth 3 state) + ;; A string. + (condition-case nil (forward-sexp 1) + ;; Can't find end of string: it extends til end of buffer. + (error (goto-char (point-max)))) + ;; A comment. + (forward-comment 1)) + t))) + +(defun vera-skip-backward-literal () + "Skip backward literal and return t if within one." + (let ((state (save-excursion + (if (fboundp 'syntax-ppss) + (syntax-ppss) + (parse-partial-sexp (point-min) (point)))))) + (when (nth 8 state) + ;; Inside a string or comment. + (goto-char (nth 8 state)) + t))) + +(defsubst vera-re-search-forward (regexp &optional bound noerror) + "Like `re-search-forward', but skips over matches in literals." + (store-match-data '(nil nil)) + (while (and (re-search-forward regexp bound noerror) + (vera-skip-forward-literal) + (progn (store-match-data '(nil nil)) + (if bound (< (point) bound) t)))) + (match-end 0)) + +(defsubst vera-re-search-backward (regexp &optional bound noerror) + "Like `re-search-backward', but skips over matches in literals." + (store-match-data '(nil nil)) + (while (and (re-search-backward regexp bound noerror) + (vera-skip-backward-literal) + (progn (store-match-data '(nil nil)) + (if bound (> (point) bound) t)))) + (match-end 0)) + +(defun vera-forward-syntactic-ws (&optional lim skip-directive) + "Forward skip of syntactic whitespace." + (save-restriction + (let* ((lim (or lim (point-max))) + (here lim) + (hugenum (point-max))) + (narrow-to-region (point) lim) + (while (/= here (point)) + (setq here (point)) + (forward-comment hugenum) + (when (and skip-directive (looking-at "^\\s-*#")) + (end-of-line)))))) + +(defun vera-backward-syntactic-ws (&optional lim skip-directive) + "Backward skip over syntactic whitespace." + (save-restriction + (let* ((lim (or lim (point-min))) + (here lim) + (hugenum (- (point-max)))) + (when (< lim (point)) + (narrow-to-region lim (point)) + (while (/= here (point)) + (setq here (point)) + (forward-comment hugenum) + (when (and skip-directive + (save-excursion (back-to-indentation) + (= (following-char) ?\#))) + (beginning-of-line))))))) + +(defmacro vera-prepare-search (&rest body) + "Execute BODY with a syntax table that includes '_'." + `(with-syntax-table vera-mode-ext-syntax-table ,@body)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; comment indentation functions + +(defsubst vera-langelem-col (langelem &optional preserve-point) + "Convenience routine to return the column of LANGELEM's relpos. +Leaves point at the relpos unless PRESERVE-POINT is non-nil." + (let ((here (point))) + (goto-char (cdr langelem)) + (prog1 (current-column) + (if preserve-point + (goto-char here))))) + +(defun vera-lineup-C-comments (langelem) + "Line up C block comment continuation lines. +Nicked from `c-lineup-C-comments'." + (save-excursion + (let ((here (point)) + (stars (progn (back-to-indentation) + (skip-chars-forward "*"))) + (langelem-col (vera-langelem-col langelem))) + (back-to-indentation) + (if (not (re-search-forward "/\\([*]+\\)" (vera-point 'eol) t)) + (progn + (if (not (looking-at "[*]+")) + (progn + ;; we now have to figure out where this comment begins. + (goto-char here) + (back-to-indentation) + (if (looking-at "[*]+/") + (progn (goto-char (match-end 0)) + (forward-comment -1)) + (goto-char (cdr langelem)) + (back-to-indentation)))) + (- (current-column) langelem-col)) + (if (zerop stars) + (progn + (skip-chars-forward " \t") + (- (current-column) langelem-col)) + ;; how many stars on comment opening line? if greater than + ;; on current line, align left. if less than or equal, + ;; align right. this should also pick up Javadoc style + ;; comments. + (if (> (length (match-string 1)) stars) + (progn + (back-to-indentation) + (- (current-column) -1 langelem-col)) + (- (current-column) stars langelem-col))))))) + +(defun vera-lineup-comment (langelem) + "Line up a comment start." + (save-excursion + (back-to-indentation) + (if (bolp) + ;; not indent if at beginning of line + -1000 + ;; otherwise indent accordingly + (goto-char (cdr langelem)) + (current-column)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; move functions + +(defconst vera-beg-block-re "{\\|\\<\\(begin\\|fork\\)\\>") + +(defconst vera-end-block-re "}\\|\\<\\(end\\|join\\(\\s-+\\(all\\|any\\|none\\)\\)?\\)\\>") + +(defconst vera-beg-substatement-re "\\<\\(else\\|for\\|if\\|repeat\\|while\\)\\>") + +(defun vera-corresponding-begin (&optional recursive) + "Find corresponding block begin if cursor is at a block end." + (while (and (vera-re-search-backward + (concat "\\(" vera-end-block-re "\\)\\|" vera-beg-block-re) + nil t) + (match-string 1)) + (vera-corresponding-begin t)) + (unless recursive (vera-beginning-of-substatement))) + +(defun vera-corresponding-if () + "Find corresponding `if' if cursor is at `else'." + (while (and (vera-re-search-backward "}\\|\\<\\(if\\|else\\)\\>" nil t) + (not (equal (match-string 0) "if"))) + (if (equal (match-string 0) "else") + (vera-corresponding-if) + (forward-char) + (backward-sexp)))) + +(defun vera-beginning-of-statement () + "Go to beginning of current statement." + (let (pos) + (while + (progn + ;; search for end of previous statement + (while + (and (vera-re-search-backward + (concat "[);]\\|" vera-beg-block-re + "\\|" vera-end-block-re) nil t) + (equal (match-string 0) ")")) + (forward-char) + (backward-sexp)) + (setq pos (match-beginning 0)) + ;; go back to beginning of current statement + (goto-char (or (match-end 0) 0)) + (vera-forward-syntactic-ws nil t) + (when (looking-at "(") + (forward-sexp) + (vera-forward-syntactic-ws nil t)) + ;; if "else" found, go to "if" and search again + (when (looking-at "\\") + (vera-corresponding-if) + (setq pos (point)) + t)) + ;; if search is repeated, go to beginning of last search + (goto-char pos)))) + +(defun vera-beginning-of-substatement () + "Go to beginning of current substatement." + (let ((lim (point)) + pos) + ;; go to beginning of statement + (vera-beginning-of-statement) + (setq pos (point)) + ;; go forward all substatement opening statements until at LIM + (while (and (< (point) lim) + (vera-re-search-forward vera-beg-substatement-re lim t)) + (setq pos (match-beginning 0))) + (vera-forward-syntactic-ws nil t) + (when (looking-at "(") + (forward-sexp) + (vera-forward-syntactic-ws nil t)) + (when (< (point) lim) + (setq pos (point))) + (goto-char pos))) + +(defun vera-forward-statement () + "Move forward one statement." + (interactive) + (vera-prepare-search + (while (and (vera-re-search-forward + (concat "[(;]\\|" vera-beg-block-re "\\|" vera-end-block-re) + nil t) + (equal (match-string 0) "(")) + (backward-char) + (forward-sexp)) + (vera-beginning-of-substatement))) + +(defun vera-backward-statement () + "Move backward one statement." + (interactive) + (vera-prepare-search + (vera-backward-syntactic-ws nil t) + (unless (= (preceding-char) ?\)) + (backward-char)) + (vera-beginning-of-substatement))) + +(defun vera-forward-same-indent () + "Move forward to next line with same indent." + (interactive) + (let ((pos (point)) + (indent (current-indentation))) + (beginning-of-line 2) + (while (and (not (eobp)) + (or (looking-at "^\\s-*$") + (> (current-indentation) indent))) + (beginning-of-line 2)) + (if (= (current-indentation) indent) + (back-to-indentation) + (message "No following line with same indent found in this block") + (goto-char pos)))) + +(defun vera-backward-same-indent () + "Move backward to previous line with same indent." + (interactive) + (let ((pos (point)) + (indent (current-indentation))) + (beginning-of-line -0) + (while (and (not (bobp)) + (or (looking-at "^\\s-*$") + (> (current-indentation) indent))) + (beginning-of-line -0)) + (if (= (current-indentation) indent) + (back-to-indentation) + (message "No preceding line with same indent found in this block") + (goto-char pos)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; syntax analysis + +(defmacro vera-add-syntax (symbol &optional relpos) + "A simple macro to append the syntax in SYMBOL to the syntax list. +try to increase performance by using this macro." + `(setq syntax (cons (cons ,symbol ,(or relpos 0)) syntax))) + +(defun vera-guess-basic-syntax () + "Determine syntactic context of current line of code." + (save-excursion + (beginning-of-line) + (let ((indent-point (point)) + syntax state placeholder pos) + ;; determine syntax state + (setq state (parse-partial-sexp (point-min) (point))) + (cond + ;; CASE 1: in a comment? + ((nth 4 state) + ;; skip empty lines + (while (and (zerop (forward-line -1)) + (looking-at "^\\s-*$"))) + (vera-add-syntax 'comment (vera-point 'boi))) + ;; CASE 2: in a string? + ((nth 3 state) + (vera-add-syntax 'string)) + ;; CASE 3: at a directive? + ((save-excursion (back-to-indentation) (= (following-char) ?\#)) + (vera-add-syntax 'directive (point))) + ;; CASE 4: after an opening parenthesis (argument list continuation)? + ((and (nth 1 state) + (or (= (char-after (nth 1 state)) ?\() + ;; also for concatenation (opening '{' and ',' on eol/eopl) + (and (= (char-after (nth 1 state)) ?\{) + (or (save-excursion + (vera-backward-syntactic-ws) (= (char-before) ?,)) + (save-excursion + (end-of-line) (= (char-before) ?,)))))) + (goto-char (1+ (nth 1 state))) + ;; is there code after the opening parenthesis on the same line? + (if (looking-at "\\s-*$") + (vera-add-syntax 'arglist-cont (vera-point 'boi)) + (vera-add-syntax 'arglist-cont-nonempty (point)))) + ;; CASE 5: at a block closing? + ((save-excursion (back-to-indentation) (looking-at vera-end-block-re)) + ;; look for the corresponding begin + (vera-corresponding-begin) + (vera-add-syntax 'block-close (vera-point 'boi))) + ;; CASE 6: at a block intro (the first line after a block opening)? + ((and (save-excursion + (vera-backward-syntactic-ws nil t) + ;; previous line ends with a block opening? + (or (/= (skip-chars-backward "{") 0) (backward-word 1)) + (when (looking-at vera-beg-block-re) + ;; go to beginning of substatement + (vera-beginning-of-substatement) + (setq placeholder (point)))) + ;; not if "fork" is followed by "{" + (save-excursion + (not (and (progn (back-to-indentation) (looking-at "{")) + (progn (goto-char placeholder) + (looking-at "\\")))))) + (goto-char placeholder) + (vera-add-syntax 'block-intro (vera-point 'boi))) + ;; CASE 7: at the beginning of an else clause? + ((save-excursion (back-to-indentation) (looking-at "\\")) + ;; find corresponding if + (vera-corresponding-if) + (vera-add-syntax 'else-clause (vera-point 'boi))) + ;; CASE 8: at the beginning of a statement? + ;; is the previous command completed? + ((or (save-excursion + (vera-backward-syntactic-ws nil t) + (setq placeholder (point)) + ;; at the beginning of the buffer? + (or (bobp) + ;; previous line ends with a semicolon or + ;; is a block opening or closing? + (when (or (/= (skip-chars-backward "{};") 0) + (progn (back-to-indentation) + (looking-at (concat vera-beg-block-re "\\|" + vera-end-block-re)))) + ;; if at a block closing, go to beginning + (when (looking-at vera-end-block-re) + (vera-corresponding-begin)) + ;; go to beginning of the statement + (vera-beginning-of-statement) + (setq placeholder (point))) + ;; at a directive? + (when (progn (back-to-indentation) (looking-at "#")) + ;; go to previous statement + (vera-beginning-of-statement) + (setq placeholder (point))))) + ;; at a block opening? + (when (save-excursion (back-to-indentation) + (looking-at vera-beg-block-re)) + ;; go to beginning of the substatement + (vera-beginning-of-substatement) + (setq placeholder (point)))) + (goto-char placeholder) + (vera-add-syntax 'statement (vera-point 'boi))) + ;; CASE 9: at the beginning of a substatement? + ;; is this line preceded by a substatement opening statement? + ((save-excursion (vera-backward-syntactic-ws nil t) + (when (= (preceding-char) ?\)) (backward-sexp)) + (backward-word 1) + (setq placeholder (point)) + (looking-at vera-beg-substatement-re)) + (goto-char placeholder) + (vera-add-syntax 'substatement (vera-point 'boi))) + ;; CASE 10: it must be a statement continuation! + (t + ;; go to beginning of statement + (vera-beginning-of-substatement) + (vera-add-syntax 'statement-cont (vera-point 'boi)))) + ;; special case: look for a comment start + (goto-char indent-point) + (skip-chars-forward " \t") + (when (looking-at comment-start) + (vera-add-syntax 'comment-intro)) + ;; return syntax + syntax))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; indentation functions + +(defun vera-indent-line () + "Indent the current line as Vera code. +Return the amount of indentation change (in columns)." + (interactive) + (vera-prepare-search + (let* ((syntax (vera-guess-basic-syntax)) + (pos (- (point-max) (point))) + (indent (apply '+ (mapcar 'vera-get-offset syntax))) + (shift-amt (- (current-indentation) indent))) + (when vera-echo-syntactic-information-p + (message "syntax: %s, indent= %d" syntax indent)) + (unless (zerop shift-amt) + (beginning-of-line) + (delete-region (point) (vera-point 'boi)) + (indent-to indent)) + (if (< (point) (vera-point 'boi)) + (back-to-indentation) + ;; If initial point was within line's indentation, position after + ;; the indentation. Else stay at same point in text. + (when (> (- (point-max) pos) (point)) + (goto-char (- (point-max) pos)))) + shift-amt))) + +(defun vera-indent-buffer () + "Indent whole buffer as Vera code. +Calls `indent-region' for whole buffer." + (interactive) + (message "Indenting buffer...") + (indent-region (point-min) (point-max) nil) + (message "Indenting buffer...done")) + +(defun vera-indent-region (start end column) + "Indent region as Vera code." + (interactive "r\nP") + (message "Indenting region...") + (indent-region start end column) + (message "Indenting region...done")) + +(defsubst vera-indent-block-closing () + "If previous word is a block closing or `else', indent line again." + (when (= (char-syntax (preceding-char)) ?w) + (save-excursion + (backward-word 1) + (when (and (not (vera-in-literal)) + (looking-at (concat vera-end-block-re "\\|\\"))) + (indent-according-to-mode))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; electrifications + +(defun vera-electric-tab (&optional prefix-arg) + "Do what I mean (indent, expand, tab, change indent, etc..). +If preceding character is part of a word or a paren then `hippie-expand', +else if right of non whitespace on line then `tab-to-tab-stop', +else if last command was a tab or return then dedent one step or if a comment +toggle between normal indent and inline comment indent, +else indent `correctly'. +If `vera-intelligent-tab' is nil, always indent line." + (interactive "*P") + (if vera-intelligent-tab + (progn + (cond ((memq (char-syntax (preceding-char)) '(?w ?_)) + (let ((case-fold-search t) + (case-replace nil) + (hippie-expand-only-buffers + (or (and (boundp 'hippie-expand-only-buffers) + hippie-expand-only-buffers) + '(vera-mode)))) + (vera-expand-abbrev prefix-arg))) + ((> (current-column) (current-indentation)) + (tab-to-tab-stop)) + ((and (or (eq last-command 'vera-electric-tab) + (eq last-command 'vera-electric-return)) + (/= 0 (current-indentation))) + (backward-delete-char-untabify vera-basic-offset nil)) + (t (indent-according-to-mode))) + (setq this-command 'vera-electric-tab)) + (indent-according-to-mode))) + +(defun vera-electric-return () + "Insert newline and indent. Indent current line if it is a block closing." + (interactive) + (vera-indent-block-closing) + (newline-and-indent)) + +(defun vera-electric-space (arg) + "Insert a space. Indent current line if it is a block closing." + (interactive "*P") + (unless arg + (vera-indent-block-closing)) + (self-insert-command (prefix-numeric-value arg))) + +(defun vera-electric-opening-brace (arg) + "Outdent opening brace." + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + (unless arg + (indent-according-to-mode))) + +(defun vera-electric-closing-brace (arg) + "Outdent closing brace." + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + (unless arg + (indent-according-to-mode))) + +(defun vera-electric-pound (arg) + "Insert `#' and indent as directive it first character of line." + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + (unless arg + (save-excursion + (backward-char) + (skip-chars-backward " \t") + (when (bolp) + (delete-horizontal-space))))) + +(defun vera-electric-star (arg) + "Insert a star character. Nicked from `c-electric-star'." + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + (if (and (not arg) + (memq (vera-in-literal) '(comment)) + (eq (char-before) ?*) + (save-excursion + (forward-char -1) + (skip-chars-backward "*") + (if (eq (char-before) ?/) + (forward-char -1)) + (skip-chars-backward " \t") + (bolp))) + (indent-according-to-mode))) + +(defun vera-electric-slash (arg) + "Insert a slash character. Nicked from `c-electric-slash'." + (interactive "*P") + (let* ((ch (char-before)) + (indentp (and (not arg) + (eq last-command-char ?/) + (or (and (eq ch ?/) + (not (vera-in-literal))) + (and (eq ch ?*) + (vera-in-literal)))))) + (self-insert-command (prefix-numeric-value arg)) + (when indentp + (indent-according-to-mode)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Miscellaneous +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Hippie expand customization (for expansion of Vera commands) + +(defvar vera-abbrev-list + (append (list nil) vera-keywords + (list nil) vera-types + (list nil) vera-functions + (list nil) vera-constants + (list nil) vera-rvm-types + (list nil) vera-rvm-functions + (list nil) vera-rvm-constants) + "Predefined abbreviations for Vera.") + +(defvar vera-expand-upper-case nil) + +(eval-when-compile (require 'hippie-exp)) + +(defun vera-try-expand-abbrev (old) + "Try expanding abbreviations from `vera-abbrev-list'." + (unless old + (he-init-string (he-dabbrev-beg) (point)) + (setq he-expand-list + (let ((abbrev-list vera-abbrev-list) + (sel-abbrev-list '())) + (while abbrev-list + (when (or (not (stringp (car abbrev-list))) + (string-match + (concat "^" he-search-string) (car abbrev-list))) + (setq sel-abbrev-list + (cons (car abbrev-list) sel-abbrev-list))) + (setq abbrev-list (cdr abbrev-list))) + (nreverse sel-abbrev-list)))) + (while (and he-expand-list + (or (not (stringp (car he-expand-list))) + (he-string-member (car he-expand-list) he-tried-table t))) + (unless (stringp (car he-expand-list)) + (setq vera-expand-upper-case (car he-expand-list))) + (setq he-expand-list (cdr he-expand-list))) + (if (null he-expand-list) + (progn (when old (he-reset-string)) + nil) + (he-substitute-string + (if vera-expand-upper-case + (upcase (car he-expand-list)) + (car he-expand-list)) + t) + (setq he-expand-list (cdr he-expand-list)) + t)) + +;; function for expanding abbrevs and dabbrevs +(defalias 'vera-expand-abbrev + (make-hippie-expand-function '(try-expand-dabbrev + try-expand-dabbrev-all-buffers + vera-try-expand-abbrev))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Comments + +(defun vera-comment-uncomment-region (beg end &optional arg) + "Comment region if not commented, uncomment region if already commented." + (interactive "r\nP") + (goto-char beg) + (if (looking-at comment-start-skip) + (comment-region beg end '(4)) + (comment-region beg end))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Help functions + +(defun vera-customize () + "Call the customize function with `vera' as argument." + (interactive) + (customize-group 'vera)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Other + +;; remove ".vr" from `completion-ignored-extensions' +(setq completion-ignored-extensions + (delete ".vr" completion-ignored-extensions)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Bug reports +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defconst vera-mode-help-address "Reto Zimmermann " + "Address for Vera Mode bug reports.") + +;; get reporter-submit-bug-report when byte-compiling +(eval-when-compile + (require 'reporter)) + +(defun vera-submit-bug-report () + "Submit via mail a bug report on Vera Mode." + (interactive) + ;; load in reporter + (and + (y-or-n-p "Do you want to submit a report on Vera Mode? ") + (require 'reporter) + (let ((reporter-prompt-for-summary-p t)) + (reporter-submit-bug-report + vera-mode-help-address + (concat "Vera Mode " vera-version) + (list + ;; report all important variables + 'vera-basic-offset + 'vera-underscore-is-part-of-word + 'vera-intelligent-tab + ) + nil nil + "Hi Reto,")))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Documentation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun vera-version () + "Echo the current version of Vera Mode in the minibuffer." + (interactive) + (message "Vera Mode %s (%s)" vera-version vera-time-stamp)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(provide 'vera-mode) + +;; arch-tag: 22eae722-7ac5-47ac-a713-c4db1cf623a9 +;;; vera-mode.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/progmodes/which-func.el --- a/lisp/progmodes/which-func.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/progmodes/which-func.el Sun Jul 15 02:05:20 2007 +0000 @@ -76,8 +76,8 @@ :version "20.3") (defcustom which-func-modes - '(emacs-lisp-mode c-mode c++-mode perl-mode cperl-mode makefile-mode - sh-mode fortran-mode f90-mode ada-mode) + '(emacs-lisp-mode c-mode c++-mode perl-mode cperl-mode python-mode + makefile-mode sh-mode fortran-mode f90-mode ada-mode) "List of major modes for which Which Function mode should be used. For other modes it is disabled. If this is equal to t, then Which Function mode is enabled in any major mode that supports it." diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/ps-mule.el --- a/lisp/ps-mule.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/ps-mule.el Sun Jul 15 02:05:20 2007 +0000 @@ -1581,5 +1581,9 @@ (provide 'ps-mule) -;;; arch-tag: bca017b2-66a7-4e59-8584-103e749eadbe +;; Local Variables: +;; generated-autoload-file: "ps-print.el" +;; End: + +;; arch-tag: bca017b2-66a7-4e59-8584-103e749eadbe ;;; ps-mule.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/ps-print.el --- a/lisp/ps-print.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/ps-print.el Sun Jul 15 02:05:20 2007 +0000 @@ -3702,7 +3702,7 @@ ;; ps-page-dimensions-database ;; ps-font-info-database -;;; ps-print - end of settings\n") +\;;; ps-print - end of settings\n") "\n"))) @@ -7031,16 +7031,71 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; To make this file smaller, some commands go in a separate file. ;; But autoload them here to make the separation invisible. - -(autoload 'ps-mule-prepare-ascii-font "ps-mule" - "Setup special ASCII font for STRING. -STRING should contain only ASCII characters.") - -(autoload 'ps-mule-set-ascii-font "ps-mule" - "Adjust current font if current charset is not ASCII.") - -(autoload 'ps-mule-plot-string "ps-mule" - "Generate PostScript code for plotting characters in the region FROM and TO. + +;;;### (autoloads (ps-mule-begin-page ps-mule-begin-job ps-mule-encode-header-string +;;;;;; ps-mule-initialize ps-mule-plot-composition ps-mule-plot-string +;;;;;; ps-mule-set-ascii-font ps-mule-prepare-ascii-font ps-multibyte-buffer) +;;;;;; "ps-mule" "ps-mule.el" "464a9fb9d59f7561a46bcd5ca87d85db") +;;; Generated autoloads from ps-mule.el + +(defvar ps-multibyte-buffer nil "\ +*Specifies the multi-byte buffer handling. + +Valid values are: + + nil This is the value to use the default settings which + is by default for printing buffer with only ASCII + and Latin characters. The default setting can be + changed by setting the variable + `ps-mule-font-info-database-default' differently. + The initial value of this variable is + `ps-mule-font-info-database-latin' (see + documentation). + + `non-latin-printer' This is the value to use when you have a Japanese + or Korean PostScript printer and want to print + buffer with ASCII, Latin-1, Japanese (JISX0208 and + JISX0201-Kana) and Korean characters. At present, + it was not tested the Korean characters printing. + If you have a korean PostScript printer, please, + test it. + + `bdf-font' This is the value to use when you want to print + buffer with BDF fonts. BDF fonts include both latin + and non-latin fonts. BDF (Bitmap Distribution + Format) is a format used for distributing X's font + source file. BDF fonts are included in + `intlfonts-1.2' which is a collection of X11 fonts + for all characters supported by Emacs. In order to + use this value, be sure to have installed + `intlfonts-1.2' and set the variable + `bdf-directory-list' appropriately (see ps-bdf.el for + documentation of this variable). + + `bdf-font-except-latin' This is like `bdf-font' except that it is used + PostScript default fonts to print ASCII and Latin-1 + characters. This is convenient when you want or + need to use both latin and non-latin characters on + the same buffer. See `ps-font-family', + `ps-header-font-family' and `ps-font-info-database'. + +Any other value is treated as nil.") + +(custom-autoload (quote ps-multibyte-buffer) "ps-mule" t) + +(autoload (quote ps-mule-prepare-ascii-font) "ps-mule" "\ +Setup special ASCII font for STRING. +STRING should contain only ASCII characters. + +\(fn STRING)" nil nil) + +(autoload (quote ps-mule-set-ascii-font) "ps-mule" "\ +Not documented + +\(fn)" nil nil) + +(autoload (quote ps-mule-plot-string) "ps-mule" "\ +Generate PostScript code for plotting characters in the region FROM and TO. It is assumed that all characters in this region belong to the same charset. @@ -7051,27 +7106,54 @@ (ENDPOS . RUN-WIDTH) Where ENDPOS is the end position of the sequence and RUN-WIDTH is the width of -the sequence.") - -(autoload 'ps-mule-initialize "ps-mule" - "Initialize global data for printing multi-byte characters.") - -(autoload 'ps-mule-begin-job "ps-mule" - "Start printing job for multi-byte chars between FROM and TO. -This checks if all multi-byte characters in the region are printable or not.") - -(autoload 'ps-mule-begin-page "ps-mule" - "Initialize multi-byte charset for printing current page.") - -(autoload 'ps-mule-encode-header-string "ps-mule" - "Generate PostScript code for plotting characters in header STRING. - -It is assumed that the length of STRING is not zero.") - +the sequence. + +\(fn FROM TO &optional BG-COLOR)" nil nil) + +(autoload (quote ps-mule-plot-composition) "ps-mule" "\ +Generate PostScript code for plotting composition in the region FROM and TO. + +It is assumed that all characters in this region belong to the same +composition. + +Optional argument BG-COLOR specifies background color. + +Returns the value: + + (ENDPOS . RUN-WIDTH) + +Where ENDPOS is the end position of the sequence and RUN-WIDTH is the width of +the sequence. + +\(fn FROM TO &optional BG-COLOR)" nil nil) + +(autoload (quote ps-mule-initialize) "ps-mule" "\ +Initialize global data for printing multi-byte characters. + +\(fn)" nil nil) + +(autoload (quote ps-mule-encode-header-string) "ps-mule" "\ +Generate PostScript code for ploting STRING by font FONTTAG. +FONTTAG should be a string \"/h0\" or \"/h1\". + +\(fn STRING FONTTAG)" nil nil) + +(autoload (quote ps-mule-begin-job) "ps-mule" "\ +Start printing job for multi-byte chars between FROM and TO. +This checks if all multi-byte characters in the region are printable or not. + +\(fn FROM TO)" nil nil) + +(autoload (quote ps-mule-begin-page) "ps-mule" "\ +Not documented + +\(fn)" nil nil) + +;;;*** ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (provide 'ps-print) -;;; arch-tag: fb06a585-1112-4206-885d-a57d95d50579 +;; arch-tag: fb06a585-1112-4206-885d-a57d95d50579 ;;; ps-print.el ends here diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/replace.el --- a/lisp/replace.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/replace.el Sun Jul 15 02:05:20 2007 +0000 @@ -860,7 +860,7 @@ (defface match '((((class color) (min-colors 88) (background light)) - :background "yellow") + :background "yellow1") (((class color) (min-colors 88) (background dark)) :background "RoyalBlue3") (((class color) (min-colors 8) (background light)) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/ruler-mode.el --- a/lisp/ruler-mode.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/ruler-mode.el Sun Jul 15 02:05:20 2007 +0000 @@ -29,7 +29,7 @@ ;;; Commentary: ;; This library provides a minor mode to display a ruler in the header -;; line. It works only on Emacs 21. +;; line. It works from Emacs 21 onwards. ;; ;; You can use the mouse to change the `fill-column' `comment-column', ;; `goal-column', `window-margins' and `tab-stop-list' settings: @@ -562,7 +562,8 @@ (progn ;; When `ruler-mode' is on save previous header line format ;; and install the ruler header line format. - (when (local-variable-p 'header-line-format) + (when (and (local-variable-p 'header-line-format) + (not (local-variable-p 'ruler-mode-header-line-format-old))) (set (make-local-variable 'ruler-mode-header-line-format-old) header-line-format)) (setq header-line-format ruler-mode-header-line-format) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/shell.el --- a/lisp/shell.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/shell.el Sun Jul 15 02:05:20 2007 +0000 @@ -5,7 +5,7 @@ ;; Author: Olin Shivers ;; Simon Marshall -;; Maintainer: FSF +;; Maintainer: FSF ;; Keywords: processes ;; This file is part of GNU Emacs. @@ -27,11 +27,6 @@ ;;; Commentary: -;; Please send me bug reports, bug fixes, and extensions, so that I can -;; merge them into the master source. -;; - Olin Shivers (shivers@cs.cmu.edu) -;; - Simon Marshall (simon@gnu.org) - ;; This file defines a shell-in-a-buffer package (shell mode) built on ;; top of comint mode. This is actually cmushell with things renamed ;; to replace its counterpart in Emacs 18. cmushell is more diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/simple.el --- a/lisp/simple.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/simple.el Sun Jul 15 02:05:20 2007 +0000 @@ -144,6 +144,15 @@ :group 'next-error :version "22.1") +(defcustom next-error-recenter nil + "*Display the line in the visited source file recentered as specified. +If non-nil, the value is passed directly to `recenter'." + :type '(choice (integer :tag "Line to recenter to") + (const :tag "Center of window" (4)) + (const :tag "No recentering" nil)) + :group 'next-error + :version "23.1") + (defcustom next-error-hook nil "*List of hook functions run by `next-error' after visiting source file." :type 'hook @@ -293,6 +302,8 @@ ;; we know here that next-error-function is a valid symbol we can funcall (with-current-buffer next-error-last-buffer (funcall next-error-function (prefix-numeric-value arg) reset) + (when next-error-recenter + (recenter next-error-recenter)) (run-hooks 'next-error-hook)))) (defun next-error-internal () @@ -301,6 +312,8 @@ ;; we know here that next-error-function is a valid symbol we can funcall (with-current-buffer next-error-last-buffer (funcall next-error-function 0 nil) + (when next-error-recenter + (recenter next-error-recenter)) (run-hooks 'next-error-hook))) (defalias 'goto-next-locus 'next-error) @@ -2177,6 +2190,18 @@ (when stderr-file (delete-file stderr-file)) (when lc (delete-file lc))))) +(defun start-file-process (name buffer program &rest program-args) + "Start a program in a subprocess. Return the process object for it. +Similar to `start-process', but may invoke a file handler based on +`default-directory'. The current working directory of the +subprocess is `default-directory'. + +PROGRAM and PROGRAM-ARGS might be file names. They are not +objects of file handler invocation." + (let ((fh (find-file-name-handler default-directory 'start-file-process))) + (if fh (apply fh 'start-file-process name buffer program program-args) + (apply 'start-process name buffer program program-args)))) + (defvar universal-argument-map @@ -5238,10 +5263,10 @@ ;;;; Keypad support. -;;; Make the keypad keys act like ordinary typing keys. If people add -;;; bindings for the function key symbols, then those bindings will -;;; override these, so this shouldn't interfere with any existing -;;; bindings. +;; Make the keypad keys act like ordinary typing keys. If people add +;; bindings for the function key symbols, then those bindings will +;; override these, so this shouldn't interfere with any existing +;; bindings. ;; Also tell read-char how to handle these keys. (mapc diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/speedbar.el --- a/lisp/speedbar.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/speedbar.el Sun Jul 15 02:05:20 2007 +0000 @@ -10,7 +10,7 @@ "The current version of speedbar.") (defvar speedbar-incompatible-version "0.14beta4" "This version of speedbar is incompatible with this version. -Due to massive API changes (removing the use of the word PATH) +Due to massive API changes (removing the use of the word PATH) this version is not backward compatible to 0.14 or earlier.") ;; This file is part of GNU Emacs. @@ -915,7 +915,7 @@ (looking-at "[0-9]+: *\\[[+-]\\] [^ \n]+ \\*?[!#]$"))] ) "Additional menu items while in file-mode.") - + (defvar speedbar-easymenu-definition-trailer (append (if (and (featurep 'custom) (fboundp 'custom-declare-variable)) @@ -958,13 +958,13 @@ (defalias 'speedbar-make-overlay (if (featurep 'xemacs) 'make-extent 'make-overlay)) -(defalias 'speedbar-overlay-put +(defalias 'speedbar-overlay-put (if (featurep 'xemacs) 'set-extent-property 'overlay-put)) -(defalias 'speedbar-delete-overlay +(defalias 'speedbar-delete-overlay (if (featurep 'xemacs) 'delete-extent 'delete-overlay)) -(defalias 'speedbar-mode-line-update +(defalias 'speedbar-mode-line-update (if (featurep 'xemacs) 'redraw-modeline 'force-mode-line-update)) ;;; Mode definitions/ user commands @@ -1053,10 +1053,10 @@ "Handle a delete frame event E. If the deleted frame is the frame SPEEDBAR is attached to, we need to delete speedbar also." - (let ((frame-to-be-deleted (car (car (cdr e))))) - (if (eq frame-to-be-deleted dframe-attached-frame) - (delete-frame speedbar-frame))) - ) + (when (and speedbar-frame + (eq (car (car (cdr e))) ;; frame to be deleted + dframe-attached-frame)) + (delete-frame speedbar-frame))) ;;;###autoload (defun speedbar-get-focus () @@ -1158,7 +1158,7 @@ ;; Backwards compatibility (defalias 'speedbar-with-attached-buffer 'dframe-with-attached-buffer) (defalias 'speedbar-maybee-jump-to-attached-frame 'dframe-maybee-jump-to-attached-frame) - + (defun speedbar-set-mode-line-format () "Set the format of the mode line based on the current speedbar environment. This gives visual indications of what is up. It EXPECTS the speedbar @@ -2055,7 +2055,7 @@ (if tag-button-function 'speedbar-highlight-face nil) tag-button-function tag-button-data)) )) - + (defun speedbar-change-expand-button-char (char) "Change the expansion button character to CHAR for the current line." (save-excursion @@ -2100,7 +2100,7 @@ (defun speedbar-default-directory-list (directory index) "Insert files for DIRECTORY with level INDEX at point." - (speedbar-insert-files-at-point + (speedbar-insert-files-at-point (speedbar-file-lists directory) index) (speedbar-reset-scanners) (if (= index 0) @@ -2454,7 +2454,7 @@ (speedbar-insert-generic-list indent lst 'speedbar-tag-expand 'speedbar-tag-find)) - + (defun speedbar-insert-etags-list (indent lst) "At level INDENT, insert the etags generated LST." (speedbar-insert-generic-list indent lst @@ -2729,7 +2729,7 @@ "Go to the line where FILE is." (set-buffer speedbar-buffer) - + (goto-char (point-min)) (let ((m nil)) (while (and (setq m (re-search-forward @@ -3220,7 +3220,7 @@ (widen) (let ((rf (speedbar-fetch-replacement-function 'speedbar-line-directory))) (if rf (funcall rf depth) default-directory)))) - + (defun speedbar-files-line-directory (&optional depth) "Retrieve the directoryname associated with the current line. This may require traversing backwards from DEPTH and combining the default @@ -3305,12 +3305,12 @@ (forward-char -2) (speedbar-do-function-pointer)) (error (speedbar-position-cursor-on-line))))) - + (defun speedbar-flush-expand-line () "Expand the line under the cursor and flush any cached information." (interactive) (speedbar-expand-line 1)) - + (defun speedbar-contract-line () "Contract the line under the cursor." (interactive) @@ -3559,11 +3559,11 @@ interested in." (save-selected-window - + (select-window (get-buffer-window speedbar-buffer t)) - + (set-buffer speedbar-buffer) - + (if (<= (count-lines (point-min) (point-max)) (1- (window-height (selected-window)))) ;; whole buffer fits diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/startup.el --- a/lisp/startup.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/startup.el Sun Jul 15 02:05:20 2007 +0000 @@ -1062,7 +1062,10 @@ (if (get-buffer "*scratch*") (with-current-buffer "*scratch*" (if (eq major-mode 'fundamental-mode) - (funcall initial-major-mode)))) + (funcall initial-major-mode)) + ;; Don't lose text that users type in *scratch*. + (setq buffer-offer-save t) + (auto-save-mode 1))) ;; Load library for our terminal type. ;; User init file can set term-file-prefix to nil to prevent this. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/subr.el --- a/lisp/subr.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/subr.el Sun Jul 15 02:05:20 2007 +0000 @@ -103,7 +103,7 @@ When COND yields non-nil, eval BODY forms sequentially and return value of last one, or nil if there are none. -\(fn COND BODY ...)" +\(fn COND BODY...)" (declare (indent 1) (debug t)) (list 'if cond (cons 'progn body))) @@ -112,7 +112,7 @@ When COND yields nil, eval BODY forms sequentially and return value of last one, or nil if there are none. -\(fn COND BODY ...)" +\(fn COND BODY...)" (declare (indent 1) (debug t)) (cons 'if (cons cond (cons nil body)))) @@ -510,6 +510,7 @@ (if (integerp b) (< a b) t) (if (integerp b) t + ;; string< also accepts symbols. (string< a b)))))) (dolist (p list) (funcall function (car p) (cdr p)))) @@ -1219,7 +1220,8 @@ Execution is delayed if `delay-mode-hooks' is non-nil. If `delay-mode-hooks' is nil, run `after-change-major-mode-hook' after running the mode hooks. -Major mode functions should use this." +Major mode functions should use this instead of `run-hooks' when running their +FOO-mode-hook." (if delay-mode-hooks ;; Delaying case. (dolist (hook hooks) @@ -2501,6 +2503,29 @@ (or (input-pending-p) ,@body)))))) +(defmacro condition-case-no-debug (var bodyform &rest handlers) + "Like `condition-case' except that it does not catch anything when debugging. +More specifically if `debug-on-error' is set, then it does not catch any signal." + (declare (debug condition-case) (indent 2)) + (let ((bodysym (make-symbol "body"))) + `(let ((,bodysym (lambda () ,bodyform))) + (if debug-on-error + (funcall ,bodysym) + (condition-case ,var + (funcall ,bodysym) + ,@handlers))))) + +(defmacro with-demoted-errors (&rest body) + "Run BODY and demote any errors to simple messages. +If `debug-on-error' is non-nil, run BODY without catching its errors. +This is to be used around code which is not expected to signal an error +but which should be robust in the unexpected case that an error is signalled." + (declare (debug t) (indent 0)) + (let ((err (make-symbol "err"))) + `(condition-case-no-debug ,err + (progn ,@body) + (error (message "Error: %s" ,err) nil)))) + (defmacro combine-after-change-calls (&rest body) "Execute BODY, but don't call the after-change functions till the end. If BODY makes changes in the buffer, they are recorded @@ -2535,6 +2560,20 @@ ;;;; Constructing completion tables. +(defun complete-with-action (action table string pred) + "Perform completion ACTION. +STRING is the string to complete. +TABLE is the completion table, which should not be a function. +PRED is a completion predicate. +ACTION can be one of nil, t or `lambda'." + ;; (assert (not (functionp table))) + (funcall + (cond + ((null action) 'try-completion) + ((eq action t) 'all-completions) + (t 'test-completion)) + string table pred)) + (defmacro dynamic-completion-table (fun) "Use function FUN as a dynamic completion table. FUN is called with one argument, the string for which completion is required, @@ -2556,10 +2595,7 @@ (with-current-buffer (let ((,win (minibuffer-selected-window))) (if (window-live-p ,win) (window-buffer ,win) (current-buffer))) - (cond - ((eq ,mode t) (all-completions ,string (,fun ,string) ,predicate)) - ((not ,mode) (try-completion ,string (,fun ,string) ,predicate)) - (t (test-completion ,string (,fun ,string) ,predicate))))))) + (complete-with-action ,mode (,fun ,string) ,string ,predicate))))) (defmacro lazy-completion-table (var fun) ;; We used to have `&rest args' where `args' were evaluated late (at the @@ -2684,6 +2720,18 @@ (looking-at (concat "\\(?:" regexp "\\)\\'"))))) (not (null pos)))) +(defsubst looking-at-p (regexp) + "\ +Same as `looking-at' except this function does not change the match data." + (let ((inhibit-changing-match-data t)) + (looking-at regexp))) + +(defsubst string-match-p (regexp string &optional start) + "\ +Same as `string-match' except this function does not change the match data." + (let ((inhibit-changing-match-data t)) + (string-match regexp string start))) + (defun subregexp-context-p (regexp pos &optional start) "Return non-nil if POS is in a normal subregexp context in REGEXP. A subregexp context is one where a sub-regexp can appear. @@ -2785,6 +2833,36 @@ (cons (substring string start) list))) (nreverse list))) + +;; (string->strings (strings->string X)) == X +(defun strings->string (strings &optional separator) + "Concatenate the STRINGS, adding the SEPARATOR (default \" \"). +This tries to quote the strings to avoid ambiguity such that + (string->strings (strings->string strs)) == strs +Only some SEPARATORs will work properly." + (let ((sep (or separator " "))) + (mapconcat + (lambda (str) + (if (string-match "[\\\"]" str) + (concat "\"" (replace-regexp-in-string "[\\\"]" "\\\\\\&" str) "\"") + str)) + strings sep))) + +;; (string->strings (strings->string X)) == X +(defun string->strings (string &optional separator) + "Split the STRING into a list of strings. +It understands elisp style quoting within STRING such that + (string->strings (strings->string strs)) == strs +The SEPARATOR regexp defaults to \"\\s-+\"." + (let ((sep (or separator "\\s-+")) + (i (string-match "[\"]" string))) + (if (null i) (split-string string sep t) ; no quoting: easy + (append (unless (eq i 0) (split-string (substring string 0 i) sep t)) + (let ((rfs (read-from-string string i))) + (cons (car rfs) + (string->strings (substring string (cdr rfs)) + sep))))))) + ;;;; Replacement in strings. diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/term/w32-win.el --- a/lisp/term/w32-win.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/term/w32-win.el Sun Jul 15 02:05:20 2007 +0000 @@ -1036,14 +1036,23 @@ ;;;; Function keys + ;;; make f10 activate the real menubar rather than the mini-buffer menu + ;;; navigation feature. + (defun menu-bar-open (&optional frame) + "Start key navigation of the menu bar in FRAME. + + This initially activates the first menu-bar item, and you can then navigate + with the arrow keys, select a menu entry with the Return key or cancel with + the Escape key. If FRAME has no menu bar, this function does nothing. + + If FRAME is nil or not given, use the selected frame." + (interactive "i") + (w32-send-sys-command ?\xf100 frame)) + (defun x-setup-function-keys (frame) "Setup Function Keys for w32." - ;; make f10 activate the real menubar rather than the mini-buffer menu - ;; navigation feature. (with-selected-frame frame - (define-key local-function-key-map [f10] - (lambda () - (interactive) (w32-send-sys-command ?\xf100))) + (define-key local-function-key-map [f10] 'menu-bar-open) (substitute-key-definition 'suspend-emacs 'iconify-or-deiconify-frame local-function-key-map global-map) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/textmodes/bibtex.el --- a/lisp/textmodes/bibtex.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/textmodes/bibtex.el Sun Jul 15 02:05:20 2007 +0000 @@ -34,7 +34,7 @@ ;; Major mode for editing and validating BibTeX files. ;; Usage: -;; See documentation for function bibtex-mode or type "\M-x describe-mode" +;; See documentation for `bibtex-mode' or type "M-x describe-mode" ;; when you are in BibTeX mode. ;; Todo: @@ -112,6 +112,7 @@ numerical-fields Delete delimiters around numeral fields. page-dashes Change double dashes in page field to single dash (for scribe compatibility). +whitespace Delete whitespace at the beginning and end of fields. inherit-booktitle If entry contains a crossref field and the booktitle field is empty, set the booktitle field to the content of the title field of the crossreferenced entry. @@ -123,6 +124,10 @@ delimiters Change delimiters according to variables `bibtex-field-delimiters' and `bibtex-entry-delimiters'. unify-case Change case of entry and field names. +braces Enclose parts of field entries by braces according to + `bibtex-field-braces-alist'. +strings Replace parts of field entries by string constants + according to `bibtex-field-strings-alist'. The value t means do all of the above formatting actions. The value nil means do no formatting at all." @@ -134,11 +139,35 @@ (const required-fields) (const numerical-fields) (const page-dashes) + (const whitespace) (const inherit-booktitle) (const realign) (const last-comma) (const delimiters) - (const unify-case)))) + (const unify-case) + (const braces) + (const strings)))) + +(defcustom bibtex-field-braces-alist nil + "Alist of field regexps that \\[bibtex-clean-entry] encloses by braces. +Each element has the form (FIELDS REGEXP), where FIELDS is a list +of BibTeX field names and REGEXP is a regexp. +Whitespace in REGEXP will be replaced by \"[ \\t\\n]+\"." + :group 'bibtex + :type '(repeat (list (repeat (string :tag "field name")) + (choice (regexp :tag "regexp") + (sexp :tag "sexp"))))) + +(defcustom bibtex-field-strings-alist nil + "Alist of regexps that \\[bibtex-clean-entry] replaces by string constants. +Each element has the form (FIELDS REGEXP TO-STR), where FIELDS is a list +of BibTeX field names. In FIELDS search for REGEXP, which are replaced +by the BibTeX string constant TO-STR. +Whitespace in REGEXP will be replaced by \"[ \\t\\n]+\"." + :group 'bibtex + :type '(repeat (list (repeat (string :tag "field name")) + (regexp :tag "From regexp") + (regexp :tag "To string constant")))) (defcustom bibtex-clean-entry-hook nil "List of functions to call when entry has been cleaned. @@ -899,6 +928,17 @@ (function :tag "Filter")))))))) (put 'bibtex-generate-url-list 'risky-local-variable t) +(defcustom bibtex-cite-matcher-alist + '(("\\\\cite[ \t\n]*{\\([^}]+\\)}" . 1)) + "Alist of rules to identify cited keys in a BibTeX entry. +Each rule should be of the form (REGEXP . SUBEXP), where SUBEXP +specifies which parenthesized expression in REGEXP is a cited key. +Case is significant. +Used by `bibtex-find-crossref' and for font-locking." + :group 'bibtex + :type '(repeat (cons (regexp :tag "Regexp") + (integer :tag "Number")))) + (defcustom bibtex-expand-strings nil "If non-nil, expand strings when extracting the content of a BibTeX field." :group 'bibtex @@ -1070,6 +1110,17 @@ ;; Internal Variables +(defvar bibtex-field-braces-opt nil + "Optimized value of `bibtex-field-braces-alist'. +Created by `bibtex-field-re-init'. +It is a an alist with elements (FIELD . REGEXP).") + +(defvar bibtex-field-strings-opt nil + "Optimized value of `bibtex-field-strings-alist'. +Created by `bibtex-field-re-init'. +It is a an alist with elements (FIELD RULE1 RULE2 ...), +where each RULE is (REGEXP . TO-STR).") + (defvar bibtex-pop-previous-search-point nil "Next point where `bibtex-pop-previous' starts looking for a similar entry.") @@ -1215,7 +1266,11 @@ (,(concat "^[ \t]*\\(" bibtex-field-name "\\)[ \t]*=") 1 font-lock-variable-name-face) ;; url - (bibtex-font-lock-url) (bibtex-font-lock-crossref)) + (bibtex-font-lock-url) (bibtex-font-lock-crossref) + ;; cite + ,@(mapcar (lambda (matcher) + `((lambda (bound) (bibtex-font-lock-cite ',matcher bound)))) + bibtex-cite-matcher-alist)) "*Default expressions to highlight in BibTeX mode.") (defvar bibtex-font-lock-url-regexp @@ -1223,7 +1278,7 @@ (concat "^[ \t]*" (regexp-opt (delete-dups (mapcar 'caar bibtex-generate-url-list)) t) "[ \t]*=[ \t]*") - "Regexp for `bibtex-font-lock-url'.") + "Regexp for `bibtex-font-lock-url' derived from `bibtex-generate-url-list'.") (defvar bibtex-string-empty-key nil "If non-nil, `bibtex-parse-string' accepts empty key.") @@ -1553,7 +1608,7 @@ bounds)))) (defun bibtex-reference-key-in-string (bounds) - "Return the key part of a BibTeX string defined via BOUNDS" + "Return the key part of a BibTeX string defined via BOUNDS." (buffer-substring-no-properties (nth 1 (car bounds)) (nth 2 (car bounds)))) @@ -1626,8 +1681,8 @@ (if (save-excursion (goto-char (match-end bibtex-type-in-head)) (looking-at "[ \t]*(")) - ",?[ \t\n]*)" ;; entry opened with `(' - ",?[ \t\n]*}")) ;; entry opened with `{' + ",?[ \t\n]*)" ; entry opened with `(' + ",?[ \t\n]*}")) ; entry opened with `{' bounds) (skip-chars-forward " \t\n") ;; loop over all BibTeX fields @@ -1736,7 +1791,7 @@ (< (point) pnt)) (goto-char (match-beginning bibtex-type-in-head)) (if (pos-visible-in-window-p (point)) - (sit-for 1) + (sit-for blink-matching-delay) (message "%s%s" prompt (buffer-substring-no-properties (point) (match-end bibtex-key-in-head)))))))) @@ -1801,21 +1856,19 @@ "Reinsert the Nth stretch of killed BibTeX text (field or entry). Optional arg COMMA is as in `bibtex-enclosing-field'." (unless bibtex-last-kill-command (error "BibTeX kill ring is empty")) - (let ((fun (lambda (kryp kr) ;; adapted from `current-kill' + (let ((fun (lambda (kryp kr) ; adapted from `current-kill' (car (set kryp (nthcdr (mod (- n (length (eval kryp))) (length kr)) kr)))))) (if (eq bibtex-last-kill-command 'field) (progn ;; insert past the current field (goto-char (bibtex-end-of-field (bibtex-enclosing-field comma))) - (set-mark (point)) - (message "Mark set") + (push-mark) (bibtex-make-field (funcall fun 'bibtex-field-kill-ring-yank-pointer bibtex-field-kill-ring) t nil t)) ;; insert past the current entry (bibtex-skip-to-valid-entry) - (set-mark (point)) - (message "Mark set") + (push-mark) (insert (funcall fun 'bibtex-entry-kill-ring-yank-pointer bibtex-entry-kill-ring))))) @@ -1835,6 +1888,15 @@ crossref-key bounds alternatives-there non-empty-alternative entry-list req-field-list field-list) + ;; Initialize `bibtex-field-braces-opt' and `bibtex-field-strings-opt' + ;; if necessary. + (unless bibtex-field-braces-opt + (setq bibtex-field-braces-opt + (bibtex-field-re-init bibtex-field-braces-alist 'braces))) + (unless bibtex-field-strings-opt + (setq bibtex-field-strings-opt + (bibtex-field-re-init bibtex-field-strings-alist 'strings))) + ;; identify entry type (goto-char (point-min)) (or (re-search-forward bibtex-entry-type nil t) @@ -1904,7 +1966,7 @@ deleted) ;; We have more elegant high-level functions for several - ;; tasks done by bibtex-format-entry. However, they contain + ;; tasks done by `bibtex-format-entry'. However, they contain ;; quite some redundancy compared with what we need to do ;; anyway. So for speed-up we avoid using them. @@ -1957,6 +2019,59 @@ "\\([\"{][0-9]+\\)[ \t\n]*--?[ \t\n]*\\([0-9]+[\"}]\\)"))) (replace-match "\\1-\\2")) + ;; remove whitespace at beginning and end of field + (when (memq 'whitespace format) + (goto-char beg-text) + (if (looking-at "\\([{\"]\\)[ \t\n]+") + (replace-match "\\1")) + (goto-char end-text) + (if (looking-back "[ \t\n]+\\([}\"]\\)" beg-text t) + (replace-match "\\1"))) + + ;; enclose field text by braces according to + ;; `bibtex-field-braces-alist'. + (let (case-fold-search temp) ; Case-sensitive search + (when (and (memq 'braces format) + (setq temp (cdr (assoc-string field-name + bibtex-field-braces-opt t)))) + (goto-char beg-text) + (while (re-search-forward temp end-text t) + (let ((beg (match-beginning 0)) + (bounds (bibtex-find-text-internal nil t))) + (unless (or (nth 4 bounds) ; string constant + ;; match already surrounded by braces + ;; (braces are inside field delimiters) + (and (< (point) (1- (nth 2 bounds))) + (< (1+ (nth 1 bounds)) beg) + (looking-at "}") + (save-excursion (goto-char (1- beg)) + (looking-at "{")))) + (insert "}") + (goto-char beg) + (insert "{"))))) + + ;; replace field text by BibTeX string constants according to + ;; `bibtex-field-strings-alist'. + (when (and (memq 'strings format) + (setq temp (cdr (assoc-string field-name + bibtex-field-strings-opt t)))) + (goto-char beg-text) + (dolist (re temp) + (while (re-search-forward (car re) end-text t) + (let ((bounds (save-match-data + (bibtex-find-text-internal nil t)))) + (unless (nth 4 bounds) + ;; if match not at right subfield boundary... + (if (< (match-end 0) (1- (nth 2 bounds))) + (insert " # " (bibtex-field-left-delimiter)) + (delete-char 1)) + (replace-match (cdr re)) + (goto-char (match-beginning 0)) + ;; if match not at left subfield boundary... + (if (< (1+ (nth 1 bounds)) (match-beginning 0)) + (insert (bibtex-field-right-delimiter) " # ") + (delete-backward-char 1)))))))) + ;; use book title of crossref'd entry (if (and (memq 'inherit-booktitle format) empty-field @@ -2047,6 +2162,31 @@ (if (memq 'realign format) (bibtex-fill-entry)))))) +(defun bibtex-field-re-init (regexp-alist type) + "Calculate optimized value for bibtex-regexp-TYPE-opt. +This value is based on bibtex-regexp-TYPE-alist. TYPE is 'braces or 'strings. +Return optimized value to be used by `bibtex-format-entry'." + (setq regexp-alist + (mapcar (lambda (e) + (list (car e) + (replace-regexp-in-string "[ \t\n]+" "[ \t\n]+" (nth 1 e)) + (nth 2 e))) ; nil for 'braces'. + regexp-alist)) + (let (opt-list) + ;; Loop over field names + (dolist (field (delete-dups (apply 'append (mapcar 'car regexp-alist)))) + (let (rules) + ;; Collect all matches we have for this field name + (dolist (e regexp-alist) + (if (assoc-string field (car e) t) + (push (cons (nth 1 e) (nth 2 e)) rules))) + (if (eq type 'braces) + ;; concatenate all regexps to a single regexp + (setq rules (concat "\\(?:" (mapconcat 'car rules "\\|") "\\)"))) + ;; create list of replacement rules. + (push (cons field rules) opt-list))) + opt-list)) + (defun bibtex-autokey-abbrev (string len) "Return an abbreviation of STRING with at least LEN characters. @@ -2099,7 +2239,7 @@ (<= (length name-list) (+ bibtex-autokey-names bibtex-autokey-names-stretch))) - ;; Take bibtex-autokey-names elements from beginning of name-list + ;; Take `bibtex-autokey-names' elements from beginning of name-list (setq name-list (nreverse (nthcdr (- (length name-list) bibtex-autokey-names) (nreverse name-list))) @@ -2161,7 +2301,7 @@ (setq word (match-string 0 titlestring) titlestring (substring titlestring (match-end 0))) ;; Ignore words matched by one of the elements of - ;; bibtex-autokey-titleword-ignore + ;; `bibtex-autokey-titleword-ignore' (unless (let ((lst bibtex-autokey-titleword-ignore)) (while (and lst (not (string-match (concat "\\`\\(?:" (car lst) @@ -2173,9 +2313,9 @@ (<= counter bibtex-autokey-titlewords)) (push word titlewords) (push word titlewords-extra)))) - ;; Obey bibtex-autokey-titlewords-stretch: + ;; Obey `bibtex-autokey-titlewords-stretch': ;; If by now we have processed all words in titlestring, we include - ;; titlewords-extra in titlewords. Otherwise, we ignore titlewords-extra. + ;; titlewords-extra in titlewords. Otherwise, we ignore titlewords-extra. (unless (string-match "\\b\\w+" titlestring) (setq titlewords (append titlewords-extra titlewords))) (mapconcat 'bibtex-autokey-demangle-title (nreverse titlewords) @@ -2343,7 +2483,7 @@ (push (cons key t) ref-keys))))))) (let (;; ignore @String entries because they are handled - ;; separately by bibtex-parse-strings + ;; separately by `bibtex-parse-strings' (bibtex-sort-ignore-string-entries t) bounds) (bibtex-map-entries @@ -2399,7 +2539,7 @@ (setq bibtex-strings strings)))))) (defun bibtex-strings () - "Return `bibtex-strings'. Initialize this variable if necessary." + "Return `bibtex-strings'. Initialize this variable if necessary." (if (listp bibtex-strings) bibtex-strings (bibtex-parse-strings (bibtex-string-files-init)))) @@ -2456,10 +2596,10 @@ bibtex-buffer-last-parsed-tick))) (save-restriction (widen) - ;; Output no progress messages in bibtex-parse-keys - ;; because when in y-or-n-p that can hide the question. + ;; Output no progress messages in `bibtex-parse-keys' + ;; because when in `y-or-n-p' that can hide the question. (if (and (listp (bibtex-parse-keys t)) - ;; update bibtex-strings + ;; update `bibtex-strings' (listp (bibtex-parse-strings strings-init t))) ;; remember that parsing was successful @@ -2519,28 +2659,35 @@ COMPLETIONS is an alist of strings. If point is not after the part of a word, all strings are listed. Return completion." ;; Return value is used by cleanup functions. + ;; Code inspired by `lisp-complete-symbol'. (let* ((case-fold-search t) (beg (save-excursion (re-search-backward "[ \t{\"]") (forward-char) (point))) (end (point)) - (part-of-word (buffer-substring-no-properties beg end)) - (completion (try-completion part-of-word completions))) + (pattern (buffer-substring-no-properties beg end)) + (completion (try-completion pattern completions))) (cond ((not completion) - (error "Can't find completion for `%s'" part-of-word)) + (error "Can't find completion for `%s'" pattern)) ((eq completion t) - part-of-word) - ((not (string= part-of-word completion)) + pattern) + ((not (string= pattern completion)) (delete-region beg end) (insert completion) + ;; Don't leave around a completions buffer that's out of date. + (let ((win (get-buffer-window "*Completions*" 0))) + (if win (with-selected-window win (bury-buffer)))) completion) (t - (message "Making completion list...") - (with-output-to-temp-buffer "*Completions*" - (display-completion-list (all-completions part-of-word completions) - part-of-word)) - (message "Making completion list...done") + (let ((minibuf-is-in-use + (eq (minibuffer-window) (selected-window)))) + (unless minibuf-is-in-use (message "Making completion list...")) + (with-output-to-temp-buffer "*Completions*" + (display-completion-list + (sort (all-completions pattern completions) 'string<) pattern)) + (unless minibuf-is-in-use + (message "Making completion list...done"))) nil)))) (defun bibtex-complete-string-cleanup (str compl) @@ -2562,20 +2709,25 @@ (bibtex-find-entry key t)) (message "Ref: %s" (funcall bibtex-summary-function))))) -(defun bibtex-copy-summary-as-kill () +(defun bibtex-copy-summary-as-kill (&optional arg) "Push summery of current BibTeX entry to kill ring. -Use `bibtex-summary-function' to generate summary." - (interactive) - (save-excursion - (bibtex-beginning-of-entry) - (if (looking-at bibtex-entry-maybe-empty-head) - (kill-new (message "%s" (funcall bibtex-summary-function))) - (error "No entry found")))) +Use `bibtex-summary-function' to generate summary. +If prefix ARG is non-nil push BibTeX entry's URL to kill ring +that is generated by calling `bibtex-url'." + (interactive "P") + (if arg (let ((url (bibtex-url nil t))) + (if url (kill-new (message "%s" url)) + (message "No URL known"))) + (save-excursion + (bibtex-beginning-of-entry) + (if (looking-at bibtex-entry-maybe-empty-head) + (kill-new (message "%s" (funcall bibtex-summary-function))) + (error "No entry found"))))) (defun bibtex-summary () "Return summary of current BibTeX entry. Used as default value of `bibtex-summary-function'." - ;; It would be neat to customize this function. How? + ;; It would be neat to make this function customizable. How? (if (looking-at bibtex-entry-maybe-empty-head) (let* ((bibtex-autokey-name-case-convert-function 'identity) (bibtex-autokey-name-length 'infty) @@ -2664,16 +2816,17 @@ (unless (looking-at field-reg) (re-search-backward field-reg nil t)))) -(defun bibtex-font-lock-url (bound) - "Font-lock for URLs. BOUND limits the search." +(defun bibtex-font-lock-url (bound &optional no-button) + "Font-lock for URLs. BOUND limits the search. +If NO-BUTTON is non-nil do not generate buttons." (let ((case-fold-search t) (pnt (point)) - field bounds start end found) + name bounds start end found) (bibtex-beginning-of-field) (while (and (not found) (<= (point) bound) (prog1 (re-search-forward bibtex-font-lock-url-regexp bound t) - (setq field (match-string-no-properties 1))) + (setq name (match-string-no-properties 1))) (setq bounds (bibtex-parse-field-text)) (progn (setq start (car bounds) end (nth 1 bounds)) @@ -2682,17 +2835,18 @@ (setq end (1- end))) (if (memq (char-after start) '(?\{ ?\")) (setq start (1+ start))) - (>= bound start))) - (let ((lst bibtex-generate-url-list) url) - (goto-char start) - (while (and (not found) - (setq url (car (pop lst)))) - (setq found (and (bibtex-string= field (car url)) - (re-search-forward (cdr url) end t) - (>= (match-beginning 0) pnt))))) - (goto-char end)) - (if found (bibtex-button (match-beginning 0) (match-end 0) - 'bibtex-url (match-beginning 0))) + (if (< start pnt) (setq start (min pnt end))) + (<= start bound))) + (if (<= pnt start) + (let ((lst bibtex-generate-url-list) url) + (while (and (not found) (setq url (car (pop lst)))) + (goto-char start) + (setq found (and (bibtex-string= name (car url)) + (re-search-forward (cdr url) end t)))))) + (unless found (goto-char end))) + (if (and found (not no-button)) + (bibtex-button (match-beginning 0) (match-end 0) + 'bibtex-url (match-beginning 0))) found)) (defun bibtex-font-lock-crossref (bound) @@ -2713,6 +2867,19 @@ start t)) found)) +(defun bibtex-font-lock-cite (matcher bound) + "Font-lock for cited keys. +MATCHER identifies the cited key, see `bibtex-cite-matcher-alist'. +BOUND limits the search." + (let (case-fold-search) + (if (re-search-forward (car matcher) bound t) + (let ((start (match-beginning (cdr matcher))) + (end (match-end (cdr matcher)))) + (bibtex-button start end 'bibtex-find-crossref + (buffer-substring-no-properties start end) + start t t) + t)))) + (defun bibtex-button-action (button) "Call BUTTON's BibTeX function." (apply (button-get button 'bibtex-function) @@ -2831,7 +2998,7 @@ (list (list nil bibtex-entry-head bibtex-key-in-head)) imenu-case-fold-search t) (make-local-variable 'choose-completion-string-functions) - ;; XEmacs needs easy-menu-add, Emacs does not care + ;; XEmacs needs `easy-menu-add', Emacs does not care (easy-menu-add bibtex-edit-menu) (easy-menu-add bibtex-entry-menu) (run-mode-hooks 'bibtex-mode-hook)) @@ -3125,7 +3292,7 @@ (goto-char (bibtex-end-of-string bounds))) ((looking-at bibtex-any-valid-entry-type) ;; Parsing of entry failed - (error "Syntactically incorrect BibTeX entry starts here.")) + (error "Syntactically incorrect BibTeX entry starts here")) (t (if (interactive-p) (message "Not on a known BibTeX entry.")) (goto-char pnt))) (point))) @@ -3163,7 +3330,7 @@ (defun bibtex-mark-entry () "Put mark at beginning, point at end of current BibTeX entry." (interactive) - (set-mark (bibtex-beginning-of-entry)) + (push-mark (bibtex-beginning-of-entry)) (bibtex-end-of-entry)) (defun bibtex-count-entries (&optional count-string-entries) @@ -3227,6 +3394,7 @@ (list key nil entry-name)))))) (defun bibtex-init-sort-entry-class-alist () + "Initialize `bibtex-sort-entry-class-alist' (buffer-local)." (unless (local-variable-p 'bibtex-sort-entry-class-alist) (set (make-local-variable 'bibtex-sort-entry-class-alist) (let ((i -1) alist) @@ -3283,27 +3451,49 @@ nil ; ENDKEY function 'bibtex-lessp)) ; PREDICATE -(defun bibtex-find-crossref (crossref-key &optional pnt split) +(defun bibtex-find-crossref (crossref-key &optional pnt split noerror) "Move point to the beginning of BibTeX entry CROSSREF-KEY. If `bibtex-files' is non-nil, search all these files. Otherwise the search is limited to the current buffer. Return position of entry if CROSSREF-KEY is found or nil otherwise. If CROSSREF-KEY is in the same buffer like current entry but before it -an error is signaled. Optional arg PNT is the position of the referencing -entry. It defaults to position of point. If optional arg SPLIT is non-nil, -split window so that both the referencing and the crossrefed entry are -displayed. -If called interactively, CROSSREF-KEY defaults to crossref key of current -entry and SPLIT is t." +an error is signaled. If NOERRER is non-nil this error is suppressed. +Optional arg PNT is the position of the referencing entry. It defaults +to position of point. If optional arg SPLIT is non-nil, split window +so that both the referencing and the crossrefed entry are displayed. + +If called interactively, CROSSREF-KEY defaults to either the crossref key +of current entry or a key matched by `bibtex-cite-matcher-alist', +whatever is nearer to the position of point. SPLIT is t. NOERROR is nil +for a crossref key, t otherwise." (interactive - (let ((crossref-key - (save-excursion - (bibtex-beginning-of-entry) - (let ((bounds (bibtex-search-forward-field "crossref" t))) - (if bounds - (bibtex-text-in-field-bounds bounds t)))))) - (list (bibtex-read-key "Find crossref key: " crossref-key t) - (point) t))) + (save-excursion + (let* ((pnt (point)) + (_ (bibtex-beginning-of-entry)) + (end (cdr (bibtex-valid-entry t))) + (_ (unless end (error "Not inside valid entry"))) + (beg (match-end 0)) ; set by `bibtex-valid-entry' + (bounds (bibtex-search-forward-field "crossref" end)) + case-fold-search best temp crossref-key) + (if bounds + (setq crossref-key (bibtex-text-in-field-bounds bounds t) + best (cons (bibtex-dist pnt (bibtex-end-of-field bounds) + (bibtex-start-of-field bounds)) + crossref-key))) + (dolist (matcher bibtex-cite-matcher-alist) + (goto-char beg) + (while (re-search-forward (car matcher) end t) + (setq temp (bibtex-dist pnt (match-end (cdr matcher)) + (match-beginning (cdr matcher)))) + ;; Accept the key closest to the position of point. + (if (or (not best) (< temp (car best))) + (setq best (cons temp (match-string-no-properties + (cdr matcher))))))) + (goto-char pnt) + (setq temp (bibtex-read-key "Find crossref key: " (cdr best) t)) + (list temp (point) t (not (and crossref-key + (string= temp crossref-key))))))) + (let (buffer pos eqb) (save-excursion (setq pos (bibtex-find-entry crossref-key t) @@ -3314,13 +3504,15 @@ (split ; called (quasi) interactively (unless pnt (setq pnt (point))) (goto-char pnt) - (if eqb (select-window (split-window)) - (pop-to-buffer buffer)) - (goto-char pos) - (bibtex-reposition-window) - (beginning-of-line) - (if (and eqb (> pnt pos)) - (error "The referencing entry must precede the crossrefed entry!"))) + (if (and eqb (= pos (save-excursion (bibtex-beginning-of-entry)))) + (message "Key `%s' is current entry" crossref-key) + (if eqb (select-window (split-window)) + (pop-to-buffer buffer)) + (goto-char pos) + (bibtex-reposition-window) + (beginning-of-line) + (if (and eqb (> pnt pos) (not noerror)) + (error "The referencing entry must precede the crossrefed entry!")))) ;; `bibtex-find-crossref' is called noninteractively during ;; clean-up of an entry. Then it is not possible to check ;; whether the current entry and the crossrefed entry have @@ -3329,6 +3521,12 @@ (t (set-buffer buffer) (goto-char pos))) pos)) +(defun bibtex-dist (pos beg end) + "Return distance between POS and region delimited by BEG and END." + (cond ((and (<= beg pos) (<= pos end)) 0) + ((< pos beg) (- beg pos)) + (t (- pos end)))) + (defun bibtex-find-entry (key &optional global start display) "Move point to the beginning of BibTeX entry named KEY. Return position of entry if KEY is found or nil if not found. @@ -3394,7 +3592,7 @@ ;; if key-exist is non-nil due to the previous cond clause ;; then point will be at beginning of entry named key. (key-exist) - (t ; bibtex-maintain-sorted-entries is non-nil + (t ; `bibtex-maintain-sorted-entries' is non-nil (let* ((case-fold-search t) (left (save-excursion (bibtex-beginning-of-first-entry))) (bounds (save-excursion (goto-char (point-max)) @@ -3576,7 +3774,7 @@ (delete-region (point-min) (point-max)) (insert "BibTeX mode command `bibtex-validate'\n" (if syntax-error - "Maybe undetected errors due to syntax errors. Correct and validate again.\n" + "Maybe undetected errors due to syntax errors. Correct and validate again.\n" "\n")) (dolist (err error-list) (insert (format "%s:%d: %s\n" file (car err) (cdr err)))) @@ -3737,7 +3935,7 @@ end-text (or (match-end bibtex-key-in-head) (match-end 0)) end end-text - no-sub t) ;; subfields do not make sense + no-sub t) ; subfields do not make sense (setq failure t))) (t (setq failure t))) (when (and subfield (not failure)) @@ -3926,8 +4124,8 @@ Don't call `bibtex-clean-entry' on @Preamble entries. At end of the cleaning process, the functions in `bibtex-clean-entry-hook' are called with region narrowed to entry." - ;; Opt. arg called-by-reformat is t if bibtex-clean-entry - ;; is called by bibtex-reformat + ;; Opt. arg CALLED-BY-REFORMAT is t if `bibtex-clean-entry' + ;; is called by `bibtex-reformat' (interactive "P") (let ((case-fold-search t) (start (bibtex-beginning-of-entry)) @@ -3946,7 +4144,7 @@ ;; set key (when (or new-key (not key)) (setq key (bibtex-generate-autokey)) - ;; Sometimes bibtex-generate-autokey returns an empty string + ;; Sometimes `bibtex-generate-autokey' returns an empty string (if (or bibtex-autokey-edit-before-use (string= "" key)) (setq key (if (eq entry-type 'string) (bibtex-read-string-key key) @@ -4027,7 +4225,7 @@ (if (not justify) (goto-char (bibtex-start-of-text-in-field bounds)) (goto-char (bibtex-start-of-field bounds)) - (forward-char) ;; leading comma + (forward-char) ; leading comma (bibtex-delete-whitespace) (open-line 1) (forward-char) @@ -4045,7 +4243,7 @@ (if bibtex-align-at-equal-sign (insert " ") (indent-to-column bibtex-text-indentation))) - ;; Paragraphs within fields are not preserved. Bother? + ;; Paragraphs within fields are not preserved. Bother? (fill-region-as-paragraph (line-beginning-position) end-field default-justification nil (point)) (if move (goto-char end-field)))) @@ -4130,15 +4328,19 @@ (,(concat (if bibtex-comma-after-last-field "Insert" "Remove") " comma at end of entry? ") . 'last-comma) ("Replace double page dashes by single ones? " . 'page-dashes) + ("Delete whitespace at the beginning and end of fields? " . 'whitespace) ("Inherit booktitle? " . 'inherit-booktitle) ("Force delimiters? " . 'delimiters) - ("Unify case of entry types and field names? " . 'unify-case)))))) + ("Unify case of entry types and field names? " . 'unify-case) + ("Enclose parts of field entries by braces? " . 'braces) + ("Replace parts of field entries by string constants? " . 'strings)))))) ;; Do not include required-fields because `bibtex-reformat' ;; cannot handle the error messages of `bibtex-format-entry'. ;; Use `bibtex-validate' to check for required fields. ((eq t bibtex-entry-format) '(realign opts-or-alts numerical-fields delimiters - last-comma page-dashes unify-case inherit-booktitle)) + last-comma page-dashes unify-case inherit-booktitle + whitespace braces strings)) (t (remove 'required-fields (push 'realign bibtex-entry-format))))) (reformat-reference-keys @@ -4178,7 +4380,7 @@ (message "Starting to validate buffer...") (sit-for 1 nil t) (bibtex-realign) - (deactivate-mark) ; So bibtex-validate works on the whole buffer. + (deactivate-mark) ; So `bibtex-validate' works on the whole buffer. (if (not (let (bibtex-maintain-sorted-entries) (bibtex-validate))) (message "Correct errors and call `bibtex-convert-alien' again") @@ -4186,7 +4388,7 @@ (sit-for 2 nil t) (bibtex-reformat read-options) (goto-char (point-max)) - (message "Buffer is now parsable. Please save it."))) + (message "Buffer is now parsable. Please save it."))) (defun bibtex-complete () "Complete word fragment before point according to context. @@ -4249,7 +4451,7 @@ ;; ;; If we quit the *Completions* buffer without requesting ;; a completion, `choose-completion-string-functions' is still - ;; non-nil. Therefore, `choose-completion-string-functions' is + ;; non-nil. Therefore, `choose-completion-string-functions' is ;; always set (either to non-nil or nil) when a new completion ;; is requested. (let (completion-ignore-case) @@ -4276,7 +4478,7 @@ (setq choose-completion-string-functions nil) (choose-completion-string choice buffer base-size) (bibtex-complete-string-cleanup choice ',compl) - t)) ; needed by choose-completion-string-functions + t)) ; needed by `choose-completion-string-functions' (bibtex-complete-string-cleanup (bibtex-complete-internal compl) compl))) @@ -4391,44 +4593,94 @@ "Browse a URL for the BibTeX entry at point. Optional POS is the location of the BibTeX entry. The URL is generated using the schemes defined in `bibtex-generate-url-list' -\(see there\). Then the URL is passed to `browse-url' unless NO-BROWSE is nil. +\(see there\). If multiple schemes match for this entry, or the same scheme +matches more than once, use the one for which the first step's match is the +closest to POS. The URL is passed to `browse-url' unless NO-BROWSE is t. Return the URL or nil if none can be generated." (interactive) + (unless pos (setq pos (point))) (save-excursion - (if pos (goto-char pos)) + (goto-char pos) (bibtex-beginning-of-entry) - ;; Always remove field delimiters - (let ((fields-alist (bibtex-parse-entry t)) + (let ((end (save-excursion (bibtex-end-of-entry))) + (fields-alist (save-excursion (bibtex-parse-entry t))) ;; Always ignore case, (case-fold-search t) - (lst bibtex-generate-url-list) - field url scheme obj fmt) - (while (setq scheme (pop lst)) - (when (and (setq field (cdr (assoc-string (caar scheme) - fields-alist t))) - (string-match (cdar scheme) field)) - (setq lst nil - scheme (cdr scheme) - url (if (null scheme) (match-string 0 field) - (if (stringp (car scheme)) - (setq fmt (pop scheme))) - (dolist (step scheme) - (setq field (cdr (assoc-string (car step) fields-alist t))) - (if (string-match (nth 1 step) field) - (push (cond ((functionp (nth 2 step)) - (funcall (nth 2 step) field)) - ((numberp (nth 2 step)) - (match-string (nth 2 step) field)) - (t - (replace-match (nth 2 step) t nil field))) - obj) - ;; If the scheme is set up correctly, - ;; we should never reach this point - (error "Match failed: %s" field))) - (if fmt (apply 'format fmt (nreverse obj)) - (apply 'concat (nreverse obj))))) - (if (interactive-p) (message "%s" url)) - (unless no-browse (browse-url url)))) + text url scheme obj fmt fl-match step) + ;; The return value of `bibtex-parse-entry' (i.e., FIELDS-ALIST) + ;; is always used to generate the URL. However, if the BibTeX + ;; entry contains more than one URL, we have multiple matches + ;; for the first step defining the generation of the URL. + ;; Therefore, we try to initiate the generation of the URL + ;; based on the match of `bibtex-font-lock-url' that is the + ;; closest to POS. If that fails (no match found) we try to + ;; initiate the generation of the URL based on the properly + ;; concatenated CONTENT of the field as returned by + ;; `bibtex-text-in-field-bounds'. The latter approach can + ;; differ from the former because `bibtex-font-lock-url' uses + ;; the buffer itself. + (while (bibtex-font-lock-url end t) + (push (list (bibtex-dist pos (match-beginning 0) (match-end 0)) + (match-beginning 0) + (buffer-substring-no-properties + (match-beginning 0) (match-end 0))) + fl-match) + ;; `bibtex-font-lock-url' moves point to end of match. + (forward-char)) + (when fl-match + (setq fl-match (car (sort fl-match (lambda (x y) (< (car x) (car y)))))) + (goto-char (nth 1 fl-match)) + (bibtex-beginning-of-field) (re-search-backward ",") + (let* ((bounds (bibtex-parse-field)) + (name (bibtex-name-in-field bounds)) + (content (bibtex-text-in-field-bounds bounds t)) + (lst bibtex-generate-url-list)) + ;; This match can fail when CONTENT differs from text in buffer. + (when (string-match (regexp-quote (nth 2 fl-match)) content) + ;; TEXT is the part of CONTENT that starts with the match + ;; of `bibtex-font-lock-url' we are looking for. + (setq text (substring content (match-beginning 0))) + (while (and (not url) (setq scheme (pop lst))) + ;; Verify the match of `bibtex-font-lock-url' by + ;; comparing with TEXT. + (when (and (bibtex-string= (caar scheme) name) + (string-match (cdar scheme) text)) + (setq url t scheme (cdr scheme))))))) + + ;; If the match of `bibtex-font-lock-url' was not approved + ;; parse FIELDS-ALIST, i.e., the output of `bibtex-parse-entry'. + (unless url + (let ((lst bibtex-generate-url-list)) + (while (and (not url) (setq scheme (pop lst))) + (when (and (setq text (cdr (assoc-string (caar scheme) + fields-alist t))) + (string-match (cdar scheme) text)) + (setq url t scheme (cdr scheme)))))) + + (when url + (setq url (if (null scheme) (match-string 0 text) + (if (stringp (car scheme)) + (setq fmt (pop scheme))) + (dotimes (i (length scheme)) + (setq step (nth i scheme)) + ;; The first step shall use TEXT as obtained earlier. + (unless (= i 0) + (setq text (cdr (assoc-string (car step) fields-alist t)))) + (if (string-match (nth 1 step) text) + (push (cond ((functionp (nth 2 step)) + (funcall (nth 2 step) text)) + ((numberp (nth 2 step)) + (match-string (nth 2 step) text)) + (t + (replace-match (nth 2 step) t nil text))) + obj) + ;; If SCHEME is set up correctly, + ;; we should never reach this point + (error "Match failed: %s" text))) + (if fmt (apply 'format fmt (nreverse obj)) + (apply 'concat (nreverse obj))))) + (if (interactive-p) (message "%s" url)) + (unless no-browse (browse-url url))) (if (and (not url) (interactive-p)) (message "No URL known.")) url))) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/textmodes/nroff-mode.el --- a/lisp/textmodes/nroff-mode.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/textmodes/nroff-mode.el Sun Jul 15 02:05:20 2007 +0000 @@ -66,6 +66,8 @@ ;; ' used otherwise). (modify-syntax-entry ?\" "\" 2" st) ;; Comments are delimited by \" and newline. + ;; And in groff also \# to newline. + (modify-syntax-entry ?# ". 2" st) (modify-syntax-entry ?\\ "\\ 1" st) (modify-syntax-entry ?\n ">" st) st) @@ -92,7 +94,7 @@ (mapconcat 'identity '("[f*n]*\\[.+?]" ; some groff extensions "(.." ; two chars after ( - "[^(\"]" ; single char escape + "[^(\"#]" ; single char escape ) "\\|") "\\)") ) @@ -127,7 +129,7 @@ (concat "[.']\\|" paragraph-separate)) ;; comment syntax added by mit-erl!gildea 18 Apr 86 (set (make-local-variable 'comment-start) "\\\" ") - (set (make-local-variable 'comment-start-skip) "\\\\\"[ \t]*") + (set (make-local-variable 'comment-start-skip) "\\\\[\"#][ \t]*") (set (make-local-variable 'comment-column) 24) (set (make-local-variable 'comment-indent-function) 'nroff-comment-indent) (set (make-local-variable 'imenu-generic-expression) nroff-imenu-expression)) diff -r 70b38dec13a1 -r 0ece58f6e0aa lisp/textmodes/org.el --- a/lisp/textmodes/org.el Sun Jul 08 11:35:01 2007 +0000 +++ b/lisp/textmodes/org.el Sun Jul 15 02:05:20 2007 +0000 @@ -5,7 +5,7 @@ ;; Author: Carsten Dominik ;; Keywords: outlines, hypermedia, calendar, wp ;; Homepage: http://www.astro.uva.nl/~dominik/Tools/org/ -;; Version: 4.77 +;; Version: 5.03b ;; ;; This file is part of GNU Emacs. ;; @@ -83,7 +83,7 @@ ;;; Version -(defconst org-version "4.77" +(defconst org-version "5.03b" "The version number of the file org.el.") (defun org-version () (interactive) @@ -97,6 +97,29 @@ (get-text-property 0 'test (format "%s" x))) "Does format transport text properties?") +(defmacro org-unmodified (&rest body) + "Execute body without changing buffer-modified-p." + `(set-buffer-modified-p + (prog1 (buffer-modified-p) ,@body))) + +(defmacro org-re (s) + "Replace posix classes in regular expression." + (if (featurep 'xemacs) + (let ((ss s)) + (save-match-data + (while (string-match "\\[:alnum:\\]" ss) + (setq ss (replace-match "a-zA-Z0-9" t t ss))) + ss)) + s)) + +(defmacro org-preserve-lc (&rest body) + `(let ((_line (org-current-line)) + (_col (current-column))) + (unwind-protect + (progn ,@body) + (goto-line _line) + (move-to-column _col)))) + ;;; The custom variables (defgroup org nil @@ -251,6 +274,11 @@ :group 'org-keywords :type 'string) +(defcustom org-archived-string "ARCHIVED:" + "String used as the prefix for timestamps logging archiving a TODO entry." + :group 'org-keywords + :type 'string) + (defcustom org-clock-string "CLOCK:" "String used as prefix for timestamps clocking work hours on an item." :group 'org-keywords @@ -388,6 +416,18 @@ :tag "Org Cycle" :group 'org-structure) +(defcustom org-drawers '("PROPERTIES") + "Names of drawers. Drawers are not opened by cycling on the headline above. +Drawers only open with a TAB on the drawer line itself. A drawer looks like +this: + :DRAWERNAME: + ..... + :END: +The drawer \"PROPERTIES\" is special for capturing properties through +the property API." + :group 'org-structure + :type '(repeat (string :tag "Drawer Name"))) + (defcustom org-cycle-global-at-bob t "Cycle globally if cursor is at beginning of buffer and not at a headline. This makes it possible to do global cycling without having to use S-TAB or @@ -432,6 +472,7 @@ :type 'integer) (defcustom org-cycle-hook '(org-cycle-hide-archived-subtrees + org-cycle-hide-drawers org-cycle-show-empty-lines org-optimize-window-after-visibility-change) "Hook that is run after `org-cycle' has changed the buffer visibility. @@ -448,15 +489,22 @@ :tag "Org Edit Structure" :group 'org-structure) -(defcustom org-special-ctrl-a nil - "Non-nil means `C-a' behaves specially in headlines. + +(defcustom org-special-ctrl-a/e nil + "Non-nil means `C-a' and `C-e' behave specially in headlines. When set, `C-a' will bring back the cursor to the beginning of the headline text, i.e. after the stars and after a possible TODO keyword. When the cursor is already at that position, another `C-a' will bring -it to the beginning of the line." +it to the beginning of the line. +`C-e' will jump to the end of the headline, ignoring the presence of tags +in the headline. A second `C-e' will then jump to the true end of the +line, after any tags." :group 'org-edit-structure :type 'boolean) +(if (fboundp 'defvaralias) + (defvaralias 'org-special-ctrl-a 'org-special-ctrl-a/e)) + (defcustom org-odd-levels-only nil "Non-nil means, skip even levels and only use odd levels for the outline. This has the effect that two stars are being added/taken away in @@ -656,10 +704,7 @@ :type 'boolean) (defcustom org-archive-stamp-time t - "Non-nil means, add a time stamp to entries moved to an archive file. -The time stamp will be added directly after the TODO state keyword in the -first line, so it is probably best to use this in combinations with -`org-archive-mark-done'." + "Non-nil means, add a time stamp to entries moved to an archive file." :group 'org-archive :type 'boolean) @@ -880,8 +925,6 @@ :group 'org-table-calculation :type 'boolean) -;; FIXME this is also a variable that makes Org-mode files non-portable -;; Maybe I should have a #+ options for constants? (defcustom org-table-formula-constants nil "Alist with constant names and values, for use in table formulas. The car of each element is a name of a constant, without the `$' before it. @@ -890,12 +933,20 @@ (setq org-table-formula-constants '((\"c\" . \"299792458.\"))) -and then use it in an equation like `$1*$c'." +and then use it in an equation like `$1*$c'. + +Constants can also be defined on a per-file basis using a line like + +#+CONSTANTS: c=299792458. pi=3.14 eps=2.4e-6" :group 'org-table-calculation :type '(repeat (cons (string :tag "name") (string :tag "value")))) +(defvar org-table-formula-constants-local nil + "Local version of `org-table-formula-constants'.") +(make-variable-buffer-local 'org-table-formula-constants-local) + (defcustom org-table-allow-automatic-line-recalculation t "Non-nil means, lines marked with |#| or |*| will be recomputed automatically. Automatically means, when TAB or RET or C-c C-c are pressed in the line." @@ -973,6 +1024,7 @@ (const :tag "plain text links" plain) (const :tag "Radio target matches" radio) (const :tag "Tags" tag) + (const :tag "Tags" target) (const :tag "Timestamps" date))) (defgroup org-link-store nil @@ -1299,7 +1351,7 @@ element is a character, a unique key to select this template. The second element is the template. The third element is optional and can specify a destination file for remember items created with this template. -The default file is given by `org-default-notes-file'. An optional third +The default file is given by `org-default-notes-file'. An optional forth element can specify the headline in that file that should be offered first when the user is asked to file the entry. The default headline is given in the variable `org-remember-default-headline'. @@ -1580,7 +1632,8 @@ '("<%m/%d/%y %a>" . "<%m/%d/%y %a %H:%M>") ; american "Custom formats for time stamps. See `format-time-string' for the syntax. These are overlayed over the default ISO format if the variable -`org-display-custom-times' is set." +`org-display-custom-times' is set. Time like %H:%M should be at the +end of the second format." :group 'org-time :type 'sexp) @@ -1704,6 +1757,28 @@ (defvar org-last-tags-completion-table nil "The last used completion table for tags.") +(defgroup org-properties nil + "Options concerning properties in Org-mode." + :tag "Org Properties" + :group 'org) + +(defcustom org-property-format "%-10s %s" + "How property key/value pairs should be formatted by `indent-line'. +When `indent-line' hits a property definition, it will format the line +according to this format, mainly to make sure that the values are +lined-up with respect to each other." + :group 'org-properties + :type 'string) + +(defcustom org-columns-default-format "%25ITEM %TODO %3PRIORITY %TAGS" + "The default column format, if no other format has been defined. +This variable can be set on the per-file basis by inserting a line + +#+COLUMNS: %25ITEM ....." + :group 'org-properties + :type 'string) + + (defgroup org-agenda nil "Options concerning agenda views in Org-mode." :tag "Org Agenda" @@ -2325,6 +2400,17 @@ (const :tag "Never" nil) (const :tag "When at beginning of entry" beg))) + +(defcustom org-agenda-default-appointment-duration nil + "Default duration for appointments that only have a starting time. +When nil, no duration is specified in such cases. +When non-nil, this must be the number of minutes, e.g. 60 for one hour." + :group 'org-agenda-prefix + :type '(choice + (integer :tag "Minutes") + (const :tag "No default duration"))) + + (defcustom org-agenda-remove-tags nil "Non-nil means, remove the tags from the headline copy in the agenda. When this is the symbol `prefix', only remove tags when @@ -2531,6 +2617,14 @@ (const :tag "Not in TOC" not-in-toc) (const :tag "On" t))) +(defcustom org-export-with-property-drawer nil + "Non-nil means, export property drawers. +When nil, these drawers are removed before export. + +This option can also be set with the +OPTIONS line, e.g. \"p:t\"." + :group 'org-export-general + :type 'boolean) + (defgroup org-export-translation nil "Options for translating special ascii sequences for the export backends." :tag "Org Export Translation" @@ -2547,6 +2641,14 @@ :group 'org-export-translation :type 'boolean) +(defcustom org-export-with-footnotes t + "If nil, export [1] as a footnote marker. +Lines starting with [1] will be formatted as footnotes. + +This option can also be set with the +OPTIONS line, e.g. \"f:nil\"." + :group 'org-export-translation + :type 'boolean) + (defcustom org-export-with-sub-superscripts t "Non-nil means, interpret \"_\" and \"^\" for export. When this option is turned on, you can use TeX-like syntax for sub- and @@ -2682,7 +2784,7 @@ (defcustom org-export-ascii-bullets '(?* ?+ ?-) "Bullet characters for headlines converted to lists in ASCII export. -The first character is used for the first lest level generated in this +The first character is is used for the first lest level generated in this way, and so on. If there are more levels than characters given here, the list will be repeated. Note that plain lists will keep the same bullets as the have in the @@ -2700,6 +2802,11 @@ :tag "Org Export HTML" :group 'org-export) +(defcustom org-export-html-coding-system nil + "" + :group 'org-export-html + :type 'coding-system) + (defcustom org-export-html-style "