Google
 

Trailing-Edge - PDP-10 Archives - AP-D471B-SB_1978 - mgnpt.bli
There are no other files named mgnpt.bli in the archive.
!***COPYRIGHT (C) 1974, 1975, 1976, 1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***

! MGNPT.BLI
! =========
!  PORT MANIPULATION ROUTINES FOR THE MCS CONFIGURATION GENERATOR

! **** LAST MODIFIED   29-JUN-76    ILG

MODULE PORT(SREG = #17, FREG = #16,  VREG = #15,
MLIST,TIMER=EXTERNAL(SIX12),FSAVE)=
BEGIN

! THIS MODULE CONTAINS THOSE ROUTINES REQUIRED TO HANDLE PORT GENERATIONS

GLOBAL BIND PT = 1;

REQUIRE MGNMAC.BLI;
REQ(MGNEXT);
REQ(MGNMC2);

EXTERNAL
	MOVE,
	LINK,
	UNLINK,
	COMPARE,
	MAKUTERM,
	DTERMCNAME,
	WCTNM;

COMMENT;
! ROUTINE PTUNHOOK
! ======= ========
! THIS ROUTINE BREAKS THE CONNECTION BETWEEN A PORT AND A TERMINAL
! USED WHEN DELETEING PORT OR 
! TERMINAL

GLOBAL ROUTINE PTUNHOOK( PORTADDR ) =
    BEGIN
	REGISTER
		TERMADDR;

	MAP	FORMAT PORTADDR;
	MAP	FORMAT TERMADDR;

	TERMADDR _ .PORTADDR[PT0SRCPTR];
	PORTADDR[PT0SRCPTR] _ 0;
	TERMADDR[T0PORTPTR] _ 0

	NOTE;	MIGHT IT BE NICE TO INFORM THE USER OF THE BREAK?

    END;

COMMENT;
! ROUTINE PRINTPORTNAME
! ======= =============
! OUTPUTS PORTNAME TO CONTROLLING TTY

ROUTINE PRINTPORTNAME( PORTNAME ) =
    BEGIN
	TYPE( 'FOR [PORT ]'); OUTSA( .PORTNAME ); TYPE( '[:?M?J]' )
    END;

COMMENT;
! ROUTINE INPORT
! ======= ======
! THIS ROUTINE ASKS FOR AND ACCEPTS A PORT NAME FROM THE USER

ROUTINE INPORT(A)=
    BEGIN
	LOCAL NONEFLG;

	NONEFLG _ FALSE;
	XTYPE(.A);							! TYPE THE QUESTION
	IF (ACHAR _ INPUT(ALINE,ALINELENGTH)) EQL CRCHAR THEN RETURN 0;	! ACCEPT AN ALTERNATE LINE ANSWER
								    	! IF THE LINE WAS EMPTY RETURN 0

! FUDGE TO ACCEPT "<NONE>" AS AN ANSWER
	IF .ACHAR EQL "<" THEN
	BEGIN
		NONEFLG _ TRUE;
		ADV(ABUFF,ABPTR,ACOUNT,ACHAR);
	END;
	IF NOT .ERRORFLG THEN GETNAME(ALINE,ACHAR);			! IF NO ERROR ACCEPTING THE LINE THEN GATHER A NAME
	IF .ACHAR EQL ">" AND  .PRIM[0] EQL 'NONE' AND .NONEFLG THEN
	BEGIN
		ADV(ABUFF,ABPTR,ACOUNT,ACHAR);	!EAT THE TRAILING ">"
		PRIM[0] _ NONETOKEN;			!SET TOKEN TO NONE
	END;
	IF NOT .ERRORFLG THEN TOOMUCHINPUT();				! IF NOT END OF LINE THEN ERROR
	IF NOT .ERRORFLG THEN IF SUBQUEUES() OR .PERIODS NEQ 0 THEN ERROR( 15 );	! IF STILL NO ERRORS, SEE IF THE USER
								    	! PUT PERIODS IN THE PORT NAME
	IF NOT .ERRORFLG THEN IF HYPHENIN( %IN% PRIM<0,0>, PT0NAMESIZE ) THEN ERROR( 110 );	! IF HYPHEN
									! IN THE PORT NAME THEN ERROR
	IF .ERRORFLG THEN 0 ELSE 1					! IF ERROR IN ANY PART, RETURN 0 ELSE 1
    END;
