Google
 

Trailing-Edge - PDP-10 Archives - bb-r775d-bm_tops20_ks_upd_4 - sources/dapsub.bli
There are 21 other files named dapsub.bli in the archive. Click here to see a list.
MODULE DAPSUB(
	IDENT='6.0(6) 1-Mar-83'
        %BLISS36(,
            ENTRY(
                  D$GEXT, ! DAP$GET_EXTENSABLE, ! extensable field -> EX str
                  D$GBIT, ! DAP$GET_BITVECTOR,  ! extensable field -> bitvector
                  D$GVST, ! DAP$GET_VARIABLE_STRING, ! variable length -> asciz
                  D$GVCT, ! DAP$GET_VARIABLE_COUNTED,! variable-len -> var-len
                  D$PEXT, ! DAP$PUT_EXTENSABLE, ! EX str -> extensable field
                  D$PBIT, ! DAP$PUT_BITVECTOR,  ! bitvector -> extensable field
                  D$SIZB, ! DAP$SIZE_BITVECTOR, ! # of bytes to send bitvector
                  D$GSTR, ! DAP$GET_STRING,     ! rest of message -> descriptor
                  SETEXB,                 ! Turn on extension bits where needed
                  CHAZAC,                 ! Convert ASCIZ to ASCIC
                  CHACAZ,                 ! Convert ASCIC to ASCIZ
                  NUM_BV,                 ! number -> variable-length field
                  NUM_VB,                 ! variable-length -> number
                  D$PSTR, ! DAP$PUT_STRING, ! descriptor -> message
                  D$GHDR, ! DAP$GET_HEADER,! DAP message header -> DAP descr
                  D$UHDR, ! DAP$UNGET_HEADER,! Reverse effect of DAP$GET_HEADER
                  D$UBYT, !DAP$UNGET_BYTE, ! Put a byte back to reread later
                  DAP$EAT_MESSAGE,         ! Gobble to the end of the message
                  D$PHDR, ! DAP$PUT_HEADER,! DAP Descr -> DAP message header
                  D$GBYT, ! DAP$GET_BYTE,  ! Get a byte
                  D$PBYT, ! DAP$PUT_BYTE,  ! Put a byte
                  D$G2BY, ! DAP$GET_2BYTE, ! Get 2 bytes
                  D$P2BY, ! DAP$PUT_2BYTE, ! Put 2 bytes
                  D$GLWD, ! DAP$GET_LONGWORD, ! variable field -> longword
                  D$PLWD, ! DAP$PUT_LONGWORD, ! longword -> variable field
                  D$GDTM, ! DAP$GET_DATE,  ! Get date/time
                  D$PDTM, ! DAP$PUT_DATE,  ! Put date/time
                  D$GMSG, ! DAP$GET_MESSAGE, ! Get a message from the net
                  D$PMSG  ! DAP$PUT_MESSAGE ! Put a message to the net
                  ))
	)= BEGIN

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

!++
! FACILITY:	FTS-20 DAP Routines
!
! ABSTRACT:	Routine to read a DAP message headers & fields
!
!
! ENVIRONMENT:	XPN
!
! AUTHOR:	Andrew Nourse, CREATION DATE: 22-Dec-81
!
! MODIFIED BY:
!
! 	, : VERSION
! 06    - Signal XPN failures (rather than letting XPN$_FAILURE blab on tty)
! 05    - Make DAP$GET_BITVECTOR handle long bitvectors correctly
! 04    - Handle reverse messages better
! 03    - Put in Entry points
! 02    - Routines to read/write dates
! 01	- The beginning
!--
!
! Library and Require Files
!

Library 'Dap';
Library 'Bli:Xport';
Library 'Blissnet';
Library 'Condit';

!
! Table of Contents
!

