Google
 

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