COMMENT;

! ROUTINE NUMPT
! ======= =====
! THIS ROUTINE NUMBERS ALL THE PORTS

GLOBAL ROUTINE NUMPT =
    BEGIN
	REGISTER
		I,
		PORTADDR;
	MAP	FORMAT PORTADDR;

	PORTADDR _ .PORTTAB<FORE>;		! GET FIRST PORT
	I _ 0;
	WHILE .PORTADDR NEQ 0 DO		! FOR EACH PORT
	    BEGIN
		PORTADDR[PT0PORTNO] _ I _ .I + 1;	! INCREMENT OUT PORT COUNTER AND STORE IN THE PORT NUMBER FIELD
		PORTADDR _ .PORTADDR[PT0FORE]		! GET NEXT PORT
	    END

    END;
COMMENT;

! ROUTINE CREATEPORT
! ======= ==========
! THIS ROUTINE STUFFS A NEW PORT IN THE PORTTAB
! INPUT POINTER TO PORTNAME
! OUTPUT POINTER TO PORT TABLE ENTRY

ROUTINE CREATEPORT( PORTNAME ) =
    BEGIN
	REGISTER PORTADDR;
	MAP	FORMAT PORTADDR;

	PORTADDR _ GMEM(PT0SIZE);
	PORTADDR[PT0LINKS] _ 0;
	MOVE( %FROM% .PORTNAME, %TO% PORTADDR[PT0NAME], PT0NAMELEN %WORDS%);
	LINK( %TO% PORTTAB, PORTADDR[PT0LINKS]);

	.PORTADDR
    END;

COMMENT;

! ROUTINE NULLPORTNAME
! ======= ============
! THIS ROUTINE RETURNS TRUE IF THE PORTNAME IS NULL

ROUTINE NULLPORTNAME(LOC) = 
	BEGIN
		RETURN IF ..LOC EQL 0 THEN TRUE ELSE FALSE
	END;
FORWARD GETPORTADDR(1);

COMMENT;

! ROUTINE MAKUPORT
! ======= ========
! THIS ROUTINE MAKES A PORT TO ATTACH TO A TERMINAL

GLOBAL ROUTINE MAKUPORT( TERMADDR, UTYPE ) =
    BEGIN
	OWN
		DONE,
		PORTADDR;

	MAP	FORMAT	PORTADDR;
	MAP	FORMAT	TERMADDR;

	%LOCAL% ROUTINE TRYANOTHER =
	    BEGIN
		WARN( 0 )
	    END;

	%LOCAL% ROUTINE SETSRC( TERMADDR ) =
	    BEGIN
		PORTADDR[PT0SRCPTR] _ .TERMADDR;
		DONE _ TRUE
	    END;

	%LOCAL% ROUTINE FIXUP( TERMADDR ) =
	    BEGIN
		PTUNHOOK( .PORTADDR );
		SETSRC( .TERMADDR )
	    END;

	LABEL	LOOP1, LOOP2;

	DONE _ FALSE;

LOOP1:	REPEAT					! UNTIL WE GET AN ACCEPTABLE ANSWER
	    BEGIN
LOOP2:		REPEAT				! UNTIL WE GET A GOOD PORT NAME
		    BEGIN
			IF .UTYPE EQL MODTYPE THEN TYPE( '[NEW ]' );
			TYPE( 'ATTACHED [PORT]?R(' );
			IF .UTYPE EQL MODTYPE THEN TYPE( ',' );
			IF INPORT( PAZ '"<NONE>",<NAME>?R)[:  ??]') EQL 0 THEN
			    IF NOT .ERRORFLG THEN
				BEGIN
				    IF .UTYPE EQL MODTYPE THEN RETURN -1;
				    !ELSE!
				    ERROR( 89 );
				    WARN( 0 )
				END
				ELSE
				BEGIN
							! IF THE ANSWER WAS UNACCEPTABLE
				    ERROR( 86 );			! TELL THE USER AND ASK AGAIN
				    WARN( 0 )
				END
			    ELSE LEAVE LOOP2
		    END;

		! WE GOT A PORT NAME
		IF .PRIM[0] EQL NONETOKEN THEN RETURN 0;	!IF SAID "<NONE>"
		IF (PORTADDR _ GETPORTADDR( PRIM<36,7> )) EQL 0 THEN
		    BEGIN
			PORTADDR _ CREATEPORT( PRIM<36,7> );
			SETSRC( .TERMADDR );
			LEAVE LOOP1
		    END
		    ELSE
		    BEGIN
			IF .PORTADDR[PT0SRCPTR] EQL 0 THEN
			BEGIN
			  SETSRC(.TERMADDR);
			  IF .DONE THEN LEAVE LOOP1
			END
			ELSE
			  ERROR(130)
		    END
	    END;

	.PORTADDR

    END;