Forward Routine
dap$get_extensable,                     !get extensable field as ex field
dap$get_bitvector,                      !get extensable field as bit vector
dap$get_variable_string,                !get variable length ascii field
dap$get_variable_counted,               !get variable-len field including count
dap$put_extensable,                     ! put extensable field
dap$put_bitvector,      !put a bitvector in message as extensable field
dap$size_bitvector,     ! count lit bits in a bitvector, how many bytes needed
dap$get_string : novalue,         ! get rest of message into string descriptor
setexb,			! turn on extension bits where needed
chazac,			! convert asciz to ascic
chacaz,			! convert ascic to asciz
num_bv:novalue,         ! convert a number to a variable-length field
num_vb,			! convert a variable-length field to a number
dap$put_string : novalue,       ! put string (possibly 8 bit bytes) in message
dap$get_header,         ! get the dap message header for a new message
dap$unget_header,       ! restore descriptor to state before we read header
dap$unget_byte: novalue,! put a byte back to reread later
dap$eat_message: novalue, ! gobble to the end of the message, ignore contents
dap$put_header: novalue, ! put the dap message header into the message
dap$get_byte,                           ! get a byte
dap$put_byte : novalue,                 ! put a byte
dap$get_2byte,                          ! get 2 bytes
dap$put_2byte : novalue,                ! put 2 bytes
dap$get_longword,                       ! get longword (as variable field)
dap$put_longword : novalue,             ! put longword (as variable field)
dap$get_date : novalue,                 ! get date/time
dap$put_date : novalue,                 ! put date/time
dap$get_message,                        ! get a message from the net
getdata : novalue,                      ! get data from msg into descr
dap$put_message;                        ! Put a message to the net

!
! Global Data
!
GLOBAL D$GTRACE: BITVECTOR[32];         ! Control tracing with this
BIND TRACE=D$GTRACE;                    ! Be reasonable


EXTERNAL ROUTINE
                XPN$SIGNAL,
                DAP$GET_STATUS,
                D$TRACE;
GLOBAL ROUTINE DAP$GET_EXTENSABLE(DD,PTR,MAXLEN)=
!++
! FUNCTIONAL DESCRIPTION:
!
!	Get an extensible field and write 8 bit bytes through PTR
!
! FORMAL PARAMETERS:
!
!	DD:     DAP Descriptor addr
!	PTR:	destination byte pointer
!	MAXLEN:	maximum number of bytes
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	Returns length of field
!
!
! SIDE EFFECTS:
!
!	NONE
!
!--
BEGIN
MAP DD: REF $DAP_DESCRIPTOR;
LOCAL
	B;				!Most recent byte

INCR FLENGTH FROM 1 TO .MAXLEN DO
	BEGIN
	CH$WCHAR_A((B=GET_BYTE(DD[$])),PTR);
	IF (.B AND %O'200') EQL 0 THEN RETURN .FLENGTH;	!Extension bit off
	END;
DAP$_FTL					!Dap field too long
END;	!DAP$GET_EXTENSABLE
GLOBAL ROUTINE DAP$GET_BITVECTOR(DD,BV,MAXLEN)=
!++
! FUNCTIONAL DESCRIPTION:
!
!	Get an extensible field and write bitvector
!
! FORMAL PARAMETERS:
!
!	DD:     DAP Descriptor addr
!	BV:	destination bit vector addr
!	MAXLEN:	maximum number of 8 bit bytes
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	Returns length of field
!
!
! SIDE EFFECTS:
!
!	NONE
!
!--
BEGIN
MAP DD: REF $DAP_DESCRIPTOR;
MAP BV: REF BITVECTOR;
LOCAL
        BVEC: REF BITVECTOR,            ![5] Current word
        OFF,                            ! Current bit offset
	B;				! Most recent byte

BVEC=.BV;                               ![5] Point to start of bitvector
OFF=0;

INCR FLENGTH FROM 1 TO .MAXLEN DO
	BEGIN
        B=GET_BYTE(DD[$]);
        IF .OFF GEQ (%BPVAL-7)
        THEN
            BEGIN
            (.BVEC)<.OFF,%BPVAL-.OFF>=.B;       ![5] Wrap around byte
            BVEC=.BVEC+1;                       ! to next word
            OFF=7-(%BPVAL-.OFF);
            IF .OFF GTR 0 THEN (.BVEC)<0,.OFF>=.B<7-.OFF,.OFF>;
            END
        ELSE (.BVEC)<.OFF,7>=.B;        ![5]
        OFF=.OFF+7;
	IF (.B AND %O'200') EQL 0 THEN RETURN .FLENGTH;	!Extension bit off
	END;
DAP$_FTL					!Dap field too long
END;	!DAP$GET_BITVECTOR
GLOBAL ROUTINE DAP$GET_VARIABLE_STRING(DD,PTR,MAXLEN)=
!++
! FUNCTIONAL DESCRIPTION:
!
!	Get a variable-length field and write it starting where PTR points
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!	MAXLEN:	maximum number of bytes
!	PTR:	destination byte pointer
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	Length of field (excluding count)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
BEGIN
LOCAL LEN;
MAP DD: REF $DAP_DESCRIPTOR;

