Google
 

Trailing-Edge - PDP-10 Archives - BB-H241B-BM - decnet/daplib.mac
There are 14 other files named daplib.mac in the archive. Click here to see a list.
TITLE	DAPLIB	Dap routines for TOPS20 DECNET
SUBTTL	D. Oran - P.J. Taylor 9-Nov-79

;
;
;
;	    COPYRIGHT (c) 1978,1979 BY
;           DIGITAL EQUIPMENT CORPORATION, MAYNARD, MA.
;
;     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			;Get Galaxy symbols
	PROLOG	(DAPLIB)		;Declare our name

	SEARCH	QSRMAC			;Get symbols for submit/print
	SEARCH	DAPSYM			;Get DAP symbols

	SALL				;SUPPRESS FULL EXPANSION

;Version Information

	DAPVER==2			;MAJOR VERSION OF DAP20
	DAPMIN==0			;MINOR VERSION OF DAP20
	DAPEDT==54			;EDIT LEVEL
	DAPWHO==0			;WHO LAST EDITED

	GLOB	DAPEDT			;Make edit number global

	VDAP20==VRSN.(DAP)		;GET THE VERSION LEVEL
SUBTTL	Table	of contents

;               TABLE OF CONTENTS FOR DAPLIB
;
;
;                        SECTION                                   PAGE
;    1. D. Oran - P.J. Taylor 9-Nov-79............................   1
;    2. Table   of contents.......................................   2
;    3. Revision        History...................................   3
;    4. IMPURE storage............................................   5
;    5. STORAGE allocated per logical link........................   6
;    6. DAP message descriptor blocks.............................  10
;    7. DAP message argument types and processor table............  11
;    8. Local macro definitions...................................  12
;    9. $DEBUG  Macro to display debugging message................  13
;   10. DEBUG and TYPER output routines...........................  14
;   11. $GODAP  Macro to establish DAPLIB context.................  15
;   12. D$INIT  Daplib initialization.............................  16
;   13. D$OPEN  Establish a logical link..........................  17
;   14. D$INTR  Interrupt processing routines.....................  18
;   15. D$CLOS  Routine to close logical link.....................  18
;   16. D$STAT  Display link status...............................  18
;   17. D$FUNC  Daplib routine to perform a File function.........  19
;   18. SRVMSG  Server initialization and tables..................  20
;   19. Server state initialization routines......................  21
;   20. SRVMSG  Server message processing loop....................  22
;   21. SRVCFI  Server routine to process Initial config message..  23
;   22. SRVCFG  Server routine to Process Config message..........  23
;   23. SRVACC  Server routine to process an ACCESS message.......  23
;   24. SRVOPN  Server routine to process ACCESS (Open)...........  24
;   25. SRVCRE  Server routine to process ACCESS (Create).........  26
;   26. SRVDEL  Server routine to process Delete requests.........  27
;   27. SRVEXE  Server routine to process submit requests.........  28
;   28. SRVDIR  Server routine to process Directory requests......  29
;   29. SRVCTL  Server routine to process a CONTROL message.......  30
;   30. FILGET  Server routine to send data messages..............  31
;   31. SRVACP  Server routine to process Access complete message.  32
;   32. ENABLE/DISABL Routine to set or clear capabilities for server  33
;   33. HOOVER  Routine to validate a users access to a file......  34
;   34. SUBMIT  Routine to Make submit request to QUASAR..........  36
;   35. SNDQSR  Routine to send message to quasar.................  37
;   36. DAPDCN  Active Task function dispatch.....................  38
;   37. Active Task message and State tables......................  39
;   38. Active Task state initialization routines.................  40
;   39. DCNMSG  Active Task message processing routine............  41
;   40. DCNCFG  Routine to process Config message.................  42
;   41. DCNNAM  Routine to process Name message...................  43
;   42. ATTACK  Routine to process ACK for Attributes message.....  43
;   43. CTLACK  Routine to process ACK for Control message........  43
;   44. DCNACP  Routine to process Accomp (Resp)..................  43
;   45. DCNSTS  Routine to process Status message.................  43
;   46. DCNATR  Routine to call user with received attributes.....  43
;   47. DCNREC  Active Task routine to receive a file.............  44
;   48. DCNTYP  Active task to type remote files..................  45
;   49. DCNSND  Active task to send files.........................  46
;   50. DCNDEL  ACTIVE TASK TO DELETE A FILE......................  47
;   51. DCNEXE  ACTIVE TASK TO EXECUTE A FILE.....................  47
;   52. DCNDIR  Active Task routine to process Directory request..  48
;   53. DCN     Unimplimented functions...........................  49
;   54. VALCFG  Validate contents of a CONFIG message.............  50
;   55. VALATT  Validate contents of an ATTRIBUTES message........  51
;   56. VALDTI  Validate the contents of DATE/TIME attributes extention  52
;   57. VALPRO  Validate the contents of protection attributes message  53
;   58. VALNAM  Validate the contents of a NAME message...........  54
;   59. VALCRC  Routine to validate the CRC.......................  54
;   60. SNDCFG  Send CONFIG message...............................  55
;   61. SNDACC  Send an ACCESS message............................  56
;   62. SNDCTC  Send a CONTROL (CONNECT) message..................  56
;   63. SNDCTR  Send a CONTROL (GET) message......................  57
;   64. SNDCTS  Send a CONTROL (PUT) message......................  57
;   65. SNDACK  Send and ACKNOWLEDGE message......................  58
;   66. SNDEOF  Send an EOF status message........................  58
;   67. SNDSTS  Routine to send a status message..................  58
;   68. SNDACP  Send an ACCOMP (CLOSE) message....................  58
;   69. SNDACA  Send an Accomp (Resp) message.....................  58
;   70. SNDWLD  Routine to send required name messages per WLDJFN.  59
;   71. SNDDSP  Send requested ATTRIBUTES messages................  60
;   72. SNDATT  Send an attributes message........................  61
;   73. SNDPRO  Send File Protection Attributes...................  62
;   74. SNDDTI  Send Date/time attributes.........................  62
;   75. SNDNAM  Send a Name message...............................  62
;   76. MSGTBL  List of valid DAP messages........................  63
;   77. GETMSG  Routine to get next DAP message from Link.........  64
;   78. VALHDR  Routine to validate standard dap message header...  65
;   79. NEWHDR  Routine to create a new header only...............  65
;   80. VALMSG  Routine to parse current DAP message..............  66
;   81. CLRMSG  Routine to clear DAP message storage..............  67
;   82. GETFIX  Routine to process DAP byte arguments.............  68
;   83. GETVAR  Routine to process DAP variable length arguments..  69
;   84. GETINT  Routine to process DAP integer arguments..........  70
;   85. GETPRO  Routine to get Protection field from DAP message..  71
;   86. GETEXF  Routine to process DAP extensible fields..........  72
;   87. GETMNU  Routine to process DAP extensible menu fields.....  72
;   88. GETDTI  Routine to process Date/time field in DAP message.  73
;   89. GETDAT  Routine to process DATA field from DAP message....  74
;   90. GETASC  Routine to process ascii data in message..........  75
;   91. TSTPRN  Routine to do final linefeed for print files......  75
;   92. GETPRN  Routine to process print file format (vax)........  76
;   93. GETFTN  Routine to process fortran file format (vax)......  77
;   94. GETPAG  Routine to get a file page from DAP message.......  78
;   95. GETIMG  Routine to process image bit stream in data message  79
;   96. GETBCT  Routine to return bitstream from DAP message......  80
;   97. GETDOS  Routine to store MACY11 variable length files.....  81
;   98. PUTMSG  Routine to build and force a message out..........  82
;   99. SNDQUE  Routine to send all messages in the send queue....  82
;  100. QUEMSG  Routine to block current message if possible......  83
;  101. BLDMSG  Routine to build a DAP message....................  84
;  102. BLDHDR  Routine to build header for current message.......  85
;  103. PUTFIX  Routine to store 1 to 4 BYTE fields in DAP message  86
;  104. PUTBYT  Routine to store a character in current message...  86
;  105. PUTERR  Routine to die on invalid argument................  86
;  106. PUTVAR  Routine to store a variable length field in DAP message  87
;  107. PUTINT  Routine to store variable length integer..........  88
;  108. PUTPRO  Routine to store DAP protection argument..........  89
;  109. PUTEXF  Routine to store extensible field in Dap message..  90
;  110. PUTMNU  Routine to store DAP extensible fields............  90
;  111. PUTDTI  Routine to store date time field in DAP message...  91
;  112. PUTDAT  Routine to store Data field in DAP message........  92
;  113. DOCRC   Routine to update cumulative CRC for data messages  93
;  114. CRCTAB  CRC TABLE DEFINITION..............................  94
;  115. PUTASC  ROUTINE TO READ ASCII DATA AND FORMAT AN OUTPUT DAP MESSAGE  95
;  116. PUTPAG  Routine to store file page in DAP message.........  96
;  117. PUTIMG  Routine to store n-bit bytes in data message......  97
;  118. PUTBCT  Store image bit stream in DAP message.............  99
;  119. PUTDOS  Process MACY11 assembler output................... 100
;  120. SETINP  Setup for local file input........................ 101
;  121. SETOUT  Setup for local file output....................... 102
;  122. OPNFIL  Routine to open the local file.................... 102
;  123. CLSFIL  Routine to close local file and update FDB........ 103
;  124. CLSINP  Routine to close input file....................... 104
;  125. DELFIL  Routine to delete the local file.................. 104
;  126. ABTFIL  Routine to abort local file operation............. 104
;  127. CHNGFD  Routine to change a field in output files FDB..... 104
;  128. EOFCHK  Routine to check for EOF in local file............ 105
;  129. INPBYT  Routine to read a byte from file.................. 105
;  130. OUTBYT  Routine to write a byte to file................... 106
;  131. GETFDB  Routine to read local file FDB and other info..... 107
;  132. GETDEV  Routine to get device attributes.................. 108
;  133. SETATT  Set attributes from swithces...................... 109
;  134. SWLOOK  Lookup user switches and convert to DAP attriubtes 110
;  135. ATLOOK  Routine to lookup attributes...................... 112
;  136. Attributes list........................................... 113
;  137. FILE EXTENTION DEFAULT TABLE.............................. 114
;  138. SETMOD  Routine to setup processor address and bytesizes.. 115
;  139. TYPSTS  Routine to expand DAP status codes................ 116
;  140. TYPDVR  ROUTINE TO TYPE OUT DAP VERSION MESSAGE........... 117
;  141. TERCVT  Routine to convert TOPS20 error code to dap status 117
;  142. LLGJFN  Routine to get JFN for logical link............... 118
;  143. LLGJFN  Get a JFN for logical link........................ 118
;  144. QSOUT   move asciz string and quote if required........... 119
;  145. LLOPEN  Routine to OPEN logical link...................... 120
;  146. LLWCON  ROUTINE TO WAIT FOR LINK TO BE CONNECTED.......... 121
;  147. LLCHK   Routine to check logical link status.............. 122
;  148. LLCLOS  Routine to close or abort a logical link.......... 123
;  149. LLRCD   Read Connect-initiate Disconnect initiate data.... 124
;  150. LLRCD   ROUTINE TO READ INFORMATION FROM CI/DI MESSAGES... 124
SUBTTL	Revision	History

COMMENT \

Edit	Comment

0020	First field test of DAPLIB
0021	Fix Daplib to default to Image mode if remote node is TOPS20
0022	Fix Daplib to Store output files DTI and PRO message info
0023	Fix bugs in blocked recieve code and SNDATT to allow ascii
	transfers to/from RSX11
0024	Move Free <CRLF> for TTY output to DCNREC instead of OPNFIL
0025	Default directory name and extention to *.* for server.
	Move Date/time info received from attributes into FDB
	for directory function.
0026	Fixed a bug in SNDWLD that caused error in directory if
	Filespec was not wild.
0027	Only do MTOPR and SIBE when required.  Globalaize Status flags.
0030	Check for Device type DSK before updating FDB
0031	Impliment TYPE routine for DCN
	Add wild logic to SRVOPN
0032	Remove code for unsupported message types
0033	Add blocking code to send logic and fix various bugs
0034	Fix bugs in send blocking code
0035	Redefined extensible field bits to begin with bit 35
	and change GETEXF and PUTEXF to automatically lite the
	extension bit when required.  Effectively extend the
	precesion for extensible fields to 70 information bits
	(or 10 bytes)

0036	Defined message types via macros in DAPSYM and invoked
	macros to declare local storage

0037	Further bugging for VAX communication

0040	Bug fixes for TYPE command and FAL

0041	Remove SY$APP from SYSCAP field since it's not supported

0042	Change GETINT to accept up to 9 byte integer fields

0043	Remove SY$RSS and SY$RSR from SYSCAP and add SY$CRC
	and appropriate support code to generate and validate
	CRC's

0044	Remedy several bugs to allow FAL to speak to VAX

0045	Disable capabilities upon reciept of CTL (PUT) to allow
	overquota errors to occur.  Also CRC changes.

0046	Add page mode transfer code so "holy" files may be transferred
	between TOPS20 nodes

0047	Don't copy file protection attribute when creating files.  This
	will cause the directory default protection to be followed if
	no protection is specified.  Also, don't update reference counts

0050	Fix a bug in PUTASC which caused CRC error on 36 bit files when
	transferred in ASCII mode.

0051	Fix an interrupt race which causes NFT and FAL to occasionally hang

0052	Add check to FAL to determine if directory is large enough to write
	file before file is created.

0053	Fix several problems for speaking to RSTS Dap 4.0

0054	Fix problem causing invalid ATTEBK and remove code to support pre
	5.3 FAL for TOPS20

\ ;end revision history
; ACCUMULATOR DEFINITIONS

	S==13				;Global link Status AC

	  S%ERR==1B11			;Error status sent or received
	  S%INIT==1B12			;State has just changed
	  S%RETN==1B13			;Return to caller flag for DCN
	  S%PUT==1B14			;Data ouptut
	  S%GET==1B15			;Data input
	  S%EOF==1B16			;EOF seen
	  S%ACP==1B17			;Access complete

	  S%STAT==777777B35		;Link state
	    .LLCFG==0			;Awaiting Config
	    .LLACC==1			;Awaiting Attributes or Access
	    .LLATT==2			;Awaiting Ext Attr or Access
	    .LLCTL==3			;Awaiting Control or Accomp
	    .LLDAT==4			;Awaiting Data or Accomp
	    .LLACP==5			;Awaiting Accomp


	CP==14				;Holds link data page address
	DL==15				;Address of current msg header
	AP==16				;Address of callers arguments

;CONSTANTS FOR COMPILATION

	DEFPRO==775200			;Default file protection

	FP%SLF==77B23			;Owner protection mask
	FP%GRP==77B29			;Group protection mask
	FP%WLD==77B35			;Wild protection mask
	FP%ALL==777777B35		;All protection fields

	FFSPEC==<FLD(1,JS%DEV)+FLD(1,JS%DIR)+FLD(1,JS%NAM)+FLD(1,JS%TYP)+FLD(1,JS%GEN)+JS%PAF>

	ND	NETTMZ,0		;Network time zone (Not implimented)
	ND	OURKON,25256		;Hours constant worth of bits

	ND	CCTIME,5		;Wait time for Connect confirm
	ND	MAXLNK,1		;Maximum number of logical links
	ND	DPMXM,^D512/2*^D9+^D100	;Maximum Dap message size
	ND	DPMXH,^D8		;Maximum Dap header size
	ND	LLMXF,^D40		;MAX LENGTH OF FILESPEC STRING

IFE MAXLNK-1,<DEFINE MULINK <IFE -1,>>
IFG MAXLNK-1,<DEFINE MULINK <IFE  0,>>


;Contants for this implimentation

	XP	CAP1,SY$SEQ+SY$SQA+SY$BLK+SY$UBK+SY$LN2+SY$EXE+SY$DTI+SY$PRO+SY$BCT+SY$DIR+SY$SUB+SY$DEL+SY$CRC+SY$VBN
	XP	CAP2,SY$WLD+SY$NAM

	XP	DAPVER,<BYTE (8) .DVMAJ,.DVMIN,.DVUSR,.DVSFT>
SUBTTL	IMPURE storage


	.PSECT	DATA			;Load where FAL or NFT left off

DEFINE	$DATA (NAME,SIZE<1>) <
 NAME:	BLOCK SIZE
	 ..LOC==.>

$DATA	DAPFRM,1			;USER PDL FRAME
$DATA	DAPFLG,1			;DAP FLAGS FROM D$INIT
$DATA	MSGDSG,1			;DAP Message designator
$DATA	LNKPGS,MAXLNK			;Per link storage address
$DATA	NETTIM,1			;Adjustment for date time


MULINK <
	 ..LOC==0			;Start at offset 0
DEFINE	$DATA (NAME,SIZE<1>) <
	 ..DEF (NAME,\..LOC)
	  ..LOC==..LOC+SIZE>

	DEFINE ..DEF (NAME,OFFSET) <
	  DEFINE NAME <OFFSET(CP)>>
> ; End MULINK
SUBTTL	STORAGE	allocated per logical link

;This part of the per link data contains Logical Link variables

;If there is more than 1 link allowed then reference all variables
; by index register (cp) else allocate storage directly


$DATA	LNKBEG,0			;Start of per link storage

$DATA	LLOPNB,.DOSIZ			;COPY OF LINK OPEN BLOCK
$DATA	CAPIBL,1			;Enabled capiblities of FAL if enabled
$DATA	DIRNUM,1			;Directory number
$DATA	USRNUM,1			;User number
$DATA	LLJFN				;JFN FOR LOGICAL LINK
$DATA	LLSTAT				;Last link status from LLCHK
$DATA	LNKSTS				;Link status and state from S
$DATA	MSGFLG				;-1 says message available
$DATA	LLDISC,20			;Disconnect cause stored here
$DATA	CLSBLK,2			;Block for closing link
$DATA	LLNAME,20			;JFNS STRING FOR LL JFN

$DATA	RCVLST				;Index for receive list
$DATA	SNDLST				;Index for send list

;Send/Recieve Queue header offsets

	.DPTYP==0			;TYPE FIELD FROM MESSAGE
	.DPFLG==1			;DAP message HEADER flags
	.DPLEN==2			;Starting size of buffer
	.DPSID==3			;DAP message HEADER Stream ID field
	.DPBCT==4			;DAP message HEADER bit count field
	.DPCNT==5			;Number of bytes left in buffer
	.DPBPT==6			;Pointer to DAP message
	.DPHDR==7			;Two word in which to build header
	  .DPSIZ==11			;Number of words in List header area


$DATA	DAPBEG,0			;Start of area to clear before config
					; messages have been exchanged on the
					; logical link.  The area begins here
					; and continues until the end of the
					; storage defined for the configuration
					; message on the next page.

$DATA	REMOST				;Remote operating system type
$DATA	OURVER				;Mutually lowest DAP version supported
$DATA	OURCAP,2			;Mutual capabilities of both ends
$DATA	OURDSP				;Mutual attributes display bits
$DATA	OURMRS				;Mutual Maximum record size
$DATA	OURSIZ				;Mutual maximum buffer size
;This part of the per link data contains the parsed fields
;from each DAP message.

;Field names will have the following format:

;	MSGFLD	Where:

;	MSG	is the three character message name (CFG for config,
;		ATT for Attributes, etc)

;	FLD	is the three character field name (BSZ for bytesize,
;		RCN for record number, etc)

;The DAP messages are defined in DAPSYM.MAC with the following field
;types

;Define macro to allocate storage for all DAP message fields.

DEFINE	XX (MSG,VAL,NAME,FLAG) <

MSG'$ST==..LOC				;;Define start of message offset
MSG'$LN==0				;;Define message storage length
MSG'$FC==0				;;Define message argument count

    DEFINE VV (VER) <>			;;Ignore version comparison this pass
    DEFINE YY (FLD,TYP,SIZ,DEF) <

	LN==1
	IFIDN <TYP><MNU>,<LN==<SIZ*7>/36+1> ;;Menu stored 35 bits per word
	IFIDN <TYP><EXF>,<LN==<SIZ*7>/36+1> ;;Exf stored 35 bits per word
	IFIDN <TYP><BYT>,<LN==<SIZ*8>/33+1> ;;Fix stored 4 bytes per word
	IFIDN <TYP><VAR>,<LN==<SIZ*7>/35+1> ;;Var stored 5 bytes per word
	IFIDN <TYP><INT>,<LN==<SIZ*8>/33+1> ;;Int stored 4 bytes per word
					    ;;All else requires 1 word

	MSG'$LN==MSG'$LN+LN		;;Accumulate message storage length
	MSG'$FC==MSG'$FC+1		;;Accumulate field count

$DATA	MSG''FLD,LN>

> ;End of XX definition


;Allocate storage for all message arguments

	XLIST
	DOMSG
	LIST
DAPSIZ==<ATTMNU>-<DAPBEG>		;Size of area to clear befor Config
					; Message is exchanged

LNKSIZ==<ATTMNU>-<LNKBEG>		;Size of area to clear before Opening
					; Logical link


;This section of per link storage contains storage for all DAP messages
; (except the CONFIG message) file variables and miscellaneous storage.

					;Area to be cleared for each function
					; Begins with Attributes message storage
					; and continues thru end of this page

;Attributes message fields saved for FAL's wild ACCESS (Open)

$DATA	ATTSAV,ATT$LN

;RAC field from control message saved for every CONTROL

$DATA	RACSAV

;Data modes for this access

$DATA	SRCMOD				;Mode of source file
$DATA	DSTMOD				;Mode of destination file


;Local file variables

$DATA	JFNBLK,20			;GTJFN Block
$DATA	LOCJFN				;JFN of local file + original flags
$DATA	WLDJFN				;Wild card JFN to hold changed flags
$DATA	LOCDEV				;Device characteristics for local file
$DATA	OPNFLG				;Flags and BSZ for local file open
$DATA	PAGFLG				;-1 if doing page mode I/O
$DATA	CRCFLG				;-1 if we are computing CRC
$DATA	FILCRC				;Computed CRC
$DATA	FILFOP				;File options from attributes
$DATA	LOCFDB,.FBLEN			;FDB Data for local file

;MACY11 format storage and flags

$DATA	MCYIDX				;Non-zero if doing MACY11 mode
$DATA	MCYDAT				;Last MACY11 word read

;Remote file variables

$DATA	ATTFDB,.FBLEN			;FDB data from remote file (directory)

;Status text storage

$DATA	STSTXT,20			;Dap status text stored here
$DATA	MSGJNK,10			;Junk string field to dump stuff into

$DATA	SNDSAB,SAB.SZ
$DATA	MSGPTR,1			;Pointer to log message char
$DATA	MSGCNT,1			;Remaining room in MSGTXT

;IPCF message area

$DATA	MSGHDR,MSHSIZ			;Message header area
$DATA	MSGARF				;Message argument flags
$DATA	MSGARC				;Message argument count
$DATA	MSGARH				;Message argument header
$DATA	MSGTXT,200			;Message body goes here

$DATA	FNCEND,0			;End of per function area

FNCSIZ==<FNCEND>-<ATTMNU>		;Size of per function storage
					; Last word to be cleared per function

	NLLPGS==<..LOC/1000>+1		;Number of pages allocated for each
					; Logical link



DATEND::	.ENDPS	DATA		;End of impure storage
;DECLARE VERSION AND ENTRY VECTOR

	LOC	137			;SET THE VERSION
	RELOC
.JBVER:	EXP	VDAP20


;ENTRY VECTOR DEFINITION

ENTVEC:	EXP	0			;NO START ADDRESS
	EXP	0			;NO REENTER ADDRESS
	EXP VDAP20			;VERSION OF DAP20 PROGRAM
SUBTTL	DAP message descriptor blocks

;Each message descriptor fully describes the message format
;and storage for the various fields.  All message types
;are defined here via the DOMSG macro in DAPSYM

;The Message Header values were obtained from the previous expansion of
;DOMSG to allocate storage for the message fields.


;	=======================================
;MSGMSD:!      .DMMSG      !  [ASCIZ\Name\]   ! (Message descriptor)
;	!--------------------------------------
;	!      MSG$LN      !      MSG$ST      !
;	!--------------------------------------
;	!  Message Flags   !      MSG$FC      !
;	!=====================================!
;	! Flags! TYP ! SIZ !  Storage offset  !	(Field descriptor)
;	!--------------------------------------
;	! Version Check word if DA%VER was on !
;	!                OR                   !
;	! Field default word if DA%DEF was on !
;	!-------------------------------------!
;	\				      \
;	\   Field descriptors for each field  \
;	\				      \
;	=======================================

;Message flag definitions

	DA%NOZ==1B0			;Dont zero message on recieve

;Field descriptor flag and field definitions

	DA%VER==1B0			;Version check word is present
	DA%DEF==1B1			;Field default word is present
	DA%TYP==77B8			;Argument type field
	DA%SIZ==777B17			;Maximum argument size in message bytes
	DA%STG==777777B35		;Argument storage offset

;Where	.DMMSG		numeric message type
;	MSG$LN		Length of message argument storage
;	MSG$ST		Starting offset of message argument storage
;	MSG$FC		Number of fields message may contain


;Define a macro to define version check word value to limit our
;menu for cantankerous implimentations...

    DEFINE VV (VER) <%%VV(VER)>
	DEFINE %%VV(VER,ECO,USR,SFT,OST) <
	    EXP DA%VER			;;Flag this is a version word
	    BYTE (8) VER,ECO,USR,SFT (4) OST>

;Define a macro to build message descriptor header

DEFINE	XX (MSG,VAL,NAME,FLAGS<0>) <

MSG'MSD: XWD .DM'MSG,[ASCIZ\NAME\]
	 XWD MSG'$LN,MSG'$ST
	 EXP FLAGS+MSG'$FC

