Google
 

Trailing-Edge - PDP-10 Archives - bb-h138f-bm - 7-sources/rmscnv.b36
There are 3 other files named rmscnv.b36 in the archive. Click here to see a list.
MODULE RMSCNV (					! Data conversions
               IDENT='1'
              )=
BEGIN              
!
!	COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1984, 1986.
!	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: RMS-20
!
! ABSTRACT: This module contains routines to convert among the datatypes
!           known to RMS:  ASCII, Packed decimal, Integer, Long (2 word)
!           Integer, and Unsigned Integer.
!           Floating-point conversion routines are in RMSFLO.
!
!
! ENVIRONMENT: TOPS-20 or TOPS-10 (KL only)
!
! AUTHOR:	Andrew Nourse, CREATION DATE: 30-August-83
!
!--
!
! TABLE OF CONTENTS:
!

FORWARD ROUTINE
	cvtps,                          ! Convert PACKED to ASCII string
        cvtsp,                          ! Convert ASCII string to PACKED
	cvtzp,                          ! Convert ASCIZ string to PACKED
        cvtsi,                          ! Convert ASCII string to INTEGER
        cvtsl,                          ! Convert ASCII string to LONG INTEGER
        cvtzl,                          ! Convert ASCIZ string to LONG INTEGER
        cvtsu,                          ! Convert ASCII string to UNSIGNED
        cvtzu,                          ! Convert ASCIZ string to UNSIGNED
        cvtsd,                          ! Convert ASCII string to DOUBLE
        cvtzd,                          ! Convert ASCIZ string to DOUBLE
        cvtsg,                          ! Convert ASCII string to G-FLOATING
        cvtzg,                          ! Convert ASCIZ string to G-FLOATING
        signbe,                         ! Check for sign at begin and end
        signb,                          ! Check for sign at beginning
        plusminus;                      ! Check char for + or -

!
! INCLUDE FILES:
!

!
! MACROS:
!
MACRO                                   ! All legal forms of BCD signs
    Visible_Plus_signs=%X'A',%X'C' %,
    Invisible_Plus_signs=%X'E',%X'F' %,
    Minus_signs=%X'B',%X'D' %;

MACRO DMUL(r,y)=MACHOP(%O'116',r,y) %;

!
! EQUATED SYMBOLS:
!

LITERAL                                 ! The form of BCD signs we store
    Visible_Plus_sign=%X'A',
    Invisible_Plus_sign=%X'E',
    Minus_sign=%X'B';

LITERAL maximum_packed_field_length=12;
LITERAL digit_size=4,
    	digit_mask=%X'F';

!
! OWN STORAGE:
!

!
! BUILTIN FEATURES:
!

BUILTIN MACHOP;

!
! EXTERNAL REFERENCES:
!
EXTERNAL ROUTINE
    cvtld,
    cvtlg;
GLOBAL ROUTINE cvtps(packednum,str)=		! Convert Packed to String
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert a packed decimal number to a string
!
! FORMAL PARAMETERS:
!
!   	packednum:	Address of Byte Pointer to packed decimal string
!   	str:		Address of Byte Pointer to store ascii string
!
! RETURNED VALUE:
!
!   	Number of characters in string
!
! SIDE EFFECTS:
!
!   	The byte pointers are updated past the strings
!--
BEGIN
LOCAL len;	! Temp to store length of result

len=( 
    INCR i from 1 TO maximum_packed_field_length
    DO
	BEGIN
	LOCAL b;	! Current byte from packed-decimal string
	LOCAL d;	! Current decimal digit

	b=CH$RCHAR_A(.packednum);	! This will contain 2 digits

	d=(.b^-digit_size) AND digit_mask;	! Fetch the first digit
	d=.d+%C'0';                     ! Convert the first digit to ASCII
	CH$WCHAR_A(.d,.str);		! Write it out to the destination

	d=.b AND digit_mask;		! Fetch the second digit
	CASE .d FROM %X'A' TO %X'F' OF
	    SET
                [Visible_plus_signs]:
		BEGIN
		CH$WCHAR_A(%C'+',.str);	! Write out a trailing plus sign
		EXITLOOP .i*2;
		END;
	    [Minus_signs]:
		BEGIN
		CH$WCHAR_A(%C'-',.str);	! Write out trailing minus sign
		EXITLOOP .i*2;
		END;
	    [Invisible_Plus_signs]:
		EXITLOOP .i*2-1;	! We are done
	    [OUTRANGE]:			   ! Has to be a real digit
		CH$WCHAR_A(.d+%C'0',.str); ! Write it out to the destination
	    TES
	END ! Loop
    );