IF (LEN=GET_BYTE(DD[$])) GTR .MAXLEN THEN RETURN DAP$_FTL;
DECR L FROM .LEN TO 1 DO
	CH$WCHAR_A(GET_BYTE(DD[$]),PTR);
CH$WCHAR_A(0,PTR);	!Make ASCIZ string
.LEN	!Return length
END;	!DAP$GET_VARIABLE_STRING
GLOBAL ROUTINE DAP$GET_VARIABLE_COUNTED(DD,PTR,MAXLEN)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Get a variable-length field and write it starting where PTR points
!	identical to MGETVAR except that the count is also copied
!	This should be used for binary fields
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!	MAXLEN:	maximum number of bytes
!	PTR:	destination byte pointer
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	length of field (excluding count)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;
LOCAL LEN;
IF (LEN=GET_BYTE(DD[$])) GTR .MAXLEN THEN RETURN DAP$_FTL;

CH$WCHAR_A(.LEN,PTR);	!Copy the count first

DECR L FROM .LEN TO 1 DO
	CH$WCHAR_A(GET_BYTE(DD[$]),PTR);
CH$WCHAR_A(0,PTR);	!Make ASCIZ string
.LEN	!Return length
END;	!DAP$GET_VARIABLE_COUNTED
GLOBAL ROUTINE SETEXB(EXF,LEN)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Turn on extension bits if any trailing bits are on
!
! FORMAL PARAMETERS:
!
!	EXF:	Address of extensible field
!	LEN:	Length of extensible field in bytes
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	The extension bits in EXF are set where they should be
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	Number of bytes needed
!
! SIDE EFFECTS:
!
!	NONE
!
!--
LOCAL B;			!Highest bit that was on
LOCAL S;			!Did we see any bits yet?

B=0;
S=0;				!Haven't seen any bits on yet
DECR I FROM ((.LEN*8)-2) TO 7 DO BEGIN
	MAP EXF: REF EX;
	IF (.EXF[.I] AND (.S EQL 0)) THEN
			BEGIN
			B=.I;	!Remember highest bit found
			S=1;	!Just saw one
			END;
	IF (.I AND 7) EQL 7 THEN EXF[.I]=.S;
		!That was an extension bit, set it if necessary
	END;
(.B/8)+1			!Return highest byte needed
END;	!SETEXB
GLOBAL ROUTINE CHAZAC(AZP,ACP)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Convert ASCIZ string to ASCIC (counted ASCII) string
!
! FORMAL PARAMETERS:
!
!	AZP:	Byte pointer to ASCIZ string
!	ACP:	Byte pointer to where to store ASCIC string
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	length of string (excluding count)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
LOCAL ACLENP;	!Pointer to length field

ACLENP=.ACP;	!Length is stored in first position
CH$RCHAR_A(ACP);	!Skip output pointer past where length will go
INCR LEN FROM 0 BY 1 DO
	BEGIN
	LOCAL C;
	CH$WCHAR_A((C=CH$RCHAR_A(AZP)),ACP);
	IF .C EQL 0 THEN
		BEGIN
		CH$WCHAR_A(.LEN,ACLENP);	!Put length in first position
		RETURN .LEN
		END
	END
END;	!CHAZAC
GLOBAL ROUTINE CHACAZ(ACP,AZP)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Convert ASCIC string to ASCIZ string
!
! FORMAL PARAMETERS:
!
!	ACP:	Byte pointer to ASCIC string
!	AZP:	Byte pointer to where to store ASCIZ string
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	The string (converted) is stored thru AZP
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	Length of string (excluding null byte at end)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
LOCAL LEN;

LEN=CH$RCHAR_A(ACP);	!Get length
CH$MOVE(.LEN,.ACP,.AZP);	!Copy that many characters
CH$WCHAR_A(0,AZP);	!Put null byte at end
.LEN			!Return length
END;	!CHACAZ
GLOBAL ROUTINE NUM_BV(VAR,NUM) :NOVALUE=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Convert an unsigned binary number
!	into a DAP-format variable-length field.
!	[Note that binary numbers are sent to DAP
!	least significant byte first]
!
! FORMAL PARAMETERS:
!
!	NONE
!
! IMPLICIT INPUTS:
!
!	VAR: address of variable-length field
!	NUM: value to convert
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE
!
! SIDE EFFECTS:
!
!	NONE
!
!--
LOCAL	PTR,
	FPTR;