FORWARD ACCEPTPORT(1);
COMMENT;

! ROUTINE MAKEPORT
! ======= ========
! GIVEN THE ADDRESS OF A PORTNAME, THIS ROUTINE CAUSE THE APPROPRIATE
! CHECKS ON THE NAME AND ACTUALLY CREATES THE SPACE

GLOBAL ROUTINE MAKEPORT(PORTNAME)=
    BEGIN

	REGISTER PORTADDR;
	MAP	FORMAT PORTADDR;

	IF .ALLSWITCH THEN RETURN(ERROR(25));


	IF SUBQUEUES() OR .PERIODS NEQ 0 THEN RETURN( ERROR( 15 ) );	! PERIODS IN A PORT NAME ARE NO NO'S

	IF HYPHENIN( .PORTNAME, PT0NAMESIZE ) THEN RETURN ERROR( 110 );	! IF HYPHEN IN PORTNAME RETURN ERROR

	IF NULLPORTNAME(.PORTNAME) THEN		! IF NO PORT SPECIFIED
	    BEGIN				! ASK THE USER FOR PORT NAMES
		REPEAT				! UNTIL HE INPUTS A <CR> BY
		    BEGIN			! ITSELF
			IF INPORT( PAZ '[PORTNAME]?R(<done>,<name>?R)[:	??') EQL 0 THEN
			    IF NOT .ERRORFLG THEN RETURN
				ELSE
				BEGIN
							! IF THE ANSWER WAS UNACCEPTABLE
				    ERROR( 86 );			! TELL THE USER AND ASK AGAIN
				    WARN( 0 )
				END
		            ELSE ACCEPTPORT(PRIM<36,7>);	! IF OK NAME EXECUTE THE FUNCTION
			CRLF
		    END
	    END;
	ACCEPTPORT(.PORTNAME)				! IF A PORT WAS SPECIFIED, USE IT
    END;
COMMENT;

! ROUTINE GETPORTADDR
! ======= ===========
! SEARCHES THE PORTTAB FOR THE PORTNAME CONTAINED AT THE CONTENTS OF PORTNAME
! IF FOUND, RETURNS THE ADDRESS OF THE PORT TABLE ENTRY
! OTHERWISE RETURNS 0

ROUTINE GETPORTADDR(PORTNAME) =
    BEGIN
	REGISTER PORTADDR;
	MAP FORMAT PORTADDR;

	IF TOOLONG(.PORTNAME,PT0NAMESIZE, PT0NAMELEN * 5) THEN
	    BEGIN
		WARN( 3 );
		TRUNCATE(.PORTNAME, PT0NAMESIZE, PT0NAMELEN * 5)
	    END;

	IF ( PORTADDR _ .PORTTAB<FORE> ) EQL 0 THEN RETURN 0;	! START AT THE BEGINNING
							! WHILE THE NAME AT PORTNAME ISN'T THE NAME IN THE TABLE DO
	WHILE NOT COMPARE(.PORTNAME,PORTADDR[PT0NAME],PT0NAMELEN) DO
							! IF END OF TABLE RETURN 0
		IF (PORTADDR _ .PORTADDR[PT0FORE]) EQL 0 THEN RETURN 0;
	.PORTADDR					! A MATCH! SO RETURN THE ADDRESS
    END;

COMMENT;

! ROUTINE ACCEPTPORT
! ======= ==========
! THIS ROUTINE CREATES A PORT TABLE ENTRY IF ONE DOES NOT EXIST
! RETURNS ERROR OTHERWISE

ROUTINE ACCEPTPORT(PORTNAME)=
    BEGIN

	! SEE IF ALREADY DEFINED
	IF GETPORTADDR(.PORTNAME) EQL 0 THEN
	   BEGIN
		CREATEPORT( .PORTNAME );		! MAKE A PORT TABLE ENTRY
		OUTS('PORT ');
		OUTSA(.PORTNAME);
		OUTS(' CREATED?M?J')
	    END
	    ELSE ERROR(14);			!DUPLICATE PORTNAME
    END;
