.TITLE CAT - MCR CATCH-ALL TASK .IDENT /2.2/ .ENABL LC ;+ ; ; Free software BY ; Project Software & Development, Inc. ; ; This software is furnished for free and may be used and copied as ; desired. This software or any other copies thereof may be provided or ; otherwise made available to any other person. No title to and ; ownership of the software is hereby transferred or allowed. ; ; The information in this software is subject to change without notice ; and should not be construed as a commitment by PROJECT SOFTWARE ; AND DEVELOPMENT, INC. ; ; PROJECT SOFTWARE assumes no responsibility for the use or reliability ; of this software on any equipment whatsoever. ; ; Project Software & Development, Inc. ; 14 Story St. ; Cambridge, Ma. 02138 ; 617-661-1444 ; ; ; Title: CAT.MAC ; Author: Robin Miller ; Date: July 19, 1982 ; ; Description: ; ; This task is envoked by the MCR when the command is not recognized ; by the MCR. It must be installed with a task name of "...CA.". ; ;- .NLIST BEX .MCALL ALUN$, DIR$, EXIT$S, EXST$S, GIN$, GLUN$, GTSK$, GMCR$ .MCALL MRKT$, QIOW$, WTSE$ .MCALL FSRSZ$, FINIT$, FDBDF$, NMBLK$, FDOP$A, FDOFF$, NBOFF$ .IF NDF DEBUG FDOFF$ DEF$L ; DEFINE FDB OFFSETS LOCALLY NBOFF$ DEF$L ; DEFINE FNB OFFSETS LOCALLY .IFF FDOFF$ DEF$G ; DEFINE FDB OFFSETS GLOBALLY NBOFF$ DEF$G ; DEFINE FNB OFFSETS GLOBALLY .ENDC ; End DEBUG conditional. ;+ ; ; Modification History: ; ; January 14, 1985 by Robin Miller. ; Modified call to CUPPER routine which now converts a string ; terminated by NULL. Removed unused DCLBUF label and string. ; ; December 13, 1984 by Robin Miller. ; Attempt to get the login UIC via the general information ; directive (GIN$) since it copies this information from the ; accounting block on RSX-11M+. ; ; September 10, 1984 by Robin Miller. ; Add check for terminal number greater than 77 octal. ; ; September 6, 1984 by Robin Miller. ; Modified to run on RSX-11M+. ; ; August 23, 1982 by Gary N. Larsen. ; Modified for support of DCL commands. ; ;- ; Local equates: ASCSIZ = 10. ; SIZE OF ASCII COMMAND NAME SY.UIC = 0 ; The system UIC. LI.UIC = 2 ; The library UIC. HD.UIC = 4 ; The default UIC. HC.UIC = 6 ; The current UIC. LO.UIC = 10 ; The login UIC. GINUIC: GIN$ GI.UIC,UICBUF,UICSIZ ; GIN$ directive to get UIC's. ; Status bit definitions: S.PRIV == 1 ; TERMINAL IS PRIVILEGED S.SPRV == 2 ; TERMINAL WAS SET PRIVILEGED S.EMCR == 4 ; TASK IS EXITING TO THE MCR S.VFAM == 10 ; TERMINAL IS OF THE VT100 FAMILY S.CMD == 200 ; A COMMAND LINE WAS SPECIFIED S.DEBUG == 100000 ; DEBUGGING OUTPUT IS ENABLED ; ; ALLOCATE LOCAL DATA, DPB, AND CONTROL DATA STRUCTURES ; FSRSZ$ 0 ; READY FSR SPACE ALUN: ALUN$ TILUN,TI,0 ; ASSIGN A LUN TO TI0: GLUN: GLUN$ TILUN,LUNBUF ; GET LUN INFORMATION ON TI0: LUNBUF::.BLKW 6 ; AND STORE IT HERE GMCR:: GMCR$ ; GET-COMMAND-LINE DPB CMDBUF == GMCR+G.MCRB ; ADDRESS OF COMMAND LINE ASCNAM::.BLKB ASCSIZ ; ASCII COMMAND NAME .EVEN RADNAM::.BLKW 3 ; RAD50 COMMAND NAME ASCTTY::.BLKB 4 ; ASCII TERMINAL NUMBER (Tnn). CMDLEN::.WORD 0 ; LENGTH OF ENTIRE COMMAND LINE CMDCNT::.WORD 0 ; LENGTH OF THE COMMAND NAME SCMD:: .WORD 0 ; START OF COMMAND PARAMETERS TBYTE:: .WORD 0 ; COMMAND TERMINATING BYTE STATUS::.WORD 0 ; CATCHALL STATUS WORD GTSK: GTSK$ TSKBUF ; GET OUR TASK PARAMETERS TSKBUF::.BLKW 16. ; AND STORE IT HERE UICBUF::.BLKW 5 ; Buffer for returned UIC's. UICSIZ = <.-UICBUF>/2 ; UIC buffer size in words. GETCHA: QIOW$ SF.GMC,TILUN,TIEFN,,IOSB,, ; GET TERM CHAR. TTYST: .BYTE TC.TTP ; GET TERMINAL TYPE TTYPE:: .BYTE T.V100 ; INITIALIZE TO VT100 TTYSIZ = .-TTYST ; SIZE OF STATUS TABLE MRKTIM::MRKT$ MRKEFN,2,2 ; MARK TIME FOR 2 SECONDS MRKWAT::WTSE$ MRKEFN ; WAIT FOR MARK TIME IOSB:: .BLKW 2 ; I/O STATUS BLOCK FOR TI0: CATFDB::FDBDF$ ; ALLOCATE AN FDB FDOP$A CATLUN ; FOR GENERAL USE CATFNB::NMBLK$ ,TSK,,LB,0 ; DEFAULT FILE NAME BLOCK ; Spawn buffer: SPNBUF::.BLKB 200. ; BUFFER FOR COMMAND TO SPAWN .EVEN .SBTTL CAT -- CATCHALL STARTUP ;+ ; ; Get the command line from MCR and compare with table of commands. ; ; Outputs: ; R5 = Points to beginning of command line (NULL if none). ; ASCNAM = Command/task name in ASCII (terminated by NULL). ; ;- CAT:: MOV @#.FSRPT,R0 ; GET POINTER TO FSR TST A.DFUI(R0) ; HAS .FINIT BEEN DONE (DDT) BNE 10$ ; IF NE, YES (DO ONLY ONCE) FINIT$ ; DO THE FINIT 10$: DIR$ #ALUN ; ASSIGN LUN TO TI0: DIR$ #GLUN ; GET LUN INFO. ON TI0: DIR$ #GETCHA ; GET TERMINAL CHARACTERISTICS DIR$ #GTSK ; GET OUR TASK PARAMETERS CALL GETUIC ; Use GIN$ to get our login UIC. BCS 15$ ; If CS, the directive failed. MOV R0,TSKBUF+G.TSDU ; Save the real login account. 15$: CALL CKEXEC ; CHECK FOR CORRECT EXECUTIVE CALL CHKPRV ; CHECK TERMINAL FOR PRIVILEGED CALL CHKVT1 ; CHECK FOR VT100 FAMILY TERMINAL MOV #ASCTTY,R0 ; STORE TERMINAL # HERE MOV #LUNBUF,R2 ; Set address of Get LUN buffer. MOVB G.LUNA(R2),(R0)+ ; Copy 1st character of terminal name CLR R1 ; Initialize for next instruction. BISB G.LUNU(R2),R1 ; Copy the terminal number. CMP R1,#77 ; Is the unit number greater than 77 ? BLOS 20$ ; If LOS, no. MOV R1,R2 ; Copy the unit number. ASH #-3,R1 ; Calculate the high order character. ADD #'A-10,R1 ; Convert it to ASCII. BIC #177770,R2 ; Calculate the low order character. ADD #'0,R2 ; Convert it to ASCII. MOVB R1,(R0)+ ; Store the MOVB R2,(R0)+ ; terminal name. BR 30$ ; And continue ... 20$: CLR R2 ; SET ZERO SUPPRESSION CALL $CBTMG ; CONVERT BINARY TO ASCII 30$: CLRB (R0) ; SHOW END OF NUMBER DIR$ #GMCR ; GET FAKE COMMAND LINE BCC GOTIT ; IF CC, GOT A COMMAND JMP ERR1 ; ELSE COMMAND LOST .SBTTL GOTIT - GOT THE COMMAND LINE FROM THE MCR ;+ ; ; GOTIT - Got the command line from the MCR. ; ; Inputs: ; $DSW = the command line byte count. ; ;- GOTIT:: MOV #CMDBUF,R0 ; ADDRESS OF COMMAND BUFFER MOV $DSW,R2 ; COPY THE COMMAND LENGTH MOV R0,R1 ; COPY THE COMMAND BUFFER ADD R2,R1 ; POINT TO THE LAST BYTE ; Check for the enable debugging character. DEC R1 ; POINT TO LAST CHARACTER CMPB (R1)+,#'+ ; IS THERE A PLUS SIGN ? BNE 5$ ; IF NE, NO BIS #S.DEBUG,STATUS ; YES, ENABLE DEBUGGING OUTPUT 3$: MOVB (R1),-(R1) ; OVERWRITE "+" WITH TERMINATOR DEC R2 ; ADJUST THE BYTE COUNT CMPB -1(R1),#SPACE ; WAS "+" SIGN PRECEEDED BY SPACE ? BEQ 3$ ; IF EQ, YES (BACKUP TERMINATOR) ; Save the terminating character. 5$: MOV R2,CMDLEN ; SAVE THE COMMAND BYTE COUNT MOVB (R1),TBYTE ; SAVE THE TERMINATING BYTE CLRB (R1) ; AND TERMINATE WITH A NULL ; Convert the command line to uppercase (R0 = address). CALL CUPPER ; Convert command to uppercase. ; Copy the ASCII command name. MOV #CMDBUF,R0 ; START OF THE COMMAND LINE MOV #ASCNAM,R1 ; COPY IT HERE CLR R2 ; INITIALIZE THE BYTE COUNT ; The first non-alphanumeric terminates the command name. 20$: CMPB (R0),#'0 ; CHECK FOR NUMERIC BLO 40$ ; IF LO, DONE CMPB (R0),#'9 ; IS IT REALLY A NUMBER ? BLOS 30$ ; IF LOS, YES CMPB (R0),#'A ; POSSIBLY ALPHABETIC ? BLO 40$ ; IF LO, NO CMPB (R0),#'Z ; REALLY ALPHABETIC ? BHI 40$ ; IF HI, NO 30$: MOVB (R0)+,(R1)+ ; COPY THE CHARACTER INC R2 ; COUNT THIS BYTE CMP R2,#ASCSIZ ; OVER THE NAME LIMIT ? BLT 20$ ; IF LT, NO JMP ERR5 ; PRINT "Command line too long." 40$: CLRB (R1) ; TERMINATE THE COMMAND NAME MOV R2,CMDCNT ; SAVE SIZE OF COMMAND NAME ; If a valid delimiter was typed, we should be able to use it. ; Should be SPACE, TAB, or SLASH for a DCL command. MOV R0,SCMD ; SAVE THE START OF THE COMMAND TSTB (R0) ; IS THERE REALLY A COMMAND ? BEQ 45$ ; IF EQ, NO BIS #S.CMD,STATUS ; ELSE, SHOW THERE IS A COMMAND 45$: MOV #ASCNAM,R0 ; ADDRESS OF THE COMMAND NAME CALL MAKRAD ; MAKE THE RADIX-50 TASK NAME ; Compare command with entries in the command table. 50$: MOV #CMDBUF,R0 ; ADDRESS OF THE COMMAND BUFFER MOV CMDCNT,R2 ; COPY THE COMMAND NAME COUNT CALL COMPAR ; DO WE HAVE A MATCH ? BCC DOIT ; IF CC, DO THE COMMAND JMP FLYRUN ; Attempt to do a flying run. .SBTTL DOIT - Do The Specified Command ;+ ; ; DOIT - Do the specified command. ; ; This routine executes the command found in the command table. The ; command to be executed will be as follows: ; ; (DCL) 1. If its a DCL command, the command keyword is copied to the ; spawn buffer. If there is an alternate command, then ; that command is used instead of the command keyword. ; This allows us to have alternate DCL commands such as ; "SHD --> SHOW DEF". Then we goto step 4. ; ; (MCR) 2. If the use keyword bit is set, the keyword is used as the ; command to spawn to the MCR. This allows us to have ; short MCR commands such as "H --> HELP". ; ; (MCR) 3. If there is a command string in the table entry, ; that command is copied to the spawn buffer before ; any command line passed on the MCR command line. ; This allows for: i.e., FREE ddn: --> PIP ddn: ; ;(BOTH) 4. The remaining command line (if any) is appended to the ; command line to be spawned, and if there is an action ; routine, that routine is called. ; ;(BOTH) 5. If we return from the action routine, the command line ; is spawned to either the MCR or DCL, or if the task ; image bit is set, a flying RUN/INStall is done. ; ;- DOIT:: MOV SAVTBL,R5 ; COPY THE TABLE ENTRY ADDRESS MOV #SPNBUF,R1 ; SETUP THE SPAWN BUFFER ADDRESS BIT #B.DCL,O.STAT(R5) ; ARE WE SPAWNING A DCL COMMAND ? BEQ 10$ ; IF EQ, NO ; See if an alternate command should be used instead of the keyword. ; i.e., SHD --> SHOW DEF MOV O.CMD(R5),R0 ; IS THERE AN ALTERNATE COMMAND ? BNE 5$ ; IF NE, YES (USE IT) MOV (R5),R0 ; ELSE, GET ADDRESS OF KEYWORD 5$: CALL MOVE ; COPY IT TO THE SPAWN BUFFER BR 20$ ; AND CONTINUE ... ; See if the keyword should be used as the MCR command. ; i.e., H --> HELP 10$: BIT #B.UKEY,O.STAT(R5) ; SHOULD WE USE THE KEYWORD ? BEQ 15$ ; IF EQ, NO MOV (R5),R0 ; COPY THE KEYWORD ADDRESS CALL MOVEC ; AND COPY IT TO THE SPAWN BUFFER ; MCR Command - Check for an alternate command string to copy. ; i.e., FREE ddn: --> PIP ddn: 15$: MOV O.CMD(R5),R0 ; IS THERE AN ALTERNATE COMMAND ? BEQ 20$ ; IF EQ, NO CALL MOVEC ; YES, COPY IT TO THE SPAWN BUFFER ; ; Append the remaining command line to the spawn buffer (if any) ; and call the action routine if there is one. ; ; Outputs: ; R1 = the updated spawn buffer address. ; 20$: CALL COPCMD ; COPY THE REMAINING COMMAND LINE TST O.ACT(R5) ; IS THERE AN ACTION ROUTINE ? BEQ 40$ ; IF EQ, NO (SPAWN WHAT WE HAVE) ; For an action routine, add a space if no command string has ; been specified so the routine being called doesn't have to. TSTB STATUS ; Was a command string specified ? BMI 30$ ; If MI, yes. MOVB #SPACE,(R1)+ ; No, so add a space. CLRB (R1) ; And set the terminator. 30$: CALL @O.ACT(R5) ; ELSE, CALL THE ACTION ROUTINE ; See if this is a task image to be RUN/INStalled. 40$: BIT #B.TASK,O.STAT(R5) ; SHOULD WE RUN/INSTALL ? BEQ 50$ ; IF EQ, NO (SPAWN IT) MOV (R5),R0 ; COPY THE KEYWORD ADDRESS CALL MAKRAD ; MAKE THE RADIX-50 TASK NAME JMP FLYALT ; GO DO IT ; Spawn the command line to the MCR or DCL. 50$: CALL SPAWN ; NOW SPAWN THE COMMAND LINE JMP EXST ; AND EXIT WITH THE STATUS .SBTTL CHKVT1 - Check For VT100 Family Terminal ;+ ; ; CHKVT1 - Check for VT100 Family Terminal. ; ; Since there are numerous VT100 family terminals (VT100, VT101, VT102, ; VT105, VT125, VT131, and VT132) at this time, this routine will set ; bit S.VFAM in the STATUS word if we're running on a VT100 family. ; ;- CHKVT1: JSR R2,$SAVVR ; Save R0 - R2 MOVB TTYPE,R0 ; Copy the terminal type. CMPB #T.V100,R0 ; Is this a VT100 ? BEQ 10$ ; If EQ, yes ; Range of terminals is T.V101 (24) through T.V132 (31). CMPB R0,#T.V101 ; Is this possible VT100 family ? BLO 20$ ; If LO, no CMPB R0,#T.V132 ; Really a in VT100 family ? BHI 20$ ; IF HI, NO 10$: BIS #S.VFAM,STATUS ; Running on VT100 family terminal 20$: RETURN .SBTTL COPCMD - Copy The Command Line ;+ ; ; COPCMD - Copy the command line to the spawn buffer. ; ; This routine is used to copy the command line (if any) to the spawn ; buffer. It also checks the ignore bit in the command table entry ; and skips the copy if it is set. ; ; Inputs: ; R1 = the output buffer address (usually the spawn buffer). ; R5 = the command table entry address. ; ; Outputs: ; R1 = the updated buffer address (if a copy occured). ; Register R0 is destroyed. ; ;- COPCMD::BIT #B.IG,O.STAT(R5) ; Should we ignore the command ? BNE 10$ ; If NE, yes MOV SCMD,R0 ; Copy start of command address CALL MOVEC ; And append it to the spawn buffer 10$: RETURN .SBTTL COMPAR - COMPARE STRING FOR ENTRY IN TABLE ;+ ; ; COMPAR - Compare string for entry in table. ; ; This routine searches for a string within a table and if found, ; passes back the address of the entry within the table. ; ; Inputs: ; R0 - Input string. ; R2 - Size of input command. ; ; Outputs: ; C bit clear/set = success/failure. ; If Success, SAVTBL = the table entry address ; ; All registers are preserved. ; ;- COMPAR:: CALL $SAVAL ; SAVE EM MOV #CMDTBL,R1 ; ADDRESS OF THE COMMAND TABLE 5$: MOV R0,R3 ; ADDRESS OF THE INPUT STRING MOV (R1),R4 ; ADDRESS OF ASCII KEYWORD CLR R5 ; INITIALIZE THE COMPARE COUNT ; The command table is in alphabetic order. If the first ; letter of the input string is greater than the first letter ; in the table entry, then the command doesn't exist. CMPB (R3),(R4) ; ARE WE PAST THIS LETTER ? BMI 100$ ; IF MI, YES (ENTRY NOT FOUND) ; Compare the current table entry. 10$: CMPB (R3)+,(R4)+ ; DO THEY MATCH BNE 20$ ; IF NE, NO (NEXT ENTRY) INC R5 ; COUNT THE CHARACTER CMPB R5,O.MIN(R1) ; HAVE WE MATCHED THE MINIMUM ? BLT 10$ ; IF LT, NO CMPB R5,O.MAX(R1) ; HAVE WE EXCEEDED COMMAND SIZE ? BGT 20$ ; IF GT, YES (NEXT ENTRY) CMPB R5,R2 ; HAVE WE MATCHED THE ENTIRE STRING ? BEQ 110$ ; IF EQ, YES (SUCCESS) BR 10$ ; ELSE CHECK NEXT BYTE ; Point to the next table entry address. 20$: ADD #TBLSIZ,R1 ; POINT TO NEXT ENTRY TST (R1) ; END OF TABLE ? BNE 5$ ; IF NE, NO (DO NEXT ENTRY) 100$: SEC ; ELSE THE ENTRY WASN'T IN THE TABLE RETURN 110$: MOV R1,SAVTBL ; SAVE THE TABLE ENTRY ADDRESS CLC ; CLEAR FOR SUCCESS RETURN .SBTTL GETUIC - Use GIN$ To Get Login UIC ;+ ; ; GETUIC - Use GIN$ to get the login UIC. ; ; This routine uses the general information directive (GIN$) to get ; the login UIC from the accounting block. The get task directive ; (GTSK$) copies the login UIC from the unit control block (UCB) ; intead of the accounting block on RSX-11M+. ; ; Inputs: ; None ; ; Outputs: ; R0 = The login UIC. ; ; Carry bit clear/set = success/failure. ; ;- GETUIC::DIR$ #GINUIC ; Try to get the login UIC. BCS 100$ ; If CS, it failed. MOV UICBUF+LO.UIC,R0 ; Copy the login UIC. 100$: RETURN .SBTTL MAKRAD - Make The RADIX-50 Task Name ;+ ; ; MAKRAD - Make the RADIX-50 task name. ; ; Convert ASCII command/task name to Radix-50 and save it in CAT ; file name block and radix-50 name buffer for file lookup. ; ; Inputs: ; R0 = the address of the ASCII string to convert. ; ; Outputs: ; All registers are preserved. ; ;- MAKRAD::CALL $SAVAL ; SAVE ALL REGISTERS MOV #RADNAM,R3 ; ADDRESS TO SAVE RAD50 NAME MOV #CATFNB+N.FNAM,R4 ; ADDRESS OF FILE NAME BLOCK CLR R1 ; SET PERIOD AS TERMINATOR CHAR. CALL $CAT5 ; CONVERT FROM ASCII TO RADIX-50 MOV R1,(R3)+ ; FIRST 3 CHARACTER OF NAME MOV R1,(R4)+ ; AND THE FILE NAME BLOCK BCS 10$ ; IF CS, LESS THAN 3 CHAR IN TASK NAME CALL $CAT5 ; ELSE, CONVERT THE NEXT 3 CHAR. MOV R1,(R3)+ ; SECOND 3 CHARACTERS OF NAME MOV R1,(R4)+ ; AND THE FILE NAME BLOCK BCS 10$ ; IF CS, LESS THAN 6 CHAR IN TASK NAME CALL $CAT5 ; CONVERT LAST 3 CHAR OF TASK NAME MOV R1,(R3)+ ; THIRD 3 CHARACTERS OF NAME MOV R1,(R4)+ ; AND THE FILE NAME BLOCK BCS 10$ ; IF CS, LESS THAN 9 CHARACTERS MOVB (R0)+,R2 ; SET UP TERMINATING CHARACTER 10$: RETURN .SBTTL Catchall Error Messages ; Error Message Routines: ERR1:: WRTMSG EM1, BR EXIERR ; Exit with error status. ERR2:: WRTMSG EM2, BR EXIERR ; Exit with error status. ERR4:: WRTMSG EM4, BR EXIERR ; Exit with error status. ERR5:: WRTMSG EM5, BR EXIERR ; Exit with error status. .SBTTL COMMON EXIT ROUTINES ; Common exit routines: EXISUC::MOV #EX$SUC,R0 ; SET SUCCESS STATUS BR EXST ; AND EXIT WITH STATUS EXIWAR::MOV #EX$WAR,R0 ; SET WARNING STATUS BR EXST ; AND EXIT WITH STATUS EXIERR::MOV #EX$ERR,R0 ; SET ERROR STATUS BR EXST ; AND EXIT WITH STATUS EXISEV::MOV #EX$SEV,R0 ; SET SEVERE STATUS ; Exit with status in R0. EXST:: EXST$S R0 ; EXIT WITH STATUS EXIT$S ; IN CASE EXST$S FAILS .END CAT