commit b65971b2c06d34c268b2b0280056e478dbc31586 (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Thu Feb 20 14:27:03 2025 +0800 ; * src/pdumper.c (Fdump_emacs_portable): Fix typo in comment. diff --git a/src/pdumper.c b/src/pdumper.c index 0cb5ddda644..fc3b5d18bde 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -4257,7 +4257,7 @@ types. */) strcpy (filename_1 + len - 5, ".dmp"); filename = DECODE_FILE (build_unibyte_string (filename_1)); } -#endif /* !MSDOS */ +#endif /* MSDOS */ ctx->fd = emacs_open (filename_1, O_RDWR | O_TRUNC | O_CREAT, 0666); SAFE_FREE (); } commit 1468190e11b7eed49a024ffbff3da2bca21862bc Author: Po Lu Date: Thu Feb 20 14:25:05 2025 +0800 ; * etc/NEWS: Announce MS-DOS updates. diff --git a/etc/NEWS b/etc/NEWS index 79a48280191..dea24adb3c9 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1624,6 +1624,12 @@ means of the GDI+ library. In addition to ':file FILE' for playing a sound from a file, ':data DATA' can now be used to play a sound from memory. +--- +** The MS-DOS port of Emacs now supports more recent releases of GCC and Binutils. +Accordingly, we have revised our recommendations for a suitable DJGPP +toolchain to GCC 14.2.0 and Binutils 2.35.1 in lieu of GCC 3.4.x and +Binutils 2.26. + ---------------------------------------------------------------------- This file is part of GNU Emacs. commit c22957c4bf7dd25857a44946169c4818996a49d9 Author: Po Lu Date: Thu Feb 20 14:04:59 2025 +0800 Port to modern GCC and pdumper on MS-DOS * config.bat (mvOk): Protoize. (djgppOk): Include sys/version.h for _DJGPP_MINOR. * lisp/loadup.el: If system-type is ms-dos, dump bootstrap-emacs as b-emacs.dmp. * msdos/INSTALL: Document new versions of tools that have been verified successfully to compile Emacs. * msdos/emacs.djl: New linker script that arranges to link symbols in `.subrs' in a contiguous part of data, as the DJGPP runtime appears to treat any non-data and non-text section as allocatable. * msdos/mainmake.v2 (install): Install emacs.dmp alongside emacs.exe. * msdos/sed1v2.inp (CFLAGS): Define to -O2 -g3. (LDFLAGS): Provide the said linker script. (HAVE_PDUMPER): Define to yes. (UNEXEC_OBJ, PAXCTL_dumped, PAXCTL_notdumped): Delete. (DUMPING): Set to pdumper. (MAKE_PDUMPER_FINGERPRINT): Don't erase this variable. Don't stubify or set minstack. Remove native-comp specific directives. Don't remove temacs prior to copying and replace `pdmp' extension with DOS-conformant `dmp'. * msdos/sed2v2.inp (HAVE_UNEXEC): Remove definition. (HAVE_PDUMPER): Define to 1. * msdos/sed6.inp (top_srcdir): Define appropriately. * msdos/sedlibmk.inp (HAVE_BLKCNT_T): Define to 1. * src/emacs.c (load_pdump) [MSDOS]: Use `dmp' suffix. * src/pdumper.c (Fdump_emacs_portable) [MSDOS]: Replace ".pdmp" suffixes with ".dmp". diff --git a/config.bat b/config.bat index fba0ac2925f..393c950074e 100644 --- a/config.bat +++ b/config.bat @@ -94,7 +94,7 @@ Goto End :mvOk rm -f junk.2 Echo Checking whether 'gcc' is available... -echo main(){} >junk.c +echo int main(void){} >junk.c gcc -c junk.c if exist junk.o goto gccOk Echo To configure 'Emacs' you need to have 'gcc'! @@ -107,7 +107,8 @@ If Not "%DJGPP%" == "" goto djgppOk Echo To compile 'Emacs' under MS-DOS you MUST have DJGPP installed! Goto End :djgppOk -echo int main() >junk.c +echo #include "sys/version.h" >junk.c +echo int main() >>junk.c echo #ifdef __DJGPP__ >>junk.c echo {return (__DJGPP__)*10 + (__DJGPP_MINOR__);} >>junk.c echo #else >>junk.c diff --git a/lisp/loadup.el b/lisp/loadup.el index ebd35291050..2477778d6a3 100644 --- a/lisp/loadup.el +++ b/lisp/loadup.el @@ -600,7 +600,10 @@ directory got moved. This is set to be a pair in the form of: (error nil)))))) (if dump-mode (let ((output (cond ((equal dump-mode "pdump") "emacs.pdmp") - ((equal dump-mode "pbootstrap") "bootstrap-emacs.pdmp") + ((equal dump-mode "pbootstrap") + (if (eq system-type 'ms-dos) + "b-emacs.pdmp" + "bootstrap-emacs.pdmp")) (t (error "Unrecognized dump mode %s" dump-mode))))) (when (and (featurep 'native-compile) (equal dump-mode "pdump")) diff --git a/msdos/INSTALL b/msdos/INSTALL index ffc1fee84f0..c5fd16aa9ac 100644 --- a/msdos/INSTALL +++ b/msdos/INSTALL @@ -19,14 +19,9 @@ the necessary utilities; search for "MS-DOS". The configuration step (see below) will test for these utilities and will refuse to continue if any of them isn't found. -You should carefully choose the version of GCC you use to build Emacs, -because recent versions of GCC don't support building Emacs very well. -The main issue is the debug info: the DJGPP build of Emacs must use -the COFF debug info. GCC support for COFF debug info was steadily -deteriorating since GCC 5, and GCC 8.1 officially stopped supporting -the -gcoff switch, which the Emacs build process needs. We recommend -using GCC 3.4.X and Binutils 2.26; GDB 7.2 is capable to debug an -Emacs binary built by this combination. +Binutils 2.35.1 with GCC 14.2.0 have been verified to be capable of +compiling the MS-DOS port of Emacs, and GDB 8.0.1, to be capable of +debugging Emacs executables produced by this configuration. Bootstrapping Emacs or recompiling Lisp files in the `lisp' subdirectory using the various targets in the lisp/Makefile file diff --git a/msdos/emacs.djl b/msdos/emacs.djl new file mode 100644 index 00000000000..3f6e0852b32 --- /dev/null +++ b/msdos/emacs.djl @@ -0,0 +1,95 @@ +/* Modified version of the default DJGPP linker script for GNU -*- c -*- + Emacs. */ + +/* Default linker script, for normal executables */ +/* Copyright (C) 2014 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +OUTPUT_FORMAT("coff-go32-exe") +ENTRY (start) +SECTIONS +{ + .text 0x1000+SIZEOF_HEADERS : { + *(.text) + *(.text.*) + *(.gnu.linkonce.t*) + *(.const*) + *(.ro*) + *(.gnu.linkonce.r*) + etext = . ; PROVIDE(_etext = .) ; + . = ALIGN(0x200); + } + .data ALIGN(0x200) : { + djgpp_first_ctor = . ; + *(SORT(.ctors.*)) + *(.ctor) + *(.ctors) + djgpp_last_ctor = . ; + djgpp_first_dtor = . ; + *(SORT(.dtors.*)) + *(.dtor) + *(.dtors) + djgpp_last_dtor = . ; + __environ = . ; + PROVIDE(_environ = .) ; + LONG(0) ; + *(.data) + *(.data.*) + *(.subrs) + *(.subrs.*) + /* Ugly workaround to prevent entire .bss to have attribute CONTENT */ + /* for C++ executables. */ + *( .bss.*) + *(.gcc_exc*) + ___EH_FRAME_BEGIN__ = . ; + *(.eh_fram*) + ___EH_FRAME_END__ = . ; + LONG(0) ; + *(.gnu.linkonce.d*) + edata = . ; PROVIDE(_edata = .) ; + . = ALIGN(0x200); + } + .bss SIZEOF(.data) + ADDR(.data) : + { + *(.bss .gnu.linkonce.b.*) + *(COMMON) + end = . ; PROVIDE(_end = .) ; + . = ALIGN(0x200); + } + /* Discard LTO sections. */ + /DISCARD/ : { *(gnu.lto_*) } + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } +} diff --git a/msdos/mainmake.v2 b/msdos/mainmake.v2 index 710294973b9..46c650c7fe7 100644 --- a/msdos/mainmake.v2 +++ b/msdos/mainmake.v2 @@ -136,6 +136,7 @@ install: all cd .. cd src mv -f emacs.exe ../bin/ + mv -f emacs.dmp ../bin/ cd .. djecho -s "(if (fboundp 'normal-top-level-add-subdirs-to-load-path)" \ " (normal-top-level-add-subdirs-to-load-path))" \ diff --git a/msdos/sed1v2.inp b/msdos/sed1v2.inp index 791d6ab2693..1de2c11a0c4 100644 --- a/msdos/sed1v2.inp +++ b/msdos/sed1v2.inp @@ -22,11 +22,11 @@ s/\.h\.in/.h-in/ /^srcdir *=/s/@[^@\n]*@/./ /^top_srcdir *=/s/@[^@\n]*@/../ /^CC *=/s/@[^@\n]*@/gcc -std=gnu99/ -/^CFLAGS *=/s/@[^@\n]*@/-O2 -gcoff/ +/^CFLAGS *=/s/@[^@\n]*@/-O2 -g3/ /^ALL_CFLAGS *=/s/@[^@\n]*@//g /^ALL_CFLAGS *=/s/ -I\.//g /^CPPFLAGS *=/s|@[^@\n]*@|-I../msdos| -/^LDFLAGS *=/s/@[^@\n]*@// +/^LDFLAGS *=/s/@[^@\n]*@/-T ..\/msdos\/emacs.djl/ /^LIBOBJS *=/s/@[^@\n]*@// /^C_SWITCH_MACHINE *=/s/@C_SWITCH_MACHINE@// /^C_SWITCH_SYSTEM *=/s/@C_SWITCH_SYSTEM@// @@ -60,7 +60,7 @@ s/ *@WEBP_LIBS@// /^JPEG_CFLAGS *=/s/@JPEG_CFLAGS@// /^TIFF_CFLAGS *=/s/@TIFF_CFLAGS@// /^HAVE_NATIVE_COMP *=/s/@HAVE_NATIVE_COMP@/no/ -/^HAVE_PDUMPER *=/s/@HAVE_PDUMPER@/no/ +/^HAVE_PDUMPER *=/s/@HAVE_PDUMPER@/yes/ /^HAVE_BE_APP *=/s/@HAVE_BE_APP@/no/ /^CHECK_STRUCTS *=/s/@CHECK_STRUCTS@// /^RUN_TEMACS \=/s/temacs/temacs.exe/ @@ -166,7 +166,6 @@ s/ *@WEBP_LIBS@// /^GMALLOC_OBJ *=/s/@GMALLOC_OBJ@/gmalloc.o/ /^VMLIMIT_OBJ *=/s/@VMLIMIT_OBJ@/vm-limit.o/ /^RALLOC_OBJ *=/s/@RALLOC_OBJ@/ralloc.o/ -/^UNEXEC_OBJ *=/s/@UNEXEC_OBJ@/unexcoff.o/ /^BUILD_DETAILS *=/s/@BUILD_DETAILS@// /^CANNOT_DUMP *=/s/@CANNOT_DUMP@/no/ /^W32_OBJ *=/s/@W32_OBJ@// @@ -194,9 +193,7 @@ s/ *@WEBP_LIBS@// /^[Aa][Mm]_/s/@AM_V@/$(V)/ /^[Aa][Mm]_/s/@AM_DEFAULT_V@/$(AM_DEFAULT_VERBOSITY)/ /^AUTO_DEPEND *=/s/@AUTO_DEPEND@/yes/ -/^PAXCTL_dumped *=/s/=.*$/=/ -/^PAXCTL_notdumped *=/s/=.*$/=/ -/^DUMPING *=/s/@DUMPING@/unexec/ +/^DUMPING *=/s/@DUMPING@/pdumper/ /^ANDROID_OBJ *=/s/@ANDROID_OBJ@// /^ANDROID_LIBS *=/s/@ANDROID_LIBS@// /^ANDROID_LDFLAGS *=/s/@ANDROID_LDFLAGS@// @@ -205,8 +202,6 @@ s/ *@WEBP_LIBS@// /^SQLITE3_CFLAGS *=/s/@SQLITE3_CFLAGS@// /^LIBSELINUX_CFLAGS *=/s/@LIBSELINUX_CFLAGS@// /^XCONFIGURE *=/s/@XCONFIGURE@// -/^[ \t]*MAKE_PDUMPER_FINGERPRINT = *$/c\ -MAKE_PDUMPER_FINGERPRINT = # While this variable is named abs_top_builddir, the distinction is # only relevant when Emacs is undergoing cross-compilation. /^abs_top_builddir =*/s/@abs_top_builddir@/../ @@ -237,14 +232,8 @@ lisp.mk: $(lispsource)/loadup.el\ /^ *ln /s/ln /cp / /^ fi/d /ifeq (\$(HAVE_NATIVE_COMP):\$(NATIVE_DISABLED),yes:)/,/endif/d -/^ *\$(RUN_TEMACS) /i\ - stubedit temacs.exe minstack=1024k -/^ *LC_ALL=C \$(RUN_TEMACS)/i\ - stubedit temacs.exe minstack=1024k /^ *LC_ALL=C.*\$(RUN_TEMACS)/s/LC_ALL=C/set &;/ -/-batch .* -l loadup/a\ - stubify emacs\ - stubedit emacs.exe minstack=3072k +/^ ANCIENT=yes \$(MAKE) -C ..\/lisp compile-first EMACS="\$(bootstrap_exe)"/d s/ @true *$/ @rem/ s/^ [^ ]*move-if-change / update / /^ [^ ]*echo[ ][ ]*timestamp/s/echo /djecho / @@ -271,6 +260,8 @@ s/echo.*buildobj.lst/dj&/ /^ *\$(AM_V_GEN)for /,/mv \$@.tmp \$@/c\ djecho "$(ALLOBJS)" | sed -e 's/^ */"/' -e 's/ *$$/"/' -e 's/ */", "/g' >>$@ } +/^ .*\$(MAKE_PDUMPER_FINGERPRINT) \$@\.tmp/s/\.tmp// +/^ rm -f \$@ && cp -f temacs\$(EXEEXT) \$@/s/rm -f \$@ && // # Remove or replace dependencies we cannot have /^\.PRECIOUS: /s!\.\./config.status !! /^\.\.\/config.status: /,/^ /d @@ -293,3 +284,4 @@ s| -I\. -I\$(srcdir)| -I.| /\$(CC) -o \$@.tmp/s/\$@.tmp/\$@/ /mv \$@.tmp \$@/d /^top_builddir =*/s/@top_builddir@/../ +s/\.pdmp/\.dmp/ diff --git a/msdos/sed2v2.inp b/msdos/sed2v2.inp index b6e4bda89e2..ff6eca0f625 100644 --- a/msdos/sed2v2.inp +++ b/msdos/sed2v2.inp @@ -37,7 +37,6 @@ /^#undef HAVE_STRUCT_UTIMBUF *$/s/^.*$/#define HAVE_STRUCT_UTIMBUF 1/ /^#undef LOCALTIME_CACHE *$/s/^.*$/#define LOCALTIME_CACHE 1/ /^#undef HAVE_TZSET *$/s/^.*$/#define HAVE_TZSET 1/ -/^#undef HAVE_UNEXEC *$/s/^.*$/#define HAVE_UNEXEC 1/ /^#undef HAVE_RINT *$/s/^.*$/#define HAVE_RINT 1/ /^#undef HAVE_C99_STRTOLD *$/s/^.*$/#define HAVE_C99_STRTOLD 1/ /^#undef HAVE_DIFFTIME *$/s/^.*$/#define HAVE_DIFFTIME 1/ @@ -138,6 +137,7 @@ s/^#undef HAVE_DECL_PUTCHAR_UNLOCKED *$/#define HAVE_DECL_PUTCHAR_UNLOCKED 0/ s/^#undef HAVE_DECL_PUTC_UNLOCKED *$/#define HAVE_DECL_PUTC_UNLOCKED 0/ s/^#undef HAVE_DECL_STRTOLL *$/#define HAVE_DECL_STRTOLL 1/ s/^#undef HAVE_DECL_STRTOIMAX *$/#define HAVE_DECL_STRTOIMAX 1/ +s/^#undef HAVE_PDUMPER *$/#define HAVE_PDUMPER 1/ s/^#undef HAVE_STRTOLL *$/#define HAVE_STRTOLL 1/ s/^#undef HAVE_STRTOULL *$/#define HAVE_STRTOULL 1/ /^#undef HAVE_STRUCT_DIRENT_D_TYPE *$/c\ diff --git a/msdos/sed6.inp b/msdos/sed6.inp index adc805a4240..687ece9d8ee 100644 --- a/msdos/sed6.inp +++ b/msdos/sed6.inp @@ -17,6 +17,7 @@ # # ---------------------------------------------------------------------- /^srcdir *=/s/@[^@\n]*@/./ +/^top_srcdir *=/s/@[^@\n]*@/..\/../ /^VPATH *=/s/@[^@\n]*@/./ /^MAKEINFO *=/s/@[^@\n]*@/makeinfo/ /^AM_DEFAULT_VERBOSITY *=/s/@AM_DEFAULT_VERBOSITY@/1/ diff --git a/msdos/sedlibmk.inp b/msdos/sedlibmk.inp index aca8857bc44..7af9a9ae7db 100644 --- a/msdos/sedlibmk.inp +++ b/msdos/sedlibmk.inp @@ -208,6 +208,7 @@ s/@PACKAGE@/emacs/ # # Edit the HAVE_foo variables /^HAVE_ATOLL *=/s/@HAVE_ATOLL@/0/ +/^HAVE_BLKCNT_T *=/s/@HAVE_BLKCNT_T@/1/ /^HAVE_CHOWN *=/s/@HAVE_CHOWN@/1/ /^HAVE_CLOSEDIR *=/s/@HAVE_CLOSEDIR@/1/ /^HAVE_DECL_GETPAGESIZE *=/s/@HAVE_DECL_GETPAGESIZE@/1/ diff --git a/src/emacs.c b/src/emacs.c index f0281044c9e..42074c56271 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -885,7 +885,11 @@ load_pdump (int argc, char **argv, char *dump_file) return argv[0]; #else +#ifdef MSDOS + const char *const suffix = ".dmp"; +#else /* !MSDOS */ const char *const suffix = ".pdmp"; +#endif /* !MSDOS */ int result; char *emacs_executable = argv[0]; ptrdiff_t hexbuf_size; diff --git a/src/lisp.h b/src/lisp.h index 89a47f0d2fe..46844be1eca 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3399,9 +3399,10 @@ CHECK_SUBR (Lisp_Object x) for more efficient dump loading. */ #ifdef DARWIN_OS # define SUBR_SECTION_ATTRIBUTE ATTRIBUTE_SECTION ("__DATA,subrs") -#else +#else /* !DARWIN_OS */ # define SUBR_SECTION_ATTRIBUTE ATTRIBUTE_SECTION (".subrs") -#endif +#endif /* !DARWIN_OS */ + /* Define a built-in function for calling from Lisp. `lname' should be the name to give the function in Lisp, diff --git a/src/pdumper.c b/src/pdumper.c index dee13fb9a81..0cb5ddda644 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -4243,8 +4243,24 @@ types. */) ctx->old_process_environment = Vprocess_environment; Vprocess_environment = Qnil; - ctx->fd = emacs_open (SSDATA (filename), - O_RDWR | O_TRUNC | O_CREAT, 0666); + { + USE_SAFE_ALLOCA; + + char *filename_1; + SAFE_ALLOCA_STRING (filename_1, filename); +#ifdef MSDOS + /* Rewrite references to .pdmp to refer to .dmp files on DOS. */ + size_t len = strlen (filename_1); + if (len >= 5 + && !strcmp (filename_1 + len - 5, ".pdmp")) + { + strcpy (filename_1 + len - 5, ".dmp"); + filename = DECODE_FILE (build_unibyte_string (filename_1)); + } +#endif /* !MSDOS */ + ctx->fd = emacs_open (filename_1, O_RDWR | O_TRUNC | O_CREAT, 0666); + SAFE_FREE (); + } if (ctx->fd < 0) report_file_error ("Opening dump output", filename); static_assert (sizeof (ctx->header.magic) == sizeof (dump_magic)); commit 89f9377139c336dd646335352b0c7480c7e19c4a Author: Stefan Kangas Date: Wed Feb 19 23:36:07 2025 +0100 Prefer defvar-keymap in conf-mode.el * lisp/textmodes/conf-mode.el (conf-mode-map): Prefer defvar-keymap. diff --git a/lisp/textmodes/conf-mode.el b/lisp/textmodes/conf-mode.el index fd4813be1f0..6540cb0813c 100644 --- a/lisp/textmodes/conf-mode.el +++ b/lisp/textmodes/conf-mode.el @@ -62,23 +62,21 @@ not align (only setting space according to `conf-assignment-space')." "Value for `conf-assignment-space' in colon style Conf mode buffers." :type 'boolean) -(defvar conf-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "\C-c\C-u" 'conf-unix-mode) - (define-key map "\C-c\C-w" 'conf-windows-mode) - (define-key map "\C-c\C-j" 'conf-javaprop-mode) - (define-key map "\C-c\C-s" 'conf-space-keywords) - (define-key map "\C-c " 'conf-space-keywords) - (define-key map "\C-c\C-c" 'conf-colon-mode) - (define-key map "\C-c:" 'conf-colon-mode) - (define-key map "\C-c\C-x" 'conf-xdefaults-mode) - (define-key map "\C-c\C-p" 'conf-ppd-mode) - (define-key map "\C-c\C-q" 'conf-quote-normal) - (define-key map "\C-c\"" 'conf-quote-normal) - (define-key map "\C-c'" 'conf-quote-normal) - (define-key map "\C-c\C-a" 'conf-align-assignments) - map) - "Local keymap for `conf-mode' buffers.") +(defvar-keymap conf-mode-map + :doc "Local keymap for `conf-mode' buffers." + "C-c C-u" #'conf-unix-mode + "C-c C-w" #'conf-windows-mode + "C-c C-j" #'conf-javaprop-mode + "C-c C-s" #'conf-space-keywords + "C-c SPC" #'conf-space-keywords + "C-c C-c" #'conf-colon-mode + "C-c :" #'conf-colon-mode + "C-c C-x" #'conf-xdefaults-mode + "C-c C-p" #'conf-ppd-mode + "C-c C-q" #'conf-quote-normal + "C-c \"" #'conf-quote-normal + "C-c '" #'conf-quote-normal + "C-c C-a" #'conf-align-assignments) (easy-menu-define conf-mode-menu conf-mode-map "Menu for `conf-mode'." commit ec34bccfee68a521e7a98ce8dce9325a146d095b Author: Michael Albinus Date: Wed Feb 19 19:38:25 2025 +0100 Simplify Tramp's find-executable * lisp/net/tramp-cache.el (with-tramp-saved-connection-property): Fix typo. * lisp/net/tramp-compat.el: Add TODO. * lisp/net/tramp-sh.el (tramp-find-executable): Simplify, using "type -P ...". (tramp-set-remote-path): Better handling of superlong $PATH. (tramp-get-remote-path): Adapt/use connection properties. * test/lisp/net/tramp-tests.el (tramp--test-enabled) (tramp-test03-file-name-host-rules): Don't wrap `tramp-cleanup-connection' with `ignore-errors'. diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el index 0c1f6181bf9..2694b8f490a 100644 --- a/lisp/net/tramp-cache.el +++ b/lisp/net/tramp-cache.el @@ -482,10 +482,10 @@ used to cache connection properties of the local machine." (hash (tramp-get-hash-table key)) (cached (and (hash-table-p hash) (gethash ,property hash tramp-cache-undefined)))) - (tramp-message key 7 "Saved %s %s" property cached) + (tramp-message key 7 "Saved %s %s" ,property cached) (unwind-protect (progn ,@body) ;; Reset PROPERTY. Recompute hash, it could have been flushed. - (tramp-message key 7 "Restored %s %s" property cached) + (tramp-message key 7 "Restored %s %s" ,property cached) (setq hash (tramp-get-hash-table key)) (if (not (eq cached tramp-cache-undefined)) (puthash ,property cached hash) diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el index 0e69cca2f32..8b18b9b14e6 100644 --- a/lisp/net/tramp-compat.el +++ b/lisp/net/tramp-compat.el @@ -245,6 +245,8 @@ value is the default binding of the variable." ;; ;; * Use `with-environment-variables'. ;; +;; * Use `ensure-list'. +;; ;; * Starting with Emacs 29.1, use `buffer-match-p'. ;; ;; * Starting with Emacs 29.1, use `string-split'. diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index ca890854f85..e008bc07301 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -4092,44 +4092,23 @@ Returns the absolute file name of PROGNAME, if found, and nil otherwise. This function expects to be in the right *tramp* buffer." (with-current-buffer (tramp-get-connection-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. "SunOS 5.10" (and maybe "SunOS - ;; 5.11") have problems with this command, we disable the call - ;; therefore. - (unless (or ignore-path (tramp-check-remote-uname vec tramp-sunos-unames)) - (tramp-send-command vec (format "which \\%s | wc -w" progname)) - (goto-char (point-min)) - (if (looking-at-p (rx bol (* blank) "1" eol)) - (setq result (concat "\\" progname)))) - (unless result - (when ignore-tilde - ;; Remove all ~/foo directories from dirlist. - (let (newdl d) - (while dirlist - (setq d (car dirlist) - 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 && test -f $d/%s; " - "then echo tramp_executable $d/%s; " - "break; fi; done <<'%s'\n" - "%s\n%s") - progname progname progname - tramp-end-of-heredoc - (string-join dirlist "\n") - tramp-end-of-heredoc)) - (goto-char (point-max)) - (when (search-backward "tramp_executable " nil t) - (skip-chars-forward "^ ") - (skip-chars-forward " ") - (setq result (buffer-substring (point) (line-end-position))))) - result))) + (unless ignore-path + (setq dirlist (cons "$PATH" dirlist))) + (when ignore-tilde + ;; Remove all ~/foo directories from dirlist. + (let (newdl d) + (while dirlist + (setq d (car dirlist) + dirlist (cdr dirlist)) + (unless (char-equal ?~ (aref d 0)) + (setq newdl (cons d newdl)))) + (setq dirlist (nreverse newdl)))) + (tramp-send-command + vec (format "%s type -P %s 2>%s" + (if dirlist (concat "PATH=" (string-join dirlist ":")) "") + progname (tramp-get-remote-null-device vec))) + (unless (zerop (buffer-size)) + (string-trim (buffer-string))))) ;; On hydra.nixos.org, the $PATH environment variable is too long to ;; send it. This is likely not due to PATH_MAX, but PIPE_BUF. We @@ -4151,18 +4130,24 @@ variable PATH." ;; Use a temporary file. We cannot use `write-region' because ;; setting the remote path happens in the early connection ;; handshake, and not all external tools are determined yet. - (setq command (concat command "\n") - tmpfile (tramp-make-tramp-temp-file vec)) - (while (not (string-empty-p command)) - (setq chunksize (min (length command) (/ pipe-buf 2)) - chunk (substring command 0 chunksize) - command (substring command chunksize)) - (tramp-send-command vec (format - "printf \"%%b\" \"$*\" %s >>%s" - (tramp-shell-quote-argument chunk) - (tramp-shell-quote-argument tmpfile)))) - (tramp-send-command vec (format ". %s" tmpfile)) - (tramp-send-command vec (format "rm -f %s" tmpfile))))) + ;; Furthermore, we know that the COMMAND is too long, due to a + ;; very long remote-path. Set it temporarily to something + ;; short. + (with-tramp-saved-connection-property (tramp-get-process vec) "remote-path" + (tramp-set-connection-property + (tramp-get-process vec) "remote-path" '("/bin" "/usr/bin")) + (setq command (concat command "\n") + tmpfile (tramp-make-tramp-temp-file vec)) + (while (not (string-empty-p command)) + (setq chunksize (min (length command) (/ pipe-buf 2)) + chunk (substring command 0 chunksize) + command (substring command chunksize)) + (tramp-send-command vec (format + "printf \"%%b\" \"$*\" %s >>%s" + (tramp-shell-quote-argument chunk) + (tramp-shell-quote-argument tmpfile)))) + (tramp-send-command vec (format ". %s" tmpfile)) + (tramp-send-command vec (format "rm -f %s" tmpfile)))))) ;; ------------------------------------------------------------ ;; -- Communication with external shell -- @@ -5569,50 +5554,48 @@ Nonexistent directories are removed from spec." (with-current-buffer (tramp-get-connection-buffer vec) ;; Expand connection-local variables. (tramp-set-connection-local-variables vec) - (with-tramp-connection-property - ;; When `tramp-own-remote-path' is in `tramp-remote-path', we - ;; cache the result for the session only. Otherwise, the - ;; result is cached persistently. - (if (memq 'tramp-own-remote-path tramp-remote-path) - (tramp-get-process vec) vec) - "remote-path" + (with-tramp-connection-property (tramp-get-process vec) "remote-path" (let* ((remote-path (copy-tree tramp-remote-path)) (elt1 (memq 'tramp-default-remote-path remote-path)) (elt2 (memq 'tramp-own-remote-path remote-path)) (default-remote-path - (when elt1 - (or - (tramp-send-command-and-read - vec - (format - "echo \\\"`getconf PATH 2>%s`\\\"" - (tramp-get-remote-null-device vec)) - 'noerror) - ;; Default if "getconf" is not available. - (progn - (tramp-message - vec 3 - "`getconf PATH' not successful, using default value \"%s\"." - "/bin:/usr/bin") - "/bin:/usr/bin")))) + (when elt1 + (or + (with-tramp-connection-property + (tramp-get-process vec) "default-remote-path" + (tramp-send-command-and-read + vec + (format + "echo \\\"`getconf PATH 2>%s`\\\"" + (tramp-get-remote-null-device vec)) + 'noerror)) + ;; Default if "getconf" is not available. + (progn + (tramp-message + vec 3 + "`getconf PATH' not successful, using default value \"%s\"." + "/bin:/usr/bin") + "/bin:/usr/bin")))) (own-remote-path ;; The login shell could return more than just the $PATH ;; string. So we use `tramp-end-of-heredoc' as marker. (when elt2 (or - (tramp-send-command-and-read - vec - (format - "%s %s %s 'echo %s \\\"$PATH\\\"'" - (tramp-get-method-parameter vec 'tramp-remote-shell) - (string-join - (tramp-get-method-parameter vec 'tramp-remote-shell-login) - " ") - (string-join - (tramp-get-method-parameter vec 'tramp-remote-shell-args) - " ") - (tramp-shell-quote-argument tramp-end-of-heredoc)) - 'noerror (rx (literal tramp-end-of-heredoc))) + (with-tramp-connection-property + (tramp-get-process vec) "own-remote-path" + (tramp-send-command-and-read + vec + (format + "%s %s %s 'echo %s \\\"$PATH\\\"'" + (tramp-get-method-parameter vec 'tramp-remote-shell) + (string-join + (tramp-get-method-parameter vec 'tramp-remote-shell-login) + " ") + (string-join + (tramp-get-method-parameter vec 'tramp-remote-shell-args) + " ") + (tramp-shell-quote-argument tramp-end-of-heredoc)) + 'noerror (rx (literal tramp-end-of-heredoc)))) (progn (tramp-warning vec "Could not retrieve `tramp-own-remote-path'") diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index 3be81449c9c..1efafb68fbc 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -282,8 +282,7 @@ being the result.") (delete-directory file 'recursive) (delete-file file)))))) ;; Cleanup connection. - (ignore-errors - (tramp-cleanup-connection tramp-test-vec nil 'keep-password))) + (tramp-cleanup-connection tramp-test-vec nil 'keep-password)) ;; Return result. (cdr tramp--test-enabled-checked)) @@ -2175,8 +2174,7 @@ being the result.") (dolist (m '("su" "sg" "sudo" "doas" "ksu")) (when (assoc m tramp-methods) (let (tramp-connection-properties tramp-default-proxies-alist) - (ignore-errors - (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)) + (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password) ;; Single hop. The host name must match `tramp-local-host-regexp'. (should-error (find-file (format "/%s:foo:" m)) commit 9faa8d32a3db893db01debaaaa1db79ec1c1b33e Merge: 0c8abe8bb50 ded77fefffa Author: Po Lu Date: Wed Feb 19 20:42:22 2025 +0800 Merge from savannah/emacs-30 ded77fefffa Fix remaining Android bugs reported over the past months commit ded77feffface0c167edacf0d807273f3d4878db Author: Po Lu Date: Wed Feb 19 20:40:12 2025 +0800 Fix remaining Android bugs reported over the past months * java/org/gnu/emacs/EmacsActivity.java (attachWindow): Guarantee that child windows promoted to toplevels receive layout parameters that direct them to receive their parents' dimensions. Otherwise, the size of the window as a child is retained on Huawei HarmonyOS 4.2 and possibly other Android distributions. * java/org/gnu/emacs/EmacsService.java (updateCursorAnchorInfo): Run anchor updates on the UI thread, as `InputMethodManager#updateCursorAnchorInfo' is liable to call `View#requestLayout'. * java/org/gnu/emacs/EmacsView.java (onMeasure): Always call `measureChildren', or child frames' onLayout handlers might not be invoked after they request a layout cycle and are duly processed in `onLayout'. (swapBuffers): Delete erroneous commentary. * java/org/gnu/emacs/EmacsWindow.java (viewLayout): If overrideRedirect, don't inadvertently clear rect.left and rect.top by recording the window's WM window-relative position. Fix typos. (reparentTo): Invalidate focus after transferring frame. (translateCoordinates): Account for override-redirect windows. Mostly important for mouse-drag-and-drop-region. diff --git a/java/org/gnu/emacs/EmacsActivity.java b/java/org/gnu/emacs/EmacsActivity.java index 8a5ccb4625b..9f36561cc02 100644 --- a/java/org/gnu/emacs/EmacsActivity.java +++ b/java/org/gnu/emacs/EmacsActivity.java @@ -179,6 +179,8 @@ children and RESETWHENCHILDLESS is set (implying it is a public final void attachWindow (EmacsWindow child) { + FrameLayout.LayoutParams defaultParams; + if (window != null) throw new IllegalStateException ("trying to attach window when one" + " already exists"); @@ -187,8 +189,15 @@ children and RESETWHENCHILDLESS is set (implying it is a /* Record and attach the view. */ + /* Reset residual LayoutParams that might remain in effect on this + window, or some distributions of Android (e.g. Huawei HarmonyOS + 4.2) will retain the size of this window as a child frame. */ + defaultParams + = new FrameLayout.LayoutParams (FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT); + syncFullscreenWith (child); window = child; - layout.addView (window.view); + layout.addView (window.view, defaultParams); child.setConsumer (this); /* If the window isn't no-focus-on-map, focus its view. */ diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index 04563590dc4..8cdf5011b70 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java @@ -937,11 +937,11 @@ invocation of app_process (through android-emacs) can } public void - updateCursorAnchorInfo (EmacsWindow window, float x, + updateCursorAnchorInfo (final EmacsWindow window, float x, float y, float yBaseline, float yBottom) { - CursorAnchorInfo info; + final CursorAnchorInfo info; CursorAnchorInfo.Builder builder; Matrix matrix; int[] offsets; @@ -963,9 +963,14 @@ invocation of app_process (through android-emacs) can Log.d (TAG, ("updateCursorAnchorInfo: " + x + " " + y + " " + yBaseline + "-" + yBottom)); - icBeginSynchronous (); - window.view.imManager.updateCursorAnchorInfo (window.view, info); - icEndSynchronous (); + EmacsService.SERVICE.runOnUiThread (new Runnable () { + @Override + public void + run () + { + window.view.imManager.updateCursorAnchorInfo (window.view, info); + } + }); } diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java index 8af76c73937..5abea711506 100644 --- a/java/org/gnu/emacs/EmacsView.java +++ b/java/org/gnu/emacs/EmacsView.java @@ -296,6 +296,9 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST && height > MeasureSpec.getSize (heightMeasureSpec)) height = MeasureSpec.getSize (heightMeasureSpec); + /* This is strictly necessary to propagate layout requests to + children. */ + this.measureChildren (widthMeasureSpec, heightMeasureSpec); super.setMeasuredDimension (width, height); } @@ -467,9 +470,6 @@ else if (child.getVisibility () != GONE) } } - /* This method is called from both the UI thread and the Emacs - thread. */ - public void swapBuffers () { @@ -620,8 +620,7 @@ else if (child.getVisibility () != GONE) detachViewFromParent (index); /* The view at 0 is the surface view. */ - attachViewToParent (child, 1, - child.getLayoutParams ()); + attachViewToParent (child, 1, child.getLayoutParams ()); } } diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java index 2f4e378fb78..861bcace2ad 100644 --- a/java/org/gnu/emacs/EmacsWindow.java +++ b/java/org/gnu/emacs/EmacsWindow.java @@ -50,6 +50,7 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.view.ViewManager; import android.view.WindowManager; @@ -331,23 +332,39 @@ private static class Coordinate { int rectWidth, rectHeight; - rect.left = left; - rect.top = top; - rect.right = right; - rect.bottom = bottom; - - rectWidth = right - left; - rectHeight = bottom - top; + /* If this is an override-redirect window, don't ever modify + rect.left and rect.top, as its WM window will always have been + moved in unison with itself. */ + if (overrideRedirect) + { + rect.right = rect.left + (right - left); + rect.bottom = rect.top + (bottom - top); + } /* If parent is null, use xPosition and yPosition instead of the geometry rectangle positions. */ - - if (parent == null) + else if (parent == null) + { + rect.left = xPosition; + rect.top = yPosition; + rect.right = rect.left + (right - left); + rect.bottom = rect.top + (bottom - top); + } + /* Otherwise accept the new position offered by the toolkit. FIXME: + isn't there a potential race condition here if the toolkit lays + out EmacsView after a child frame's rect is set but before it + calls onLayout to read the modifies rect? */ + else { - left = xPosition; - top = yPosition; + rect.left = left; + rect.top = top; + rect.right = right; + rect.bottom = bottom; } + rectWidth = right - left; + rectHeight = bottom - top; + return EmacsNative.sendConfigureNotify (this.handle, System.currentTimeMillis (), left, top, rectWidth, @@ -1363,6 +1380,11 @@ else if (keyCode >= KeyEvent.KEYCODE_NUMPAD_0 EmacsWindowManager manager; ViewManager parent; + /* Invalidate the focus; this should transfer the input focus + to the next eligible window as this window is no longer + present in parent.children. */ + EmacsActivity.invalidateFocus (7); + /* First, detach this window if necessary. */ manager = EmacsWindowManager.MANAGER; manager.detachWindow (EmacsWindow.this); @@ -1637,6 +1659,18 @@ else if (EmacsWindow.this.isMapped) array[0] += x; array[1] += y; + /* In the case of an override redirect window, the WM window's + extents and position match the Emacs window exactly. */ + + if (overrideRedirect) + { + synchronized (this) + { + array[0] += rect.left; + array[1] += rect.top; + } + } + /* Return the resulting coordinates. */ return array; }