FORWARD DISPORT(1);

COMMENT;

! ROUTINE DISPPORT
! ======= ===========
! THIS ROUTINE HANDLES THE INDIVIDUAL CASES OF DISPLAY PORT:...
! CASE 1: IF AN INDIVIDUAL PORT IS REQUESTED ( BY NAME ), DISPORT IS
!	  CALLED WITH THE ADDRESS OF THE PORT TABLE ENTRY
! CASE 2: IF /ALL WAS SPECIFIED, DISPORT IS CALLED FOR EACH ENTRY IN
!	  PORT TABLE
! CASE 3: IF NO NAME OR SWITCH WAS GIVEN, THE USER IS ASKED FOR THE
!	  NAMES OF THE PORTS TO BE DISPLAYED

GLOBAL ROUTINE DISPPORT(PORTNAME)=
    BEGIN
	REGISTER PORTADDR;
	MAP FORMAT PORTADDR;

	IF SUBQUEUES() OR .PERIODS NEQ 0 THEN RETURN( ERROR( 15 ) );	! PERIODS IN A PORT NAME ARE NO NO'S

	IF HYPHENIN( .PORTNAME, PT0NAMESIZE ) THEN RETURN ERROR( 110 );	! IF HYPHEN IN PORTNAME RETURN ERROR

	IF NULLPORTNAME(.PORTNAME) AND NOT .ALLSWITCH THEN
	    BEGIN				! ASK THE USER FOR PORT NAMES
		REPEAT		! UNTIL HE INPUTS A <CR> BY
		    BEGIN			! ITSELF
			IF INPORT( PAZ '[PORTNAME]?R(<done>,<name>?R)[:	??') EQL 0 THEN 
			    IF NOT .ERRORFLG THEN RETURN
				ELSE
				BEGIN
							! IF THE ANSWER WAS UNACCEPTABLE
				    ERROR( 86 );			! TELL THE USER AND ASK AGAIN
				    WARN( 0 )
				END
			    ELSE IF (PORTADDR _ GETPORTADDR(PRIM)) EQL 0 THEN
				RETURN(ERROR(13))
				ELSE DISPORT(.PORTADDR);
			CRLF
		    END
	    END;

	IF .ALLSWITCH THEN
	    BEGIN
		PORTADDR _ .PORTTAB<FORE>;
		WHILE .PORTADDR NEQ 0 DO
		    BEGIN
			DISPORT( .PORTADDR);
			PORTADDR _ .PORTADDR[PT0FORE]
		    END;
		RETURN
	    END;
	IF (PORTADDR _ GETPORTADDR(.PORTNAME)) EQL 0 THEN RETURN(ERROR(13))
	    ELSE DISPORT(.PORTADDR)
    END;

FORWARD DPORTNAME(1), DPORTATTACHEDTERM(1);
COMMENT;

! ROUTINE DISPORT
! ======= =======
! THIS ROUTINE DISPLAYS THE PORT'S NAME,
! AND PARAMETERS

ROUTINE DISPORT(PORTADDR)=
    BEGIN
	MAP FORMAT PORTADDR;
	DPORTNAME(.PORTADDR);
	DPORTATTACHEDTERM(.PORTADDR);
	OUTPUTCRLF
    END;

COMMENT;

! ROUTINE DPORTNAME
! ======= =========
! THIS ROUTINE DISPLAYS THE PORT NAME

ROUTINE DPORTNAME(PORTADDR)=
    BEGIN
	MAP FORMAT PORTADDR;
	OUTPUT('PORTNAME: '); XOUTPUT(PORTADDR[PT0NAME]);
	OUTPUTCRLF
    END;

COMMENT;

! ROUTINE DPNAME
! ======= =========
! THIS ROUTINE DISPLAYS THE PORT NAME WITHOUT LABEL

GLOBAL ROUTINE DPNAME(PORTADDR)=
    BEGIN
	MAP FORMAT PORTADDR;
	XOUTPUT(PORTADDR[PT0NAME])
    END;

COMMENT;

! ROUTINE DPORTATTACHEDTERM
! ======= =========
! THIS ROUTINE DISPLAYS THE PORT'S ATTACHED TERMINAL