;;Define a macro to build argument descriptors

    DEFINE YY (FIELD,TYP,SIZ,DEF) <
	%%YY==FLD(.AR'TYP,DA%TYP)+FLD(SIZ,DA%SIZ)+FLD(MSG''FIELD,DA%STG)
      IFB  <DEF>,<
	EXP	%%YY>
      IFNB <DEF>,<
	EXP	%%YY+DA%DEF
	EXP	DEF>

    > ;End of YY definition
> ;End of XX definition

;Expand message descriptors for each defined message type


	XLIST
	DOMSG				;;Expand message descriptors
	LIST
SUBTTL	DAP message argument types and processor table

;DAP message argument types are described below.
;There are two processors associated with each argument type.  The
;Argument processors are responsible for converting DAP format to
;internal format (GET) and from internal format to DAP format (PUT)


;MNU	Field is a menu which determines which message fields follow
;	Menu's are stored as extensible fields and cause 1 word of
;	storage to be reserved for every 5 DAP bytes

;EXF	Field is an extensible field which is generally used as a bit
;	map of specific options requested or a menu of message fields
;	which follow.  Extensible fields have 7 information bits per
;	DAP byte and are stored as 36 information bits per word.
;	Bit 35 is the least significant bit of the extensible field.

;FIX	Field is a Byte or group of Bytes.  Dap Bytes are stored
;	right justified 4 per 36 bit word.

;INT	Field is a variable length unsigned integer.  The DAP field
;	is stored as a 36 bit integer value

;VAR	Field is a variable length Ascii field.  It is stored as an
;	ASCIZ string of 7 bit bytes.


;PRO	Field is a file protection field.  Dap protection codes are
;	translated to system protection mask.
;DTI	Field is an 18 byte Date/time argument.  This field is stored
;	internally as a 36 bit quantity.

;IMA	Field is an image field of a DATA message.  This field is not
;	stored, but is processed by the apporpriate data processor


;Define a macro to generate argument processor table entries
; and define values for argument type symbols

DEFINE XX (TYP,CNT) <
	.AR'TYP==ZZ
	ZZ==ZZ+1
	XWD GET'TYP,PUT'TYP>


;Build the argument processor table

	ZZ==0				;Start with argument type 0

ARGTBL:	XLIST
	MSGARG				;Expand argument processor table
	LIST
SUBTTL	Local macro definitions

;MACRO TO GENERATE STATUS CODES
DEFINE	$STATUS (MAC,MIC,MIC2) <
  IFB  <MIC2>,<MOVX S1,FLD(MAC,ER%MAC)+FLD(MIC,ER%MIC)>
  IFNB <MIC2>,<MOVX S1,FLD(MAC,ER%MAC)+FLD(MIC,ER%TYP)+FLD(MIC2,ER%FLD)>
	       SETZM S2>

;MACRO TO GENERATE MESSAGE FORMAT ERRORS
DEFINE	$MFERR (TYP,FLD)	<
		JRST [$STATUS ER$FMT,TYP,FLD
		      $RETF]>

;MACRO TO GENERATE MESSAGE SYNC ERRORS
DEFINE	$MSERR (TYP) <
		JRST [$STATUS ER$SNC,TYP
			 $RETF]>

;MACRO TO GENERATE MESSAGE FIELD ERRORS
DEFINE	$MIERR (TYP,FLD) <
		JRST [$STATUS ER$INV,TYP,FLD
		      $RETF]>

;MACRO TO GENERATE UNSUPPORTED MESSAGE FEATURES ERRORS
DEFINE	$MUERR (TYP,FLD) <
		JRST [$STATUS ER$USP,TYP,FLD
		      $RETF]>

;MACRO TO GENERATE TRANSFER STATUS ERROR MESSAGES
DEFINE	$MTERR (TYP) <
		JRST [$STATUS ER$TRN,TYP
			$RETF]>

DEFINE	$MOERR (TYP) <
		JRST [$STATUS ER$OPN,TYP
			$RETF]>


DEFINE	$MCERR (TYP) <
		JRST [$STATUS ER$TRM,TYP
			$RETF]>


;MACRO TO CHANGE DAP STATE AND MESSAGE DISPATCH
DEFINE	$STATE	(VAL)	<MOVX	S,S%INIT+VAL>

;OPDEF TO RETURN FALSE IF FALSE
OPDEF	$RETIF	[JUMPF	.POPJ]

;OPDEF TO RETURN TRUE IF TRUE
OPDEF	$RETIT	[JUMPT	.POPJ]

;MACRO TO GENERATE POINTER TO TEXT
DEFINE TXT(TEXT) <POINT 7,[ASCIZ\TEXT\]>
GETTER:	MOVEI	S1,.FHSLF		;Get my last JSYS error
	GETER
	 ERJMP	.+1
	HRRZ	S2,S2			;Return code in S2
	$RETT


SUBTTL	$DEBUG	Macro to display debugging message

DEFINE	$DEBUG	(MSG,ITXT,%L1) <
	$CALL	[$TEXT (DEBUG,<[^Q/%L1/ITXT]>)
		 $RET
	%L1:!	 TXT<MSG>]
	SUPPRESS %L1
> ;End of $DEBUG


DEFINE	$FATAL	(MSG,ITXT,%L1) <
	$CALL	[$TEXT (,<?^Q/%L1/ITXT>)
		 PJRST FATAL
	%L1:!	 TXT<MSG>]
	SUPPRESS %L1
> ;End of $FATAL


DEFINE	$WARN	(MSG,ITXT,%L1) <
	$CALL	[$TEXT (,<%^Q/%L1/ITXT>)
		 $RET
	%L1:!	 TXT<MSG>]
	SUPPRESS %L1
> ;End of $WARN
SUBTTL	DEBUG and TYPER output routines

;DEBUG	Text output routine for $DEBUG macro

DEBUG:	SKIPN	S2,MSGDSG		;Get output designator
	$RETT
	EXCH	S1,S2			;Setup for bout
	BOUT
	$RETT

;Routine to Type text and ITEXT

;Accepts	S1/ Output designator
;		S2/ Pointer to asciz text
;		T1/ Address of ITEXT
;		T2/ Prefix character

TYPER:	TRVAR	<TXTBP,<TMPTXT,^D30>> ;Save some space
	EXCH	T2,S2			;Get prefix character
	SKIPE	S2			;Any desired?
	BOUT				;Yes..dump it
	MOVE	S2,T2			;Restore text pointer
	MOVE	T2,[POINT 7,TMPTXT]	;Get a pointer
	MOVEM	T2,TXTBP		;Save for DEPBP
	SKIPE	T1			;Any ITEXT?
	$TEXT	(DEPBP,<^Q/S2/^I/(T1)/>^0)	;Yes..get it
	SKIPN	T1			;Any ITEXT?
	$TEXT	(DEPBP,<^Q/S2/>^0)	;No..just do string
	HRROI	S2,TMPTXT		;Get source designator
	SETZM	T1			;Terminate on a null
	SOUT
	$RETT

DEPBP:	IDPB	S1,TXTBP		;Store per TEXT Byte Pointer
	$RETT
SUBTTL	$GODAP	Macro to establish DAPLIB context

DEFINE	$GODAP (SAVLST) <
	LSTOF.
IFNB <SAVLST>,<$SAVE <S,SAVLST>>
IFB  <SAVLST>,<$SAVE <S>>
	LSTON.
	JSP TF,GODAP>

MULINK <
DEFINE	$GODAP (SAVLST) <
	LSTOF.
IFNB <SAVLST>,<$SAVE <S,CP,SAVLST>>	;SAVE AC'S
IFB  <SAVLST>,<$SAVE <S,CP>>		;JUST SAVE STATUS AND CP
	LSTON.
	JSP	TF,GODAP>
> ;End MULINK


;GODAP	is called upon entry to DAPLIB by the various routines
;	It sets up CP and S which are used throughout DAPLIB
;	to reference the logical link storage and status.

;	All returns to the calling program go through GOUSR
;	which preserves the contents of S which holds the
;	last known link status.

;Accepts	S1/	Link index

;Returns	CP/	Address of link storage
;		S/	Last known link status


GODAP:	MOVEM	P,DAPFRM		;Save frame for Error return
	MOVEI	S1,(S1)			;Get right half only
	CAIL	S1,1			;CHECK ENTRY LIMITS
	CAILE	S1,MAXLNK
	 $FATAL	(Invalid link index)
MULINK <
	SKIPG	CP,LNKPGS-1(S1)		;Point to per/link storage
	 $FATAL (Logial link not established)
>
	MOVE	S,LNKSTS		;Get proper link status flags
	PUSH	P,[GOUSR]		;Stack return address
	MOVEM	P,DAPFRM		;Save frame for error return
	JRST	@TF			;Back to our caller
GOUSR:	MOVEM	S,LNKSTS		;Save link status
	$RET				;No..Return True/False per routine


FATAL:	MOVEI	S1,.DCX38		;User abort
	MOVX	S2,TXT(Fatal error)
	$CALL	D$CLO1			;Close the link
	MOVE	P,DAPFRM		;Restore frame
	$RETF				;Back thru GOUSR
SUBTTL	D$INIT	Daplib initialization

;Accepts	S1/	Size of initialization block
;		S2/	Address of initialization blocl

D$INIT::$SAVE	<P1>			;Preserve an AC
	MOVEM	P,DAPFRM		;Save in case of error
	CAIE	S1,.DISIZ		;Proper arg block size?
	 $FATAL	(Invalid argument length)
	MOVE	S1,.DIFLG(S2)		;Get flags
	MOVEM	S1,DAPFLG		;Save them
	MOVE	S1,.DIMSG(S2)		;GET message designator
	MOVEM	S1,MSGDSG		;Save it
	LOAD	S1,DAPFLG,DI%CNT	;Get count to allocate
	CAILE	S1,MAXLNK		;Check range
	 $FATAL	(Too many links requested)
	MOVNS	S1			;Negate count
	HRLZ	P1,S1			;Put it in P1
MULINK <
D$INI1:	MOVX	S1,NLLPGS		;Get count of pages per link
	$CALL	M%AQNP			;Get them
	PG2ADR	S1			;Convert to address
	MOVEM	S1,LNKPGS(P1)		;Store in proper place
	AOBJN	P1,D$INI1		;Do all requested
> ;End MULINK
	$RETT
SUBTTL	D$OPEN	Establish a logical link

;Accepts	S1/ Size of argument block (.DOSIZ)
;		S2/ Address of Argument block

;Returns TRUE	S1/ Link index
;	 FALSE	S1/ Dap error code

D$OPEN::$SAVE	<AP,CP>
	MOVEM	P,DAPFRM		;Save for error
	MOVE	AP,S2			;Save argument address
	CAIE	S1,.DOSIZ		;SIZE MATCH?
	 $FATAL	(Invalid argument length)
	LOAD	S1,.DOFLG(S2),DO%LNK	;Get requested link index
D$OPN2:	$GODAP	<T1,T2,T3,T4>		;Get link context
	MOVEI	S1,LNKSIZ		;Clear Link area
	MOVEI	S2,LNKBEG		;...
	$CALL	.ZCHNK
	MOVEI	S1,LLOPNB		;Point to OPEN block
	HRLI	S1,(AP)			;Point to Argument
	BLT	S1,.DOSIZ-1+LLOPNB	;Copy calling argument
	MOVEI	AP,LLOPNB		;Point to our copy
	$CALL	L%CLST			;Create receive list
	 JUMPE	S1,.-1			;Fudge if first list is 0
	MOVEM	S1,RCVLST		;Remember index
	 JUMPE	S1,.-1			;Should never happen
	$CALL	L%CLST			;Create send list
	MOVEM	S1,SNDLST		;Remember index
	$CALL	LLGJFN			;Go get proper JFN
	$CALL	LLOPEN			;Open and attach to PSI
	MOVE	S1,.DOFLG(AP)		;Get the flags
	TXNE	S1,DO%WCN		;Wait for a connection?
	$CALL	LLWCON			;Yes.. go wait for it.
	$RETT
SUBTTL	D$INTR	Interrupt processing routines

;Accepts	S1/ Link index
;		S2/ Interrupt cause


D$INTR::$GODAP	<DAPFRM>		;Save current frame
	CAIN	S2,.DICDN		;Connect interrupt?
	PJRST	CICON			;Yes..process it
	CAIN	S2,.DIINA		;Interrupt message?
	PJRST	PSIIM			;Yes..read the message
	CAIN	S2,.DIDAV		;Data available?
	SETOM	MSGFLG			;Yes..Flag it
	$RETT				;Return

SUBTTL	D$CLOS	Routine to close logical link

;Accepts	S1/	Link index
;		S2/	Address of reason block

;Reason block	Length,,NSP disconnect code
;		Pointer to optional data to be sent

;Returns TRUE	Link has been closed

D$CLOS::$GODAP	<T1,T2,T3,T4>		;Get link context
	SKIPN	LLJFN			;Have a JFN?
	 $FATAL	(Logical link is not open)
	MOVE	S1,.DCCOD(S2)		;Get the reason code
	TLNN	S1,-2			;Optional data specified?
	TDZA	S2,S2			;No..clear pointer
	MOVE	S2,.DCPTR(S2)		;Yes..get the pointer
D$CLO1:	SKIPE	LLJFN			;Still have JFN?
	$CALL	LLCLOS			;Yes..Close the link
	SKIPE	S1,RCVLST		;Get receive list index
	$CALL	L%DLST			;Destroy it
	SETZM	RCVLST			;Mark it deleted
	SKIPE	S1,SNDLST		;Get send list index
	$CALL	L%DLST			;Destroy it
	SETZM	SNDLST			;Mark it deleted
	SKIPE	LOCJFN			;Still have JFN?
	$CALL	ABTFIL			;Yes..abort file operation
	SKIPE	LOCJFN			;Still have JFN?
	$CALL	RELJFN			;Yes..release it
	$RETT

SUBTTL	D$STAT	Display link status

;Accepts	S1/ Link index

;Returns TRUE	S1/ Link status
;		    Link is open

;	 FALSE	S1/ Link status
;		    Link is not open

D$STAT::$GODAP	<S2,T1>			;Get link context
	$CALL	LLCHK			;Get the link status
	$RET				;Return status to user
SUBTTL	D$FUNC	Daplib routine to perform a File function

;Accepts	S1/	Function block size
;		S2/	Address of function block

D$FUNC::MOVEM	P,DAPFRM		;Save for errors
	CAIE	S1,.DFSIZ		;Proper size arg
	 $FATAL	(Invalid argument length)
	LOAD	S1,.DFFLG(S2),DF%LNK	;Get reqested link
	SKIPN	S1			;link specified?
	SETO	S1,			;No..use current
	$GODAP	<T1,T2,T3,T4,DL,AP>	;Set link context
	MOVE	AP,S2			;Point to calling args
	$CALL	LLWCON			;No..wait for it
	TXNE	S1,MO%SRV		;Is it a server?
	PJRST	SRVMSG			;Yes..Process server messages
	MOVEI	S1,FNCSIZ		;Clear per function storage
	MOVEI	S2,ATTMNU		;...
	$CALL	.ZCHNK			;...
	SKIPE	S1,.DFLFA(AP)		;Get local file switches
	$CALL	SWLOOK			;Find them
	 JUMPF	[$FATAL (Invalid switches for local file)]
	MOVEM	S1,SRCMOD		;Assume local node is Source.
	SKIPE	S1,.DFRFA(AP)		;Get remote file switches
	$CALL	SWLOOK			;Find them
	 JUMPF	[$FATAL (Invalid switches for remote file)]
	MOVE	S2,SRCMOD		;Put local mode in S2
	LOAD	T1,.DFFLG(AP),DF%ACC	;Get our function
	CAIN	T1,AF$CRE		;Creating remote file?
	EXCH	S1,S2			;Yes..S1=Local S2=Remote
	MOVEM	S1,SRCMOD		;Save source mode
	MOVEM	S2,DSTMOD		;Save destination mode
	$CALL	CHKMOD			;Check for valid mode
	 JUMPF	[$FATAL (Can't do requested file format conversion)]
	PJRST	DAPDCN
SUBTTL	SRVMSG	Server initialization and tables

SRVMLS:	SRVS00,,SRVI00			;Server .LLCFG state
	SRVS01,,SRVI01			;Server .LLACC state
	SRVS02,,0			;Server .LLATT state
	SRVS03,,0			;Server .LLCTL state
	SRVS04,,0			;Server .LLDAT state
	SRVS05,,SRVI05			;Server .LLACP state


;Message dispatch for .LLCFG state

SRVS00:	.DMCFG,,SRVCFI			;Accept only Config message
	 0


;Message dispatch for .LLACC state

SRVS01:	.DMCFG,,SRVCFG			;Process Config
	.DMACC,,SRVACC			;Process Access
	.DMATT,,VALATT			;Process Attributes
	 0


;Message dispatch for .LLATT state

SRVS02:	.DMDTI,,VALDTI			;Process Date/time Attributes
	.DMPRO,,VALPRO			;Process Protection Attributes
	.DMACC,,SRVACC			;Process Access
	 0


;Message dispatch for .LLCTL state

SRVS03:	.DMCTL,,SRVCTL			;Process Control
	.DMACP,,SRVACP			;Process ACCOMP
	 0


;Message dispatch for .LLDAT state

SRVS04:	.DMDAT,,FILPUT		;Process Data
	.DMACP,,SRVACP			;Process ACCOMP
	 0

;Message dispatch for .LLACP state

SRVS05:	.DMACP,,SRVACP			;Process ACCOMP
	 0
SUBTTL	Server state initialization routines

;Initialization for .LLCFG state

SRVI00:	MOVEI	S1,DAPSIZ		;Clear Config storage
	MOVEI	S2,DAPBEG		;...
	$CALL	.ZCHNK			;...
	MOVEI	S1,DPMXM		;Set default Max message size
	MOVEM	S1,OURSIZ		;Save for first message
	$RETT

;Initialization for .LLACC state

SRVI01:	SKIPE	LOCJFN			;Clean up any previous file ops
	$CALL	ABTFIL
	SKIPE	LOCJFN
	$CALL	RELJFN
	MOVEI	S1,FNCSIZ		;Clear per function area
	MOVEI	S2,ATTMNU		;...
	$CALL	.ZCHNK
	MOVX	S1,TXT(PS)		;Set default device to PS:
	MOVEM	S1,.GJDEV+JFNBLK	;...
	MOVE	S1,.DOUSR+LLOPNB	;Set default directory to user
	MOVEM	S1,.GJDIR+JFNBLK	;...
	MOVE	S1,[.NULIO,,.NULIO]	;Set null string input
	MOVEM	S1,.GJSRC+JFNBLK	;...
	$RETT

;Initialization for .LLACP state

SRVI05:	TXZ	S,S%EOF!S%GET!S%PUT	;Clear data flags
	$RETT
SUBTTL	SRVMSG	Server message processing loop

SRVMSG:	TXZE	S,S%RETN		;Time to return?
	$RET				;Yes..return to caller
	$CALL	SNDQUE			;Dump the send queues
	TXZN	S,S%INIT		;State just change?
	JRST	SRVMS1			;No..skip initialization
	HRRZ	S1,SRVMLS(S)		;Do state initialization
	JUMPE	S1,SRVMS1		;If routine is present
	$CALL	0(S1)
SRVMS1:	TXNN	S,S%GET			;Getting file data?
	JRST	SRVMS2			;No..process a message
	SKIPGE	MSGFLG			;Message available interrupt?
	JRST	[$CALL	LLCHK			;Yes..Check link status
		 SKIPGE	MSGFLG			;Is there a message there?
		 JRST	SRVMS2			;Yes..go recieve it
		 JRST	.+1]			;No..continue
	$CALL	FILGET			;Get and send data record
	TXNE	S,S%EOF			;Did we see EOF?
	$CALL	SNDEOF			;Yes..send EOF status
	TXNN	S,S%INIT		;State change on this record?
	JRST	SRVMS1			;No..Get next record
	JRST	SRVMSG			;Yes..back to do state change
SRVMS2:	HLRZ	S1,SRVMLS(S)		;Get proper message list address
	$CALL	GETMSG			;Get a message
	 JUMPF	SRVMS3			;Send failing status
	$CALL	0(S1)			;Call message processing routine
	 JUMPF	SRVMS3			;Send failing status
	JRST	SRVMSG			;Process next message

SRVMS3:	$CALL	SNDSTS			;Send status from routine
	$STATE	.LLACC			;Back to initial Access state
	$CALL	ENABLE			;Make sure we are enabled
	JRST	SRVMSG
SUBTTL	SRVCFI	Server routine to process Initial config message

SRVCFI:	$CALL	SRVCFG			;Validate and return config
	 $RETIF				;Return failing status
	$STATE	.LLACC			;Move to access state
	$RETT


SUBTTL	SRVCFG	Server routine to Process Config message

SRVCFG:	$CALL	VALCFG			;Validate the message
	 $RETIF				;Return failing status
	$CALL	SNDCFG			;Send our config message
	$RETT


SUBTTL	SRVACC	Server routine to process an ACCESS message

SRVACC:	$CALL	ENABLE			;Make sure we are wheel
	MOVE	S1,ACCFNC		;Get the Function field
	CAIL	S1,AF$OPN		;Is it valid
	CAILE	S1,AF$EXE
	$MUERR	.DMACC,20		;No..return unsupported
	MOVX	S1,POLINI		;Initilize CRC to -1
	MOVEM	S1,FILCRC
	MOVE	S1,ACCOPT		;Get the options
	TXNE	S1,AO$CRC		;Want to compute CRC
	SETOM	CRCFLG			;Yes..remember that for all data
	TXNE	S1,AO$RSS!AO$RSR!AO$GO	;Anything we don't support?
	$MUERR	.DMACC,21		;Yes..return unsupported
	MOVE	S1,.DFLFS(AP)		;Point to user storage
	HRROI	S2,ACCFIL		;Point to Access filespec
	$CALL	CPYSTR			;Copy the name

	LOAD	S1,ACCFNC		;Get desired access
	JRST	@ACCTBL-AF$OPN(S1)	;Dispatch to processor

ACCTBL:	JRST	SRVOPN			;Open existing files
	JRST	SRVCRE			;Create a new file
	$MUERR	.DMACC,20		;Rename (Unsupported)
	JRST	SRVDEL			;Delete files
	$MUERR	.DMACC,20		;Resrvd (Unsupported)
	JRST	SRVDIR			;Directory of files
	JRST	SRVSUB			;Submit file on close
	JRST	SRVEXE			;Execute files
SUBTTL	SRVOPN	Server routine to process ACCESS (Open)

;SRVOPN	is called while processing an Access(Open).  It is
;	responsible for ensuring that FAL can open the specified
;	file in the mode requested by the attributes message.

;	Since DAP file attributes are not stored as in integral
;	part of the file header (FDB) it is up to the requestor
;	to specify how the file is to be opened.

;	The following rules apply to opening files:

;	1)  If the requestor has sent an attributes message
;	which specifies a non-native file access mode, the
;	specified file will be opened in image mode using the
;	actual file bytesize.

;	2)  If the requestor has sent an attributes message
;	which specifies a native file access mode the file
;	will be opened using the bytesize demanded by that
;	data mode.  (Image mode allows the user to specify
;	the bytesize to use when openning the file)

;	3)  If the requestor has sent an attributes message
;	which specifies Image mode but has excluded the bytesize
;	attribute the actual file bytesize will be used for the
;	open.

;In all cases the attributes returned to the requestor reflect the
;current openning of the file.  (i.e if the requestor wants to see
;the file data as a 36 bit image data but the files bytesize is actually
;7 bits per byte, the attributes returned will say the file is a 36
;bit file since the data will be returned in this fasion.)

;DAP allows the user to use wild cards in the initial ACCESS (Open).
;In this case each file will be opened according to the initial
;attributes message if the requested mode is legal for that file.  If
;the initial mode is not legal for a particular file (e.g the files
;bytesize does not match what is reqired for the data processor) the
;file will be opened in Image mode.


SRVOPN:	$CALL	SETINP			;Setup for file input
	 $RETIF
	MOVE	S1,ATTMNU		;Get menu bits
	TXNN	S1,AT$DAT		;Data mode specified?
	SETZM	ATTDAT			;No..clear bogus default
	TXNN	S1,AT$RFM		;Record format specified?
	SETZM	ATTRFM			;No..clear bogus default
	TXNN	S1,AT$BSZ		;Bytesize specified?
	SETZM	ATTBSZ			;No..clear bogus default
	SKIPN	WLDJFN			;Is this a wild open?
	JRST	SRVNX1			;No..process the request
	HRLI	S1,ATTMNU		;Yes..Save original attributes
	HRRI	S1,ATTSAV
	BLT	S1,ATT$LN+ATTSAV
	PJRST	SRVNXT			;Fall into common wild open code
;SRVNXT	is called from Access complete function for each additional
;	wild file in a wild ACCESS (Open)

;SRVNX1	is the entry for a non wild ACCESS (Open)


SRVNXT:	$CALL	SNDWLD			;Send of wild name messages
SRVNX1:	MOVEI	S1,.CKARD		;Make sure requestor can read it
	$CALL	JEDGAR
	 $RETIF				;Return failing status
	$CALL	ATLOOK			;Lookup specified attributes
	 JUMPF	[MOVE T1,REMOST		;Get remote system type
		 DMOVE S1,[EXP .MD1,.MD1]	;Assume image mode
		 CAIE T1,.OSTP20		;TOPS20 or TOPS10?
		 CAIN T1,.OSTP10
		  JRST .+1			;Yes..use image
		 LOAD T1,.FBBYV+LOCFDB,FB%BSZ	;No..check bytesize
		 CAIE T1,^D7			;
		 CAIN T1,^D36
		 DMOVE S1,[EXP .MD8,.MD8]	;Assume ascii mode
		 JRST .+1]
	MOVEM	S1,SRCMOD		;Save local mode
	MOVEM	S2,DSTMOD		;Save destination mode
	SKIPE	S1,ATTBSZ		;User specified bytesize?
	STORE	S1,.FBBYV+LOCFDB,FB%BSZ	;Yes..use it for Open
	MOVEI	S1,ATTMSD		;Clear remaining attributes
	$CALL	CLRMSG
	$CALL	SETMOD			;Check for proper mode
	 JUMPF	[$MUERR .DMATT,21]	;Else return bad mode
	MOVE	T1,[POINT 4,MODTB2(S1)]	;Get pointer to destination mode
	ILDB	T1,T1			;Get default destination mode
	SKIPN	DSTMOD
	MOVEM	T1,DSTMOD
SRVNX2:	MOVEM	S2,ATTBSZ		;Save attributes bytesize
	MOVX	S1,AT$DAT+AT$RFM+AT$RAT+AT$BSZ
	MOVEM	S1,ATTMNU
	$CALL	OPNFIL			;Open the file for input
	 $RETIF				;Return failing status
	MOVE	S1,DSTMOD		;Get destination mode
	SETZ	S2,			;Clear extra attributes
	$CALL	SETATT			;Setup proper attributes
	SKIPN	S1,ACCDSP		;Display requested?
	MOVX	S1,DI$ATT		;No..default is attributes
	$CALL	SNDDSP			;Send them off
	$CALL	SNDACK			;Send an ACK for this ACCESS
	$STATE	.LLCTL			;Wait for Control or Accomp
	$RETT
SUBTTL	SRVCRE	Server routine to process ACCESS (Create)

;SRVCRE	is called while processing an ACCESS (Create) message.
;	It is responsible for opening the file in the mode specified
;	by the initial attributes message.

;	Since DAP file attributes are not stored as a part of the
;	file header (FDB) it is up to the requestor to specify how
;	the file is to be created.

;	The following rules apply to creating files:

;	1)  If the user specified that the file be created in a
;	mode not native to our file system, an error will be returned.

;	2)  If the user specified that the file be created in image
;	mode and failed to specify a byte size, the file will be opened
;	as an 8 bit file.  (DAP default for bytesize is 8 bit bytes)

;	3)  If the user specified image mode with a byte size of 0
;	the file will be created as a 36 bit file.

;	4)  If the user specified image mode with a byte size of 1 to 36
;	the file will be created per the requestors wishes.

;	5)  If the user specified ascii mode the file will be opened
;	using a bytesize of 7 .

;In all cases the attributes returned will reflect the current opening
;of the file.

SRVSUB:	MOVX	S1,FB$SUB		;Get submit bit for close
	IORM	S1,ATTFOP		;Remember it
					;Enter common create code

SRVCRE:	$CALL	ATLOOK			;Lookup incomming attributes
	 JUMPF	[$MUERR .DMATT,21]	;Bad data mode
	SKIPN	MODTB7(S1)		;Legal mode for Create?
	 $MUERR	.DMATT,21		;No..bad data mode
	MOVEM	S1,SRCMOD		;Save our source mode
	MOVEM	S2,DSTMOD		;Save destination mode
	$CALL	SETOUT			;Setup to create a file
	 $RETIF				;Return failing status
	MOVEI	S1,.CKACF		;Check access for file creation
	$CALL	JEDGAR			;See if user can create
	 $RETIF				;Return failing status
	SKIPN	S1,ATTBSZ		;Bytesize equal 0?
	MOVEI	S1,^D36			;Yes..make it 36 (if image mode)
	STORE	S1,.FBBYV+LOCFDB,FB%BSZ	;Save for SETMOD
	$CALL	SETMOD			;Setup the data mode
	 JUMPF	[$MUERR	.DMATT,21]	;Else return failing status

SRVCR1:	MOVEM	S2,ATTBSZ		;Save bytesize for attributes
	$CALL	OPNFIL			;Open the file for output
	 $RETIF				;Return failing status
	MOVX	S1,AT$DAT+AT$RFM+AT$RAT+AT$DEV+AT$BSZ
	MOVEM	S1,ATTMNU		;Setup minimum attributes menu
	SKIPN	S1,ACCDSP		;Display field present?
	MOVX	S1,DI$ATT		;No..Default is attributes
	$CALL	SNDDSP			;Send them out
	$CALL	SNDACK			;SEND OUT AN ACK
	$STATE	.LLCTL			;Wait for Control or Accomp
	$RETT				;AND RETURN SUCCESS
SUBTTL	SRVDEL	Server routine to process Delete requests

SRVDEL:	MOVEI	S1,ATTMSD		;Clear attributes message
	$CALL	CLRMSG
	MOVX	S1,DT$IMA		;Set image mode
	MOVEM	S1,ATTDAT
	MOVX	S1,FB$UDF		;Undefined format
	MOVEM	S1,ATTRFM
	MOVX	S1,AT$DAT+AT$RFM+AT$BSZ+AT$DEV+AT$BSZ
	MOVEM	S1,ATTMNU		;Set minimum attributes menu
	$CALL	SETINP			;Setup to find existing file
	 $RETIF
SRVDE1:	LOAD	S1,.FBBYV+LOCFDB,FB%BSZ
	MOVEM	S1,ATTBSZ		;Store actual bytesize
	MOVX	S1,.CKACF		;Must be able to create file
	$CALL	JEDGAR			;CHECK THE ACCESS
	 $RETIF				;Return failing status
	SKIPE	S1,ACCDSP		;Want any attributes?
	$CALL	SNDDSP			;No..default is display none
	$CALL	DELFIL			;Delete the file
	$CALL	NXTINP			;Look for next file
	 JUMPT	SRVDE1			;Found it..go delete it
	$CALL	SNDACA			;Send ACCOMP (Resp)
	$STATE	.LLACC+S%RETN		;Return to Access state
	$RETT
SUBTTL	SRVEXE	Server routine to process submit requests

SRVEXE:	HRROI	S1,[ASCIZ/CTL/]		;Get default extention
	MOVEM	S1,.GJEXT+JFNBLK
	MOVEI	S1,ATTMSD		;Clear initial attributes
	$CALL	CLRMSG			;Clear it
	MOVEI	S1,.MD8			;Set ascii stream attributes
	SETZM	S2			;No MRS or other attributes
	$CALL	SETATT
	$CALL	SETINP			;Set up for file input
	 $RETIF				;Return failing status
SRVEX1:	LOAD	S1,.FBBYV+LOCFDB,FB%BSZ	;Get file bytesize
	CAIE	S1,^D7			;Must be 7 or 36
	CAIN	S1,^D36
	SKIPA				;Ok..submit it
	 $MOERR	ER$BSZ			;Bad bytesize
	MOVX	S1,.CKARD		;Check read access
	$CALL	JEDGAR			;Check access and submit
	 $RETIF				;Return failing status
	$CALL	SUBMIT			;Submit the file
	SKIPE	S1,ACCDSP		;Want any attributes?
	$CALL	SNDDSP			;Yes..send them out
	$CALL	NXTINP			;Get next file in the group
	 JUMPT	SRVEX1			;Back to submit next file
	$CALL	SNDACA			;Send ACCOMP (Resp)
	$STATE	.LLACC+S%RETN		;Return to Access state
	$RETT
SUBTTL	SRVDIR	Server routine to process Directory requests