CH$WCHAR(0,.str); ! Write a null after the digits to make ASCIZ
    		  ! This does not update the pointer, so the null
    		  ! gets overwritten if the string is appended to
.len ! Return length of output string
END;                                    ! END OF CVTPS
GLOBAL ROUTINE cvtsp(str,alen,packednum,len)=  ! Convert ASCIZ String to PACKED
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCII string to a packed decimal number 
!
! FORMAL PARAMETERS:
!
!   	str:		Address of Byte Pointer to ascii string
!	alen:		Length of ascii string
!   	packednum:	Address of Byte Pointer to store packed decimal string
!       len:            Length of packed decimal string
!
! RETURNED VALUE:
!
!   	0	If ASCII field cannot be converted to packed decimal
!       1	If ASCII field can be converted to packed decimal
!
! SIDE EFFECTS:
!
!   	The byte pointers are updated past the strings
!--
BEGIN
BIND bcdsign=UPLIT(Minus_sign,          ! [-1] Minus
                   Invisible_Plus_sign, ! [0]  No sign provided, thereby plus
                   Visible_Plus_sign)   ! [1]  Explicit plus sign provided
             + 1 : VECTOR;              ! Add 1 to make origin -1

LOCAL sign: INITIAL(0),
      byt: INITIAL(0),                  ! byte to stuff 2 nibbles into
      nibbles,                          ! number of nibbles
      fillers;                          ! number of leading 0's to add

sign=signbe(.str,alen);                 ! Get the sign & adjust ptr & count

nibbles=.len*2;                         ! Number of digits in field incl sign
fillers=.nibbles-1-.alen;               ! Number of leadig zero digits to add
IF .fillers LSS 0 THEN RETURN 0;        ! Won't fit. Lose!

INCR i FROM 1 TO .nibbles-1
DO  BEGIN
    LOCAL c;
    IF .fillers GTR 0                   ! Still padding?
    THEN
        BEGIN
        fillers=.fillers-1;             ! countdown
        c=0;                            ! Pad with a leading zero
        END
    ELSE c=CH$RCHAR_A(.str)-%C'0';      ! Done padding, get a real character

    IF (.c LSS 0) OR (.c GTR 9)         ! Is this a real digit?
    THEN RETURN 0;                      ! No. Lose!

    IF .i                                   ! 1st,3rd,5th... digits
    THEN byt=.c^digit_size                  ! go in left nibble of byte
    ELSE CH$WCHAR_A(.byt OR .c,.packednum); ! even digits into right nibble
    END;

CH$WCHAR_A(.byt OR .bcdsign[.sign],.packednum);  ! Write out the sign
1                                       ! Return TRUE
END;
GLOBAL ROUTINE cvtzp(str,packednum,len)=     ! Convert ASCIZ String to PACKED
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCIZ string to a packed decimal number 
!
! FORMAL PARAMETERS:
!
!   	str:		Byte Pointer to ascii string
!   	packednum:	Byte Pointer to store packed decimal string
!       len:            Length of packed decimal string
!
! RETURNED VALUE:
!
!   	Number of characters in ASCIZ string, or
!   	0	If ASCII field cannot be converted to packed decimal
!
!--
BEGIN
LOCAL alen: INITIAL(0);                 ! Length of string
LOCAL tptr;                             ! Copy of pointer to string

tptr=.str;

WHILE (CH$RCHAR_A(tptr) NEQ 0) DO alen=.alen+1; ! Count until we see a null

IF cvtsp(str,.alen,packednum,.len)      ! Routine that uses counted strings
THEN .alen                              ! Success, return length of source str
ELSE 0                                  ! Failure, return 0
END;                                    ! CVTZP
GLOBAL ROUTINE cvtsi(str,len,int)=
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCII string to INTEGER
!
! FORMAL PARAMETERS:
!
!   	str:		Address of Byte Pointer to ascii string
!       len:            Length of ASCII string
!       int:            Address to store Long Integer
!
! RETURNED VALUE:
!
!	1	If ASCII field can be converted
!   	0	If ASCII field cannot be converted
!
!--
BEGIN
LOCAL
    sign;