ROUTINE DPORTATTACHEDTERM(PORTADDR)=
    BEGIN
	MAP FORMAT PORTADDR;
	OUTPUT( 'ATTACHED TERMINAL: ');
	IF .PORTADDR[PT0SRCPTR] NEQ 0 THEN
		DTERMCNAME( .PORTADDR[PT0SRCPTR])
	    ELSE OUTPUT( '<NONE>');

	OUTPUTCRLF
    END;

COMMENT;

COMMENT;

! ROUTINE DPTNAMES
! ======= ===========
! THIS ROUTINE DISPLAYS THE NAMES OF ALL PORTS IN THE PORTTAB

GLOBAL ROUTINE DPTNAMES =
    BEGIN
	REGISTER PORTADDR;
	MAP	FORMAT PORTADDR;

	PORTADDR _ .PORTTAB<FORE>;
	WHILE .PORTADDR NEQ 0 DO
	    BEGIN
		XOUTPUT(PORTADDR[PT0NAME]);
		PORTADDR _ .PORTADDR[PT0FORE];
		OUTPUTCRLF
	    END

    END;
COMMENT;

! ROUTINE MODIPORT
! ======= ========
!

! THIS ROUTINE TRAPS THE "MODIFY PORT:" COMMAND AND RETURNS AN
! ERROR

GLOBAL ROUTINE MODIPORT(PORTNAME) =
	BEGIN
		OWN	HIST33;		!HIST:WAS "DONE" IN MODPORT
		ERROR(129)
	END;
FORWARD DELPORT(1),KILLPORTS();
COMMENT;

! ROUTINE DELEPORT
! ======= ===========
! THIS ROUTINE HANDLES THE INDIVIDUAL CASES OF DELETE PORT:...
! CASE 1: IF AN INDIVIDUAL PORT IS REQUESTED ( BY NAME ), DELPORT IS
!	  CALLED WITH THE ADDRESS OF THE PORT TABLE ENTRY
! CASE 2: IF /ALL WAS SPECIFIED, DELPORT IS CALLED FOR EACH ENTRY IN
!	  PORT TABLE
! CASE 3: IF NO NAME OR SWITCH WAS GIVEN, THE USER IS ASKED FOR THE
!	  NAMES OF THE PORTS TO BE DELETED

GLOBAL ROUTINE DELEPORT(PORTNAME)=
    BEGIN
	REGISTER PORTADDR;
	MAP FORMAT PORTADDR;

	IF SUBQUEUES() OR .PERIODS NEQ 0 THEN RETURN( ERROR( 15 ) );	! PERIODS IN A PORT NAME ARE NO NO'S

	IF HYPHENIN( .PORTNAME, PT0NAMESIZE ) THEN RETURN ERROR( 110 );	! IF HYPHEN IN PORTNAME RETURN ERROR

	IF NULLPORTNAME(.PORTNAME) AND NOT .ALLSWITCH THEN
	    BEGIN				! ASK THE USER FOR PORT NAMES
		REPEAT		! UNTIL HE INPUTS A <CR> BY
		    BEGIN			! ITSELF
			IF INPORT( PAZ '[PORTNAME]?R(<done>,<name>?R)[:	??') EQL 0 THEN 
			    IF NOT .ERRORFLG THEN RETURN
				ELSE
				BEGIN
							! IF THE ANSWER WAS UNACCEPTABLE
				    ERROR( 86 );			! TELL THE USER AND ASK AGAIN
				    WARN( 0 )
				END
			    ELSE IF (PORTADDR _ GETPORTADDR(PRIM)) EQL 0 THEN
				RETURN(ERROR(13))
				ELSE DELPORT(.PORTADDR);
			CRLF
		    END
	    END;

	IF .DELTYPEFLAG THEN TYPE( 'PORTS DELETED:[?M?J]' );

	IF .ALLSWITCH THEN
	    BEGIN
		IF NOT(CONFIRMED()) THEN RETURN;
		KILLPORTS();
		RETURN
	    END;
	IF (PORTADDR _ GETPORTADDR(.PORTNAME)) EQL 0 THEN RETURN(ERROR(13))
	    ELSE DELPORT(.PORTADDR);
    END;
COMMENT;

! ROUTINE KILLPORTS
! ======= ===========
! THIS ROUTINE DELETES ALL PORTS FROM THE PORTTAB