FPTR=CH$PTR(.VAR,0,8);	!Pointer to length field
PTR=CH$PTR(.VAR,1,8);	!Pointer to data portion
INCR I FROM 0 TO ((%BPVAL+7)/8)-1 DO
	BEGIN
	IF .NUM EQL 0 THEN	(CH$WCHAR_A(.I,FPTR);	!Write the length
				RETURN);
	CH$WCHAR_A(.NUM,PTR);	!Write the next 8 bits worth
	NUM=.NUM^(-8);		!and shift it away
	END
END;	!NUM_BV
GLOBAL ROUTINE NUM_VB(VAR)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Convert a variable-length field into a binary number (unsigned)
!
! FORMAL PARAMETERS:
!
!	VAR: address of variable-length field
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	Binary value
!
! SIDE EFFECTS:
!
!	NONE
!
!--
LOCAL	PTR,
	NUM;

NUM=0;
PTR=CH$PTR(.VAR,0,8);

INCR I FROM 0 TO CH$RCHAR_A(PTR)-1 DO
	BEGIN
	NUM=.NUM+(CH$RCHAR_A(PTR)^(.I*8))
	END;
.NUM
END; !NUM_VB
GLOBAL ROUTINE DAP$PUT_STRING(DD,DATADESC): NOVALUE=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!       Put a string of data from a descriptor into DAP message
!       8 bit bytes permissable
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       DATA: STRING to put
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	length of field (excluding count)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;
MAP DATADESC: REF $XPN_DESCRIPTOR();

LOCAL DESCPTR;

DESCPTR=.DATADESC[XPO$A_ADDRESS];
DECR I FROM .DATADESC[XPO$H_LENGTH]-1 TO 0
DO PUT_BYTE(DD[$],CH$RCHAR_A(DESCPTR));
END;	!DAP$PUT_STRING
GLOBAL ROUTINE DAP$PUT_VARIABLE_STRING(DD,PTR): NOVALUE=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!       Put a string of ASCIZ data into DAP message
!       8 bit bytes permissable
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       PTR: Pointer to STRING to put
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	length of field (excluding count)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;

LOCAL LEN,
      TPTR;

TPTR=.PTR;
LEN=0;
WHILE CH$RCHAR_A(TPTR) NEQ 0 DO LEN=.LEN+1;     ! Count chars in string

DECR I FROM .LEN-1 TO 0
DO PUT_BYTE(DD[$],CH$RCHAR_A(PTR));
END;	!DAP$PUT_VARIABLE_STRING
GLOBAL ROUTINE DAP$PUT_VARIABLE_COUNTED(DD,PTR) : NOVALUE =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!       Put a string of ASCIC data into DAP message
!       8 bit bytes permissable
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       PTR: Pointer to STRING to put
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	length of field (excluding count)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;
LOCAL LEN;

PUT_BYTE(DD[$],(LEN=CH$RCHAR_A(PTR)));  ! Put the length field first

DECR I FROM .LEN-1 TO 0
DO PUT_BYTE(DD[$],CH$RCHAR_A(PTR));
END;	!DAP$PUT_VARIABLE_COUNTED
GLOBAL ROUTINE DAP$PUT_EXTENSABLE(DD,EXF)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!       Put a string of bits in EXTENSABLE format into DAP message
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       EXF: FIELD to put
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	length of field (excluding count)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;
MAP EXF: REF EX;

LOCAL CNT;
LOCAL TPTR;
LOCAL BYT;

TPTR=CH$PTR(.EXF,0 %BLISS36(,9));         ! Point to extensable field

DO  BEGIN
    PUT_BYTE(DD[$],(BYT=CH$RCHAR_A(TPTR)));
    CNT=.CNT+1;
    END WHILE .BYT<7,1> NEQ 0;          ! Keep it up until extensable bit off
.CNT
END;	!DAP$PUT_EXTENSABLE
GLOBAL ROUTINE DAP$PUT_BITVECTOR(DD,BV,MAXLEN)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!       Put a string of bits in EXTENSABLE format into DAP message
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       BV: Addr of bit vector
!       MAXLEN: maximum number of bytes possible 
!
! ROUTINE VALUE:
!
!	length of field (excluding count)
!
!--
MAP DD: REF $DAP_DESCRIPTOR;

LOCAL BVEC;                             ![5]
LOCAL CNT;
LOCAL OFF;
LOCAL BYT;

OFF=0;
BVEC=.BV;                               ![5]

CNT=$DAP_SIZE_BITVECTOR[.BVEC,.MAXLEN]; ![5]

