10	FUNCTION LONG EXT_MENU

	!======================================================================
  	!PROGRAM---------------------VERSION-------------------LANGUAGE--------
	!EXT_MENU     			2			BASIC
	!
	!DESCRIPTION-----------------------------------------------------------
	!Performs menu selection and port allocation for EXTERNAL
	!Menu displays facilities the current user is allowed to access.
	!When user selects a facility, selects and allocates a suitable port,
	!then returns port info via MENU_SELECTION_COM to calling routine.
	!
	!======================================================================

	%TITLE "EXTERNAL Menu Driver"
	%IDENT "EXT_MENU 88.10.12"
	%SBTTL "DOCUMENTATION SECTION"

	!**********************************************************************
	!			OPTIONS
	!**********************************************************************

	OPTION	TYPE = EXPLICIT			! Explicit declarations only

100	!**********************************************************************
	!			DOCUMENTATION SECTION
	!**********************************************************************
	!
	!======================================================================
	!			MODIFICATION HISTORY
	!======================================================================
	!VERSION--------AUTHOR------------------DATE------------APPROVAL-------
	!   1		Keith Walker		88.01.25	1723
	!   2		Keith Walker		88.10.12	1741
	!
	!======================================================================
	!			COMPILE/LINK/INSTALL INSTRUCTIONS
	!======================================================================
	!$BASIC EXT_MENU
	!$LINK/NOTRACE EXTERNAL,-
	!EXT_UNSOL_MBX_AST, EXT_READ_PORT_AST,-
	!EXT_PROC_BUF_AST, EXT_WRITE_TERM_AST,-
	!EXT_SCRIPT_INTERP, EXT_SCREEN_HDR,-
	!EXT_MENU, EXT_CONNECT_LOOP, CHKRDB
	!======================================================================

	!**********************************************************************
	!			FILES ACCESSED
	!**********************************************************************
	!     NAME	    MODE    CHANNEL		  DESCRIPTION
	!--------------	   ------   -------	-------------------------------
	!LF_MENU	    READ    MENU_FILE	menu file
	!LF_PORTS	    READ    PORTS_FILE	port selection file
	!   		
	!**********************************************************************

	%PAGE
	%SBTTL "DECLARATION SECTION"