GLOBAL ROUTINE KILLPORTS =
    BEGIN
	REGISTER PORTADDR;
	MAP	FORMAT PORTADDR;

	PORTADDR _ .PORTTAB<FORE>;
	WHILE .PORTADDR NEQ 0 DO
	    PORTADDR _ DELPORT(.PORTADDR)

    END;
COMMENT;

! ROUTINE DELPORT
! ======= =======
! THIS ROUTINE DELETES THE PORT SPECIFIED FROM THE PORT TABLE
! RETURNS THE ADDRESS OF THE NEXT PORT IN THE PORT TABLE

ROUTINE DELPORT(PORTADDR)=
    BEGIN
	OWN NEXT;
	MAP FORMAT PORTADDR;

	XTYPE( PORTADDR[PT0NAME] );			! TYPE THE NAME OF THE PORT DELETED, IF MSGLEVEL EQL LONG
	TYPECRLF;

	NEXT _ .PORTADDR[PT0FORE];
	UNLINK(%FROM% PORTTAB, .PORTADDR);
	IF .PORTADDR[PT0SRCPTR] NEQ 0 THEN		!IF THERE'S A TERMINAL,UNHOOK IT
	    PTUNHOOK( .PORTADDR );		! CLEAR PORTPTR IN THE TERMTAB ENTRY POINTED TO
	PMEM(.PORTADDR,PT0SIZE);
	.NEXT
    END;
FORWARD WCPTNAME, WCPTNM;

COMMENT;

! ROUTINE WCPORT
! ======= ======
! THIS ROUTINE WRITES THE PORT SECTION OF THE COMPILE FILE

GLOBAL ROUTINE WCPORT=
    BEGIN
    ! IT IS ASSUMED THAT THE TERMINALS HAVE BEEN NUMBERED 0 THROUGH NNNNN

    ! THEN FOR EACH PORT
    ! OUTPUT PTnnnn: PORT(NAME, MODE, IF CONV THEN T# ELSE 0, SIGNON, SIGNOFF, TYPE, STATUS)

	REGISTER PORTADDR;
	MAP FORMAT PORTADDR;

	OUTPUT( '?L	SUBTTL PORTS?M?J?M?JFREEPORTS==0?M?J?M?JPORTTAB::EXP	.+1?M?J' );

	PORTADDR _ .PORTTAB<FORE>;

	WHILE .PORTADDR NEQ 0 DO
	    BEGIN
		WCPTNM( .PORTADDR );
		OUTPUTC( ":" );

		OUTPUT('	%PORT');
		XOUTPUT(PLIT ASCIZ '(');

		! OUTPUT NAME,
		WCPTNAME(.PORTADDR);
		OUTPUTCOMMA;

		! OUTPUT TERMINAL LABEL, OR BLANK IF NON-ASSOCIATED
		IF .PORTADDR[PT0SRCPTR] EQL 0 THEN OUTPUT(' ')
		    ELSE WCTNM(.PORTADDR[PT0SRCPTR]);
		OUTPUT(')?M?J');
		PORTADDR _ .PORTADDR[PT0FORE]
	    END;

	OUTPUT( '	EXP	0			; MUST BE LAST ENTRY IN PORT TAB?M?J' );

    END;

COMMENT;

! ROUTINE WCPTNAME
! ======= ========
! THIS ROUTINE WRITES THE PORT NAME TO THE COMPILE FILE

ROUTINE WCPTNAME(PORTADDR)=
    BEGIN
	MAP FORMAT PORTADDR;
	XOUTPUT(PORTADDR[PT0NAME])
    END;

COMMENT;

! ROUTINE WCPTNM
! ======= ======
! THIS ROUTINE WRITES THE PORT NUMBER

GLOBAL ROUTINE WCPTNM( PORTADDR ) =
    BEGIN
	MAP	FORMAT PORTADDR;

	OUTPUT( 'PP' );
	OUTPUTD( .PORTADDR[PT0PORTNO] )

    END;
COMMENT;

! ROUTINE WHATPORTS
! ======= =========
! RETURNS GOOD IF PORTS EXIST, ELSE RETURNS BAD
GLOBAL ROUTINE WHATPORTS(TELL)=
    BEGIN
		IF .PORTTAB<FORE> EQL 0 THEN
		BEGIN
		  ERROR(37);
		  RETURN BAD
		END;
	  GOOD
	END;