INCR I FROM 1 TO .CNT
DO  BEGIN
    IF .OFF GEQ (%BPVAL-7)
    THEN
        BEGIN
        BYT=.(.BVEC)<.OFF,%BPVAL-.OFF>; ![5] Wrap around byte
        BVEC=.BVEC+1;                   ! to next word
        OFF=7-(%BPVAL-.OFF);
        IF .OFF GTR 0 THEN BYT<7-.OFF,.OFF>=.(.BVEC)<0,.OFF>
        END
    ELSE
        BEGIN
        BYT=.(.BVEC)<.OFF,7>;           ![5]
        OFF=.OFF+7;
        END;

    BYT<7,1>=(.I NEQ .CNT);             ! Set extensable bit unless last
    PUT_BYTE(DD[$],.BYT);
    END;

.CNT
END;	!DAP$PUT_BITVECTOR
GLOBAL ROUTINE DAP$SIZE_BITVECTOR(BVEC,MAXLEN,MINLEN)=
BEGIN
MAP BVEC: REF BITVECTOR;
LOCAL CNT;

CNT=.MINLEN;                            ! Must be at least 1
DECR I FROM (.MAXLEN*7)-1 TO 0          ! See how many bytes we need
DO IF .BVEC[.I] NEQ 0 THEN
     BEGIN
     CNT=(.I+7)/7;
     EXITLOOP;
     END;
.CNT
END;                                    ! End of DAP$SIZE_BITVECTOR
GLOBAL ROUTINE DAP$GET_STRING(DD,DATADESC) : NOVALUE =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!       Get a string of data into a descriptor from DAP
!       8 bit bytes permissable
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       DATA: Where to put the data
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	length of field (excluding count)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;
MAP DATADESC: REF $XPN_DESCRIPTOR();

LOCAL DESCPTR;

DESCPTR=.DATADESC[XPO$A_ADDRESS];
DECR I FROM .DD[DAP$H_LENGTH]-1 TO 0
DO CH$WCHAR_A(GET_BYTE(DD[$]),DESCPTR);
END;	!DAP$GET_STRING
GLOBAL ROUTINE DAP$GET_HEADER(DD)=
!Get the DAP message header for the next message
!++
! FUNCTIONAL DESCRIPTION:
!
!	Get the DAP message header for the next message
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP header block
!
! IMPLICIT INPUTS:
!
!	If no data in descriptor, DD[DAP$A_NLB] is used to find NLB
!
! IMPLICIT OUTPUTS:
!
!	DD is set up
!
! ROUTINE VALUE:
!
!	DAP message type.
!
! SIDE EFFECTS:
!
!	DAP Message header will have been read
!
!--
	BEGIN
        MAP DD: REF $DAP_DESCRIPTOR;
        LOCAL MFLAGS;

	IF .DD[DAP$H_BYTES_REMAINING] LEQ 0 THEN DAP$GET_MESSAGE(DD[$]);
	!Get new buffer if needed

        ! Save position of start of message in case we need to back up
        DD[DAP$H_OFFSET]=.DD[DAP$H_BYTES_USED];

	DD[DAP$H_LENGTH]=.DD[DAP$H_BYTES_REMAINING];

        DD[DAP$B_OPERATOR]=GET_BYTE(DD[$]);          !Message type

	DAP$GET_BITVECTOR(DD[$],DD[DAP$V_MFLAGS],5); !Message Flags

	IF .DD[DAP$V_MFLAGS_LENGTH]               !Length if present
	THEN DD[DAP$H_LENGTH]=GET_BYTE(DD[$]) +
                              (IF .DD[DAP$V_MFLAGS_LEN256]
                               THEN (GET_BYTE(DD[$])^8) ELSE 0) +
                              .DD[DAP$V_MFLAGS_BITCNT];
                              ! Length field, with high order byte if present
                              ! add 1 byte for bit count if present
                              ! since that is not supposed to be counted
                              ! in the length (being part of the header)

        IF .DD[DAP$V_MFLAGS_BITCNT]
        THEN DD[DAP$H_BITCNT]=GET_BYTE(DD[$]);  ! Bit Count

	.DD[DAP$B_OPERATOR]	!Returned as value
	END;	!End of DAP$GET_HEADER