200	!======================================================================
	!			DECLARATION SECTION
	!======================================================================

	!**********************************************************************
	!			%INCLUDE FILE DECLARATIONS
	!**********************************************************************

	%INCLUDE "$PSLDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB"
	%INCLUDE "EXT_COMMON.BAS"

	!**********************************************************************
	!			CONSTANTS
	!**********************************************************************

	DECLARE WORD CONSTANT &
		L_MENU = 100, &
		L_PORTS = 20

	!**********************************************************************
	!			RECORDS
	!**********************************************************************

	!**********************************************************************
	!			MAPS
	!**********************************************************************

	!**********************************************************************
	!			COMMONS
	!**********************************************************************

	!**********************************************************************
	!			VARIABLES
	!**********************************************************************

	DECLARE WORD &
		ACCEPT_MENU,		!whether or not to accept menu item &
		ANY_PORT_EXISTS,	!TRUE if any suitable port exists &
		PORT_EXISTS		!TRUE if specified port type exists

	DECLARE LONG &
		FUNC_STAT,		!status from function &
		I,			!miscellaneous counter &
		ITEM_COUNT,		!counter to parse lists &
		MENU_COL1,		!number of items in 1 column &
		MENU_COL2,		!number of items in 2 column &
		MENU_COUNT,		!number of items in menu &
		MENU_INDEX,		!pointer to menu item &
		PORT_COUNT,		!number of items in ports list &
		PORT_INDEX,		!pointer to port info &
		SCREEN_LINES		!number of screen lines used

	DECLARE STRING &
		ALT_NODES,		!names of nodes where ports are avail &
		AVAIL_CLASS,		!class available for selected facility &
		DEBUG_FLAG,		!debug symbol from DCL &
					!0: no debugging &
					!1: print script parsing info &
					!2: print scripts & labels &
					!3: print interpreted lines &
					!4: print INPUT parameters &
					!5: print condition flags &
		MENU_CODE,		!code from menu item &
		MENU_FMT,		!print using string &
		MENU_INPUT,		!input string from user &
		MENU_NAME,		!name of selected facility &
		MENU_RIGHTS,		!rights list for menu item &
		MODEM_TYPE_S,		!type of modem for selected facility &
		OPTION_STRING,		!info from ports or menu file &
		PORT_NAME_S,		!name of selected port &
		PREF_CLASS,		!class preferred for selected facility &
		TRY_ANOTHER		!user's input to try another class

	!**********************************************************************
	!			ARRAYS
	!**********************************************************************

	DIMENSION STRING &
		MENU(L_MENU, 2%),	!holds menu text &
			      		!0: code, 1: name, 2: class &
		PORTS(L_PORTS, 2%)	!holds port info:
				  	!0: port, 1: class, 2: modem

	!**********************************************************************
	!			FUNCTIONS
	!**********************************************************************

	DECLARE STRING FUNCTION &
		GET_SUB_STR

	!**********************************************************************
	!			EXTERNAL CONSTANTS
	!**********************************************************************

	EXTERNAL LONG CONSTANT &
		PSL$C_SUPER, &
		SS$_ABORT, &
		SS$_NORMAL, &
		SS$_DEVNOTALLOC

	!**********************************************************************
	!			EXTERNAL FUNCTIONS
	!**********************************************************************

	EXTERNAL WORD FUNCTION &
		CHKRDB		!checks if user holds spec. Rights ID 

	EXTERNAL LONG FUNCTION &
		SYS$ALLOC

	EXTERNAL LONG &
		PARSE_MENU

	!**********************************************************************
	!			EXTERNAL SUBPROGRAMS
	!**********************************************************************

	EXTERNAL SUB &
		LIB$DO_COMMAND, &
		LIB$GET_SYMBOL, &
		LIB$SET_SYMBOL

	%PAGE
	%SBTTL "INITIALIZATION SECTION"
300	!======================================================================
	!			INITIALIZATION SECTION
	!======================================================================

	ON ERROR GOTO ERROR_HANDLING

	!**********************************************************************
	!	    		PRINT USING FORMATS
	!**********************************************************************

	MENU_FMT = &
		CHR$(27) + "['m" + &
		"   'RRR - 'LLLLLLLLLLLLLLLLLLLLLLLLLLLLL" + &
		CHR$(27) + "['m" + &
		"   'RRR - 'LLLLLLLLLLLLLLLLLLLLLLLLLLLLL" + &
		CHR$(27) + "[0m"

	!**********************************************************************
	!			VARIABLES
	!**********************************************************************

	CALL LIB$GET_SYMBOL("NODE", NODE_NAME)
	CALL LIB$GET_SYMBOL("DEBUG", DEBUG_FLAG)
	FUNC_STAT = SS$_NORMAL
	ALT_NODES = ""

	%PAGE
	%SBTTL "MAIN LOGIC SECTION"
