GNU EMACS FOR OPENVMS VAX -- 19.28 AND 21.2, BINARY AND SOURCE KIT
==================================================================
Douglas P. Fields, Jr.  <symbolics@lisp.engineer>      23 September 2026
(first published 20 September 2026; this kit is built FROM THE
REPOSITORY -- vax/19.28 and vax/21.2, commit ids in section 6 -- not
from the original hand-built tree)

Two terminal-only (no DECwindows) builds of GNU Emacs for OpenVMS VAX,
built and tested on OpenVMS VAX V7.3 with Compaq C V6.4 on a VAXstation
4000/96, and installed from this kit on a VAXstation 4000/60 and on a
simulated MicroVAX 3900 (SIMH).

  GNU Emacs 19.28   Richard Levitte's VMS port ("VMS patches created on
                    Wednesday, December 25 1996").  Small and quick:
                    about 815 files, 24 MB.  The long-proven one.
  GNU Emacs 21.2    Thien-Thi Nguyen's VMS port (emacs212_3).  As far as
                    we could find it had only run on Alpha, Itanium and
                    x86-64; this is a VAX build.  Text-mode menu bar,
                    MULE, font-lock, 1,894 files, 76 MB.

The 21.2 tree used here came by way of Eric Brown's OpenVMS x86-64 work
on that port (configure.com for current VMS, vms7-3.h, TRADCPP); our VAX
changes sit on top of his.  Thanks to him, to Thien-Thi Nguyen and to
Richard Levitte.

They install side by side, share no file, and can each be running as a
"kept editor" at the same time.  Emacs is free software under the GNU
General Public License (see ETC]COPYING in either tree); the matching
source, and every change made to it, is in the source kit.  There is NO
WARRANTY.


1. REQUIREMENTS
---------------
 * OpenVMS VAX V7.3.  Older versions are UNTESTED.  (Not Alpha, not
   Itanium: these are VAX images.)
 * TCP/IP Services for OpenVMS.  Both images are linked against
   UCX$IPC_SHR; without it they presumably will not activate (untested).
 * About 400,000 free blocks (200 MB) on the system disk while installing
   both versions: 196,000 for the savesets, which you can delete
   afterwards, and about 190,000 for the two installed trees.
 * SYSTEM (or SYSPRV) to install.  No compiler is needed.
 * The install location is FIXED.  The directory is compiled into the
   images, so they run from SYS$SYSDEVICE:[GNU...] and nowhere else:
        19.28   SYS$SYSDEVICE:[GNU.BIN], [GNU.LIB...], [GNU.INFO], ...
        21.2    SYS$SYSDEVICE:[GNU.EMACS21...]
   To use another location, rebuild from the source kit with a different
   --prefix (section 6).


2. WHAT IS IN THE BINARY KIT
----------------------------
  EMACS1928_VAX.BCK      BACKUP saveset, 47,376 blocks (24,256,512 bytes)
  EMACS212_VAX.BCK       BACKUP saveset, 148,491 blocks (76,027,392 bytes)
  EMACS_KIT_INSTALL.COM  the installer
  GNU_EMACS_LOGIN.COM    defines EMACS, EMACS19, EMACS21 at login
  KEPTEMACS.COM          the kept-editor procedure
  EMACSTEST.COM, .EL     regression test
  EMACSTEST-HELPER.COM   makes the two record-format files EMACSTEST.EL
                         cannot make itself -- REQUIRED alongside them
  GNU_STARTUP.COM        19.28's own startup procedure (boot-time logicals)
  MAKE_EMACS_KIT.COM     how the savesets were made
  SHA256SUMS.TXT         checksums of all of the above
Either saveset may be left out; the installer installs what it finds.


3. INSTALLING
-------------
Get all the files into ONE directory on the VAX.  Create the directory
at a terminal first.  TRANSFER MODES MATTER:

  the two .BCK savesets          BINARY  (FTP "binary")
  every .COM, .EL and .TXT file  TEXT    (FTP "ascii")

A procedure sent in binary arrives as 512-byte fixed-length records, and
DCL answers the first command you type with
        %RMS-W-RTB, 512 byte record too large for user's buffer
The kit is not corrupt: send the text files again in ascii mode.  (UnZip
for VMS gets both kinds right by itself.)

The savesets arrive with the wrong record attributes however they travel,
and BACKUP would say "not a BACKUP save set"; the installer fixes that
itself, with
        SET FILE/ATTRIBUTES=(RFM:FIX,LRL:32256,MRS:32256,RAT:NONE)

  $ SET DEFAULT dev:[the.kit.directory]
  $ @EMACS_KIT_INSTALL CHECK        ! says what it would do; changes nothing
  $ @EMACS_KIT_INSTALL

