From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  1-AUG-1989 01:11
To:	MRGATE::"ARISIA::EVERHART"
Subj:	RE: Big Mem TeX for VMS

Message-Id:  <8908010453.AA22637@crdgw1.ge.com>
Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Mon, 31 JUL 89 08:19:01 PDT
Received: from Venus.YCC.Yale.Edu by KL.SRI.COM with TCP; Mon, 31 Jul 89 07:52:25 PDT
Date: Mon, 31 Jul 89 10:54 EDT
From: "Jerry Leichter - LEICHTER-JERRY@CS.YALE.EDU"
 <LEICHTER@Venus.YCC.Yale.Edu>
Subject: RE: Big Mem TeX for VMS
To: phri!marob!samperi@nyu.EDU, INFO-VAX@KL.SRI.COM
X-Vms-To: IN%"phri!marob!samperi@nyu.EDU"

	We have both the free DECUS TeX software, and the commercial Arbortext
	version of TeX. Both versions choke on complex (typical here) pages,
	due to stupid memory limitations. It was easy to port CTeX to VMS, and
	when compiled with the BIGG option, the memory limitation problems
	went away.  Unfortunately, CTeX is much slower than DECUS/Arbortext
	TeX. This would be OK, but for the fact that we do not have a full set
	of pixel (or .GF) files, and METAFONT crashes due to that stupid
	memory limitation when we try to build missing pixel files. It's
	turning into a huge project to bring up a full functional TeX under
	VMS, with a complete list of pixel files.

	Could somebody suggest where a complete TeX implementation can be
	obtained for VMS, without the common (stupid) memory limitation, and
	with a complete set of pixel or .GF files? (GF files are sufficient,
	since we want to run all of our dvi files through PostScript filters,
	by means of dvi2ps.)

Adrian Clark has created a change file for an extended VMS TeX.  Besides sup-
porting very large amounts of memory, it has some other VMS goodies, like an
editor interface.  I've agreed to distribute the stuff in the US.  Since this
message will undoubtedly inspire a whole bunch of requests which I cannot pos-
sibly deal with one at a time, I'm enclosing below exactly what you would get
from me if you asked for this stuff.  Be aware:  You will have to be a TeX
guru to make use of it.  You are expected to know how to update change files
for newer (or older - downdate?) versions of TeX, build an INITEX.CH from a
VIRTEX.CH, and so on.  NO HELP ON THIS IS AVAILABLE FROM ME!!!!

On the matter of font files:  I don't know what memory limitations you are
running into.  Metafont, built using the standard change files available from
Score, should be able to build any font in the standard TeX set.

I know of no easy sources for a complete set of TeX fonts.  There are too many
of them, and they have to be tuned for a particular print engine.  There's a
good collection on Score, but I don't know what printer they were built for.

BTW, there is no reason today to be using .GF files as anything other than an
intermediate representation on the way to .PK files.  There is no reason to be
using .PXL files at all.  .PK files are much smaller, and can actually be read
more quickly than .GF files.  (.PXL files MIGHT have an advantage here, but it
is not a large one.)  Whether you use Postcript filters or anything else is of
no relevance here.
							-- Jerry
------------------Cover Letter---------------------
Either included below or sent under separate cover is ALIEN.ARC, a DECUS C
archive containing Adrian Clark's TeX change files.  The archive contains
three files:  NOTE.TEX is the source for a TUGboat article that described
this stuff; TEX_BITS.FOR is a small FORTRAN program providing some interface
functions - compile it and include it when you link TeX; and VIRTEX.ALIEN,
the change file needed to create VIRTEX.  I assume you know how to create a
corresponding INITEX file - since they differ in only a couple of lines, it's
a real waste for me to send both.

You can split a DECUS C archive up with the DECUS C archx program, or you can
use an editor - just look for lines starting "-h-".  (Actually, lines that
start "--" should have one "-" removed.  I think there is one of those in
the archive, and it is part of a comment.)  Or you can use the "ARCHX.COM"
file I've enclosed below.

The VIRTEX change file corresponds to TeX V2.94.  I haven't had the chance
to make an updated version, and I probably won't in the near future, but
99.99% of the time all that's required is to change the "2.94" in the two
"banner lines" to "2.98" (or whatever).  (Have a look at other "2.94"'s
just to be sure.)  If TANGLE accepts the result without complaint, it should
work fine.  If it doesn't, someone (probably Adrian) will have to figure out
exactly what in TeX changed.  (This kind of change hasn't occured in a long,
long time.)

Good luck!
							-- Jerry

------------------ARCHX.COM------------------------
$! archx written (quickly) in DCL [by Martin Minow]
$	was_verify = 'f$verify(0) + f$verify(0'archx_verify' .gt. 0)
$	on control_y then goto abnormal_exit
$	on warning then goto abnormal_exit
$! Hack command argument
$	source = p1
$	if source .eqs. "" then -
	    read/end=abnormal_exit/prompt="Archive source file: " -
	    sys$command source
$	outname = ""
$	if f$parse(source,,,, "SYNTAX_ONLY") .eqs. "" then goto noinput
$	source = f$parse(source, ".ARC")
$	open/read/error=noinput input 'source'
$ read:
$	read/end=endfile/error=abnormal_exit input line
$	if f$extract(0, 3, line) .eqs. "-h-" then goto gotheader
$	if f$extract(0, 1, line) .nes. "-" then goto dowrite
$	line = f$extract(1, f$length(line), line)
$ dowrite:
$	if outname .nes. "" then goto write
$	    write sys$output "No output file, skipping ""''line"""
$	    goto read
$ write:
$	count = count + 1
$	write output line
$	goto read
$!
$ gotheader:
$	if outname .nes. "" then close output
$	if outname .nes. "" then -
$	    write sys$output "  Closed ""''outname'"", wrote ''count' records."
$	outname = f$element(1, " ", line)
$	i = f$locate("	", outname)		! Note: "<TAB>"
$	outname = f$extract(0, i, outname)	! Might get whole string
$ docreate:
$	if f$parse(outname,,,, "SYNTAX_ONLY") .eqs. "" then goto nocreate
$	outname = f$parse(outname,".")
$	open/write/error=nocreate output 'outname'
$	write sys$output "Creating ""''outname'"""
$	count = 0
$	goto read
$	exit
$ noinput:
$	write sys$error "Can't open ""''source'"""
$	if .not. $status then write sys$error f$message($status)
$	goto abnormal_exit
$!
$ nocreate:
$	write sys$error "Can't create ""''outname'"""
$	if .not. $status then write sys$error f$message($status)
$	if f$mode() .eqs. "INTERACTIVE" then goto askforoutput
$	write sys$error " ... Skipping this file"
$	outname = "NL:"
$	goto docreate
$!
$ askforoutput:
$	read/end=abnormal_exit/prompt="Output for ""''line'"": " -
	    sys$command outname
$	goto docreate
$!
$ endfile:
$	close input
$	if outname .nes. "" then close output
$	if outname .nes. "" then -
$	    write sys$output "  Closed ""''outname'"", wrote ''count' records."
$	$status = 1				! SS$_NORMAL (How do right?)
$	goto normal_exit
$!	
$ abnormal_exit:
$	status = $status			!save failure status
$	if status then status = "%x08000002"	!force error if neccessary
$	set noon
$	goto exit
$ normal_exit:
$	status = $status			!save success status
$ exit:
$	exit ('status' .or. %x10000000) + f$verify(was_verify) * 0

-----------------------------archive--------------------------
-h- note.tex	Mon Feb 13 11:02:01 1989	USERCS:[LEICHTER.TEX.ALIEN]NOTE.TEX;3
% --- ------------------------------------------------------------------------
% --- Note on the Enhanced TeX-editor interface for VMS.
% --- (Submitted to TUGboat)
% --- ------------------------------------------------------------------------

% --- ------------------------------------------------------------------------
% --- Mnemonics and macros.
% --- ------------------------------------------------------------------------

\def\|#1|{{\tt#1}}

\def\VAX{\leavevmode\hbox{V\kern-.12em A\kern-.1em X}}
\def\VMS{\leavevmode\hbox{V\kern-.06em MS}}

% --- ------------------------------------------------------------------------
% --- Document style.
% --- ------------------------------------------------------------------------

\nofiles
\documentstyle[TUGBOAT]{article}
%\documentstyle[11pt,date,A4]{article}

\title{An Enhanced \TeX-Editor Interface for \VMS}
\author{Adrian F. Clark\\
   Essex University}

\begin{document}
   \maketitle

