Google
 

Trailing-Edge - PDP-10 Archives - cuspbinsrc_2of2_bb-fp63b-sb - 10,7/lp20/lp20.mac
There are no other files named lp20.mac in the archive.
	TITLE	LP20	LP20 RAM AND VFU FILE MANIPULATOR
	SUBTTL	T. LITT /TL

;
;
;        COPYRIGHT (c) 1986
;                    DIGITAL EQUIPMENT CORPORATION
;			 ALL RIGHTS RESERVED.
;
;     THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED
;     AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE
;     AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE.   THIS
;     SOFTWARE  OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR
;     OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON.  NO  TITLE  TO
;     AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED.
;
;     THE INFORMATION  IN  THIS  SOFTWARE  IS  SUBJECT  TO  CHANGE
;     WITHOUT  NOTICE  AND SHOULD NOT BE CONSTRUED AS A COMMITMENT
;     BY DIGITAL EQUIPMENT CORPORATION.
;
;     DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY
;     OF  ITS  SOFTWARE  ON  EQUIPMENT  WHICH  IS  NOT SUPPLIED BY
;     DIGITAL.

	SEARCH	GLXMAC,ORNMAC
	SALL			;MAKE NICE MACROS
	.DIRECT	FLBLST
	PROLOG	(LP20)
	.TEXT	|/SYMSEG:LOW/LOCALS,REL:OPRPAR/SEGMENT:LOW|

	LOC	137
.JBVER::VRSN.	LP2
	RELOC

TOPS20<
DEFINE COPYRIGHT,<ASCIZ \
COPYRIGHT >
>

COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1986. ALL RIGHTS RESERVED.
\;END COPYRIGHT MACRO


	COMMENT	$
LP20 is a replacement for MAKVFU, MAKRAM (a -20 only utility), and DMPVFU.
It is intended that LP20 will consolidate all RAM and VFU file manipulation
utilities.

I gratefully note stealing the GLXLIB skeleton interface from DPM...

	$
SUBTTL	Table of Contents

;	TABLE OF CONTENTS FOR LP100/LP20 RAM and VFU file manipulator
;
;
;			   SECTION			      PAGE
;    1. Table of Contents.....................................   2
;    2. Revision history......................................   3
;    3. Assembly parameters...................................   4
;    4. Various control blocks................................   5
;    5. Command table definitions.............................   6
;    6. Initialization........................................   7
;    7. Error message processing..............................   8
;    8. Command tables
;         8.1   Major modes...................................   9
;         8.2   Generic commands..............................  11
;         8.3   RAM mode......................................  14
;         8.4   VFU mode......................................  15
;    9. Parser action routines for field validation...........  16
;   10. Generic commands
;        10.1   Control-Z and EXIT............................  17
;        10.2   HELP..........................................  18
;        10.3   MODE..........................................  19
;        10.4   LIST and SHOW.................................  22
;        10.5   READ and WRITE................................  25
;   11. RAM commands
;        11.1   ARROW.........................................  35
;        11.2   CLEAR.........................................  36
;        11.3   (CONDITIONALLY-)TRANSLATE.....................  37
;        11.4   LIST and SHOW support.........................  39
;        11.5   LOWER-CASE/UPPER-CASE.........................  42
;        11.6   NUMBER-OF-DATA-BITS...........................  43
;        11.7   Utility routines..............................  44
;   12. VFU commands
;        12.1   CLEAR.........................................  45
;        12.2   LENGTH........................................  46
;        12.3   LINES-PER-INCH................................  47
;        12.4   LIST and SHOW support.........................  48
;        12.5   (UN-)PUNCH....................................  51
;        12.6   PAGE-SIZE.....................................  53
;        12.7   Utility routines..............................  54
;   13. Parser interface
;        13.1   Argument fetchers.............................  55
;   14. Default RAM data......................................  56
;   15. Macros for generating default VFU data................  58
;   16. Default VFU data buffer...............................  60
;   17. Error routines........................................  61
;   18. Impure storage........................................  62
SUBTTL	Revision history


REPEAT	0,<

Edit	Who	Date	What
----	---   ---------	-------------------------------------------------------
   1	 TL   27-APR-86	Create from the pure frustration with what came before.
   2	 TL   27-APR-86	Make the changes for TOPS-20.
   3	 TL   02-MAY-86	Add RAM mode CLEAR command
   4	 TL   10-MAY-86	Remove $ABBREV macro.  KEYTAB can serve.

>

	LP2EDT==4

	LP2VER==1		;VERSION
	LP2MIN==0
	LP2WHO==0
SUBTTL	Assembly parameters

;ACCUMULATORS:

	C=10		;CHARACTER AC

	F=11		;FLAG AC
	;RH IS TEMP FOR EACH CMD
	;LH IS GLOBAL
	F.R8BT==(1B0)		;RAM IS 8-BIT

	P=17		;NORMAL STACK

;VARIOUS PARAMETERS:

	PDLSIZ==^D1000	;PUSH-DOWN STACK SIZE
	FILSIZ==16	;NUMBER OF WORDS NEEDED FOR AN ASCIZ FILESPEC