.int=0;                                 ! Init destination cell

sign=signb(.str,len) OR 1;              ! Get the sign & adjust ptr & count
                                        ! Make unspecified sign positive

DECR I FROM .len-1 TO 0
DO  BEGIN
    LOCAL c;

    c=CH$RCHAR_A(.str)-%C'0';           ! Get next character and un-ascify
    IF (.c LSS 0) OR (.c GTR 9)         ! Make sure it is a digit
    THEN RETURN 0;                      ! It wasn't. Lose!

    .int=..int*10+.c;                   ! Multiply it all by 10
    END;

.int=..int*.sign;                       ! Put sign back
1                                       ! Return TRUE
END;                                    ! CVTSI
GLOBAL ROUTINE cvtsl(str,len,longint: REF VECTOR)=
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCII string to a LONG INTEGER
!
! FORMAL PARAMETERS:
!
!   	str:		Address of Byte Pointer to ascii string
!       len:            Length of ASCII string
!       longint:        Address to store Long Integer
!
! RETURNED VALUE:
!
!	1	If ASCII field can be converted
!   	0	If ASCII field cannot be converted
!
!--
BEGIN
LOCAL
    sign;

REGISTER
    temp1=6: INITIAL(0),
    temp2=7: INITIAL(0),
    temp3=8: INITIAL(0),
    temp4=9: INITIAL(0);

sign=signb(.str,len) OR 1;              ! Get the sign & adjust ptr & count
                                        ! Make unspecified sign positive

DECR I FROM .len-1 TO 0
DO  BEGIN
    LOCAL c;

    c=CH$RCHAR_A(.str)-%C'0';           ! Get next character and un-ascify
    IF (.c LSS 0) OR (.c GTR 9)         ! Make sure it is a digit
    THEN RETURN 0;                      ! It wasn't. Lose!

    dmul(temp1,UPLIT(0,10));            ! Multiply it all by 10
    temp2=.temp2; temp3=.temp3; temp4=.temp4; ! Hack to keep compiler away

    IF (.temp1 NEQ 0) OR (.temp2 NEQ 0) ! Check if we will overflow
    THEN RETURN 0;                      ! Yes. Lose!

    temp1=.temp3;                       ! Move low order result up
    temp2=.temp4+.c;                    ! and add in new digit
    END;

IF .sign LSS 0                          ! Is this negative
THEN
    BEGIN                               ! yep.
    dmul(temp1,UPLIT(-1,-1));           ! Negate it.
    longint[0]=.temp3;                  ! Store result including sign
    longint[1]=.temp4;                  !
    END
ELSE
    BEGIN
    longint[0]=.temp1;
    longint[1]=.temp2;
    END;

1                                       ! Return TRUE
END;                                    ! CVTSL
GLOBAL ROUTINE cvtsls(str,len,longint: REF VECTOR, scale)=
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCII string to a LONG INTEGER with scale factor 
!
! FORMAL PARAMETERS:
!
!   	str:		Address of Byte Pointer to ascii string
!       len:            Length of ASCII string
!       longint:        Address to store Long Integer
!       scale:          Decimal scale factor
!
! RETURNED VALUE:
!
!	1	If ASCII field can be converted
!   	0	If ASCII field cannot be converted
!
!--
BEGIN
LOCAL
    sign,
    mantissa: VECTOR[CH$ALLOCATION(20)],
    mptr,
    digits_in_mantissa: INITIAL(0),
    digits_before_point: INITIAL(-1),
    c,
    expptr;                             ! pointer to exponent, if any

mptr=CH$PTR(mantissa);
!
! Look for exponent
!
expptr=..str;                           ! Look for exponent starting here
.scale=0;

INCR i FROM 0 TO .len-1                 ! Loop through the string
DO SELECT (c=CH$RCHAR_A(expptr)) OF     !  looking for
    SET
    [%C'D' TO %C'G', %C'd' TO %C'g']:   ! a character that introduces 
        BEGIN                           !     an exponent.
        IF cvtsi(expptr,.len-.i-1,.scale) EQL 0 ! Convert scale factor
        THEN RETURN 0;                  	! unless we can't 
        len=.i;                         ! Length of mantissa
        EXITLOOP;
        END;
    [%C'.']: digits_before_point=.digits_in_mantissa;

    [%C'+', %C'-', %C'0' TO %C'9']:
        BEGIN
        CH$WCHAR_A(.c,mptr);   ! copy mantissa
        digits_in_mantissa=.digits_in_mantissa+1;
        END;
    TES;        