\noindent The author described various enhancements to the Stanford
distribution of \TeX\ under \VAX/\VMS\ in a couple of previous articles. The
most significant of these was to allow an editor to be invoked (by typing
`\|e|' or `\|E|') when \TeX\ spotted an error in its input file.  The editor
which was interfaced to \TeX\ at that time was \|TPU|.  Since then, a number of
requests have been made for interfaces to other editors, usually \|EDT|.  The
author is pleased to announce that this has now been done, in a way which is
fully compatible with the previous editor interface.  This note discusses the
interfaces to the editors usually encountered under \VMS\ and shows how other
editors can also be used.

\VMS\ is supplied with a number of editors: \|EDT| and, latterly, \|TPU| are
the most widely used, but \|Real Programmers| and people who have used other
DEC systems sometimes prefer \|TECO|; those of us who remember the bad old days
under \VMS^1 will probably be familiar with \|SOS| (which, although
unsupported, can still be acquired through DECUS).  There are also layered
products which provide editors, such as \|LSE| (language-sensitive editor) and
a Unix-compatible \|ed| in DECshell.  And, of course, there are third party and
public-domain products---for example, Gnu \|Emacs| and \|STE|, the {\sl
Software Tools\/} editor.

The basic strategy for invoking an editor from \TeX\ is (in \VMS\ jargon) to
spawn a sub-process which executes a DCL command to edit the erroneous \TeX\
input file. When the corrections have been made, the editor is exited, the
sub-process deleted and control returned to the \TeX\ session.  However,
sub-process creation and deletion is rather slow under \VMS, so invoking
editors in this way can give an unsatisfactory response on systems with a
significant load.  For this reason, both \|TPU| and \|EDT| are {\em
callable,\/} i.e.\ they can be invoked as procedures from \TeX; this gives a
much better response.

To decide which editor to use, \TeX\ looks at the logical name \verb|TEX$EDIT|
(by analogy with \|MAIL| and other utilities).  This should translate to the
name of the editor to be used (see below).  If the logical name is not defined,
\|TPU| is selected, for compatibility with the previous version of the editor
interface.  Following selection of the editor, \TeX\ translates the logical
name \verb|TEX$EDIT_INIT|, which should give the initialisation file for the
appropriate editor.  (For \|TPU|, if \verb|TEX$EDIT_INIT| does not exist, \TeX\
translates \verb|TEX$TPU_INI|, again for compatibility with the previous
version).  What happens next depends on the chosen editor.

For \|TPU|, a scratch file is created and the contents of any initialisation
file copied to it.  Commands are added to position the cursor at the place
where \TeX\ spotted the error.  The scratch file is then used as the \|TPU|
initialisation file.  After exiting the editor, this scratch file is deleted.

The process for \|EDT| is similar: an initialisation file specified via
\verb|TEX$EDIT_INIT| is copied to a scratch file which is used to initialise
\|EDT|.  However, it is not possible to position the cursor exactly at the
erroneous text automatically (\|EDT| is somewhat lacking in this respect), only
to the right line.  So the command sequence \|GOLD M| is defined, which can be
used to position the column correctly by hand.

Since both \|TPU| and \|EDT| are callable, but only one can be used in a
particular \TeX\ session, it is obviously somewhat inefficient to have both
permanently linked (they are both quite large). Fortunately, both editors are
implemented as {\em sharable images.\/}  This allows \TeX\ to determine which
editor to use via \verb|TEX$EDIT|, then load the appropriate sharable image
using the run-time library routine \verb|LIB$FIND_IMAGE_SYMBOL| before invoking
the editor.

With the possible exception of \|LSE|, which is \|TPU|-based but not available
to the author, the other DEC editors are not callable, and must be invoked, as
would a non-DEC editor, by spawning a DCL command. Of the non-callable editors,
only \|TECO| can position the cursor in its initialisation file.  However,
input to \|TECO| is split into pages (i.e., \|TECO| makes a single pass through
the file with a buffer of finite capacity), so it is not wise to position the
cursor automatically. Instead, a macro is defined in \|q|-register `\|1|' to
perform the positioning.

Any other editor is executed with a fixed sequence of command line arguments,
separated by spaces: the file to be edited; the erroneous line; the erroneous
column; and the initialisation file (if any).  This allows a DCL procedure to
be specified as \verb|TEX$EDIT|, permitting editor-specific processing.
For example, the trivial procedure for use with \|SOS| would be:

\begin{verbatim}
   $ DEFINE/USER SYS$INPUT SYS$COMMAND:
   $ SOS 'P1'
\end{verbatim}

The change file and editor-specific code for \TeX^2.93 can be obtained by
contacting the author at either \|alien@uk.ac.essex.ese| or
\|alien@uk.ac.kcl.ph.ipg|.  Both these addresses are on JANET, the U.K.\
academic network.  The change file also features a large ($>$64K) memory, to
enable the production of PiC\TeX\ graphics and halftone images.

\end{document}
-h- tex_bits.for	Mon Feb 13 11:02:01 1989	USERCS:[LEICHTER.TEX.ALIEN]TEX_BITS.FOR;3
C --- -----------------------------------------------------------------
C ---                          T e X _ B I T S
C
C --- This file contains the additional code required for VAX/VMS TeX.
C --- It is intended for TeX 2.0--0 and later versions.
C --- The routines are:
C
C ---       INVOKE_EDITOR: invoke the editor
C ---          INVOKE_TPU: handle TPU invocation
C ---             INVOKE_TPU$TPU: interface to callable TPU
C ---          INVOKE_EDT: handle EDT invocation
C ---             INVOKE_EDT$EDIT: interface to callable EDT
C ---          INVOKE_TECO: handle TECO invocation
C ---          INVOKE_OTHER: handle invocation of other editor (e.g., Emacs)
C ---          PAD_FN:        filename processing for INVOKE_EDITOR
C ---          TLATE:         translate a logical name
C ---       TTY:           are we being used interactively?
C
C --- This file also has a version number: it is 3.0--0.
C
C --- This code was written by Adrian F. Clark (``Alien''). For further
C --- information, see the accompanying TeX change file.
C
C --- -----------------------------------------------------------------
      SUBROUTINE INVOKE_EDITOR( FN, LINE, CHR )
C --- -----------------------------------------------------------------
C
C --- This TeX-support routine invokes callable TPU to edit the file
C --- FN and attempts to position the cursor at the CHRth character of
C --- line number LINE.
C
C --- Copyright (C) Alien 1988 -- All rights reserved.
C
      IMPLICIT NONE
C
      PARAMETER COMMAND_FILE = 'SYS$SCRATCH:TEX_TEMP.EDIT'
      PARAMETER CMDLUN = 1, INILUN = 2
      INCLUDE '($LNMDEF)'
C
      CHARACTER*(*) FN
      INTEGER LINE, CHR
C
      CHARACTER*255 FULLNAME, EDITOR, INIFN
      CHARACTER*1 NULL, BLANK/' '/
      INTEGER NFN, LFN, NEDITOR, NINIFN, IOS, TLATE
      LOGICAL DELINI, INVOKE_TPU, INVOKE_EDT, INVOKE_TECO, INVOKE_OTHER
C
C --- Locate the last non-blank and non-null character of FN.
C
      NULL = CHAR(0)
      LFN = LEN( FN )
      DO 1 NFN = LFN, 1, -1
         IF( (FN(NFN:NFN).NE.BLANK) .AND. (FN(NFN:NFN).NE.NULL) )
     &    GO TO 2
    1 CONTINUE
C
C --- If we reach here, the string is blank. Produce a warning and return.
C
      PRINT *, 'No filename specified.'
      RETURN
    2 CONTINUE
C
C --- Pad out any missing parts of the filename (usually the .TEX).
C --- PAD_FN returns the number of characters in the filled part of
C --- FULLNAME in NFN.
C
      CALL PAD_FN( FN, NFN, FULLNAME )
C
C --- Translate the logical name TEX$EDITOR, which should give us the
C --- chosen editor.  If it's not defined, use (callable) TPU.  (We
C --- must remember to fold the translation to upper case before
C --- proceeding.)
C
      NEDITOR = TLATE( 'TEX$EDIT', EDITOR )
      IF( NEDITOR .LE. 0 ) THEN
         EDITOR = 'TPU'
         NEDITOR = 3
      ELSE
         CALL STR$UPCASE( EDITOR(1:NEDITOR), EDITOR(1:NEDITOR) )
      END IF
C
C --- Translate the logical name TEX$EDIT_INIT, which should give us the
C --- name of the initialisation file, if any.  If the logical name and
C --- the file both exist, the contents of the file are executed before
C --- the cursor has been positioned at the appropriate line.
C
C --- Note that, if we're using TPU as our editor and TEX$EDIT_INIT does
C --- not exist, we look at the logical name TEX$TPU_INI.  This is for
C --- compatibility with version 2.0 of the editor interface.
C
      NINIFN = TLATE( 'TEX$EDIT_INIT', INIFN )
      IF( (NINIFN .EQ. 0) .AND. (EDITOR(1:NEDITOR) .EQ. 'TPU') )
     &  NINIFN = TLATE( 'TEX$TPU_INI', INIFN )
C
C --- We now branch according to our chosen editor.  The following list
C --- is ordered in preceived likelihood of use.
C
      IF( (EDITOR(1:NEDITOR).EQ.'TPU') .OR.
     &           (EDITOR(1:NEDITOR).EQ.'EVE') ) THEN
C
C --- TPU or EVE.
C
         DELINI = INVOKE_TPU( INIFN, NINIFN, COMMAND_FILE, CMDLUN,
     &     INILUN, FULLNAME(1:NFN), LINE, CHR )
      ELSE IF( EDITOR(1:NEDITOR) .EQ. 'EDT' ) THEN
C
C --- EDT.
C
         DELINI = INVOKE_EDT( INIFN, NINIFN, COMMAND_FILE, CMDLUN,
     &     INILUN, FULLNAME(1:NFN), LINE, CHR )
      ELSE IF( EDITOR(1:NEDITOR) .EQ. 'TECO' ) THEN
C
C --- Good ol' TECO.
C
         DELINI = INVOKE_TECO( INIFN, NINIFN, COMMAND_FILE, CMDLUN,
     &     INILUN, FULLNAME(1:NFN), LINE, CHR )
      ELSE
C
C --- Who knows?
C
         DELINI = INVOKE_OTHER( EDITOR(1:NEDITOR), INIFN, NINIFN,
     &     COMMAND_FILE, CMDLUN, INILUN, FULLNAME(1:NFN), LINE, CHR )
      END IF
C
C --- Delete the command file, if necessary.
C
      IF( DELINI ) THEN
         OPEN( UNIT=CMDLUN, FILE=COMMAND_FILE, STATUS='OLD',
     &     IOSTAT=IOS )
         IF( IOS .EQ. 0 ) THEN
            CLOSE( UNIT=CMDLUN, STATUS='DELETE', IOSTAT=IOS )
            IF( IOS .NE. 0 )
     &        PRINT 100, 'Can''t delete editor command file!'
         ELSE
            PRINT 100, 'Can''t re-open editor command file!'
         END IF
      END IF
C
C --- All done.
C
  100 FORMAT(1X,A/)
      END
C --- -----------------------------------------------------------------
      SUBROUTINE PAD_FN( IN, NCH, OUT )
C --- -----------------------------------------------------------------
C
C --- This routine pads out the filename in IN(1:NCH), returning the
C --- (existing) filename in OUT. NCH is changed to reflect the filled
C --- part of OUT.
C --- We use LIB$FIND_FILE to search first in the current directory
C --- and then in TEX$INPUTS:.
C
C --- Copyright (C) Alien 1987 -- All rights reserved.
C
      IMPLICIT NONE
      INCLUDE '($RMSDEF)'
C
      CHARACTER*(*) IN, OUT
      INTEGER NCH
C
      CHARACTER*1 NULL
      INTEGER N, IOS, CONTEXT, LIB$FIND_FILE
C
C --- Look for the file in the current directory. Since we may be
C --- editing the same input file several times, we must remove any
C --- version number which TeX provides. If we don't do this, we'll
C --- end up editing the same version of the input file every time
C --- we spot a mistake. This will go wrong if the user provides a
C --- version number on the input file. Sigh...
C
      DO 1 N = NCH, 1, -1
         IF( IN(N:N) .EQ. ';' ) GO TO 2
    1 CONTINUE
      N = NCH   ! no version number
    2 CONTINUE
C
      CONTEXT = 0
      IOS = LIB$FIND_FILE( IN(1:N), OUT, CONTEXT, '[].TEX' )
      IF( CONTEXT .NE. 0 ) CALL LIB$FIND_FILE_END( CONTEXT )
      IF( .NOT.IOS .AND. (IOS.NE.RMS$_NMF) ) CALL EXIT( IOS )
      IF( IOS ) GO TO 4
C
C --- Look for the file in TEX$INPUTS:.
C
      IOS = LIB$FIND_FILE( IN(1:N), OUT, CONTEXT, 'TEX$INPUTS:.TEX' )
      IF( CONTEXT .NE. 0 ) CALL LIB$FIND_FILE_END( CONTEXT )
      IF( .NOT.IOS .AND. (IOS.NE.RMS$_NMF) ) CALL EXIT( IOS )
      IF( IOS ) GO TO 4
C
C --- We couldn't find a matching file, so let's try to edit IN.
C
    3 CONTINUE
      OUT = IN
      RETURN
C
    4 CONTINUE
C
C --- We've found a matching file, so locate the last non-blank
C --- character of it and return.
C
      NULL = CHAR(0)
      DO 5 NCH = LEN(OUT), 1, -1
         IF( (OUT(NCH:NCH).NE.' ') .AND. (OUT(NCH:NCH).NE.NULL) )
     &    GO TO 6
    5 CONTINUE
      NCH = 1
    6 CONTINUE
C
      END
C --- -----------------------------------------------------------------
      LOGICAL FUNCTION TTY ( NAME )
C --- -----------------------------------------------------------------
C
C --- This TeX-support routine determines whether NAME is or translates
C --- to a terminal device. It is totally general; it will, for
C --- example, return the value .TRUE. if called with argument 'TTA0'
C --- from a batch job---assuming, of course, you actually have a TTA0.
C
C --- Copyright (C) Alien 1987 -- All rights reserved.
C
      IMPLICIT NONE
C
      INCLUDE '($DCDEF)'
      INCLUDE '($DVIDEF)'
C
      CHARACTER*(*) NAME
C
      INTEGER F, L, LAST
      INTEGER BLK(4), VAL
      INTEGER ISTAT, SYS$GETDVIW
C
C --- BLK is the request block for the SYS$GETDVIW system service.
C
      BLK(1) = ISHFT(DVI$_DEVCLASS, 16) .OR. 4
      BLK(2) = %LOC( VAL )
      BLK(3) = 0
      BLK(4) = 0
      VAL = 0
C
C --- Find the first and last non-blank characters of NAME.
C
      LAST = LEN( NAME )
      DO 1 F = 1, LAST
         IF( NAME(F:F) .NE. ' ' ) GO TO 2
    1 CONTINUE
      GO TO 5
C
    2 CONTINUE
      DO 3 L = LAST, F, -1
         IF( NAME(L:L) .NE. ' ' ) GO TO 4
    3 CONTINUE
      GO TO 5
    4 CONTINUE
C
C --- Get the device information.
C
      ISTAT = SYS$GETDVIW(,, NAME(F:L), BLK,,,,)
C
C --- $GETDVI returns DC$_TERM if NAME is (or translates to) a terminal.
C --- DECnet remote terminals (RTAn) and PSI terminals (NVAn) are
C --- handled correctly this way.
C
    5 CONTINUE
      TTY = VAL .EQ. DC$_TERM
C
      END
C --- ------------------------------------------------------------------
      INTEGER FUNCTION TLATE( LOGNAM, TRANS )
C --- ------------------------------------------------------------------
C
C --- This function translates the logical name LOGNAM, returning the
C --- translation string in TRANS.  The length of TRANS is returned as
C --- the value of the function if the logical name exists; but if the
C --- logical name is not extant, the function returns the value zero.
C
C --- Copyright (C) Alien 1988 -- All rights reserved.
C
      IMPLICIT NONE
C
      INCLUDE '($LNMDEF)'
C
      CHARACTER*(*) LOGNAM, TRANS
C
      INTEGER TRNITM(4), IOS, TLEN, SYS$TRNLNM
C
C --- Set up the request block.
C
      TRNITM(1) = ISHFT(LNM$_STRING,16) .OR. LEN(TRANS)
      TRNITM(2) = %loc(TRANS)
      TRNITM(3) = %loc(TLEN)
      TRNITM(4) = 0
C
C --- And invoke SYS$TRNLNM.
C
      IOS = SYS$TRNLNM( , 'LNM$DCL_LOGICAL', LOGNAM, , TRNITM )
C
C --- If it succeeded, return the length filled. But if it failed,
C --- return zero.
C
      IF( IOS ) THEN
         TLATE = TLEN
      ELSE
         TLATE = 0
      END IF
C
      END
C --- ------------------------------------------------------------------
      LOGICAL FUNCTION INVOKE_TPU( INIFN, NINIFN, CMDFN, CMDLUN,
     &  INILUN, FN, LINE, COL )
C --- ------------------------------------------------------------------
C
C --- This routine invokes callable TPU for TeX.  INIFN (filled up to
C --- NINIFN) is the name of the initialisation file, if any.  CMDFN is
C --- the name of the command file to be created. CMDLUN and INILUN are
C --- the Fortran channel numbers on which to access the two files.
C --- FN is the name of the file we actually want to edit (i.e., the
C --- one where TeX spotted the error) and LINE and COL give the
C --- location in the file where the cursor is to be positioned.
C --- The value returned by the function describes whether the command
C --- file has been created.
C
C --- Copyright (C) Alien 1988 -- All rights reserved.
C
      IMPLICIT NONE
C
      CHARACTER*(*) INIFN, CMDFN, FN
      INTEGER NINIFN, CMDLUN, INILUN, LINE, COL
C
      INTEGER IOS, NCH, TPU_ADDR, INVOKE_TPU$TPU, LIB$FIND_IMAGE_SYMBOL
      LOGICAL FIRST/.TRUE./
C
C --- We start off, on the first call, by loading the TPU sharable image
C --- and finding the start address of the function TPU$TPU.
C
      IF( FIRST ) THEN
         FIRST = .FALSE.
         IOS = LIB$FIND_IMAGE_SYMBOL( 'TPUSHR', 'TPU$TPU', TPU_ADDR )
         IF( .NOT. IOS ) THEN
            CALL LIB$SIGNAL( %val(IOS) )
            INVOKE_TPU = .FALSE.
            RETURN
         END IF
      END IF
C
C --- Open the command file.
C
      OPEN( UNIT=CMDLUN, FILE=CMDFN, STATUS='NEW', DEFAULTFILE='.TPU',
     &  CARRIAGECONTROL='LIST', IOSTAT=IOS )
      IF( IOS .EQ. 0 ) THEN
         INVOKE_TPU = .TRUE.
C
C --- Open the initialisation file and copy its contents. (EDIT_COPY
C --- also closes INILUN.)
C
         IF( NINIFN .GT. 0 ) THEN
            OPEN( UNIT=INILUN, FILE=INIFN(1:NINIFN), STATUS='OLD',
     &        DEFAULTFILE='.TPU', READONLY, IOSTAT=IOS )
            IF( IOS .EQ. 0 ) CALL EDIT_COPY( INILUN, CMDLUN )
         END IF
C
C --- Position the cursor, close the command file.
C
         IF( LINE .GT. 1 ) WRITE( CMDLUN, 100 ) 'vertical', LINE-1
         IF( COL .GT. 0 ) WRITE( CMDLUN, 100 ) 'horizontal', COL
         CLOSE( UNIT=CMDLUN )
C
C --- Invoke TPU.
C
         IOS = INVOKE_TPU$TPU( 'TPU/COMMAND=' // CMDFN // ' ' // FN,
     &      %val(TPU_ADDR) )
      ELSE
C
C --- We couldn't open the command file: produce a warning message and
C --- edit without positioning the cursor.
C
         INVOKE_TPU = .FALSE.
         PRINT 200, LINE, COL
         IOS = INVOKE_TPU$TPU( 'TPU/NOCOMMAND ' // FN, %val(TPU_ADDR) )
      END IF
C
C --- Check the return status from TPU.
C
      IF( .NOT. IOS ) CALL LIB$SIGNAL( %val(IOS) )
C
C --- FORMATs.
C
  100 FORMAT( 'move_', A, '(', I11, ');' )
  200 FORMAT( ' Can''t create command file for the editor!'/
     & ' You want to look at line ', I11,' column ', I11 )
C
      END
C --- ------------------------------------------------------------------
      LOGICAL FUNCTION INVOKE_TPU$TPU( CMD, TPU_FUNC )
C --- ------------------------------------------------------------------
C
C --- This routine actually invokes TPU$TPU.  Since we've been sneaky
C --- and dynamically linked the sharable image, we must invoke TPU$TPU
C --- via this secondary routine.
C
      IMPLICIT NONE
C
      CHARACTER*(*) CMD
      LOGICAL TPU_FUNC
      EXTERNAL TPU_FUNC
C
      INVOKE_TPU$TPU = TPU_FUNC( CMD )
C
      END
C --- ------------------------------------------------------------------
      LOGICAL FUNCTION INVOKE_EDT( INIFN, NINIFN, CMDFN, CMDLUN,
     &  INILUN, FN, LINE, COL )
C --- ------------------------------------------------------------------
C
C --- This routine invokes callable EDT for TeX.  INIFN (filled up to
C --- NINIFN) is the name of the initialisation file, if any.  CMDFN is
C --- the name of the command file to be created. CMDLUN and INILUN are
C --- the Fortran channel numbers on which to access the two files.
C --- FN is the name of the file we actually want to edit (i.e., the
C --- one where TeX spotted the error) and LINE and COL give the
C --- location in the file where the cursor is to be positioned.
C --- The value returned by the function describes whether the command
C --- file has been created.
C
C --- Copyright (C) Alien 1988 -- All rights reserved.
C
      IMPLICIT NONE
C
      CHARACTER*(*) INIFN, CMDFN, FN
      INTEGER NINIFN, CMDLUN, INILUN, LINE, COL
C
      INTEGER IOS, NCH, EDT_ADDR, INVOKE_EDT$EDIT, LIB$FIND_IMAGE_SYMBOL
      LOGICAL FIRST/.TRUE./
C
C --- We start off, on the first call, by loading the EDT sharable image
C --- and finding the start address of the function EDT$EDIT.
C
      IF( FIRST ) THEN
         FIRST = .FALSE.
         IOS = LIB$FIND_IMAGE_SYMBOL( 'EDTSHR', 'EDT$EDIT', EDT_ADDR )
         IF( .NOT. IOS ) THEN
            CALL LIB$SIGNAL( %val(IOS) )
            INVOKE_EDT = .FALSE.
            RETURN
         END IF
      END IF
C
C --- Open the command file.
C
      OPEN( UNIT=CMDLUN, FILE=CMDFN, STATUS='NEW', DEFAULTFILE='.EDT',
     &  CARRIAGECONTROL='LIST', IOSTAT=IOS )
      IF( IOS .EQ. 0 ) THEN
         INVOKE_EDT = .TRUE.
C
C --- Open the initialisation file and copy its contents. (EDIT_COPY
C --- also closes INILUN.)
C
         IF( NINIFN .GT. 0 ) THEN
            OPEN( UNIT=INILUN, FILE=INIFN(1:NINIFN), STATUS='OLD',
     &        DEFAULTFILE='.EDT', READONLY, IOSTAT=IOS )
            IF( IOS .EQ. 0 ) CALL EDIT_COPY( INILUN, CMDLUN )
         END IF
C
C --- Position the cursor, close the command file.
C
         LINE = LINE - 1
         WRITE( CMDLUN, 100 ) LINE, LINE, COL
         PRINT *, 'Type <GOLD> M to position the cursor at the error.'
         CLOSE( UNIT=CMDLUN )
C
C --- Invoke EDT.
C
         IOS = INVOKE_EDT$EDIT( CMDFN, FN, %val(EDT_ADDR) )
      ELSE
C
C --- We couldn't open the command file: produce a warning message and
C --- edit without positioning the cursor.
C
         INVOKE_EDT = .FALSE.
         PRINT 200, LINE, COL
         IOS = INVOKE_EDT$EDIT( ' ', FN, %val(EDT_ADDR) )
      END IF
C
C --- Check the return status from EDT.
C
      IF( IOS .NE. 1 ) PRINT 300, IOS
C
C --- FORMATs.
C
  100 FORMAT( ' find +', I11/
     & ' define key gold m as "BR ', I11, '(+V) ', I11, '(+C)."'/
     & ' set mode change' )
  200 FORMAT( ' Can''t create command file for the editor!'/
     & ' You want to look at line ', I11,' column ', I11 )
  300 FORMAT( ' EDT$EDIT returned an error status: ', I11, '!!' )
C
      END
C --- ------------------------------------------------------------------
      LOGICAL FUNCTION INVOKE_EDT$EDIT( CMDFN, FN, EDT_FUNC )
C --- ------------------------------------------------------------------
C
C --- This routine actually invokes EDT$EDIT.  Since we've been sneaky
C --- and dynamically linked the sharable image, we must invoke it via
C --- this secondary routine.
C
      IMPLICIT NONE
C
      CHARACTER*(*) CMDFN, FN
      LOGICAL EDT_FUNC
      EXTERNAL EDT_FUNC
C
      IF( CMDFN .EQ. ' ' ) THEN
         INVOKE_EDT$EDIT = EDT_FUNC( FN )
      ELSE
         INVOKE_EDT$EDIT = EDT_FUNC( FN, , CMDFN )
      END IF
C
      END
C --- ------------------------------------------------------------------
      LOGICAL FUNCTION INVOKE_TECO( INIFN, NINIFN, CMDFN, CMDLUN,
     &  INILUN, FN, LINE, COL )
C --- ------------------------------------------------------------------
C
C --- This routine invokes TECO for TeX (in a sub-process).  INIFN
C --- (filled up to NINIFN) is the name of the initialisation file, if
C --- any.  CMDFN is the name of the command file to be created. CMDLUN
C --- and INILUN are the Fortran channel numbers on which to access the
C --- two files.  FN is the name of the file we actually want to edit
C --- (i.e., the one where TeX spotted the error) and LINE and COL give
C --- the location in the file where the cursor is to be positioned.
C --- The value returned by the function describes whether the command
C --- file has been created.
C
C --- Copyright (C) Alien 1988 -- All rights reserved.
C
      IMPLICIT NONE
C
      CHARACTER*(*) INIFN, CMDFN, FN
      INTEGER NINIFN, CMDLUN, INILUN, LINE, COL
C
      CHARACTER*1 ESC
      INTEGER IOS, NCH, LIB$SPAWN
C
      ESC = CHAR(27)
C
C --- Open the command file.
C
      OPEN( UNIT=CMDLUN, FILE=CMDFN, STATUS='NEW', DEFAULTFILE='.TEC',
     &  CARRIAGECONTROL='LIST', RECL=2048, IOSTAT=IOS )
      IF( IOS .EQ. 0 ) THEN
         INVOKE_TECO = .TRUE.
C
C --- Open the initialisation file and copy its contents. (EDIT_COPY
C --- also closes INILUN.)
C
         IF( NINIFN .GT. 0 ) THEN
            OPEN( UNIT=INILUN, FILE=INIFN(1:NINIFN), STATUS='OLD',
     &        DEFAULTFILE='.TEC', READONLY, IOSTAT=IOS )
            IF( IOS .EQ. 0 ) CALL EDIT_COPY( INILUN, CMDLUN )
         END IF
C
C --- Position the cursor, close the command file.
C
         IF( COL .LT. 0 ) COL = 0
         WRITE( CMDLUN, 100 ) '1', LINE-1, COL, ESC, ESC
         CLOSE( UNIT=CMDLUN )
C
C --- Invoke TECO.
C
         IOS = LIB$SPAWN( 'EDIT/TECO/COMMAND=' // CMDFN // ' ' // FN )
      ELSE
C
C --- We couldn't open the command file: produce a warning message and
C --- edit without positioning the cursor.
C
         INVOKE_TECO = .FALSE.
         PRINT 200, LINE, COL
         IOS = LIB$SPAWN( 'EDIT/TECO/NOCOMMAND ' // FN )
      END IF
C
C --- Check the return status from LIB$SPAWN.
C
      IF( .NOT. IOS ) CALL LIB$SIGNAL( %val(IOS) )
C
C --- FORMATs.
C
  100 FORMAT( '@^U', A, '/J', I11, 'L', I11, 'C/', A, A )
  200 FORMAT( ' Can''t create command file for the editor!'/
     & ' You want to look at line ', I11,' column ', I11 )
C
      END
C --- ------------------------------------------------------------------
      LOGICAL FUNCTION INVOKE_OTHER( EDIT, INIFN, NINIFN, CMDFN, CMDLUN,
     &  INILUN, FN, LINE, COL )
C --- ------------------------------------------------------------------
C
C --- This routine invokes any editor for TeX (in a sub-process).  INIFN
C --- (filled up to NINIFN) is the name of the initialisation file, if
C --- any.  CMDFN is the name of the command file to be created. CMDLUN
C --- and INILUN are the Fortran channel numbers on which to access the
C --- two files.  FN is the name of the file we actually want to edit
C --- (i.e., the one where TeX spotted the error) and LINE and COL give
C --- the location in the file where the cursor is to be positioned.
C --- The value returned by the function describes whether the command
C --- file has been created.
C
C --- Copyright (C) Alien 1988 -- All rights reserved.
C
      IMPLICIT NONE
C
      CHARACTER*(*) EDIT, INIFN, CMDFN, FN
      INTEGER NINIFN, INILUN, CMDLUN, LINE, COL
C
      CHARACTER*10 CLINE, CCOL
      INTEGER IOS, NCH, LIB$SPAWN
C
C --- We simply encode LINE and COL, then generate an edit command and
C --- pass it to LIB$SPAWN.  We always return the value .FALSE., since
C --- there's never a temporary initialisation file to be deleted.
C
      INVOKE_OTHER = .FALSE.
C
      IF( COL .LT. 0 ) COL = 0
      WRITE( CLINE, 100 ) LINE
      WRITE( CCOL,  100 ) COL
C
      IF( NINIFN .LE. 0 ) THEN
         NINIFN = 1
         INIFN(1:NINIFN) = ' '
      END IF
      IOS = LIB$SPAWN( EDIT // ' ' // FN // ' ' // CLINE // ' ' //
     &  CCOL // ' ' // INIFN(1:NINIFN) )
C
C --- Check the return status from LIB$SPAWN.
C
      IF( .NOT. IOS ) CALL LIB$SIGNAL( %val(IOS) )
C
C --- FORMATs.
C
  100 FORMAT( I10 )
      END
C --- ------------------------------------------------------------------
      SUBROUTINE EDIT_COPY( INCH, OUTCH )
C --- ------------------------------------------------------------------
C
C --- This routine copies the contents of the file attached to Fortran
C --- channel INCH to channel OUTCH.  When end-of-file is reached on
C --- INCH, it is closed and the routine returns.
C
C --- This code was written by Adrian F. Clark (``Alien'').
C
      IMPLICIT NONE
C
      INTEGER INCH, OUTCH
C
      CHARACTER*255 B
      INTEGER NB
C
    1 CONTINUE
         READ( INCH, 100, END=2, ERR=2 ) NB, B
         IF( NB .LE. 0 ) THEN
            WRITE( OUTCH, 200 )
         ELSE
            WRITE( OUTCH, 300 ) B(1:NB)
         END IF
      GO TO 1
C
    2 CONTINUE
      CLOSE( UNIT=INCH )
C
  100 FORMAT( Q, A )
  200 FORMAT( / )
  300 FORMAT( A )
C
      END
-h- virtex.alien	Mon Feb 13 11:02:01 1989	USERCS:[LEICHTER.TEX.ALIEN]VIRTEX.ALIEN;5

                    +----------------------------------+
                    | VAX/VMS change file for TeX 2.94 |
                    +----------------------------------+

This change file, and the VAX implementation of TeX which results from
it, may be distributed to anyone who asks for it, providing no payment
is requested or received.

Major features of this VAX implementation are:

	o TeX automagically finds out whether it is in batch or
	  interactive mode

	o an interface to various editors at the "?" error prompt

	o greatly increased memory, to allow \TeX to set \pictures, etc

Any comments, queries or---dare I say it---suspected bugs should be
reported to:

	Dr. Adrian F. Clark  (``Alien'')
of:
	Dept Electronic Systems Engineering
	Essex University
	Wivenhoe Park
	Colchester
	Essex C04 3SQ
	United Kingdom
Tel:	Colchester (0206) 872432 (direct)
JANET:  alien@uk.ac.essex.ese
--or-	alien@uk.ac.kcl.ph.ipg

This implementation was carried out in the author's spare time. No commitment
is given or implied that this program is correct ---not even that it runs.
However, the implementor would be pleased to lend assistance to TeX sites who
are struggling to bring up this version. He is, however, not so keen to debug
obscure TeX macros and hackery.

(Footnote: The changes given below are functional rather than pretty.
           If you WEAVE the output, it'll come out pretty ugly!)

\noindent The versions of VAX/VMS \TeX\ 2.94 are as follows:

   0. changes as for 2.93b--0 (21-NOV-1988), plus correcting the value
      of |last_text_char| (promulgated by Chris Thompson of Cambridge);
      improved editor interface in TeX_BITS.FOR.

   1. increase the sizes of buf_size, font_max, font_mem_size, save_size
      and hyph_size (suggested by Jerry Leichter, LEICHTER@EDU.YALE.YCC.VENUS).

This version, for TeX 2.0, 2.1, 2.2 and 2.93b:
		Copyright (C) 1987 by Adrian F. Clark, Essex University.

Original version, for TeX 1.3:
		Copyright (C) 1983 by David Fuchs, Stanford University.

{Section 0}
@x
\pageno=3
@y
\pageno=3
\let\maybe=\iffalse
\def\title{\TeX82 2.94 Changes for VAX/VMS as of \today}
@z

{Section 2}
@x
@d banner=='This is TeX, Version 2.94' {printed when \TeX\ starts}
@y
For VAX/VMS, we append a second number to the version of \TeX; this describes
the version of the VMS implementation.

We also have an associated file written in Fortran,which contains
the code required to determine whether \TeX\ is being used interactively
and to interface \TeX\ to TPU. That file also has a version number, which
will {\it not\/} normally be the same as this one.

\noindent The versions of VAX/VMS \TeX\ 2.0 are as follows:

   0. first promulgated version.

   1. |file_name_size| increased from 69 to 255 (9--JUL--1987).

\noindent The versions of VAX/VMS \TeX\ 2.2 are as follows:

   0. same changes as for 2.0--1 (17-AUG-1987).

\noindent The versions of VAX/VMS \TeX\ 2.94 are as follows:

   0. same changes as for 2.0--1 (25-AUG-1988).



@d banner=='This is TeX, Version 2.94--1 on VAX/VMS'

@z

{Section 4}
@x
procedure initialize; {this procedure gets things started properly}
@y
@<VAX/VMS procedures@>@/
procedure initialize; {this procedure gets things started properly}
@z

{Section 7}
@x
@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
@y
@d debug==@{
@d gubed==@}
@z

{Section 7}
@x
@d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering
  usage statistics}
@d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering
  usage statistics}
@y
@d stat==
@d tats==
@z

{Section 8}
@x
@d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version}
@d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version}
@y
@d init== @{
@d tini== @}
@z

{Section 9}
@x compiler directives== starlet and VAX reserved words
@<Compiler directives@>=
@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead}
@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging}
@y
On VAX/VMS, there are no compiler directives that can be introduced in this
way, but we take this opportunity to include a few sysetem dependent goodies.

@d VAX_text==@= text @>
@d VAX_new==@= new @>
@d VAX_none==@= none @>
@d VAX_word==@= word @>
@d VAX_error==@= error @>
@d VAX_length==@= length @>
@d VAX_continue==@= continue @>
@d VAX_external==@= external @>
@d VAX_readonly==@= readonly @>
@d VAX_volatile==@= volatile @>
@d VAX_aligned==@= aligned @>
@d VAX_unsigned==@= unsigned @>
@d VAX_carriage_control==@= carriage_control @>
@d VAX_io_setmode==@= io$_setmode @>
@d VAX_iom_ctrlcast==@= io$m_ctrlcast @>
@d VAX_immed==@= %immed @>
@d VAX_stdescr==@= %stdescr @>
@d VAX_ref==@= %ref @>
@d VAX_qiow==@= $qiow @>
@d VAX_assign==@= $assign @>
@d VAX_numtim==@= $numtim @>
@d VAX_lib_get_foreign==@= lib$get_foreign @>
@d VAX_disposition==@= disposition @>
@d VAX_delete==@= delete @>
@d VAX_save==@= save @>
@d VAX_varying==@= varying @>
@d VAX_substr==@= substr @>
@d VAX_trnlog==@= $trnlog @>
@d VAX_ss_normal==@= ss$_normal @>
@d VAX_user_action==@=user_action@>
@d VAX_create==@=$create@>
@d VAX_connect==@=$connect@>
@d VAX_open==@=$open@>
@d VAX_FAB_type==@= FAB$type @>
@d VAX_RAB_type==@= RAB$type @>
@d VAX_NAM_type==@= NAM$type @>
@d VAX_PAS_FAB==@= PAS$FAB @>
@d VAX_PAS_RAB==@= PAS$RAB @>
@d VAX_undefined==@= undefined@>
@d VAX_FAB_L_NAM== @=FAB$L_NAM@>
@d VAX_NAM_B_RSL== @=NAM$B_RSL@>
@d VAX_NAM_L_RSA== @=NAM$L_RSA@>
@d VAX_invoke_editor== @= invoke_editor@>

@<Compiler directives@>=
@\@=[inherit('sys$library:starlet')]@>@\
 {allows us to use system symbols and routines}
@z

{Section 10}
@x
@d othercases == others: {default for cases not listed explicitly}
@y
@d othercases == otherwise {default for cases not listed explicitly}
@z

{Section 11}
@x [1] compile-time constants
@!mem_max=30000; {greatest index in \TeX's internal |mem| array;
  must be strictly less than |max_halfword|;
  must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
@!mem_min=0; {smallest index in \TeX's internal |mem| array;
  must be |min_halfword| or more;
  must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
@!buf_size=500; {maximum number of characters simultaneously present in
  current lines of open files and in control sequences between
  \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
@!error_line=72; {width of context lines on terminal error messages}
@!half_error_line=42; {width of first lines of contexts in terminal
  error messages; should be between 30 and |error_line-15|}
@!max_print_line=79; {width of longest text lines output; should be at least 60}
@!stack_size=200; {maximum number of simultaneous input sources}
@!max_in_open=6; {maximum number of input files and error insertions that
  can be going on simultaneously}
@!font_max=75; {maximum internal font number; must not exceed |max_quarterword|
  and must be at most |font_base+256|}
@!font_mem_size=20000; {number of words of |font_info| for all fonts}
@!param_size=60; {maximum number of simultaneous macro parameters}
@!nest_size=40; {maximum number of semantic levels simultaneously active}
@!max_strings=3000; {maximum number of strings; must not exceed |max_halfword|}
@!string_vacancies=8000; {the minimum number of characters that should be
  available for the user's control sequences and font names,
  after \TeX's own error messages are stored}
@!pool_size=32000; {maximum number of characters in strings, including all
  error messages and help texts, and the names of all fonts and
  control sequences; must exceed |string_vacancies| by the total
  length of \TeX's own strings, which is currently about 23000}
@!save_size=600; {space for saving values outside of current group; must be
  at most |max_halfword|}
@!trie_size=8000; {space for hyphenation patterns; should be larger for
  \.{INITEX} than it is in production versions of \TeX}
@!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8}
@!file_name_size=40; {file names shouldn't be longer than this}
@!pool_name='TeXformats:TEX.POOL                     ';
  {string of length |file_name_size|; tells where the string pool appears}
@y
@!mem_max=327144; {greatest index in \TeX's internal |mem| array;
  large enough for a 512 by 512 pixel image;
  must be strictly less than |max_halfword|;
  must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
@!mem_min=0; {smallest index in \TeX's internal |mem| array;
  must be |min_halfword| or more;
  must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
@!buf_size=2000; {maximum number of characters simultaneously present in
  current lines of open files and in control sequences between
  \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
@!error_line=79; {width of context lines on terminal error messages}
@!half_error_line=50; {width of first lines of contexts in terminal
  error messages; should be between 30 and |error_line-15|}
@!max_print_line=79; {width of longest text lines output; should be at least 60}
@!stack_size=200; {maximum number of simultaneous input sources}
@!max_in_open=6; {maximum number of input files and error insertions that
  can be going on simultaneously}
@!font_max=125; {maximum internal font number; must not exceed |max_quarterword|
  and must be at most |font_base+256|}
@!font_mem_size=44000; {number of words of |font_info| for all fonts}
@!param_size=60; {maximum number of simultaneous macro parameters}
@!nest_size=40; {maximum number of semantic levels simultaneously active}
@!max_strings=10000; {maximum number of strings; must not exceed |max_halfword|}
@!string_vacancies=20000; {the minimum number of characters that should be
  available for the user's control sequences and font names,
  after \TeX's own error messages are stored}
@!pool_size=65000; {maximum number of characters in strings, including all
  error messages and help texts, and the names of all fonts and
  control sequences; must exceed |string_vacancies| by the total
  length of \TeX's own strings, which is currently about 22500}
@!save_size=1500; {space for saving values outside of current group; must be
  at most |max_halfword|}
@!trie_size=8000; {space for hyphenation patterns; should be larger for
  \.{INITEX} than it is in production versions of \TeX}
@!dvi_buf_size=1024; {size of the output buffer; must be a multiple of 8}
@!VAX_block_length=512; {must be half |dvi_buf_size| on VAX/VMS}
@!file_name_size=255; {file names shouldn't be longer than this}
@!pool_name=
  'TeX$formats:bigTeX.POOL                                              ';
  {string of length |file_name_size|; tells where the string pool appears}
@.TeX{\$}formats@>
@z


{Section 12}
@x [1] Tangle-time constants
@d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX};
  must not be less than |mem_min|}
@d mem_top==30000 {largest index in the |mem| array dumped by \.{INITEX};
  must be substantially larger than |mem_bot|
  and not greater than |mem_max|}
@d font_base=0 {smallest internal font number; must not be less
  than |min_quarterword|}
@d hash_size=2100 {maximum number of control sequences; it should be at most
  about |(mem_max-mem_min)/10|, but 2100 is already quite generous}
@d hash_prime=1777 {a prime number equal to about 85\% of |hash_size|}
@d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions}
@y
@d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX};
  must not be less than |mem_min|}
@d mem_top==327144 {largest index in the |mem| array dumped by \.{INITEX};
  must be substantially larger than |mem_bot|
  and not greater than |mem_max|}
@d font_base=0 {smallest internal font number; must not be less
  than |min_quarterword|}
@d hash_size=5000 {maximum number of control sequences; it should be at most
  about |(mem_max-mem_min)/10|, but 2100 is already quite generous}
@d hash_prime=4253 {a prime number equal to about 85\% of |hash_size|}
@d hyph_size=503 {another prime; the number of \.{\\hyphenation} exceptions}
@z

{Section 23}
@x [2] System-dependent character set changes:
@^character set dependencies@>
@^system dependencies@>

@<Set init...@>=
for i:=1 to @'37 do xchr[i]:=' ';
@y
@^character set dependencies@>
@^system dependencies@>

The code shown here is intended to be used on VAX/VMS systems,
and at other installations where only the printable ASCII set, plus
|carriage_return|, |tab|, and |form_feed| will show up in text files.
All |line_feed| and |null| characters are skipped.

@d form_feed=@'14 {ASCII code used at end of a page}
@d tab=@'11

@<Set initial values...@>=
for i:=1 to @'37 do xchr[i]:=' ';
xchr[form_feed]:=chr(form_feed);
xchr[tab]:=chr(tab);
@z

{Section 25}
@x [3] alpha files are text and byte files are blocks
@!alpha_file=packed file of text_char; {files that contain textual data}
@!byte_file=packed file of eight_bits; {files that contain binary data}
@y
@!alpha_file=VAX_text; {files that contain textual data}
@!byte_block=packed array [0..VAX_block_length-1] of eight_bits;
@!byte_file=packed file of byte_block; {files that contain binary data}
@z


{Section 27}
@x
@d reset_OK(#)==erstat(#)=0
@d rewrite_OK(#)==erstat(#)=0

@p function a_open_in(var f:alpha_file):boolean;
@y
@p function user_reset
	(var FAB:VAX_FAB_type;
	 var RAB:VAX_RAB_type;
	 var F:unsafe_file):integer;
var status:integer; NAM:NAM_ptr; p:charptr; i:integer;
begin
last_length:=0;
status:=VAX_open(FAB);
if odd(status) then status:=VAX_connect(RAB);
if odd(status) then begin
	NAM:=FAB.VAX_FAB_L_NAM::NAM_ptr;
	if NAM<>nil then last_length:=NAM^.VAX_NAM_B_RSL;
	for i:=1 to last_length do begin
		p:=(NAM^.VAX_NAM_L_RSA::integer+i-1)::charptr;
		last_name[i]:=p^;
		end;
	end;
user_reset:=status;
end;
@#
function user_rewrite
	(var FAB:VAX_FAB_type;
	 var RAB:VAX_RAB_type;
	 var F:unsafe_file):integer;
var status:integer; NAM:NAM_ptr; p:charptr; i:integer;
begin
status:=VAX_create(FAB);
if odd(status) then status:=VAX_connect(RAB);
if odd(status) then begin
	NAM:=FAB.VAX_FAB_L_NAM::NAM_ptr;
	if NAM<>nil then last_length:=NAM^.VAX_NAM_B_RSL;
	for i:=1 to last_length do begin
		p:=(NAM^.VAX_NAM_L_RSA::integer+i-1)::charptr;
		last_name[i]:=p^;
		end;
	end;
user_rewrite:=status;
end;
@#
function a_open_in(var f:alpha_file):boolean;
@z

{Section 27}
@x [3] file opening
begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f);
@y
begin
open(f,name_of_file,VAX_readonly,VAX_user_action:=user_reset,
	VAX_error:=VAX_continue);
if status(f)>0 then a_open_in:=false
else begin
 reset(f,VAX_error:=VAX_continue);
 a_open_in:=status(f)<=0;
 end;
@z

{Section 27}
@x
begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f);
@y
begin
open(f,name_of_file,VAX_new,16383,VAX_disposition:=VAX_delete,
	VAX_user_action:=user_rewrite,VAX_error:=VAX_continue);
if status(f)>0 then a_open_out:=false
else begin
 linelimit(f,maxint);
 rewrite(f,VAX_error:=VAX_continue);
 a_open_out:=status(f)<=0;
 end;
@z

{Section 27}
@x
begin reset(f,name_of_file,'/O'); b_open_in:=reset_OK(f);
@y
begin
open(f,name_of_file,VAX_readonly,VAX_user_action:=user_reset,
	VAX_error:=VAX_continue);
if status(f)>0 then b_open_in:=false
else begin
 reset(f,VAX_error:=VAX_continue);
 b_open_in:=status(f)<=0;
 end;
@z

{Section 27}
@x
begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f);
@y
begin
open(f,name_of_file,VAX_new,VAX_disposition:=VAX_delete,
	VAX_user_action:=user_rewrite,VAX_error:=VAX_continue);
if status(f)>0 then b_open_out:=false
else begin
 rewrite(f,VAX_error:=VAX_continue);
 b_open_out:=status(f)<=0;
 end;
@z

{Section 27}
@x
begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f);
@y
begin
open(f,name_of_file,VAX_readonly,VAX_user_action:=user_reset,
	VAX_error:=VAX_continue);
if status(f)>0 then w_open_in:=false
else begin
 reset(f,VAX_error:=VAX_continue);
 w_open_in:=status(f)<=0;
 end;
fmt_count:=0; {hack}
@z

{Section 27}
@x
begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f);
@y
begin
open(f,name_of_file,VAX_new,VAX_disposition:=VAX_delete,
	VAX_user_action:=user_rewrite,VAX_error:=VAX_continue);
if status(f)>0 then w_open_out:=false
else begin
 rewrite(f,VAX_error:=VAX_continue);
 w_open_out:=status(f)<=0;
 end;
fmt_count:=0; {hack}
@z

{Section 28}
@x [3] file closing
begin close(f);
@y
begin close(f,VAX_disposition:=VAX_save,VAX_error:=VAX_continue);
@z

{Section 28}
@x
begin close(f);
@y
begin close(f,VAX_disposition:=VAX_save,VAX_error:=VAX_continue);
@z

{Section 28}
@x
begin close(f);
@y
begin close(f,VAX_disposition:=VAX_save,VAX_error:=VAX_continue);
@z

{Section 30}
@x [3] read into auxiliary buffer first
representing the beginning and ending of a line of text.

@<Glob...@>=
@y
representing the beginning and ending of a line of text.

On VAX/VMS, we will read the lines first into an auxiliary buffer, in
order to save the running time of procedure-call overhead.  We have
to be very carefull to handle lines longer than the arbitrarily chosen
length of the |aux_buf|.

@<Glob...@>=
@!aux_buf:VAX_varying [133] of char; {where the characters go first}
@z

{Section 31}
@x [3] ditto
@p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;
  {inputs the next line or returns |false|}
var last_nonblank:0..buf_size; {|last| with trailing blanks removed}
begin if bypass_eoln then if not eof(f) then get(f);
  {input the first character of the line into |f^|}
last:=first; {cf.\ Matthew 19\thinspace:\thinspace30}
if eof(f) then input_ln:=false
else  begin last_nonblank:=first;
  while not eoln(f) do
    begin if last>=max_buf_stack then
      begin max_buf_stack:=last+1;
      if max_buf_stack=buf_size then
        overflow("buffer size",buf_size);
@:TeX capacity exceeded buffer size}{\quad buffer size@>
      end;
    buffer[last]:=xord[f^]; get(f); incr(last);
    if buffer[last-1]<>" " then last_nonblank:=last;
    end;
  last:=last_nonblank; input_ln:=true;
  end;
end;
@y
@p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;
  {inputs the next line or returns |false|}
label found;
var @!len:integer; {length of line input}
@!k:0..buf_size; {index into |buffer|}
begin
last:=first; {cf.\ Matthew 19\thinspace:\thinspace30}
if status(f)<>0 then input_ln:=false
else  begin
  while not eoln(f) do
    begin read(f,aux_buf,VAX_error:=VAX_continue);
    len:=VAX_length(aux_buf);
    if last+len>=max_buf_stack then
      begin
      if last+len<buf_size then max_buf_stack:=last+len
      else overflow("buffer size",buf_size);
      end;
    for k:=last to last+len-1 do buffer[k]:=xord[aux_buf[k-last+1]];
    last:=last+len;
    end;
  found: if last>first then if buffer[last-1]=" " then begin
	decr(last); goto found; end;
  input_ln:=true;
  read_ln(f,VAX_error:=VAX_continue);
  end;
end;
@z

{Section 33}
@x [3] terminal file opening
@ Here is how to open the terminal files
in \ph. The `\.{/I}' switch suppresses the first |get|.
@^system dependencies@>

@d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input}
@d t_open_out==rewrite(term_out,'TTY:','/O') {open the terminal for text output}
@y
@ Here is how to open the terminal files
under VAX/VMS.
@^system dependencies@>