DEFINE	$MSG	(TYP,PFX,RET,TXT),<
	PUSHJ	P,[PUSHJ P,ERRMSG
		   XWD	"TYP",''PFX''
		   XWD	RET,[ITEXT (<'TXT>)]]
>

	CR.SAV==CR.SIZ			;FOR ACTION ROUTINES

	CHRMSK==177
	BYTMSK==377
SUBTTL	Various control blocks

; GLXLIB INITIALIZATION BLOCK
IB:	$BUILD	(IB.SZ)			;SIZE OF BLOCK
	  $SET	(IB.PRG,,%%.MOD)	;PROGRAM NAME
	  $SET	(IB.OUT,,T%TTY)		;TTY OUTPUT
	  $SET	(IB.FLG,IT.OCT,1)	;REQUIRE COMMAND TERMINAL
	$EOB				;END OF BLOCK


; PARSER BLOCK
PARBLK:	$BUILD	PAR.SZ			;SIZE OF BLOCK
	  $SET	(PAR.TB,,CMD010)	;ADDRESS OF TABLES
	  $SET	(PAR.PM,,PROMPT)	;PROMPT STRING
	  $SET	(PAR.CM,,CMDBLK)	;COMMAND RETURN BLOCK
	$EOB				;END OF BLOCK

PROMPT:	ASCIZ	|LP20>|			;PROMPT STRING

; DEFAULT DATA FILE FD
TOPS10<
DEFFIL:	$BUILD	(FDMSIZ)		;SIZE OF BLOCK
	  $SET	(.FDLEN,FD.LEN,FDMSIZ)	;LENGTH OF FD
	  $SET	(.FDLEN,FD.TYP,.FDNAT)	;FILE SPEC TYPE (NATIVE)
	  $SET	(.FDSTR,,<'DSK   '>)	;ERSATZ DEVICE HLP:
	  $SET	(.FDNAM,,<'LP20  '>)	;FILE NAME
	  $SET	(.FDEXT,,<'VFU   '>)	;EXTENSION
	$EOB
>
TOPS20<
DEFFIL:	$BUILD	(<.FDLEN+1>)		;SIZE OF BLOCK
	  $SET	(.FDLEN,FD.LEN,FDXSIZ)	;LENGTH OF FD
	  $SET	(.FDLEN,FD.TYP,.FDNAT)	;FILE SPEC TYPE (NATIVE)
	$EOB				;END OF BLOCK
DEFFNM:	ASCIZ	|DSK:LP20.VFU|
	BLOCK	FDXSIZ-<.-DEFFNM>	;ALLOCATE ENOUGH SPACE FOR ANYTHING
>
SUBTTL	Command table definitions

; LIST COMMAND SWITCHES
	LS.ALL==1B19			;/ALL-ENTRIES
	LS.BRF==1B20			;/BRIEF
	LS.LIN==1B21			;/BY-LINE
	LS.TTY==1B22			;LIST ON TTY:
	LS.VAL==77			;RESERVED FOR SWITCHES WITH VALUES

; PUNCH COMMAND MODIFIER
	PU.UNP==1B19			;UN-PUNCH

; WRITE COMMAND SWITCHES
	WR.8BT==1B19			;/8-BIT FORMAT
	WR.L10==1B20			;/LP100-CODES
SUBTTL	Initialization

START:	JFCL				;NO CCL ENTRY
	RESET				;STOP I/O
	MOVE	P,[IOWD PDLSIZ,PDL]	;SET UP STACK
	MOVEI	S1,IB.SZ		;LENGTH OF IB
	MOVEI	S2,IB			;ADDRESS OF IB
	PUSHJ	P,I%INIT##		;FIREUP GLXLIB
	MOVE	T1,[Z.BEG,,Z.BEG+1]	;SET UP BLT
	SETZM	Z.BEG			;CLEAR FIRST WORD
	BLT	T1,Z.END-1		;CLEAR ENTIRE LOWSEG
	MOVEI	T1,MSGTYO		;MESSAGE TYPEOUT ROUTINE
	MOVEM	T1,TYOADR		;SAVE
	SETZB	S1,S2			;CLEAR ACS
	PUSHJ	P,P$INIT##		;INITIALIZE THE PARSER

GETCMD:	MOVE	P,[IOWD PDLSIZ,PDL]	;SET UP STACK
	TRZ	F,-1			;CLEAR PER-COMMAND FLAGS
	MOVE	S1,[CMDBLK,,CMDBLK+1]	;SET UP BLT
	SETZM	CMDBLK			;CLEAR FIRST WORD
	BLT	S1,CMDBLK+PAGSIZ-1	;CLEAR OUT COMMAND PARSER PAGE
	MOVEI	S1,COM.SZ-1
	STORE	S1,.MSTYP+CMDBLK,MS.CNT	;SET INITIAL SIZE
	MOVEI	S1,PAR.SZ		;GET SIZE OF PARSER BLOCK
	MOVEI	S2,PARBLK		;POINT TO IT
	PUSHJ	P,PARSER##		;PARSE THE COMMAND
	JUMPF	COMERR			;CHECK FOR PARSER ERRORS

DISPAT:	MOVEI	S1,COM.SZ+CMDBLK	;POINT TO FIRST ARGUMENT
	PUSHJ	P,P$SETU##		;GET BASE ADDRESS OF PARSED DATA
	PUSHJ	P,P$KEYW##		;GET KEYWORD VALUE
	SKIPT				;CHECK FOR CONFUSION
	$STOP	(LIC,<LP20 is confused>)
	PUSHJ	P,(S1)			;DISPATCH TO PROCESSOR
	JRST	GETCMD			;GO GET ANOTHER COMMAND


; HERE ON PARSER ERRORS
COMERR:	MOVE	S1,PRT.FL(S2)		;GET THE FLAGS
	SKIPA	S2,PRT.EM(S2)		;GET THE ADDRESS OF ERROR TEXT
SYNERR:	MOVEI	S2,[ASCIZ |Command syntax error|]
	$TEXT	(,<^M^J? ^T/0(S2)/>)
	JRST	GETCMD			;GO TRY AGAIN
SUBTTL	Error message processing

MSGTYO:	$CALL	K%TPOS			;RETURN HORRIZONTAL CARRIAGE POSITION
	MOVEI	S2,[ASCIZ ||]		;ASSUME ALREADY AT LEFT MARGIN
	SKIPE	S1			;TEST
	MOVEI	S2,[BYTE(7) .CHCRT,.CHLFD,0] ;NEED A CRLF
TOPS10<
	HRROI	T4,.GTWCH		;GETTAB TO
	GETTAB	T4,			; RETURN WATCH BITS
	  SETZ	T4,			;STRANGE ...
	TLNN	T4,(JW.WPR!JW.WFL)	;HAVE PREFIX OR FIRST LINE SET?
	TLO	T4,(JW.WPR!JW.WFL)	;NO--DEFAULT TO THEM
>

; Prefix
	HLRZ	T1,ERRPFX		;GET SEVERITY CHARACTER
	MOVSI	T2,'LP2'		;OUR NAME
	HRR	T2,ERRPFX		;FORM PREFIX
TOPS10<
	TXNN	T4,JW.WPR		;WANT PREFIX?
	SETZ	T2,			;NO

; First line
	TXNE	T4,JW.WFL		;WANT FIRST LINE?
>
	SKIPA	T3,[ERRSTR]		;YES
	MOVEI	T3,[ASCIZ ||]		;POINT TO NULL TEXT

; Termination
	CAIE	T1,"["			;INFORMATIONAL?
	TDZA	T4,T4			;NO
	MOVEI	T4,"]"			;TERMINATE PROPERLY
	$TEXT	(,<^T/(S2)/^7/T1/^W/T2/ ^T/(T3)/^7/T4/^M^J>)
	POPJ	P,			;RETURN
SUBTTL	Command tables -- Major modes

	;STARTUP TABLE -- USED TO SELECT INITIAL MODE
CMD010:	$INIT(CMD020)
CMD020:	$KEYDSP	(CMD030)
CMD030:	$STAB
	DSPTAB	(,.CTRLZ,<>,CM%INV)
	DSPTAB	(EXI010,.EXIT,<EXIT>)
	DSPTAB	(HLP010,.HELP,<HELP>)
	DSPTAB	(MOD010,.MODE,<MODE>)
	DSPTAB	(TAK010,.POPJ,<TAKE>)
	$ETAB

	;RAM MODE COMMANDS
RAM010:	$INIT(RAM020)
RAM020:	$KEYDSP	(RAM030)
RAM030:	$STAB
	DSPTAB	(,.CTRLZ,<>,CM%INV)
	DSPTAB	(ARR010,.ARROW,<ARROW-MODE>)
	DSPTAB	(CLR020,.RMCLR,<CLEAR>)
	DSPTAB	(DEL010,.DELIM,<CONDITIONALLY-TRANSLATE>)
	DSPTAB	(DEL010,.DELIM,<DELIMITED-TRANSLATE>,CM%INV)
	DSPTAB	(EXI010,.EXIT,<EXIT>)
	DSPTAB	(HLP010,.HELP,<HELP>)
	DSPTAB	(LST010,.LIST,<LIST>)
	DSPTAB	(LOW010,.LOWER,<LOWER-CASE>)
	DSPTAB	(MOD010,.MODE,<MODE>)
	DSPTAB	(NUM010,.DATAB,<NUMBER-OF-DATA-BITS>)
	DSPTAB	(WRI010,.WRITE,<OUTPUT>,CM%INV)
	DSPTAB	(REA010,.READ,<READ>)
	DSPTAB	(SHO010,.SHOW,<SHOW>)
	DSPTAB	(TAK010,.POPJ,<TAKE>)
	DSPTAB	(TRA010,.TRANS,<TRANSLATE>)
	DSPTAB	(UPP010,.UPPER,<UPPER-CASE>)
	DSPTAB	(WRI010,.WRITE,<WRITE>)
	$ETAB
	;VFU MODE COMMANDS
VFU010:	$INIT(VFU020)
VFU020:	$KEYDSP	(VFU030)
VFU030:	$STAB
	DSPTAB	(,.CTRLZ,<>,CM%INV)
	KEYTAB	(VFUCLR,<C>,<CM%ABR!CM%INV>)	;BECAUSE OF INVIS CHANNEL CMD
	DSPTAB	(CHA010,.CHANN,<CHANNEL>,CM%INV)
VFUCLR:	DSPTAB	(CLR010,.CLEAR,<CLEAR>)
	DSPTAB	(EXI010,.EXIT,<EXIT>)
	DSPTAB	(HLP010,.HELP,<HELP>)
	DSPTAB	(INF010,.SHOW,<INFORMATION>,CM%INV)
	DSPTAB	(LEN010,.LENGT,<LENGTH>)
	DSPTAB	(LIN010,.LINES,<LINES-PER-INCH>)
	DSPTAB	(LST010,.LIST,<LIST>)
	DSPTAB	(MOD010,.MODE,<MODE>)
	DSPTAB	(CLR010,.CLEAR,<NEW>,CM%INV)
	DSPTAB	(WRI020,.WRITE,<OUTPUT>,CM%INV)
	DSPTAB	(PAG010,.PAGES,<PAGE-SIZE>)
	DSPTAB	(PUN010,.CHANN,<PUNCH>)
	DSPTAB	(REA010,.READ,<READ>)
	DSPTAB	(SHO010,.SHOW,<SHOW>)
	DSPTAB	(TAK010,.POPJ,<TAKE>)
	DSPTAB	(UNP010,.UNPUN,<UN-PUNCH>)
	DSPTAB	(WRI020,.WRITE,<WRITE>)
	$ETAB
SUBTTL	Command tables -- Generic commands

EXI010:	$NOISE	(CONFRM,<to the monitor>)

HLP010:	$NOISE	(HLPKEY,<with command>)
HLPKEY:	$KEY	(CONFRM,CMD030,<$ALTERNATE(CONFRM)>)

LST010:	$NOISE	(LSTSWI,<editing buffer to>)
LSTSWI:	$SWITCH	(,LSTRAM,<$ACTION (SHRSWT),$ALTER (LST040)>)
LSTRAM:	$STAB
	DSPTAB	(NEXT(LSTSWI),<LS.BRF>,<BRIEF>)
	$ETAB
LSTVFU:	$STAB
;	DSPTAB	(NEXT(LSTSWI),<LS.BRF>,<BRIEF>)
	DSPTAB	(NEXT(LSTSWI),<LS.LIN>,<BY-LINE>)
	$ETAB
LST040:	$OFILE	(CONFRM,<output listing file>,)

	;MODE COMMAND
MOD010:	$NOISE	(MOD020,<of operation is>)
MOD020:	$KEY	(MOD040,MOD030)
MOD030:	$STAB
	KEYTAB	(-1,<RAM>)
	KEYTAB	(1,<VFU>)
	$ETAB
MOD040:	$NOISE	(CONFRM,<file mode>)

REA010:	$IFILE	(CONFRM,<input data file>,<>)
SHO010:	$NOISE	(SHOSWI,<editing buffer contents>)
SHOSWI:	$SWITCH	(,SHORAM,<$ACTION (SHRSWT),$ALTERNATE (CONFRM)>)
SHORAM:	$STAB
	DSPTAB	(CONFRM,<LS.ALL>,<ALL-ENTRIES>)
	DSPTAB	(SHO030,<1>,<BEGIN:>)
	DSPTAB	(SHO030,<2>,<END:>)
	$ETAB
SHOVFU:	$STAB
	DSPTAB	(CONFRM,<LS.ALL>,<ALL-ENTRIES>)
	DSPTAB	(SHO050,<1>,<BEGIN:>)
	DSPTAB	(NEXT(SHOSWI),<LS.LIN>,<BY-LINE>)
	DSPTAB	(SHO050,<2>,<END:>)
	$ETAB

SHO030:	$QUOTE	(NEXT(SHOSWI),<quoted character>,<$ACTION(CHKCHS),$ALTER(SHO040)>)
SHO040:	$NUMBER	(NEXT(SHOSWI),^D8,<octal character code>,<$ACTION(CHKCHR)>)

SHO050:	$NUMBER	(NEXT(SHOSWI),^D10,<decimal line or channel number>,<>)

TAK010:	$CRLF	(<$ALTERNATE(TAKFDB##),$PREFILL(TAKDEF)>)

WRI010:	$OFILE	(CONFRM,<output data file>,<>)

WRI020:	$SWITCH	(,WRI025,<$ACTION (SHRSWT),$ALTER (WRI030)>)
WRI025:	$STAB
	DSPTAB	(NEXT(WRI020),<WR.8BT>,<8-BIT-FORMAT>)
	DSPTAB	(NEXT(WRI020),<WR.L10>,<LP100-CODES>)
	$ETAB
WRI030:	$OFILE	(CONFRM,<output data file>,<>)

CONFRM:	$CRLF
	;A real kludge to deal with OPRPAR's non-global routines
	;Broken by GALAXY 5 Move to more suitable place
TAKDEF:	MOVEI	S1,TAKFDB##		; Get the TAKE address
	AOS	S1			; Bump over the header
	STORE	S1,CR.PDB(S2),RHMASK	; Save new PDB to use
	$RETT				; Return
SUBTTL	Command tables -- RAM mode

ARR010:	$NOISE	(ARR020,<translation for>)
ARR020:	$QUOTE	(CONFRM,<quoted character>,<$ACTION(CHKCHS),$ALTER(ARR030)>)
ARR030:	$NUMBER	(CONFRM,^D8,<octal character code>,<$ACTION(CHKCHR)>)

CLR020:	$NOISE	(CONFRM,<entire RAM>)

TRA010:	$NOISE	(DEL010,<unconditionally>)

DEL010:	$QUOTE	(DEL030,<quoted character>,<$ACTION(CHKCHS),$ALTER(DEL020)>)
DEL020:	$NUMBER	(DEL030,^D8,<octal character code>,<$ACTION(CHKCHR)>)

DEL030:	$NOISE	(DEL040,<to>)

DEL040:	$QUOTE	(CONFRM,<quoted character>,<$ACTION(CHKCHS),$ALTER(DEL045)>)
DEL045:	$NUMBER	(CONFRM,^D8,<octal character code>,<$ACTION(CHKCHR),$ALTERNATE(DEL050)>)

DEL050:	$KEYDSP	(DEL060)
DEL060:	$STAB
	DSPTAB	(DEL070,0,<DELIMITER-CHARACTER>,CM%INV)
	DSPTAB	(CONFRM,1,<NO-ACTION>)
	DSPTAB	(DEL070,0,<PREFIX-CHARACTER>)
	DSPTAB	(DEL080,2,<SLEW>)
	DSPTAB	(DEL090,3,<VFU-CHANNEL>)
	$ETAB

DEL070:	$NOISE	(DEL074,<and>)
DEL074:	$KEYDSP	(DEL075,<$DEFAULT(<NO-ACTION>),$ALTERNATE(DEL076)>)
DEL075:	$STAB
	DSPTAB	(CONFRM,1,<NO-ACTION>)
	DSPTAB	(DEL080,2,<SLEW>)
	DSPTAB	(DEL090,3,<VFU-CHANNEL>)
	$ETAB
DEL076:	$QUOTE	(CONFRM,<quoted character>,<$ACTION(CHKCHS),$ALTER(DEL078)>)
DEL078:	$NUMBER	(CONFRM,^D8,<octal character code>,<$ACTION(CHKCHR)>)

DEL080:	$NUMBER	(DEL082,^D10,,<$ACTION(CHKSLW)>)
DEL082:	$NOISE	(CONFRM,<lines>)

DEL090:	$NUMBER	(CONFRM,^D10,,<$ACTION(CHKVFU)>)

LOW010:	$NOISE	(CONFRM,<output>)

NUM010:	$NOISE	(NUM020,<is>)
NUM020:	$KEY	(CONFRM,NUM030)
NUM030:	$STAB
	KEYTAB	(0,<7-BITS>)
	KEYTAB	(1,<8-BITS>)
	$ETAB

UPP010:	$NOISE	(CONFRM,<output only>)
SUBTTL	Command tables -- VFU mode

UNP010:
PUN010:	$NOISE	(CHA020,<channel number>)

CHA010:	$NOISE	(CHA020,<number>)

CHA020:	$NUMBER	(CHA030,^D10,<VFU channel number>,<$ACTION(CHKVFU)>)

CHA030:	$KEYDSP	(CHA040)

CHA040:	$STAB
	DSPTAB	(CONFRM,0,<ALL-LINES>)
	DSPTAB	(CONFRM,1,<BOTTOM-OF-FORM>)
	DSPTAB	(CHA050,2,<EVERY>)
	DSPTAB	(CHA055,3,<FORMS-BREAK>)
	DSPTAB	(CHA060,4,<LINES>)
	DSPTAB	(CONFRM,5,<TOP-OF-FORM>)
	$ETAB

CHA050:	$NUMBER	(CHA055,^D10,,<$ACTION(CHKLIN)>)
CHA055:	$NOISE	(CONFRM,<lines>)

CHA060:	$NOISE	(CHA062,<numbered>)
CHA062:	$NUMBER	(CHA064,^D10,,<$ACTION(CHKLIN)>)
CHA064:	$COMMA	(CHA062,<$ALTERNATE(CONFRM)>)

CLR010:	$NOISE	(CONFRM,<entire VFU>)

INF010:	$NOISE	(CONFRM,<about current VFU>)

LEN010:	$NOISE	(LEN020,<of physical page is>)
LEN020:	$NUMBER	(LEN030,^D10,,<$DEFAULT(<66>)>)
LEN030:	$NOISE	(CONFRM,<lines>)

LIN010:	$NOISE	(LIN020,<set by VFU is>)
LIN020:	$KEY	(CONFRM,LIN030,<$DEFAULT(<PRINTER-CONTROLLED>)>)
LIN030:	$STAB
	KEYTAB	(354,6-LPI)
	KEYTAB	(355,8-LPI)
	KEYTAB	(356,LEFT-ALONE,CM%INV)
	KEYTAB	(356,PRINTER-CONTROLLED)
	$ETAB

PAG010:	$NOISE	(PAG020,<of logical page is>)
PAG020:	$NUMBER	(PAG030,^D10,,<>)
PAG030:	$NOISE	(CONFRM,<lines>)
SUBTTL	Parser action routines for field validation

	;ROUTINE TO VERIFY OCTAL CHARACTER CODES FOR RAM COMMANDS
	;STRING
CHKCHS:	MOVE	S2,CR.SAV(S2)		;GET ADDRESS OF PARSE DATA
	LDB	S1,[POINT 7,CR.RES(S2),13] ;GET SECOND CHARACTER
	JUMPN	S1,CHKCER		;IF STRING TOO LONG, ERROR
	LDB	S1,[POINT 7,CR.RES(S2),6] ;FIRST CHARACTER IS VALUE
	CAIA
	;NUMBER
CHKCHR:	MOVE	S1,CR.RES(S2)		;GET DATUM
	CAIL	S1,0			;MUST BE IN RANGE 0 THRU
	CAILE	S1,^D255		;255
	 JRST	CHKCER			;FOR 8-BIT MODE
	TLNN	F,F.R8BT		;OK IF 8-BIT MODE
	 CAIG	S1,^D127		;BUT 7 BIT MODE MUST BE 0 THRU 127
	$RETT				;OK
CHKCER:	MOVEI	S1,ERARG$		;ERROR CODE
	MOVEI	S2,[ASCIZ /Invalid character code/]
	$RETF				;NG

	;ROUTINE TO VERIFY SLEW RANGES FOR RAM COMMANDS
CHKSLW:	MOVE	S1,CR.RES(S2)		;GET DATUM
	CAIL	S1,0			;MUST BE IN RANGE 0 THRU
	CAILE	S1,^D15			;15
	 CAIA				;ERROR
	$RETT				;OK
	MOVEI	S1,ERARG$		;ERROR CODE
	MOVEI	S2,[ASCIZ /Invalid slew distance (0 thru 15)/]
	$RETF				;NG

	;ROUTINE TO VERIFY VFU CHANNEL NUMBERS
CHKVFU:	MOVE	S1,CR.RES(S2)		;GET DATUM
	CAIL	S1,1			;MUST BE IN RANGE 1 THRU
	CAILE	S1,^D12			;12
	 CAIA
	$RETT				;OK
	MOVEI	S1,ERARG$		;ERROR CODE
	MOVEI	S2,[ASCIZ /Invalid channel number/]
	$RETF				;NG

	;ROUTINE TO VERIFY VFU LINE NUMBERS
CHKLIN:	MOVE	S1,CR.RES(S2)		;GET DATUM
	 CAIL	S1,1			;MUST BE IN RANGE 1 THRU
	CAMLE	S1,LINSPP		;PHYSICAL PAGE SIZE
	 CAIA
	$RETT				;OK
	MOVEI	S1,ERARG$		;ERROR CODE
	MOVEI	S2,[ASCIZ /Invalid line number/]
	$RETF				;NG
SUBTTL	Generic commands -- Control-Z and EXIT


	EXP	CTLZ.H			;ADDRESS OF HELP TEXT
.CTRLZ:	JRST	.EXIT			;SAME AS EXIT


CTLZ.H:	ASCIZ	|
Typing Control-Z will cause the program to
return to monitor level.  This is the preferred
method of exiting the program.
|


	EXP	EXIT.H			;ADDRESS OF HELP TEXT
.EXIT:	$HALT				;RETURN TO MONITOR
	JRST	START			;THE FOOL TYPED CONTINUE


EXIT.H:	ASCIZ	|
The EXIT command will cause the program to
return to monitor level.  This command is
equivalent to typing ^Z.
|
SUBTTL	Generic commands -- HELP


	EXP	HELP.H			;ADDRESS OF HELP TEXT
.HELP:	PUSHJ	P,P$KEYW##		;GET A KEYWORD
	JUMPF	HELP.1			;SHOULDN'T FAIL
	MOVE	S1,ARG.DA(S2)		;POINT TO RETURNED DATA
	HLRZ	S1,(S1)			;NOW GET PROCESSOR ADDRESS
	MOVE	S1,-1(S1)		;AND THE HELP TEXT POINTER
	HRROI	S1,(S1)			;FINALLY POINT TO THE TEXT
	JRST	HELP.2			;ONWARD

HELP.1:	HRROI	S1,HELP.H		;POINT HELP FOR THIS COMMAND

HELP.2:	$CALL	K%SOUT			;TYPE IT
	HRROI	S1,[BYTE(7).CHCRT,.CHLFD,0] ;POINT TO A CRLF
	$CALL	K%SOUT			;TYPE IT
	POPJ	P,			;DONE


HELP.H:	ASCIZ	|
The HELP command will print useful information about
any other command.  Typing HELP with no argument will
cause this text to be printed.
|
SUBTTL	Generic commands -- MODE

	EXP	MODE.H
.MODE:	$CALL	P$KEYW##		;GET KEYWORD
	JUMPF	SYNERR
	HRREM	S1,CMDMOD		;SET NEW MODE
	MOVE	T1,S1			;SAVE WORD INDEX
	ASH	S1,1			;INDEX BY TWOS
	MOVE	T2,S1			;SAVE BY-TWOS INDEX

	DMOVE	S1,[EXP RAM010,[ASCIZ /LP20_RAM>/]
		    EXP	-1,0		;TOP LEVEL
		    EXP VFU010,[ASCIZ /LP20_VFU>/]
		    ]+2(T2)		 ;GET ADDRESS OF NEW PARSE TABLE/PROMPT
	STORE	S1,PARBLK+PAR.TB	;STORE NEW PARSE TABLE ADDRESS
	STORE	S2,PARBLK+PAR.PM	;STORE NEW PROMPT ADDRESS

	DMOVE	S1,[SIXBIT /RAM/	;DEFAULT FILE EXTENSION
		    EXP RAM030		;AND HELP KEYWORDS
		    SIXBIT /___/
		    EXP 0
		    SIXBIT /VFU/
		    EXP VFU030]+2(T2)	;FOR THIS MODE
TOPS10<
	STORE	S1,DEFFIL+.FDEXT	;SET IN DEFAULT FILE SPEC
>
TOPS20<
	$TEXT	(<-1,,DEFFNM>,<DSK:LP20.^W/S1/^0>)
>
	STORE	S2,HLPKEY+.CMDAT+1	;STORE CORRECT HELP CHAIN

	DMOVE	S1,[XWD	DEFRAM,RDATA	;DEFAULT RAM
		    EXP	RDATA+DEFRLN
		    EXP	0,0
		    XWD	DEFVFU,RDATA	;DEFAULT VFU
		    EXP	RDATA+DEFVLN
		    ]+2(T2)		;FOR THIS MODE
	BLT	S1,-1(S2)		;COPY DEFAULT DATA INTO PLACE
	DMOVE	S1,[EXP	LSTRAM,SHORAM	;SWITCH PARSES FOR LIST AND SHOW
		    EXP	0,0
		    EXP LSTVFU,SHOVFU]+2(T2)
	MOVEM	S1,LSTSWI+.CMDAT+1	;STORE FOR LIST
	MOVEM	S2,SHOSWI+.CMDAT+1	;AND FOR SHOW

	DMOVE	S1,[POINT 8,RDATA	;ASSUME VFU STYLE DATA
		    EXP 4]
	DMOVEM	S1,FILPTR		;POINT TO DEFAULT VFU

	MOVEI	S1,^D66
	MOVEM	S1,LINSPP
	MOVEI	S1,^D60
	MOVEM	S1,LINSLP

	MOVEI	S1,377			;LOWER LIMIT IS 377
	MOVEM	S1,RAMLIM
	SETZM	RAMLIM+1		;UPPER LIMIT IS UNTOUCHED

	SKIPL	CMDMOD			;IN VFU MODE?
	 $RET				;YES, DONE

	MOVE	S1,[XWD RDATA,RDATA+100] ; RAM DATA IS DUPLICATED FOR SECOND
	BLT	S1,RDATA+177		;128 CHARACTERS

	DMOVE	S1,[POINT 18,RDATA	;SETUP RAM STYLE POINTERS
		    EXP 2]
	DMOVEM	S1,FILPTR		;TO DEFAULT RAM

	$RET
MODE.H:	ASCIZ	|
The MODE command selects the operating mode of the LP20 program.

RAM mode is used for editing .RAM files, which specify how the ASCII
characters in a user data file are to be interpreted by an LP20 controller.

VFU mode is used for editing .VFU files, which specify the vertical
pitch and physical size of each logical page, and on which line(s) each
VFU channel stops.
|
SUBTTL	Generic commands -- LIST and SHOW

	EXP	SHOW.H
.SHOW:	TROA	F,LS.TTY!LS.BRF		;MARK LISTING TO TERMINAL
	 EXP	LIST.H
.LIST:	DMOVE	T1,RAMLIM		;DEFAULT /BEGIN AND /END
	CAMLE	T1,T2			;IF OUT OF ORDER
	 EXCH	T1,T2			;USER HASN'T TOUCHED ANYTHING
LIST0S:	PUSHJ	P,P$SWIT##		;GET SWITCH
	JUMPF	LIST.0			;NONE, TRY FILESPEC
	MOVE	S1,ARG.DA(S2)		;GET RETURNED CODE
	TRNE	S1,LS.VAL		;VALUE SWITCH?
	 JRST	LIST0V			;YES, PROCESS VALUE
	TRO	F,(S1)			;NO - SET ANY BITS FOR THIS COMMAND
	JRST	LIST0S			;LOOP FOR ALL SWITCHES

LIST0V:	MOVE	T3,S1			;SAVE SWITCH CODE
	PUSHJ	P,PARCHR		;GET VALUE
	 JUMPF	SYNERR
	CAIN	T3,1			;/BEGIN?
	 JRST	[MOVEM	S1,T1		;YES, SAVE
		 MOVEM	S1,RAMLIM	;AND RESET LOWER LIMIT FOR DEFAULT
		 JRST	LIST0S]		;LOOP FOR MORE SWITCHES
	CAIN	T3,2			;/END?
	 JRST	[MOVEM	S1,T2		;YES, SAVE
		 MOVEM	S1,RAMLIM+1	;AND RESET UPPER LIMIT FOR DEFAULT
		 JRST	LIST0S]		;LOOP FOR MORE SWITCHES
	JRST	LIST0S			;LOOP FOR MORE
LIST.0:	CAMLE	T1,T2			;MUST BE IN ORDER
	 $MSG	(<?>,BEM,GETCMD,</BEGIN:^O3R0/T1,BYTMSK/ exceeds /END:^O3R0/T2,BYTMSK/>)
	DMOVEM	T1,RAMLIM		;SAVE NEW DEFAULTS
	TRNE	F,LS.TTY		;SHOW?
	 JRST	LIST.2			;YES, SKIP ALL THIS
	PUSHJ	P,P$OFIL##		;GET FILE
	JUMPF	SYNERR			;COMMAND SYNTAX ERROR
	PUSH	P,S1
	PUSHJ	P,P$CFM##		;MUST BE EOL
	POP	P,S1
	JUMPF	SYNERR			;COMMAND SYNTAX ERROR

	MOVEM	S1,FILEFD+FOB.FD	;SAVE FD ADDRESS
	SETZM	FILEFD+FOB.US		;NO IYB PPN
	SETZM	FILEFD+FOB.CD		;NO CONNECTED DIRECTORY
	SETZM	FILEFD+FOB.AB		;NO ATTRIBUTES BLOCK

	MOVEI	S1,^D7			;7 BIT BYTES
	MOVEM	S1,FILEFD+FOB.CW	;SAVE

	MOVEI	S1,FOB.SZ		;LENGTH OF FOB
	MOVEI	S2,FILEFD		;ADDRESS OF FOB
	$CALL	F%OOPN
	JUMPT	LIST.1			;ONWARD IF NO ERRORS
	MOVE	S2,FILEFD+FOB.FD	;GET OUR FD
	$MSG	(<?>,CWF,GETCMD,<Cannot write ^F/(S2)/; ^E/S1/>)

LIST.1:	MOVEM	S1,LSTIFN		;SAVE
	MOVNI	S2,1			;WE WANT THE EXACT FD
	$CALL	F%FD			;GET IT
	SKIPT				;ANY ERRORS?
	SKIPA	S2,FILEFD+FOB.FD	;YES--JUST USE WHAT WE HAVE
	MOVEI	S2,(S1)			;POINT TO SOURCE
	$MSG	(<[>,WLF,,<Writing listing to ^F/(S2)/>)

LIST.2:	MOVEM	F,TXTFLG		;SAVE FLAGS FOR $TEXT OUTPUT
	MOVE	S1,CMDMOD		;GET COMMAND MODE
	PUSHJ	P,@[EXP LIST.R,0,LIST.V]+1(S1) ;CALL LISTER
					;T1/ BEGIN: T2/ END:

	MOVE	S1,LSTIFN
	TRNN	F,LS.TTY		;DON'T CLOSE FILE IF SHOW CMD
	 $CALL	F%REL			;CLOSE DISK FILE
	TRNE	F,LS.TTY		;TTY LISTING?
	 $TEXT	(LSTCHR,<>)		;YES, ADD A <CR><LF> BEFORE PROMPT
	$RET
SHOW.H:	ASCIZ	|
The SHOW (editing buffer) command lists the contents of the editing buffer
on your terminal.  (Use LIST to direct the output to a disk file.)

The following switches may be used to control the output produced:
	/ALL-ENTRIES	List entire buffer
	/BEGIN:		Start listing at specified position
	/END:		End listing with specified position

The default is to show only the part of the buffer of current interest.

In VFU mode, the following additional switch selects the output format:
	/BY-LINE	Output VFU by line number rather than by channel

The default is to output a listing by channel number.
|

LIST.H:	ASCIZ	|
The LIST (editing buffer to) filespec command produces a readable listing
of the editing buffer on the specified file.

The output file must be on disk.  Use SHOW for listing the buffer to your
terminal.

In RAM mode, the following switch may be used:
	/BRIEF		Do not include reference data at end of listing

The default is to include about a page of reference data at the end of
the listing.

In VFU mode, the following switche may be used:
	/BY-LINE	Output VFU by line number rather than by channel

The default is to output a listing by channel number.
|

LSTCHR:	MOVE	S2,TXTFLG		;GET FLAGS (F IS APPARENTLY CORRUPT)
	TRNE	S2,LS.TTY		;SHOW?
	 PJRST	K%BOUT##		;YES, LET GLXTXT DO IT
	MOVE	S2,S1			;COPY BYTE
	MOVE	S1,LSTIFN		;GET THE IFN OF THE FILE
	PJRST	F%OBYT			;GO OUTPUT IT
SUBTTL	Generic commands -- READ and WRITE


	EXP	READ.H
.READ:	SETZ	T1,			;READ
	CAIA	WRIT.H
.WRITE:	MOVEI	T1,1			;WRITE

FILE:	HRRI	F,WR.L10		;DEFAULT TO WRITE/LP100
	PUSHJ	P,@[EXP	P$IFIL##	;GET INPUT FILE
		    EXP	P$OFIL##](T1)	;GET OUTPUT FILE
	JUMPT	FILE.D			;GOT IT
	HLLZS	F			;ELSE RESET FLAGS

FILE.A:	PUSHJ	P,P$SWIT##		;TRY TO GET A SWITCH
	JUMPF	FILE.C			;CAN'T
	MOVE	S1,ARG.DA(S2)		;GET RETURNED CODE
	IOR	F,S1			;SAVE FLAG
	JRST	FILE.A			;LOOP FOR ANOTHER


FILE.C:	PUSHJ	P,@[EXP	P$IFIL##	;GET INPUT FILE
		    EXP	P$OFIL##](T1)	;GET OUTPUT FILE
	JUMPF	SYNERR			;COMMAND SYNTAX ERROR
	PUSH	P,S1
	PUSHJ	P,P$CFM##		;MUST BE EOL
	POP	P,S1
	JUMPF	SYNERR			;COMMAND SYNTAX ERROR

FILE.D:	MOVEM	S1,FILEFD+FOB.FD	;SAVE FD ADDRESS
	SETZM	FILEFD+FOB.US		;NO IYB PPN
	SETZM	FILEFD+FOB.CD		;NO CONNECTED DIRECTORY
	SETZM	FILEFD+FOB.AB		;NO ATTRIBUTES BLOCK
	PUSHJ	P,@[EXP E$READ,E$WRIT](T1) ;DO I/O
	POPJ	P,			;RETURN
READ.H:	ASCIZ	|
The READ command reads a pre-existing VFU or RAM file into the editing
buffer.

In VFU mode, the controller type (LP20 or LP100) is determined automatically.
|

WRIT.H:	ASCIZ	|
The WRITE command writes the editing buffer to a new .VFU or .RAM file.

In VFU mode, the file format may be selected with the following switches:
	/8-BIT-FORMAT	Writes a (TOPS-20) 8-bit VFU file with LP20 codes.
	/LP100-CODES	Writes LP100-format VFU codes.
The default is /LP100-CODES in a (TOPS-10) 7-bit VFU file.

If both /8-BIT-FORMAT and /LP100-CODES are specified, the LP100 codes
will be written to a (TOPS-20) 8-bit VFU file.

Note that TOPS-10 normally uses /LP100-CODES in 7-bit VFU files, even with
LP20 controllers.  The monitor/LPTSPL provide automatic translation.
|
E$READ::TDZA	P2,P2			;READ
E$WRIT:: MOVEI	P2,1			;WRITE
	MOVEI	S1,^D36			;36 BIT BYTES
	MOVEM	S1,FILEFD+FOB.CW	;SAVE
	MOVEI	S1,FOB.SZ		;LENGTH OF FOB
	MOVEI	S2,FILEFD		;ADDRESS OF FOB
	XCT	FILTAB(P2)		;OPEN FOR INPUT OR OUTPUT
	JUMPT	FILE.1			;ONWARD IF NO ERRORS
	MOVE	S2,FILEFD+FOB.FD	;GET TARGET FD
	SKIPN	P2			;READING OR WRITING?
	$MSG	(<?>,CRF,GETCMD,<Cannot read ^F/(S2)/; ^E/S1/>)
	$MSG	(<?>,CWF,GETCMD,<Cannot write ^F/(S2)/; ^E/S1/>)

FILE.1:	MOVEM	S1,IFN			;SAVE
	MOVNI	S2,1			;WE WANT THE EXACT FD
	$CALL	F%FD			;GET IT
	SKIPT				;ANY ERRORS?
	SKIPA	S2,FILEFD+FOB.FD	;YES--JUST USE WHAT WE HAVE
	MOVEI	S2,(S1)			;POINT TO SOURCE
	HRLZS	S2			;BUILD A BLT POINTER
	HRRI	S2,FD			;GET DESTINATION
	LOAD	S1,.FDLEN(S1),FD.LEN	;GET LENGTH
	BLT	S2,FD-1(S1)		;COPY IT AWAY
	JUMPN	P2,OPEN.4		;JUMP IF WRITING
	MOVE	S1,IFN			;GET IFN
	PUSHJ	P,GETFSZ		;GET FILE SIZE IN WORDS
	 SKIPLE	S1			;BETTER BE A REAL FILE
	CAILE	S1,MAXFIL		;MAKE SURE IT'S REASONABLE
	 $MSG	(<?>,NLS,GETCMD,<Not a legal size for ^F/FD/>)
	$CALL	M%GMEM			;GET MEMORY TO MATCH SIZE OF FILE
	ADJSP	P,3			;ALLOCATE SOME SPACE
	DMOVEM	S1,-2(P)		;STORE RESULT
	MOVN	P1,S1			;NEGATE SIZE
	MOVSS	P1			;MAKE AOBJN POINTER TO FILE
	HRR	P1,S2			;COMPLETE WITH ADDRESS
	MOVEM	P1,0(P)			;SAVE IT FOR LATER
	$MSG	(<[>,RDF,,<Reading data from ^F/FD/>)

OPEN.1:	MOVE	S1,IFN			;GET IFN
	$CALL	F%IBYT			;GET A WORD
	JUMPT	OPEN.2			;JUMP IF NO ERRORS
	$MSG	(<?>,FIE,OPEN.E,<^E/S1/ reading ^F/FD/>)

OPEN.E:	DMOVE	S1,-2(P)		;GET FILE MEMORY
	$CALL	M%RMEM			;GET RID OF IT
	ADJSP	P,-3			;FIX STACK
	MOVE	S1,IFN			;GET IFN
	$CALL	F%REL			;RELEASE THE FILE
	JRST	GETCMD			;DONE
OPEN.2:	MOVEM	S2,(P1)			;PUT A WORD
	AOBJN	P1,OPEN.1		;LOOP THROUGH ENTIRE FILE

	POP	P,P1			;POINT TO FILE IN MEMORY
	DMOVE	T1,[POINT 18,RDATA	;ASSUME .RAM FILE
		    EXP	2]		;BYTES/WORD
	MOVE	S2,[POINT 18,(P1),17]	;EXTERNAL IS ALSO 18 BIT
	PUSH	P,[0]			;NORMAL BYTES
	SKIPG	CMDMOD			;PROCESSING VFU?
	 JRST	OPEN.R			;NO, NOTHING SPECIAL

	SETZM	VFUSIZ			;VFU IS EMPTY
	;FIGURE OUT FILE FORMAT
	DMOVE	T1,[POINT 8,RDATA	;VFU'S ARE STORED INTERNALLY AS 8 BIT
		    EXP	5]		;BYTES/WD
	MOVE	S2,[POINT 7,(P1)]	;ASSUME 7-BIT EXTERNAL REPRESENTATION
	ILDB	S1,S2			;GET FIRST BYTE
	 CAIL	S1,25			;SKIP IF LESS THAN FIRST VALID START
	CAILE	S1,27			;SKIP IF IN RANGE
	 SETOM	(P)			;NOT, WIERD 8-BIT BYTES
	SKIPE	(P)			;WIERD?
	 MOVE	S2,[POINT 16,(P1),15]	;YES, ASSUME 8-BIT VFU IN DTE FORMAT
OPEN.R:	DMOVEM	T1,FILPTR		;SAVE POINTERS TO INTERNAL DATA

OPEN.3:	LDB	S1,S2			;GET THE NEXT BYTE
	SKIPN	(P)			;DTE FORMAT?
	 JRST	OPN.3A			;NO
	IDPB	S1,T1			;YES, DEPOSIT LOW BYTE FIRST
	PUSHJ	P,CHKSTP		;CHECK FOR STOP CODE
	 JRST	OPN.3S			;GOT ONE, STOP
	LSH	S1,-8			;GET HIGH BYTE NEXT

OPN.3A:	IDPB	S1,T1			;STORE IN INTERNAL BUFFER
	PUSHJ	P,CHKSTP		;CHECK FOR STOP CODE
	 JRST	OPN.3S			;GOT ONE, STOP
	IBP	S2			;POINT TO NEXT EXTERNAL BYTE
	TRNN	S2,-1			;DONE ENTIRE INTERNAL WORD YET?
	 JRST	OPEN.3			;NO, KEEP GOING
	HLLZS	S2			;YES, RECYCLE THE WORD OFFSET
	AOBJN	P1,OPEN.3		;AND LOOP FOR ENTIRE FILE

	SKIPGE	CMDMOD			;VFU MODE?
	 JRST	OPN.3R			;NO, RAM
OPN.3S:	SETZ	S2,			;ASSUME BAD FILE
	MOVE	S1,FILPTR		;GET POINTER TO FILE
	ILDB	S1,S1			;READ FIRST BYTE
	CAIN	S1,25			;GENERIC START?
	 MOVEI	S2,356			;YES, USE 8-BIT VARIETY
	CAIN	S1,26			;6-LPI START?
	 MOVEI	S2,354			;YES, LIKEWISE
	CAIN	S1,27			;8-LPI START?
	 MOVEI	S2,355			; ...
	JUMPN	S2,OPN.3B		;JUMP IF VALID START CODE
	 CAIL	S1,354			;NOT 7-BIT, IS IT 8?
	CAILE	S1,356			;...
	 $MSG	(<?>,IVS,OPEN.E,<Invalid VFU start code ^O/S1/>)
	JRST	OPN.3C			;VALID 8-BIT START, CHECK STOP

OPN.3B:	MOVE	S1,FILPTR		;GET POINTER TO START BYTE
	IDPB	S2,S1			;REPLACE START BYTE WITH 8-BIT CODE
	MOVEI	S2,1			;SET INDEX FOR PROPER STOP CODE

OPN.3C:	LDB	S1,T1			;GET LAST VFU DATA BYTE
	CAME	S1,[EXP 357,126](S2)	;MAKE SURE STOP CODE MATCHES START
	 $MSG	(<?>,NVS,OPEN.E,<Invalid VFU stop code ^O/S1/>)
	MOVEI	S1,357			;SET TO 8-BIT CODE
	DPB	S1,T1			;SO INTERNAL CODES ARE ALWAYS 8-BIT
	MOVE	S1,VFUSIZ		;GET SIZE OF VFU
	 CAIGE	S1,<143*2>+2		;MAX OF 143 LINES + START AND STOP
	TRNE	S1,1			;BETTER BE EVEN (2-BYTE PAIRS +S +S)
OPN.3D:	 $MSG	(<?>,NVL,OPEN.E,<Invalid VFU length>)
	LSH	S1,-1			;TURN INTO LINES
	SOJLE	S1,OPN.3D		;CORRECT FOR START AND STOP. BE SANE.
	MOVEM	S1,LINSPP		;SET AS PHYSICAL LENGTH
	CAMGE	S1,LINSLP		;CHECK LOGICAL LENGTH
	 MOVEM	S1,LINSLP		;LOGICAL WAS PAST NEW PHYSICAL, SHORTEN
	JRST	OPN.3X			;IT'S OK, EXIT

OPN.3R:	MOVE	S1,-2(P)		;GET SIZE OF .RAM FILE
	CAIE	S1,200			;RAM FILES MUST BE 256 CHARS IN 18 BITS
	 $MSG	(<?>,NRF,OPEN.E,<Not a RAM file>)

OPN.3X:	DMOVE	S1,-2(P)		;GET FILE MEMORY
	$CALL	M%RMEM			;GET RID OF IT
	ADJSP	P,-3			;FIX STACK
	MOVEI	S1,377			;LOWER LIMIT IS 377
	MOVEM	S1,RAMLIM
	SETZM	RAMLIM+1		;UPPER LIMIT IS UNTOUCHED
	JRST	OPEN.5			;DONE, RELEASE FILE AND EXIT
	;ROUTINE TO TURN AN IFN IN S1 INTO THE FILE SIZE IN WORDS

TOPS10<
	;ON TOPS-10, WE CAN TRUST GLXFIL
GETFSZ:	MOVX	S2,FI.SIZ		;SIZE OF FILE IN BYTES
	PJRST	F%INFO			;GET SIZE OF FILE
>
TOPS20<
	;ON THE OTHER HAND, TOPS-20 GLXFIL JUST DOESN'T
GETFSZ:	$SAVE	<T1,T2,T3>
	MOVX	S2,FI.CHN		;GET THE JFN ASSIGNED
	$CALL	F%INFO			;BY GLXLIB
	MOVE	S2,[2,,.FBBYV]		;READ 2 WORDS OF FDB INFO
	MOVEI	T1,T2			;INTO T2 AND T3
	GTFDB%				;READ
	 ERJMP	[$STOP	(JSF,<GTFDB% JSYS failed>)]
	MOVEI	S1,^D36			;BITS/WORD
	LOAD	S2,T2,FB%BSZ		;BYTE SIZE OF FILE
	IDIVI	S1,(S2)			;COMPUTE BYTES/WORD IN FILE
	MOVE	S2,T3			;GET BYTES IN FILE
	EXCH	S1,S2			;SWITCH
	IDIVI	S1,(S2)			;COMPUTE WORDS IN FILE
	SKIPE	S2			;PARTIAL WORD AT END?
	 AOJ	S1,			;YES, ALLOW FOR IT
	$RET				;RETURN S1/ FILE SIZE IN WORDS
>
OPEN.4:	$MSG	(<[>,WDF,,<Writing data to ^F/FD/>)
	SKIPG	CMDMOD			;VFU?
	 JRST	OPN.4R			;NO, RAM IS SIMPLE
	TRNN	F,WR.8BT		;/8-BIT FORMAT?
	 TRO	F,WR.L10		;NO, MUST BE /LP100 CODES
	MOVE	T1,FILPTR		;POINT TO DATA
	SETZM	VFUSIZ			;CLEAR VFU SIZE
OPN.4A:	ILDB	S1,T1			;GET VFU CODE
	PUSHJ	P,CHKSTP		;SEE IF A STOP CODE
	 CAIA				;YES
	JRST	OPN.4A			;NO, CONTINUE
	MOVE	S1,VFUSIZ		;GET SIZE OF VFU IN BYTES
	TRNN	F,WR.8BT		;/8-BIT FORMAT?
	 IDIVI	S1,5			;NO, 7.  5/WORD
	TRNE	F,WR.8BT		;/8-BIT FORMAT?
	 IDIVI	S1,4			;YES, 4/WORD
	SKIPE	S2			;PARTIAL WORD?
	 AOJ	S1,			;YES, ALLOCATE IT
	$CALL	M%GMEM			;ALLOCATE A SCRATCH BUFFER
	ADJSP	P,2			;SAVE SOME SPACE
	DMOVEM	S1,-1(P)		;TO SAVE THE DESCRIPTOR
	HRLI	S2,(POINT 8,)		;ASSUME /8-BIT FORMAT
	TRNN	F,WR.8BT		;IS IT?
	 HRLI	S2,(POINT 7,)		;AH, WELL, 7-BIT

	MOVE	T2,FILPTR		;POINT TO DATA
	ILDB	S1,T2			;GET START CODE
	TRNE	F,WR.L10		;/LP100?
	 MOVE	S1,[EXP 26,27,25]-354(S1) ;YES -- TRANSLATE TO 7-BIT START
	IDPB	S1,S2			;OUTPUT START CODE

	SETZM	VFUSIZ			;RECOMPUTE SIZE OF VFU
OPN.4B:	ILDB	S1,T2			;GET NEXT DATA BYTE
	PUSHJ	P,CHKSTP		;SEE IF A STOP BYTE
	 JRST	OPN.4C			;JUMP WHEN AT END
	IDPB	S1,S2			;NOT AT END, COPY VFU DATA
	JRST	OPN.4B			;LOOP TO END OF VFU

	;HELPER ROUTINE TO SEE IF WE GOT A STOP CODE
CHKSTP:	SKIPG	CMDMOD			;MUST BE A VFU
	 JRST	.POPJ1			;RAM, CAN'T BE A STOP CODE
	PUSH	P,S1			;SAVE INPUT
	ANDI	S1,377			;IN CASE OF A 16-BIT FILE
	 CAIE	S1,126			;7-BIT STOP?
	CAIN	S1,357			;OR 8-BIT?
	 SOS	-1(P)			;YES TO EITHER, STOP
	POP	P,S1
	AOS	VFUSIZ			;COUNT ANOTHER VFU BYTE READ
	JRST	.POPJ1
OPN.4C:	TRNE	F,WR.L10		;/LP100 ?
	 MOVEI	S1,126			;YES, USE LP100 STOP CODE
	IDPB	S1,S2			;STORE STOP CODE

	TRNN	F,WR.8BT		;8-BIT FORMAT?
	 JRST	OPN.4E			;NO, NO SWAPPING NEEDED
	MOVE	T1,0(P)			;YES, GET POINTER TO DATA
	HRLI	T1,(POINT 16,)		;DO IT TWO BYTES AT A TIME
	PUSH	P,S1			;SAVE STOP CODE
OPN.4D:	ILDB	S1,T1			;GET NEXT BYTE PAIR
	MOVE	T2,S1			;COPY NEW BYTES
	LSH	S1,8			;SHIFT HIGH BYTE UP
	LSH	T2,-8			;SHIFT LOW BYTE DOWN
	DPB	T2,[POINT 8,S1,35]	;SO
	DPB	S1,T1			;STORE SWAPPED BYTES
	LDB	S1,[POINT 8,S1,35-8]	;GET HIGH BYTE
	CAME	S1,(P)			;SEE IF A STOP BYTE
	 JRST	OPN.4D			;NO, CONTINUE (STOP CAN'T BE LOW)
	ADJSP	P,-1			;TOSS STOP CODE

OPN.4E:	MOVS	S2,-1(P)		;GET NUMBER OF WORDS IN VFU
	HRR	S2,0(P)			;ADDRESS OF BUFFER

OPN.WF:	MOVE	S1,IFN			;GET IFN
	$CALL	F%OBUF			;WRITE THE BUFFER OUT
	JUMPT	OPN.WX			;CHECK FOR ERRORS
	ADJSP	P,1			;ADJUST STACK
	$MSG	(<?>,FOE,OPEN.E,<^E/S1/ writing ^F/FD/>)
OPN.4R:	MOVSI	S2,200			;WORDS IN A .RAM FILE
	HRRI	S2,RDATA		;WHERE IT COMES FROM
	MOVE	S1,IFN			;GET IFN
	$CALL	F%OBUF			;WRITE THE BUFFER OUT
	SKIPT				;CHECK FOR ERRORS
	$MSG	(<?>,EOR,OPEN.5,<^E/S1/ writing ^F/FD/>)
	PUSHJ	P,OPEN.5		;CLOSE THE FILE
TOPS20<
	MOVEI	S1,400			;BYTES IN FILE
	MOVEI	S2,^D18			;NORMAL BYTE-SIZE FOR TOPS-20
	PUSHJ	P,SETBSZ		;SET THE BYTE-SIZE
>
	$RET				;DONE

OPN.WX:	DMOVE	S1,-1(P)		;GET FILE MEMORY
	$CALL	M%RMEM			;GET RID OF IT
	ADJSP	P,-2			;FIX STACK
	PUSHJ	P,OPEN.5		;CLOSE THE FILE
TOPS20<
	AOS	S1,VFUSIZ		;DON'T FORGET THE START CODE
	TRNE	F,WR.8BT		;IF 8-BIT MODE
	 ASH	S1,-1			;WE WANT 16-BIT BYTES
	MOVEI	S2,^D7			;ASSUME 7-BIT FILE
	TRNE	F,WR.8BT		;BUT, IF 8-BIT MODE
	 MOVEI	S2,^D16			;USE 16-BIT BYTES
	PUSHJ	P,SETBSZ		;SET THE BYTE-SIZE
>
	$RET				;DONE

OPEN.5:	MOVE	S1,IFN			;GET IFN
	$CALL	F%REL			;RELEASE
	POPJ	P,			;AND RETURN

FILTAB:	$CALL	F%IOPN			;READ
	$CALL	F%OOPN			;WRITE
	;ROUTINES TO UPDATE FILE BYTE SIZE AND EOF POINTER
	;ENTERED WITH S1/ BYTES WRITTEN, S2/ PROPER BYTE SIZE

TOPS20<
SETBSZ:	$SAVE	<T1,T2,T3,T4>
	DMOVE	T2,S1			;SAVE THE LENGTH AND BYTE SIZE
	MOVSI	S1,(GJ%OLD!GJ%SHT)	;WE MUST FIND THE FILE AGAIN
	HRROI	S2,FD+.FDSTG		;POINT TO THE EXACT FILENAME
	GTJFN%				;GET THE FILE
	 $STOP	(FDP,<Output file ^F/FD/ has disappeared>)
	MOVE	T4,S1			;SAVE RESULT
	HRLI	S1,.FBBYV(CF%NUD)	;DON'T UPDATE DISK, UPDATE BYTE SIZE
	MOVX	S2,FB%BSZ		;CHANGE JUST THE BYTE SIZE
	STORE	T3,T1,FB%BSZ		;STORE THE NEW BYTE SIZE FOR CHFDB%
	CHFDB%				;UPDATE BYTE SIZE
	 ERJMP	CHFERR			;ERROR
	MOVE	S1,T4			;GET JFN AGAIN
	HRLI	S1,.FBSIZ		;FILE SIZE
	SETO	S2,			;ALL BITS
	MOVE	T1,T2			;CORRECT LENGTH
	CHFDB%				;UPDATE
	ERJMP	CHFERR			;OOPS
	MOVE	S1,T4			;ONCE AGAIN, OUR JFN
	RLJFN%				;GET RID OF IT
	 $STOP	(JDP,<JFN for ^F/FD/ has disappeared>)
	$RET				;DONE

CHFERR:	$STOP	(CFF,<CHFDB% JSYS failure>)
>
SUBTTL	RAM commands -- ARROW

	EXP	ARRO.H
.ARROW:	PUSHJ	P,PARCHR		;GET THE CHARACTER CODE
	JUMPF	SYNERR
	MOVEI	S2,INTBIT+"^"		;ARROW MODE TRANSLATION
	PUSHJ	P,SETRAM		;UPDATE THE RAM
	$RET

ARRO.H:	ASCIZ	|
The ARROW ch command causes the character specified by ch to be
printed as ^C, where C is the upper-case character matching ch.  

The RAM is loaded with Interrupt and the special code "^", which
causes the monitor to expand the character in up-arrow form.
|
SUBTTL	RAM commands -- CLEAR

	EXP	RCLR.H
.RMCLR:	PUSHJ	P,P$CFM##		;CONFIRM
	JUMPF	SYNERR
	SETZM	RDATA			;MAKE RAM DO NOTHING
	MOVE	S1,[XWD RDATA,RDATA+1]
	BLT	S1,RDATA+<^D256/2>	;CLEAR ENTIRE RAM
	$RET

RCLR.H:	ASCIZ	|
The CLEAR command initialized the entire RAM such that no character
will translate.

Note that MODE RAM loads in a default RAM, not a CLEAR RAM.
|
SUBTTL	RAM commands -- (CONDITIONALLY-)TRANSLATE

	EXP	DELM.H
.DELIM:	SETZ	T1,			;NO TRANSLATE
	CAIA	TRAN.H
.TRANS:	 MOVEI	T1,TRNBIT		;TRANSLATE
	PUSHJ	P,PARCHR		;GET THE CHARACTER CODE
	JUMPF	SYNERR
	MOVE	T2,S1			;SAVE CHARACTER
	PUSHJ	P,TRN0.0		;CALL PROCESSOR
	 $RETF
	$RETT

TRN0.0:	PUSHJ	P,PARCHR		;GET THE NEW CHARACTER CODE
	JUMPF	TRAN.1			;JUMP IF NONE
TRAN.0:	IOR	S1,T1			;SET TRANSLATE/DELIMITER BITS
	MOVE	S2,T2			;GET CHAR BEING TRANSLATED
	EXCH	S1,S2			;CHAR IN S1
	PUSHJ	P,SETRAM		;CHANGE RAM
	JRST	.POPJ1			;OK

	;PROBABLY A KEYWORD
TRAN.1:	$CALL	P$KEYW##		;GET THE CODE
	JUMPF	SYNERR
	PUSHJ	P,@[EXP	TRN1.D		;PREFIX-CHARACTER (DELIMITER-CHARACTER)
		    EXP	TRN1.N		;NO-ACTION
		    EXP	TRN1.S		;SLEW
		    EXP	TRN1.V](S1) 	;VFU
	JRST	SYNERR
	JRST	TRAN.0

TRN1.D:	IORI	T1,DELBIT		;SET DELIMITER BIT
	ADJSP	P,-1			;TOSS RETURN
	JRST	TRN0.0			;PROCESS POSSIBILITIES

TRN1.N:	SETZ	S1,			;NO-ACTION IS ZERO
	JRST	.POPJ1			;HAPPY

TRN1.S:	$CALL	P$NUM##			;GET THE SLEW AMOUNT
	$RETIF
	IORI	S1,PAPBIT+SLWBIT	;SAY PAPER MOTION AND SLEW
	JRST	.POPJ1			;OK

TRN1.V:	$CALL	P$NUM##			;GET THE CHANNEL NUMBER
	$RETIF
	SOJ	S1,			;MAKE CHANNELS START AT 0 FOR HW
	IORI	S1,PAPBIT		;PAPER MOTION, VFU CHANNEL
	JRST	.POPJ1			;OK
DELM.H:	ASCIZ	|
CONDITIONALLY-TRANSLATE (character code) <octal number> (to) <object>
Causes the  specified  character  to  be  translated to the specified
object only  when  preceded  by  a  PREFIX-CHARACTER.   See  the
TRANSLATE command.  When not translated, characters print as themselves.
|

TRAN.H:	ASCIZ	|
TRANSLATE (character code)  <octal  number>  (to)  <object>
Causes  the specified  character  to  be  translated to the specified object.
For conditional translation, see CONDITIONALLY-TRANSLATE.

Available objects:

PREFIX-CHARACTER (and) <other  object>
Specifies  that  this  is  a PREFIX-CHARACTER.  PREFIX-CHARACTERs
cause the FOLLOWING character to be translated.   PREFIX-CHARACTERs
themselves are translated unconditionally.  (Possibly to themselves.)
The translation for this character is specified as <other object>.
The default is NO-ACTION.

NO-ACTION
When translated, no action or printing will occur.

SLEW <decimal number> (lines)
When the character is translated, causes the printer to slew  the specified
number of lines, which must be in the range 0 to 15.

VFU-CHANNEL <decimal number>
When the character is translated, the printer advances to the next hole in
the specified channel of the vertical format tape.  Channel number must be
in the range 1 to 12.

<octal number>
When translated, the character will print as the specified code.
|
SUBTTL	RAM commands -- LIST and SHOW support

LIST.R:	$TEXT	(LSTCHR,<^M^JUser data   RAM data        RAM Flags>)
	$TEXT	(LSTCHR,<Oct ASCII   Oct ASCII^A>)
	TRNN	F,LS.BRF		;IF /BRIEF, DON'T MISLEAD
	 $TEXT	(LSTCHR,<    (See key below)^A>)
	$TEXT	(LSTCHR,<^M^J--- -----   --- -----   ----------------->)

	MOVE	T3,FILPTR		;POINT TO FILE DATA
	MOVSI	T4,-400			;ASSUME MAX LENGTH
	TRNN	F,LS.TTY		;IF FILE LISTING
	 JRST	LSTR.L			;USE MAX
	TRNN	F,LS.ALL		;IF ONLY PART WANTED
	 JRST	LSTR.P			;DO PARTIAL LISTING
	MOVEI	S1,377			;FULL LISTING
	MOVEM	S1,RAMLIM		;SO RESET WORKING RANGE
	SETZM	RAMLIM+1		;AS USER HAS SEEN WHOLE THING
	JRST	LSTR.L			;NOW GO DO IT

LSTR.P:	MOVE	T3,T1			;WHERE TO START
	ADJBP	T3,FILPTR		;BUMP TO BEGINNING
	SUBM	T1,T2			;- (END - BEGIN)
	MOVSI	T4,-1(T2)		; - ( (END - BEGIN) + 1 )
	HRR	T4,T1			;START AT BEGINNING (WHERE ELSE?)

LSTR.L:	ILDB	S1,T3			;GET NEXT BYTE
	HRRZ	S2,T4			;GET CURRENT BYTE
	PUSHJ	P,LSTR.C
	MOVE	S2,S1
	PUSHJ	P,LSTR.C
	TRNE	S1,INTBIT
	 $TEXT	(LSTCHR,<Int ^A>)
	TRNE	S1,DELBIT
	 $TEXT	(LSTCHR,<Del ^A>)
	TRNE	S1,TRNBIT
	 $TEXT	(LSTCHR,<Trn ^A>)
	TRNN	S1,PAPBIT
	 JRST	LSTR.1
	CHNMSK==17
	 TRNN	S1,SLWBIT
	SKIPA	T1,[[ITEXT (<VFU chn ^D/S1,CHNMSK/^A>)]]
	 SKIPA	T1,[[ITEXT (<Slew ^D/S1,CHNMSK/^A>)]]
	AOJ	S1,
	$TEXT	(LSTCHR,<PI ^I/(T1)/^A>)

LSTR.1:	$TEXT	(LSTCHR,<>)
	AOBJN	T4,LSTR.L
	TRNN	F,LS.BRF			;QUIET IF /BRIEF
	 $TEXT	(LSTCHR,<^T/RAMKEY/^A>)
	$RET
;ROUTINE TO LIST A CHARACTER AS OCTAL, ASCII

LSTR.C:	ANDI	S2,BYTMSK			;PITCH CONTROL BITS
	MOVE	T2,S2
	PUSH	P,S2
	ANDI	S2,CHRMSK
	CAIL	S2,40
	 SKIPA	T1,[[ITEXT	(<  ^7/S2,CHRMSK/  ^A>)]]
	MOVEI	T1,[ITEXT	(< ^^^7/S2,CHRMSK/  ^A>)]
	CAIN	S2,177
	 MOVEI	T1,[ITEXT	(< DEL ^A>)]
	CAIGE	S2,40
	 JRST	[POP P,S2
		 TRO S2,100
		 JRST .+2]
	POP	P,S2
	$TEXT	(LSTCHR,<^O3R0/T2,BYTMSK/ ^I/(T1)/   ^A>)
	$RET
RAMKEY:	ASCIZ	|
-----------------General information---------------
Characters sent to the printer are looked-up in the RAM to determine how
they are processed.  The RAM may specify that a character is to be printed,
translated to another character or action, conditionally translated, or 
ignored.

After the RAM processing occurs, a second level of processing is handled
by the controller.  <TAB> characters (011) are translated to enough spaces
to reach the next 8-column tab stop. (If past col 127, executes a LF, then
tabs to col 9.)  <NUL> characters (000) are not passed to the printer at all.
They may be used to inhibit any action.  <CR> (015), <LF> (012), and <FF> (014)
are normally translated by the RAM, but if output will cause paper motion
independent of the VFU.  Any other non-printing character will be printed
as a space.  Any non-paper motion character received in column 133 causes
a <LF> to be output first.

Character marked as "delimiters" can cause the following character to
be processed differently from the normal case.  For example, the RAM can
implement FORTRAN carriage control  See examples below.

----------------Key to flags-------------------
Int	Processor intervenes before character is printed.  If Trn is set,
	applys only if DELHLD is st. (Prefixed character)  Driver handles
	if data is 136 (^), otherwise "Undefined character interrupt".

Del	Current and following character are translated, regardless of Trn.
	See examples.  DELHLD is set for next character.

Trn	RAM data or command is sent to printer rather than input character.
	Modifies Int, PI.  DEL forces Trn action.

PI	Paper motion initiated if Trn or DELHLD also set.  Motion may
	be a slew (absolute physical advance), or VFU channel advance.

Examples:
---------
To make "1" advance to top-of-form when in column 1, but print as "1"
otherwise (eg, FORTRAN carriage control): 
	<CR>	Del no-action
	<LF>	Del no-action
	 1	PI VFU chn 1

To make <CR> advance 0 lines:
	<CR>	Trn PI Slew 0

To print all <ESC> characters as "$":
	<ESC>	Trn	(Data = 044)

To print Control/X as "^X":
	^X	Int	(Data = 136)	[Implemented in device driver]
|
SUBTTL	RAM commands -- LOWER-CASE/UPPER-CASE

	EXP	LOWR.H
.LOWER:	MOVEI	S2,TRNBIT+"@"+40	;CONVERT TO SELF
	PJRST	RAMCAS			;DO CASE

	EXP	UPPR.H
.UPPER:	MOVEI	S2,TRNBIT+"@"		;CONVERT TO UPPER CASE
	;PJRST	RAMCAS

RAMCAS:	MOVEI	S1,"@"+40		;DO ALL LOWER CASE LETTERS
	DMOVE	T1,S1			;SAVE POSITION,CONVERTED VALUE
	MOVEI	T3,177-140		;NUMBER OF CODES TO DO (140-176)
RAMCA1:	PUSHJ	P,SETRAM		;UPDATE RAM WITH NEW DATA
	AOS	S1,T1			;ADVANCE TO NEXT CHAR
	AOS	S2,T2			;ADVANCE DATA TOO
	SOJG	T3,RAMCA1		;CONTINUE FOR ALL ASCII LOWER-CASE
	$RET

LOWR.H:	ASCIZ	|
The LOWER-CASE (output) command sets the ASCII lower case codes (140 thru 
176) to translate to themselves.  Used with 96 character printers.
|

UPPR.H:	ASCIZ	|
The UPPER-CASE (output only) command sets the ASCII lower case codes (140 
thru 176) to translate to the corresponding upper case characters. Used
with 64 character printers.
|
SUBTTL	RAM commands -- NUMBER-OF-DATA-BITS

	EXP	DATB.H
.DATAB:	$CALL	P$KEYW			;GET THE KEYWORD
	JUMPF	SYNERR
	SKIPN	S1			;8?
	 TLZA	F,F.R8BT		;NO
	TLO	F,F.R8BT		;YES
	$RET
SUBTTL	RAM commands -- Utility routines

SETRAM:	CAMGE	S1,RAMLIM		;SEE IF NEW LOW
	 MOVEM	S1,RAMLIM		;IT IS
	CAMLE	S1,RAMLIM+1		;SEE IF NEW HIGH
	 MOVEM	S1,RAMLIM+1		;IT IS
	ROT	S1,-1			;COMPUTE RAM OFFSET
	SKIPL	S1			;ODD BYTE?
	 HRLM	S2,RDATA(S1)		;NO, EVEN
	SKIPGE	S1			;EVEN?
	 HRRM	S2,RDATA(S1)		;NO, ODD
	ADDI	S1,^D128/2		;POINT TO SECOND HALF
	TLNE	F,F.R8BT		;8-BIT DATA?
	 $RET				;YES, DONE
	SKIPL	S1			;NO, PUT IN HIGH HALF ALSO
	 HRLM	S2,RDATA(S1)
	SKIPGE	S1
	 HRRM	S2,RDATA(S1)
	$RET

DATB.H:	ASCIZ	|
The NUMBER-OF-DATA-BITS n command determines whether the input code is
considered to be 7 or 8 bit characters.  

When n is 7-BIT, entries made for codes 0-177 are duplicated for 200-377.

When n is 8-BIT, entries made for codes 0-177 are independent of 200-377.
|
SUBTTL	VFU commands -- CLEAR

	EXP	CLR.H
.CLEAR:	$CALL	P$CFM##			;MAKE SURE
	JUMPF	SYNERR

	TRO	F,PU.UNP		;WE UNPUNCH
	MOVEI	T3,177777		;CLEARING ALL CHANNELS
	MOVE	T1,LINSPP		;STARTING FROM THE LAST

CLR.1:	SOJL	T1,.POPJ		;DONE IF PAST LINE 0
	MOVE	S1,T1			;COPY CURRENT LINE
	PUSHJ	P,SETVFU		;CLEAR ALL CHANNELS
	JRST	CLR.1			;AND LOOP FOR ALL LINES ON PAGE

CLR.H:	ASCIZ	|
The CLEAR command clears the entire VFU so that no line is marked for any
channel.

Note that the MODE VFU command loads a default VFU, not a CLEAR VFU.
|
SUBTTL	VFU commands -- LENGTH

	EXP	LENG.H
.LENGT:	$CALL	P$NUM##			;GET THE PAGE LENGTH
	JUMPF	SYNERR			;HUH?
	CAMN	S1,LINSPP		;ANY CHANGE?
	 $RET				;NO, DON'T BOTHER
	JUMPLE	S1,SYNERR		;SANITY
	CAILE	S1,^D143		;IN RANGE
	 $MSG	(<?>,LTL,GETCMD,<Length may not exceed 143 lines>)
	EXCH	S1,LINSPP		;STORE NEW LENGTH, GET OLD
	MOVE	T1,S1			;COPY OLD
	MOVEI	T3,177777		;BITS TO CLEAR OLD STOP CODE & DATA
	TRO	F,PU.UNP		;UNPUNCH THEM
	PUSHJ	P,SETVFU		;SO
LINE.1:	AOS	S1,T1			;ADVANCE A LINE
	CAMLE	S1,LINSPP		;UP TO NEW LENGTH YET?
	 JRST	LINE.2			;YES, STOP NOW
	PUSHJ	P,SETVFU		;NO, CLEAR NEWLY ALLOCATED LINE
	JRST	LINE.1			;LOOP TILL ALL NEW LINES ARE CLEARED

LINE.2:	MOVEI	T3,357			;ADD NEW BITS
	MOVE	S1,LINSPP		;LOCATION
	CAMGE	S1,LINSLP		;IS THIS LESS THAN THE LOGICAL PAGE?
	 MOVEM	S1,LINSLP		;YES, SHORTEN LOGICAL PAGE TO LENGTH
	TRZ	F,PU.UNP		;PUNCH, THIS TIME
	PUSHJ	P,SETVFU		;SO - THE STOP CODE GETS "PUNCHED"
	$RET				;DONE

LENG.H:	ASCIZ	|
The LENGTH n command resets the page length to n lines.

N must be less than or equal to 143 lines.  

If the new length is less than the logical page size, the page size is
reduced to the new length.

If the new length is larger than the previous length, all channels are
cleared for the new lines.
|
SUBTTL	VFU commands -- LINES-PER-INCH

	EXP	LPI.H
.LINES:	$CALL	P$KEYW##		;GET THE KEYWORD
	JUMPF	SYNERR
	MOVE	S2,FILPTR		;POINT TO FILE DATA
	IDPB	S1,S2			;REPLACE THE START CODE PER DEMAND
	$RET

LPI.H:	ASCIZ	|
LINES-PER-INCH
Specifys which LPI setting is selected by the VFU.  Not all
printers support 6-LPI and 8-LPI selections.  If a VFU which selects
an unsupported LPI setting is loaded, VFU errors will result.

PRINTER-CONTROLLED works with all current printers.
	6-LPI			VFU selects 6 lines per inch
	8-LPI			VFU selects 8 lines per inch
	PRINTER-CONTROLLED	VFU accepts printer's switch or lever setting
|
SUBTTL	VFU commands -- LIST and SHOW support

	;T1/	BEGIN:
	;T2/	END:
LIST.V:	$TEXT	(LSTCHR,<>)
	TRNE	F,LS.TTY		;FOR TERMINAL, INCLUDE THESE
	 $TEXT	(LSTCHR,<Length: ^D/LINSPP/^M^JPage-size: ^D/LINSLP/>)

	MOVE	S1,FILPTR		;GET FILE POINTER
	ILDB	S1,S1			;GET START CODE
	SUBI	S1,354			;MAKE IN RANGE 0-2
	$TEXT	(LSTCHR,<VFU selects ^T/@LPITAB(S1)/^M^J>)
	TRNN	F,LS.LIN		;/BY-LINE?
	 JRST	LSTV.C			;NO, DO BY CHANNELS

	;LISTING IS /BY-LINES
	$TEXT	(LSTCHR,<Line	              Channels>)
	$TEXT	(LSTCHR,<----	----------------------------------->)

	MOVE	T3,FILPTR		;POINT TO FILE DATA
	IBP	T3			;SKIP START CODE
	MOVN	T4,LINSPP		;ASSUME MAX LENGTH
	MOVSS	T4			;AOBJN STYLE
	HRRI	T4,1			;FROM LINE 1
	TRNN	F,LS.TTY		;IF FILE LISTING
	 JRST	LSTL.1			;USE MAX
	TRNN	F,LS.ALL		;IF ONLY PART WANTED
	 JRST	LSTL.0			;DO PARTIAL LISTING
	MOVEI	S1,377			;FULL LISTING
	MOVEM	S1,RAMLIM		;SO RESET WORKING RANGE
	SETZM	RAMLIM+1		;AS USER HAS SEEN WHOLE THING
	JRST	LSTL.1			;NOW GO DO IT

LSTL.0:	CAMLE	T2,LINSPP		;BIGGER THAN PHYSICAL PAGE?
	 MOVE	T2,LINSPP		;YES, ONLY THAT MUCH

	 SKIPLE	T1			;SKIP IF TOO SMALL 
	CAMLE	T1,LINSPP		; ALSO BAD IF TOO BIG
	 MOVEI	T1,1			;USE LINE 1

	MOVE	T3,T1			;WHERE TO START
	SOJ	T3,			;MAKE 0-RELATIVE
	ASH	T3,1			;2 BYTES OF DATA PER LINE
	AOJ	T3,			;SKIP START CODE
	ADJBP	T3,FILPTR		;BUMP TO BEGINNING
	SUBM	T1,T2			;- (END - BEGIN)
	MOVSI	T4,-1(T2)		; - ( (END - BEGIN) + 1 )
	HRR	T4,T1			;START AT BEGINNING (WHERE ELSE?)
	;LOOP FOR EACH LINE
LSTL.1:	ILDB	S1,T3			;GET NEXT BYTE
	ILDB	S2,T3			;GET HIGH BYTE
	LSH	S2,6			;SHIFT HIGH CHANNELS OVER
	IOR	S1,S2			;MAKE CHANNEL MASK

	$TEXT	(LSTCHR,< ^D3 /T4,RHMASK/	^A>)

	MOVEI	T1,^D12			;NUMBER OF CHANNELS
	MOVEI	S2,1_^D12		;PRE-DECREMENTED CHANNEL MASK

	;LOOP FOR EACH CHANNEL
LSTL.2:	LSH	S2,-1			;NEXT CHANNEL
	TRNE	S1,(S2)			;IS MARK SET?
	 $TEXT	(LSTCHR,<^D2 /T1/ ^A>)	;YES, LIST CHANNEL
	TRNN	S1,(S2)			;CHECK AGAIN
	 $TEXT	(LSTCHR,<   ^A>)	;NOT SET, ALLOW SPACE
	SOJG	T1,LSTL.2		;LOOP FOR ALL CHANNELS

	HRRZ	S1,T4			;GET LINE NUMBER
	CAMN	S1,LINSLP		;LOGICAL END-OF-PAGE?
	 $TEXT	(LSTCHR,< [End of Page]^A>)
	$TEXT	(LSTCHR,<>)		;CRLF
	AOBJN	T4,LSTL.1		;LOOP FOR ALL LINES
	$RET
	;LISTING IS /BY-CHANNEL
LSTV.C:	$TEXT	(LSTCHR,<Chn	Lines>)
	$TEXT	(LSTCHR,<---	----------------------------------------------------------------------->)

	MOVE	T4,[XWD	-^D12,1]	;DO ALL CHANNELS
LSTC.2:	$TEXT	(LSTCHR,< ^D2 /T4,RHMASK/	^A>)

	MOVN	T3,LINSPP		;LINES/PHYSICAL PAGE
	MOVSS	T3
	HRRI	T3,1			;START AT LINE 1
	PUSH	P,FILPTR		;SAVE BYTE POINTER
	IBP	(P)			;SKIP START CODE

LSTC.3:	PUSH	P,[EXP	^D24]		;MAX LINES TO LIST/LINE
LSTC.4:	ILDB	S1,-1(P)		;GET LOW BYTE
	ILDB	S2,-1(P)		;AND HIGH BYTE
	LSH	S2,6			;SHIFT INTO POSITION
	IOR	S1,S2			;AND MERGE
	MOVEI	S2,1			;COMPUTE THIS CHANNEL
	LSH	S2,-1(T4)		;SLIDE MASK INTO PLACE
	TRNN	S1,(S2)			;IS THIS CHANNEL MARKED?
	 AOBJN	T3,LSTC.4		;NO, LOOP FOR ALL LINES
	JUMPGE	T3,LSTC.6		;EXIT IF NO MORE

	SOSL	(P)			;SPACE LEFT ON THIS LINE?
	 JRST	LSTC.5			;YES, CONTINUE
	$TEXT	(LSTCHR,<^M^J	^A>)	;NO, START A NEW LINE
	ADJSP	P,-1			;TOSS OLD COUNT
	XCT	LSTC.3			;START A NEW ONE
	SOS	(P)			;AND ACCOUNT FOR THIS LINE

LSTC.5:	$TEXT	(LSTCHR,<^D2 /T3,RHMASK/ ^A>)	;YES, LIST THIS LINE
	AOBJN	T3,LSTC.4		;LOOP FOR NEXT LINE

LSTC.6:	ADJSP	P,-2			;TOSS STACKED BP
	$TEXT	(LSTCHR,<>)		;NEW LINE
	AOBJN	T4,LSTC.2		;NEXT CHANNEL
	$RET


	;LPI labels
LPITAB:	[ASCIZ	/6-LPI/]
	[ASCIZ	/8-LPI/]
	[ASCIZ	/Printer-controlled LPI/]
SUBTTL	VFU commands -- (UN-)PUNCH

	EXP	UNPU.H
.UNPUN:	TROA	F,PU.UNP		;SET UNPUNCH
	 EXP	CHAN.H
.CHANN:	$CALL	P$NUM##			;PARSE THE CHANNEL NUMBER
	JUMPF	SYNERR
	SOS	T4,S1			;SAVE IT - IN INTERNAL FORM
	MOVEI	T3,1			;CHANNEL BIT
	CAILE	T4,5			;IF IN A HIGH BYTE
	 ADDI	S1,2			;SKIP UNUSED BITS
	LSH	T3,(S1)			;KEEP A BIT MASK FOR THE DATA

	$CALL	P$KEYW##		;PARSE THE KEYWORD
	JUMPF	SYNERR
	JRST	@[EXP	CHAN.A		;ALL
		  EXP	CHAN.B		;BOTTOM
		  EXP	CHAN.E		;EVERY
		  EXP	CHAN.F		;FORMS-BREAK (lines)
		  EXP	CHAN.L		;LINES
		  EXP	CHAN.T		;TOP
		 ](S1)			;DISPATCH ON KEYWORD CODE

	;CHANNEL N ALL
CHAN.A:	MOVE	T2,LINSLP		;LINES PER LOGICAL PAGE
CHNA.1:	SOJL	T2,.POPJ		;NEXT LINE TO SET
	MOVE	S1,T2			;LINE TO SET
	PUSHJ	P,SETVFU		;SET CHANNEL FOR CURRENT LINE
	JRST	CHNA.1

	;BOTTOM
CHAN.B:	MOVE	S1,LINSLP		;PUT MARK AT BOTTOM
	SOJA	S1,SETVFU		;MAKE 0-BASED, SET BIT, AND RETURN

	;EVERY N
CHAN.E:	$CALL	P$NUM##			;GET STEP SIZE
	JUMPF	SYNERR
	MOVE	T2,S1			;SAVE STEP SIZE

	SETZ	T1,			;START ON LINE 0
CHNE.1:	MOVE	S1,T1			;GET CURRENT LINE
	PUSHJ	P,SETVFU		;SET IN VFU
	ADD	T1,T2			;ADD STEP SIZE
	CAMGE	T1,LINSLP		;OFF LOGICAL PAGE?
	 JRST	CHNE.1			;NOT YET
	$RET
	;FORMS-BREAK
CHAN.F:	MOVE	T1,LINSLP		;GET FIRST LINE OF FORMS-BREAK AREA
CHNF.1:	CAML	T1,LINSPP		;IF AT OR PAST PHYSICAL PAGE
	 $RET				;DONE
	MOVE	S1,T1			;MORE TO DO, COPY CURRENT LINE
	PUSHJ	P,SETVFU		;SET IN VFU
	AOJA	T1,CHNF.1		;NOW CONTINUE WITH NEXT LINE

	;LINES N,M,...
CHAN.L:	$CALL	P$NUM##			;GET LINE NUMBER
	 JUMPF	CHNL.X			;NONE, MUST BE CONFIRM
CHNL.1:	SOJ	S1,			;MAKE LINES START AT ZERO
	PUSHJ	P,SETVFU		;SET STOP FOR SPECIFIED LINE

	$CALL	P$COMM##		;PARSE A POSSIBLE COMMA
	JUMPF	CHNL.X			;IF NOT, MUST BE CONFIRM
	$CALL	P$NUM##			;COMMA, LINE NUMBER MUST FOLLOW
	JUMPT	CHNL.1			;GO PROCESS THIS NUMBER
	$MSG	(<%>,TCI,,<Trailing comma ignored>)

CHNL.X:	$CALL	P$CFM##			;CONFIRM
	$RETIT				;RETURN IF OK
	$MSG	(<%>,JEL,,<Junk at end of line ignored>)
	$RET

	;TOP-OF-FORM
CHAN.T:	SETZ	S1,			;LINE TO MARK
	PJRST	SETVFU			;SET AND RETURN

CHAN.H:	ASCIZ	|
PUNCH	(channel) vfu-channel arg
Specifies line or lines on which a channel will stop.
Arg may be one of:
	ALL-LINES	Mark all lines on the logical page
	BOTTOM-OF-FORM	Mark last line on the logical page
	EVERY n		Mark every nth line on the logical page from line 1
	FORMS-BREAK	Un-mark the forms-break area
	LINES n,m,...	Mark the specified lines
	TOP-OF-FORM	Mark the first line on the page
|

UNPU.H:	ASCIZ	|
UN-PUNCH (channel) vfu-channel arg
Specifies line or lines on which a channel will no longer stop.
Arg may be one of:
	ALL-LINES	Un-mark all lines on the logical page
	BOTTOM-OF-FORM	Un-mark last line on the logical page
	EVERY n		Un-mark every nth line on the logical page from line 1
	FORMS-BREAK	Un-mark the forms-break area
	LINES n,m,...	Un-mark the specified lines
	TOP-OF-FORM	Un-mark the first line on the page
|
SUBTTL	VFU commands -- PAGE-SIZE

	EXP	PAGS.H
.PAGES:	PUSHJ	P,P$NUM##		;GET THE PAGESIZE
	JUMPF	SYNERR			;HUH?
	JUMPLE	S1,SYNERR		;SILLY PEOPLE GET SILLY MESSAGE
	CAMLE	S1,LINSPP		;BETTER BE LESS THAN PHYSICAL PAGE
	 $MSG	(<?>,PTB,GETCMD,<Pagesize ^D/S1/ exceeds length ^D/LINSPP/>)
	MOVEM	S1,LINSLP		;OK, CHANGE IT
	$RET

PAGS.H:	ASCIZ	|
The PAGE-SIZE n command sets the length of a logical page to n lines.  N must
be less than or equal to the form length. (See the LENGTH command.)  

The logical page size determines how many lines commands such as PUNCH EVERY
and PUNCH ALL will effect.  

Lines beyond the logical page size may be punched with PUNCH LINE, or
FORMS-BREAK.

The logical page size is defined for your convenience in entering commands
only; it has no direct meaning to the line-printer controller and is
not recorded in the VFU file.
|
SUBTTL	VFU commands -- Utility routines

	;ENTER WITH LINE # IN S1, BITS TO TURN ON IN T3
SETVFU:	LSH	S1,1			;2 BYTES/VFU LINE
	AOJ	S1,			;SKIP START BYTE
	ADJBP	S1,FILPTR		;POINT TO FIRST BYTE OF LINE
	ILDB	S2,S1			;GET BYTE
	PUSH	P,S1
	PUSH	P,S2			;SAVE LOW BYTE
	ILDB	S2,S1			;HIGH BYTE
	LSH	S2,8
	IOR	S2,(P)			;COMBINE
	TRNN	F,PU.UNP		;PUNCH?
	 TRO	S2,(T3)			;YES, SET USER'S BITS
	TRNE	F,PU.UNP		;UN-PUNCH?
	 TRZ	S2,(T3)			;YES, CLEAR USER'S BITS
	MOVEM	S2,(P)			;SAVE A COPY
	LSH	S2,-8
	DPB	S2,S1			;PUT HIGH BYTE BACK
	POP	P,S2			;GET LOW BYTE
	POP	P,S1			;POINTER
	DPB	S2,S1			;STORE THAT
	$RET
SUBTTL	Parser interface -- Argument fetchers

	;RETURN A CHARACTER CODE FROM A QUOTED STRING OR AN INTEGER
PARCHR:	PUSHJ	P,P$NUM##		;FETCH A NUMBER
	$RETIT				;DONE IF GOT ONE
	PUSHJ	P,P$QSTR##		;NOPE, TRY A QUOTED STRING
	$RETIF				;NOPE, WE LOSE
	LDB	S1,[POINT 7,CR.RES(S1),6] ;OK, GET FIRST CHARACTER
	$RETT				;LET THAT BE THE DATA
SUBTTL	Default RAM data

DEFINE RAMWRD (TYPE,DATUM) <
	IFE TYPE-OTHER,<
		..T==TRNBIT+DATUM ;;TRANSLATE TO OTHER
		>
	IFE TYPE-ARROW,<
		..T==INTBIT+"^"	;;FORM DATUM WORD
		>		;;END OF ARROW TRANSLATION

	IFE TYPE-SELF,<
		..T==TRNBIT+BYTE ;;TRANSLATE TO SELF
		>

	IFE TYPE-PAPER,<
		..T==VFUBIT+<DATUM-1> ;;PAPER MOTION
		>

	IFE TYPE-DEL,<
		..T==DELBIT	;;DELIMITER
		>
	IFE TYPE-IGNORE,<
		..T==TRNBIT+0	;;SEND NON-PRINTING CHARACTER
		>
	IFE TYPE-IMAGE,<
		..T==DATUM	;;PROVIDE BINARY QUANTITY
		>

	IFE BYTE&1,< .T==..T>
	IFN BYTE&1,< XWD .T,..T>;;GENERATE WORD
	BYTE==BYTE+1		;;NEXT BYTE
>				;;END OF MACRO

	;DEFINITIONS FOR THE ABOVE MACRO

	PAPBIT==1B27		;PAPER MOTION BIT
	TRNBIT==1B26		;TRANSLATE BIT
	DELBIT==1B25		;DELIMITER BIT
	INTBIT==1B24		;INTERRUPT BIT 
	VFUBIT==PAPBIT+TRNBIT	;VFU OR SLEW TRANSLATION
	SLWBIT==1B31		;SLEW, NOT VFU CHANNEL

	ARROW==0		;ARROW MODE
	SELF==1			;TRANSLATE TO SELF
	PAPER==2		;PAPER MOTION CHARACTER
	DEL==3			;DELIMITER
	OTHER==4		;TRANSLATE TO A PARTICULAR CODE
	IGNORE==5		;IGNORE THIS CODE
	IMAGE==6		;DATUM IS FULL DESCRIPTION

	BYTE==200		;IT MAY SEEM STRANGE, BUT MAKRAM HAD THIS BUG
				;AND WE WANT THE DEFAULT RAM TO BE COMPATIBLE,
				;NOT RIGHT. (!)
DEFRAM:	RAMWRD SELF		;NULL GOES TO SELF
	REPEAT ^D8,<RAMWRD ARROW> ;1-10 IS ARROW MODE
	RAMWRD SELF		;TAB GOES TO SELF
	RAMWRD PAPER,^D8	;LF IS VERT MOTION
	RAMWRD PAPER,7		;VT IS CHANNEL 7
	RAMWRD PAPER,1		;FF IS TOP OF FORM
	RAMWRD PAPER,SLWBIT+1	;SPACE 0 LINES
	REPEAT 2,<RAMWRD ARROW> ;16-17 ARROW TRANSLATION
	RAMWRD PAPER,2		;20 VFU CH 2
	RAMWRD PAPER,3		;21 VFU CH 3
	RAMWRD PAPER,4		;22 VFU CH 4
	RAMWRD PAPER,5		;23 VFU CH 5
	RAMWRD PAPER,6		;24 VFU CH 6
	REPEAT 6,<RAMWRD ARROW>	;25-32 ARROW MODE
	RAMWRD OTHER,"$"	;33 PRINTS AS $
	REPEAT 4,<RAMWRD ARROW>	;34-37 ARROW MODE
	REPEAT 177-40,<
	   RAMWRD SELF>		;ALL REST GO TO SELF
	RAMWRD IGNORE		;EXCEPT DELETE, WHO HAD NONE!!!!
	DEFRLN==.-DEFRAM
SUBTTL	Macros for generating default VFU data

; THE FOLLOWING MACROS ARE USED TO GENERATE VFUBUF, WHICH CONTAINS
; THE DEFAULT VFU DATA TO BE LOADED. 

DEFINE MOD(A,B),<A-<<A/B>*B>>		;TAKE A MODULO B

; MACRO OUTBYT - USED TO GENERATE A STREAM OF 8-BIT BYTES. CALLED EACH TIME
; A BYTE NEEDS OUTPUTING. ASSEMBLES 4 8-BIT BYTES AND THEN OUTPUTS A
; EXP PSEUDO-OP.

DEFINE OUTBYT(B),<
	..BP==..BP+8			;;BUMP THE POSITION POINTER BY BYTE SIZE
	B==<B&377>_<^D35-..BP>		;;MAKE SURE ONLY 8 BITS WIDE AND THEN
					;;SHIFT TO PROPER POSITION IN CURRENT WORD
	..B==..B!B			;;PUT BYTE INTO ACCUMULATOR
	IFE ..BP-^D31,<			;;IF WE'RE AT THE LAST BYTE IN CURRENT WORD
		..BP==-1		;;RESET POSITION POINTER TO BEGINNING
	EXP	..B			;;ASSEMBLE THE WORD
		..B=0			;;CLEAR OUT THE ACCUMULATOR
	>;END IFE
>;END DEFINE

; MACRO LASBYT - MUST BE CALLED AFTER ANY USAGE OF OUTBYT MACRO TO ENSURE
; THAT THE LAST BYTE(S) GET OUTPUT.

DEFINE LASBYT,<
	IFN ..BP+1,<			;;IF THERE IS SOMETHING LEFT IN THE ACCUMUALTOR
	EXP	..B			;; ASSEMBLE IT
	>;END IFN
>;END DEFINE
; MACRO VFUBIT - CALLED TO OUTPUT TWO BYTES OF DATA FOR A PARTICULAR
; LINE NUMBER IN THE VFU. GENERATES CHANNEL BIT SETTINGS FOR
; A STANDARD VFU TAPE.

DEFINE VFUBIT(LINE),<
	..BT==0				;;ZERO THE BIT ACCUMULATOR
					;;DO 1ST BYTE - CHANNELS 1-6
	IFE LINE,<..BT==..BT!1>		;;LINE 0 GETS CHANNEL 1 (TOP OF FORM)
	IFE MOD(LINE,36),<..BT==..BT!2>	;;EVERY 30 LINES GETS CHANNEL 2
	IFE MOD(LINE,2),<..BT==..BT!4>	;;EVEN NUMBERED LINES GET CHANNEL 3
	IFE MOD(LINE,3),<..BT==..BT!10>	;;EVERY 3RD LINE GETS CHANNEL 4
	IFE MOD(LINE,12),<..BT==..BT!40>;;EVERY TEN LINES GETS CHANNEL 6
	IFLE LINE-^D59,<..BT==..BT!20>	;;ALL LINES GET CHANNEL 5
	IFGE LINE-^D60,<..BT==20>	;;LINES 60-65 GET ONLY CHANNEL 5
	OUTBYT(..BT)			;;OUTPUT THIS BYTE
					;;DO 2ND BYTE - CHANNELS 7-12
	..BT==0				;;ZERO THE BIT ACCUMULATOR
	IFE MOD(LINE,24),<..BT==..BT!1>	;;EVERY 20 LINES GET CHANNEL 7
	IFLE LINE-^D59,<..BT==..BT!2>	;;LINES 0-59 GET CHANNEL 8
TOPS10<
	IFE LINE-^D59,<..BT==..BT!40>	;;LINE 59 GETS CHANNEL 12
	IFGE LINE-^D60,<..BT==0>	;;LINES 60-65 GET NOTHING
>
TOPS20<	;;DON'T ASK WHY, BUT TOPS-20 PUTS BOF ON FIRST LINE OF FORMS BREAK AREA

	IFE LINE-^D60,<..BT==40>	;;LINE 60 GETS CHANNEL 12
	IFGE LINE-^D61,<..BT==0>	;;LINES 61-65 GET NOTHING
>
	OUTBYT(..BT)			;;OUTPUT THIS BYTE
>;END DEFINE
SUBTTL	Default VFU data buffer

	..BP==-1			;INITIALIZE POSITION FOR FIRST BYTE
	..B==0				;INITIALIZE BYTE ACCUMULATOR

	..L==0				;INITIALIZE LINE COUNTER
	STARTC==356			;DEFINE START CODE
	STOPC==357			;DEFINE STOP CODE

DEFVFU:
	OUTBYT(STARTC)			;OUTPUT THE START CODE
REPEAT ^D66,<				;66 LINES/PAGE
	VFUBIT(..L)			;DO BYTES FOR THIS LINE
	..L==..L+1			;BUMP LINE COUNTER
>;END REPEAT
	OUTBYT(STOPC)			;OUTPUT THE STOP CODE
	LASBYT				;FINISH UP
	DEFVLN==.-DEFVFU
SUBTTL	Error routines


ERRMSG:	MOVEM	0,ERRACS+0		;SAVE AC 0
	MOVE	0,[1,,ERRACS+1]		;SET UP BLT
	BLT	0,ERRACS+17		;SAVE ALL ACS
	MOVE	S1,[POINT 7,ERRSTR]	 ;BYTE POINTER TO STORAGE
	MOVEM	S1,ERRPTR		;SAVE
	POP	P,S1			;GET ADDRESS OF ARGUMENTS
	POP	P,ERRRET		;RETRIEVE RETURN ADDRESS
	MOVE	S2,0(S1)		;GET SEVERITY,,PREFIX
	MOVEM	S2,ERRPFX		;STORE
	MOVE	S2,1(S1)		;GET ADDRESS OF ITEXT BLOCK
	HRRZM	S2,ERRITX		;SAVE IT
	TLNE	S2,-1			;SPECIAL RETURN ADDRESS GIVEN?
	HLRZM	S2,ERRRET		;YES--OVERWRITE DEFAULT
	DMOVE	S1,ERRACS+S1		;RESTORE S1 AND S2
	$TEXT	(ERROUT,<^I/@ERRITX/^0>) ;STORE TEXT
	PUSHJ	P,@TYOADR		;CALL TYPEOUT ROUTINE
	MOVE	0,[ERRACS+1,,1]		;SET UP BLT
	BLT	0,16			;RESTORE ACS 1-16
	MOVE	0,ERRACS+0		;RESTORE AC 0
	PJRST	@ERRRET			;RETURN

ERROUT:	IDPB	S1,ERRPTR		;STORE CHARACTER
	POPJ	P,			;NO--RETURN
SUBTTL	Impure storage

Z.BEG:!					;BEGINING OF DATA STORAGE

PDL:	BLOCK	PDLSIZ			;SUBROUTINE CALL STACK
ERRACS:	BLOCK	20			;ERROR PROCESSOR - AC STORAGE
ERRRET:	BLOCK	1			;ERROR PROCESSOR - RETURN ADDRESS
ERRITX: BLOCK	1			;ERROR PROCESSOR - ITEXT BLOCK ADDRESS
ERRPTR:	BLOCK	1			;ERROR PROCESSOR - BYTE POINTER
ERRPFX:	BLOCK	1			;ERROR PROCESSOR - PREFIX
ERRSTR:	BLOCK	<^D132+5>/5
TYOADR:	BLOCK	1
FD:	BLOCK	FDXSIZ			;READ/WRITE FD
IFN:	BLOCK	1			;READ/WRITE IFN
LSTIFN:	BLOCK	1
FILEFD:	BLOCK	FDXSIZ
CMDBLK:	BLOCK	PAGSIZ			;COMMAND PARSER PAGE
CMDMOD:	BLOCK	1			;COMMAND MODE: 0 NONE/-1 RAM/1 VFU
RDATA:	BLOCK	<MAXFIL==<400/2>>	;SPACE FOR 256 CHAR RAM AND MAX VFU
VFUSIZ:	BLOCK	1			;NUMBER OF VFU DATA BYTES READ
LINSLP:	BLOCK	1			;LINES PER LOGICAL PAGE
LINSPP:	BLOCK	1			;LINES PER PHYSICAL PAGE
TXTFLG:	BLOCK	1			;COPY OF F FOR USE IN $TEXT RTNS
					;CHANGES MADE TO F MUST APPEAR HERE
					;FOR $TEXT ROUTINES TO SEE THEM
RAMLIM:	BLOCK	2			;LIMITS OF USER-TOUCHED RAM

;****
FILPTR:	BLOCK	1			;BYTE POINTER TO FILE
FILCTR:	BLOCK	1			;BYTES/WORD FOR FILE
;****

Z.END:!				;END OF DATA STORAGE

	END	START