1000	!======================================================================
	!			MAIN LOGIC SECTION
	!======================================================================

	GOSUB READ_PORTS	!read ports info
	IF PORT_COUNT = 0% THEN
	  PRINT "There are no external communication lines on node "; &
	  	TRM$(NODE_NAME); "."
	  PRINT "Please log onto "; ALT_NODES; " and try again."
	  FUNC_STAT = SS$_ABORT
	  GOTO END_OF_PROGRAM
	END IF

	GOSUB DISPLAY_SCREEN	!clear screen
	GOSUB READ_MENU		!read and display the menu
	GOSUB SELECT_MENU_ITEM	!ask for user's selection
	IF MENU_INDEX = 99% THEN	!user wants out
	  FUNC_STAT = SS$_ABORT
	  GOTO END_OF_PROGRAM
	END IF

	GOSUB GET_FAC_INFO	!get info on selected facility
	GOSUB GET_PORT		!try to allocate a port
	IF FUNC_STAT = SS$_ABORT THEN
	  GOTO END_OF_PROGRAM
	END IF
	IF FUNC_STAT = SS$_DEVNOTALLOC THEN
	  IF ANY_PORT_EXISTS THEN
	    PRINT "All suitable communication lines on node "; &
		TRM$(NODE_NAME); " are busy."
	  ELSE
	    PRINT "There are no suitable communication lines on node "; &
		TRM$(NODE_NAME)
	  END IF
	  PRINT "Please log onto another node and try again."
	  GOTO END_OF_PROGRAM
	END IF

	!all OK: set results in common block...
	FACILITY_CODE = MENU_CODE
	PORT_NAME = PORT_NAME_S
	MODEM_CLASS = AVAIL_CLASS
	MODEM_TYPE = MODEM_TYPE_S
	FACILITY_NAME = MENU_NAME

	!...and define symbols...
	CALL LIB$SET_SYMBOL("FACILITY", MENU_CODE, 1%)
	CALL LIB$SET_SYMBOL("PORT", PORT_NAME_S, 1%)
	CALL LIB$SET_SYMBOL("CLASS", AVAIL_CLASS, 1%)
	CALL LIB$SET_SYMBOL("MODEM_TYPE", MODEM_TYPE_S, 1%)
	GOSUB RESET_SCROLL	!reset scrolling region...
	IF DEBUG_FLAG <> "0" THEN
	  PRINT "FACILITY: "; MENU_CODE
	  PRINT "PORT: "; PORT_NAME_S
	  PRINT "CLASS: "; AVAIL_CLASS
	  PRINT "MODEM_TYPE_S: "; MODEM_TYPE_S
	END IF
	FUNC_STAT = SS$_NORMAL
	GOTO END_OF_PROGRAM

	%PAGE
	%SBTTL "SUBROUTINE DEFINITION SECTION"