It announces each step:
  1. sets the savesets' record attributes
  2. restores them to SYS$SYSDEVICE:[GNU...] with BACKUP/NEW_VERSION (every
     restored file becomes the new highest version), then PURGEs
     SYS$SYSDEVICE:[GNU...] down to one version per file -- so installing
     twice, or over an older copy of this kit, is safe and leaves exactly
     one copy of everything.  (An earlier version of this installer used
     BACKUP/REPLACE, which only overwrites a file already on disk at the
     SAME version number the saveset carries; once a target's own versions
     had drifted -- any earlier reinstall bumps them -- the next kit landed
     BESIDE the old files instead of replacing them, roughly doubling the
     tree.  Fixed R09, MEASURED: see reviews/R09-request.md.)  A file you
     edited IN PLACE under [GNU...] is still overwritten -- keep site
     changes in the SITE-LISP directory.
  3. makes everything world-readable
  4. copies the four shared procedures to SYS$SYSDEVICE:[GNU]
  5. copies GNU_STARTUP.COM to SYS$COMMON:[SYS$STARTUP] if none is there;
     if one is, leaves it alone and says whether it matches the kit's
  6. shows the two lines that SYLOGIN.COM needs and ASKS before adding
     them (the old file remains as the previous version); on a 19.28
     install, ASKS SEPARATELY before adding the ETAGS/B2M/EMACSCLIENT line
     too (see below), inserted ABOVE the first.  It never touches
     SYSTARTUP_VMS.COM; it prints the one line to add yourself:
        $ @SYS$STARTUP:GNU_STARTUP * "TABLE=/SYSTEM,QUIET"
     (19.28 only: the ESHELL logical name and the GNU help library.)
  7. runs the regression test; the procedure's exit status is the test's.

The SYLOGIN lines define EMACS, EMACS19, EMACS21 and the RUNEMACS
commands.  19.28's other commands -- ETAGS, B2M, EMACSCLIENT -- come from
GNU_STARTUP itself; the installer now offers to add this line for you,
ABOVE the lines it added for EMACS/EMACS19/EMACS21 -- answer its second
question, or add it yourself:
        $ @SYS$STARTUP:GNU_STARTUP * NOLOGICALS,QUIET