@d t_open_in==begin open(term_in,'SYS$INPUT');
 reset(term_in);
 in_FAB:=VAX_PAS_FAB(term_in);
 in_RAB:=VAX_PAS_RAB(term_in);
 end {open the terminal for text input}
@d t_open_out==begin
 open(term_out,'SYS$OUTPUT',VAX_carriage_control:=VAX_none);
 linelimit(term_out,maxint);
 rewrite(term_out);
 out_FAB:=VAX_PAS_FAB(term_out);
 out_RAB:=VAX_PAS_RAB(term_out);
 end {open the terminal for text output}
@z

{Section 34}
@x [3] terminal hacks: clear and update
these operations can be specified in \ph:
@^system dependencies@>

@d update_terminal == break(term_out) {empty the terminal output buffer}
@d clear_terminal == break_in(term_in,true) {clear the terminal input buffer}
@d wake_up_terminal == do_nothing {cancel the user's cancellation of output}
@y
these operations can be specified in VAX/VMS Pascal:
@^system dependencies@>

@d update_terminal == write_ln(term_out) {empty the terminal output buffer}
@d clear_terminal == in_RAB^.@=RAB$V_PTA@>:=true
	{clear the terminal input buffer}
@.PTA@>
@d wake_up_terminal == begin
	out_RAB^.@=RAB$V_CCO@>:=true;
	write_ln(term_out);
	out_RAB^.@=RAB$V_CCO@>:=false;
	end {cancel the user's cancellation of output}
@.CCO@>
@d crlf == chr(13),chr(10)
@z

{Section 37}
@x [3] terminal initialization
@ The following program does the required initialization
without retrieving a possible command line.
It should be clear how to modify this routine to deal with command lines,
if the system permits them.
@^system dependencies@>

@p function init_terminal:boolean; {gets the terminal input started}
label exit;
begin t_open_in;
loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
@.**@>
  if not input_ln(term_in,true) then {this shouldn't happen}
    begin write_ln(term_out);
    write(term_out,'! End of file on the terminal... why?');
@.End of file on the terminal@>
    init_terminal:=false; return;
    end;
  loc:=first;
  while (loc<last)and(buffer[loc]=" ") do incr(loc);
  if loc<last then
    begin init_terminal:=true;
    return; {return unless the line was all blank}
    end;
  write_ln(term_out,'Please type the name of your input file.');
  end;
exit:end;
@y
@ The following program does the required initialization
by retrieving a possible command line, and if none exists,
prompting the user for the first line of input.
@^system dependencies@>

@p
[VAX_external] function VAX_lib_get_foreign(
  VAX_stdescr cmdlin:[VAX_volatile] packed array [$l1..$u1:integer] of char
	:= VAX_immed 0;
  VAX_stdescr prompt:[VAX_volatile] packed array [$l2..$u2:integer] of char
	:= VAX_immed 0;
  var len : [VAX_volatile] sixteen_bits := VAX_immed 0;
  var flag : [VAX_volatile] integer := VAX_immed 0)
    :integer; extern;

function init_terminal:boolean; {gets the terminal input started}
label exit;
var command_line: packed array[1..300] of char;
@!len: sixteen_bits;
@!i: integer;
begin t_open_in;
i:=0;
VAX_lib_get_foreign(command_line,,len,i);
i:=1; while (i<=len) and (command_line[i]=' ') do incr(i);
if i<=len then begin
	loc:=first;
	last:=first;
	while i<=len do begin
		buffer[last]:=xord[command_line[i]];
		if (buffer[last]>="A") and (buffer[last]<="Z")
		then buffer[last]:=buffer[last]+"a"-"A";
		incr(last); incr(i);
		end;
	init_terminal:=true; return;
	end;
loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
@.**@>
  if not input_ln(term_in,true) then {this shouldn't happen}
    begin write(term_out,crlf);
    write_ln(term_out,'! End of file on the terminal... why?',crlf);
@.End of file on the terminal@>
    init_terminal:=false; return;
    end;
  loc:=first;
  while (loc<last)and(buffer[loc]=" ") do incr(loc);
  if loc<last then
    begin init_terminal:=true;
    return; {return unless the line was all blank}
    end;
  write_ln(term_out,'Please type the name of your input file.',crlf);
  end;
exit:end;
@z

{Section 51}
@x [4] bad_pool needs real crlf
@ @d bad_pool(#)==begin wake_up_terminal; write_ln(term_out,#);
@y
@ @d bad_pool(#)==begin wake_up_terminal; write_ln(term_out,#,crlf);
@z

{Section 56}
@x [5] real crlf for terminal
@d wterm(#)==write(term_out,#)
@d wterm_ln(#)==write_ln(term_out,#)
@d wterm_cr==write_ln(term_out)
@y
@d wterm(#)==write(term_out,#)
@d wterm_ln(#)==write_ln(term_out,#,crlf)
@d wterm_cr==write_ln(term_out,crlf)
@z

{Section 71}
@x [5] Turn off clearing typeahead after terminal input
term_offset:=0; {the user's line ended with \<\rm return>}
@y
in_RAB^.@=RAB$V_PTA@>:=false; {turn off purging of typeahead}
@.PTA@>
term_offset:=0; {the user's line ended with \<\rm return>}
@z

{Section 74}
@x
@ @<Set init...@>=interaction:=error_stop_mode;
@y
@ On VAX/VMS, we set the initial value of |interaction| to be |error_stop_mode|
for terminal sessions and |batch_mode| otherwise. We determine whether \TeX\
is being executed from a terminal by translating the logical name
\.{SYS$INPUT}.

@<Set init...@>=
  if tty('SYS$INPUT') then
    interaction:=error_stop_mode
  else
    interaction:=batch_mode;
@z

{Section 84}
@x
@ It is desirable to provide an `\.E' option here that gives the user
an easy way to return from \TeX\ to the system editor, with the offending
line ready to be edited. But such an extension requires some system
wizardry, so the present implementation simply types out what file should be
edited and the relevant line number.
@y
@ We provide an `\.E' option in this VMS implementation, which allows the user
to make corrections to his or her input file as \TeX\ spots errors.
VAX/VMS supports a fairly wide variety of editors, from \.{EDT} and \.{TPU}
to \.{SOS} and \.{SLP}. If we were to set up the \TeX/editor interface
to be similar to, say, \.{MAIL}, we would have to allow the user to
invoke any editor on the system. This would mean linking the \TeX\ executable
against the \.{EDT} and \.{TPU} sharable images, spawning sub-processes to
invoke the other editors.
Recognizing the increasing popularity of \.{TPU}, the `\.E' option is set
up to invoke callable \.{TPU}; this can be set up to be \.{EVE}, the \.{EDT}
emulator or a customized interface, such as \.{EVEplus}, simply by assigning
the logical name \.{TPUSECINI}.
@z

{Section 84}
@x
"E": if base_ptr>0 then
  begin print_nl("You want to edit file ");
@.You want to edit file x@>
  print(input_stack[base_ptr].name_field);
  print(" at line "); print_int(line);
  interaction:=scroll_mode; jump_out;
  end;
@y
"E": if base_ptr>0 then
  begin
@.Editing file x@>
  edit_file(input_stack[base_ptr].name_field, line, loc);
  show_context;
  goto continue;
  end;
@z

{Section 96}
@x [6] interrupts
@d check_interrupt==begin if interrupt<>0 then pause_for_instructions;
  end

@<Global...@>=
@!interrupt:integer; {should \TeX\ pause for instructions?}
@y
@d check_interrupt==begin if interrupt<>0 then pause_for_instructions;
  end
@d enable_control_C==
VAX_qiow(,tt_chan,VAX_io_setmode+VAX_iom_ctrlcast,,,,
	VAX_immed ctrlc_rout,,VAX_immed 3,,,);

@<Global...@>=
@!interrupt:[VAX_volatile]integer; {should \TeX\ pause for instruction?}
@z

{Section 97}
@x
interrupt:=0; OK_to_interrupt:=true;
@y
interrupt:=0; OK_to_interrupt:=true;
if VAX_assign('TT',tt_chan,,)=1 then enable_control_C;
@z

{Section 109}
@x [7] double precision reals
@d set_glue_ratio_zero(#) == #:=0.0 {store the representation of zero ratio}
@d set_glue_ratio_one(#) == #:=1.0 {store the representation of unit ratio}
@d float(#) == # {convert from |glue_ratio| to type |real|}
@d unfloat(#) == # {convert from |real| to type |glue_ratio|}
@d float_constant(#) == #.0 {convert |integer| constant to |real|}

@<Types...@>=
@!glue_ratio=real; {one-word representation of a glue expansion factor}
@y
On VAX/VMS, we use some hackery to cause floating point numbers stored in
|mem| to be |single|, but other |real| variables and expressions are
done as |double| length reals.

@d set_glue_ratio_zero(#) == #:=0.0 {store the representation of zero ratio}
@d set_glue_ratio_one(#) == #:=1.0 {store the representation of unit ratio}
@d real == double {use double precision reals for computation}
@d float(#) == dble(#) {convert from |glue_ratio| to type |real|}
{FIX ME}
@d unfloat(#) == sngl(1.0@&D0 * #) {convert from |real| to type |glue_ratio|}
@d float_constant(#) == #.0@&D0 {convert |integer| constant to |real|}

@<Types...@>=
@!glue_ratio=r@&e@&a@&l; {one-word representation of a glue expansion factor}
@z

{Section 110}
@x
@d max_halfword==65535 {largest allowable value in a |halfword|}
@y
@d max_halfword==327144+1 {largest allowable value in a |halfword|}
@z

{Section 111}
@x
if (min_halfword>0)or(max_halfword<32767) then bad:=12;
@y
if (min_halfword>0)or(max_halfword<327144) then bad:=12;
@z

{Section 112}
@x
@d qi(#)==#+min_quarterword
  {to put an |eight_bits| item into a quarterword}
@d qo(#)==#-min_quarterword
  {to take an |eight_bits| item out of a quarterword}
@d hi(#)==#+min_halfword
  {to put a sixteen-bit item into a halfword}
@d ho(#)==#-min_halfword
  {to take a sixteen-bit item from a halfword}
@y
@d qi(#)==#
@d qo(#)==#
@d hi(#)==#
@d ho(#)==#
@z

{Section 113}
@x [8] block up word files
@!word_file = file of memory_word;
@y
@!word_block = packed array [0..VAX_block_length-1] of memory_word;
@!word_file = packed file of word_block;
@z

{Section 186}
@x [12] check glue ratio for REALness
arbitrary random value. The following code assumes that a properly
formed nonzero |real| number has absolute value $2^{20}$ or more when
it is regarded as an integer; this precaution was adequate to prevent
floating point underflow on the author's computer.
@y
arbitrary random value. The following code uses the VAX/VMS predeclared
routine |undefined|.
@z

{Section 186}
@x
  if abs(mem[p+glue_offset].int)<@'4000000 then print("?.?")
@y
  if VAX_undefined(mem[p+glue_offset].gr) then print("?.?")
@z

{Section 232}
@x [17] Special form_feed initialization:
cat_code("\"):=escape; cat_code("%"):=comment;
@y
cat_code("\"):=escape; cat_code("%"):=comment;
cat_code(form_feed):=car_ret;
@z

{Section 241}
@x [17] date/time
Since standard \PASCAL\ cannot provide such information, something special
is needed. The program here simply specifies July 4, 1776, at noon; but
users probably want a better approximation to the truth.

@p procedure fix_date_and_time;
begin time:=12*60; {minutes since midnight}
day:=4; {fourth day of the month}
month:=7; {seventh month of the year}
year:=1776; {Anno Domini}
@y
@p procedure fix_date_and_time;
var t:array[1..7] of signed_halfword; {raw year, month, day and time}
begin VAX_numtim(t);
year:=t[1]; month:=t[2]; day:=t[3];
time:=t[4]*60+t[5]; {minutes since midnight}
@z

{Section 513}
@x [28] file names and default areas
following structure:  If the name contains `\.>' or `\.:', the file area
@y
following structure:  If the name contains `\.>', `\.]' or `\.:', the file area
@z

{Section 514}
@x [28] system logical names
@d TEX_area=="TeXinputs:"
@.TeXinputs@>
@d TEX_font_area=="TeXfonts:"
@.TeXfonts@>
@y
@d TEX_area=="TeX$inputs:"
@.TeXinputs@>
@.TeX{\$}inputs@>
@d TEX_font_area=="TeX$fonts:"
@.TeXfonts@>
@.TeX{\$}fonts@>
@z

{Section 516}
@x [28] directories delimited with square brackets
else  begin if (c=">")or(c=":") then
@y
else  begin if (c=">")or(c="]")or(c=":") then
@z

{Section 517}
@x [29] Logical name translation:
@ The third.
@^system dependencies@>

@p procedure end_name;
begin if str_ptr+3>max_strings then
  overflow("number of strings",max_strings-init_str_ptr);
@:TeX capacity exceeded number of strings}{\quad number of strings@>
if area_delimiter=0 then cur_area:=""
else  begin cur_area:=str_ptr; incr(str_ptr);
  str_start[str_ptr]:=area_delimiter+1;
  end;
if ext_delimiter=0 then
  begin cur_ext:=""; cur_name:=make_string;
  end
else  begin cur_name:=str_ptr; incr(str_ptr);
  str_start[str_ptr]:=ext_delimiter; cur_ext:=make_string;
  end;
end;
@y
@ The third.  We have to check to see if a logical name has been
referred to, and if so, translate it.
@^system dependencies@>

@p procedure end_name;
label restart,exit;
var s,@!u:VAX_varying[file_name_size] of char;
@!t:packed array[1..file_name_size] of char;
@!TRNLOG_return: integer; {what did the TRNLOG return?}
@!i:pool_pointer;
@!len:signed_halfword;
@!c:char;
begin
restart:
if (str_pool[area_delimiter]=":") and (pool_ptr=area_delimiter+1) then
  begin
  cur_area:=make_string;
  len:=length(cur_area)-1; {don't include the colon}
  for i:=1 to len do begin
	c:=xchr[str_pool[str_start[cur_area]+i-1]];
	if ('a'<=c) and (c<='z') then c:=chr(ord(c)+ord('A')-ord('a'));
	t[i]:=c;
	end;
  s:=VAX_substr(t,1,len);
  TRNLOG_return:=VAX_trnlog(s,len,t,,,);   {NB: should use $TRNLNM now}
  if TRNLOG_return<>VAX_ss_normal then begin
    cur_ext:=""; cur_name:=""; {silly case}
    return;
    end;
  flush_string; {needn't remember logical name in |cur_area|}
  begin_name;
  for i:=1 to len do
    if not more_name(xord[t[i]]) then goto restart;
  goto restart; {heavy!}
  end;
if str_ptr+3>max_strings then
  overflow("number of strings",max_strings-init_str_ptr);
@:TeX capacity exceeded number of strings}{\quad number of strings@>
if area_delimiter=0 then cur_area:=""
else  begin cur_area:=str_ptr; incr(str_ptr);
  str_start[str_ptr]:=area_delimiter+1;
  end;
if ext_delimiter=0 then
  begin cur_ext:=""; cur_name:=make_string;
  end
else  begin cur_name:=str_ptr; incr(str_ptr);
  str_start[str_ptr]:=ext_delimiter; cur_ext:=make_string;
  end;
exit:
end;
@z

{Section 520}
@x [28] system logical names
@d format_default_length=20 {length of the |TEX_format_default| string}
@d format_area_length=11 {length of its area part}
@y
@d format_default_length=21 {length of the |TEX_format_default| string}
@d format_area_length=12 {length of its area part}
@z

{Section 520}
@x [28] system logical names
TEX_format_default:='TeXformats:plain.fmt';
@y
TEX_format_default:='TeX$formats:PLAIN.fmt';
@.TeX{\$}formats@>
@z

{Section 525}
@x [28] get file name from system
@p function make_name_string:str_number;
var k:1..file_name_size; {index into |name_of_file|}
begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings)or
 (cur_length>0) then
  make_name_string:="?"
else  begin for k:=1 to name_length do append_char(xord[name_of_file[k]]);
  make_name_string:=make_string;
  end;
end;
@y
@p function make_name_string:str_number;
var k:1..file_name_size; {index into |name_of_file|}
begin if (pool_ptr+last_length>pool_size)or(str_ptr=max_strings) then
  make_name_string:="?"
else  begin for k:=1 to last_length do append_char(xord[last_name[k]]);
  make_name_string:=make_string;
  end;
end;
@z

{Section 529}
@x
@p procedure pack_job_name(@!s:str_number); {|s = ".log"|, |".dvi"|, or
@y
@p procedure pack_job_name(@!s:str_number); {|s = ".lis"|, |".dvi"|, or
@z

{Section 534}
@x
pack_job_name(".log");
@y
pack_job_name(".lis");
@z

{Section 535}
@x
prompt_file_name("transcript file name",".log");
@y
prompt_file_name("transcript file name",".lis");
@z

{Section 563}
@x [29] tfm blocking
if not b_open_in(tfm_file) then abort;
@y
if not b_open_in(tfm_file) then abort;
tfm_count:=0;
@z

{Section 564}
@x [29] tfm blocked
@d fget==get(tfm_file)
@d fbyte==tfm_file^
@y
@d fget==begin incr(tfm_count);
	if tfm_count=VAX_block_length then begin
		get(tfm_file,VAX_error:=VAX_continue); tfm_count:=0; end
	end
@d fbyte==tfm_file^[tfm_count]
@z

{Section 575}
@x [29] tfm blocked
if eof(tfm_file) then abort;
@y
if status(tfm_file)<>0 then abort;
if eof(tfm_file) then abort;
@z

{Section 595}
@x [31] dvi blocked
@ Some systems may find it more efficient to make |dvi_buf| a |packed|
array, since output of four bytes at once may be facilitated.
@^system dependencies@>

@<Glob...@>=
@!dvi_buf:array[dvi_index] of eight_bits; {buffer for \.{DVI} output}
@y
@ Some systems may find it more efficient to make |dvi_buf| a |packed|
array, since output of four bytes at once may be facilitated.  On VAX/VMS,
we get even more complicated than that, for efficiency.

@d dvi_buf==d_buffer.b  {buffer for \.{DVI} output}

@<Glob...@>=
@!d_buffer: [VAX_volatile,VAX_aligned(9)] packed record
	case boolean of
		false: (b:packed array[dvi_index] of eight_bits);
		true:  (l:byte_block; r:byte_block; j:eight_bits);
		end;
@z

{Section 597}
@x [31] dvi blocked
@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
|write_dvi(a,b)|. For best results, this procedure should be optimized to
run as fast as possible on each particular system, since it is part of
\TeX's inner loop. It is safe to assume that |a| and |b+1| will both be
multiples of 4 when |write_dvi(a,b)| is called; therefore it is possible on
many machines to use efficient methods to pack four bytes per word and to
output an array of words with one system call.
@^system dependencies@>
@^inner loop@>
@^defecation@>

@p procedure write_dvi(@!a,@!b:dvi_index);
var k:dvi_index;
begin for k:=a to b do write(dvi_file,dvi_buf[k]);
end;
@y
@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
|write| on the other variant of the |dvi_buf| record.  Thus, we have to be
sure that things line up properly.
@^system dependencies@>
@^inner loop@>
@^defecation@>

@<Check the ``co...@>=
if dvi_buf_size<>2*VAX_block_length then bad:=223;
@z

{Section 598}
% [31] dvi blocked
@x
  begin write_dvi(0,half_buf-1); dvi_limit:=half_buf;
@y
  begin write(dvi_file,d_buffer.l); dvi_limit:=half_buf;
@z

{Section 598}
@x
else  begin write_dvi(half_buf,dvi_buf_size-1); dvi_limit:=dvi_buf_size;
@y
else  begin write(dvi_file,d_buffer.r); dvi_limit:=dvi_buf_size;
@z

{Section 599}
@x [31] dvi blocked
if dvi_limit=half_buf then write_dvi(half_buf,dvi_buf_size-1);
if dvi_ptr>0 then write_dvi(0,dvi_ptr-1)
@y
if dvi_limit=half_buf then write(dvi_file,d_buffer.r);
for k:=dvi_ptr to dvi_buf_size do dvi_buf[k]:=223;
if dvi_ptr>0 then write(dvi_file,d_buffer.l);
if dvi_ptr>half_buf then write(dvi_file,d_buffer.r);
@z

{Section 1305}
@x [50] block fmt files
@d dump_wd(#)==begin fmt_file^:=#; put(fmt_file);@+end
@d dump_int(#)==begin fmt_file^.int:=#; put(fmt_file);@+end
@d dump_hh(#)==begin fmt_file^.hh:=#; put(fmt_file);@+end
@d dump_qqqq(#)==begin fmt_file^.qqqq:=#; put(fmt_file);@+end
@y
@d fmt_put==begin incr(fmt_count);
	if fmt_count=VAX_block_length then begin
		put(fmt_file,VAX_error:=VAX_continue); fmt_count:=0; end
	end
@d fmt_word==fmt_file^[fmt_count]

@d dump_wd(#)==begin fmt_word:=#; fmt_put;@+end
@d dump_int(#)==begin fmt_word.int:=#; fmt_put;@+end
@d dump_hh(#)==begin fmt_word.hh:=#; fmt_put;@+end
@d dump_qqqq(#)==begin fmt_word.qqqq:=#; fmt_put;@+end
@z

{Section 1306}
@x
@d undump_wd(#)==begin get(fmt_file); #:=fmt_file^;@+end
@d undump_int(#)==begin get(fmt_file); #:=fmt_file^.int;@+end
@d undump_hh(#)==begin get(fmt_file); #:=fmt_file^.hh;@+end
@d undump_qqqq(#)==begin get(fmt_file); #:=fmt_file^.qqqq;@+end
@y
@d fmt_get==begin incr(fmt_count);
	if fmt_count=VAX_block_length then begin
		get(fmt_file,VAX_error:=VAX_continue); fmt_count:=0; end
	end
@d undump_wd(#)==begin fmt_get; #:=fmt_word;@+end
@d undump_int(#)==begin fmt_get; #:=fmt_word.int;@+end
@d undump_hh(#)==begin fmt_get; #:=fmt_word.hh;@+end
@d undump_qqqq(#)==begin fmt_get; #:=fmt_word.qqqq;@+end
@z

{Section 1308}
@x
x:=fmt_file^.int;
@y
x:=fmt_word.int;
@z

{Section 1329}
@x [50] fmt file blocked
w_close(fmt_file)
@y
while fmt_count>0 do dump_int(0); {flush out the buffer}
w_close(fmt_file)
@z

{Section 1332}
@x return a status value to VMS
final_end: ready_already:=0;
@y
final_end:
   begin
      ready_already:=0;
      if      history = warning_issued       then
         @= $exit( sts$k_warning + sts$m_inhib_msg ) @>
      else if history = error_message_issued then
         @= $exit( sts$k_error   + sts$m_inhib_msg ) @>
      else if history = fatal_error_stop     then
         @= $exit( sts$k_severe  + sts$m_inhib_msg ) @>
      {else we'll exit with a success status anyway}
   end
@z

{Section 1376}
@x [54] left overs
This section should be replaced, if necessary, by changes to the program
that are necessary to make \TeX\ work at a particular installation.
It is usually best to design your change file so that all changes to
previous sections preserve the section numbering; then everybody's version
will be consistent with the published program. More extensive changes,
which introduce new sections, can be inserted here; then only the index
itself will get a new section number.
@y
Here are the remaining changes to the program
that are necessary to make \.{TeX} work on VAX/VMS.

@ Here are the things we need for |byte_file| and |word_file| files:

@<Glob...@>=
@!tfm_count: 0..VAX_block_length;
@!fmt_count: 0..VAX_block_length;

@ Here's the interrupt stuff.

@<Types...@>=
@!signed_halfword=[VAX_word] -32768..32767;
@!sixteen_bits=[VAX_word] 0..65535;

@ @<Glob...@>=
@!itm: array [1..4] of VAX_unsigned;
@!res: [VAX_volatile] integer;
@!tt_chan: [VAX_volatile] signed_halfword;

@ @<VAX/VMS procedures@>=
[asynchronous] procedure @!ctrlc_rout;
begin
interrupt:=1;
enable_control_C;
end;

function tty(
  VAX_stdescr FN: [VAX_volatile] packed array [n1..n2: integer] of char
  ): boolean;
  external;

{invoke editor; based on ``print''}
procedure edit_file(@!s:integer; l:integer; p:halfword);
label exit;
procedure VAX_invoke_editor(
   VAX_stdescr FN: [VAX_volatile] packed array [n1..n2: integer] of char;
   VAX_ref lin: integer;
   VAX_ref posn: integer );
   external; {Actually, its written in Fortran}
var j:pool_pointer; {current character code position}
var i:integer;  {pointer into fname}
var pp:integer; {copy of p, made into an integer}
var fname:packed array [1..file_name_size] of char;
begin if s>=str_ptr then s:="???" {this can't happen}
@.???@>
else if s<128 then
  if s<0 then s:="???" {can't happen}
  else if (@<Character |s| is the current new-line character@>) then
    if selector<pseudo then
      return;
for i:=1 to file_name_size do
   fname[i]:=' ';
i:=0;
j:=str_start[s];
while j<str_start[s+1] do
  begin incr(i); fname[i]:=xchr[str_pool[j]]; incr(j);
  end;
pp:=cur_input.loc_field - cur_input.start_field;  {position on current line}
VAX_invoke_editor(fname, l, pp);
exit:end;


@ Here is the stuff for magic file operations.
@<Types...@>=
unsafe_file = [unsafe] file of char;
FAB_ptr = ^VAX_FAB_type;
RAB_ptr = ^VAX_RAB_type;
NAM_ptr = ^VAX_NAM_type;
charptr = ^char;

@ @<VAX/VMS procedures@>=
function VAX_PAS_FAB(var foobar:unsafe_file):FAB_ptr; extern;
function VAX_PAS_RAB(var foobar:unsafe_file):RAB_ptr; extern;

@ @<Glob...@>=
in_FAB,out_FAB: FAB_ptr;
in_RAB,out_RAB: RAB_ptr;
last_length: integer;
last_name:packed array [1..file_name_size] of char;
@z