15000	!======================================================================
	!			SUBROUTINE DEFINITION SECTION
	!======================================================================

 RESET_SCROLL:
	!**********************************************************************
	!clears VT100 scrolling region
	!**********************************************************************

	PRINT CHR$(27); "[1;24r"; CHR$(27); "[24;1H"
	RETURN

 GET_FAC_INFO:
 	!**********************************************************************
	!get info on selected facility
	!**********************************************************************

	MENU_CODE = MENU(MENU_INDEX, 0%)
	MENU_NAME = MENU(MENU_INDEX, 1%)
	IF DEBUG_FLAG <> "0" THEN
	  PRINT "FACILITY: "; MENU_CODE, MENU_NAME
	END IF
	RETURN

 GET_PORT:
 	!**********************************************************************
	!attempts to allocate a suitable port
	!returns FUNC_STAT
	!**********************************************************************

	PORT_EXISTS = FALSE
	ANY_PORT_EXISTS = FALSE
	I = 0%
	ITEM_COUNT = 0%

 GET_PORT_CLASS:
	ITEM_COUNT = ITEM_COUNT + 1%
	PREF_CLASS = GET_SUB_STR(MENU(MENU_INDEX, 2%), ITEM_COUNT)
	IF PREF_CLASS = "" THEN
	  GOTO NO_PORT_TYPE
	END IF

 FIND_A_PORT:
	!check for availability of port:
	PORT_EXISTS = FALSE
	IF DEBUG_FLAG <> "0" THEN
	  PRINT "Checking for "; PREF_CLASS; " port"
	END IF
	FOR PORT_INDEX = 1 TO PORT_COUNT
	  IF PORTS(PORT_INDEX, 1%) = PREF_CLASS THEN
	    PORT_EXISTS = TRUE
	    ANY_PORT_EXISTS = TRUE
	    !we have found a port: allocate it...
	    FUNC_STAT = SYS$ALLOC(PORTS(PORT_INDEX, 0%),,, &
		PSL$C_SUPER BY VALUE, )
	    IF (FUNC_STAT AND 1%) = 1% THEN
	      !we have got the port...                
	      GOTO PORT_ALLOCATED
	    END IF
	  END IF
	NEXT PORT_INDEX

 NO_PORT_TYPE:
	!couldn't find a port: try another class if specified...
	IF PORT_EXISTS THEN
	  PRINT
	  PRINT "All "; PREF_CLASS; " lines are busy."
	END IF
	IF GET_SUB_STR(MENU(MENU_INDEX, 2%), ITEM_COUNT + 1%) <> "" THEN
	  !we could try another type of port...
	  IF PORT_EXISTS THEN
	    INPUT "Do you wish to try another type of line"; TRY_ANOTHER
	    TRY_ANOTHER = EDIT$(SEG$(TRY_ANOTHER, 1, 1), 32)
	  ELSE
	    TRY_ANOTHER = "Y"
	  END IF
	  IF TRY_ANOTHER = "N" THEN
	    FUNC_STAT = SS$_ABORT
	    RETURN
	  ELSE
	    GOTO GET_PORT_CLASS
	  END IF	!try another
	END IF	!get_sub_str

	!no other classes: sorry
	FUNC_STAT = SS$_DEVNOTALLOC
	RETURN

 PORT_ALLOCATED:
	PORT_NAME_S = PORTS(PORT_INDEX, 0%)
	AVAIL_CLASS = PORTS(PORT_INDEX, 1%)
	MODEM_TYPE_S = PORTS(PORT_INDEX, 2%)
	FUNC_STAT = SS$_NORMAL
	PRINT CHR$(27); "[2J"; CHR$(27); "[24;1H";
	PRINT "Line type "; AVAIL_CLASS; " allocated"
	IF DEBUG_FLAG <> "0" THEN
	  PRINT "Port "; PORT_NAME_S; " ("; MODEM_TYPE_S; ") allocated"
	END IF
	RETURN

 SELECT_MENU_ITEM:
 	!**********************************************************************
	!get user to select a menu item
	!**********************************************************************

	PRINT
	WHEN ERROR IN
	  INPUT "       Enter number of selection"; MENU_INPUT
	USE
	  IF ERR = 11 THEN	!ctrl/z
	    MENU_INPUT = "EXIT"
	    CONTINUE
	  ELSE
	    EXIT HANDLER
	  END IF
	END WHEN

	WHEN ERROR IN
	  MENU_INDEX = VAL%(MENU_INPUT)
	USE
	  IF POS("EXIT", EDIT$(MENU_INPUT, 32%), 1%) = 1% THEN
	    MENU_INDEX = 99% 
	    CONTINUE
	  ELSE
	    MENU_INDEX = -1%
	    CONTINUE
	  END IF
	END WHEN

	GOTO SELECT_MENU_EXIT IF MENU_INDEX = 99%
	IF MENU_INDEX < 1 OR MENU_INDEX > MENU_COUNT THEN
	  PRINT "Enter a selection between 1 and "; NUM1$(MENU_COUNT); &
		", or EXIT."
	  GOTO SELECT_MENU_ITEM		!try again
	END IF

 SELECT_MENU_EXIT:
	RETURN

 READ_PORTS:
 	!**********************************************************************
	!read PORTS.DAT file
	!**********************************************************************

	OPEN "LF_PORTS" FOR INPUT AS FILE #PORTS_FILE, &
		ACCESS READ, ALLOW MODIFY
	PORT_COUNT = 0%
	PORT_INDEX = 0%

 READ_PORTS_LINE:
	!read a line from the menu...
	WHEN ERROR IN
    	  INPUT #PORTS_FILE; OPTION_STRING; PORT_NAME_S; &
		AVAIL_CLASS; MODEM_TYPE_S
	USE
	  RETRY IF ERR = 59	!not enough data
	  CONTINUE END_OF_PORTS
	END WHEN
	!ignore comments...
 	GOTO READ_PORTS_LINE IF SEG$(OPTION_STRING, 1%, 1%) = "!"

	IF OPTION_STRING <> TRM$(NODE_NAME) THEN
	  !line is for another node: ignore it, but first save its node name...
	  IF ALT_NODES = "" THEN
	    !this is the first node...
	    ALT_NODES = OPTION_STRING
	  ELSE
	    !this is not the first node...
	    IF POS(ALT_NODES, OPTION_STRING, 1%) = 0% THEN
	      !this node is not already on the list...
	      IF POS(ALT_NODES, "one of", 1%) = 0% THEN
	        !this is the second node...
	        ALT_NODES = "one of " + ALT_NODES
	      END IF
	      I = POS(ALT_NODES, " or ", 1%)
	      IF I > 0% THEN
	        !replace existing "or" with comma...
	        ALT_NODES = SEG$(ALT_NODES, 1%, I-1%) + ", " + &
			SEG$(ALT_NODES, I+4%, LEN(ALT_NODES))
	      END IF	!I > 0
	      ALT_NODES = ALT_NODES + " or " + OPTION_STRING
	    END IF	!pos(alt_nodes..)
	  END IF	!alt_nodes
	  GOTO READ_PORTS_LINE 
	END IF		!option_string

 ADD_TO_PORTS:
	!save the info...
	PORT_INDEX = PORT_INDEX + 1%
	PORTS(PORT_INDEX, 0%) = PORT_NAME_S
	PORTS(PORT_INDEX, 1%) = AVAIL_CLASS
	PORTS(PORT_INDEX, 2%) = MODEM_TYPE_S

	!get the next line
	GOTO READ_PORTS_LINE

 END_OF_PORTS:
	CLOSE #PORTS_FILE
	PORT_COUNT = PORT_INDEX
	RETURN

 DISPLAY_SCREEN:
      	!**********************************************************************
	!clears screen, displays header
      	!**********************************************************************

	PRINT CHR$(27); "[2J"; CHR$(27); "[0;0H"; CHR$(27); "[1m"; &
		"                   APMC EXTERNAL COMMUNICATIONS SYSTEM"; &
		CHR$(27); "[0m"
	PRINT
	PRINT "	                   Available options:"
	PRINT
	SCREEN_LINES = 4%

	RETURN

 READ_MENU:                                  
      	!**********************************************************************
	!reads the menu file, selects the facilities the user is allowed
	!to choose, and displays the choices
	!**********************************************************************

	OPEN "LF_MENU" FOR INPUT AS FILE #MENU_FILE, &
		ACCESS READ, ALLOW MODIFY
	MENU_COUNT = 0%
	MENU_INDEX = 0%

 READ_MENU_LINE:
	!read a line from the menu...
	WHEN ERROR IN
    	  INPUT #MENU_FILE; MENU(0%, 0%); MENU(0%, 1%); MENU(0%, 2%); MENU_RIGHTS
	USE
	  RETRY IF ERR = 59	!not enough data
	  CONTINUE END_OF_MENU
	END WHEN
	!ignore comments...
	GOTO READ_MENU_LINE IF SEG$(MENU(0%, 0%), 1%, 1%) = "!"

	MENU(0%, 2%) = EDIT$(MENU(0%, 2%), 2%)	!delete spaces and tabs
	MENU_RIGHTS = EDIT$(MENU_RIGHTS, 2%)	!delete spaces and tabs
	ITEM_COUNT = 0%

 READ_MENU_RIGHTS:
	!get a rights ident...
	ITEM_COUNT = ITEM_COUNT + 1%
	OPTION_STRING = GET_SUB_STR(MENU_RIGHTS, ITEM_COUNT)
	IF OPTION_STRING = "" THEN
	  !user can't select this item, so ignore it...
	  GOTO READ_MENU_LINE
	END IF

	!does the user hold this right?...
	ACCEPT_MENU = CHKRDB(OPTION_STRING)
	GOTO ADD_TO_MENU IF ACCEPT_MENU <> 0%	!user holds it
	!user doesn't hold it: are there any other rights specified?...
	GOTO READ_MENU_RIGHTS

 ADD_TO_MENU:
	MENU_INDEX = MENU_INDEX + 1%
	MENU(MENU_INDEX, 0%) = MENU(0%, 0%)
	MENU(MENU_INDEX, 1%) = MENU(0%, 1%)
	MENU(MENU_INDEX, 2%) = MENU(0%, 2%)
	GOTO READ_MENU_LINE

 END_OF_MENU:
	CLOSE #MENU_FILE

	MENU_COUNT = MENU_INDEX
	MENU_COL2 = INT(MENU_COUNT / 2%)
	MENU_COL1 = MENU_COUNT - MENU_COL2
	FOR MENU_INDEX = 1% TO MENU_COL2
	  PRINT USING MENU_FMT; "0"; NUM1$(MENU_INDEX); &
		MENU(MENU_INDEX, 1%); &
		"0"; NUM1$(MENU_INDEX + MENU_COL1); &
		MENU(MENU_INDEX + MENU_COL1, 1%)
	  SCREEN_LINES = SCREEN_LINES + 1%
	NEXT MENU_INDEX
	IF MENU_COL1 = MENU_COL2 THEN
	  PRINT USING MENU_FMT; "1"; "EXIT"; "Exit External System"; "0"
	ELSE
	  PRINT USING MENU_FMT; "0"; NUM1$(MENU_COL1); MENU(MENU_COL1, 1%); &
		"1"; "EXIT"; "Exit External System"
	END IF
	SCREEN_LINES = SCREEN_LINES + 1%
	!set scrolling region for user interaction...
	PRINT CHR$(27); "["; NUM1$(SCREEN_LINES+1%); ";24r";
	PRINT CHR$(27); "["; NUM1$(SCREEN_LINES+1%); ";1H";
	RETURN

	%PAGE
	%SBTTL "FUNCTION DEFINITION SECTION"
