Trailing-Edge
-
PDP-10 Archives
-
decuslib10-08
-
43,50512/xfer.b36
There are no other files named xfer.b36 in the archive.
MODULE XFER=
!Routines to move the actual file data across the network, doing such
!conversions as needed.
BEGIN
!
! Table of Contents
!
FORWARD ROUTINE
RECV, !Get data & put it in a file
XMIT, !Put file data out the network
RECVHANDLE, !Condition handler for RECV
XMITHANDLE; !Condition handler for XMIT
!
! Conditionals
!
OWN SNDEOF: INITIAL(0); ![6] Send EOF at end of transmit
MACRO ALWAYS_SEND_EOF=.SNDEOF %;!
!
! Library references
!
REQUIRE 'INTR.REQ';
LIBRARY 'DAPLIB';
!
! Version
!
THIS_IS [XFER] VERSION[52] EDIT [7] DATE [11,DEC,79]
!
! Revision history
!
%(
[7] Make default action of [6] be not to send eof
[6] Don't always Send STATUS(EOF) on end of transfer
[5] Do Output between Ascii Stream records
[4] Handle ASCII STREAM properly, change record size to 512 for RSTS.
[3] Change default record size to 252 so not send tiny packets
and move special image-mode/end-of-file stuff to DOACM (in DAP module)
[2] Handle ACCESS COMPLETE during transfer properly
[1] XMIT & RECV (and their handlers) moved here from DAP. Changed to
use BYTE mode all the time.
)%
!
! External references
!
EXTERNAL ROUTINE
XBIN, !Get a byte from the net
XBOUT, !Put a byte out the net
BIN, !Get a byte from a file or something
BOUT, !Put one out
XINPUT, !Get a new packet from the network
XOUTPUT,!Force the current packet out
DOACM, ![2] Process ACCESS COMPLETE message
UNWIND; !Unwind the stack
%IF FTTOPS10
%THEN
EXTERNAL ROUTINE FIXIMG
%ELSE
MACRO FIXIMG(A,B)=WIN %
%FI;
!
!Literals
!
LITERAL CR=%O'15', !Carriage return
LF=%O'12', !Line feed
FF=%O'14'; !Form feed
GLOBAL ROUTINE RECV(NB)=
!Accept data messages and write the associated data into an (already open) file
!Argument:
!NB: Node data block, which is the fileblock for the link itself.
! The fileblock for the file is pointed to by NB[NDB$FB]
!This routine will return when finished successfully, or signal errors.
!It is intended to be useable regardless of which end initiated the transfer.
BEGIN
MAP NB: REF NDB;
BIND FB=.NB[NDB$FB]: FILE_BLOCK;
BIND DATATYPE=NB[NDB$DATATYPE]: EX; !DAP datatype field
LOCAL
C, !Last byte in
MTYPE, !Message type
RECNUM: BYTE8VECTOR[9]; !Record number
ESTABLISH(RECVHANDLE,NB);
TOPS10<
IF .DATATYPE[DAT$IMA] AND (.FB[FILE$O_BYTESIZE] NEQ 4) !Check for image mode
THEN BEGIN
FB[FILE$O_BYTESIZE]=4; !4 bits at at time to do wraparound correctly
FB[FILE$O_COUNT]=.FB[FILE$O_COUNT]*9; !9 bytes per word
END
ELSE IF .DATATYPE[DAT$ASC] AND (.FB[FILE$O_BYTESIZE] NEQ 7)
THEN BEGIN
FB[FILE$O_BYTESIZE]=7; !7-bit ascii (in case we were misled)
FB[FILE$O_COUNT]=.FB[FILE$O_COUNT]*5; !5 characters per word
END;
>
WHILE WIN DO
BEGIN !Until EOF or error
LABEL DOSTS;
GET_HDR; !Message type, length, etc.
SELECT .MTYPE OF SET
[DAP_DAT]: BEGIN
GETVC(RECNUM,8,8); !Get the record number
!and ignore it for now
IF .DATATYPE[DAT$IMA]
THEN WHILE .NB[NDB$MLENGTH] GTR 0 DO
!do the unpacking myself
BEGIN
LOCAL TWORD;
TWORD=GET_BYTE;
BOUT(FB[FILE$START],.TWORD<4,4>); !First nibble
BOUT(FB[FILE$START],.TWORD<0,4>); !Second
END
ELSE IF .DATATYPE[DAT$ASC] !ASCII
THEN BEGIN !Block or ASCII stream
LOCAL B; !Last byte gotten
WHILE .N[MLENGTH] GTR 0
DO BOUT(FB,(B=GET_BYTE));
IF .EX[N[FAC],FB$BIO] EQL 0 ![4]
THEN SELECT .B OF SET !Ascii stream
[LF TO CR]:; !Already has VFE
[OTHERWISE]: BEGIN
BOUT(FB,CR);
BOUT(FB,LF);
END;
TES; ![4] ^^^
END
ELSE IF .DATATYPE[DAT$M11] !MACY11 format
THEN BEGIN
LOCAL TWORD,
POS;
CLEARV(TWORD);
POS=26; !First byte stored there
WHILE .N[MLENGTH] GTR 0 DO
BEGIN
TWORD<.POS,8>=GET_BYTE;
!Position to next byte
POS=(SELECTONE .POS OF SET
[26]: 18;
[18]: 8;
[8]: 0;
[0]: (BOUT(FB,.TWORD);26);
TES);
END;
END
ELSE CRASH('NETXXX Undefined datatype (RECV)');
END;
[DAP_STS]: DOSTS:
BEGIN
LOCAL
MACCODE,
MICCODE,
RFA: BYTE8VECTOR[9],
RECNUM: BYTE8VECTOR[9],
STV: BYTE8VECTOR[9];
MICCODE=GET_2BYTE; !Put both here for now
MACCODE=.MICCODE AND %O'170000'; !Pick out MACCODE
MICCODE=.MICCODE AND %O'7777'; !and MICCODE
GETVC(RFA,8);
GETVC(RECNUM,8);
GETVC(STV,8);
SELECT .MACCODE OF SET
[MAC$PEND]: ; !Ignore it for now
[MAC$SUCC,MAC$TRANS]:
BEGIN
IF .MICCODE EQL ER$EOF
THEN BEGIN !End-of-file
IF .N[MASTER]
THEN RETURN
FIXIMG(NB[FILE$START],
FB[FILE$START])
ELSE LEAVE DOSTS; !Ignore
END;
END;
[OTHERWISE]: ERROR(.RMTERR+.MACCODE+.MICCODE,
.STV,.(STV+1));
TES;
END;
[DAP_ACM]: RETURN DOACM(NB[FILE$START]);
[OTHERWISE]: SEND_STATUS(MAC$SYNC,DAP_DAT);
TES;
END;
END; !RECV
GLOBAL ROUTINE XMIT(NB)=
BEGIN
MAP NB: REF NDB;
BIND FB=.NB[NDB$FB]: FILE_BLOCK;
LOCAL RECNUM: BYTE8VECTOR[8]; !Record number
LOCAL MFLAGS: EX[1]; !Message flags
LOCAL USE_TBYTE, !Flag to inform handler if TBYTE contains data
TBYTE; !Temp for half-built byte
BIND DATATYPE=NB[NDB$DATATYPE]: EX; !DAP DATATYPE field
OWN RECSIZE: INITIAL(252); !Record size for output
ESTABLISH(XMITHANDLE,.NB,USE_TBYTE,TBYTE); !Set up condition handler
CLEARV(MFLAGS,RECNUM,TBYTE,USE_TBYTE);
IF .DATATYPE[DAT$IMA] !Check for image mode
THEN BEGIN
FB[FILE$I_BYTESIZE]=4; !4 bits at at time to do wraparound correctly
FB[FILE$I_COUNT]=.FB[FILE$I_COUNT]*9; !bytes are 9 times smaller
END;
DO BEGIN
PUT_BYTE(DAP_DAT); !Data message
PUTEX(MFLAGS);
!No length field or streamid for now
PUTVAR(RECNUM);
!IMAGE mode
IF .DATATYPE[DAT$IMA] THEN
BEGIN
DECR C FROM .RECSIZE-1 TO 0
DO BEGIN
TBYTE=(USE_TBYTE=0);
TBYTE<4,4>=BIN(FB[FILE$START]); !Get a nibble
USE_TBYTE=1; !Tell handler there is a byte waiting
TBYTE<0,4>=BIN(FB[FILE$START]); ! if we get EOF
PUT_BYTE(.TBYTE); !Pump the byte out the network
END;
XOUTPUT(NB[FILE$START]);
END
!ASCII block or stream mode
ELSE IF .DATATYPE[DAT$ASC] THEN
BEGIN
IF .EX[N[FAC],FB$BIO] !Block mode
THEN !
BEGIN
DECR C FROM .RECSIZE-1 TO 0
DO PUT_BYTE(BIN(FB));
XOUTPUT(NB[FILE$START]);
END
ELSE ![4] Stream mode
BEGIN !
LOCAL B; !byte we just got
DO BEGIN
SELECT (B=BIN(FB)) OF SET
[CR]: BEGIN !Process CR
IF (B=BIN(FB)) EQL LF
THEN EXITLOOP !Strip off CRLF
ELSE PUT_BYTE(CR); !Not record separator
END;
[ALWAYS]:
IF .B NEQ 0 !Strip nulls
THEN PUT_BYTE(.B); !Write the data out
[LF TO FF]: EXITLOOP;
TES;
END WHILE 1;
XOUTPUT(NB[FILE$START]); ![5] Send it out
END !ASCII Stream processing
END !ASCII processing
!MACY11 (BIN16) mode
ELSE IF .DATATYPE[DAT$M11] THEN
BEGIN
DECR C FROM .RECSIZE-1 TO 0
DO BEGIN
TBYTE=BIN(FB[FILE$START]); !Get a word from the file
PUT_BYTE(.TBYTE<26,8>); !Pull out 4 bytes
PUT_BYTE(.TBYTE<18,8>); !...
PUT_BYTE(.TBYTE<8,8>); !...
PUT_BYTE(.TBYTE<0,8>); !...
END;
XOUTPUT(NB[FILE$START]);
END
!Should never get here no matter what the remote system tells us
!The datatype has already been checked by this point
ELSE CRASH('NETXXX Unsupported data mode (XMIT)');
END UNTIL 0; !Until we hit EOF, actually
END; !XMIT
ROUTINE XMITHANDLE(SIGNAL_ARGS,MECH_ARGS,ENABLE_ARGS)=
BEGIN
MAP SIGNAL_ARGS: REF VECTOR,
MECH_ARGS: REF VECTOR,
ENABLE_ARGS: REF VECTOR;
!These are all argument lists of the form:
!length,arg1,arg2,arg3,arg4,... (words)
!length does not include the length word itself
!ENABLE_ARGS[1]: address of NDB
!ENABLE_ARGS[2]: USE_TBYTE if set, there is a leftover byte
!ENABLE_ARGS[3]: TBYTE this contains the byte
BIND NB=ENABLE_ARGS[1]: REF NDB;
IF .(SIGNAL_ARGS[SA_CODE])<STSCODE> EQL ENDFILE
THEN BEGIN
IF ..ENABLE_ARGS[2] THEN PUT_BYTE(..ENABLE_ARGS[3]);
!Output the pending byte if there was one
ONOEOR(NB)=0; !This is End-of-record
XOUTPUT(.NB); !Shove out the data
!Always send EOF if old -10 software on network [6]
IF ALWAYS_SEND_EOF OR (.N[MASTER] EQL 0)
THEN SEND_STATUS(MAC$SUCC,ER$EOF); !Status(EOF)
!This is a 'standard' UNWIND
UNWIND(.MECH_ARGS[MA_DEPTH]+1);
!Establisher of this handler will RETURN
RETURN
END;
RETURN SS$_RESIGNAL !Pass the buck
END; !XMITHANDLE
ROUTINE RECVHANDLE(SIGNAL_ARGS,MECH_ARGS,ENABLE_ARGS)=
BEGIN
MAP SIGNAL_ARGS: REF BLOCK FIELD(SA_FIELDS),
MECH_ARGS: REF VECTOR,
ENABLE_ARGS: REF VECTOR;
!These are all argument lists of the form:
!length,arg1,arg2,arg3,arg4,... (words)
!length does not include the length word itself
BIND NB=ENABLE_ARGS[1]: REF NDB;
IF .SIGNAL_ARGS[SA$STSCODE] EQL DAPEOM
THEN RETURN SS$_CONTINUE; !Ignore end-of-message
RETURN SS$_RESIGNAL
END; !RECVHANDLE
END ELUDOM