10 !====================================================================== !PROGRAM---------------------VERSION-------------------LANGUAGE-------- !EXTERNAL 13 BASIC ! !DESCRIPTION----------------------------------------------------------- !Program to provide users with access to external facilities. !Performs customized menu selection, automatic port allocation, !dialling and logging-on. Keeps a log file of the session. ! !====================================================================== %TITLE "External Communications Program" %IDENT "EXTERNAL 92.11.04" %SBTTL "DOCUMENTATION SECTION" !********************************************************************** ! OPTIONS !********************************************************************** OPTION TYPE = EXPLICIT ! Explicit declarations only 100 !********************************************************************** ! DOCUMENTATION SECTION !********************************************************************** ! !====================================================================== ! MODIFICATION HISTORY !====================================================================== !VERSION--------AUTHOR------------------DATE------------APPROVAL------- ! 1 Keith Walker 86.08.20 E-1637 ! 2 Keith Walker 86.09.03 E-1637 ! 3 Keith Walker 86.10.06 M-7407 ! 4 Keith Walker 88.02.10 1723 ! 5 Keith Walker 88.10.11 1741 ! 6 Keith Walker 88.11.29 E102_0_9 ! 7 Keith Walker 89.03.23 M102-0-41 ! 8 Keith Walker 89.06.03 M102_0_46 ! 9 Keith Walker 89.06.09 M102_0_49 ! 10 Keith Walker 90.02.02 M102_0_74 ! 11 Keith Walker 90.02.02 M102_0_75 ! 12 John Post 90.12.21 E102ISD_0_21 ! 13 Keith Walker 92.11.02 E102ISD_0_30 ! !====================================================================== ! COMPILE/LINK INSTRUCTIONS !====================================================================== !$BASIC EXTERNAL !$LINK EXTERNAL,- ! EXT_READ_PORT_AST, EXT_UNSOL_MBX_AST,- ! EXT_PROC_BUF_AST, EXT_WRITE_TERM_AST,- ! EXT_SCRIPT_INTERP, EXT_SCREEN_HDR,- ! EXT_MENU, EXT_CONNECT_LOOP, EXT_PARSE,- ! CHKRGHTS, EXT_FT_MENU, XMODEM ! !====================================================================== !********************************************************************** ! FILES ACCESSED !********************************************************************** ! NAME MODE CHANNEL DESCRIPTION !-------------- ------ ------- ------------------------------- !xxxx.LOG WRITE LOG_FILE log file !MENU.DAT READ MENU_FILE menu file !PORTS.DAT READ PORTS_FILE ports file !EXTERNAL_yy.LOG APPEND RECORD_FILE record file !xxxx.SCR READ SCRIPT_FILE script files !EXT_xxx.LIS WRITE variable buffer dump on script error ! !********************************************************************** %PAGE %SBTTL "DECLARATION SECTION" 200 !====================================================================== ! DECLARATION SECTION !====================================================================== !********************************************************************** ! DECLARATIONS FROM %INCLUDE FILES !********************************************************************** %INCLUDE "EXT_COMMON.BAS" !********************************************************************** ! CONSTANTS !********************************************************************** !********************************************************************** ! RECORDS !********************************************************************** !********************************************************************** ! MAPS !********************************************************************** MAP (PERM_LOG_MAP) !used for writing to permanent log & STRING START_TIME = 12,& STRING END_TIME = 12, & STRING FAC_NAME = 10, & STRING USER_NAME = 12, & STRING ACCOUNT_NAME = 12, & STRING MNODE_NAME = 10, & STRING MPORT_NAME = 5, & STRING MODEM_NAME = 10, & STRING MESSAGE = 50 MAP (TIME_MAP) & STRING ASCTIM = 23 !********************************************************************** ! COMMONS !********************************************************************** !********************************************************************** ! VARIABLES !********************************************************************** DECLARE STRING & ABORT_TEXT, & COMMAND_LINE, & LOG_FILE_NAME, & DEFAULT_VIEW, & LOOP_TO_MENU DECLARE WORD & TERM_BUF, & TERM_IOSB(3) DECLARE LONG & BAUD_RATE, & I, & J, & JUNK, & PARITY_FLAGS, & PID, & RIGHTS_ID, & TERM_READ_CODE, & EXIT_STATUS, & TIMER_EFN, & CONNECT_EFN, & FLAGS DECLARE QUAD & MODEM_CONTROL, & DELTA_TIME !********************************************************************** ! ARRAYS !********************************************************************** !********************************************************************** ! FUNCTIONS !********************************************************************** DECLARE STRING FUNCTION & NOW !returns current date/time !********************************************************************** ! EXTERNAL CONSTANTS !********************************************************************** EXTERNAL LONG CONSTANT & SMG$M_REVERSE, & SMG$M_BOLD, & IO$_TTY_PORT, & IO$_SENSEMODE, & IO$_SETMODE, & IO$_WRITEVBLK, & IO$_READVBLK, & IO$M_LT_CONNECT, & IO$M_LT_DISCON, & IO$M_NOECHO, & IO$M_TIMED, & IO$M_SET_MODEM, & IO$M_MAINT, & JPI$_USERNAME, & JPI$_ACCOUNT, & JPI$_PID, & LIB$M_CLI_CTRLY, & SS$_WASSET, & SS$_NORMAL, & TT$C_BAUD_110, & TT$C_BAUD_300, & TT$C_BAUD_1200, & TT$C_BAUD_2400, & TT$C_BAUD_4800, & TT$C_BAUD_9600, & TT$C_BAUD_19200, & TT$M_ALTDISPAR, & TT$M_ALTFRAME, & TT$M_ALTRPAR, & TT$M_DISPARERR, & TT$M_DS_DTR, & TT$M_EIGHTBIT, & TT$M_HOSTSYNC, & TT$M_MECHTAB, & TT$M_MODEM, & TT$M_NOBRDCST, & TT$M_NOTYPEAHD, & TT$M_ODD, & TT$M_PARITY, & TT$M_TTSYNC, & TT2$M_ALTYPEAHD, & TT2$M_AUTOBAUD, & TT2$M_DRCS, & TT2$M_EDIT, & TT2$M_PASTHRU, & TT2$M_PRINTER !********************************************************************** ! EXTERNAL FUNCTIONS !********************************************************************** EXTERNAL LONG & EXT_PARSE, !CLI table to parse EXT command & EXT_READ_PORT_AST, & EXT_MBX_KICKER_AST EXTERNAL LONG FUNCTION & SMG$SET_KEYPAD_MODE, & SMG$DELETE_PASTEBOARD, & SMG$DELETE_VIRTUAL_KEYBOARD, & SMG$CREATE_VIRTUAL_KEYBOARD, & SMG$CREATE_PASTEBOARD, & SMG$CREATE_VIRTUAL_DISPLAY, & SMG$CREATE_VIEWPORT, & SMG$LABEL_BORDER, & SMG$PASTE_VIRTUAL_DISPLAY, & SMG$UNPASTE_VIRTUAL_DISPLAY, & CLI$DCL_PARSE, & CLI$PRESENT, & CLI$GET_VALUE, & LIB$FIND_FILE, & LIB$FREE_EF, & LIB$GET_EF, & LIB$GET_FOREIGN, & LIB$GET_SYMBOL, & LIB$SET_SYMBOL, & LIB$GETJPI, & LIB$ASN_WTH_MBX, & LIB$DISABLE_CTRL, & SYS$ASCTOID, & SYS$CANCEL, & SYS$CANTIM, & SYS$DCLAST, & SYS$ASSIGN, & SYS$GETTIM, & SYS$QIO, & SYS$QIOW, & SYS$DALLOC, & SYS$DASSGN, & SYS$SETIMR, & EXT_SCRIPT_INTERP, & EXT_MENU, & CHKRGHTS !********************************************************************** ! EXTERNAL SUBPROGRAMS !********************************************************************** EXTERNAL SUB & EXT_SCREEN_HDR %PAGE %SBTTL "INITIALIZATION SECTION" 300 !====================================================================== ! INITIALIZATION SECTION !====================================================================== ON ERROR GOTO ERROR_HANDLING !<<< CALL LIB$DISABLE_CTRL(LIB$M_CLI_CTRLY) !!<< "" THEN COMMAND_LINE = "EXT " + EDIT$(COMMAND_LINE, 152) !parse the line... JUNK = CLI$DCL_PARSE(COMMAND_LINE, EXT_PARSE, , , ) IF (JUNK AND 1%) = 1% THEN JUNK = CLI$PRESENT("TEST") !we don't use this info at present !but here it is, just in case JUNK = CLI$PRESENT("P1") IF (JUNK AND 1%) = 1% THEN !there is a facility... JUNK = CLI$GET_VALUE("P1", FACILITY_CODE) JUNK = LIB$SET_SYMBOL("FACILITY_CODE", TRM$(FACILITY_CODE), 1%) END IF !junk (cli$present status) ELSE !if we have got a command line, it should be right... EXIT PROGRAM JUNK END IF !junk (cli$dcl_parse status) ELSE !no command line JUNK = LIB$GET_SYMBOL("EXTINI", FACILITY_CODE) END IF !command line DISPLAY_MENU: !display menu and get selection: if the command line gave us a !facility name, we won't actually display the menu, but we need to !call the routine to allocate an appropriate port... JUNK = EXT_MENU IF (JUNK AND 1%) = 0% THEN GOTO EXIT_PROG END IF CONT_FLAG = TRUE !not finished yet !enable ^C trap... JUNK = CTRLC CALL EXT_SCREEN_HDR("Facility selected: " + TRM$(FACILITY_NAME), & "Enter to abort") !open log file... LOG_FILE_NAME = "SYS$LOGIN:" + TRM$(FACILITY_CODE) + ".LOG" OPEN LOG_FILE_NAME FOR OUTPUT & AS FILE #LOG_FILE, & ORGANIZATION SEQUENTIAL STREAM, & MAP LOG_BUF_MAP JUNK = LIB$FIND_FILE(LOG_FILE_NAME, LOG_FILE_NAME, 0%) !assign channels for I/O... JUNK = SYS$ASSIGN("SYS$OUTPUT", TERM_CHAN, , ) IF (JUNK AND 1%) = 0% THEN GOTO STOP_CONNECTION END IF !channels for modem I/O have already been assigned by EXT_MENU !get status of terminal and port... JUNK = SYS$QIOW(!efn!, TERM_CHAN BY VALUE, & IO$_SENSEMODE BY VALUE, & ,,, & OLD_TERM_MODE(0) BY REF, & 12% BY VALUE,,,,) JUNK = SYS$QIOW(!efn!, PORT_CHAN BY VALUE, & IO$_SENSEMODE BY VALUE, & ,,, & OLD_PORT_MODE(0) BY REF, & 12% BY VALUE,,,,) !set up the port... !---------------------------------------------------------------------- !For a served port, this stuff has very little effect, but on the other !hand, it does no harm. The data bits and parity settings for served !ports are handled elsewhere. This code here works for hard-wired !ports. !---------------------------------------------------------------------- PORT_MODE(0) = OLD_PORT_MODE(0) PORT_MODE(1) = OLD_PORT_MODE(1) & AND (NOT TT$M_NOTYPEAHD) !allow typeahead & OR TT$M_HOSTSYNC !we can throttle the port & AND (NOT TT$M_TTSYNC) !the port can't throttle us & AND (NOT TT$M_MODEM) !we control DTR & OR TT$M_EIGHTBIT !eight bit data & OR TT$M_NOBRDCST !don't send junk to the port PORT_MODE(2) = OLD_PORT_MODE(2) & OR TT2$M_ALTYPEAHD !big buffer & OR TT2$M_PASTHRU !let all bytes through !set defaults (8 bits, no parity, 1200 baud)... SEVENBIT_FLAG = FALSE PARITY_SELECT = 0 !none PARITY_FLAGS = TT$M_ALTDISPAR OR TT$M_DISPARERR !ignore parity on input PARITY_FLAGS = PARITY_FLAGS OR TT$M_ALTRPAR !no parity on output PARITY_FLAGS = PARITY_FLAGS OR TT$M_ALTFRAME OR 8% !8 bits BAUD_RATE = TT$C_BAUD_1200 !1200 baud JUNK = SYS$QIOW(!efn!, PORT_CHAN BY VALUE, & IO$_SETMODE BY VALUE, & ,,, & PORT_MODE(0) BY REF, & 12% BY VALUE, & BAUD_RATE BY VALUE,, & PARITY_FLAGS BY VALUE,) GOSUB DTR_ON !switch on DTR !kick off receive AST loop by reading data from the port... JUNK = SYS$DCLAST(EXT_READ_PORT_AST BY REF, !astprm!, !acmode!) !... and start the mailbox kicker... JUNK = SYS$SETIMR(!efn!, ONE_SEC, EXT_MBX_KICKER_AST, & MBX_KICKER_TIMER BY VALUE) !run the facility script... IF DEFAULT_VIEW = "1" THEN !let user see script if verify is on... VIEW_FLAG = TRUE LOG_FLAG = TRUE !log script ELSE !if no verify, VIEW is off unless the script turns it on.. VIEW_FLAG = FALSE LOG_FLAG = FALSE !don't log script END IF CENSOR_FLAG = FALSE ECHO_FLAG = FALSE !normally, no local echo EXIT_STATUS = EXT_SCRIPT_INTERP(TRM$(FACILITY_CODE), "S", SCRIPT_FILE) ONLINE_DONE: !print the abort message, if any... JUNK = LIB$GET_SYMBOL("ABORT_TEXT", ABORT_TEXT) IF ABORT_TEXT <> " " THEN PRINT CHR$(27); "[1m"; ABORT_TEXT; CHR$(27); "[0m" END IF CALL EXT_SCREEN_HDR("Disconnecting from " + TRM$(FACILITY_NAME), & "Exit in progress") !run the disconnect script... IF DEFAULT_VIEW = "1" THEN !let user see script if verify is on... VIEW_FLAG = TRUE LOG_FLAG = TRUE !log script ELSE !if no verify, VIEW is off unless the script turns it on.. VIEW_FLAG = FALSE LOG_FLAG = FALSE !don't log script END IF ECHO_FLAG = FALSE !ECHO is off unless the script turns it on JUNK = EXT_SCRIPT_INTERP(TRM$(MODEM_TYPE), "D", SCRIPT_FILE) !record the session... I = 0 WHEN ERROR IN !note no FOR INPUT or FOR OUTPUT clause: first user of new year !creates new file... OPEN "LF_RECORD_LOG" AS FILE #RECORD_FILE, & ORGANIZATION SEQUENTIAL FIXED, & ACCESS APPEND, ALLOW MODIFY, & MAP PERM_LOG_MAP USE I = I + 1% SLEEP 1% RETRY IF I < 10% !keep trying a reasonable number of times PRINT "ERROR_APMC: Unable to record session. (Err="; & ERR; ") Please contact Technical Support." CONTINUE STOP_CONNECTION !forget it if it takes too long END WHEN JUNK = LIB$GET_SYMBOL("START_TIME", START_TIME) JUNK = LIB$GET_SYMBOL("NODE", MNODE_NAME) END_TIME = NOW TIME_OFF = CUR_TIME FAC_NAME = TRM$(FACILITY_CODE) I = 0% JUNK = LIB$GETJPI(JPI$_USERNAME, , , , USER_NAME, I) USER_NAME = SEG$(USER_NAME, 1, I) + SPACE$(12 - I) JUNK = LIB$GETJPI(JPI$_ACCOUNT, , , , ACCOUNT_NAME, I) ACCOUNT_NAME = SEG$(ACCOUNT_NAME, 1, I) + SPACE$(12 - I) MPORT_NAME = TRM$(PORT_NAME) MODEM_NAME = TRM$(MODEM_TYPE) MESSAGE = ABORT_TEXT PUT #RECORD_FILE CLOSE #RECORD_FILE IF LOG_PTR > 0 THEN PUT #LOG_FILE, COUNT LOG_PTR LOG_PTR = 0 END IF CLOSE #LOG_FILE !summarize for user... PRINT PRINT PRINT "Log file is: "; LOG_FILE_NAME CALL LIB$SUB_TIMES(TIME_OFF, TIME_ON, DELTA_TIME) CALL SYS$ASCTIM(, ASCTIM, TIME_ON, 1% BY VALUE) PRINT "Connected at: "; SEG$(ASCTIM, 1, 8) CALL SYS$ASCTIM(, ASCTIM, TIME_OFF, 1% BY VALUE) PRINT "Disconnected at: "; SEG$(ASCTIM, 1, 8) CALL SYS$ASCTIM(, ASCTIM, DELTA_TIME, 1% BY VALUE) PRINT "Elapsed Time: "; SEG$(ASCTIM, 1, 8) PRINT SET NO PROMPT INPUT "Press RETURN to continue..."; COMMAND_LINE STOP_CONNECTION: !stop the AST loop... CONT_FLAG = FALSE IF MBX_ACTIVE THEN JUNK = SYS$CANCEL(MBX_CHAN BY VALUE) END IF !reset the terminal... IF OLD_TERM_MODE(0%) <> 0% OR OLD_TERM_MODE(1%) <> 0% OR & OLD_TERM_MODE(2%) <> 0% THEN JUNK = SYS$QIOW(!efn!, TERM_CHAN BY VALUE, & IO$_SETMODE BY VALUE, & ,,, & OLD_TERM_MODE(0) BY REF, & 12% BY VALUE,,,,) END IF GOSUB RESET_SCROLL !reset the port and disable typeahead... GOSUB DTR_OFF IF OLD_PORT_MODE(0%) <> 0% OR OLD_PORT_MODE(1%) <> 0% OR & OLD_PORT_MODE(2%) <> 0% THEN OLD_PORT_MODE(1) = OLD_PORT_MODE(1) OR TT$M_NOTYPEAHD PARITY_FLAGS = TT$M_ALTDISPAR OR TT$M_DISPARERR !ignore parity on input PARITY_FLAGS = PARITY_FLAGS OR TT$M_ALTRPAR !default to none PARITY_FLAGS = PARITY_FLAGS OR TT$M_ALTFRAME OR 8% !default 8 bits BAUD_RATE = TT$C_BAUD_1200 JUNK = SYS$QIOW(!efn!, PORT_CHAN BY VALUE, & IO$_SETMODE BY VALUE, & ,,, & OLD_PORT_MODE(0) BY REF, & 12% BY VALUE, & BAUD_RATE BY VALUE,, & PARITY_FLAGS BY VALUE,) END IF IF SERVED_PORT = "Y" THEN JUNK = SYS$QIOW(!efn!, PORT_CHAN BY VALUE, & (IO$_TTY_PORT OR IO$M_LT_DISCON) BY VALUE, & !iosb!, & !astadr!, !astprm!, !p1!, !p2!, !p3!, !p4!, !p5!, !p6!) END IF JUNK = SYS$CANTIM(0% BY VALUE, !acmode!) JUNK = SYS$DASSGN(PORT_CHAN BY VALUE) JUNK = SYS$DASSGN(TERM_CHAN BY VALUE) JUNK = SYS$DASSGN(MBX_CHAN BY VALUE) JUNK = SYS$DALLOC(TRM$(PORT_NAME), !acmode!) !optionally return to menu... IF LOOP_TO_MENU = "Y" THEN FACILITY_CODE = "" GOTO DISPLAY_MENU END IF EXIT_PROG: IF POS(DEBUG_FLAG, "6", 1) > 0 THEN PRINT PRINT "INPUT PERFORMANCE SUMMARY" PRINT PRINT USING "Delayed reads (1-5b): ###,###"; DBG_DELAY_CNT PRINT USING "Undelayed reads (>5b): ###,###"; DBG_NODELAY_CNT PRINT " -------" PRINT USING "Reads with data: #,###,###"; DBG_DATA_CNT PRINT PRINT USING " Bytes read from port: ##,###,###"; DBG_BYTE_CNT IF DBG_DATA_CNT > 0 THEN PRINT USING " Average bytes per read: ###,###.#"; & REAL(DBG_BYTE_CNT) / REAL(DBG_DATA_CNT) END IF PRINT PRINT USING "Input loop halts (0b): ###,###"; DBG_UNSOL_CNT PRINT " ---------" PRINT USING "Total READs from port: #,###,###"; DBG_READ_CNT PRINT END IF GOTO END_OF_PROGRAM %PAGE %SBTTL "SUBROUTINE DEFINITION SECTION" 15000 !====================================================================== ! SUBROUTINE DEFINITION SECTION !====================================================================== INIT_SMG: !********************************************************************** !initializes SMG stuff... !********************************************************************** !create keyboard... JUNK = SMG$CREATE_VIRTUAL_KEYBOARD(KB_ID) JUNK = SMG$SET_KEYPAD_MODE(KB_ID, 0%) !create pasteboard... JUNK = SMG$CREATE_PASTEBOARD(PB_ID) !create the menu displays... JUNK = SMG$CREATE_VIRTUAL_DISPLAY(1%, 80%, HDR_DISP) JUNK = SMG$CREATE_VIRTUAL_DISPLAY(1%, 10%, ACTION_DISP, , SMG$M_REVERSE) JUNK = SMG$CREATE_VIRTUAL_DISPLAY(1%, 80%, MSG_DISP, , SMG$M_BOLD) JUNK = SMG$CREATE_VIRTUAL_DISPLAY(50%, 78%, MENU_DISP) JUNK = SMG$CREATE_VIEWPORT(MENU_DISP, 1%, 1%, 20%, 78%) JUNK = SMG$CREATE_VIRTUAL_DISPLAY(1%, 40%, EXIT_DISP, , SMG$M_BOLD) JUNK = SMG$LABEL_BORDER(MENU_DISP, "External Facilities", , , SMG$M_BOLD) JUNK = SMG$CREATE_VIRTUAL_DISPLAY(12%, 55%, HELP_DISP, , SMG$M_REVERSE) JUNK = SMG$LABEL_BORDER(HELP_DISP, "HELP", , , SMG$M_REVERSE) RETURN DTR_ON: !********************************************************************** !toggle DTR on !********************************************************************** ! Toggle DTR on MODEM_CONTROL::SINGLE_BYTE(2%) = TT$M_DS_DTR MODEM_CONTROL::SINGLE_BYTE(3%) = 0% JUNK = SYS$QIOW(!efn!, PORT_CHAN BY VALUE, & (IO$_SETMODE OR IO$M_SET_MODEM OR IO$M_MAINT) BY VALUE, & !iosb!, !astadr!, !astprm!, & MODEM_CONTROL BY REF,,,,,) RETURN DTR_OFF: !********************************************************************** !toggle DTR off !********************************************************************** ! Toggle DTR off MODEM_CONTROL::SINGLE_BYTE(2%) = 0% MODEM_CONTROL::SINGLE_BYTE(3%) = TT$M_DS_DTR JUNK = SYS$QIOW(!efn!, PORT_CHAN BY VALUE, & (IO$_SETMODE OR IO$M_SET_MODEM OR IO$M_MAINT) BY VALUE, & !iosb!, !astadr!, !astprm!, & MODEM_CONTROL BY REF,,,,,) RETURN RESET_SCROLL: !********************************************************************** !clears VT100 scrolling region !********************************************************************** PRINT CHR$(27); "[1;24r"; !scroll whole screen PRINT CHR$(27); "[24;1H"; !cursor to bottom PRINT CHR$(27); "[0m"; !no special effects RETURN %PAGE %SBTTL "FUNCTION DEFINITION SECTION" 20000 !====================================================================== ! FUNCTION DEFINITION SECTION !====================================================================== !********************************************************************** !returns current date/time as YYMMDDHHMMSS !********************************************************************** DEF STRING NOW DECLARE WORD & NOW_BUF(6) DECLARE LONG & NOW_LONG DECLARE STRING & NOW_STR CALL SYS$GETTIM(CUR_TIME) CALL SYS$NUMTIM(NOW_BUF(0), CUR_TIME) NOW_LONG = 1000000% + NOW_BUF(3) * 10000% + & NOW_BUF(4) * 100% + NOW_BUF(5) NOW_STR = SEG$(NUM1$(NOW_LONG), 2, 7) NOW_LONG = NOW_BUF(0) * 10000% + & NOW_BUF(1) * 100% + NOW_BUF(2) NOW_STR = SEG$(NUM1$(NOW_LONG), 3, 8) + NOW_STR NOW = NOW_STR END DEF %PAGE %SBTTL "ERROR HANDLING SECTION" 25000 !====================================================================== ! ERROR HANDLING SECTION !====================================================================== ERROR_HANDLING: IF ERR = 28 THEN !ctrl/c JUNK = LIB$SET_SYMBOL("ABORT_TEXT", "Interrupted by user") RESUME ONLINE_DONE END IF ON ERROR GOTO 0 !====================================================================== ! END OF PROGRAM !====================================================================== END_OF_PROGRAM: !errors are downgraded to non-reported info... EXIT_STATUS = (EXIT_STATUS AND X"FFFFFFF8") OR X"10000003" EXIT PROGRAM EXIT_STATUS 29999 END 30000 SUB DO_EXT !====================================================================== !This subprogram is what would execute if EXT_PARSE actually did !something. Since we are only interested in parsing the string, this !routine does nothing. However, it still has to exist, so here it is... !====================================================================== END SUB