20000	!======================================================================
	!		       	FUNCTION DEFINITION SECTION
	!======================================================================

	!**********************************************************************
	!given a string which is composed of substrings separated by "+" signs,
	!and an integer, returns the specified substring
	!**********************************************************************

	DEF STRING GET_SUB_STR(STRING GSS_INPUT, WORD GSS_COUNT)

	DECLARE WORD &
		GSS_P1, GSS_P2, GSS_INDEX

	GSS_P1 = 1%
	GSS_P2 = POS(GSS_INPUT, "+", 1%)
	GSS_P2 = LEN(GSS_INPUT) + 1% IF GSS_P2 = 0%
	GSS_INDEX = 1%

 GSS_CHECK:
	IF GSS_COUNT = GSS_INDEX THEN
	  !we have the requested substring...
	  GET_SUB_STR = SEG$(GSS_INPUT, GSS_P1, GSS_P2 - 1%)
	  EXIT DEF
	END IF

	IF GSS_P2 >= LEN(GSS_INPUT) THEN
	  !there are not enough substrings...
	  GET_SUB_STR = ""
	  EXIT DEF
	END IF

	GSS_P1 = GSS_P2 + 1%
	GSS_P2 = POS(GSS_INPUT, "+", GSS_P1)
	GSS_P2 = LEN(GSS_INPUT) + 1% IF GSS_P2 = 0%
	GSS_INDEX = GSS_INDEX + 1%
	GOTO GSS_CHECK

	END DEF

	%PAGE                                                                  
	%SBTTL "ERROR HANDLING SECTION"
25000	!======================================================================
	!			ERROR HANDLING SECTION
	!======================================================================

 ERROR_HANDLING:
	GOSUB RESET_SCROLL	!reset scrolling region...
	ON ERROR GOTO 0
                                                                               
	!======================================================================
	!			END OF PROGRAM
	!======================================================================

 END_OF_PROGRAM:
 	GOSUB RESET_SCROLL	!reset scrolling region...
	EXIT FUNCTION FUNC_STAT

29999	END FUNCTION