GLOBAL ROUTINE DAP$UNGET_HEADER(DD)=
!++
! FUNCTIONAL DESCRIPTION:
!
!	Backtrack so DAP$GET_HEADER gets same message over again
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP header block
!
! IMPLICIT INPUTS:
!
!	If no data in descriptor, DD[DAP$A_NLB] is used to find NLB
!
! IMPLICIT OUTPUTS:
!
!	DD is set up
!
! ROUTINE VALUE:
!
!	DAP message type.
!
! SIDE EFFECTS:
!
!	Current DAP Message will be read again on next DAP$GET_HEADER
!
!--
	BEGIN
        MAP DD: REF $DAP_DESCRIPTOR;
        LOCAL BACKUP_COUNT;

        ! How far do we need to back up?
        BACKUP_COUNT=.DD[DAP$H_BYTES_USED]-.DD[DAP$H_OFFSET];

        ! Restore position of start of message.
        DD[DAP$H_BYTES_USED]=.DD[DAP$H_OFFSET];
        DD[DAP$H_BYTES_REMAINING]=.DD[DAP$H_BYTES_REMAINING]+.BACKUP_COUNT;
        DD[DAP$A_DATA]=CH$PLUS(.DD[DAP$A_DATA],-.BACKUP_COUNT);

	DD[DAP$H_LENGTH]=.DD[DAP$H_BYTES_REMAINING];

	.DD[DAP$B_OPERATOR]	!Returned as value
	END;	!End of DAP$UNGET_HEADER
GLOBAL ROUTINE DAP$UNGET_BYTE(DD): NOVALUE=
!++
! FUNCTIONAL DESCRIPTION:
!
!	Backtrack 1 byte so DAP$GET_BYTE gets same byte over again
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP header block
!
! IMPLICIT INPUTS:
!
!	If no data in descriptor, DD[DAP$A_NLB] is used to find NLB
!
!--
	BEGIN
        MAP DD: REF $DAP_DESCRIPTOR;

        ! Back everything up 1 byte
        DD[DAP$H_BYTES_USED]=.DD[DAP$H_BYTES_USED]-1;
        DD[DAP$H_BYTES_REMAINING]=.DD[DAP$H_BYTES_REMAINING]+1;
        DD[DAP$A_DATA]=CH$PLUS(.DD[DAP$A_DATA],-1);
	DD[DAP$H_LENGTH]=.DD[DAP$H_LENGTH]+1;
	END;	!End of DAP$UNGET_BYTE
GLOBAL ROUTINE DAP$EAT_MESSAGE(DD): NOVALUE=
!++
! FUNCTIONAL DESCRIPTION:
!
!       Ignore rest of message, be ready to read next message
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP header block
!
!--
    BEGIN
    MAP DD: REF $DAP_DESCRIPTOR;

    WHILE .DD[DAP$H_LENGTH] GTR 0
    DO DAP$GET_BYTE(DD[$]);
    END;	!End of DAP$EAT_MESSAGE
GLOBAL ROUTINE DAP$PUT_HEADER(DD): NOVALUE=
!Build the DAP message header for the next message
!++
! FUNCTIONAL DESCRIPTION:
!
!	Build the DAP message header for the next message
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP header block
!
! IMPLICIT INPUTS:
!
!	NLB attached to DD will be used for output if necessary.
!
! SIDE EFFECTS:
!
!       If new message won't fit (as determined by info in DD)
!       then the current contents of the buffer are output first
!--
	BEGIN
        MAP DD: REF $DAP_DESCRIPTOR;

	IF .DD[DAP$H_BYTES_REMAINING] LEQ (.DD[DAP$H_LENGTH]+5)
        THEN DAP$PUT_MESSAGE(DD[$]);
	!Output buffer if new message won't fit

        PUT_BYTE(DD[$],.DD[DAP$B_OPERATOR]);          !Message type

        IF (.DD[DAP$H_LENGTH] GTR 255)            !need to set len256?
        AND .DD[DAP$V_MFLAGS_LENGTH]
        THEN DD[DAP$V_MFLAGS_LEN256]=1;

	DAP$PUT_BITVECTOR(DD[$],DD[DAP$V_MFLAGS],6);   !Message Flags

	IF .DD[DAP$V_MFLAGS_LENGTH]               !Length if present
	THEN PUT_BYTE(DD[$], .DD[DAP$H_LENGTH]);

        IF .DD[DAP$V_MFLAGS_LEN256]               ! Really long?
        THEN PUT_BYTE(DD[$], .DD[DAP$H_LENGTH]^-8);

        IF .DD[DAP$V_MFLAGS_BITCNT]               ! Bits left over?
        THEN PUT_BYTE(DD[$],.DD[DAP$H_BITCNT]);

	END;	!End of DAP$PUT_HEADER
GLOBAL ROUTINE DAP$GET_BYTE(DD)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Get a byte
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	The byte gotten, or -1 if message is empty
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;