Either SYLOGIN edit goes before a final "$ EXIT" (any case, with or
without a status) if the file ends with one, otherwise at the end.  THE
INSTALLER DOES NOT DETECT an EXIT inside an IF block, or a SYLOGIN.COM
that branches around its own end -- it will append after such an EXIT
instead of before it.  Read the result (the procedure prints the new
file's version number) if your SYLOGIN.COM does either.
It stops, having changed nothing further, if BACKUP cannot restore.

To remove:  delete SYS$SYSDEVICE:[GNU.EMACS21...] for 21.2, or all of
[GNU...] for both; take the hook lines out of SYLOGIN.COM and
SYSTARTUP_VMS.COM; delete SYS$COMMON:[SYS$STARTUP]GNU_STARTUP.COM.


4. USING IT
-----------
After the next login (or  @SYS$SYSDEVICE:[GNU]GNU_EMACS_LOGIN ):

  $ EMACS19 [file]      GNU Emacs 19.28       $ EMACS21 [file]    21.2
  $ EMACS   [file]      the default version
  $ RUNEMACS21 -batch -l file.el               run directly, no kept process

EMACS / EMACS19 / EMACS21 start a KEPT EDITOR: C-z returns you to DCL and
leaves Emacs alive in a subprocess; the same command re-attaches to it
with your buffers intact.  C-x C-c really exits.

The default is 19.28 if installed.  To change it, define the logical name
GNU_EMACS_DEFAULT as 19 or 21 -- for everyone:
  $ DEFINE/SYSTEM/EXECUTIVE GNU_EMACS_DEFAULT 21      (and at boot)
or for yourself, in LOGIN.COM, followed by @SYS$SYSDEVICE:[GNU]GNU_EMACS_LOGIN

Keyboards.  On a terminal, "M-x" means press ESC, then x.  DEC LK201 /
LK401 / LK411 keyboards have no Esc key: use F11 (both builds map it),
or Ctrl-[ anywhere.  If Ctrl-S freezes the screen instead of searching,
a terminal, terminal server or emulator is using it for flow control:
either turn XON/XOFF off there, or  M-x enable-flow-control  and then
use C-\ for C-s and C-^ for C-q.

Terminal types VT100 through VT500-series are recognised as VMS reports
them (SET TERMINAL/INQUIRE).  For anything else:
  $ DEFINE EMACS_TERM "vt200"


5. TESTING
----------
  $ @SYS$SYSDEVICE:[GNU]EMACSTEST [19|21|ALL] [mutate-check-name]

254 checks per version (255 with the one KNOWN_BUG line), in 20 named
GROUPs: the Lisp system, regexps, strings and lists, time and timers,
VMS file version numbers, VMS file names and search lists, record
formats (Stream, Variable, VFC), backup and auto-save, file attributes,
file-name completion (the class the 21.2 completion crash slipped
through) and dired, access checks compared
with the privileges the process actually holds, synchronous and
asynchronous DCL subprocesses, garbage collection under load, byte
compilation, editing primitives, and system information.  It prints
"GROUP name" once per group, "PASS name" / "FAIL name: detail" per
check, "KNOWN_BUG name" for a check that asserts a currently-open bug's
behaviour on purpose, and a final "EMACSTEST: n passed, m failed, k
known bugs" line; it exits with a VMS error status if anything FAILED
(a KNOWN_BUG does not count as a failure).  RUN IT AS AN ORDINARY USER
TOO: several of the bugs below exist only for unprivileged users or
only in -batch.

P2, if given, is a check NAME exactly as printed: that one check's
outcome is deliberately negated (EMACSTEST_MUTATE), so its FAIL line and
this procedure's own bad exit status can be demonstrated on demand --
the fail-first proof every check in this suite has been shown to pass,
either this way or against a real known-bad image (the completion group
against the pre-patch-10 build; several subprocess checks against a
pre-patch-8 build).  To run against a different image for one version
(such as a known-bad build), define RUNEMACS19 or RUNEMACS21 locally in
the session before calling this procedure -- it reads whatever symbol is
in effect.  EMACSTEST-HELPER.COM (it creates the Variable-length and VFC
files the record-formats group reads) travels next to EMACSTEST.COM and
EMACSTEST.EL -- in the installed SYS$SYSDEVICE:[GNU] for the command
above, or wherever else you copy all three files together.  EMACSTEST.COM
defines the EMACSTEST_HOME logical to that directory before loading
EMACSTEST.EL, which finds the helper there; EMACSTEST_HOME falls back to
SYS$LOGIN: only if EMACSTEST.EL is loaded some other way (e.g.
"RUNEMACSnn -batch -l EMACSTEST.EL" by hand, from a directory holding
both files, without going through EMACSTEST.COM).  Nothing needs to be
copied into SYS$LOGIN: first: the command above works for any account,
from a fresh login, with nothing uploaded.

Verified 20/21-SEP-2026 with the original 33-check suite: 25/25, then
33/33, for both versions, as SYSTEM and as an unprivileged user, on the
build machine and on machines installed from this kit.  Grown to 245
checks in 20 groups 22-SEP-2026 (R06): every check shown to fail on
demand (mutation) or, for the patch-10 (completion group) and patch-8
(subprocess checks) guards, against the preserved pre-patch image;
244-245/245 for both versions as SYSTEM, USER1 and EMTEST (NOPRIV) on
the build machine, one open bug each on 19.28 (a timer, KNOWN_BUG) and
21.2 (a directory writability check, KNOWN_BUG, unprivileged only);
full run under 2 minutes per version.  Also by hand, earlier: both kept
editors at once, M-!, and M-x shell, as the unprivileged user.

Grown to 254 checks 23-SEP-2026 (R09), against a kit built and installed
FROM THE REPOSITORY -- fresh installs on the build machine (VAX96), a
true clean-room simulator install (nothing pre-existing, every account
and file created by the kit itself), and a reinstall of the hardware
install machine (VAX60): 254 passed + 1 known bug, BOTH versions, on
EVERY target, as SYSTEM/PRIV, an unprivileged account, and a NOPRIV-only
account.  The simulator's is its first real baseline ever (it had only
ever carried a pre-kit 19.28 before).  See reviews/R09-request.md for
every count and transcript.


6. THE SOURCE KIT, AND WHAT WAS CHANGED
---------------------------------------
As of R09 (23-SEP-2026) the source kit is built straight from this
project's own git repository, not from a hand-assembled changes/
directory:
  emacs-19_28-19961225.zip           Richard Levitte's 19.28 VMS kit,
                                      UNMODIFIED (the true upstream)
  emacs-21.2-vms-x86-64.zip          Eric Brown's 21.2 VMS x86-64 kit
                                      (emacs212_3), UNMODIFIED
  emacs-19.28-vax-source-8ef4c9a.zip `git archive` of this repository's
                                      vax/19.28 branch, commit
                                      8ef4c9ae6e8f1d7509920252b23bb667e
                                      54f3e98 -- the COMPLETE tree as
                                      built (every file, not a diff)
  emacs-21.2-vax-source-07e550d.zip  `git archive` of vax/21.2, commit
                                      07e550d3068fb3b4209b357b2679774950
                                      c9bd0a -- likewise complete
  SOURCE_KIT_README.TXT, SHA256SUMS.TXT
The two vax/* archives ARE the ten changes below (and every build-system
repair), already applied, as ordinary source files -- "diff" them against
the two unmodified upstream archives yourself, or read the changes as
commits in the repository's own `emacs/` submodule history (`git log
vax/19.28`, `git log vax/21.2`).  Older kits (through 21-SEP-2026)
carried a hand-built emacs-NN-vms-vax-changes/ directory of whole
pristine/patched file pairs instead; that format is retired.

To build 21.2 from the vax/21.2 archive: unzip it in a directory under
your own account, then
  $ SUBMIT/NOPRINT/LOG_FILE=SYS$LOGIN:E21.LOG/PARAMETERS=(CONFIGURE) -
        dev:[...]BUILD_EMACS21.COM
(18 minutes on a 4000/96), and the same with /PARAMETERS=(INSTALL) as
SYSTEM.  P2 is the prefix if you want another one.  Needs Compaq C and
MMS.  19.28 has no BUILD_EMACS21.COM equivalent yet; build it the way
docs/EMACS_ON_VAX_INSTALLATION.md section 7 describes (configure.com,
then the generated makefiles repaired -- legacy-changes/19.28/
fix_generated.py -- then MMS).

Emacs 21.2 -- ten changes.  1-7 and 10 are VAX-only and leave Alpha/x86
alone:
  1 m/vax.h        compile switch /OPTIMIZE=(LEVEL=5,TUNE=HOST) is Alpha's
  2 emacs.c        <libicb.h> does not exist on VAX (and is not used)
  3 sysdep.c       64-bit integers: the VAX compiler has none.  Privilege
                   mask held as two longwords
  4 vmsproc.c      "long long" delta time -> LIB$EMUL; and XPROCESS()
                   applied to what is already a struct pointer
  5 vmsmap.c       the VAX linker puts the BSS markers beside DATA, so the
                   BSS range duplicated DATA and the dump aborted
  6 vmsfns.c       a symbol name from VSI C on x86-64, typed into the
                   source; on VAX the function is plain sys_access
  7 descrip.mms_in_in   make-docfile commands too long for DCL when the
                   build directory is deep; that batch of docstrings was
                   silently left out of DOC.  Re-batched 3 files per command
  8 vmsproc.c      ALL PLATFORMS.  The last record a subprocess wrote before
                   exiting was dropped (M-! SHOW TIME printed nothing)
  9 sysdep.c       ALL PLATFORMS.  Under -batch, file access was checked as
                   the account that BUILT Emacs, because the UIC is cached
                   in a static that the dump file preserves
 10 dired.c         Compaq C for VAX inlines a function that calls the
                   alloca builtin, then keeps using SP-relative slots after
                   SP has moved: file-name completion (C-x C-f TAB, RET in
                   dired) jumped into data and killed Emacs.  That buffer
                   now comes from the heap.  19.28 is immune: it uses
                   Emacs's own alloca.c
  + etc/termcap.src    VMS terminal names (vt200-80 ...) and VT400/VT500
  + lisp/term/vt500.el new
A traditional C preprocessor (TRADCPP, in the 21.2 kit) is used in place
of Compaq C's, which puts a space between every token and so wrecks the
generated MMS files.  The 19.28 build predates our finding that, and
repairs the generated files with a script instead (fix_generated.py).

Emacs 19.28 -- build-system repairs, plus:
  vmsproc.c        the same dropped-record bug as 8 above
  callproc.c       close() was called on an index into Emacs's own mailbox
                   table; in "emacs -batch -l file.el" that closed the file
                   being loaded, and Emacs died at the next read of it
  etc/termcap.dat  VT400/VT500;  lisp/term/vt500.el new


7. FIXES SINCE THE 21-SEP-2026 KIT
-----------------------------------
By symptom, one line each (full detail: PLAN.md's Status table and TODO
register; commit ids in section 6 above are where they landed):
 * 21.2 M-x shell was slow -- DIRECTORY SYS$SYSTEM: 10.97 -> 1.81 s on
   VAX96 (per-record CPU cost in the pty read path, drained per read).
 * A one-shot asynchronous subprocess (both versions) never exited --
   DCL kept reading for another command, so no sentinel ever ran.
 * A one-shot subprocess's last output record could be dropped at exit.
 * A -batch pty subprocess delivered every output record to its filter
   truncated to its first 10 characters.
 * delete-process of a genuinely idle interactive DCL child hung.
 * 19.28: an interactive shell's exit sentinel ran only at the next
   keystroke, not when the child actually exited.
 * 19.28, -batch: sit-for never returned after an interactive child
   process logged out.
 * 21.2: a failing subprocess's exit status was shown as a Unix signal
   instead of the real VMS completion code.
 * 19.28: dired's RET said "Buffer is read-only" instead of visiting the
   file (now bound the same as f).
 * start-process with a program but no argument (a bare interactive
   subshell) crashed the whole image, both versions.
 * The kit installer doubled the installed tree on a reinstall --
   BACKUP/REPLACE only overwrites a file already at the SAME version the
   saveset carries; a target whose versions had drifted got the new
   files ALONGSIDE the old ones. Fixed with BACKUP/NEW_VERSION + PURGE
   (MEASURED, R09: fail-first reproduced the doubling with a minimal
   saveset, then shown fixed).
 * EMACSTEST-HELPER.COM (required by EMACSTEST.EL for the record-formats
   checks) was missing from the kit entirely -- not packaged, not
   installed, not staged for the installer's own self-test.  Every
   install's regression test, and every future EMACSTEST run, would have
   been missing the two checks that need it. Now packaged, installed to
   SYS$SYSDEVICE:[GNU], and staged to SYS$LOGIN: before the self-test.
 * That fix above was not enough: EMACSTEST.EL still loaded the helper by
   the literal name SYS$LOGIN:EMACSTEST-HELPER.COM, so a genuinely fresh
   account with nothing staged (i.e. every real outside user following
   section 5's own documented command) still failed the record-formats
   group -- caught by an orchestrator review that ran that exact command
   from a fresh login with nothing uploaded. Fixed: EMACSTEST.COM now
   defines EMACSTEST_HOME to its own directory before loading
   EMACSTEST.EL, which finds the helper there, falling back to
   SYS$LOGIN: only when run some other way (section 5). Verified
   fail-first (the old behavior reproduced) then passing, as an
   unprivileged and a NOPRIV-only account, on both hardware machines,
   from fresh logins with nothing uploaded.
 * tests/emacs/run_all.py gained an --installed Tier 1 mode that runs the
   exact command section 5 documents against whatever is already
   installed, with no upload or staging seam -- the check that would have
   caught the bug above; it is this project's release gate from now on.
 * The installer now also offers the ETAGS/B2M/EMACSCLIENT SYLOGIN line
   (19.28 only), previously only printed as an instruction to add by
   hand (section 3 above).
 * tools/vaxsync.py's `unpack` refuses a non-empty target unless
   --purge is given (a repeated UNZIP into one doubled its file count
   too, the same class of bug as the installer's).


8. KNOWN LIMITATIONS
--------------------
 * 21.2 images built before 20-SEP-2026 20:30 (none was published) die in
   file-name completion: change 10 above.  To tell, complete a file name:
   a fixed Emacs prints a list, an unfixed one dies with a traceback
   naming file_name_completion.  EMACSTEST checks it.
 * 21.2: a completion list shows a name once per VMS file version, so the
   same name can appear several times; 19.28 shows it once.
 * No X/DECwindows support was built.
 * Output captured from a subprocess ends with one extra blank line.
 * 19.28, M-x shell: the mode line keeps saying "run" after the subshell
   has logged out.
 * 19.28 is configured with the VMS 5.5 system description, the newest
   that kit has; it works on 7.3.
 * The link reports %LINK-W-MULDEF for DECC$MALLOC, DECC$FREE ... and the
   directory routines: Emacs's own versions replacing the C library's, by
   design, in both ports.
 * GNU_STARTUP.COM carries the build machine's node name in comment lines.
   They are data for the kit's own installer and are never executed.
 * Neither version notices a terminal window resize; redraw at the new
   width needs an explicit M-x set-screen-width or C-l.
 * 21.2, unprivileged accounts only: file-writable-p on the account's OWN
   home directory (not a file) says nil, contradicted by a real write
   there succeeding right afterward.  KNOWN_BUG in EMACSTEST.
 * 19.28: run-at-time never fires a scheduled timer in -batch mode (it
   shells out to a `timer` helper program this port never builds).
   KNOWN_BUG in EMACSTEST.  21.2 is unaffected.