SRVDIR:	HRROI	S1,[ASCIZ/*/]		;Get some wild cards
	MOVEM	S1,.GJNAM+JFNBLK	;Set wild filename
	MOVEM	S1,.GJEXT+JFNBLK	;Set wild filetype
	MOVEI	S1,ATTMSD		;Clear attributes message
	$CALL	CLRMSG
	MOVX	S1,DT$IMA		;Attributes are image undefined
	MOVEM	S1,ATTDAT
	MOVX	S1,FB$UDF
	MOVEM	S1,ATTRFM
	MOVX	S1,AT$DAT+AT$RFM+AT$BSZ
	MOVEM	S1,ATTMNU		;Set minimum attributes menu
	$CALL	SETINP			;Set up for file input
	 $RETIF				;Return failing status
SRVDI1:	LOAD	S1,.FBBYV+LOCFDB,FB%BSZ
	MOVEM	S1,ATTBSZ		;Save actual file bytesize
	MOVX	S1,.CKADL		;Check directory list access
	$CALL	JEDGAR			; directory list for file
	 JUMPF	SRVDI2			;Failed - skip this file
	$CALL	SNDWLD			;Send off proper name messages
	SKIPE	S1,ACCDSP		;Want any attributes returned?
	$CALL	SNDDSP			;Send out requested attributes
SRVDI2:	$CALL	NXTINP			;Step to next file
	JUMPT	SRVDI1			;Go back and process it
	$CALL	SNDACA			;Send ACCOMP (Resp)
	$STATE	.LLACC+S%RETN		;Return to Access state
	$RETT				; And return success
SUBTTL	SRVCTL	Server routine to process a CONTROL message

SRVCTL:	MOVE	T1,CTLFNC		;Get desired function
	CAIL	T1,CF$GET		;Do we support it?
	CAILE	T1,CF$REW		;...
	 $MUERR	.DMCTL,20		;No..return unsupported
	MOVE	S1,CTLMNU		;Get the menu
	MOVE	S2,RACSAV		;Get old record access field
	TXNN	S1,CT$RAC		;RAC field present?
	JRST	SRVCT1			;No..use the previous one
	MOVE	S2,CTLRAC		;Yes..get it and check it
	CAIL	S2,RB$SQF		;...
	CAILE	S2,RB$BKF		;...
	 $MUERR	.DMCTL,22
	MOVEM	S2,RACSAV		;Save in case of null RAC field
SRVCT1:	MOVEM	S2,CTLRAC		;Save for this access
	SKIPE	CTLKRF			;Was KRF field specified?
	$MUERR	.DMCTL,24		;Yes..return unsupported
	SKIPE	CTLROP			;Was ROP field specified?
	$MUERR	.DMCTL,25		;Yes..return unsupported
	SKIPE	CTLHSH			;Was HSH field specified?
	$MUERR	.DMCTL,26		;Yes..return unsupported
	SKIPE	CTLDSP			;Was display field specified?
	$MUERR	.DMCTL,27		;Yes..return unsupported
	PJRST	@CTLTBL-CF$GET(T1)	;Yes..Dispatch to processor


CTLTBL:	PJRST	CTLGET			;Control (Get)
	PJRST	CTLCON			;Control (Connect)
	$MUERR	.DMCTL,20		;Control (Update) unsupported
	PJRST	CTLPUT			;Control (Put)
	$MUERR	.DMCTL,20		;Control (Delete) unsupported
	$MUERR	.DMCTL,20		;Control (Rewind) unsupported

CTLCON:	$CALL	SNDACK			;Send ACK message
	$RETT

CTLGET:	$STATE	.LLDAT+S%GET		;Getting file records
	MOVE	S1,CTLRAC		;Get access type
	CAIE	S1,RB$BKF		;Block mode file I/O?
	$RETT				;No..just return
	SETOM	PAGFLG			;Yes..do page mode
	MOVE	S1,[GETPAG,,PUTPAG]	;Setup page mode processor
	MOVEM	S1,DATDAT
	MOVE	S1,CTLKEY		;Get the binary key
	MOVEM	S1,DATRCN		;Save it
	$RETT

CTLPUT:	$STATE	.LLDAT+S%PUT		;Writing file records
	$CALL	DISABL			;Allow over quota checking
	MOVE	S1,CTLRAC
	CAIE	S1,RB$BKF		;Block mode file xfer?
	$RETT				;No..just return
	SETOM	PAGFLG			;Yes..set page mode flag
	MOVE	S1,[GETPAG,,PUTPAG]	;Setup proper processor
	MOVEM	S1,DATDAT
	$RETT
SUBTTL	FILGET	Server routine to send data messages

FILGET:	SKIPF	PAGFLG			;Page mode
	SKIPN	S1,DATRCN		; and not FDB?
	JRST	FILGE1			;No..just send the message
	SUBI	S1,1			;Yes..convert VBN to page number
	LSH	S1,-^D2
	HRL	S1,LOCJFN
	RPACS				;Get page accessibility
	 ERJMP	TERCVT
FILGE1:	MOVEI	S1,DATMSD		;Point to data message
	$CALL	QUEMSG			;Build and send the message
	SKIPT	PAGFLG			;Page mode?
	$RETT				;Return
	SKIPN	S1,DATRCN		;Yes..ready for next page
	JRST	FILGE2			;If VBN was 0, start at page 0
	SUBI	S1,1			;Convert to file page number
	LSH	S1,-^D2
	ADDI	S1,1			;Step to next page
FILGE2:	HRL	S1,LOCJFN
	FFUFP				;Find next used page
	 ERJMP	[CAIE S1,FFUFX3		;Eof?
		 PJRST TERCVT		;No..return the failure
		 TXO S,S%EOF		;Yes..mark the status
		 $RETT]
	HRRZ	S1,S1
	LSH	S1,^D2			;Convert to VBN
	ADDI	S1,1
	MOVEM	S1,DATRCN		;Save for next data message
	$RETT
	
FILPUT:	MOVE	S1,.DPBPT(DL)		;Point to the data
	MOVE	S2,.DPCNT(DL)		;Get the count
	SKIPF	CRCFLG			;Doing CRC?
	$CALL	DOCRC			;Yes, calculate it
	HLRZ	S1,DATDAT		;Get routine address
	$CALL	0(S1)			;Call the routine
	$RET				;Return per processing routine
SUBTTL	SRVACP	Server routine to process Access complete message

SRVACP:	$CALL	ENABLE			;Turn on wheel again
	MOVE	T1,ACPFNC		;Get the closing function
	CAIL	T1,AC$TRM		;Within range?
	CAILE	T1,AC$SKP
	 $MUERR	.DMACP,20		;No..Return unsupported
	JRST	@ACPTBL-AC$TRM(T1)	;Do the function

ACPTBL:	PJRST	ACPTRM			;ACCOMP (Close)
	$MIERR	.DMACP,20		;Accomp (Resp) is illegal
	PJRST	ACPPUR			;ACCOMP (Purge)
	PJRST	ACPEOS			;ACCOMP (Eos)
	PJRST	ACPSKP			;ACCOMP (Skip)

ACPPUR:	$CALL	ABTFIL			;Abort current file operation
	PJRST	ACPSKP			;Step to next file
ACPTRM:	$SAVE	<P1>			;Preserve an AC
	$CALL	VALCRC			;Validate the CRC
	 $RETIF				;Return error on failure
	SKIPN	P1,ACPFOP		;Get completion file options
	MOVE	P1,FILFOP		;Else use options from attributes
	TXNE	P1,FB$SUB		;Want to submit file?
	 $CALL	SUBMIT			;Yes..do the submit
	TXNE	P1,FB$SPL		;Want to spool the file
	 $CALL	PRINT			;Yes..do the print
	TXNE	P1,FB$SPL+FB$SUB	;Spooling or printing?
	 JRST	ACPCLS			;Yes..just close the file
	TXNE	P1,FB$DEL		;Want to delete the file?
	 $CALL	DELFIL			;Yes..delete it now
ACPCLS:	$CALL	CLSFIL			;Close current file normally
	 $RETIF				;Return failing status
ACPSKP:	SKIPN	WLDJFN			;Wild JFN?
	JRST	ACPACK			;No..send ACCOMP (Ack)
	$CALL	NXTINP			;Another file to do?
	 JUMPF	ACPACK			;No..send ACCOMP (Ack)
	HRLI	S1,ATTSAV		;Yes..restore initial attributes
	HRRI	S1,ATTMNU		; before calling SRVNXT
	BLT	S1,ATT$LN+ATTMNU
	SETZM	SRCMOD			;Clear source and destination
	SETZM	DSTMOD			; Modes
	PJRST	SRVNXT			;Process the next file

ACPACK:	$CALL	SNDACA			;No..send Accomp (Resp)
	$STATE	.LLACC+S%RETN		;Back to initial access state
	$RETT

ACPEOS:	$CALL	SNDACA			;Send Accomp (Resp)
	$STATE	.LLCTL			;Back to control state
	$RETT
SUBTTL	ENABLE/DISABL Routine to set or clear capabilities for server


ENABLE:	SKIPE	T1,CAPIBL		;Are we already enabled?
	$RET				;Yes, just return
	MOVEI	S1,.FHSLF		;Get my fork handle
	RPCAP				;Get my capabilites
	TXON	T1,SC%OPR+SC%WHL	;Enable operator and/or wheel
	EPCAP				; if not already enabled
	MOVEM	T1,CAPIBL		;Save for upcomming disable
	$RET

DISABL:	SKIPN	T1,CAPIBL		;Are we already disabled?
	$RET				;Yes, just return
	MOVEI	S1,.FHSLF		;Get my for handle
	SETO	S2,
	TXZ	T1,SC%OPR+SC%WHL	;Clear operator and wheel
	EPCAP
	SETZM	CAPIBL			;Say no longer enabled
	$RET
SUBTTL	HOOVER	Routine to validate a users access to a file

;Accepts	S1/ Requested access

;Returns TRUE	Access is allowed
;	 FALSE	Access denied

JEDGAR:	STKVAR	<<CHKBLK,5>>
	MOVEM	S1,.CKAAC+CHKBLK	;Save requested access
	HRRZ	S1,LOCJFN		;Get file JFN
	MOVEM	S1,.CKAUD+CHKBLK	;Save the JFN
	MOVE	S1,DIRNUM		;Get directory number
	MOVEM	S1,.CKACD+CHKBLK	;Save as directory
	MOVE	S1,USRNUM		;Get user number
	MOVEM	S1,.CKALD+CHKBLK	;Save as user
	SETZM	.CKAEC+CHKBLK		;Check with no privs
	MOVX	S1,CK%JFN+5		;Set JFN flag and length
	MOVEI	S2,CHKBLK		;Point to args
	CHKAC				;Check the access
	 TDZA	TF,TF			;Jsys failed..return false
	MOVE	TF,S1			;Return True/False per chkacc
	JUMPT	JEDGA1			;Return success
	$STATUS	ER$FIL,ER$PRV		;Return privilege failure
	MOVE	S2,.CKAAC+CHKBLK	;Get requested access
	MOVE	S2,ACCERR(S2)		;Get proper extended error
	$RETF				;Return the failure

JEDGA1:	MOVE	S1,.CKAAC+CHKBLK	;Get requested access
	CAIE	S1,.CKACF		;Was it create?
	$RETT				;No..just return
	SETZM	S1			;Yes..see if we have room
	HRRZ	S2,LOCJFN
	RCDIR				;Get directory number
	 ERJMP	TERCVT
	MOVE	S1,T1			;Put directory number in S1
	GTDAL				;Get directory allocation
	 ERJMP	TERCVT
	SUB	S1,S2			;Get remaining page count
	LOAD	S2,.FBBYV+ATTFDB,FB%PGC	;Get requested file page count
	CAML	S1,S2			;Enough room?
	$RETT				;Yes..return success
	$STATUS	ER$FIL,ER$FUL		;Report quota exceeded
	$RETF

ACCERR:	OPNX3				;Read access required
	OPNX4				;Write access required
	0
	0
	0
	0
	0
	0
	DELFX1				;Delete access required
	OPNX4				;Write access required

PRINT:	SKIPA	T1,[.OTLPT]		;Get Printer object type
SUBMIT:	MOVEI	T1,.OTBAT		;Get BATCH object type
	MOVEI	S1,.QOCQE		;Get Create message type
	MOVEM	S1,MSGHDR
	SETZM	.MSFLG+MSGHDR		;Clear the flags
	SETZM	.MSCOD+MSGHDR		;Clear the ack code
	SETZM	MSGARF			;Clear argument flags
	MOVEI	S1,6			;Get minimum argument count
	MOVEM	S1,MSGARC		;Save it
	MOVE	S1,[2,,.QCQUE]		;Store que type argement header
	MOVEM	S1,2+MSGARF
	MOVEM	T1,3+MSGARF		;Store queue object type
	MOVE	S1,[2,,.QCOID]		;Store user-id header
	MOVEM	S1,4+MSGARF
	MOVE	S1,USRNUM		;Store user number
	MOVEM	S1,5+MSGARF
	MOVE	S1,[2,,.QCCDI]		;Store connected directory
	MOVEM	S1,6+MSGARF
	MOVE	S1,DIRNUM		;Use users directory
	MOVEM	S1,7+MSGARF
	MOVE	S1,[2,,.QCBLT]		;Store log file disposition
	MOVEM	S1,10+MSGARF
	MOVEI	S1,%BAPND		;Append logfile
	MOVEM	S1,11+MSGARF
	MOVEI	S1,12+MSGARF		;Point to file header
	MOVEI	S2,.QCFIL		;Store file type
	MOVEM	S2,(S1)
	HRROI	S2,NAMFSP		;Point to file
	$CALL	STRARG			;Store it
	MOVEI	S2,.QCNAM		;Get user string function
	MOVEM	S2,0(S1)		;Store user function
	MOVE	S2,.DOUSR+LLOPNB	;Point to user string
	$CALL	STRARG			;Store it
	SKIPN	.DOUSR+LLOPNB		;Account specified?
	JRST	SUBM10			;No..submit what we have
	AOS	MSGARC			;Yes..bump arg count
	MOVEI	S2,.QCACT		;Store account header
	MOVEM	S2,0(S1)
	MOVE	S2,.DOACT+LLOPNB	;Point to account string
	$CALL	STRARG			;Copy the string
SUBM10:	SUBI	S1,MSGHDR		;Get message length
	MOVEI	S2,MSGHDR		;Get message address
	PJRST	SNDQSR			;Send it to QUASAR

STRARG:	HRRZ	T2,S1			;Remember header address
	HRROI	S1,1(S1)		;Point to destination
	SETZ	T1,			;Terminate on null
	SOUT
	MOVEI	S1,1(S1)		;Point S1 to next word
	MOVE	T1,S1
	SUB	T1,T2			;Compute argument length
	HRLM	T1,0(T2)		;Save in header
	$RETT				;Return
SUBTTL	SNDQSR	Routine to send message to quasar

;ACCEPTS	S1/ Length of message
;		S2/ Address of message

SNDQSR:	MOVX	T1,SP.QSR		;Get quasars index
	TXO	T1,SI.FLG		;Set special index flag
	MOVEM	T1,SAB.SI+SNDSAB
	SETZM	SAB.PD+SNDSAB		;Clear the pid
	MOVX	T1,MF.ACK		;Lite ack bit
	IORM	T1,.MSFLG(S2)		;Store in message
	MOVEM	S1,SAB.LN+SNDSAB	;Store the length
	MOVEM	S2,SAB.MS+SNDSAB	;Store the address
	MOVEI	S1,SAB.SZ
	MOVEI	S2,SNDSAB
	$CALL	C%SEND
	$CALL	C%BRCV			;Get the ack from QUASAR
	$RET				;Return true/false per C%SEND
SUBTTL	DAPDCN	Active Task function dispatch

DAPDCN:	$STATE	.LLCFG			;Start at Config state
	SKIPN	CFGVER			;Exchanged config messages?
	$CALL	DCNMSG			;No..Exchange Config messages
	 $RETIF				;Return failing status

	$STATE	.LLACC			;Step to access state
	MOVE	S1,[.NULIO,,.NULIO]	;Set null string input
	MOVEM	S1,.GJSRC+JFNBLK	;...
	HRROI	S1,ACCFIL		;Store remote filespec
	SKIPE	S2,.DFRFS(AP)		;Pointer present?
	$CALL	CPYSTR			;Yes..store it
	MOVE	S1,.DFRFO(AP)		;Get remote file options
	MOVEM	S1,ACCOPT		;Save for access
	LOAD	S1,.DFFLG(AP),DF%ACC	;Get desired function
	STORE	S1,ACCFNC
	CAIL	S1,AF$OPN		;Actual DAP function?
	CAILE	S1,AF$EXE		;...
	JRST	DAPDC1			;No..Check for special request
	$CALL	@DCNTBL-AF$OPN(S1)	;Process the request
	JUMPF	DCNABT			;Abort link on error
	$RETT

DCNABT:	HRROI	T1,STSTXT		;Expand failing status
	TXNN	S,S%ERR			;Did we receive status?
	$CALL	TYPSTS			;No..expand our message
	MOVX	T1,TXT()		;Assume local status error
	TXNE	S,S%ERR			;Unless we received status
	MOVX	T1,TXT(Remote status - );Get Remote status error
	HRROI	T2,STSTXT		;Point to expaned text
	$FATAL	(,^Q/T1/^Q/T2/)		;Display message and return


DCNTBL:	JRST	DCNREC			;AF$OPN - Recieve existing files
	JRST	DCNSND			;AF$SND - Send existing file
	JRST	DCNREN			;AF$REN - Rename existing files
	JRST	DCNDEL			;AF$DEL - Delete existing files
	JRST	DAPDC2			;Function 5 (reserved)
	JRST	DCNDIR			;AF$DIR - Directory of files
	JRST	DCNSUB			;AF$SUB - Send and execute file
	JRST	DCNEXE			;AF$EXE - Execute existing file

DAPDC1:	CAIL	S1,AF$TYP		;Special function?
	CAILE	S1,AF$PRN		;...
DAPDC2:	$FATAL	(Function not implimented)
	$CALL	@DCNTB1-AF$TYP(S1)	;Process the request
	JUMPF	DCNABT
	$RETT

DCNTB1:	JRST	DCNTYP			;AF$TYP - Type remote files
	JRST	DCNPRN			;AF$PRN	- Print remote files
SUBTTL	Active Task message and State tables

DCNMLS:	DCNS00,,DCNI00			;DCN .LLCFG state
	DCNS01,,0			;DCN .LLACC state
	DCNS02,,0			;DCN .LLATT state
	DCNS03,,0			;DCN .LLCTL state
	DCNS04,,0			;DCN .LLDAT state
	DCNS05,,0			;DCN .LLACP state


;Message dispatch for .LLCFG state

DCNS00:	.DMCFG,,DCNCFG
	.DMSTS,,DCNSTS
	 0

;Message dispatch for .LLACC state

DCNS01:	.DMACP,,DCNACP
	.DMNAM,,DCNNAM
	.DMATT,,VALATT
	.DMSTS,,DCNSTS
	 0

;Message dispatch for .LLATT state

DCNS02:	.DMDTI,,VALDTI
	.DMPRO,,VALPRO
	.DMNAM,,ATTNAM
	.DMACK,,ATTACK
	.DMACP,,ATTACP
	.DMSTS,,DCNSTS
	 0

;Message dispatch for .LLCTL state

DCNS03:	.DMACK,,CTLACK
	.DMSTS,,DCNSTS
	 0

;Message dispatch for .LLDAT state

DCNS04:	.DMDAT,,FILPUT		;Process data messages (share server routine)
	.DMSTS,,DCNSTS
	 0

;Message dispatch for .LLACP state

DCNS05:	.DMACP,,DCNACP
	.DMNAM,,ACPNAM
	.DMSTS,,DCNSTS
	 0
SUBTTL	Active Task state initialization routines

;Active Task initialization for .LLCFG state

DCNI00:	MOVEI	S1,DAPSIZ		;Clear Config storage
	MOVEI	S2,DAPBEG		;...
	$CALL	.ZCHNK			;...
	MOVEI	S1,DPMXM		;Store maximum message size
	MOVEM	S1,OURSIZ
	$CALL	SNDCFG			;Send config message
	$RETT
SUBTTL	DCNMSG	Active Task message processing routine

DCNMSG:	$CALL	SNDQUE			;Dump the send queues
	TXZN	S,S%INIT		;State just change?
	JRST	DCNMS1			;No..check for messages
	HRRZ	S1,DCNMLS(S)		;Get initialization address
	JUMPE	S1,DCNMS1		;State initialization routine?
	$CALL	0(S1)			;Yes..Call it

DCNMS1:	TXNN	S,S%PUT			;Doing a PUT?
	JRST	DCNMS2			;No..wait for message
	SKIPGE	MSGFLG			;Have I recieved a message?
	JRST	[$CALL	LLCHK			;Yes..Check link status
		 SKIPGE MSGFLG			;Is there a message there?
		 JRST	DCNMS2			;Yes..go recieve it
		 JRST	.+1]			;No..continue in line
	$CALL	FILGET			;Send a record
	 $RETIF				;Return failing status
	TXNN	S,S%EOF			;Seen EOF?
	JRST	DCNMS1			;No..send the next record
	$RETT				;Yes..return to caller

DCNMS2:	HLRZ	S1,DCNMLS(S)		;Get message list address
	$CALL	GETMSG			;Read the message
	 $RETIF				;Return failing status
	$CALL	0(S1)			;Call message processor
	 $RETIF				;Return failing status
	TXZN	S,S%RETN		;Return to caller?
	JRST	DCNMSG			;No..Back to get next message
	$RETT
SUBTTL	DCNCFG	Routine to process Config message

DCNCFG:	$CALL	VALCFG			;Validate the Config
	 $RETIF				;Return failing status
	$STATE	.LLACC			;Move to next state
	TXO	S,S%RETN		;Return to caller
	$RETT
SUBTTL	DCNNAM	Routine to process Name message


ATTNAM:	$CALL	VALNAM			;Validate the message
	 $RETIF				;Return failing status
	TXNE	S1,NA$FSP		;Filespec?
	JRST	DCNNA1			;Yes..Call user with the message
	$CALL	DCNATR			;Call user with our attributes
ACPNAM:	MOVNS	.DPTYP(DL)		;Request Reparse of this message
	TXO	S,S%RETN		;Return to caller
	$RETT

DCNNAM:	$CALL	VALNAM			;Validate the name
	 $RETIF				;Return failing status
DCNNA1:	HRLZ	S1,S1			;Put flags in left half of S1
	HRRI	S1,.DMNAM		;Identify name message
	$CALL	DCNRTN			;Call user routine
	$RETT				;Return success

SUBTTL	ATTACK	Routine to process ACK for Attributes message
SUBTTL	CTLACK	Routine to process ACK for Control message

ATTACK:	MOVX	S1,.DMACK		;Get ack message type
	MOVEI	S2,ATTFDB		;Point to FDB
	$CALL	DCNRTN			;Call user routine
CTLACK:	TXO	S,S%RETN		;Return to caller
	$RETT				;Return success



SUBTTL	DCNACP	Routine to process Accomp (Resp)

ATTACP:	$CALL	DCNATR			;Call user with attributes
DCNACP:	TXO	S,S%ACP+S%RETN		;Set Accomp and return flags
	MOVX	S1,.DMACP		;Get message type
	$CALL	DCNRTN			;Call user routine
	$RETT				;Return success


SUBTTL	DCNSTS	Routine to process Status message

DCNSTS:	MOVE	S1,STSCOD		;Get the status code
	MOVE	S2,STSSTV		;Get the extended status
	CAXE	S1,FLD(ER$TRN,ER%MAC)+FLD(ER$EOF,ER%MIC)	;EOF?
	 JRST	DCNSTE			;No..return the status
	TXO	S,S%EOF+S%RETN		;Yes..Set EOF and return flags
	$RETT

DCNSTE:	HRROI	T1,STSTXT		;Point to text storage
	$CALL	TYPSTS			;Expand this error
	TXO	S,S%ERR			;Set remote status error flag
	$RETF

SUBTTL	DCNATR	Routine to call user with received attributes

DCNATR:	MOVEI	S1,.DMATT		;Say we have an attribute msg
	MOVEI	S2,ATTFDB		;Point to the fudged FDB
DCNRTN:	SKIPE	.DFRTN(AP)		;User routine specified?
	$CALL	@.DFRTN(AP)		;Yes..call it
	$RET				;Return TF from user routine
SUBTTL	DCNREC	Active Task routine to receive a file

DCNREC:	MOVEI	S1,ATTMSD		;Clear initial attributes msg
	$CALL	CLRMSG
	MOVE	S1,SRCMOD		;Get our source mode
	SKIPE	S2,.DFRFA(AP)		;Remote switches specified
	$CALL	SETATT			;Yes..setup requested mode
	$CALL	SNDATT			;Send of dummy attributes
	MOVX	S2,FB$GET		;Setup Access message
	MOVEM	S2,ACCFAC		; to allow shared reading
	MOVE	S1,OURDSP		;Setup access display
	MOVEM	S1,ACCDSP		; to request all attributes
	$CALL	SNDACC			;Send out file Access message
DCNR20:	$STATE	.LLACC			;Wait for file attributes
	$CALL	DCNMSG			;Get Servers response
	 $RETIF				;Return failing status

	$CALL	ATLOOK			;Lookup the attributes
	 JUMPF	[SKIPN S1,SRCMOD	;Get source mode
		 $FATAL (Unsupported remote file attributes)
		 $WARN	(File attributes don't match processing mode)
		 PUSH P,ATTMOD(S1)	;Save default destination mode
		 MOVE S2,.DFRFA(AP)	;Setup specified attributes
		 $CALL SETATT
		 POP	P,S2		;Get default destination mode
		 JRST .+1]		;Proceed
	SKIPE	SRCMOD			;Have a source mode
	 JRST	[CAME	S1,SRCMOD	;Yes..see if it matches
		 $WARN	(File attributes don't match processing mode)
		 JRST .+2]		;Proceed
	MOVEM	S1,SRCMOD		;No..store what we have
	SKIPN	DSTMOD			;Have a destination mode?
	MOVEM	S2,DSTMOD		;No..store our default
	$CALL	CHKMOD			;Make sure modes are legal
	 JUMPF	[$FATAL	(Illegal destination processing mode)]
	$CALL	SETOUT			;Setup for local file output
	 JUMPF	[$FATAL (,^E/[-2]/)]
	MOVEI	S1,.DMNAM		;Give caller expanded filespec
	$CALL	DCNRTN
	MOVE	S1,ATTBSZ		;Get attributes byte size
	STORE	S1,.FBBYV+LOCFDB,FB%BSZ	;Save for image mode
	$CALL	SETMOD			;Setup data mode
	 JUMPF	[$FATAL	(Can't establish requested mode for output)]
	$CALL	OPNFIL			;OPEN LOCAL FILE FOR OUTPUT
	 JUMPF	[$FATAL (,^E/[-2]/)]
	$CALL	SNDCTC			;START UP A DATA STREAM
	$STATE	.LLCTL			;Get response to control
	$CALL	DCNMSG			;GET ACK FROM SERVER
	 $RETIF				;Return failing status
	$CALL	SNDCTR			;Start record retrivial
	$STATE	.LLDAT			;Accept Data or Status
	LOAD	S2,LOCDEV,DV%TYP	;GET DEVICE TYPE
	CAIE	S2,.DVTTY		;IS IT A TTY?
	JRST	DCNR30			;NO -- GET FIRST MESSAGE
	MOVX	S1,.CHCRT		;YES - START WITH A <CRLF>
	$CALL	OUTBYT			;Write to terminal
	 $RETIF				;Return the failure on error
	MOVX	S1,.CHLFD		;...
	$CALL	OUTBYT			;Write to terminal
	 $RETIF
DCNR30:	$CALL	DCNMSG			;Process Data until EOF Status
	 $RETIF				;Return failing status
	$CALL	SNDACP			;SEND AN ACCESS COMPLETE MESSAGE
	$STATE	.LLACP			;Wait for Accomp (Resp)
	$CALL	DCNMSG			;GET THE ACCOMP ACK
	 $RETIF				;Return failing status
	$CALL	CLSFIL			;CLOSE OUT LOCAL FILE
	 JUMPF	[$FATAL (,^E/[-2]/)]
	TXNE	S,S%ACP			;Access complete?
	$RETT
	SKIPN	.DFRFA(AP)		;Remote mode specified?
	SETZM	SRCMOD			;No..clear sorce mode
	SKIPN	.DFLFA(AP)		;Local mode specified?
	SETZM	DSTMOD			;No..clear destination mode
	JRST	DCNR20			;Back for next file
SUBTTL	DCNTYP	Active task to type remote files

DCNTYP:	MOVEI	S1,ATTMSD		;Clear initial attributes
	$CALL	CLRMSG
	MOVEI	S1,.MD8			;Pretend user typed /ASCII
	SETZM	S2			;No other attributes
	$CALL	SETATT			;Set up dummy attributes message
	$CALL	SNDATT			;Send of dummy attributes
	MOVEI	S1,.PRIOU		;Output to terminal
	MOVEM	S1,LOCJFN
	MOVX	S1,AF$OPN		;Function is read existing file
	MOVEM	S1,ACCFNC
	MOVX	S1,FB$GET		;SET UP FAC FIELD
	MOVEM	S1,ACCFAC		;TO ALLOW SHARED READING
	MOVX	S1,DI$ATT+DI$NAM	;Display Attributes and name
	MOVEM	S1,ACCDSP
	$CALL	SNDACC			;Send out file Access message
DCNT20:	$STATE	.LLACC			;Get attributes and Ack
	$CALL	DCNMSG			;Get Servers response
	 $RETIF				;Return failing status
	$CALL	ATLOOK			;Find attributes
	 JUMPF	[$FATAL	(Remote file attributes not supported)]
	MOVEM	S1,SRCMOD		;Save the mode
	MOVEM	S2,DSTMOD		;Save default output mode
	CAIE	S2,.MD8			;Destination mode must be ascii
	 $FATAL	(File is not ASCII)
	MOVE	S1,MODTB3(S1)		;Get processor address
	MOVEM	S1,DATDAT		;Save it
	$CALL	SNDCTC			;START UP A DATA STREAM
	$STATE	.LLCTL			;Accept Ack from server
	$CALL	DCNMSG			;Get the Ack
	 $RETIF				;Return failing status
	$CALL	SNDCTR			;Start record retrivial
	$STATE	.LLDAT			;Accept Data or Status
	$CALL	DCNMSG
	 $RETIF				;Return failing status
	$CALL	TSTPRN			;Do CRLF if needed
	$CALL	SNDACP			;SEND AN ACCESS COMPLETE MESSAGE
	$STATE	.LLACP			;Wait for Access complete
	$CALL	DCNMSG			;GET THE ACCOMP ACK
	 $RETIF				;Return failing status
	TXNN	S,S%ACP			;Access complete
	JRST	DCNT20			;No..process next file
	$RETT				;ALL DONE!
SUBTTL	DCNSND	Active task to send files

;DCNSND	Holds these truths to be self evident:

;   1)	The default mode for reading files is /IMAGE if no switches
;	are specified.

;   2)	The local file will be read using the mode specified by the
;	local file switches.

;   3)	If the user specified any remote file switches the file will
;	be created using specified mode.

;   4)	If no remote switches are specified the remote file will be
;	created using the mode of the input file.  If the remote FAL
;	cannot create files in that mode the following occurs:

;	a)  If the local input mode is /ASCII a second try will be made
;	to create the file as if the user had specified /ASCII/VARIABLE
;	on the remote file specification.


DCNSND:	$SAVE	<P1>			;Preserve an AC
	$CALL	SETINP			;Setup for local file input
	 JUMPF	[$FATAL (,^E/[-2]/)]
	MOVEI	S1,.DMNAM		;Signify name message type
	$CALL	DCNRTN			;Give expanded name to caller
	SKIPN	.DFLFA(AP)		;Local file mode specified?
	 JRST	[SETZM SRCMOD		;No..clear requested mode
		 MOVE T1,REMOST		;Talking to TOPS20 or TOPS10?
		 CAIE T1,.OSTP20
		 CAIN T1,.OSTP10
		 JRST	.+1		;Yes..use default mode
		 LOAD T1,.FBBYV+LOCFDB,FB%BSZ	;No..get file bytesize
		 MOVEI S1,.MD1		;Assume image mode
		 CAIE T1,^D7		;Unless bytesize is 7 or 36
		 CAIN T1,^D36
		 MOVEI S1,.MD8		;Use ascii mode
		 MOVEM S1,SRCMOD
		 JRST	.+1]		;Continue
	$CALL	SETMOD			;Setup proper data mode
	 JUMPF	[$FATAL	(Can't establish requested input mode)]
	STORE	S2,ATTBSZ		;Save bytesize for attributes
	MOVX	S1,AT$BSZ		;Set bitsize menu bit
	IORM	S1,ATTMNU	
	$CALL	OPNFIL			;Open in requested mode
	 JUMPF	[$FATAL (,^E/[-2]/)]
	MOVE	S1,SRCMOD		;Get our source mode
	HRLI	P1,(POINT 4)		;Create default mode pointer
	HRRI	P1,MODTB2(S1)		; per source mode
	SKIPN	S1,DSTMOD		;Have a destination mode?
	ILDB	S1,P1			;No..get default
DCNS10:	MOVE	S2,.DFRFA(AP)		;Get remote attributes
	$CALL	SETATT			;Yes..setup attributes
	MOVE	S1,OURDSP		;Send out all supported attribs
	TXZ	S1,DI$NAM		;Except name attributes
	$CALL	SNDDSP			;Send file attributes
	MOVX	S2,FB$PUT		;Setup ACCESS (Create)
	MOVEM	S2,ACCFAC
	MOVX	S1,DI$ATT+DI$NAM	;Request Attributes and name
	MOVEM	S1,ACCDSP
	$CALL	SNDACC			;Send off the Access message
	$STATE	.LLACC			;Accept Ack for Access
	$CALL	DCNMSG			;Get servers response
	JUMPT	DCNS20			;Onward if we received ack

;Here to see if we can try a second default for remote file attributes

	MOVE	T1,S1			;Get the error code
	TXZ	T1,ER%FLD		;Clear field type
	CAXE	T1,FLD(ER$USP,ER%MAC)+FLD(.DMATT,ER%TYP)
	$RETF				;No..return the DAP status
	SKIPE	.DFRFA(AP)		;Remote switches specified?
	 $FATAL	(Remote system does not support requested mode)
	ILDB	S1,P1			;Get the next default
	JUMPN	S1,DCNS10		;Yes..try it out
	 $FATAL	(Remote system does not support default mode)

DCNS20:	$CALL	SNDCTC			;START UP A DATA STREAM
	$STATE	.LLCTL			;Get Ack for Contol
	$CALL	DCNMSG			;GET THE ACK
	 $RETIF				;Get failing status
	$CALL	SNDCTS			;Send ctl msg to start Xmission
	$STATE	.LLACP+S%PUT		;We're doing a PUT
	$CALL	DCNMSG			;Send the data
	 $RETIF				;Get failing status

DCNS50:	$CALL	SNDACP			;SEND AN ACCESS COMPLETE
DCNS70:	$STATE	.LLACP			;Access complete state
	$CALL	DCNMSG			;Get the Accomp (Resp)
	 $RETIF				;Get failing status
	$CALL	CLSFIL			;CLOSE OUT LOCAL FILE
	 JUMPF	[$FATAL	(^E/[-2]/)]
	$RETT				;ALL DONE!
SUBTTL	DCNDEL  ACTIVE TASK TO DELETE A FILE
SUBTTL	DCNEXE	ACTIVE TASK TO EXECUTE A FILE

DCNEXE:	MOVE	S1,OURCAP		;Get capabilities
	TXNN	S1,SY$EXE		;Support submit?
	 $FATAL	(Remote system does not support file submission)
DCNDEL:	MOVX	S1,DI$NAM		;Display file name
	MOVEM	S1,ACCDSP
	$CALL	SNDACC			;SEND ACCESS MESSAGE FOR DELETE
DCND70:	$STATE	.LLACC			;Get Name from Access or Accomp
	$CALL	DCNMSG			;GET THE SERVERS ACCOMP
	 $RETIF				;Get failing status
	 JUMPF	.RETF
	TXNN	S,S%ACP			;Access complete?
	JRST	DCND70			;No..back for next file
	$RETT				;ALL DONE!
SUBTTL	DCNDIR	Active Task routine to process Directory request

DCNDIR:	MOVE	S1,OURCAP		;Get mutual capabilities
	TXNN	S1,SY$DIR		;Support directory?
	JRST	DCNDI2			;No..try anyhow!
	MOVE	S1,OURDSP		;Get mutually supported display
	TXZ	S1,DI$NAM		;Get all except name
	MOVEM	S1,ACCDSP		;Display all
	$CALL	SNDACC			;Send ACCESS (DIRECTORY)
DCNDI1:	$STATE	.LLACC			;Get response from Access
	SETZM	ATTMNU			;Clear attributes menu
	SETZM	DTIMNU			;Clear date/time menu
	SETZM	PROMNU			;Clear protection menu
	$CALL	DCNMSG			;Process the server's responses
	 $RETIF				;Get failing status
	TXNN	S,S%ACP			;Access complete?
	JRST	DCNDI1			;No..back for next file
	$RETT


;Get attributes by Opening file

DCNDI2:	MOVEI	S1,ATTMSD		;Point to attributes message
	$CALL	CLRMSG			;Clear it
	$CALL	QUEMSG			;Send it off
	MOVX	S1,AF$OPN		;Open the file
	MOVEM	S1,ACCFNC
	MOVX	S1,FB$GET		;SET UP FAC FIELD
	MOVEM	S1,ACCFAC		;TO ALLOW SHARED READING
	MOVE	S1,OURDSP		;Request all attributes
	MOVEM	S1,ACCDSP
	$CALL	SNDACC			;Send out file Access message
DCNDI3:	$STATE	.LLACC			;Wait for file attributes
	$CALL	DCNMSG			;Get Servers response
	 $RETIF				;Return failing status
	$CALL	SNDACP			;SEND AN ACCESS COMPLETE MESSAGE
	$STATE	.LLACP			;Wait for Accomp (Resp)
	$CALL	DCNMSG			;GET THE ACCOMP ACK
	 $RETIF				;Return failing status
	TXNN	S,S%ACP			;Access complete?
	JRST	DCNDI3			;No..back for next file
	$RETT
SUBTTL	DCN	Unimplimented functions

DCNREN:	$FATAL	(Function not implimented)
DCNSUB:	$FATAL	(Function not implimented)
DCNPRN:	$FATAL	(Function not implimented)
SUBTTL	VALCFG	Validate contents of a CONFIG message

VALCFG:	MOVX	S1,DPMXM		;Get my maximum message size
	SKIPE	CFGSIZ			;Use it if Config size is zero
	CAMGE	S1,CFGSIZ		;Is config size smallest?
	MOVEM	S1,CFGSIZ		;No..use my maximum size
	MOVE	S1,CFGSIZ		;Compute maximim record size
	MOVEM	S1,OURSIZ		;Save as maximum buffer size
	SUBI	S1,DPMXH-2		; as buffer size minus maximum
	MOVEM	S1,OURMRS		; header size
	SKIPN	S1,CFGOST		;OSTYPE valid?
	$MIERR	.DMCFG,21		;No..illegal field value
	MOVEM	S1,REMOST		;Save remote OSTYPE
	SKIPN	CFGFST			;Filesys field valid?
	$MIERR	.DMCFG,22		;No..illegal field value
	MOVE	S1,CFGVER		;Get Major DAP version
	DPB	S1,[POINT 8,T1,7]	;Assemble version info
	MOVE	S1,CFGECO		;Get minor DAP version
	DPB	S1,[POINT 8,T1,15]
	MOVE	S1,CFGUSR		;Get DAP user version
	DPB	S1,[POINT 8,T1,23]
	MOVE	S1,CFGSFT		;Get DAP software version
	DPB	S1,[POINT 8,T1,31]
	MOVE	S1,CFGUSS		;Get user software version
	DPB	S1,[POINT 4,T1,35]
	CAXLE	T1,DAPVER		;Use lowest version
	MOVX	T1,DAPVER
	MOVEM	T1,OURVER
	DMOVE	S1,CFGCAP		;Get system capabilities
	AND	S1,[CAP1]		;Get logical AND of capabilities
	AND	S2,[CAP2]		; ...
	DMOVEM	S1,OURCAP		;Save as our mutual capabilities
	MOVX	T2,DI$ATT		;Get attributes display bit
	TXNE	S1,SY$PRO		;Support protection attributes?
	TXO	T2,DI$PRO		;Yes..Dont request it's display
	TXNE	S1,SY$DTI		;Support date/time attributes?
	TXO	T2,DI$DTI		;Yes..Dont request it' display
	TXNE	S2,SY$NAM		;Support name message?
	TXO	T2,DI$NAM		;Yes..Dont request it's display
	MOVEM	T2,OURDSP		;Save mutual display bits
	$RETT
SUBTTL	VALATT	Validate contents of an ATTRIBUTES message

VALATT:	MOVE	S1,ATTDAT		;Get DATATYPE field
	TXNN	S1,DT$ASC!DT$IMA	;Ascii or image?
	$MIERR	.DMATT,21		;No..illegal field
	TXNE	S1,DT$EBC!DT$CMP	;Ebcdic or compressed?
	$MUERR	.DMATT,21		;Yes..unsupported attributes
	MOVE	S1,ATTORG		;Get ORG field
	MOVE	S1,ATTRAT		;Get RAT field
	MOVEI	S1,.FBLEN		;Get the size of our FDB
	MOVEI	S2,ATTFDB		;Point to it
	$CALL	.ZCHNK			;Clear it
	MOVE	S1,ATTBSZ		;Save byte size from attributes
	CAILE	S1,^D36			;Too large?
	$MIERR	.DMATT,36		;Yes..return unsupported
	STORE	S1,.FBBYV+ATTFDB,FB%BSZ
	MOVE	T1,ATTMNU		;Get attributes menu
	TXNN	T1,AT$ALQ		;ALQ field present?
	JRST	VALAT1			;No..skip it
	MOVE	S1,ATTALQ		;Number of blocks allocated
	IDIVI	S1,4			; divided by 4
	SKIPE	S2			; rounded up
	ADDI	S1,1			; equals number of pages
	STORE	S1,.FBBYV+ATTFDB,FB%PGC
	SKIPN	S1,ATTBLS		;Block size given?
	MOVEI	S1,^D512		;No..assume 512
	IMUL	S1,ATTALQ		;BLS * ALQ
	STORE	S1,.FBSIZ+ATTFDB	;Is approximate file byte count
VALAT1:	TXC	T1,AT$EBK+AT$BLS+AT$FFB	;Can we compute file byte count?
	TXCE	T1,AT$EBK+AT$BLS+AT$FFB
	JRST	VALAT3			;No..skip it
	MOVE	S1,ATTEBK		;Yes..end of file block
	SUBI	S1,1			; Converted to LBN
	IMUL	S1,ATTBLS		; times bytes per block
	ADD	S1,ATTFFB		; plus first free byte
	STORE	S1,.FBSIZ+ATTFDB	; equals file byte count
VALAT3:	MOVE	S1,ATTFOP		;Save attributes options
	MOVEM	S1,FILFOP
	$STATE	.LLATT			;Move to attributes state
	$RETT
SUBTTL	VALDTI	Validate the contents of DATE/TIME attributes extention

VALDTI:	SKIPN	T1,DTIMNU		;Anything specified?
	$RETT				;No..just return
	MOVE	S1,DTICDT		;Get creation date/time
	TXNE	T1,DA$CDT		;Was it given?
	MOVEM	S1,.FBCRV+ATTFDB	;Yes..store it
	MOVE	S1,DTIRDT		;Get last update date/time
	TXNE	T1,DA$RDT		;Was it specified?
	MOVEM	S1,.FBWRT+ATTFDB	;Yes..store it
	$RETT
SUBTTL	VALPRO	Validate the contents of protection attributes message

VALPRO:	SKIPN	T1,PROMNU		;Get protection menu
	$RETT				;Return if menu is null
	HRROI	S1,PROOWN		;Point to owner field
	TXNE	T1,PR$OWN		;Specified?
	MOVEM	S1,.FBAUT+ATTFDB	;Yes..save as author
	SKIPE	S1,PROSLF		;Get owners protection
	STORE	S1,.FBPRT+ATTFDB,FP%SLF
	SKIPE	S1,PROGRP		;Get group protection
	STORE	S1,.FBPRT+ATTFDB,FP%GRP
	SKIPE	S1,PROWLD		;Get wild protection
	STORE	S1,.FBPRT+ATTFDB,FP%GRP
	$RETT
SUBTTL	VALNAM	Validate the contents of a NAME message

;Returns TRUE	S1/ Flag from name message
;		S2/ Pointer to string

VALNAM:	SKIPN	S1,NAMTYP		;Get the name menu flags
	$MIERR	.DMNAM,20		;Invalid menu
	TXNE	S1,NA$DFS!NA$RFS	;Do we support it?
	$MUERR	.DMNAM,20		;No..unsupported
	TXNE	S1,NA$FSP		;File spec?
	HRROI	S2,NAMFSP		;Yes..point to it
	TXNE	S1,NA$VOL		;Volume (or device)
	HRROI	S2,NAMVOL		;Yes..point to it
	TXNE	S1,NA$DIR		;Directory?
	HRROI	S2,NAMDIR		;Yes..point to it
	TXNE	S1,NA$FNM		;File name?
	HRROI	S2,NAMFNM		;Yes..point to it
	$RETT


SUBTTL	VALCRC	Routine to validate the CRC 

VALCRC:	SKIPT	CRCFLG			;Checking CRC?
	 $RETT				;No..always return true
	MOVE	S1,FILCRC		;Get computed CRC	
	CAME	S1,ACPCRC		;Had better match
	$MCERR	(ER$CRC)		; else bad CRC	
	$RETT
SUBTTL	SNDCFG	Send CONFIG message

SNDCFG:	MOVEI	S1,DPMXM		;Store maximum buffer size
	MOVEM	S1,CFGSIZ
	MOVEI	S1,.OSTP20		;Store operating system type
	MOVEM	S1,CFGOST
	MOVEI	S1,.FST20		;Store file system type
	MOVEM	S1,CFGFST
	MOVEI	S1,.DVMAJ		;Store DAP major version
	MOVEM	S1,CFGVER
	MOVEI	S1,.DVMIN		;Store DAP minor version
	MOVEM	S1,CFGECO
	MOVEI	S1,.DVUSR		;Store DAP user version
	MOVEM	S1,CFGUSR
	MOVEI	S1,.DVSFT		;Store DECnet version
	MOVEM	S1,CFGSFT
	MOVEI	S1,.DVUSF		;Store User DECnet version
	MOVEM	S1,CFGUSS
	DMOVE	S1,[EXP CAP1,CAP2]	;Store our capabilities
	DMOVEM	S1,CFGCAP
	MOVEI	S1,CFGMSD		;Build configuration message
	$CALL	PUTMSG			;Force it out
	$RETT
SUBTTL	SNDACC	Send an ACCESS message

;Accepts	ACCxxx setup by caller and DAPDCN

SNDACC:	MOVE	S1,OURVER		;Get version level check
	MOVX	S2,DI$NAM		;Get bit for name display
	CAMN	S1,[BYTE (8) 4,1,0,2]	;RSX Pseudo 5.3 fal?
	ANDCAM	S2,ACCDSP		;Yes..clear name display bit
	MOVX	S1,POLINI		;Initialize CRC
	MOVEM	S1,FILCRC
	MOVE	S1,OURCAP		;Get mutual capabilities
	MOVX	S2,AO$CRC		;Get bit to request CRC
	TXNE	S1,SY$CRC		;Do we both support CRC?
	 JRST	[SETOM CRCFLG		;Yes..remember to generate it
		 IORM S2,ACCOPT		;Ask FAL to do the same
		 JRST .+1]		;Continue
	MOVEI	S1,ACCMSD		;Point to message descriptor
	$CALL	PUTMSG			;Force it out
	$RETT


SUBTTL	SNDCTC	Send a CONTROL (CONNECT) message

SNDCTC:	MOVEI	S1,CTLMSD		;Point to control message
	$CALL	CLRMSG			;Clear all fields
	MOVX	S2,CF$CON		;Function is start a data stream
	MOVEM	S2,CTLFNC
	MOVX	S2,CT$RAC		;Get Menu bits
	MOVEM	S2,CTLMNU
	MOVX	S2,RB$SQF		;Sequential file transfer
	MOVEM	S2,CTLRAC
	$CALL	PUTMSG			;Force it out
	$RETT
SUBTTL	SNDCTR	Send a CONTROL (GET) message

SNDCTR:	MOVEI	S1,CTLMSD		;Point to control message
	$CALL	CLRMSG			;Clear it out
	MOVX	S2,CF$GET		;Get GET function
	MOVEM	S2,CTLFNC
	MOVX	S2,CT$RAC		;Get menu bits
	MOVEM	S2,CTLMNU
	MOVX	S2,RB$SQF		;Sequential transfer
	MOVEM	S2,CTLRAC		; for Record Access
	PJRST	SNDCTL			;Check to see if block mode ok.
	$RETT


SUBTTL	SNDCTS	Send a CONTROL (PUT) message

SNDCTS:	MOVEI	S1,CTLMSD		;Point to control message
	$CALL	CLRMSG			;Clear it out
	MOVX	S2,CF$PUT		;PUT PUT function
	MOVEM	S2,CTLFNC
	MOVX	S2,CT$RAC		;Get menu bits
	MOVEM	S2,CTLMNU
	MOVX	S2,RB$SQF		;Sequential transfer
	MOVEM	S2,CTLRAC		; for Record Access
	PJRST	SNDCTL			;Check to if block mode ok.

SNDCTL:	SKIPN	.DFLFA(AP)		;User specified mode?
	SKIPE	.DFRFA(AP)
	 PJRST	SNDCT1			;Yes..don't do page mode
	MOVE	S1,REMOST
	CAIE	S1,.OSTP20		;Talking to TOPS20?
	 JRST	SNDCT1			;No..don't do page mode
	MOVE	S1,OURCAP
	TXNN	S1,SY$VBN		;Remote FAL support block mode?
	 JRST	SNDCT1
	MOVE	S1,ATTDEV
	TXNN	S1,FB$MDI		;Remote device DSK?
	 JRST	SNDCT1
	LOAD	S1,LOCDEV,DV%TYP
	CAIE	S1,.DVDSK		;Local device DSK?
	 JRST	SNDCT1
	SETOM	PAGFLG			;Great..use page mode
	SETZM	CTLKEY			;Start with VBN 0 (FDB)
	MOVX	S1,CT$KEY		;Set the menu bit
	IORM	S1,CTLMNU
	MOVX	S1,RB$BKF		;Request block mode
	MOVEM	S1,CTLRAC
	MOVE	S1,[GETPAG,,PUTPAG]	;Setup proper processor
	MOVEM	S1,DATDAT
SNDCT1:	MOVEI	S1,CTLMSD		;Point to the message
	$CALL	PUTMSG			;Send it off
	$RETT
SUBTTL	SNDACK	Send and ACKNOWLEDGE message

SNDACK:	MOVEI	S1,ACKMSD		;Point to ACK message
	$CALL	PUTMSG			;Force it out
	$RETT


SUBTTL	SNDEOF	Send an EOF status message

SNDEOF:	$STATUS	ER$TRN,ER$EOF		;EOF status
	$CALL	SNDSTS			;Send a status message
	$STATE	.LLACP			;Move to access complete state
	$RETT


SUBTTL	SNDSTS	Routine to send a status message

;Accepts	S1/ STATUS CODE
;		S2/ SECONDARY STATUS

SNDSTS:	DMOVE	T1,S1			;Save Calling args
	MOVEI	S1,STSMSD		;Point to status message
	$CALL	CLRMSG			;Clear it out
	MOVEM	T1,STSCOD		;Save status code
	MOVEM	T2,STSSTV		;Save extended status
	$CALL	QUEMSG			;Send it out
	$RETT


SUBTTL	SNDACP	Send an ACCOMP (CLOSE) message


SNDACP:	MOVX	S2,AC$TRM		;Get CLOSE function
	MOVEM	S2,ACPFNC
	$CALL	SNDCRC			;Put CRC into ACP message
	MOVEI	S1,ACPMSD		;Point to message descriptor
	$CALL	PUTMSG			;Force it out
	$RETT				;Return

SNDCRC:	SKIPT	CRCFLG			;Want to send CRC?
	 $RETT				;No..just ruturn
	MOVE	S1,FILCRC		;Yes..get what we computed
	MOVEM	S1,ACPCRC		;Store in the message
	$RETT

SUBTTL	SNDACA	Send an Accomp (Resp) message

SNDACA:	MOVEI	S1,ACPMSD		;Ppoint to message descriptor
	MOVX	S2,AC$ACK		;Get ACK function
	MOVEM	S2,ACPFNC
	$CALL	PUTMSG			;Force it out
	$RETT
SUBTTL	SNDWLD	Routine to send required name messages per WLDJFN

;Accepts	WLDJFN and LOCJFN setup via SETINP

SNDWLD:	$SAVE	<P1>
	MOVE	P1,WLDJFN		;Get change flags
	TXNN	P1,GN%STR		;Structure change?
	 JRST	SNDWL1			;No..check directory
	HRROI	S1,NAMVOL
	HRRZ	S2,LOCJFN
	MOVX	T1,FLD(1,JS%DEV)+JS%PAF	;Send "DEV:"
	JFNS
	 ERJMP	TERCVT			;Return false if error
	MOVX	S1,NA$VOL		;Say it's a volume (structure)
	MOVEM	S1,NAMTYP		;Store Name type
	$CALL	SNDNAM			;Send it off
SNDWL1:	TXNN	P1,GN%DIR		;Directory change?
	JRST	SNDWL2			;No..just send filename
	HRROI	S1,NAMDIR
	HRRZ	S2,LOCJFN
	MOVX	T1,FLD(1,JS%DIR)+JS%PAF	;Send "<Directory>"
	JFNS
	 ERJMP	TERCVT			;Return error if this fails
	MOVX	S1,NA$DIR		;Say its a directory
	MOVEM	S1,NAMTYP
	$CALL	SNDNAM			;Send of the directory
SNDWL2:	HRROI	S1,NAMFNM		;Point to name storage
	HRRZ	S2,LOCJFN
	MOVX	T1,FLD(1,JS%NAM)+FLD(1,JS%TYP)+FLD(1,JS%GEN)+JS%PAF
	JFNS
	 ERJMP	TERCVT
	MOVX	S2,NA$FNM		;Say its a filename
	MOVEM	S2,NAMTYP		;Store the name type
	$CALL	SNDNAM			;Send it off
	$RETT
SUBTTL	SNDDSP	Send requested ATTRIBUTES messages

;Accepts	S1/ Display field from Access message

SNDDSP:	MOVE	S2,CFGVER		;Check for old FAL
	CAIGE	S2,^D5			;Dap 5.1 or later?
	JRST	SNDATT			;No..just send attrubutes
	$SAVE	<P1>			;Preserve P1 for "menu"
	SKIPN	P1,S1			;Put requested fields in P1
	MOVX	P1,DI$ATT		;Default is attributes
	AND	P1,OURDSP		;Clear impossible requests
	TXNE	P1,DI$ATT		;Return Main Attributes message?
	$CALL	SNDATT			;Yes - Send off main attributes
	TXNE	P1,DI$DTI		;Want DATE and Time message?
	$CALL	SNDDTI			;Yes - do it
	TXNE	P1,DI$PRO		;Send Protection message?
	$CALL	SNDPRO			;Yes - do it
	TXNN	P1,DI$NAM		;Want Name stuff?
	$RETT				;No - then just return ok
	MOVX	S1,NA$FSP		;Will send whole filespec
	MOVEM	S1,NAMTYP		;Store argument type
	$CALL	SNDNAM
	$RETT
SUBTTL	SNDATT	Send an attributes message

;SNDATT	is called to send file attributes per this openning of file.
;	Datatype and record formats must be setup by SETBSZ.

;Accepts	ATTxxx setup via GETFDB, SETBSZ and SETATT

SNDATT:	MOVE	S1,ATTMNU		;Get the calling menu
	TXNN	S1,AT$BSZ		;Is BSZ field present?
	JRST	SNDAT2			;No..skip these fields
	LOAD	S2,.FBBYV+LOCFDB,FB%PGC	;Get page count
	IMULI	S2,^D4			;Compute block allocated
	MOVEM	S2,ATTALQ		;ATTALQ=Page_count/4
	LOAD	T2,.FBSIZ+LOCFDB	;Get actual file bytecnt
	LOAD	S1,.FBBYV+LOCFDB,FB%BSZ	;Get actual file bytesiz
	MOVEI	S2,^D36			;
	IDIV	S2,S1			;Compute bytes per word
	IMULI	S2,^D128		;Compute bytes per block
	MOVEM	S2,ATTBLS		;ATTBLS=Bytes_per_word*128
	IDIV	T2,S2			;Compute end block
	ADDI	T2,1			;EBK begins at 1
	MOVEM	T2,ATTEBK		;ATTEBK=File_byte_count/ATTBLS+1
	MOVEM	T3,ATTFFB		;ATTFFB=REM(File_byte_count/ATTBLS)
	MOVX	S1,AT$BLS+AT$ALQ+AT$BSZ+AT$EBK+AT$FFB
	IORM	S1,ATTMNU		;Set proper menu bits
SNDAT2:	MOVEI	S1,ATTMSD		;Point to message
	$CALL	QUEMSG			;Send it out
	$RETT
SUBTTL	SNDPRO	Send File Protection Attributes

;Accepts	LOCFDB setup via GETFDB

SNDPRO:	SETZB	T1,PROMNU		;Clear our menu
	HRRZ	S1,LOCJFN		;Get file JFN
	HRLI	S1,.GFAUT		;Get the file author (Owner)
	HRROI	S2,PROOWN		;Point to storage
	GFUST
	 ERJMP	SNDPR1			;Send null protection
	TXO	T1,PR$OWN		;Set the menu bits
	SKIPN	S1,.FBPRT+LOCFDB	;Get file protection
	JRST	SNDPR1			;Send null protection field
	MOVEM	S1,PROWLD		;Save wild protection
	LSH	S1,-6
	MOVEM	S1,PROGRP		;Save group protection
	LSH	S1,-6
	MOVEM	S1,PROSLF		;Save owner protection
	TXO	T1,PR$SLF+PR$GRP+PR$WLD	;Set the menu bits
SNDPR1:	MOVEM	T1,PROMNU
	MOVEI	S1,PROMSD		;Point to message descriptor
	$CALL	QUEMSG			;Send it off
	$RETT


SUBTTL	SNDDTI	Send Date/time attributes

;Accepts	LOCFDB Setup via GETFDB

SNDDTI:	MOVX	S2,DA$CDT+DA$RDT	;Get menu bits
	SKIPN	S1,.FBCRV+LOCFDB	;Get local creation date/time
	TXZ	S2,DA$CDT		;Clear the menu bit
	MOVEM	S1,DTICDT
	SKIPN	S1,.FBWRT+LOCFDB	;Get last update date/time
	TXZ	S2,DA$RDT		;Clear the menu bit
	MOVEM	S1,DTIRDT
	MOVEM	S2,DTIMNU		;Setup the menu
	MOVEI	S1,DTIMSD		;Point to message descriptor
	$CALL	QUEMSG			;Send it out
	$RETT


SUBTTL	SNDNAM	Send a Name message

;Accepts	NAMxxx setup via GETFDB or SNDWLD

SNDNAM:	MOVEI	S1,NAMMSD		;Point to message descriptor
	$CALL	QUEMSG			;Send it off
	$RETT
SUBTTL	MSGTBL	List of valid DAP messages

;Generate a message table for defined DAP message types
;GETMSG uses this list to accept or reject a specific DAP message type

;Each entry is of the form:

;	Message Type,,Message descriptor address

;Message types are defined in the DOMSG macro of DAPSYM


;Define a macro to build the message table entry
DEFINE	XX (MSG,VAL,NAME,FLAG) <
	.DM'MSG,,MSG'MSD>

;Define a macro to ignore the specific message argument types and version
DEFINE	VV (VER) <>
DEFINE	YY (FLD,TYP,SIZ,DEF) <>

;Expand the list of valid messages

MSGTBL:	DOMSG
	MSG$LN==.-MSGTBL
SUBTTL	GETMSG	Routine to get next DAP message from Link

;Accepts	S1/ Message list address

;Returns TRUE	Message fields stored in respective storage cells
;
;		S1/ Calling message list entry
;		S2/ Parsed message type


;Returns FALSE	S1/ Sync or Unsupported Error code
;		S2/ Parsed message type

GETMSG:	$SAVE	<P2,P1>			;Preserve some AC's
	MOVE	P1,S1			;Remember calling list address
	MOVSI	P2,-MSG$LN		;Get length of table
	$CALL	LLRECV			;Recieve a message
	$CALL	VALHDR			;Validate the header
	 $RETIF				;Return failure if header is bad
	
GETMS1:	HLRZ	S2,MSGTBL(P2)		;Get the message type
	CAMN	S1,S2			;Is it a match?
	JRST	GETMS2			;Yes..process it
	AOBJN	P2,GETMS1		;No..try the next
	$STATUS	ER$USP,0,ER$TYP		;Not found..unsupported message type
	MOVE	S2,.DPTYP(DL)		;Return the message type
	STORE	S2,S1,ER%TYP		;Save in Unsupported status
	$RETF

GETMS2:	SKIPN	S2,0(P1)		;Find message in calling list
	 JRST	[$STATUS ER$SNC,0	;Return SYNC error
		 MOVE S2,.DPTYP(DL)	;Return message type
		 STORE S2,S1,ER%MIC	;Save in DAP status
		 $RETF]			;Return the failure
	HLRZ	S2,S2			;Get the list type
	CAME	S1,S2			;Is it a match?
	AOJA	P1,GETMS2		;No..try the next

GETMS3:	HRRZ	S1,MSGTBL(P2)		;Get message header address
	$CALL	VALMSG			;Validate the message
	 $RETIF				;Return on failure
	HRRZ	S1,0(P1)		;Return calling list entry
	HLRZ	S2,0(P1)		;Return parsed message type
	$RETT				;Return success
SUBTTL	VALHDR	Routine to validate standard dap message header

;Accepts	DL/ Address of current message header

;Creates a new header for this message if more messages follow


;Returns TRUE	S1/ Type field of received message

;	 FALSE	S1/ Message format error status

VALHDR:	SKIPLE	S1,.DPTYP(DL)		;Reparse?
	$RETT				;Yes..just return
	$SAVE	<P1,P2>			;P1 HOLDS FLAGS
	SETZB	P1,P2			;P2 HOLDS LENGTH FIELD
	$CALL	GETBYT			;GET MESSAGE TYPE FIELD
	 JUMPF	[$MFERR 0,10]		;BAD
	MOVEM	S1,.DPTYP(DL)		;STORE MESSAGE TYPE
	MOVEI	S1,5			;Maximum flag size is 5
	MOVEI	S2,.DPFLG(DL)		;Store in DPFLG
	$CALL	GETEXF			;GET HEADER FLAGS
	 JUMPF	[$MFERR 0,10]		;NULL - FAILED
	MOVE	P1,.DPFLG(DL)		;Put the flags in P1
	TXNN	P1,HD$SID		;STREAMID FIELD IN MESSAGE?
	JRST	VALHD1			;NO
	$CALL	GETBYT			;YES..GET IT
	 JUMPF	[$MFERR 0,11]		;FAILED
	MOVEM	S1,.DPSID(DL)		;SAVE IT
VALHD1:	TXNN	P1,HD$LEN		;LENGTH FIELD PRESENT?
	JRST	VALHD2			;NO
	$CALL	GETBYT			;GET IT
	 JUMPF	[$MFERR 0,12]		;FAILED
	MOVE	P2,S1			;SAVE IN P2
	TXNN	P1,HD$LN2		;LENGTH 256 BIT PRESENT?
	JRST	VALHD2			;NO
	$CALL	GETBYT			;GET HIGH ORDER PART
	 JUMPF	[$MFERR 0,13]		;BAD FORMAT
	LSH	S1,10			;MAKE IT HIGH ORDER
	ADD	P2,S1			;ADD TO LOW ORDER PART
VALHD2:	TXNN	P1,HD$BCT		;IS BIT COUNT PRESENT?
	JRST	VALHD3			;NO
	$CALL	GETBYT			;YES..GET IT
	 JUMPF	[$MFERR 0,14]		;BAD FORMAT
	MOVEM	S1,.DPBCT(DL)		;SAVE IT
	CAILE	S1,7			;Within range?
	 $MIERR	(0,14)			;No..return invalid field
	MOVE	S1,.DPTYP(DL)		;Get message type
	CAIA	S1,.DMDAT		;Data message ;**Skip for Kludge
	 $MIERR	(0,14)			;No..return invalid field
VALHD3:	TXNE	P1,HD$SEG		;Segmented message?
	 $MUERR	(0,15)			;Yes..return unsupported
	TXNE	P1,HD$LEN!HD$LN2	;IS MESSAGE BLOCKED?
	CAMN	P2,.DPCNT(DL)		;YES..IS SIZE EXACT?
	JRST	VALHD5			;YES..JUST RETURN
VALHD4:	MOVE	S1,RCVLST		;Message is blocked.
	$CALL	NEWHDR			;Create a new header
	MOVEM	P2,.DPCNT(DL)		;Save actual count
	SUBM	P2,.DPCNT(S2)		;Adjust next message count
	MOVNS	T1,.DPCNT(S2)		;Get positive count
	MOVEM	T1,.DPLEN(S2)		;Save actual length
	ADJBP	P2,.DPBPT(S2)		;Adjust next message pointer
	MOVEM	P2,.DPBPT(S2)		;Save for next parse
	SETZM	.DPTYP(S2)		;Clear next message type
	SETZM	.DPFLG(S2)		;Clear next message flags
	SETZM	.DPBCT(S2)		;Clear next message bitcnt
VALHD5:	MOVE	S1,.DPCNT(DL)		;Set length and count the same
	MOVEM	S1,.DPLEN(DL)
	MOVE	S1,.DPTYP(DL)		;Return current message type
	$RETT

SUBTTL	NEWHDR	Routine to create a new header only

;Accepts	S1/ Send of recieve list address

;Returns TRUE	DL/ Address of new message header
;		S2/ Address of old message header
;		Old header copied to new header

NEWHDR:	MOVEI	S2,.DPSIZ		;Create header entry
	$CALL	L%CBFR			; Before current entry
	HRL	S1,DL			;Source is old header
	HRR	S1,S2			;Dest is new header
	BLT	S1,.DPSIZ-1(S2)		;Copy old header
	EXCH	DL,S2			;Make new header current
	$RETT
SUBTTL	VALMSG	Routine to parse current DAP message

;VALMSG	reads the message descriptor and parses each argument field
;	described in the message descriptor.  The message descriptor
;	is defined using the DOMSG and xxxMSG macros that live in
;	DAPSYM, thus to add another message or field to a message
;	it is only necessary to add the definition to DAPSYM.

;VALMSG	will ensure that the message information is parsed and stored
;	in the appropriate local storage.

;Accepts	S1/ Address of message descriptor

;Returns TRUE	    All message fields stored

;	 FALSE	S1/ Message format error code
;		S2/ Parsed message type

VALMSG:	$SAVE	<P1,P2,P3,P4>
	MOVE	P1,S1			;P1 points to message descriptor
	$DEBUG	(Received ,<^Q/0(P1),RHMASK/ message>)
	MOVE	T1,2(P1)		;Get message flags and fld count
	TXNN	T1,DA%NOZ		;Clear message before recieve?
	$CALL	CLRMSG			;Yes..zero message storage
	MOVX	P3,FLD(ER$FMT,ER%MAC)+FLD(20,ER%FLD) ;Init format error
	HLRZ	S1,0(P1)		;Get message type
	STORE	S1,P3,ER%TYP		;Save message type in error code
	HRLZ	T1,T1			;Get message field count
	JUMPE	T1,VALMS7		;Exit if no message fields
	MOVN	T1,T1			;Negate it to form AOBJN pointer
	HRRI	T1,3(P1)		;Point to first argument
	MOVE	P1,T1			;Put pointer in P1
	SETOM	P2			;Setup initial menu
VALMS1:	MOVE	T1,(P1)			;Get next field type
	TXNN	T1,DA%VER		;Want version check?
	JRST	VALMS2			;No..see if default is present
	ADDI	P1,1			;Yes..point past it
	AOJA	P1,VALMS1		;Get the next field descriptor
VALMS2:	LOAD	S1,T1,DA%SIZ		;Get max size of argument
	LOAD	S2,T1,DA%STG		;Get storage offset for argument
MULINK<	ADD	S2,CP>			;Get actual storage address
	LOAD	P4,T1,DA%TYP		;Get argument type
	TXNN	T1,DA%DEF		;Default present?
	JRST	VALMS3			;No..call the processor
	ADDI	P1,1			;Yes..point to it
	MOVE	T1,0(P1)		;Get the default
	MOVEM	T1,(S2)			;Store it

;VALMSG Continued on next page
;VALMSG Continued from previous page

VALMS3:	TXNN	P2,1			;Is field specified by menu?
	JRST	VALMS5			;No..skip it
	HLRZ	T1,ARGTBL(P4)		;Yes..get processor address
	CAIN	P4,.ARDAT		;Message data field?
	 JRST	VALMS4			;Yes..always call the processor
	SKIPG	.DPCNT(DL)		;No..is field present?
	 TDZA	S1,S1			;No..clear possible menu result
VALMS4:	$CALL	0(T1)			;Yes..call the processor
	 JUMPF	VALMS6			;Return format error if false
VALMS5:	LSH	P2,-1			;Shift menu one place
	CAIN	P4,.ARMNU		;Argument type a menu?
	AND	P2,S1			;Yes..Save selected menu bits
	ADDI	P3,1			;Bump format error to next field
	AOBJN	P1,VALMS1		;Do all fields
	MOVE	T1,.DPTYP(DL)		;Get message type
	CAIE	T1,.DMCFG		;Don't check length for config
	CAIN	T1,.DMDAT		; or data message
	 JRST	VALMS7			;Data will be processed later
	SKIPG	.DPCNT(DL)		;Finished..Everything parse?
	JRST	VALMS7			;Yes..return success
	MOVX	S1,ER$USP		;No..specify Unsupported field
	STORE	S1,P3,ER%MAC
VALMS6:	MOVE	S1,P3			;Get current field format error
	LOAD	S2,S1,ER%TYP		;Extract message type
	$RETF				;Return the failure

VALMS7:	$RETT


SUBTTL	CLRMSG	Routine to clear DAP message storage

;Accepts	S1/ Message descriptor address

CLRMSG:	$SAVE	<S1,S2>			;Preserve scratch AC's
	HRRZ	S2,1(S1)		;Get starting offsett
	HLRZ	S1,1(S1)		;Get size of storage
MULINK<	ADD	S2,CP>			;Get storage address
	$CALL	.ZCHNK
CLRMS1:	$RETT
	
SUBTTL	GETFIX	Routine to process DAP byte arguments

;GETFIX	Get 1 to 4 bytes from DAP message

;Accepts	S1/ number of bytes to retrieve
;		S2/ destination address

;Returns	S1/ result (bytes stored right to left)
;		S2/ destination address

GETFIX:	CAIL	S1,1			;Check range
	CAILE	S1,4
	 $RETF				;Return failure
	MOVE	T1,S1			;Save byte count
	$CALL	GETBYT			;Get byte from message
	 $RETIF				;Return on failure
	MOVE	T2,S1			;Put byte in T2
	SOJE	T1,GETFI1		;Exit if count is zero
	$CALL	GETBYT
	 $RETIF
	DPB	S1,[POINT 8,T2,27]	;Store next byte
	SOJE	T1,GETFI1		;Exit if count is zero
	$CALL	GETBYT			;Get next byte
	 $RETIF				;Return on failure
	DPB	S1,[POINT 8,T2,19]	;Store next byte
	SOJE	T1,GETFI1		;Exit if count is zero
	$CALL	GETBYT
	 $RETIF				;Return on failure
	DPB	S1,[POINT 8,T2,11]	;Store this byte
GETFI1:	MOVEM	T2,(S2)			;Store the result
	MOVE	S1,T2			;Return answer in S1
	$RETT

;GETBYT	is the lowest level routine called in message parsing
;	It is called to return a single DAP message byte

;Returns TRUE	S1/ 8 bit byte from message

;	 FALSE	S1/ 0 (no more bytes in current message)

GETBYT:	SOSGE	.DPCNT(DL)		;Is byte available?
	 JRST	[SETZM S1		;No..Clear our answer
		 $RETF]			;Return a failure
	ILDB	S1,.DPBPT(DL)		;Yes..return the byte
	$RETT
SUBTTL	GETVAR	Routine to process DAP variable length arguments

;GETVAR	Get variable length ascii field from DAP message
;	Field is stored as an Asciz string

;Accepts	S1/ Maximum size of argument
;		S2/ Storage address

;Returns	S1/ Actual size of argument
;		S2/ Storage address

GETVAR:	MOVE	T1,S1			;Put count in T1
	$CALL	GETBYT			;Get the count byte
	 $RETIF				;Return on failure
	CAMLE	S1,T1			;Check length of field
	$RETF				;Argument to long
	$SAVE	<S1,S2>			;Save returning arguments
	HRLI	S2,(POINT 7)		;Point to destination
	SKIPN	T1,S1			;Put actual count in T1
	JRST	GETVA2			;Exit on null count
GETVA1:	$CALL	GETBYT			;Get a byte from message
	 $RETIF				;Return on failure
	IDPB	S1,S2			;Store the byte in message
	SOJG	T1,GETVA1		;Get all the bytes
GETVA2:	IDPB	T1,S2			;Store a null
	$RETT				;Return
SUBTTL	GETINT	Routine to process DAP integer arguments

;GETINT	Get variable length integer field from DAP message

;Accepts	S1/ Maximum size of field
;		S2/ Storage address

;Returns	S1/ Argument low order bits
;		S2/ Argument high order bits

GETINT:	HRR	T4,S2			;Save original address
	HRL	T4,S1			;Save original count
	SETZB	T1,T2			;Clear the result
	$CALL	GETBYT			;Get the count byte
	 $RETIF				;Return on failure
	JUMPE	S1,GETIN1		;Exit on null count
	CAIG	S1,^D9			;Argument length ok?
	CAMLE	S1,.DPCNT(DL)		;Enough bytes left?
	$RETF				;No..return the error
	MOVE	T3,S1			;Store the actual length
	$CALL	GETBYT			;Get the least significant byte
	DPB	S1,[POINT 8,T1,35]	;Store it
	SOJE	T3,GETIN1		;Exit if count is zero
	$CALL	GETBYT			;Get the next byte
	DPB	S1,[POINT 8,T1,27]	;Store it
	SOJE	T3,GETIN1		;Exit if count is zero
	$CALL	GETBYT			;Get the next byte
	DPB	S1,[POINT 8,T1,19]	;Store it
	SOJE	T3,GETIN1		;Exit if count is zero
	$CALL	GETBYT			;Get the next byte
	DPB	S1,[POINT 8,T1,11]	;Store it
	SOJE	T3,GETIN1		;Exit if count is zero
	$CALL	GETBYT			;Get the next byte
	DPB	S1,[POINT 4,T1,3]	;Store 4 bits
	LSH	S1,-4			;Get the next 4
	DPB	S1,[POINT 4,T2,35]	;Store them
	SOJE	T3,GETIN1		;Exit if count is zero
	$CALL	GETBYT			;Get the next byte
	DPB	S1,[POINT 8,T2,31]	;Store it
	SOJE	T3,GETIN1		;Exit if count is zero
	$CALL	GETBYT			;Get the next byte
	DPB	S1,[POINT 8,T2,23]	;Store it
	SOJE	T3,GETIN1		;Exit if count is zero
	$CALL	GETBYT			;Get the next byte
	DPB	S1,[POINT 8,T2,15]	;Store it
	SOJE	T3,GETIN1		;Exit if count is zero
	$CALL	GETBYT			;Get the next byte
	DPB	S1,[POINT 8,T2,7]	;Store it
GETIN1:	DMOVE	S1,T1			;Return the result
	MOVEM	S1,0(T4)		;Save low order part
	HLRZ	T3,T4			;Get argument length
	CAIL	T3,^D5			;Want a high order part?
	MOVEM	S2,1(T4)		;Save high order part
	$RET
SUBTTL	GETPRO	Routine to get Protection field from DAP message

;GETPRO	Get 3 byte extensible protection field from message
;	and store in internal format

;Accepts	S1/ Size of protection field (3)
;		S2/ Storage address

;Returns	S1/ Internal protection right justified
;		S2/ Storage address


GETPRO:	PUSH	P,S2			;Save storage address
	$CALL	GETEXF			;Process as extensible field
	MOVX	S2,77			;Assume full access allowed
	TXNE	S1,PR$DRA		;Allow read access?
	TXZ	S2,FP%RD		;No..then deny it
	TXNE	S1,PR$DWA		;Allow write access?
	TXZ	S2,FP%WR		;No..then deny it
	TXNE	S1,PR$DEA		;Allow execute access?
	TXZ	S2,FP%EX		;No..then deny it
	TXNE	S1,PR$DAA		;Allow append access?
	TXZ	S2,FP%APP		;No..then deny it
	TXNE	S1,PR$DLA		;Allow directory list access?
	TXZ	S2,FP%DIR		;No..then deny it
	CAIE	S2,77			;Anything denied?
	TXZ	S2,1			;Yes..clear LSB
	MOVE	S1,S2			;Put internal protection in S1
	POP	P,S2			;Restore storage address
	MOVEM	S1,(S2)			;Store the result
	$RET				;Return True/false per result
					; of GETEXF call
SUBTTL	GETEXF	Routine to process DAP extensible fields
SUBTTL	GETMNU	Routine to process DAP extensible menu fields

;GETEXF	Reads an extensible field from DAP message
;Extensible fields are stored right justifed and may be up to
;70 information bits in length (10 dap bytes)
;The Extention bits are not stored in the extensible field

;Accepts	S1/ Maximum size of field
;		S2/ Storage address

;Returns	S1/ Low order bits of extensible field
;		S2/ High order bits of extensible field

GETMNU:
GETEXF:	SETZB	T1,T2			;Clear result
	SETZM	T3			;Clear counter
	MOVE	T4,S1			;Save maximum size
GETEX1:	$CALL	GETBYT			;Get the low order byte
	 $RETIF				;Return on error
	CAILE	T3,^D10			;Done too much?
	 $RETF				;Yes..return failure
	DPB	S1,EXFTBL(T3)		;Store the byte
	CAIN	T3,5			;Doing 1 bit entry?
	JRST	GETEX2			;Yes..store next 6 bits
	TXNN	S1,DP$EXF		;No..Extended?
	JRST	GETEX3			;No..check the result
	AOJA	T3,GETEX1		;Get next byte

GETEX2:	ADDI	T3,1			;Get next pointer
	LSH	S1,-1			;Get next 6 bits
	DPB	S1,EXFTBL(T3)		;Store them
	TXNE	S1,DP$EXF/2(T3)		;Extended?
	AOJA	T3,GETEX1		;Yes..do the next byte

GETEX3:	CAILE	T3,1(T4)		;Done too many bytes?
	$RETF				;Yes..return failure
	MOVEM	T1,0(S2)		;Store low order bits
	CAILE	T4,5			;Double word value?
	MOVEM	T2,1(S2)		;Yes..store high order bits
	DMOVE	S1,T1			;Return result in S1-S2
	$RETT

EXFTBL:	POINT 7,T1,35			;Byte 0 (bits 1-7)
	POINT 7,T1,28			;Byte 1
	POINT 7,T1,21			;Byte 2
	POINT 7,T1,14			;Byte 3
	POINT 7,T1,7			;Byte 4
	POINT 1,T1,0			;Byte 5 (bit 7)
	POINT 6,T2,35			;Byte 5 (bits 1-6)
	POINT 7,T2,29			;Byte 6 (bits 1-7)
	POINT 7,T2,22			;Byte 7
	POINT 7,T2,15			;Byte 8
	POINT 7,T2,8			;Byte 9
	POINT 2,T2,1			;Byte 10 (Bits 6-7)
SUBTTL	GETDTI	Routine to process Date/time field in DAP message

;GETDTI	Gets an 18 byte date time field stored as dd-mmm-yyyy hh:mm
;	and stored the field in standard internal format

;Accepts	S1/ Argument size (18)
;		S2/ Storage address

;Returns	S1/ Internal Date/time
;		S2/ Storage address

GETDTI:	CAMLE	S1,.DPCNT(DL)		;Enough room in message?
	$RETF				;No..return failure
	PUSH	P,S2			;Save storage address
	MOVEI	S2,MSGJNK		;Point to temporary string
	HRLI	S2,(POINT 7)		;Generate pointer
	MOVE	T1,S1			;Move count to T1
	$CALL	GETVA1			;Extract bytes from message
	 JUMPF	GETDT1			;Return False on failure
	HRROI	S1,MSGJNK		;Point to string
	MOVX	S2,IT%NNM!IT%AIS!IT%AAC!IT%NTM!IT%NTZ
	IDTIM				;Convert to internal form
	 MOVX	TF,FALSE		;Indicate failure
	MOVE	S1,S2			;Return result in S1
GETDT1:	POP	P,S2			;Restore storage address
	MOVEM	S1,(S2)			;Store the result
	$RET				;Return TF per results
SUBTTL	GETDAT	Routine to process DATA field from DAP message
REPEAT 0,<

GETDAT:	MOVE	S1,.DPBPT(DL)		;Point to the data
	MOVE	S2,.DPCNT(DL)		;Get remaining count
	SKIPF	CRCFLG			;Computing CRC?
	$CALL	DOCRC			;Yes..process it
	HLRZ	S1,DATDAT		;Get dispatch address
	$CALL	0(S1)			;Call the processor
	$RET	
>
GETDAT:	$RETT				;Data will be processed by
					;  FILPUT
SUBTTL	GETASC	Routine to process ascii data in message

GETASC:	MOVE	S1,ATTRFM		;Get record format
	CAXE	S1,FB$VFC		;Variable with fixed control?
	JRST	GETAS1			;No..standard ascii
	SKIPN	T1,ATTFSZ		;Yes..get fixed control size
	 JRST	GETAS1			;Null fixed size..ignore it
	$CALL	GETBYT			;Just strip the Line seq for now
	 JUMPF	ILLREC			;Illegal record format
	SOJG	T1,.-2			;Get entire fixed header
GETAS1:	$CALL	GETBYT			;Get byte from message
	 JUMPF	GETAS2			;Check for implied CR-LF
	$CALL	OUTBYT			;Write the byte
	 $RETIF				;Return the error on failure
	JRST	GETAS1			;Get the next byte

GETAS2:	MOVE	S1,ATTRAT		;Get file attributes
	TXNN	S1,FB$CR		;Implied CR-LF?
	$RETT				;No..just return
	LDB	S1,.DPBPT(DL)		;Get terminating byte
	MOVEI	S2,1			;Get a one bit
	LSH	S2,0(S1)		;Justify per character
	TXNE	S2,ASCBRK		;Was it a break character?
	$RETT				;Yes..don't append CRLF
GETAS3:	MOVEI	S1,.CHCRT		;Get a CR
	$CALL	OUTBYT			;Write to file
	 $RETIF				;Return the error on failure
	MOVEI	S1,.CHLFD		;Get a LF
	$CALL	OUTBYT
	 $RETIF				;Return the error on failure
	$RETT

ILLREC:	$MTERR	(ER$IRC)		;Illegal record format
SUBTTL	TSTPRN	Routine to do final linefeed for print files

TSTPRN:	MOVE	S1,ATTRAT		;Get record attributes
	TXNE	S1,FB$PRN+FB$FTN	;Print or Fortran format?
	JRST	GETAS3			;Yes..do final <CRLF>
	$RETT				;No..just return
SUBTTL	GETPRN	Routine to process print file format (vax)

GETPRN:	$CALL	GETBYT			;Get the first byte
	 JUMPF	ILLREC			;Illegal record format
	$CALL	GETPR3			;Write prefix
	 $RETIF				;Return the error on failure
	$CALL	GETBYT			;Get postfix byte
	 JUMPF	ILLREC			;Illegal record format
	MOVE	T4,S1			;Remember it
GETPR1:	$CALL	GETBYT			;Get byte from message
	 JUMPF	GETPR2			;Do post fixup
	$CALL	OUTBYT			;Write the byte
	 $RETIF				;Return the error on failure
	JRST	GETPR1			;Get the next byte
GETPR2:	MOVE	S1,T4			;Get post fixup character
GETPR3:	SKIPN	T1,S1			;Put character in T1
	JRST	GETPR4			;Just write a null
	TXNE	S1,200			;Count of linefeeds?
	TDZA	T1,T1			;No..clear the count
	MOVEI	S1,.CHLFD		;Get the character
	TXZN	S1,140			;8 bit control character?
	TXZ	S1,200			;No..clear MSB
GETPR4:	$CALL	OUTBYT			;No..just store the character
	 $RETIF				;Return the error on failure
	SOJG	T1,GETPR4		;Repeat until finished
	$RETT
SUBTTL	GETFTN	Routine to process fortran file format (vax)

GETFTN:	$CALL	GETBYT			;Get the first byte
	 JUMPF	ILLREC			;Illegal record format
	$CALL	GETFT3			;Write prefix
	 $RETIF
	$CALL	GETBYT			;Get postfix byte
	 JUMPF	ILLREC			;Illegal record format
	MOVE	T4,S1			;Remember it
GETFT1:	$CALL	GETBYT			;Get byte from message
	 JUMPF	GETFT2			;Do post fixup
	$CALL	OUTBYT			;Write the byte
	 $RETIF				;Return the error on failure
	JRST	GETFT1			;Get the next byte
GETFT2:	MOVE	S1,T4			;Get post fixup character
GETFT3:	SKIPN	T1,S1			;Put character in T1
	JRST	GETFT4			;Just write a null
	TXNE	S1,200			;Count of linefeeds?
	TDZA	T1,T1			;No..clear the count
	MOVEI	S1,.CHLFD		;Get the character
	TXZN	S1,140			;8 bit control character?
	TXZ	S1,200			;No..clear MSB
GETFT4:	$CALL	OUTBYT			;No..just store the character
	 $RETIF				;Return the error on failure
	SOJG	T1,GETFT4		;Repeat until finished
	$RETT
SUBTTL	GETPAG	Routine to get a file page from DAP message

;GETPAG is called to create a filepage whose VBN is in DATRCN from
;	the data in this message.  Trailing zero words need not be
;	part of the data message.

; If VBN is 0 the file FDB will be transferred.  VBN is the LBN +1.
; 

GETPAG:	$SAVE	<P1,P2,P3>
	SKIPN	P3,DATRCN		;Get Requested VBN
	JRST	GETPA3			;Zero is special case for FDB
	SUBI	P3,1			;Convert to file page number
	LSH	P3,-^D2	
	$CALL	M%NXPG			;Get a page for the file
	MOVE	P2,S1			;Remember page number
	LSH	S1,^D9			;Convert to address
	MOVE	P1,S1			;Save the address
	HRLI	P1,-PAGSIZ		;Build AOBJN pointer
	SETZM	0(P1)			;Create the page
	SETZM	.DPBCT(DL)		;Clear starting bitcount
GETPA1:	MOVEI	S2,^D36			;Get a word from the messagee
	$CALL	GETBCT
	 JUMPF	GETPA2			;Finished if zero words are missing
	MOVEM	S1,0(P1)		;Save the word for file
	AOBJN	P1,GETPA1		;Finish the page
GETPA2:	SKIPLE	.DPCNT(DL)		;Make sure byte count is exausted
	 JRST	ILLREC			;Else return illegal record format
	MOVE	S1,P2			;Get page number
	HRLI	S1,.FHSLF		;Map from process to file
	MOVE	S2,P3			;Get the file page number
	HRL	S2,LOCJFN
	MOVX	T1,PM%WR+PM%RD+PM%EX	;Set appropriate access bits
	PMAP
	 ERJMP	TERCVT			;Return the error
	MOVE	S1,P2			;Release the page
	$CALL	M%RELP
	$RETT

GETPA3:	$SAVE	<.FBAUT+ATTFDB>		;Save author if any from Attributes
					;Replace rest of FDB from data message
	MOVSI	P1,-.FBLEN		;Get length of the FDB
	HRRI	P1,ATTFDB		;Point to it
	SETZM	.DPBCT(DL)		;Clear initial bit count
GETPA4:	MOVEI	S2,^D36			;Get an FDB word
	$CALL	GETBCT
	 JUMPF	GETPA5			;Premature end of FDB
	MOVEM	S1,0(P1)		;Store the word
	AOBJN	P1,GETPA4		;Get all the words
GETPA5:	SETZM	.DPCNT(DL)		;Ignore short or long FDB
	$RETT				;Return
SUBTTL	GETIMG	Routine to process image bit stream in data message

;GETIMG	Processes an image mode bit stream in the DAP message and
;	turns it into a byte stream which is stored on disk.  This
;	routine is the standard routine called to Unpack n-bit
;	bytes from the DAP  message.  The routine supports 4 record
;	formats and stores the information on disk in the following
;	manner:

; UDF	<Data...Data>
; FIX	<Data...Data>
; VAR	<Cnt(LSB)><Cnt(MSB)><Data...Data>
; VFC	<Hdr(LSB)..Hdr(MSB)><Cnt(LSB)><Cnt(MSB)><Data...Data>

;The actual bytesize of the image mode bit stream in the message
;is specified in the attributes message that proceeds the data.

GETIMG:	$SAVE	<P1,P2>			;Save some AC's
	MOVE	P2,ATTBSZ		;P2 gets size of bitstream
	MOVE	S1,.DPCNT(DL)		;Get remaining count
	IMULI	S1,^D8			;Get number of bits
	IDIV	S1,P2			;Compute bitcount
	CAME	S2,.DPBCT(DL)		;Is it correct?
	 $MFERR	(.DMDAT,14)		;No..invalid format
	MOVE	P1,S1			;P1 gets count of bytes
	SETZM	.DPBCT(DL)		;Bitcount must start at 0
	MOVE	S1,ATTRFM		;Get record format
	CAIE	S1,FB$FIX		;Fixed record format?
	CAIN	S1,FB$UDF		; or Undefined record format?
	JRST	GETIM3			;Yes..just store the data
	CAIN	S1,FB$VAR		;Variable?
	JRST	[SKIPLE MCYIDX		;Yes..doing MACY11 mode?
		 $CALL ALNMCY		;Yes..align on even byte
		 JRST GETIM2]		;Process variable records
	SKIPN	S1,ATTFSZ		;Fixed header size?
	JRST	GETIM2			;No..process as variable.
	SUB	P1,S1			;Yes..subtract the fixed size
	PUSH	P,P1			;Save variable portion count
	MOVE	P1,S1			;Store the fixed part
GETIM1:	MOVE	S2,P2			;Get the bytesize
	$CALL	GETBCT			;Get the first byte
	 JUMPF	[POP P,P1		;Restore the stack
		 $RET]			;Return the error
	$CALL	OUTBYT			;Write the byte
	 $RETIF				;Return the error on failure
	SOJG	P1,GETIM1		;Finish the fixed part
	POP	P,P1			;Restore variable count
GETIM2:	MOVE	S1,P1			;Write the record count
	$CALL	OUTBYT
	 $RETIF				;Return the error on failure
	CAIL	P2,^D12			;Small bytes?
	JRST	GETIM3			;No..Don't write second byte
	MOVN	S2,P2			;Yes..Get shift value
	LSH	S1,0(S2)		;get the second byte
	$CALL	OUTBYT			;Write the MSB of count
	 $RETIF				;Return the error on failure
GETIM3:	SOJL	P1,GETIM4		;Finish when count expired
	MOVE	S2,P2			;Get the Attributes byte size
	$CALL	GETBCT			;Get the bit stream
	 $RETIF				;Return the error
	$CALL	OUTBYT			;Write the byte to file
	 $RETIF				;Return the error on failure
	JRST	GETIM3			;Get the next word

GETIM4:	$RETT				;Return to caller
SUBTTL	GETBCT	Routine to return bitstream from DAP message

;Accepts	S2/ Bytesize (1-36)

;Returns TRUE	S1/ Byte right justified

GETBCT:	CAIN	S2,^D8			;Nice bytesize?
	JRST	[$CALL	GETBYT		;Yes, get one and return
		 $RETIT			; Success if one was found
		 JRST	ILLREC]		;Else return failure
	SETZ	T4,			;Clear result
	MOVE	T3,[POINT 8,T4,35]	;Get pointer to result
	SKIPN	T1,.DPBCT(DL)		;Residual bit count?
	JRST	GETBC1			;no..start at byte boundry
	HLLZ	T2,BCTTBL(T1)		;Get pointer adjustment
	ADD	T2,.DPBPT(DL)		;Get pointer to bits
	LDB	T4,T2			;Put them in answer
	DPB	T1,[POINT 6,T3,5]	;Pos = Bitcount
	SUB	S2,T1			;Get remaining bits
	JUMPLE	S2,GETBC4		;None left to get
GETBC1:	IDIVI	S2,^D8			;Get S2 bytcnt T1 Bitcnt
	JUMPE	S2,GETBC3		;Any full bytes to do?
GETBC2:	$CALL	GETBYT			;Yes..Get a byte
	 JUMPF	ILLREC			;Illegal record format
	DPB	S1,T3			;Store in result
	ADD	T3,[100000,,0]		;Say we stored 8 bits
	SOJG	S2,GETBC2		;Get next full byte
GETBC3:	JUMPE	T1,GETBC4		;Any residual bits?
	$CALL	GETBYT			;Yes..get them
	 JUMPF	ILLREC			;Illegal record format
	DPB	T1,[POINT 6,T3,11]	;Size = Bitcount
	DPB	S1,T3			;Store the odd bytes
	HRRE	S2,BCTTBL(T1)		;Get residual bitcnt
GETBC4:	MOVNM	S2,.DPBCT(DL)		;Store it
	MOVE	S1,T4			;Get the result
	$RETT
SUBTTL	GETDOS	Routine to store MACY11 variable length files

GETDOS:	$SAVE	<P1,P2>			;Preserve some AC's
	MOVEI	S1,1			;Write first sync frame
	$CALL	OUTBYT
	 $RETIF				;Return the error on failure
	MOVEI	S1,0			;Write next sync frame
	$CALL	OUTBYT
	 $RETIF				;Return the error on failure
	MOVE	P1,.DPCNT(DL)		;Get the record count
	MOVEI	S1,4(P1)		;Get count to include header
	MOVEI	P2,1(S1)		;Initialize checksum
	$CALL	OUTBYT			;Store first count byte in file
	 $RETIF				;Return the error on failure
	LSH	S1,-^D8			;Get High order byte
	ADD	P2,S1			;Include in checksum
	$CALL	OUTBYT			;Store in file
	 $RETIF				;Return the error on failure
GETDO1:	$CALL	GETBYT			;Get a byte from the record
	 JUMPF	ILLREC			;Illegal record format
	ADD	P2,S1			;Tally the checksum
	$CALL	OUTBYT			;Write to file
	 $RETIF				;Return the error on failure
	SOJG	P1,GETDO1		;Do all record bytes
	MOVN	S1,P2			;Negate checsum
	ANDX	S1,377			;Just write 8 bits
	$CALL	OUTBYT			;Store in file
	 $RETIF				;Return the error on failure
	MOVEI	P1,6			;Store 6 null bytes
	MOVEI	S1,0
	$CALL	OUTBYT
	 $RETIF				;Return the error on failure
	SOJG	P1,.-2
	$RETT
SUBTTL	PUTMSG	Routine to build and force a message out

;PUTMSG	Is called to block a message to the end of the existing
;	message queue and then force all messages to be sent

;Accepts	S1/ Address of message descriptor

PUTMSG:	$CALL	QUEMSG			;Do header fixup
	PJRST	SNDQUE			;Empty the queue!


SUBTTL	SNDQUE	Routine to send all messages in the send queue

SNDQUE:	MOVE	S1,SNDLST		;Position to last entry
	$CALL	L%LAST
	 JUMPF	SNDQU2			;Return when finished
	SETZM	.DPLEN(S2)		;Clear to force message out

SNDQU1:	MOVE	S1,SNDLST		;Point to send que
	$CALL	L%FIRST			;Get first message address
	 JUMPF	SNDQU2			;Return when finished
	$CALL	LLSEND			;Send the message
	$CALL	DELMSG			;Delete current message
	JRST	SNDQU1			;Send the rest

SNDQU2:	$RETT				;The queues are empty!

;SUBTTL	DELMSG	Routine to delete current message in the Send Queue

DELMSG:	MOVE	S1,SNDLST		;Delete current send Queue entry
	$CALL	L%DENT
	$RETT
SUBTTL	QUEMSG	Routine to block current message if possible

;QUEMSG	is called to block a message to the existing message queue
;	if possible and then send all but the final message in the
;	message queue

;Accepts	S1/ Address of message descriptor

QUEMSG:	$CALL	BLDMSG			;Build the message
	SKIPG	.DPTYP(DL)		;Valid message?
	 PJRST	DELMSG			;No..delete it and return
	$CALL	BLDHDR			;Build the header
	MOVE	S1,SNDLST		;Get previous entry
	$CALL	L%PREV
	 JUMPF	QUEMS1			;No previous entry
	MOVE	S1,.DPLEN(S2)		;Get previous remaining length
	SUB	S1,.DPCNT(DL)		;May we block this message?
	JUMPLE	S1,[SETZM .DPLEN(S2)	;No..Clear previous length
		    JRST QUEMS1]
	MOVEM	S1,.DPLEN(DL)		;Save new remaining length
QUEMS1:	MOVE	S1,.DPLEN(DL)
	MOVE	S2,.DPFLG(DL)
	CAIL	S1,DPMXH		;May we block current message?
	TXNN	S2,HD$LEN		;...
	SETZB	DL,.DPLEN(DL)		;No..send all messages
QUEMS2:	MOVE	S1,SNDLST		;Yes..send all but current
	$CALL	L%FIRST
	 JUMPF	QUEMS3			;All have been sent!
	CAMN	S2,DL			;Current message?
	JRST	QUEMS3			;All but the last has been sent!
	$CALL	LLSEND			;No..send this message
	$CALL	DELMSG			; Then delete it
	JRST	QUEMS2			;Do all except last message

QUEMS3:	$RETT				;Return
SUBTTL	BLDMSG	Routine to build a DAP message

;BLDMSG	is called to construct a DAP message from the message descriptor
;	storing all requested fields in the DAP message.  BLDMSG checks
;	the version check words from the message descriptor to ensure
;	that extra fields known locally are not sent to a DAP implimen-
;	tation that doesn't understand them

;Accepts	S1/ Address of message descriptor

BLDMSG:	$SAVE	<P1,P2>
	MOVE	P1,S1			;P1 points to message descriptor
	$DEBUG	(Building ,<^Q/0(P1),RHMASK/ message>)
	MOVE	S1,SNDLST		;Allocate a message buffer
	MOVE	S2,OURSIZ		; for largest message
	SUBI	S2,DPMXH-2		;Subtract maximum header size
	$CALL	NEWBUF
	HLRZ	S1,0(P1)		;Store message type
	MOVEM	S1,.DPTYP(DL)		; in message header
	HRLZ	T1,2(P1)		;Get field count
	JUMPE	T1,BLDMS7		;Exit if no message fields
	MOVN	T1,T1			;Make AOBJN pointer
	HRRI	T1,3(P1)		;Point to first argument
	MOVE	T2,OURVER		;Get our version for checking
	TRZ	T2,17			;Clear user version level
	MOVE	P1,T1			;Put pointer in P1
	SETOM	P2			;Set initial menu to all fields
BLDMS1:	MOVE	S1,0(T1)		;Get first argument type
	TXNN	S1,DA%VER		;Version check word?
	JRST	BLDMS2			;No..check next arg
	ADDI	T1,1			;Yes..point to it
	MOVE	T3,0(T1)		;Get the check word
	TXNE	T3,17			;OSTYPE specifed for check?
	 JRST	[XOR T3,REMOST		;Yes..it must match.
		 TXNE T3,17		;did they match?
		 AOJA T1,BLDMS1		;No..skip this check
		 JRST .+1]		;Yes..check it
	CAMLE	T2,T3			;Within our range?
	AOJA	T1,BLDMS1		;Yes..on to get next field
	JRST	BLDMS3			;No..terminate our menu
BLDMS2:	TXNE	S1,DA%DEF		;Default word presnt?
	ADDI	T1,1			;Yes..bump past it
	LSH	P2,1			;Mark a valid menu item
	AOBJN	T1,BLDMS1		;On to finish all fields
BLDMS3:	SETCAM	P2,P2			;Fixup our menu
BLDMS4:	MOVE	T1,0(P1)		;Get argument descriptor
	TXNE	T1,DA%VER		;Is there a version check field?
	JRST	[ADDI P1,1		;Yes..ignore it
		 AOJA P1,BLDMS4]	;Get the next field
	TXNE	T1,DA%DEF		;Is there a default word?
	ADDI	P1,1			;Yes..bump past it
	TXNN	P2,1			;Is menu bit set?
	JRST	BLDMS5			;No..try next field
	LSH	P2,-1			;Yes..get next menu bit
	LOAD	S1,T1,DA%SIZ		;Get Maximum field len
	LOAD	S2,T1,DA%STG		;Get storage offset
MULINK<	ADD	S2,CP>			;Get actual storage address
	LOAD	T1,T1,DA%TYP		;Get the argument type
	CAIN	T1,.ARMNU		;Is argument a menu?
	ANDB	P2,0(S2)		;Yes..remember it
	HRRZ	T1,ARGTBL(T1)		;Get the processor address
	$CALL	0(T1)			;Store the field
	JRST	BLDMS6			;Do the next field
BLDMS5:	LSH	P2,-1			;Get next menu item
BLDMS6:	AOBJN	P1,BLDMS4		;Back for next field
BLDMS7:	$RETT
SUBTTL	BLDHDR	Routine to build header for current message

;Accepts	DL/ Address of current message header

BLDHDR:	MOVE	S1,.DPFLG(DL)		;Get existing flags
	MOVE	S2,.DPCNT(DL)		;Get remaining count
	SUB	S2,.DPLEN(DL)		;Subtract original count
	ADDM	S2,.DPLEN(DL)		;Adjust remaining length
	MOVM	T2,S2			;Remember operand length
	MOVE	T3,OURCAP		;Get mutual capabilities
	SKIPE	.DPBCT(DL)		;Bitcount present?
	TXO	S1,HD$BCT		;Yes..set the flag
	SKIPE	.DPSID(DL)		;Stream ID present?
	TXO	S1,HD$SID		;Yes..set the flag
	CAIG	T2,^D255		;More than 255 bytes?
	JRST	[TXO S1,HD$LEN		;No..set length flag
		 JRST BLDHD1]		;Check blocking support
	TXNE	T3,SY$LN2		;Yes..do we support Len 256?
	TXO	S1,HD$LEN+HD$LN2	;Yes..set both flags
BLDHD1:	TXNN	T3,SY$BLK		;Do we support blocking?
	TXZ	S1,HD$LEN+HD$LN2	;No..Don't send length fields
	MOVEM	S1,.DPFLG(DL)		;Save the flags
	SUBI	S2,2			;Count message type and flags
	TXNE	S1,HD$SID		;Stream Id?
	SUBI	S2,1			;Yes..count it
	TXNE	S1,HD$LEN		;Length field?
	SUBI	S2,1			;Yes..count it
	TXNE	S1,HD$LN2		;Length 256?
	SUBI	S2,1			;Yes..count it
	TXNE	S1,HD$BCT		;Bit count?
	SUBI	S2,1			;Yes..count it
	MOVMM	S2,.DPCNT(DL)		;Save count of bytes in message
	ADJBP	S2,.DPBPT(DL)		;Reset message pointer
	MOVEM	S2,.DPBPT(DL)		;Save for Sending message
	MOVE	T1,.DPTYP(DL)		;Get message type
	IDPB	T1,S2			;Store the message type
	IDPB	S1,S2			;Store the flag byte
	MOVE	T1,.DPSID(DL)		;Get Stream Id
	TXNE	S1,HD$SID		;Want it?
	IDPB	T1,S2			;Yes..store it
	TXNE	S1,HD$LEN		;Want Length field?
	IDPB	T2,S2			;Yes..store it
	LDB	T1,[POINT 8,T2,27]	;Get Length 256 field
	TXNE	S1,HD$LN2		;Want it?
	IDPB	T1,S2			;Yes..store it
	MOVE	T1,.DPBCT(DL)		;Get bitcount field
	TXNE	S1,HD$BCT		;Want it?
	IDPB	T1,S2			;Yes..store it
	$RETT
SUBTTL	PUTFIX	Routine to store 1 to 4 BYTE fields in DAP message

;Accepts	S1/ Number of bytes to store (1 to 4)
;		S2/ Address of word containing bytes (MSB thru LSB)

PUTFIX:	CAIL	S1,1			;Check range
	CAILE	S1,4
	 $CALL	PUTERR			;Die on error
	CAMLE	S1,.DPCNT(DL)		;Check for room
	 $CALL	PUTERR			;Die on error
	MOVE	T1,S1			;Save the count
	MOVE	S1,0(S2)		;Get the argument
PUTFI1:	$CALL	PUTBYT			;Store the byte
	LSH	S1,-^D8			;Get the next byte
	SOJG	T1,PUTFI1		;Do all bytes
	$RETT


SUBTTL	PUTBYT	Routine to store a character in current message

;Accepts	S1/ Character to store in message

PUTBYT:	SOSGE	.DPCNT(DL)		;Any room left in buffer?
	 $CALL	PUTERR			;Die on error
	IDPB	S1,.DPBPT(DL)		;PUT BYTE IN MESSAGE
	$RETT				;AND RETURN

SUBTTL	PUTERR	Routine to die on invalid argument

;PUTERR	is called from PUT??? when bad arguments are encountered
;	or the message buffer is out of room

PUTERR:	$FATAL	(Dap message buffer is full)
SUBTTL	PUTVAR	Routine to store a variable length field in DAP message

;Accepts	S1/ Maximum size of field
;		S2/ Address of ASCIZ string to store

PUTVAR:	MOVE	T4,S1			;Remember maximum size
	CAIG	T4,^D255		;Request too large
	CAML	T4,.DPCNT(DL)		;...
	$CALL	PUTERR			;Yes..return a failure
	HRLI	S2,(POINT 7)
	MOVE	T1,S2			;Save pointer to source
	SETZB	T2,S1			;Clear counts
	$CALL	PUTBYT			;Store null count for now
	MOVE	T3,.DPBPT(DL)		;Remember pointer to count
PUTVA1:	ILDB	S1,T1			;Get source byte
	JUMPE	S1,PUTVA2		;Exit on null
	$CALL	PUTBYT			;Store byte in message
	AOJA	T2,PUTVA1		;Back for next
PUTVA2:	MOVE	S1,T1			;Return updated pointer
	DPB	T2,T3			;Store actual count
	CAMLE	T2,T4			;Within requested size?
	$CALL	PUTERR			;No..return a failure
	$RETT				;Return success
SUBTTL	PUTINT	Routine to store variable length integer

;Accepts	S1/ Maximum size of field
;		S2/ Address of integer to store in message

PUTINT:	MOVE	T4,S1			;Remember maximum size
	CAIG	T4,^D9			;Request too large?
	CAML	T4,.DPCNT(DL)		;...
	$CALL	PUTERR			;Yes..return a failure
	$CALL	PUTBYT			;Write a dummy count
	MOVE	T3,.DPBPT(DL)		;Save the pointer
	MOVE	T2,0(S2)		;Get low order part
	CAIG	T4,4			;Hi order part?
	TDZA	T1,T1			;No..clear holding reg
	MOVE	T1,1(S2)		;Yes..get it
	MOVEI	S2,1			;Get a count of 1
PUTIN1:	MOVE	S1,T2			;Get Least significant byte
	$CALL	PUTBYT			;Store byte from integer
	LSHC	T1,-^D8			;Get next byte
	SKIPN	T1			;Time to quit?
	SKIPE	T2			;...
	AOJA	S2,PUTIN1		;No..do the next byte
	DPB	S2,T3			;Store actual count
	CAMLE	S2,T4			;Within requested size?
	$CALL	PUTERR			;No..return a failure
	$RETT				;Yes..return success
SUBTTL	PUTPRO	Routine to store DAP protection argument

;PUTPRO is called with internal protection code and converts
;	it to DAP protection before sending off the argument

;Accepts	S1/ Maximum size of field (3 bytes)
;		S2/ Address of local protection code

PUTPRO:	SETZM	T1			;Assume all access allowed
	MOVE	T2,0(S2)		;Get argument
	TXNN	T2,FP%RD		;Read access allowed?
	TXO	T1,PR$DRA		;No..deny it
	TXNN	T2,FP%WR		;Write access allowed?
	TXO	T1,PR$DWA!PR$DDA	;No..deny write and delete
	TXNN	T2,FP%EX		;Execute access allowed?
	TXO	T1,PR$DEA		;No..deny it
	TXNN	T2,FP%APP		;Append access allowed?
	TXO	T1,PR$DAA		;No..deny it
	TXNN	T2,FP%DIR		;Directory list access allowed?
	TXO	T1,PR$DLA		;No..deny it
	MOVEI	S2,T1			;Point to extensible field
;	PJRST	PUTEXF			;Send the dap protection
	
SUBTTL	PUTEXF	Routine to store extensible field in Dap message
SUBTTL	PUTMNU	Routine to store DAP extensible fields

;Accepts	S1/ Maximum size of field (1 to 10)
;		S2/ Address of EXARG

;EXARG:	Low order 36 bits of extensible field
;	High order 36 bits of extensible field


PUTMNU:
PUTEXF:	CAMLE	S1,.DPCNT(DL)		;Enough room?
	 $CALL	PUTERR			;No..die on error
	MOVE	T1,0(S2)		;Low order part to T1
	CAIG	S1,5			;More than 5 bytes?
	TDZA	S2,S2			;No..clear high order part
	MOVE	S2,1(S2)		;Yes..high order part to S2
PUTEX1:	MOVEI	S1,177			;Get 7 bit mask
	AND	S1,T1			;Get 7 bits from low order part
	LSHC	S2,-^D7			;Get next 7 bytes 
	SKIPN	S2			;Have more to do after this?
	SKIPE	T1
	TXO	S1,DP$EXF		;Yes..set extension bit
	$CALL	PUTBYT			;Store in the message
	TXNE	S1,DP$EXF		;Anything left?
	JRST	PUTEX1			;Yes..back for next byte
	$RETT
SUBTTL	PUTDTI	Routine to store date time field in DAP message

;Accepts	S1/ Message field size (18)
;		S2/ Address of Date/time word

PUTDTI:	CAIN	S1,^D18			;Proper size?
	CAMLE	S1,.DPCNT(DL)		; and enough room?
	$CALL	PUTERR			;No..return a failure
	MOVE	S2,0(S2)		;Put value in S2
	HRROI	S1,MSGJNK		;Point to temporary storage
	SETZM	T1			;Standard options
	ODTIM				;Generate the date string
	MOVEI	T1,MSGJNK		;Point to the string
	HRLI	T1,(POINT 7)
	MOVEI	T2,^D18			;Store 18 bytes
PUTDT1:	ILDB	S1,T1			;Get a byte
	$CALL	PUTBYT			;Store in message
	SOJG	T2,PUTDT1		;Finish all bytes
	$RETT
SUBTTL	PUTDAT	Routine to store Data field in DAP message

PUTDAT:	$SAVE	<P1,P2>
	MOVE	P1,.DPBPT(DL)		;Get pointer to data
	MOVE	P2,.DPCNT(DL)		;Preserve remaining count
	HRRZ	S1,DATDAT		;Get processor address
	$CALL	0(S1)			;Call the processor
	 $RETIF				;Return error on failure
	DMOVE	S1,P1			;Restore starting pointer and count
	SUB	S2,.DPCNT(DL)		;Compute actual count
	SKIPF	CRCFLG			;Computing CRC?
	$CALL	DOCRC			;Compute the CRC
	$RETT
SUBTTL	DOCRC	Routine to update cumulative CRC for data messages

;ACCEPTS	S1/ Pointer to 8 bit data stream
;		S2/ Byte count


; This routine is used to build the 16-bit CRC checksum character used
; to ensure DAP data integrity.  The CRC is initialized to -1 when a
; file ACCESS is initiated.  Both NFT and FAL compute the CRC on each
; data byte sent or recieved.  When the file is closed the CRC's NFT
; sends the CRC it has generated to the remote system where it must
; match the CRC generated by FAL.

DOCRC:	JUMPLE	S2,.RETT		;Return on null count
	MOVE	T1,FILCRC		;Get current CRC
DOCR1:	ILDB	T2,S1			;Get a byte from message
	XORB	T1,T2			;Include byte in CRC
	ANDI	T2,377			;Compute offset into table
	LSH	T1,-^D8			;Xor remaining CRC from table
	XOR	T1,CRCTAB(T2)		;Compute new CRC
	SOJG	S2,DOCR1		;Do the next
	MOVEM	T1,FILCRC		;Save computed CRC
	$RETT
SUBTTL	CRCTAB	CRC TABLE DEFINITION


	POLY==164405		;X^16+X^15+X^13+X^7+X^4+X^2+X^1+1

	POLINI==177777		;Initial value of -1 (16 bits)


DEFINE BLDCRC <
	LSTOF. XCREF
	ZZ==0
  REPEAT ^D256, <CRC (\ZZ)
		 ZZ==ZZ+1>
	LSTON.
> ;End BLDCRC


DEFINE CRC (BYTE) <
	.CRC=BYTE
REPEAT ^D8,<
	  .X=.CRC&1
	  IFN <.X>,<.CRC=.CRC_-1
		    .CRC=.CRC^!POLY>
	  IFE <.X>,<.CRC=.CRC_-1>>
	EXP .CRC
> ;End CRC


CRCTAB:	BLDCRC			;Generate the table
SUBTTL	PUTASC	ROUTINE TO READ ASCII DATA AND FORMAT AN OUTPUT DAP MESSAGE

;PUTASC	breaks ascii stream text up into records for transmission.
;Break characters are: <ESC><^Z><DC1-4><DLE><FF><VT> and <LF>

	ASCBRK==^B00001100000111110001110000000000

PUTASC:	MOVE	T1,ATTRFM		;Get record format
	MOVE	T2,ATTRAT		;Get record attributes
	SKIPN	T3,ATTMRS		;GET MAXIMUM RECORD SIZE
	MOVE	T3,.DPCNT(DL)		;No MRS..use remaining count
	SETOM	S1			;Say Last character was -1
PUTAS1:	SOSGE	T3			;Any room left?
	JRST	PUTAS4			;No..Check for MRS
	MOVE	T4,S1			;Remember last character stored
PUTAS2:	$CALL	INPBYT			;Get a byte from file
	 JUMPF	PUTAS3			;Check for EOF
	TXNE	T2,FB$CR		;Implied CRLF envelope?
	JUMPE	S1,PUTAS2		;Yes..then strip nulls
	$CALL	PUTBYT			;Store in the message
	CAIL	S1,.CHLFD		;Possible break character?
	CAILE	S1,.CHESC
	JRST	PUTAS1			;No..send next charcter
	MOVEI	S2,1			;Yes..check it out
	LSH	S2,0(S1)		;Justify bit per charcter
	TXNN	S2,ASCBRK		;Break character?
	JRST	PUTAS1			;Not a break..get next character
	CAIN	S1,.CHLFD		;<CRLF>?
	CAIE	T4,.CHCRT
	JRST	PUTAS5			;No..send the record
	TXNN	T2,FB$CR		;Yes..Stripping <CRLF>?
	JRST	PUTAS5			;No..send the record
	MOVEI	S1,2			;Yes..Get 2
	ADDM	S1,.DPCNT(DL)		;Back up count by 2
	MOVNI	S1,2
	ADJBP	S1,.DPBPT(DL)		;Back up pointer by 2
	MOVEM	S1,.DPBPT(DL)
PUTAS5:	$RETT				;Return and send the record

PUTAS3:	$CALL	EOFCHK			;Check error for EOF
	 $RETIF				;Return False on error
	SKIPGE	T4			;Stored any characters?
	SETZM	.DPTYP(DL)		;No..delete this message
	$RETT


PUTAS4:	SKIPE	ATTMRS			;Max record size given?
	$MTERR	ER$IRC			;Yes..bad record format
	$RETT				;No..send the record
SUBTTL	PUTPAG	Routine to store file page in DAP message

;PUTPAG sends a file page whose VBN is in DATRCN.  Trailing zero
;words in the file page are not sent.

PUTPAG:	$SAVE	<P1,P2,P3>		;Preserve some AC's
	SKIPN	P1,DATRCN		;Get requested VBN.
	JRST	PUTP50			;Zero is special case for FDB
	SUBI	P1,1			;Convert to file page address
	LSH	P1,-^D2
	$CALL	M%NXPG			;Get non existant page
	MOVSI	S2,.FHSLF		;Map file page to my process
	HRR	S2,S1
	MOVE	P3,S2			;Remember for unmapping
	EXCH	S1,P1			;Remember process page
	HRL	S1,LOCJFN		;Get JFN,,file page
	MOVX	T1,PM%RD+PM%PLD		;Preload page
	PMAP
	 ERJMP	TERCVT
	LSH	P1,^D9			;Convert P1 to address
	HRLI	P1,-PAGSIZ		;Create AOBJN pointer
	SETZ	P2,			;Clear count of trailing nulls
PUTP10:	SKIPN	S1,0(P1)		;Get a word
	AOJA	P2,PUTP40		;Count a null
	JUMPE	P2,PUTP30		;Any zeros to write?
PUTP20:	SETZ	S1,			;Yes..write them
	MOVEI	S2,^D36
	$CALL	PUTBCT
	SOJG	P2,PUTP20
	MOVE	S1,0(P1)		;Reclaim data
PUTP30:	MOVEI	S2,^D36
	$CALL	PUTBCT			;Write it
PUTP40:	AOBJN	P1,PUTP10		;Write the entire page
	SETOM	S1			;Unmap the file page
	MOVE	S2,P3
	SETZM	T1
	PMAP
	 ERJMP	TERCVT
	MOVEI	S1,-PAGSIZ(P1)		;Release our page
	LSH	S1,-^D9
	$CALL	M%RELP
	$RETT

PUTP50:	$CALL	GETFDD			;Setup actual FDB
	MOVSI	P1,-.FBLEN
	HRRI	P1,LOCFDB
PUTP60:	MOVE	S1,0(P1)		;Send entire FDB
	MOVEI	S2,^D36
	$CALL	PUTBCT
	AOBJN	P1,PUTP60
	$RETT
SUBTTL	PUTIMG	Routine to store n-bit bytes in data message

;This routine is the counterpart for GETIMG.  It reads file bytes
;and stores them in the DAP message as a bitstream whose size is
;determined by the attributes bytesize.

PUTIMG:	$SAVE	<P1,P2,P3>		;Preserve some AC's
	MOVE	S1,ATTRFM		;Get record format
	MOVE	P2,ATTBSZ		;Get attributes bytesize
	CAIN	S1,FB$UDF		;Undefined record format?
	JRST	PUTIM4			;Yes..calculate largest MRS
	CAIN	S1,FB$FIX		;Fixed length?
	JRST	PUTIM5			;Yes..go process it
	CAIE	S1,FB$VAR		;Variable length records?
	SKIPN	P1,ATTFSZ		;No..Zero length VFC?
	JRST	PUTIM2			;Yes..process variable length
PUTIM1:	$CALL	INPBYT			;Get a header byte
	 JUMPF	PUTI10			;See if it's EOF
	MOVE	S2,P2			;Get attributes byte size
	$CALL	PUTBCT			;Store the bitstream
	SOJG	P1,PUTIM1		;Store entire fixed header
	JRST	PUTIM3			;Process the variable count
PUTIM2:	SKIPLE	MCYIDX			;Doing MACY11 file?
	$CALL	ALNMCY			;Yes..align on half-word
PUTIM3:	$CALL	INPBYT			;Get LSB of count
	 JUMPF	PUTI10			;See if it's EOF
	MOVE	P1,S1			;Save it
	CAIL	P2,^D12			;MSB of count present?
	JRST	PUTIM6			;No..go check our count
	$CALL	INPBYT			;Get it
	 JUMPF	PUTI10			;Check for EOF
	LSH	S1,(P2)			;Position MSB of count
	IOR	P1,S1			;Tally the total count
	JRST	PUTIM6			;Check count against MRS
PUTIM4:	MOVE	S1,.DPCNT(DL)		;Get remaining count
	IMULI	S1,^D8			;Get number of remaining bits
	IDIV	S1,P2			;Get bits/bytesize
	MOVE	P1,S1			;Store computed maximum size
	JRST	PUTIM6			;Check against actual maximum
PUTIM5:	SKIPN	P1,ATTMRS		;Get maximum record size
	MOVE	P1,OURMRS		;Use our maximum as default
PUTIM6:	MOVE	P3,P1			;Save requested count
PUTIM7:	$CALL	INPBYT			;get a byte from file
	 JUMPF	PUTIM9			;Check for EOF
	MOVE	S2,P2			;Get the attributes bytesize
	$CALL	PUTBCT			;Store the bit stream
	SOJG	P1,PUTIM7		;Return when count exausted
PUTIM8:	$RETT

;PUTIMG continued on next page
;PUTIMG continued from previous page

PUTIM9:	$CALL	EOFCHK			;EOF while fetching data?
	 $RETIF				;No..return the error
	MOVE	S1,ATTRFM		;Yes..get our record format
	CAIE	S1,FB$VAR		;Is it variable or VFC?
	CAIN	S1,FB$VFC
	 $MTERR	ER$IRC			;Yes..then illegal record
	CAMN	P1,P3			;Have we stored anything?
	SETZM	.DPTYP(DL)		;No..scratch this message
	$RETT				;No..just return

PUTI10:	$CALL	EOFCHK			;EOF looking for Hdr or Cnt?
	 $RETIF				;No..return the faliure
	SETZM	.DPTYP(DL)		;Yes..scatch this message
	$RETT
SUBTTL	PUTBCT	Store image bit stream in DAP message

;Accepts	S1/ right justified byte
;		S2/ byte size (1-36 bits)

PUTBCT:	CAIN	S2,^D8			;Nice byte size?
	PJRST	PUTBYT			;Yes..putone and return
	SKIPN	T1,.DPBCT(DL)		;Any residual bitcount?
	JRST	PUTBC1			;No..start at byte boundry
	HLLZ	T2,BCTTBL(T1)		;Yes..get pointer adjustment
	ADD	T2,.DPBPT(DL)		;Point to residual bits
	DPB	S1,T2			;Store them
	SUB	S2,T1			;Get bits remaining in S1
	JUMPLE	S2,PUTBC4		;All done?
	MOVN	T1,T1			;No..get shift right value
	LSH	S1,0(T1)		;Right justify remaining bits
PUTBC1:	IDIVI	S2,^D8			;Get S2 bytecount T1 bitcount
	JUMPE	S2,PUTBC3		;Any full bytes to send?
PUTBC2:	$CALL	PUTBYT			;Yes..store a byte
	LSH	S1,-^D8			;Get next byte
	SOJG	S2,PUTBC2		;Do them all
PUTBC3:	JUMPE	T1,PUTBC4		;Any odd bits?
	$CALL	PUTBYT			;Yes..store them
	HRRE	S2,BCTTBL(T1)		;Get negitive bitcount
PUTBC4:	MOVNM	S2,.DPBCT(DL)		;Save the bitcount
	$RETT				;All finished

BCTTBL:	000000,,0			;Pointer adjust,,-bitcount
	067100,,-7			;Bytesize==1
	057200,,-6			;Bytesize==2 etc.
	047300,,-5
	037400,,-4
	027500,,-3
	017600,,-2
	007700,,-1			;Bytesize==7 Bitcnt==1
SUBTTL	PUTDOS	Process MACY11 assembler output

;PUTDOS	Processes MACY11 assembler output files and stores
;	them as variable length data.  MACY11 assembler
;	is equivalent in format to PDP21 style paper tape format
;	as follows

;Byte 0	<1>	sync byte
;Byte 1 <0>	null follows sync
;Byte 2 <cnt>	low order of (length of "Data" in bytes)+4=[n]
;Byte 4 <cnt>	high order of (length of "Data in bytes)+4=[n]
;Byte 5	<data>
;Byte n		(last byte of "Data")
;Byte n+1	Checksum byte (Two's complement add with carry ignored)
;		Checksum includes all bytes in record including header

;6 Nulls followed by next record (The nulls are ignored)


PUTDOS:	$SAVE	<P1,P2>			;Save an AC for checksum
PUTDO1:	$CALL	INPBYT			;Get a byte
	 JUMPF	[$CALL EOFCHK		;Check for EOF
		  $RETIF		;Return if not EOF
		 SETZM .DPTYP(DL)	;Else cancel this message
		 $RETT]			;And return
	JUMPE	S1,PUTDO1		;Ignore leading nulls
	CAIE	S1,1			;First byte is <1>
	 JRST	PUTDO4			; Else bad record format
	MOVE	P2,S1			;Initialize checksum
	$CALL	INPBYT			;Get the next byte
	 JUMPF	PUTDO3			;Check EOF and return failure
	JUMPN	S1,PUTDO4		;Second byte is <0>
	$CALL	INPBYT			;Third byte is L.O. count
	 JUMPF	PUTDO3			;Check EOF and return failure
	ADD	P2,S1			;Tally Checksum
	MOVE	P1,S1			;P1 will contain count
	$CALL	INPBYT			;Fourth byte is H.O. count
	 JUMPF	PUTDO3			;Check EOF and return failure
	ADD	P2,S1			;Tally checksum
	DPB	S1,[POINT 8,P1,27]	;Store High order part of count
	SUBI	P1,4			;Subtract four bytes for header
	CAMLE	P1,OURMRS		;Do we have enough room for it?
	 $MTERR	(ER$RTB)		;Nope..record too big!
PUTDO2:	$CALL	INPBYT			;Get next byte
	 JUMPF	PUTDO3			;Check EOF and return failure
	ADD	P2,S1			;Tally checksum
	$CALL	PUTBYT			;Store in message
	SOJG	P1,PUTDO2		;Repeat until count exausted
	$CALL	INPBYT			;Last byte is checksum
	 JUMPF	PUTDO3			;Check EOF and return error
	ADD	P2,S1			;Tally checksum
	TXNE	P2,377			;Are all checksum bits zero?
	JRST	PUTDO4			;No..Bad checksum
	$RETT				;Hurray..We made it!

PUTDO3:	$CALL	EOFCHK			;Check for EOF
	 $RETIF				;Return if file error
PUTDO4:	$MTERR	ER$IRC			;Else return record format error
SUBTTL	SETINP	Setup for local file input

;Accepts	AP/ Address of D$FUNC argument block

;Returns TRUE	S1/ Wild JFN flags
;		S2/ Pointer to expanded filespec


SETINP:	MOVEI	S1,JFNBLK		;Point to GTJFN block
	MOVE	T1,1+OURCAP		;Get second capability word
	MOVX	S2,GJ%OLD		;File must exist
	MOVE	T2,ACCFNC		;Get requested access
	CAIE	T2,AF$DIR		;Directory
	TXNE	T1,SY$WLD		; or do we support wild cards?
	TXO	S2,GJ%IFG+GJ%FLG	;Yes..allow them and get flags
	MOVEM	S2,.GJGEN(S1)		;Save for GTJFN
	MOVE	S2,.DFLFS(AP)		;Get pointer to local file spec
	GTJFN
	 ERJMP	TERCVT			;Convert error and fail
	MOVEM	S1,LOCJFN		;Save JFN and flags
	TXNN	S1,GJ%DEV+GJ%DIR+GJ%NAM+GJ%EXT+GJ%VER ;Anything wild?
	TDZA	S1,S1			;No..clear wild JFN
	TXO	S1,GN%STR+GN%DIR+GN%NAM+GN%EXT	;Mark change flags
	MOVEM	S1,WLDJFN		;Save for message generation
	$CALL	GETDEV			;Get device attributes
	 $RETIF				;Return if this fails
	TXNN	S2,DV%IN		;Can device do input?
	 PJRST	DEVERR			;No..bad device
	JRST	NXTIN1			;Continue after GNJFN

NXTINP:	MOVE	S1,LOCJFN		;Get original JFN
	GNJFN				;Get the next file
	 ERJMP	[$CALL	RELJFN		;No file match..release JFN
		 $RETF]			;Return false
	MOVEM	S1,WLDJFN		;Save state change flags
NXTIN1:	$CALL	GETFDB			;Read FDB and Get byte size
	MOVX	S1,OF%RD		;Get read access bit for open
	MOVEM	S1,OPNFLG		;Save for open
	MOVE	S1,WLDJFN		;Return wild JFN and flags
	HRROI	S2,NAMFSP		;Point to full filespec
	$RETT
SUBTTL	SETOUT	Setup for local file output

;Accepts	AP/ Address of D$FUNC argment block

;Returns	S1/ Local JFN
;		S2/ Pointer to expanded filespec

SETOUT:	MOVEI	S1,JFNBLK		;Point to JFN block
	MOVX	S2,GJ%FOU		;File is for output
	MOVEM	S2,.GJGEN(S1)		;Save the flags
	MOVE	S2,.DFLFS(AP)		;Get pointer to local file spec
	GTJFN				;Find the file
	 ERJMP	TERCVT
	MOVEM	S1,LOCJFN		;Save the JFN
	$CALL	GETDEV			;Get device attributes
	 $RETIF				;Return if this fails
	TXNN	S2,DV%OUT		;Can device do output?
	 PJRST	DEVERR			;No..then fail
	$CALL	GETFDB			;Get the FDB info
	MOVX	S1,OF%WR		;Get write access bit for open
	MOVEM	S1,OPNFLG		;Save for Open
	MOVE	S1,LOCJFN		;Return the JFN
	HRROI	S2,NAMFSP		;Point to full filespec
	$RETT

SUBTTL	OPNFIL	Routine to open the local file


OPNFIL:	HRRZ	S1,LOCJFN		;Get local JFN
	MOVE	S2,OPNFLG		;Get our flags
	OPENF				;Open the file
	 ERJMP	TERCVT			;Return the error
	$RETT				;Return success
SUBTTL	CLSFIL	Routine to close local file and update FDB

CLSFIL:	LOAD	S1,LOCDEV,DV%TYP	;Get device type
	MOVE	S2,OPNFLG		;Get file open flags
	CAIN	S1,.DVDSK		;Is it disk?
	TXNN	S2,OF%WR		; and writing file?
	PJRST	CLSINP			;No..just close it
	SKIPLE	MCYIDX			;Yes..Residual MACY11 byte?
	$CALL	OUTMCD			;Yes..write last word
	MOVX	S1,CO%NRJ		;Don't release JFN
	HRR	S1,LOCJFN
	CLOSF				;Close the file
	 ERJMP	TERCVT
FIXFDB:	MOVX	S1,CF%NUD+<.FBCRV>B17	;Get offset
	MOVX	S2,FWMASK		;set all bits to change
	SKIPE	T1,.FBCRV+ATTFDB	;Get creation date/time
	$CALL	CHNGFD			;Change the FDB
	MOVX	S1,CF%NUD+<.FBWRT>B17	;Get the offset
	SKIPE	T1,.FBWRT+ATTFDB	;Get last update date/time
	$CALL	CHNGFD			;Change the FDB
;	MOVX	S1,CF%NUD+<.FBPRT>B17	;Get the offset
;	MOVX	S2,FP%SLF+FP%GRP+FP%WLD	;Get protection mask
;	SKIPE	T1,.FBPRT+ATTFDB	;Get file protection
;	$CALL	CHNGFD			;Change the FDB
	SKIPT	PAGFLG			;Doing page I/O?
	JRST	CLSFI1			;No..don't change bytecount
	MOVX	S1,CF%NUD+<.FBSIZ>B17	;Get offset for bytecount word
	MOVX	S2,FWMASK		;CHANGE ALL BITS
	SKIPE	T1,.FBSIZ+ATTFDB	;Get file byte count
	$CALL	CHNGFD			;CHANGE THE FDB
	MOVX	S1,CF%NUD+<.FBBYV>B17	;Get offset for bytesize
	MOVX	S2,FB%BSZ		;Change bytesize
	SKIPE	T1,.FBBYV+ATTFDB	;Get file bytesize
	$CALL	CHNGFD			;CHANGE THE FDB
	SKIPT	PAGFLG			;Recieve entire FDB?
	JRST	CLSFI1			;No..don't update remaining info
	MOVX	S1,CF%NUD+<.FBCTL>B17	;Yes..update remaining INFO
	MOVX	S2,FB%FCF		;Get mask for countrol word
	SKIPE	T1,.FBCTL+ATTFDB
	$CALL	CHNGFD
	MOVX	S1,CF%NUD+<.FBBYV>B17	;Update mode and bytesize
	MOVX	S2,FB%BSZ+FB%MOD
	SKIPE	T1,.FBBYV+ATTFDB
	$CALL	CHNGFD
	MOVX	S1,CF%NUD+<.FBCRE>B17	;Update creation date if possible
	MOVX	S2,FWMASK
	SKIPE	T1,.FBCRE+ATTFDB
	$CALL	CHNGFD
	MOVX	S1,CF%NUD+<.FBREF>B17	;Update last reference
	MOVX	S2,FWMASK
	SKIPE	T1,.FBREF+ATTFDB
	$CALL	CHNGFD
;	MOVX	S1,CF%NUD+<.FBCNT>B17	;Update access counts if possible
;	MOVX	S2,FWMASK
;	SKIPE	T1,.FBCNT+ATTFDB
;	$CALL	CHNGFD
	MOVX	S1,CF%NUD+<.FBUSW>B17	;Update user settable word
	MOVX	S2,FWMASK
	SKIPE	T1,.FBUSW+ATTFDB
	$CALL	CHNGFD
CLSFI1:	HRRZ	S1,LOCJFN		;Get file JFN
	MOVE	S2,.DOACT+LLOPNB	;Point to files account
	SACTF				;SET FILE'S ACCOUNT DESIGNATOR
	 ERJMP	RELJFN			;Failed..Release JFN
	HRLI	S1,.SFAUT		;SET THE AUTHOR STRING
	SKIPN	S2,.FBAUT+ATTFDB	;Author specified?
	MOVE	S2,.DOUSR+LLOPNB	;Pickup pointer to user string
	SFUST				;DO IT
	 ERJMP	RELJFN			;Failed..Release JFN
	HRLI	S1,.SFLWR		;SET LAST WRITER
	MOVE	S2,.DOUSR+LLOPNB	;Pickup pointer to user string
	SFUST				;DO IT
	 ERJMP	RELJFN			;Failed..Release JFN
	PJRST	RELJFN			;Release output JFN
SUBTTL	CLSINP	Routine to close input file

CLSINP:	MOVE	S1,LOCJFN		;Input JFN wild?
	TXZE	S1,GJ%DEV+GJ%DIR+GJ%NAM+GJ%EXT+GJ%VER
	TXO	S1,CO%NRJ		;Yes..don't release JFN
	CLOSF				;Always close the file
	 ERJMP	TERCVT
	$RETT

SUBTTL	DELFIL	Routine to delete the local file

DELFIL:	HRRZ	S1,LOCJFN		;Get the local JFN
	TXO	S1,DF%NRJ		;Don't release JFN
	SETZ	S2,			;Default number of generations
	DELF				;Delete it
	 ERJMP	TERCVT			;Convert the error and return
	PJRST	RLNJFN			;Release JFN if not wild

SUBTTL	ABTFIL	Routine to abort local file operation

ABTFIL:	HRRZ	S1,LOCJFN		;GET JFN FOR LOCAL FILE
	TXO	S1,CZ%ABT!CO%NRJ	;ABORT OPERATIONS
	CLOSF				;AND CLOSE THE FILE
	 ERJMP	TERCVT			;Return failure
RLNJFN:	MOVE	S1,LOCJFN		;Get local JFN
	TXNE	S1,GJ%DEV+GJ%DIR+GJ%NAM+GJ%EXT+GJ%VER
	$RETT				;Don't release wild JFN
RELJFN:	HRRZ	S1,LOCJFN		;Get file JFN
	RLJFN				;Release it
	 ERJMP	[CAIE	S1,DESX3	;JFN not assigned?
		 PJRST	TERCVT		;Return failure
		 JRST	.+1]		;Return in line
	SETZM	LOCJFN			;Clear file JFN
	SETZM	WLDJFN			;Clear wild JFN
	$RETT

SUBTTL	CHNGFD	Routine to change a field in output files FDB

;Accepts	S1/ Offset to FDB location,,0
;		S2/ Mask for requested bits
;		T1/ Requested bits

CHNGFD:	HRR	S1,LOCJFN		;Get file JFN
	CHFDB				;Change FDB per S1-T1
	 ERJMP	.RETF			;Pass back failure
	$RETT				;Return success
SUBTTL	EOFCHK	Routine to check for EOF in local file

;Returns TRUE	We are at EOF
;	 FALSE	Some other file error occured

EOFCHK:	$CALL	TERCVT			;Get last error code
	CAXE	S1,FLD(ER$TRN,ER%MAC)+FLD(ER$EOF,ER%MIC)	;EOF?
	 $RETF				;No..give bad return
	TXO	S,S%EOF			;Yes..set EOF flag
	$RETT				;Return true

SUBTTL	INPBYT	Routine to read a byte from file

;Returns TRUE	S1/ Next byte in File
;	 FALSE	    Byte not available

INPBYT:	SKIPE	MCYIDX			;MACY11 mode?
	JRST	INPMCY			;Yes..get a byte
	HRRZ	S1,LOCJFN		;No..get a byte
	BIN
	 ERJMP	TERCVT			;Return failing status
	MOVE	S1,S2			;Return the byte in S1
	$RETT

INPMCY:	AOSN	S2,MCYIDX		;Increment byte index
	JRST	INPMC1			;Read first word of file
	CAIGE	S2,5			;Time for a new word?
	JRST	INPMC2			;No..just return the byte
INPMC1:	HRRZ	S1,LOCJFN		;Yes..get a file word
	BIN
	 ERJMP	TERCVT
	MOVEM	S2,MCYDAT		;Save the word
	MOVEI	S2,1			;Index begins at 1 for byte 1
	MOVEM	S2,MCYIDX		;Save for next pass
INPMC2:	LDB	S1,MCYTBL-1(S2)
	$RETT


MCYTBL:	POINT	8,MCYDAT,17		;MACY11 byte 1
	POINT	8,MCYDAT,9		;MACY11 byte 2
	POINT	8,MCYDAT,35		;MACY11 byte 3
	POINT	8,MCYDAT,27		;MACY11 byte 4
SUBTTL	OUTBYT	Routine to write a byte to file

;Accepts	S1/ Byte to write to file

;Returns TRUE	S1/ Byte that was written
;	 FALSE	    Byte could not be written

OUTBYT:	SKIPE	MCYIDX			;MACY11 mode?
	 JRST	OUTMCY			;Yes..bumble it!
	MOVE	S2,S1			;Get the byte to be written
OUTBY1:	MOVE	S1,LOCJFN		;Get the file JFN
	BOUT				;Write the byte
	 ERJMP	TERCVT			;Return if failure
	MOVE	S1,S2			;Restore the byte
	$RETT

OUTMCY:	AOSN	S2,MCYIDX		;Bump the byte index
	 AOS	S2,MCYIDX		;Once more for first word
	CAIGE	S2,5			;Ready to write word?
	JRST	OUTMC1			;No..just store the byte
OUTMCD:	PUSH	P,S1			;Yes..save our byte
	MOVE	S1,LOCJFN		;Get the file JFN
	MOVE	S2,MCYDAT		;Get our last word
	BOUT				;Write it
	 ERJMP	[POP P,S1		;Fixup the stack
		 PJRST TERCVT]		;And return the failure
	POP	P,S1			;Retrieve our byte
	SETZM	MCYDAT			;Clear our last word
	MOVEI	S2,1			;Index begins at 1
	MOVEM	S2,MCYIDX
OUTMC1:	DPB	S1,MCYTBL-1(S2)		;Store the byte
	$RETT


ALNMCY:	MOVEI	TF,1			;Get a bit
	TDNE	TF,MCYIDX		;Even byte boundry?
	AOS	MCYIDX			;No..Align it
	$RETT
SUBTTL	GETFDB	Routine to read local file FDB and other info

GETFDB:	HRROI	S1,NAMFSP		;Point to filespec storage
	HRRZ	S2,LOCJFN		;Expand this file name
	MOVX	T1,FFSPEC		;Dev:<directory>name.ext.gen
	JFNS
	 ERJMP	TERCVT			;Convert error and return
GETFDD:	HRRZ	S1,LOCJFN		;Get JFN
	HRLZI	S2,.FBLEN		;Read all words form FDB
	MOVEI	T1,LOCFDB		; into local copy
	GTFDB
	 ERJMP	[MOVEI S1,.FBLEN	;Get length of FDB
		 MOVEI	S2,LOCFDB	;Point to it
		 $CALL	.ZCHNK		;Clear it
		 JRST	GETFD1]		;Just return
GETFD1:	$RETT
SUBTTL	GETDEV	Routine to get device attributes

;Accepts	LOCJFN setup by SETINP or SETOUT

;Returns TRUE	S1/ DAP device word (Also stored in ATTDEV)
;		S2/ Local device characteristics word

;	 FALSE	S1/ DAP unsupported device error

GETDEV:	HRRZ	S1,LOCJFN		;Get device JFN
	DVCHR				;Read device characteristics
	 ERJMP	DEVERR			;Return unsupported device
	MOVEM	S2,LOCDEV		;Save device word
	TXNN	S2,DV%AV		;Available?
	 PJRST	DEVERR			;No..return an error
	MOVX	S1,FB$AVL		;Device must be available
	TXNE	S2,DV%OUT		;Capable of output?
	TXO	S1,FB$ODV		;Yes..
	TXNE	S2,DV%IN		;Capable of input?
	TXO	S1,FB$IDV		;Yes..
	TXNE	S2,DV%DIR		;Have a directory?
	TXO	S1,FB$SDI		;Yes..assume single for now
	TXNE	S2,DV%MDD		;Multiple directories
	TXO	S1,FB$MDI		;Yes..
	TXNE	S2,DV%ASN		;Assigned?
	TXO	S1,FB$ALL		;Yes..
	TXNE	S2,DV%MNT		;Mounted?
	TXO	S1,FB$MNT		;Yes..
	ANDX	S2,DV%TYP		;Issolate device type
	MOVEI	T1,DEVTBL		;Point to devices
GETDE1:	SKIPN	T2,0(T1)		;Get table entry
	 JRST	DEVERR			;Unsupported device
	HRR	S2,T2			;Setup for equallity
	CAME	S2,T2			;Does it match?
	AOJA	T1,GETDE1		;No..try the next
	IOR	S1,(T2)			;Yes..set the bits
	MOVEM	S1,ATTDEV		;Save device attributes
	MOVE	S2,LOCDEV		;Return local device char word
	$RETT

DEVERR:	$STATUS	ER$FIL,ER$DEV		;Bad device
	$RETF


DEVTBL:	.DVDSK,,[FB$MDI+FB$SHR+FB$RAD]	;Disk
	.DVLPT,,[FB$REC+FB$SQD+FB$SPL]	;Line printer
	.DVCDP,,[FB$REC+FB$SQD+FB$SPL]	;Card punch
	.DVPLT,,[FB$REC+FB$SQD+FB$SPL]	;Plotter
	.DVMTA,,[FB$FOD+FB$SQD]		;Magtape
	.DVTTY,,[FB$TRM+FB$SQD]		;Terminal
	.DVCDR,,[FB$REC+FB$SQD]		;Card reader
	.DVNUL,,[FB$NUL]		;Null device
	 EXP 0				;Terminate list
SUBTTL	SETATT	Set attributes from swithces

;SETATT	is called to setup the attributes message per S1

;Accepts	S1/ Mode to setup in attributes
;		S2/ extra file attributes and Max record size


;Returns with
;		ATTMNU with appropriate bits set
;		ATTDAT with appropriate datatype
;		ATTRFM with appropriate record format
;		ATTRAT with appropriate record attributes
;		ATTMRS with calling arg or default of 512

SETATT:	MOVX	T2,AT$DAT+AT$RFM+AT$RAT+AT$MRS
	ANDCAM	T2,ATTMNU		;Clear the Menu bits
	LOAD	T1,S2,DF%MRS		;Get maximum record size
	SKIPN	T1			;Anything specified?
	MOVEI	T1,^D512		;No..use nice default
	MOVEM	T1,ATTMRS		;Save it
	MOVE	S1,MODTB1(S1)		;Get attributes per mode
	LOAD	T1,S1,DF%DAT		;Get Data type
	MOVEM	T1,ATTDAT		;Save it
	LOAD	T1,S1,DF%RFM		;Get record format
	MOVEM	T1,ATTRFM		;Save it
	CAIN	T1,FB$UDF		;Undefined record format?
	TXZ	T2,AT$MRS		;Yes..clear the MRS menu bit
	LOAD	T1,S1,DF%RAT		;Get record attributes
	MOVEM	T1,ATTRAT		;Save it
	IORM	T2,ATTMNU		;Set the menu bits
	$RETT
SUBTTL	SWLOOK	Lookup user switches and convert to DAP attriubtes

;Accepts	S1/ Data type - record format - record attributes

;Returns	S1/ Data mode implied by switches

SWLOOK:	ANDX	S1,DF%DAT+DF%RFM+DF%RAT	;Keep interesting bits
	MOVSI	S2,-MOD$LN		;Get length of the table
	JUMPE	S1,SWLOO3		;Establish default mode
	TXNE	S1,FLD(DT$IMA+DT$ASC,DF%DAT) ;Datatype specified?
	 JRST	SWLOO1			;Yes..see what we have
	TXNN	S1,FLD(FB$MCY,DF%RAT)	;No..Was MACY11 specified?
	 TXO 	S1,FLD(DT$IMA,DF%DAT)	;No..Datatype is image
SWLOO1:	CAMN	S1,MODTBL(S2)		;Match an entry?
	JRST	SWLOO3			;Yes..finish up
	AOBJN	S2,SWLOO1		;No..try the next
SWLOO2:	$RETF				;Return a failure

SWLOO3:	HRRZ	S1,S2			;Return mode in S1
	$RETT

;CHKMOD	Routine to check for legal input to output mode


CHKMOD:	SKIPE	S1,SRCMOD		;Unspecified source?
	SKIPN	S2,DSTMOD		;Unspecified destination?
	 $RETT				;Yes..can't check it yet!
	MOVNS	S2			;Get right shift value for mode
	MOVX	T1,1B0			;Get the bit for Mode (0)
	LSH	T1,0(S2)		;Get the bit for dest mode
	TDNN	T1,MODTBO(S1)		;Valid for source mode?
	 $RETF				;No..return the error
	$RETT
;Define a macro to generate table entries

DEFINE XX (MOD,RFM<0>,RAT<0>) <
	FLD(MOD,DF%DAT)+FLD(RFM,DF%RFM)+FLD(RAT,DF%RAT)>

;Define a macro to generate a bit mask

DEFINE XB (BIT) <
	ZZ==0
   IRP <BIT>,<ZZ==ZZ!1B<BIT>>
	EXP ZZ>

;Define a macro to generate default mode word

DEFINE XM (MODES) <
	BYTE (4) MODES>

	.MD1==^D1			;/IMAGE
	.MD2==^D2			;/IMAGE/FIXED
	.MD3==^D3			;/IMAGE/VARIABLE
	.MD4==^D4			;/IMAGE/MACY
	.MD5==^D5			;/MACY
	.MD6==^D6			;/MACY/FIXED
	.MD7==^D7			;/MACY/VARIABLE
	.MD8==^D8			;/ASCII
	.MD9==^D9			;/ASCII/FIXED
	.MD10==^D10			;/ASCII/VARIABLE
	.MD11==^D11			;Print file format
	.MD12==^D12			;Fortran format


;Table of valid calling switches

MODTBL:	XX 0				;Mode(0) unspecified
	XX DT$IMA			;Mode(1) /IMAGE
	XX DT$IMA,FB$FIX		;Mode(2) /IMAGE/FIXED
	XX DT$IMA,FB$VAR		;Mode(3) /IMAGE/VARIABLE
	XX DT$IMA,  0   ,FB$MCY		;Mode(4) /IMAGE/MACY11
	XX   0   ,  0   ,FB$MCY		;Mode(5) /MACY11
	XX   0   ,FB$FIX,FB$MCY		;Mode(6) /MACY11/FIXED
	XX   0   ,FB$VAR,FB$MCY		;Mode(7) /MACY11/VARIABLE
	XX DT$ASC			;Mode(8) /ASCII
	XX DT$ASC,FB$FIX		;Mode(9) /ASCII/FIXED
	XX DT$ASC,FB$VAR		;Mode(10) /ASCII/VARIABLE
	XX -1				;Mode(11) Cant be specified
	XX -1				;Mode(12) Can't be specified

	MOD$LN==.-MODTBL		;Compute length

;Table of valid output modes per input mode

MODTBO:	0
	XB <.MD1>
	XB <.MD1,.MD2,.MD6>
	XB <.MD3,.MD5,.MD7>
	XB <.MD1,.MD4>
	XB <.MD3,.MD5,.MD7>
	XB <.MD1,.MD2,.MD4,.MD6>
	XB <.MD3,.MD5,.MD7>
	XB <.MD8,.MD10>
	XB <.MD8,.MD9>
	XB <.MD8,.MD10>
	XB <.MD8>
	XB <.MD8>

;Table for DAP equivalent attributes

MODTB1:	XX DT$IMA,FB$UDF		;unspecified
	XX DT$IMA,FB$UDF		;/IMAGE
	XX DT$IMA,FB$FIX		;/IMAGE/FIXED
	XX DT$IMA,FB$VAR		;/IMAGE/VARIABLE
	XX DT$IMA,FB$UDF,FB$MCY		;/IMAGE/MACY11
	XX DT$IMA,FB$STM,FB$MCY		;/MACY (Dos Binary)
	XX DT$IMA,FB$FIX,FB$MCY		;/MACY11/FIXED
	XX DT$IMA,FB$VAR,FB$MCY		;/MACY11/VARIABLE
	XX DT$ASC,FB$STM		;/ASCII
	XX DT$ASC,FB$FIX		;/ASCII/FIXED
	XX DT$ASC,FB$VAR,FB$CR		;/ASCII/VARIABLE
	XX DT$ASC,FB$VFC,FB$PRN		;Print format is read only
	XX DT$ASC,FB$VFC,FB$FTN		;Fortran format is read only

;Table of default output modes per source mode

MODTB2:	0
	XM <.MD1>			;/IMAGE (TO) /IMAGE
	XM <.MD2>			;/IMAGE/FIX (TO) /IMAGE/FIX
	XM <.MD3>			;/IMAGE/VAR (TO) /IMAGE/VAR
	XM <.MD1>			;/IMAGE/MAC (TO) /IMAGE
	XM <.MD3>			;/MACY (TO) /IMAGE/VAR
	XM <.MD2>			;/MACY/FIX (TO) /IMAGE/FIX
	XM <.MD3>			;/MACY/VAR (TO) /IMAGE/VAR
	XM <.MD8,.MD10>			;/ASCII (TO) /ASCII [/VARIABLE]
	XM <.MD8>			;/ASCII/FIX (TO) /ASCII
	XM <.MD8,.MD10>			;/ASCII/VAR (TO) /ASCII [/VARIABLE]
	XM <.MD11>			;Print file to ascii stream
	XM <.MD12>			;Fortran file to ascii stream

;Table of processor addresses for various modes

MODTB3:	0
	XWD GETIMG,PUTIMG		;/IMAGE
	XWD GETIMG,PUTIMG		;/IMAGE/FIXED
	XWD GETIMG,PUTIMG		;/IMAGE/VARIABLE
	XWD GETIMG,PUTIMG		;/MACY/IMAGE
	XWD GETDOS,PUTDOS		;/MACY
	XWD GETIMG,PUTIMG		;/MACY/FIXED
	XWD GETIMG,PUTIMG		;/MACY/VARIABLE
	XWD GETASC,PUTASC		;/ASCII
	XWD GETASC,PUTASC		;/ASCII/FIXED
	XWD GETASC,PUTASC		;/ASCII/VARIABLE
	XWD GETPRN,[PJRST .RETT]	;PRN format is read only
	XWD GETFTN,[PJRST .RETT]	;FTN format is read only

;Table of valid file bytesizes for mode

MODTB4:	0
	EXP -1				;1 to 36 for IMAGE
	EXP -1
	EXP -1
	XB <18,0>			;18 or 36 for MACY
	XB <18,0>
	XB <18,0>
	XB <18,0>
	XB <7,8,0>			;7 8 or 36 for ASCII
	XB <7,8,0>
	XB <7,8,0>
	XB <7>				;7 for print format
	XB <7>				;7 for fortran format

;Table of file open bytesize for mode

MODTB5:	0
	EXP 0				;Actual file bytesize for IMAGE
	EXP 0
	EXP 0
	EXP ^D36			;36 for /MACY
	EXP ^D36
	EXP ^D36
	EXP ^D36
	EXP ^D7				;7 for ASCII
	EXP ^D7				;7 for ASCII FIXED
	EXP ^D7				;7 for ASCII VARIABLE
	EXP ^D7				;7 for print format
	EXP ^D7				;7 for fortran format

;Table of attributes bytesize for mode

MODTB6:	0
	EXP 0				;Actual file bytesize for IMAGE
	EXP 0
	EXP 0
	EXP ^D8				;8 bit bytes for MACY11
	EXP ^D8
	EXP ^D8
	EXP ^D8
	EXP ^D8				;8 bit bytes for ASCII
	EXP ^D8
	EXP ^D8
	EXP ^D8				;8 bit bytes for print format
	EXP ^D8				;8 bit bytes for fortran format

;Table of valid modes for FAL file create

MODTB7:	0
	EXP -1				;Image undefined Ok for FAL
	0
	0
	EXP -1				;Macy11 Ok for FAL
	EXP -1
	EXP -1
	EXP -1
	EXP -1				;Ascii stream Ok for FAL
	0
	0				;Can't create print files
	0				;Can't create print format
	0				;Can't create fortran format
SUBTTL	ATLOOK	Routine to lookup attributes

;ATLOOK	is called after recieving an attributes message to return
;	the data mode implied by the message and also the default
;	output mode.

;Returns TRUE	S1/ Source mode implied by attributes
;		S2/ Default output mode implied by source mode

;	 FALSE	S1/ Unsupported data type

ATLOOK:	MOVE	S1,ATTDAT		;Get data mode of attributes
	STORE	S1,S2,DF%DAT		;Store in proper field
	MOVE	S1,ATTRFM		;Get record format of attributes
	STORE	S1,S2,DF%RFM		;Store in proper field
	MOVE	S1,ATTRAT		;Get record attributes
	STORE	S1,S2,DF%RAT		;Store in proper field
	ANDX	S2,DF%DAT+DF%RFM+DF%RAT	;Keep interesting fields
	TXZ	S2,FLD(DT$EXE+DT$EXP+DT$SEN+100+,DF%DAT) ;ignored bits
	MOVSI	S1,-ATT$LN		;Get count of valid entries
ATLOO1:	CAMN	S2,ATTTBL(S1)		;Entry match?
	JRST	ATLOO2			;Yes..process it
	AOBJN	S1,ATLOO1		;No..try the next
	$MUERR	.DMATT,21		;Not found..return unsupported

ATLOO2:	HRRZ	S2,ATTMOD(S1)		;Get default output mode
	HLRZ	S1,ATTMOD(S1)		;Get implied source mode
	$RETT				;Return success
SUBTTL	Attributes list

ATTTBL:	XX	DT$ASC,FB$STM		;Stream ascii
	XX	DT$ASC,FB$UDF		;Undefined ascii
	XX	DT$ASC,FB$STM,FB$EBF	;Stream ascii
	XX	DT$IMA,FB$UDF		;Undefined image
	XX	DT$IMA,FB$UDF,FB$MCY	;Macy image
	XX	DT$IMA,FB$FIX,FB$MCY	;Macy Fixed
	XX	DT$IMA,FB$VAR,FB$MCY	;Macy variable
	XX	DT$IMA,FB$STM,FB$MCY	;Macy stream (Assembler)
	XX	DT$ASC,FB$FIX		;Fixed ascii
	XX	DT$ASC,FB$FIX,FB$CR	;Fixed ascii
	XX	DT$ASC,FB$FIX,FB$EBF	;Fixed ascii
	XX	DT$ASC,FB$VAR		;Variable ascii
	XX	DT$ASC,FB$VAR,FB$CR	;Variable ascii
	XX	DT$ASC,FB$VAR,FB$EBF	;Variable ascii
	XX	DT$IMA,FB$FIX		;Fixed image
	XX	DT$IMA,FB$VAR		;Variable image
	XX	DT$IMA,FB$FIX,FB$CR	;Fixed image [ascii]
	XX	DT$IMA,FB$VAR,FB$CR	;Variable image [ascii]
	XX	DT$IMA,FB$VFC,FB$PRN	;Print file format
	XX	DT$IMA,FB$VFC,FB$CR	;Sos file format
	XX	DT$ASC,FB$VFC,FB$PRN	;Ascii print
	XX	DT$ASC,FB$VFC,FB$CR	;Ascii Sos
	XX	DT$IMA,FB$VFC,FB$FTN	;Fortran files
	XX	DT$ASC,FB$VFC,FB$FTN
	XX	DT$IMA,FB$STM		;Ascii stream from RSTS
		ATT$LN==.-ATTTBL	;Number of valid attributes

ATTMOD:	XWD	.MD8,.MD8		;Stream ascii (to) Stream ascii
	XWD	.MD8,.MD8		;Undefined ascii (to) Stream ascii
	XWD	.MD8,.MD8		;Stream ascii (to) Stream ascii
	XWD	.MD1,.MD1		;Undefined image (to) Undefined image
	XWD	.MD4,.MD4		;Macy image (to) Macy image
	XWD	.MD6,.MD6		;Macy fixed (to) Macy fixed
	XWD	.MD7,.MD7		;Macy variable (to) Macy variable
	XWD	.MD5,.MD5		;Macy stream (to) Macy stream
	XWD	.MD9,.MD8		;Fixed ascii (to) Stream ascii
	XWD	.MD9,.MD8		;Fixed ascii (to) Stream ascii
	XWD	.MD9,.MD8		;Fixed ascii (to) Stream ascii
	XWD	.MD10,.MD8		;Variable ascii (to) Stream ascii
	XWD	.MD10,.MD8		;Variable ascii (to) Stream ascii
	XWD	.MD10,.MD8		;Variable ascii (to) Stream ascii
	XWD	.MD2,.MD2		;Fixed image (to) Fixed image
	XWD	.MD3,.MD3		;Variable image (to) Variable image
	XWD	.MD9,.MD8		;Fixed image [ascii] (to) stream ascii
	XWD	.MD10,.MD8		;Variable image [ascii] (to) Strm ascii
	XWD	.MD11,.MD8		;Print format to stream ascii
	XWD	.MD10,.MD8		;Sos to stream ascii
	XWD	.MD11,.MD8		;Print format to stream ascii
	XWD	.MD10,.MD8		;Sos to stream ascii
	XWD	.MD12,.MD8		;Fortran files
	XWD	.MD12,.MD8		;Fortran files
	XWD	.MD8,.MD8
SUBTTL	SETMOD	Routine to setup processor address and bytesizes

;SETMOD	is called after SETINP or SETOUT to establish proper mode

;Returns TRUE	S1/ mode
;		S2/ Attributes bytesize


SETMOD:	MOVE	S1,OPNFLG		;Get file open flags
	TXNN	S1,OF%RD		;Reading the file?
	 JRST	[MOVE T1,DSTMOD		;Get destination mode
		 JRST SETMO2]		;Setup per destination
	LOAD	S1,.FBBYV+LOCFDB,FB%BSZ	;Yes..get file BSZ
	MOVX	S2,1B0			;Get a bit to test
	SKIPN	T1,SRCMOD		;Get the source mode
	 JRST	[MOVEI T1,.MD1		;Assume image mode
		 CAIN S1,^D7		;Unless bytesize is 7
		 MOVEI T1,.MD8		;which means ascii
		 MOVEM T1,SRCMOD	;Remember it
		 JRST .+1]		;Continue
	CAIN	S1,^D36			;Bytesize = 36?
	JRST	SETMO1			;Yes..test with bit 0
	MOVNS	S1			;Get -bytesize
	LSH	S2,0(S1)		;Shift to proper bit
SETMO1:	TDNN	S2,MODTB4(T1)		;OK for this mode?
	 $MIERR	.DMATT,36		;No..bad bytesize
SETMO2:	SKIPN	S1,MODTB5(T1)		;Get open BSZ
	LOAD	S1,.FBBYV+LOCFDB,FB%BSZ	;Use file BSZ
	SKIPN	S2,MODTB6(T1)		;Get BSZ for attributes
	MOVE	S2,S1			;Use file open BSZ
	STORE	S1,OPNFLG,OF%BSZ	;Save for open
	MOVE	T2,MODTB3(T1)		;Get processor dispatch
	MOVEM	T2,DATDAT
	MOVE	T2,MODTB1(T1)		;Get DAP attributes
	SETZM	MCYIDX			;Clear MACY flag
	TXNE	T2,FLD(FB$MCY,DF%RAT)	;Unless wanted
	SETOM	MCYIDX
	MOVE	S1,T1			;Return mode in S1
	$RETT
SUBTTL	TYPSTS	Routine to expand DAP status codes

;Accepts	S1/ Status code
;		S2/ Extended status
;		T1/ Output designator

;		T1/ Updated designator

TYPSTS:	$SAVE	<S1,S2,P1,P2,P3,P4>	;Preserve some AC's
	MOVE	P1,T1			;Save output designator
	LOAD	P2,S1,ER%MAC		;Get MACODE
	LOAD	P3,S1,ER%MIC		;Get MICODE
	SKIPE	P4,S2			;Save extended status
	 JRST	[CAIL	P4,.ERBAS	;Check for valid error codes
		 CAILE	P4,.ERBAS+.ERMAX
		 JRST .+1		;Invalid code for our system
		 MOVE S1,P1		;Get output designator
		 HRROI S2,[ASCIZ//]	;No text
		 MOVEI T1,[ITEXT<^E/P4/>]	;Only our error
		 JRST TYPST8]		;Display it
	MOVSI	S2,-MIC$LN		;Get length of table
	CAIN	P2,ER$USP		;Unsupported status error?
	 JRST	TYPST1			;Yes..do actual lookup
	CAIL	P2,ER$FMT		;Format, Invalid, or SYNC error?
	CAILE	P2,ER$SNC		;...
	 ANDX	S1,ER%MIC		;No..do generic lookup
TYPST1:	HRRZ	T1,MICTBL(S2)		;Get the status code
	CAMN	S1,T1			;Match what we have?
	 JRST	TYPST2			;Yes..display it
	AOBJN	S2,TYPST1		;No..check the next
	CAIN	P2,ER$USP		;Unsupported status error?
	 JRST	TYPST3			;Yes..do name lookup
	CAIL	P2,ER$FMT		;Format, Invalid, or SYNC error?
	CAILE	P2,ER$SNC		;...
	SKIPA	S1,P1			;No..get output designator
	JRST	TYPST3			;Yes..do name lookup
	JRST	TYPST7			;Display per ITEXT

TYPST2:	MOVE	S1,P1			;Get output designator
	HLRO	S2,MICTBL(S2)		;Get pointer to string
	SETZ	T1,			;No ITEXT
	JRST	TYPST8			;Store the status
TYPST3:	MOVSI	S2,-MSG$LN		;Get number of message types
	MOVE	S1,P3			;Get MICODE
	CAIE	P2,ER$SNC		;SYNC error?
	LSH	S1,-6			;No..get message type
	ANDX	P3,ER%FLD		;Clear all but field from error
TYPST4:	HLRZ	T1,MSGTBL(S2)		;Get Message type
	CAMN	S1,T1			;Match what we have?
	JRST	TYPST5			;Yes..get the name
	AOBJN	S2,TYPST4		;No..try the next
	HRROI	T1,[ASCIZ/Unknown/]
	JRST	TYPST6
TYPST5:	HRRZ	S2,MSGTBL(S2)		;Get Message descriptor
	HRRO	T1,0(S2)		;Get pointer to name
TYPST6:	EXCH	P1,T1			;Put pointer in P1
	MOVE	S1,T1			;Put output designator in S1
TYPST7:	HRROI	S2,[ASCIZ//]		;Null string
	MOVE	T1,MACTBL(P2)		;Get proper ITEXT to expand
TYPST8:	SETZ	T2,			;Get null prefix character
	$CALL	TYPER			;Display the string
	MOVE	T1,S1			;Return designator in T1
	$RETT
SUBTTL	TYPDVR	ROUTINE TO TYPE OUT DAP VERSION MESSAGE

TYPDVR:	$DEBUG <DAP version >,<^O/[.DVMAJ]/.^O/[.DVMIN]/>
	$RETT

SUBTTL	TERCVT	Routine to convert TOPS20 error code to dap status

;Returns	S1/ Dap status code
;		S2/ Last TOPS20 error code

TERCVT:	$CALL	GETTER			;Get last JSYS error in S2
	MOVE	T1,[IOWD S20DLN,S20DAP+1]	;Point to table
TERCV1:	HLRZ	S1,(T1)			;GET TOPS-20 ERROR FROM TABLE
	CAMN	S1,S2			;MATCHING ENTRY?
	JRST	TERCVF			;YES!
	AOBJN	T1,TERCV1		;NO MATCH - LOOP BACK FOR NEXT
	TDZA	S1,S1			;Return unspecified error
TERCVF:	HRRZ	S1,(T1)			;GET CORRESPONDING DAP STATUS
	MOVX	T1,ER$FIL		;Assume file open error
	TXNN	S,S%GET+S%PUT+S%EOF	;Is it?
	JRST	TERCV2			;yes
	MOVX	T1,ER$TRN		;No..Assume transfer error
	TXNE	S,S%EOF			;Is it?
	MOVX	T1,ER$TRM		;Termination error
TERCV2:	STORE	T1,S1,ER%MAC		;STUFF MACCODE INTO DAP STATUS
	$RETF				;Return calling failure
SUBTTL	LLGJFN	Routine to get JFN for logical link

SUBTTL	LLGJFN	Get a JFN for logical link
;Accepts	CP/ Base of per link info
;		AP/ Base of calling argument block

;Returns TRUE	Link has a JFN

LLGJFN:	MOVE	T2,.DOFLG(AP)		;GET ARGUMENT BLOCK FLAGS
	MOVE	T4,[-DCNSIZ,,DCNPFX+1]	;ASSUME DCN:
	TXNE	T2,DO%SRV		; UNLESS WE WANT TO BE A SERVER
	JRST	[$CALL ENABLE		;YES..MAKE SURE WE ARE WHEEL
		 MOVE T4,[-SRVSIZ,,SRVPFX+1]	;DEVICE IS SRV:
		 JRST .+1]		;CONTINUE ON.
	HRRZ	T3,-1(T4)		;GET OFFSET TO FIRST POINTER
	ADDI	T3,(AP)			;GET ACTUAL ADDRESS
	HRROI	S1,LLNAME		;POINT TO NAME AREA
LLGJF1:	MOVX	T1,177B6		;Get first character mask
	SKIPE	T2,(T3)			;IS THIS field present
	TDNN	T1,(T2)			; AND NOT NULL?
	JRST	LLGJF2			;NO..SKIP IT
	MOVE	S2,(T4)			;YES..DO PREFIX
	SETZ	T1,
	SOUT
	MOVE	S2,T2			;DO THE FIELD
	$CALL	QSOUT			;COPY STRING
LLGJF2:	AOJ	T3,			;NEXT FIELD
	AOBJN	T4,LLGJF1		;DO ALL PRESENT

	MOVX	S1,GJ%NEW+GJ%SHT	;MUST NOT EXIST
	HRROI	S2,LLNAME		;POINT TO FILESPEC
	GTJFN				;GO GET THE JFN
	 $FATAL	(Can't get JFN for logical link - ,^E/[-2]/)
	MOVEM	S1,LLJFN		;SAVE THE JFN
	HRROI	S1,LLNAME		;POINT TO NAME STRING STORAGE
	HRRZ	S2,LLJFN		;GET LL JFN
	MOVX	T1,FFSPEC		;Full file spec
	JFNS				;SAVE OFF FULL FILESPEC STRING
LLGDC3:	$DEBUG <Network JFN Established, >,<^T/LLNAME/>
	$RETT
DCNPFX:	DCNSIZ,,.DONOD			;SIZE,,FIRST OFFSET
	TXT(DCN:)			;PREFIX FOR NODE
	TXT(-)				;PREFIX FOR OBJECT
	TXT(-)				;PREFIX FOR DISCRIPTOR
	TXT(.)				;PREFIX FOR TASKNAME
	TXT(;USERID:)			;PREFIX FOR USERID
	TXT(;PASSWORD:)			;PREFIX FOR PASSWORD
	TXT(;CHARGE:)			;PREFIX FOR ACCOUNT
	TXT(;DATA:)			;PREFIX FOR DATA
	DCNSIZ==.-DCNPFX-1		;SIZE OF TABLE

SRVPFX:	SRVSIZ,,.DOOBJ			;SIZE,,FIRST OFFSET
	TXT(SRV:)			;PREFIX FOR OBJECT
	TXT(-)				;PREFIX FOR DESCRIPTOR
	TXT(.)				;PREFIX FOR TASKNAME
	SRVSIZ==.-SRVPFX-1		;SIZE OF TABLE

SUBTTL	QSOUT	move asciz string and quote if required

QSOUT:	$SAVE	<T1,T2>
	TLCE	S2,-1
	TLCN	S2,-1
	 HRLI	S2,(POINT 7,0)
QSOUT1:	ILDB	T1,S2			;Get source byte
	SKIPN	T2,T1			;Put byte in T2
	JRST	QSOUT3			;Finished on null
	CAIL	T1,"0"			;Check numeric
	CAILE	T1,"9"
	 TRZA	T2,40			;Make upper case
	JRST	QSOUT2			;Numeric..store it
	CAIL	T2,"A"			;Check alpha
	CAILE	T2,"Z"
	 SKIPA	T2,[EXP "V"-100]	;Get quote character
	JRST	QSOUT2			;Alpha..store it
	CAIN	T1,"-"			;Allow hyphen
	JRST	QSOUT2			;Store it
	IDPB	T2,S1
QSOUT2:	IDPB	T1,S1			;Store the character
	JRST	QSOUT1			;Back for more

QSOUT3:	MOVE	T2,S1			;Get dest pointer
	IDPB	T1,T2			;Store null terminator
	$RETT				;Return

CPYSTR:	SETZM	T1			;Terminate on null
	SOUT
	$RETT
SUBTTL	LLOPEN	Routine to OPEN logical link

;LLOPEN		Opens NETWORK JFN for DCN: or SRV:
;Accepts	CP/ Base of per link data
;		AP/ Base of D$OPEN argument block

;Returns TRUE	LINK is open and attatched to interrupt system
;	 	Although not necessarily connected

LLOPEN:	$DEBUG <Attempting to Open Logical link>
	MOVE	S1,LLJFN		;GET JFN OF LL TO OPEN
	MOVE	S2,[FLD(^D8,OF%BSZ)+OF%RD+OF%WR]
	OPENF				;TRY TO OPEN LINK
	 ERJMP	LLOPN5			;RELEASE JFN AND RETURN
LLOPN1:	MOVE	S1,LLJFN		;GET JFN AGAIN
	MOVEI	S2,.MORTN		;GET TASK NAME FOR THIS LL
	SKIPE	T1,.DOTSK(AP)		;POINT TO TASK NAME
	MTOPR				;DO MTOPR
	 ERJMP	LLOPN4
	MOVEI	S2,.MOACN		;ENABLE FOR CONNECT INTERRUPTS
	MOVE	T1,.DOPSI(AP)		;GET PSI FLAGS
	MOVX	T4,DO%PSI		;GET PSI FLAG
	TDNE	T4,.DOFLG(AP)		;Want to be on PSI?
	MTOPR				;yes..do MTOPR
	 ERJMP	LLOPN4

;HERE WHEN LINK IS OPEN AND MTOPRS DONE
LLOPN2:	$STATE	.LLCFG			;Say link is waiting on Config
	MOVE	S2,.DOTSK(AP)		;Get task pointer
	$DEBUG	<Logical link open>
	$RETT				;RETURN SUCCESS

;HERE WHEN LINK CAN'T BE OPENED
LLOPN4:	MOVE	S1,LLJFN		;GET THE JFN
	TXO	S1,CZ%ABT		;ABORT IT
	CLOSF
	 ERJMP	.+1
LLOPN5:	SETZB	S,LLJFN			;MARK NOT OPENED
	 $FATAL	(Can't open logical link - ,^E/[-2]/)
SUBTTL	LLWCON	ROUTINE TO WAIT FOR LINK TO BE CONNECTED

;RETURN TRUE		S1/ Link status from MTOPR

LLWCON:	MOVEI	T4,^D5			;Wait for 5 CCTIME intervals
LLWC1:	$CALL	LLCHK			;CHECK LL STATUS
	 JUMPF	LLWC3			;Find out why we aborted
	TXNE	S1,MO%CON		;LINK CONNECTED?
	$RETT				;Yes..give good return
	TXNE	S1,MO%SYN		;LINK CLOSED OUT BY OTHER END?
	 JRST	LLWC3			;Yes..Find out why
	TXNE	S1,MO%SRV		;IS THIS A SERVER?
	JRST	LLWC4			;Yes..wait for interrupt
	SOJG	T4,LLWC2		;Tried enough?
	$CALL	DIABT			;Cancel the link
	$FATAL	(Remote node is not responding)

LLWC4:	TDZA	S1,S1			;Sleep for ever
LLWC2:	MOVEI	S1,CCTIME		;NO..GET WAIT TIME
	$CALL	I%SLP			;AND SNOOZE
	JRST	LLWC1			;TRY AGAIN

;HERE WHEN LINK IS ABORTED
LLWC3:	SKIPE	LLJFN			;Still have a JFN?
	$CALL	DIABT			;Yes..respond to abort
	HRRZ	S1,LLSTAT		;Get last status
	CAIE	S1,.DCX34		;Was it bad password?
	CAIN	S1,.DCX36		;Or bad account?
	$FATAL	(Remote node refused connection - ,^T/LLDISC/)
	$FATAL	(Logical link was aborted - ,^T/LLDISC/)
SUBTTL	LLCHK	Routine to check logical link status

;Accepts	CP/ Base of per link data

;Returns TRUE	S1/	Link status - link is active
;	 FALSE	S1/	Link status - link is aborted

LLCHK:	MOVE	S1,LLJFN		;Get link JFN
	MOVEI	S2,.MORLS		;READ LINK STATUS
	MOVE	T1,LLSTAT		;Return last status on failure
	MTOPR
	 ERJMP	[TXO T1,MO%ABT		;Say Abort status
		 JRST LLCHK1]		;Back in line
	MOVEM	T1,LLSTAT		;Save latest status
	AOSE	MSGFLG			;Message interrupt recieved?
	JRST	LLCHK1			;No..just return status in S1
	SIBE				;Yes..make sure we have one
	SETOM	MSGFLG			;Flag message available
LLCHK1:	MOVE	S1,T1			;Put MTOPR status in S1
	TXNE	S1,MO%ABT		;Link aborted?
	 $RETF				;Return false
	$RETT				;No..return true
SUBTTL	LLCLOS	Routine to close or abort a logical link


;Accepts	S1/ NSP disconnect code
;		S2/ Pointer to optional data to be sent

LLCLOS:	SKIPN	LLJFN			;Is link open?
	 $FATAL	(Logical link is not open)
	DMOVEM	S1,CLSBLK		;Save our reason
	SETZB	T1,T2			;Clear pointer and length
	JUMPE	S2,LLCLS2		;Optional data?
	TLCE	S2,-1			;Yes..make a real pointer
	TLCN	S2,-1
	 HRLI	S2,(POINT 7)		;Ready to count the bytes
	MOVE	T1,S2			;Save pointer for MTOPR
LLCLS1:	ILDB	S1,S2			;Get the bytes
	JUMPE	S1,LLCLS2		;Do the MTOPR
	AOJA	T2,LLCLS1		;Count until null
	CAILE	T2,^D16			;Enforce max of 16
	MOVEI	T2,^D16
LLCLS2:	HRLZ	S2,CLSBLK		;Put abort code in place
	HRRI	S2,.MOCLZ		;Get the close function
	MOVE	S1,LLJFN		;Get the JFN
	MTOPR
	 ERJMP	LLCLS3			;Abort if MTOPR fails
	TLNE	S2,-1			;Did we abort link?
LLCLS3:	TXOA	S1,CZ%ABT		;Yes..set bit for close
LLCLS4:	MOVE	S1,LLJFN		;Pick up JFN
	CLOSF
	 $FATAL	(Can't close logical link - ,^E/[-2]/)
	SETZB	S,LLJFN			;Clear JFN word
	$RETT
SUBTTL	LLRCD	Read Connect-initiate Disconnect initiate data

SUBTTL	LLRCD	ROUTINE TO READ INFORMATION FROM CI/DI MESSAGES
;Accepts	CP/ Base of per link data

;Returns TRUE	Data via pointers in LLOPNB

LLRCD:	MOVE	S1,LLJFN		;GET LINK JFN
	MOVSI	T4,-CDISIZ		;GET NUMBER OF REQUESTS
LLRCD1:	HLRZ	S2,CDITBL(T4)		;GET FUNCTION
	HRRZ	T1,CDITBL(T4)		;GET OFFSET TO ENTRY
	ADDI	T1,LLOPNB		;GET ACTUAL ADDRESS OF POINTER
	SKIPN	T1,(T1)			;NULL POINTER?
	 JRST	LLRCD2			;YES..ON TO NEXT FUNCTION
	TLCE	T1,-1
	TLCN	T1,-1			;REAL BYTE POINTER?
	 HRLI	T1,(POINT 7,0)		;NO..MAKE IT ASCII
	MTOPR				;NO..DO IT
	 ERJMP	.+1			;IGNORE ERRORS
	SETZ	S2,			;GET A NULL
	IDPB	S2,T1			;TERMINATE WITH NULL
LLRCD2:	AOBJN	T4,LLRCD1		;BACK TO READ ALL ITEMS
	MOVEM	T2,.DOUIC+LLOPNB	;SAVE UIC IF ANY

	MOVEI	S2,.MORSS		;READ SEGMENT SIZE
	SETZM	T1
	MTOPR
	 ERJMP	.+1			;IGNORE ERRORS
	MOVEM	T1,.DOSSZ+LLOPNB	;SAVE SEGMENT SIZE

	MOVEI	S2,.MORCN		;READ CONNECTED OBJECT
	SETZ	T1,
	MTOPR
	 ERJMP	.+1			;IGNORE ERRORS
	STORE	T1,.DOFLG+LLOPNB,DO%OBJ ;SAVE ACCESS OBJECT TYPE
	$RETT				;ALL DONE, RETURN


CDITBL:	.MORHN,,.DONOD			;READ REMOTE HOST NAME
	.MORTN,,.DOTSK			;READ TASK NAME
	.MORUS,,.DOUSR			;READ USER
	.MORPW,,.DOPSW			;READ PASSWORD
	.MORAC,,.DOACT			;READ ACCOUNT
	.MORDA,,.DOOPD			;READ DATA
					;*** .MORDA MUST BE LAST ***
	.MOROD,,.DODSC			;READ OBJECT-DESCRIPTOR
	CDISIZ==.-CDITBL		;SIZE
SUBTTL	STOSTS	Routine to store link status

;Accepts	S1/ Output designator
;		S2/ Link status code

;Returns TRUE	Reason code is stored
;	 FALSE	Invalid reason code

STOSTS:	HRRZ	S2,S2			;PUT STATUS CODE IN S2
	SETZ	T1,			;SET FOR SOUT AGAIN
	CAILE	S2,DSCMAX		;KNOWN REASON?
	$RETF				;NO..JUST RETURN
	HRRO	S2,DSCTBL(S2)		;POINT TO DISCONNECT TEXT
	SOUT
	$RETT
SUBTTL	LLSEND	Routine to send messages across Link

;Accepts	S2/ Header address of message to be sent

;Returns TRUE	Message has been sent

LLSEND:	MOVE	S1,LLJFN		;Get link JFN
	MOVN	T1,.DPCNT(S2)		;Get byte count
	SKIPLE	.DPLEN(S2)		;More to come?
	JRST	LLSEN1			;Yes..send with SOUT
	MOVE	S2,.DPBPT(S2)		;Get the byte pointer
	SOUTR				;No..Send with end of message
	 ERJMP	LLSENE			;Die on failure
	$RETT

LLSEN1:	MOVE	S2,.DPBPT(S2)		;Get the pointer
	SOUT				;Send of part of a record
	 ERJMP	LLSENE			;Die on failure
	$RETT


LLSENE:	$FATAL	(Logical link transmission error - ,^E/[-2]/)
SUBTTL	LLRECV	Routine to receive link messages

;Returns TRUE	DL/ Address of message header

LLRECV:	MOVE	S1,RCVLST		;Point to recieve list
	$CALL	L%FIRST			;Point to first entry
	JUMPF	LLREC3			;Anything there?
	SKIPL	T1,.DPTYP(S2)		;Yes..want to reparse it?
	JRST	LLREC1			;No..delete it
	MOVNM	T1,.DPTYP(S2)		;Yes..fix the type
	MOVE	T1,.DPLEN(S2)		;Yes..Get original length
	EXCH	T1,.DPCNT(S2)		;Reset message count
	SUB	T1,.DPLEN(S2)		;Get characters parsed
	ADJBP	T1,.DPBPT(S2)		;Reset message pointer
	MOVEM	T1,.DPBPT(S2)
	JRST	LLREC2			;On to receive next message

LLREC1:	$CALL	L%DENT			;Delete first list entry
LLREC2:	MOVE	S1,RCVLST		;Point to first message in list
	$CALL	L%FIRST
	JUMPF	LLREC3
	MOVE	DL,S2			;Point to our entry
	SETOM	MSGFLG			;Force SIBE check in LLCHK
	$CALL	LLCHK			;Get link status and SET/CLEAR MSGFLG
	TXNN	S1,MO%EOM		;Do we have a full message ready?
	$RETT				;No..return with first message in list

LLREC3:	MOVE	S1,RCVLST		;Get recieve list index
	MOVE	S2,OURSIZ		;Get size of a buffer
	$CALL	NEWBUF			;Allocate new buffer
	MOVE	S1,LLJFN
	MOVE	S2,.DPBPT(DL)		;Get pointer to buffer
	MOVN	T1,.DPCNT(DL)		;Get max count
	SINR				;Read a logical message
	 ERJMP	LLRECE			;Bad news
	ADDB	T1,.DPCNT(DL)		;Save actual count
	MOVEM	T1,.DPLEN(DL)		;Save as length
	JRST	LLREC2			;Back to check for next message

LLRECE:	$CALL	GETTER			;Get my last error
	CAIN	S2,IOX4			;End of file?
	$FATAL	(Logical link was terminated)
	$FATAL	(Logical link reception error - ,^E/[-2]/)
SUBTTL	NEWBUF	Routine to allocate a new buffer

;Accepts	S1/ Send or recieve list index
;		S2/ Required byte count of buffer

;Returns TRUE	DL/ Address of new message buffer

NEWBUF:	DMOVE	T1,S1			;Save list index and count
	$CALL	L%LAST			;Position to end of list
	DMOVE	S1,T1			;Restore list index and count
	TRZE	S2,3			;Spare word needed?
	ADDI	S2,4			;Yes..account for it
	LSH	S2,-2			;Compute word count
	ADDI	S2,.DPSIZ		;Add header size
	$CALL	L%CENT			;Create an entry
	MOVE	DL,S2			;Point to it
	MOVEI	S2,.DPSIZ(S2)		;Point to message area
	HRLI	S2,(POINT 8)
	MOVEM	S2,.DPBPT(DL)		;Save in header
	MOVEM	T2,.DPCNT(DL)		;Save counts
	MOVEM	T2,.DPLEN(DL)		;Save length
	$RETT
SUBTTL	Connect	event interrupt service


;HERE ON CI RECEIVED
CICON:	$CALL	LLCHK			;Get link status
	TXNN	S1,MO%SRV		;AM I A SERVER?
	 $RETT				;NO - DONE
	$CALL	LLRCD			;READ CONNECT DATA


;HERE TO CHECK FOR VALID CONNECT PARAMETERS
CICHK:	MOVEI	S1,.DCX34		;Assume no access
	SETZ	S2,			;No optional text
	SKIPE	T1,.DOCID+LLOPNB	;GET ADDRESS OF CHECK ROUTINE
	$CALL	0(T1)			;CALL IT
	 JUMPF	LLCLOS			;abort link on failure
	MOVEM	S1,USRNUM		;Save user number
	MOVEM	S2,DIRNUM		;Save directory number
CIACC:	MOVE	S1,LLJFN		;GET JFN FOR LL
	MOVEI	S2,.MOCC		;ACCEPT THE CONNECTION
	SETZM	T2			;NO RETURN DATA
	MTOPR
	 ERJMP	.+1
	$CALL	LLCHK			;Get new link Status
	$RET				;Return True/false per LLCHK

;Here to respond to DI and store reason for disconnect

DIABT:	SKIPN	S1,LLJFN		;Have a JFN?
	JRST	DIAB1			;No..just store status
	MOVX	S2,.MORDA		;Yes..read optional data
	HRROI	T1,LLDISC		;Save disconnect cause
	MTOPR
	 ERJMP	DIAB1			;Oops..just store staus
	JUMPE	T2,DIAB1		;No data..just store status
	SETZ	S2,			;Get a null
	IDPB	S2,T1			;Terminate with a null
	CAIL	T2,7			;At least 7 characters?
	JRST	DIAB2			;yes..Ignore status

DIAB1:	HRROI	S1,LLDISC		;Point to disconnect cause
	MOVE	S2,LLSTAT		;Get last known status
	$CALL	STOSTS			;Store the status String
DIAB2:	MOVEI	S1,.DCX42		;Response to DI request
	SETZ	S2,			;No optional data
	PJRST	LLCLOS			;Close the link
SUBTTL	Interrupt	message processing

PSIIM:	MOVE	S1,LLJFN		;Get links jfn
	MOVEI	S2,.MORIM		;Read the message
	MOVEI	T1,.NULIO		;Can it for now
	MTOPR
	 ERJMP .RETF
	$RETT
SUBTTL	Table	of NSP disconnect reasons

DEFINE DISCR <
	ER	(0,No error)
	ER	(1,Resource allocation failure)
	ER	(2,Target node does not exist)
	ER	(3,Node shutting down)
	ER	(4,Target task does not exist)
	ER	(5,Invalid name field)
	ER	(6,Target task queue overflow)
	ER	(7,Unspecified error condition)
	ER	(8,Third party aborted the logical link)
	ER	(9,<User abort (asynchronous disconnect)>)
	ER	(24,Flow control violation)
	ER	(32,Too many connections to node)
	ER	(33,Too many connections to target task)
	ER	(34,Access not permitted)
	ER	(35,Logical link Services mismatch)
	ER	(36,Invalid account)
	ER	(37,Segment size too small)
	ER	(38,<User aborted, timed out, or canceled link>)
	ER	(39,No path to target node)
	ER	(40,Flow control violation)
	ER	(41,No current link to target node)
	ER	(42,Confirmation of Disconnect Initiate)
	ER	(43,Image data field too long)
> ;END DISCR DEFINITION

DEFINE ER (VALUE,TXT) <
	.DCX'VALUE==^D'VALUE
	IFDEF %%CUR,<%%DIF==^D'VALUE-%%CUR-1>
	IFNDEF %%CUR,<
		%%CUR==0
		%%DIF==^D'VALUE>
	IFG %%DIF,<REPEAT %%DIF,<[ASCIZ\Unknown\]>>
	[ASCIZ\TXT\]
	%%CUR==^D'VALUE
> ;END OF ER DEFINITION

DSCTBL:	DISCR				;GENERATE TABLE OF REASONS
	DSCMAX==.-DSCTBL
	PURGE	%%CUR,%%DIF
SUBTTL	PURE	TABLES

DEFINE	ER (NAME,VALUE,TEXT) <
	 ER$'NAME==VALUE
> ;End of ER definition

	MACCOD				;Equate the error codes

MACTBL:	[ITEXT	<Operation in progress (^O/P3/)>]
	[ITEXT	<Operation successful (^O/P3/)>]
	[ITEXT	<Unsupported ^Q/P1/ message (^O/P3/)>]
	[ITEXT	<Reserved status message ^O/P2/(^O/P3/)>]
	[ITEXT	<File open error (^O/P3/)>]
	[ITEXT	<Data transfer warning (^O/P3/)>]
	[ITEXT	<Access termination error (^O/P3/)>]
	[ITEXT	<^Q/P1/ message format error (^O/P3/)>]
	[ITEXT	<Invalid ^Q/P1/ message (^O/P3/)>]
	[ITEXT	<^Q/P1/ message received out of sequence>]


;Define macro to generate MICCODE error table

DEFINE ER (NAM,VALUE,TEXT) <
		[ASCIZ\TEXT\],,VALUE
		 ER$'NAM==VALUE
> ;End of ER definition


MICTBL:	MICCOD				;GENERATE MICCODE ERROR TEXT TABLE
	MIC$LN==.-MICTBL		;Remember number of entries in table
SUBTTL	TOPS	20 TO DAP ERROR CONVERSION TABLE

S20DAP:					;TABLE MUST BE SEARCHED - IN ASCENDING SEQ BY 20
	XWD	CACTX1,ER$PRV
	XWD	GJFX3,ER$CJF
	XWD	GJFX4,ER$FNM
	XWD	GJFX5,ER$FNM
	XWD	GJFX6,ER$DEV
	XWD	GJFX7,ER$DIR
	XWD	GJFX9,ER$FNM
	XWD	GJFX10,ER$FID
	XWD	GJFX11,ER$FID
	XWD	GJFX12,ER$FID
	XWD	GJFX13,ER$FID
	XWD	GJFX14,ER$FID
	XWD	GJFX16,ER$DEV
	XWD	GJFX17,ER$DNF
	XWD	GJFX18,ER$FNF
	XWD	GJFX19,ER$FNF
	XWD	GJFX20,ER$FNF
	XWD	GJFX21,ER$FNF
	XWD	GJFX22,ER$DME
	XWD	GJFX23,ER$FUL
	XWD	GJFX24,ER$FNF
	XWD	GJFX27,ER$FEX
	XWD	GJFX28,ER$DNR
	XWD	GJFX29,ER$DNR
	XWD	GJFX32,ER$FNF
	XWD	GJFX33,ER$FNM
	XWD	GJFX34,ER$FID
	XWD	GJFX35,ER$PRV
	XWD	OPNX1,ER$SYS
	XWD	OPNX2,ER$FNF
	XWD	OPNX3,ER$PRV
	XWD	OPNX4,ER$PRV
	XWD	OPNX5,ER$PRV
	XWD	OPNX6,ER$PRV
	XWD	OPNX7,ER$DNR
	XWD	OPNX8,ER$DNR
	XWD	OPNX9,ER$ACT
	XWD	OPNX10,ER$FUL
	XWD	OPNX12,ER$PRV
	XWD	OPNX13,ER$IOP
	XWD	OPNX14,ER$IOP
	XWD	OPNX15,ER$PRV
	XWD	OPNX16,ER$PLG
	XWD	OPNX17,ER$DME
	XWD	OPNX18,ER$DEV
	XWD	DESX1,ER$SYS
	XWD	DESX2,ER$DEV
	XWD	DESX3,ER$CJF
	XWD	DESX4,ER$SYS
	XWD	DESX5,ER$COF
	XWD	DESX6,ER$FNF
	XWD	CLSX1,ER$SYS
	XWD	CLSX2,ER$SYS
	XWD	DELFX1,ER$PRV
	XWD	SFBSX2,ER$BSZ
	XWD	IOX4,ER$EOF
	XWD	IOX5,ER$RER
	XWD	IOX6,ER$WER
	XWD	STADX1,ER$PRV
	XWD	STADX2,ER$PRM
	XWD	DEVX3,ER$DNR
	XWD	RNAMX1,ER$DEV
	XWD	RNAMX3,ER$PRV
	XWD	RNAMX4,ER$DME
	XWD	RNAMX8,ER$PRV
	XWD	RNMX12,ER$FID
	XWD	PMAPX6,ER$FUL
	XWD	OPNX23,ER$FUL
	XWD	GJFX38,ER$FNF
	XWD	IOX7,ER$DME
	XWD	IOX9,ER$IOP
	XWD	OPNX25,ER$WLK
	XWD	GJFX41,ER$FNM
	XWD	GJFX42,ER$FID
	XWD	DELFX3,ER$DME
	XWD	MTOX17,ER$DNR
	XWD	DESX9,ER$IOP
	XWD	IOX11,ER$FUL
	XWD	OPNX31,ER$FNF		;File is offline
	S20DLN=.-S20DAP-1

	LSTOF.				;Do literal expansion
	LIT
	LSTON.


	END