.str=.expptr;                           ! Update caller's byte pointer

IF .digits_before_point GEQ 0           ! If decimal point seen
THEN .scale=..scale+.digits_before_point-.digits_in_mantissa; ! Adjust scale

cvtsl(%REF(CH$PTR(mantissa)),.digits_in_mantissa,.longint)
                                        ! Convert the rest as normally
END;                                    ! CVTSLS
GLOBAL ROUTINE cvtzl(str,longint: REF VECTOR)=
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCIZ string to a LONG INTEGER
!
! FORMAL PARAMETERS:
!
!   	str:		Byte Pointer to ascii string
!       longint:        Address to store Long Integer
!
! RETURNED VALUE:
!
!   	Number of characters in ASCIZ string, or
!   	0	If ASCII field cannot be converted
!
!--
BEGIN
LOCAL alen: INITIAL(0);                 ! Length of string
LOCAL tptr;                             ! Copy of pointer to string

tptr=.str;

WHILE (CH$RCHAR_A(tptr) NEQ 0) DO alen=.alen+1; ! Count until we see a null

IF cvtsl(str,.alen,.longint)            ! Routine that uses counted strings
THEN .alen                              ! Success, return length of source str
ELSE 0                                  ! Failure, return 0
END;                                    ! CVTZL
GLOBAL ROUTINE cvtsu(str,len,unsint)=
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCII string to a UNSIGNED INTEGER
!
! FORMAL PARAMETERS:
!
!   	str:		Byte Pointer to ascii string
!       len:            Length of ASCII string
!       unsint:         Address to store Unsigned Integer
!
! RETURNED VALUE:
!
!	1	If ASCII field can be converted
!   	0	If ASCII field cannot be converted
!
!--
BEGIN
LOCAL
    longint: VECTOR[2];                 ! Temp for Long-integer result

IF CVTSL(.str,.len,longint)             ! Convert to long-integer
THEN RETURN 0;                          ! If we can, if not return failure

unsint=.longint[1];                     ! All significant data should be here
                                        ! so the high word should be all zero
.longint[0] EQL 0                       ! If so, win, else lose
END;                                    ! CVTSU
GLOBAL ROUTINE cvtzu(str,unsint)=
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCIZ string to a UNSIGNED INTEGER
!
! FORMAL PARAMETERS:
!
!   	str:		Byte Pointer to ascii string
!       unsint:         Address to store Unsigned Integer
!
! RETURNED VALUE:
!
!   	Number of characters in ASCIZ string, or
!   	0	If ASCII field cannot be converted
!
!--
BEGIN
LOCAL alen: INITIAL(0);                 ! Length of string
LOCAL tptr;                             ! Copy of pointer to string

tptr=.str;

WHILE (CH$RCHAR_A(tptr) NEQ 0) DO alen=.alen+1; ! Count until we see a null

IF cvtsu(str,.alen,.unsint)             ! Routine that uses counted strings
THEN .alen                              ! Success, return length of source str
ELSE 0                                  ! Failure, return 0
END;                                    ! CVTZU
GLOBAL ROUTINE cvtsd(str,len,dbl: REF VECTOR)=
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCIZ string to a DOUBLE FLOAT
!
! FORMAL PARAMETERS:
!
!   	str:		Addr of Byte Pointer to ASCII string
!       len:            Length of ASCII string
!       dbl:            Address to store Double Float
!
! RETURNED VALUE:
!
!	1	If ASCII field can be converted
!   	0	If ASCII field cannot be converted
!
!--
BEGIN
LOCAL
    longint: VECTOR[2],                 ! Temp for Long-integer intermediate
    scale;                              ! Scale factor for intermediate

IF cvtsls(.str,.len,longint,scale) EQL 0  ! Convert to Long-integer first
THEN RETURN 0;                          ! Fail if it did