IF .DD[DAP$H_LENGTH] LEQ 0
THEN (IF .DD[DAP$V_MFLAGS_MORE]
      THEN GET_HEADER(DD[$])
      ELSE RETURN -1);

DD[DAP$H_LENGTH]=.DD[DAP$H_LENGTH]-1;             ! Decr DAP length
DD[DAP$H_BYTES_REMAINING]=.DD[DAP$H_BYTES_REMAINING]-1; ! And bytes left
DD[DAP$H_BYTES_USED]=.DD[DAP$H_BYTES_USED]+1;     ! Incr bytes eaten

CH$RCHAR_A(DD[DAP$A_DATA])                        ! Finally read the byte
END;	!DAP$GET_BYTE
GLOBAL ROUTINE DAP$PUT_BYTE(DD,DATA) : NOVALUE =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!       Put a byte of data into a descriptor
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       DATA: Byte to put
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	length of field (excluding count)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;
LOCAL LEN;

DD[DAP$H_BYTES_USED]=.DD[DAP$H_BYTES_USED]+1;
DD[DAP$H_BYTES_REMAINING]=.DD[DAP$H_BYTES_REMAINING]-1;
CH$WCHAR_A(.DATA,DD[DAP$A_DATA]);	!Copy the count first
END;	!DAP$PUT_BYTE
GLOBAL ROUTINE DAP$GET_2BYTE(DD)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Get 2 bytes
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	The byte gotten, or -1 if message is empty
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;

GET_BYTE(DD[$])+(GET_BYTE(DD[$])^8)

END;	!DAP$GET_2BYTE
GLOBAL ROUTINE DAP$PUT_2BYTE(DD,DATA): NOVALUE =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!       Put 2 bytes of data into a descriptor
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       DATA: Value to put
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;

PUT_BYTE(DD[$],.DATA);
PUT_BYTE(DD[$],(.DATA)^-8);
END;	!DAP$PUT_2BYTE
GLOBAL ROUTINE DAP$GET_LONGWORD(DD)=
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	Get a longword (4 bytes) of binary data
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	The value gotten
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;
LOCAL LEN,
      VALUE;

VALUE=0;
LEN=GET_BYTE(DD[$]);

INCR I FROM 0 TO .LEN-1
DO
    BEGIN
    IF .VALUE<%BPVAL-8,8> NEQ 0            ! Check for overflow about to happen
    THEN SIGNAL (DAP$_FTL,0,DD[$]);        ! It did. This way allows lots of
    VALUE=.VALUE+(GET_BYTE(DD[$])^(.I*8)); ! leading zeroes without error
    IF .VALUE LSS 0
    THEN SIGNAL (DAP$_FTL,0,DD[$]);     ! If sign flipped, we overflowed too.
    END;

.VALUE
END;	!DAP$GET_LONGWORD
GLOBAL ROUTINE DAP$PUT_LONGWORD(DD,DATA) : NOVALUE =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!       Put a byte of data into a descriptor as variable field
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       DATA: Value to put
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
!
!	length of field (excluding count)
!
! SIDE EFFECTS:
!
!	NONE
!
!--
MAP DD: REF $DAP_DESCRIPTOR;
LOCAL LEN;

LEN=4;                                            ! For now

PUT_BYTE(DD[$],.LEN);

DECR I FROM .LEN-1 TO 0                           ! Put the least signif first
DO (PUT_BYTE(DD[$],.DATA);
    DATA=.DATA^-8);
END;	!DAP$PUT_LONGWORD
GLOBAL ROUTINE DAP$GET_DATE(DD: REF $DAP_DESCRIPTOR,PTR) : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
!
!	Get a Date from a message (18 bytes, ASCII)
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       PTR: thru which to write date
!
!--
      BEGIN                             ! Read a date/time (18 ascii bytes)
      DECR I FROM 17 TO 0
      DO CH$WCHAR_A(DAP$GET_BYTE(DD[$]),PTR);
      END;
GLOBAL ROUTINE DAP$PUT_DATE(DD: REF $DAP_DESCRIPTOR,PTR) : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
!
!	Put a Date into a message (18 bytes, ASCII)
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!       PTR: thru which to read date
!
!--
      BEGIN                             ! Put a date/time (18 ascii bytes)
      DECR I FROM 17 TO 0
      DO DAP$PUT_BYTE(DD[$],CH$RCHAR_A(PTR));
      END;