IF cvtld(longint,.scale,.dbl)           ! Convert long to double
THEN 1                                  ! Win, return TRUE
ELSE 0                                  ! Failure, return FALSE
END;                                    ! CVTSD
GLOBAL ROUTINE cvtzd(str,dbl: REF VECTOR)=
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCIZ string to a DOUBLE FLOAT
!
! FORMAL PARAMETERS:
!
!   	str:		Byte Pointer to ascii string
!       dbl:           Address to store Double Float
!
! RETURNED VALUE:
!
!   	Number of characters in ASCIZ string, or
!   	0	If ASCII field cannot be converted
!
!--
BEGIN
LOCAL alen: INITIAL(0);                 ! Length of string
LOCAL tptr;                             ! Copy of pointer to string

tptr=.str;

WHILE (CH$RCHAR_A(tptr) NEQ 0) DO alen=.alen+1; ! Count until we see a null

IF cvtsd(str,.alen,.dbl)                ! Routine that uses counted strings
THEN .alen                              ! Success, return length of source str
ELSE 0                                  ! Failure, return 0
END;
GLOBAL ROUTINE cvtsg(str,len,gfl: REF VECTOR)=
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCIZ string to GFLOAT
!
! FORMAL PARAMETERS:
!
!   	str:		Addr of Byte Pointer to ASCII string
!       len:            Length of ASCII string
!       gfl:            Address to store G-Float
!
! RETURNED VALUE:
!
!	1	If ASCII field can be converted
!   	0	If ASCII field cannot be converted
!
!--
BEGIN
LOCAL
    longint: VECTOR[2],                 ! Temp for Long-integer intermediate
    scale;                              ! Scale factor for intermediate

IF cvtsls(.str,.len,longint,scale) EQL 0  ! Convert to Long-integer first
THEN RETURN 0;                          ! Fail if it did

IF cvtlg(longint,.scale,.gfl)           ! Convert long to G-float
THEN 1                                  ! Win, return TRUE
ELSE 0                                  ! Failure, return FALSE
END;                                    ! CVTSG
GLOBAL ROUTINE cvtzg(str,gfl: REF VECTOR)=
!++
! FUNCTIONAL DESCRIPTION:
!
!   	Convert ASCIZ string to a DOUBLE FLOAT
!
! FORMAL PARAMETERS:
!
!   	str:		Byte Pointer to ascii string
!       gfl:           Address to store GFLOAT
!
! RETURNED VALUE:
!
!   	Number of characters in ASCIZ string, or
!   	0	If ASCII field cannot be converted
!
!--
BEGIN
LOCAL alen: INITIAL(0);                 ! Length of string
LOCAL tptr;                             ! Copy of pointer to string

tptr=.str;

WHILE (CH$RCHAR_A(tptr) NEQ 0) DO alen=.alen+1; ! Count until we see a null

IF cvtsg(str,.alen,.gfl)                ! Routine that uses counted strings
THEN .alen                              ! Success, return length of source str
ELSE 0                                  ! Failure, return 0
END;                                    ! CVTZG
ROUTINE signbe(str,alen) =              ! Check for leading or trailing sign
BEGIN
LOCAL sign;

sign=plusminus(CH$RCHAR(..str));        ! Look for sign at beginning of string
IF .sign NEQ 0                          ! If we did find one...
THEN CH$RCHAR_A(.str)                   ! Incr pointer over it
ELSE sign=plusminus(CH$RCHAR(CH$PLUS(..str,..alen)));
                                        ! Else Look for sign at end
IF .sign NEQ 0 THEN .alen=..alen-1;     ! Sign supplied, we just want # digits
.sign                                   ! Return state of sign
END;                                    ! check_sign
ROUTINE signb(str,alen) =             ! Check for leading sign
BEGIN
LOCAL sign;

sign=plusminus(CH$RCHAR(..str));        ! Look for sign at beginning of string
IF .sign NEQ 0                          ! If we did find one...
THEN
    BEGIN
    CH$RCHAR_A(.str);                   ! Incr pointer over it
    .alen=..alen-1;                     ! Sign supplied, we just want # digits
    END;
.sign                                   ! Return state of sign
END;                                    ! check_sign
ROUTINE plusminus(c)=(IF .c EQL %C'+'   ! Local routine to check for signs
                      THEN 1
                      ELSE IF .c EQL %C'-'
                           THEN -1
                           ELSE 0);
END ELUDOM