GLOBAL ROUTINE DAP$GET_MESSAGE(DD) =
!++
! FUNCTIONAL DESCRIPTION:
!
!	Get a message from remote system
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!
! COMPLETION CODES:
!
!       Success/Failure code returned by BLISSNET
!
!--
BEGIN
LOCAL R;
MAP DD: REF $DAP_DESCRIPTOR;
BIND NLB=.DD[DAP$A_NLB]: $XPN_NLB();

R = $XPN_GET(NLB=NLB, OPTION=WAIT, FAILURE=XPN$SIGNAL);  ! Get message

GETDATA(DD[$]);

.R
END;
ROUTINE GETDATA (DD: REF $DAP_DESCRIPTOR): NOVALUE =
BEGIN
BIND NLB=.DD[DAP$A_NLB]: $XPN_NLB();

$XPN_DESC_INIT(DESCRIPTOR=DD[DAP$T_DATA],CLASS=BOUNDED); ! Point to it
DD[DAP$A_DATA]=.NLB[NLB$A_STRING];                       ! 
DD[DAP$H_BYTES_REMAINING]=DD[DAP$H_MESSAGE_LENGTH]=.NLB[NLB$H_BYTES];

! Trace if requested
IF .D$GTRACE LSS 0 THEN D$TRACE(DD[$],DAP$K_TRACE_INPUT);
END;
GLOBAL ROUTINE DAP$PUT_MESSAGE(DD) =
!++
! FUNCTIONAL DESCRIPTION:
!
!	Put a message to remote system
!
! FORMAL PARAMETERS:
!
!       DD: Addr of DAP descriptor
!
! COMPLETION CODES:
!
!       Success/Failure code returned by BLISSNET
!
!--
       BEGIN
       LOCAL R;
       MAP DD: REF $DAP_DESCRIPTOR;     ! Message descriptor (bounded)
                                        ! data is in prefix
       BIND OTHER_DD=.DD[DAP$A_OTHER_DD]: $DAP_DESCRIPTOR;    

       IF (OTHER_DD NEQ 0)
       AND (.OTHER_DD[DAP$H_BYTES_REMAINING] EQL 0) ![4] Check for
       THEN                                         ![4] reverse traffic
           BEGIN                                    ![4]
           BIND NLB=.DD[DAP$A_NLB]: $XPN_NLB();
           IF .NLB[NLB$V_DATA_REQ] EQL 0          ![4] Is a read posted?
           THEN $XPN_GET(NLB=NLB,                 ![4] No. post one.
                         FAILURE=XPN$SIGNAL);     ![6] Signal failure if any
           SELECT $XPN_EVENT_INFO(NLB=NLB, FAILURE=XPN$SIGNAL) OF ![6]
           SET
           [XPN$_INTERRUPT]:                      ![4] Got interrupt message
               BEGIN
               0                        !? need to do this for FAL
               END;
           [XPN$_DATA]:                           ![4] got data message
               BEGIN
               GETDATA(OTHER_DD[$]);    ![4] make descr point to data
               IF DAP$GET_HEADER(OTHER_DD[$]) EQL DAP$K_STATUS
               THEN
                   BEGIN
                   SIGNAL(DAP$GET_STATUS(OTHER_DD[$]))
                   END
               ELSE DAP$UNGET_HEADER(OTHER_DD[$])
               END;
           TES;
           END;                                   ![4] 

       DD[DAP$H_BYTES_REMAINING]=.DD[DAP$H_BYTES_USED]; !Make descr point
       DD[DAP$H_BYTES_USED]=0;                          !to data in message
       DD[DAP$A_DATA]=CH$PLUS(.DD[DAP$A_DATA],-.DD[DAP$H_BYTES_REMAINING]);

       ! Trace message if requested
       IF .D$GTRACE LSS 0 THEN D$TRACE(DD[$],DAP$K_TRACE_OUTPUT);

       IF .DD[DAP$V_INTERRUPT]
       THEN
           BEGIN
           R=$XPN_PUT(NLB=.DD[DAP$A_NLB],STRING=DD[DAP$T_DATA],
                      OPTION=END_OF_MESSAGE,  FAILURE=XPN$SIGNAL,
                      TYPE=INTERRUPT);
           DD[DAP$V_INTERRUPT]=0;
           END
       ELSE
           R=$XPN_PUT(NLB=.DD[DAP$A_NLB],STRING=DD[DAP$T_DATA],
                      OPTION=END_OF_MESSAGE, TYPE=DATA, FAILURE=XPN$SIGNAL);


       DD[DAP$H_BYTES_REMAINING]=.DD[DAP$H_MESSAGE_LENGTH];

       .R
       END;
END ELUDOM