.ENABL LC .TITLE MC2 - Aux command dispatcher .IDENT /02/ .NLIST BEX ;+ ; Title: MC2 - Auxillary MCR command dispatcher ; Version: 02 ; Author: Greg Thompson (Informatics/PMI) ; Date: 9/20/78 ; ; MC2 takes command lines for which MCR can not find an installed task ; for and further processes these commands for which would have otherwise ; received an "MCR -- TASK NOT IN SYSTEM" error message. ; ; MC2 first examines its internal command translation table for the ; entered command name. If the command is found in the table it is ; processed by an internal routine and in most cases requeued to MCR as ; some other command. If the command is not found then a search is made ; for CM:[1,55]command.* where command is the entered command name. If ; an .TSK extension is found the task is installed, marked to be removed ; on exit and invoked using the command line that invoked MC2. If an .CMD ; extension is found an @ is issued on the command file. If none of ; these extensions are found the same search is made in the SY:[grp,mem] ; directory where [grp,mem] is the users UIC and if he is a privileged ; user also CM:[1,56]. If still no suitable file is found an "MC2 -- ; Command not found." error message is returned. ; ; Assemble: ; ; MAC [12,24]MC2,[12,34]MC2/-SP=[1,1]EXEMC/ML,[11,10]RSXMC/PA:1,[12,10]MC2 ; ; Insert in MCR library: ; ; LBR [1,24]MCR/IN=[12,24]MC2 ; ; Build: ; ; TKB ; TKB>[1,54]MC2/PR/-SE/-FP/CP=[1,24]MCR/LB:MC2 ; TKB>[1,54]RSX11M.STB ; TKB>[1,1]EXELIB/LB ; TKB>/ ; TKB>UNITS=2 ; TKB>ASG=SY:1 ; TKB>ASG=TI:2 ; TKB>STACK=64 ; TKB>TASK=...MC2 ; TKB>PRI=160 ; TKB>/ ;- .MCALL QIOW$,DIR$,GMCR$,EXIT$S,MRKT$,WSIG$S,CLEF$S .MCALL FSRSZ$,FINIT$,FDBDF$,FDOP$A ; .PAGE ; ; Internal command processing table ; (Alphabetical order) ; CTABL: .WORD DELETE,CDELET ; Delete (file) .WORD DIRECT,CDIREC ; Directory .WORD ERASE,CERASE ; Erase (file) .WORD FREE,CFREE ; Free .WORD PURGE,CPURGE ; Purge (files) .WORD RENAME,CRENAM ; Rename (file) .WORD SPOOL,CSPOOL ; Spool file .WORD TYPE,CTYPE ; Type (file to terminal) .WORD UIC,CUIC ; Uic (set/display uic) .WORD 0 ; End of table ; ; Table of supported file extensions ; ; Format: .RAD50 /ext/ ; RAD50 extension name ; .WORD Pext ; Address of routine to process it ; EXTABL: .RAD50 /CMD/ ; Indirect command files .WORD PCMD ; .RAD50 /TSK/ ; Task image files .WORD PTSK ; .RAD50 / / ; End of extension table .WORD 0 ; ; .PAGE ; ; Equates ; LUNFL = 1 ; LUN for file operations LUNTI = 2 ; LUN for TI: output EFTI = 2 ; Event flag for TI operations MKTEF = 3 ; Mark time event flag MAXL = 9. ; Max # of chars for a command name CR = 015 ; ASCII carriage return LF = 012 ; ASCII line feed ESC = 033 ; ASCII escape character SPA = 040 ; ASCII space MC2A = 020040 ; Two ASCII spaces MKTIME = 4.*60. ; Time to wait for INS to work (in ticks) MINLEN = 3 ; Minimum length for internal command ; ; File system stuff ; FSRSZ$ 0 ; No files will be opened FDB: FDBDF$ ; Define a FDB for .FIND FDOP$A LUNFL,MC2T ; Indicate LUN to use ; MC2T: .WORD 4 ; Dataset descriptor DEVPTR: .WORD DEVSY ; Pointer to device name .WORD 9. ; DIRPTR: .WORD DIRUSR ; Pointer to directory name COML: .WORD 0 ; Length of command string .WORD COMAND ; (Dataset name) ; ; Get command line DPB and buffer ; GMCR: GMCR$ ; Get command line BUF = GMCR+2 ; Buffer address BPTR: .WORD 0 ; Pointer into command line ENDBF: .WORD 0 ; Pointer to end of MCR command buffer CMDR50: .BLKW 2 ; Holds command name in RAD50 MRKT: MRKT$ MKTEF,MKTIME,1 ; Time to wait for INS to work ; ; MC2s error messages ; WERR: QIOW$ IO.CCO,LUNTI,EFTI,,,,<0,0,040> ERR1: .ASCIZ /MC2 -- Command missing./ ERR2: .ASCIZ /MC2 -- Command not found./ ERR3: .ASCIZ /MC2 -- Syntax error./ ERR4: .ASCIZ /MC2 -- No pool space./ ERR5: .ASCIZ /MC2 -- Unable to install task./ ERR6: .ASCIZ /MC2 -- Unable to start task./ ; ; Internal command strings ; DELETE: .ASCIZ /DELETE/ ; Delete (file) DIRECT: .ASCIZ /DIRECTORY/ ; Directory ERASE: .ASCIZ /ERASE/ ; Erase FREE: .ASCIZ /FREE/ ; Free PURGE: .ASCIZ /PURGE/ ; Purge (files) RENAME: .ASCIZ /RENAME/ ; Rename (file) SPOOL: .ASCIZ /SPOOL/ ; Spool file (with selective delete) TYPE: .ASCIZ /TYPE/ ; Type (file to terminal) UIC: .ASCIZ /UIC/ ; Uic (set /uic) ; ; File spec parameters ; DEVSY: .ASCII /SY0:/ ; Device SY of user files DEVCM: .ASCII /CM0:/ ; Device CM of system files DIRUSR: .ASCII /[000,000]/ ; Directory of user files DIRSYS: .ASCII /[001,055]/ ; Directory of system files DIRPRV: .ASCII /[001,056]/ ; Directory of system files (priv user only) ; ; Misc strings ; .EVEN COMAND: .ASCII /xxxxxxxxx.*/ ; Command string TASKE: .ASCIZ !/TASK=! ; INS: .ASCIZ /INS / ; CMD: .ASCIZ /.CMD/ ; PIP: .ASCIZ /PIP / ; SDA: .ASCIZ /;*/ ; SDE: .ASCIZ !/DE! ; SLI: .ASCIZ !/LI! ; SFR: .ASCIZ !/FR! ; SPU: .ASCIZ !/PU! ; SRE: .ASCIZ !/RE! ; SSP: .ASCIZ !/SP! ; PIPTI: .ASCIZ /PIP TI:=/ ; SETUIC: .ASCIZ /SET UIC/ ; .EVEN ; .PAGE ; ; Auxillary MCR command dispatcher ; ; Process command line ; MC2: DIR$ #GMCR ; Get command line BCC 20$ ; Got a command line 10$: MOV #ERR1,R0 ; "Command missing" error message JMP ERROR ; ; ; Got our command line, move command name, figure length ; 20$: MOV #BUF,BPTR ; Initialize buffer pointer CLR R2 ; Init command length counter MOV #COMAND,R0 ; R0 -> place to put command string MOV #MC2A,(R0) ; Init first six chars of command name MOV #MC2A,2(R0) ; To all spaces (since it gets $CAT5ed) MOV #MC2A,4(R0) ; 30$: CALL GETC ; Get next character BCS 45$ ; End of command string CMPB #'/,R1 ; Is it a slash "/" for options? BEQ 48$ ; Yes, end of command name MOVB R1,(R0)+ ; Put character in buffer INC R2 ; Bump character count CMP R2,#MAXL ; Maximum length of comand reached? BLT 30$ ; No, get another character 40$: CALL GETC ; Yes, flush rest of command to next space BCC 40$ ; 45$: CMP #SPA,R1 ; Was it a space? BNE 50$ ; No 48$: DEC BPTR ; Yes, back over it 50$: MOV R2,COML ; Save command length BEQ 10$ ; If zero - command missing error CMP R2,#MINLEN ; Is string too short to be a local command BLT GETFIL ; Yes ; ; Now look for command in internal command table ; MOV #CTABL-2,R0 ; R0 -> command table 60$: MOV #COMAND,R1 ; R1 -> entered command MOV COML,R2 ; R2 = command length TST (R0)+ ; Skip over last dispatch address MOV (R0)+,R3 ; R3 -> current possible command BEQ GETFIL ; End of table if ptr zero 70$: CMPB (R1)+,(R3)+ ; Compare a byte of the strings BLO GETFIL ; If < current entry - not in table BHI 60$ ; If > current entry - try next command DEC R2 ; This char matches BGT 70$ ; More string to compare JMP @(R0)+ ; Match - dispatch to handling routine ; .PAGE ; ; Look for CM:[1,55]command.* to process command ; GETFIL: FINIT$ ; Init FSR MOV COML,R1 ; Get length of command MOVB #'.,COMAND(R1) ; Put ".*" on end of command string MOVB #'*,COMAND+1(R1) ; ADD #2,COML ; Include ".*" in string length MOV #DEVCM,DEVPTR ; First look at the "CM" device MOV #DIRSYS,DIRPTR ; And to systems directory CALL GUCB ; Get UCB address MOV U.UIC(R2),R3 ; Get his default UIC BIT #FE.MUP,$FMASK ; Multi-user protection? BEQ 10$ ; No, use default UIC then MOV U.LUIC(R2),R3 ; Yes, use login UIC 10$: MOV #DIRUSR,R2 ; Get ptr to place to put UIC MOV #1,R4 ; Don't zero suppress, do add seperators CALL .PPASC ; Convert UIC to ASCII CALL FIND ; Try to find a file ; ; If he is a privileged user try CM:[1,56] also ; CALL GUCB ; Get UCB address BIT #U2.PRV,U.CW2(R2) ; Is user privileged? BEQ 20$ ; No, skip [1,56] MOV #DIRPRV,DIRPTR ; Try [1,56] directory CALL FIND ; Last chance for priv user ; ; Try looking in SY:[grp,mem] for command ; 20$: MOV #DEVSY,DEVPTR ; Next look in users SY: device MOV #DIRUSR,DIRPTR ; And in users directory CALL FIND ; Last chance MOV #ERR2,R0 ; Command not found error BR ERROR ; Issue error message ; ; Try to find a command.* file to process command ; If it returns - no file found ; FIND: MOV #FDB,R0 ; Get address of FDB MOV #,R1 ; Address of file name block MOV #MC2T,R2 ; Dataset descriptor address CLR R3 ; No default filename block CALL .PARSE ; Parse file name BCS 20$ ; Error occured 10$: MOV #FDB,R0 ; Restore FDB address MOV #,R1 ; Restore FNB address CALL .FIND ; Look for a file BCC 30$ ; File found 20$: RETURN ; No file found, return ; ; Found something, check for valid extension ; 30$: MOV ,R2 ; Get file name extension MOV #EXTABL,R3 ; Get ptr to table of supported extensions 40$: CMP R2,(R3)+ ; Match? BNE 50$ ; No TST (R3) ; Make sure its not end of table BEQ 10$ ; End of table, skip this file TST (SP)+ ; Flush FINDs return address JMP @(R3)+ ; Match, dispatch to routine ; 50$: TST (R3)+ ; End of table? BNE 40$ ; No, check next entry BR 10$ ; Yes, skip this file ; .PAGE ; ; Get next character from MCR command line ; ; Character returned in R1 ; Carry set if end of current string ; GETC: MOVB @BPTR,R1 ; Get next byte INC BPTR ; Point at next character CMPB #SPA,R1 ; Space? BEQ 20$ ; Yes, set carry but advance pointer CMPB #ESC,R1 ; Escape character at end? BEQ 10$ ; Yes CMPB #CR,R1 ; CR at end? BNE 30$ ; No, return good character 10$: DEC BPTR ; Don't move past end of command line 20$: SEC ; Indicate end of current string RETURN ; Return to caller (char in R1) ; 30$: CLC ; Indicate good character received RETURN ; Return to caller (char in R1) ; ; Issue an error message to TI: and exit ; ; R0 = address of error message (zero terminated) ; ERROR: MOV R0,R1 ; Copy buffer address 10$: TSTB (R1)+ ; End of message? BNE 10$ ; No SUB R0,R1 ; Yes, figure length DEC R1 ; Don't count the zero in MOV R0,WERR+Q.IOPL ; Yes, set message address MOV R1,WERR+Q.IOPL+2 ; Set message length DIR$ #WERR ; Issue error message MOV $TKTCB,R0 ; Get our TCB address BIS #T3.MCR,T.ST3(R0) ; Make sure we prompt after message ; EXIT: EXIT$S ; and exit ; ; Get a MCR command buffer ; ; Returns R0 -> Place to put mcr command string in system state ; GMCRBF: MOV (SP)+,R5 ; Get return address MOV (R5)+,R1 ; Addr to return too after swstk$ CLR R0 ; Assume no error CALL $SWSTK,GMCREX ; Enter system state MOV #84.,R1 ; Buffer size to R1 CALL $ALOCB ; Get a buffer BCC 10$ ; Buffer available MOV #ERR4,2(SP) ; No pool space available error RETURN ; Return to users state with error ; 10$: CALL GUCB ; Get our UCB address MOV R2,2(R0) ; Set TI UCB address MOV R0,-(SP) ; Save buffer address MOV R0,ENDBF ; Create ptr to end of buffer ADD #84.,ENDBF ; CMP (R0)+,(R0)+ ; Point R0 at place for text CALL (R5) ; Call caller back MOV (SP)+,R1 ; Get buffer address back CALL $QMCRL ; Queue command to MCR MOV $TKTCB,R1 ; Get our TCB pointer again BIC #T3.MCR,T.ST3(R1) ; Inhibit MCR prompt RETURN ; Done ; GMCREX: TST R0 ; Any errors? BNE ERROR ; Yes, report error TST R1 ; Does he want us to return to him? BNE 10$ ; Yes, pass control to caller BR EXIT ; No, just exit ; 10$: JMP (R1) ; Return to caller ; ; Return: ; R1 -> TCB ; R2 -> UCB ; GUCB: MOV $TKTCB,R1 ; R1 -> our TCB MOV T.UCB(R1),R2 ; Get TI UCB address 20$: CMP U.RED(R2),R2 ; Redirected? BEQ 30$ ; No MOV U.RED(R2),R2 ; Yes, follow chain BR 20$ ; Check again 30$: RETURN ; Return to caller ; .PAGE ; ; Routines to support given file extensions ; ; Indirect command file found ; PCMD: CALL GMCRBF ; Get a buffer for a MCR command .WORD 0 ; Just exit when done MOVB #'@,(R0)+ ; Issue @ command for file CALL DEVDIR ; Output device name and directory CALL MVCMD ; Output command name MOV #CMD,R1 ; Output ".CMD" extension CALL MVSTR ; CALL MVRST ; Output rest of command string RETURN ; Return and queue command to MCR ; ; Task image found ; ; Create second half of task name in form CMDTxx ; PTSK: CALL GUCB ; Second half of task name is terminal ID MOV R2,R0 ; Put UCB address in R0 MOV U.DCB(R0),R2 ; Get DCB address MOVB D.NAM(R2),COMAND+3 ; 1st char is 1st char of terminal name SUB D.UCB(R2),R0 ; Compute relative UCB address MOV D.UCBL(R2),R1 ; Get UCB length CALL $DIV ; Compute relative unit number ADD D.UNIT(R2),R0 ; Compute absolute unit number MOV R0,R1 ; Copy it BIC #177700,R0 ; Mask off high bits ASR R0 ; Move over 3 bits ASR R0 ; ASR R0 ; BIC #177770,R1 ; Mask off high bits of lower digit ADD #'0,R1 ; Make it an ASCII number TST R0 ; Is high digit zero? BNE 6$ ; No MOVB R1,COMAND+4 ; Yes, supress leading zero MOVB #SPA,COMAND+5 ; BR 8$ ; ; 6$: ADD #'0,R0 ; Make it an ASCII number MOVB R0,COMAND+4 ; Set first octal digit of terminal number MOVB R1,COMAND+5 ; Set second octal digit ; 8$: MOV #COMAND,R0 ; Convert first 3 chars of command name CLR R1 ; Dont accept period CLR CMDR50+2 ; Init second half of task name to blanks CALL $CAT5 ; Convert name to RAD50 MOV R1,CMDR50 ; Set first half of task name BCS 9$ ; If end of name reached, use trailing blanks CLR R1 ; No periods allowed CALL $CAT5 ; Convert second 3 chars of command name MOV R1,CMDR50+2 ; Set second half of task name ; ; Get a buffer for an INS command ; 9$: CALL GMCRBF ; Get a buffer for a MCR command .WORD 30$ ; Where to return after queueing INS command MOV R0,-(SP) ; Save buffer address ; ; Use 3 chars of command name followed by terminal letter/number ; Bump letter if needed to find a task name not in use ; 10$: MOV #CMDR50,R3 ; Now see if our task name is in use CALL $SRSTD ; Does task name exist? BCS 20$ ; No, use this name then ; ; Desired task name in use - If REM=NO & Not Active & Not being fixed ; and we are ...MC2 use it, else pick other name. ; ; This is so we clean up INStalls that previous MC2s timeout on ; TST T.STAT(R0) ; Is task active? BPL 15$ ; Yes, skip over it BIT #T3.REM,T.ST3(R0) ; Is the task's REM bit on? BNE 15$ ; Yes, in act of being removed BIT #T2.BFX,T.ST2(R0) ; Is task being fixed? BNE 15$ ; Yes, can't use it MOV $TKTCB,R0 ; Get our TCB address CMP T.NAM(R0),#^R... ; Are we ...MC2? BNE 15$ ; No, skip it (...MC2 may be using it) TST (SP)+ ; Yes, we can use it - flush buffer addr RETURN ; And return now ; ; Pick another name by bumping the letter in the taskname ; 15$: INCB COMAND+3 ; Bump letter of terminal name MOV #COMAND+3,R0 ; Convert terminal name to RAD50 CLR R1 ; No periods CALL $CAT5 ; Convert it MOV R1,CMDR50+2 ; Set second half of name BR 10$ ; And try again ; ; Found a free task name, create INS command ; 20$: MOV (SP)+,R0 ; Restore buffer pointer MOV #INS,R1 ; Output "INS " CALL MVSTR ; CALL DEVDIR ; Output device and directory CALL MVCMD ; Output command name MOV #TASKE,R1 ; Output "/TASK=" CALL MVSTR ; MOV CMDR50,R1 ; Output task name CALL $C5TA ; MOV CMDR50+2,R1 ; CALL $C5TA ; MOVB #ESC,(R0)+ ; RETURN ; Return and queue command to MCR ; ; Wait for INS of task to occur ; 30$: DIR$ #MRKT ; Set to give up eventually BCS 60$ ; Woops couldn't set timer 40$: WSIG$S ; Wait for significant event CLR R0 ; R0 will indicate what to do CALL $SWSTK,50$ ; Enter system state MOV #CMDR50,R3 ; CALL $SRSTD ; Look for our task BCC 80$ ; Task found RETURN ; Return to user state ; ; Returned from system state, check for error ; 50$: TST R0 ; Keep waiting? BNE 70$ ; No CLEF$S #MKTEF ; Yes, see if our timeout EF went off CMP #IS.SET,$DSW ; Was it set? BNE 40$ ; No, wait some more 60$: MOV #ERR5,R0 ; Give up, report INS error 70$: CMP #1,R0 ; Just exit? BEQ 78$ ; Yes JMP ERROR ; No, issue error message ; 78$: JMP EXIT ; Exit ; ; Task installed, start it up ; 80$: TST T.STAT(R0) ; Is task active? BMI 100$ ; No, start it up 90$: MOV #ERR6,2(SP) ; Yes, opps issue error RETURN ; Return to user state ; ; Determine protection uic for task ; 100$: MOV R0,-(SP) ; Save TCB address CALL GUCB ; Get our UCB address MOV U.UIC(R2),R1 ; Set default UIC MOV R1,R3 ; Copy default UIC BIT #FE.MUP,$FMASK ; Multi-user protection? BEQ 110$ ; No BIT #U2.PRV,U.CW2(R2) ; Privileged user? BNE 110$ ; Yes, use R1 as protection UIC MOV U.LUIC(R2),R1 ; No, get protection UIC ; ; Start task executing ; 110$: CALL $TSKRP ; Start task with protection MOV (SP)+,R5 ; Restore TCB address BCS 90$ ; Woops, couldn't start it MOV #84.,R1 ; Get a MCR command buffer for command CALL $ALOCB ; Try for one BCC 120$ ; Got one MOV #ERR4,2(SP) ; No pool space error RETURN ; Return to user ; 120$: MOV R5,2(R0) ; Set TCB address BIS #T3.REM,T.ST3(R5) ; Set to remove task on completion MOV R0,-(SP) ; Save ptr to buffer MOV R0,ENDBF ; Create ptr to end of buffer ADD #84.,ENDBF ; CMP (R0)+,(R0)+ ; Point R0 at place for text MOV #BUF,BPTR ; Reset command buffer pointer CALL MVRST ; Copy rest of line to buffer CMPB #ESC,R1 ; Terminated by an ESC? BEQ 130$ ; Yes BIS #T3.MCR,T.ST3(R5) ; No, set to prompt on task exit 130$: MOV (SP)+,R0 ; Restore buffer pointer MOV $MCRCB,(R0) ; Add command line to GMCR list MOV R0,$MCRCB ; MOV #1,2(SP) ; Return a 1 in R0 to indicate success RETURN ; To user state and let command run! ; .PAGE ; ; Internal command routines ; ; ; DELETE file command ; CDELET: CALL GMCRBF ; Get MCR command buffer .WORD 0 ; Exit when done MOV #PIP,R1 ; Output "PIP" CALL MVSTR ; CALL MVRST ; Output rest of line MOV #SDE,R1 ; Add "/DE" on end CALLR ENDSTR ; Then queue command to MCR ; ; DIRECTORY command ; CDIREC: CALL GMCRBF ; Get MCR command buffer .WORD 0 ; Exit when done MOV #PIP,R1 ; Output "PIP" CALL MVSTR ; CALL MVRST ; Output rest of line MOV #SLI,R1 ; Add "/LI" on end CALLR ENDSTR ; Then queue command to MCR ; ; ERASE command ; CERASE: CALL GMCRBF ; Get MCR command buffer .WORD 0 ; Exit when done MOV #PIP,R1 ; Output "PIP" CALL MVSTR ; CALL FNAMES ; Process file names MOV #SDE,R1 ; Add "/DE" on end CALLR ENDSTR ; Then queue command to MCR ; ; FREE space command ; CFREE: CALL GMCRBF ; Get MCR command buffer .WORD 0 ; Exit when done MOV #PIP,R1 ; Output "PIP" CALL MVSTR ; CALL MVRST ; Output rest of line MOV #SFR,R1 ; Add "/FR" on end CALLR ENDSTR ; Queue MCR command ; ; PURGE files ; CPURGE: CALL GMCRBF ; Get MCR command buffer .WORD 0 ; Exit when done MOV #PIP,R1 ; Output "PIP" CALL MVSTR ; CALL MVRST ; Output rest of line MOV #SPU,R1 ; Add "/PU" on end CALLR ENDSTR ; Queue MCR command ; ; RENAME file command ; CRENAM: CALL GMCRBF ; Get MCR command buffer .WORD 0 ; Exit when done MOV #PIP,R1 ; Output "PIP" CALL MVSTR ; CALL MVRST ; Output rest of line MOV #SRE,R1 ; Add "/RE" on end CALLR ENDSTR ; Queue MCR command ; ; SPOOL file command ; CSPOOL: CALL GMCRBF ; Get MCR command buffer .WORD 0 ; Exit when done MOV #PIP,R1 ; Output "PIP" CALL MVSTR ; CALL MVRST ; Output rest of line MOV #SSP,R1 ; Add "/SP" on end CALLR ENDSTR ; Queue MCR command ; ; TYPE file to terminal command ; CTYPE: CALL GMCRBF ; Get MCR command buffer .WORD 0 ; Exit when done MOV #PIPTI,R1 ; Output "PIP" CALL MVSTR ; CALL MVRST ; Output rest of line RETURN ; Queue MCR command ; ; UIC set/display command ; CUIC: CALL GMCRBF ; Get MCR command buffer .WORD 0 ; Exit when done MOV #SETUIC,R1 ; Output "SET UIC" CALL MVSTR ; 10$: CALL GETCS ; Get a character BCS 50$ ; No UIC specified - display UIC then CALL TNUM ; Is it a number? BCC 10$ ; No MOVB #'=,(R0)+ ; Yes, output the "=[" MOVB #'[,(R0)+ ; MOVB R1,(R0)+ ; and the number CALL GETCS ; Get a character BCS 45$ ; End of line CALL TNUM ; Is it a number? BCC 20$ ; No, assume its the comma MOVB R1,(R0)+ ; Yes, output second digit CALL GETCS ; Get a character BCS 45$ ; End of line CALL TNUM ; Is it another number? BCC 20$ ; No, assume its the comma MOVB R1,(R0)+ ; Yes, output third digit 20$: MOVB #',,(R0)+ ; Add "," to output 30$: CALL GETCS ; Get a character BCS 45$ ; End of line CALL TNUM ; A number? BCC 30$ ; No, flush till we find one MOVB R1,(R0)+ ; Yes, output first digit 2nd half CALL GETCS ; Get a character BCS 45$ ; End of line CALL TNUM ; A number? BCC 40$ ; No MOVB R1,(R0)+ ; Yes, output second digit CALL GETCS ; Get a character BCS 45$ ; End of line CALL TNUM ; A number? BCC 40$ ; No MOVB R1,(R0)+ ; Yes output third digit 40$: CALL GETCS ; Now look for terminator BCC 40$ ; 45$: MOVB #'],(R0)+ ; Add trailing ']' 50$: MOVB R1,(R0)+ ; Add terminator on end RETURN ; Queue MCR command ; .PAGE ; ; Output subroutines ; ; ; Output device name and directory ; DEVDIR: MOV DEVPTR,R1 ; Device name is first MOVB (R1)+,(R0)+ ; d MOVB (R1)+,(R0)+ ; d MOVB (R1)+,(R0)+ ; n MOVB (R1)+,(R0)+ ; : MOV DIRPTR,R1 ; Directory is next MOVB (R1)+,(R0)+ ; [ MOVB (R1)+,(R0)+ ; g MOVB (R1)+,(R0)+ ; g MOVB (R1)+,(R0)+ ; g MOVB (R1)+,(R0)+ ; , MOVB (R1)+,(R0)+ ; m MOVB (R1)+,(R0)+ ; m MOVB (R1)+,(R0)+ ; m MOVB (R1)+,(R0)+ ; ] RETURN ; ; ; Output command name ; MVCMD: SUB #2,COML ; Don't include ".*" MOV #BUF,R1 ; In filename which is next 10$: MOVB (R1)+,(R0)+ ; Move a byte of command name DEC COML ; Subtract one from length BGT 10$ ; Still characters left, continue RETURN ; ; ; Output rest of command string ; MVRST: CALL MVCHR ; Move a character BCC MVRST ; For the rest of the command line RETURN ; ; ; Output a string ; R1 -> string to output (zero terminated) ; MVSTR: MOVB (R1)+,(R0)+ ; Move a byte BNE MVSTR ; Not end if not zero DEC R0 ; Do not include zero byte RETURN ; ; ; Move a character from input to output ; - Return carry set if end of string ; - Char moved retuned in R1 ; MVCHR: CALL GETC ; Get a character MOVB R1,(R0)+ ; Output the character BCC 10$ ; Not delimiter CMPB #SPA,R1 ; Was it just a space? BNE CSET ; No, real end of line 10$: CMP R0,ENDBF ; Reached end of buffer yet? BHIS CSET ; Yes, indicate end of line CCLR: CLC ; No, indicate not end of line RETURN ; ; ; GETC with no carry set on space ; GETCS: CALL GETC ; Get a character BCS 10$ ; Carry set RETURN ; ; 10$: CMPB #SPA,R1 ; Space? BEQ CCLR ; Yes CSET: SEC ; No, set carry and return RETURN ; ; ; Insert a string before last output character ; INSERT: CMPB #CR,@BPTR ; Is the character a CR? BEQ 10$ ; Yes, don't need to backup CMPB #ESC,@BPTR ; How about a ESC? BEQ 10$ ; Yes, don't backup DEC BPTR ; Backup one character on input 10$: DEC R0 ; Backup one character on output CALL MVSTR ; Output our string CALLR MVCHR ; Put back the character ; ; See if there is room for N characters ; ROOM2: MOV #-2,R1 ; Is there room for two characters? ROOMN: ADD ENDBF,R1 ; Set up pointer CMP R0,R1 ; What we need is a post-indirect indexing mode RETURN ; Return with CCs set ; ROOM3: MOV #-3,R1 ; Is there room for three characters? BR ROOMN ; Continue ; ; Process file names adding ;* where necessary ; FNAMES: CLR R2 ; R2 flag = 1 - ; seen, 2 - in directory 10$: CALL MVCHR ; Move a character BCS 30$ ; End of line reached CMPB #';,R1 ; Is it the semi-colon BNE 20$ ; No BIS #1,R2 ; Yes, remember it BR 10$ ; Continue ; 20$: BIT #2,R2 ; Are we in a directory name? BNE 22$ ; Yes, then comma doesn't end a filename CMPB #',,R1 ; Have we reached the end of a file name BNE 22$ ; No CALL 40$ ; Yes, add ";*" if necessary BR 10$ ; Continue ; 22$: CMPB #'[,R1 ; Are we entering a directory? BNE 24$ ; No BIS #2,R2 ; Yes, remember it BR 10$ ; Continue ; 24$: CMPB #'],R1 ; Leaving a directory? BNE 10$ ; No BIC #2,R2 ; Yes, remember it BR 10$ ; Continue ; 30$: CALLR 40$ ; Add ";*" if necessary and return to caller ; 40$: BIT #1,R2 ; Do we need to output a ";*" ? BEQ 60$ ; Yes BIC #1,R2 ; No, reset flag 50$: RETURN ; Return from 40$ call ; 60$: CALL ROOM2 ; Is there room for two more chars? BHIS 50$ ; No, just return MOV #SDA,R1 ; Yes, insert ";*" before character CALLR INSERT ; And return from call ; ; Add a 3 character string to the end of a line ; ENDSTR: MOV R1,-(SP) ; Save string pointer CALL ROOM3 ; Is there room for three characters? BHIS 10$ ; No, just stick string at end then MOV (SP)+,R1 ; Yes, restore string pointer CALLR INSERT ; Insert string before terminator ; 10$: MOV (SP)+,R1 ; Restore string pointer MOV ENDBF,R0 ; Setup pointer SUB #3,R0 ; To stick 3 chars on end CALLR MVSTR ; Move the string to end of line ; ; Test to see if a character is a octal number ; ; Carry set if it is ; TNUM: CMPB R1,#'0 ; Check lower bound BLO CCLR ; Not a number CMPB R1,#'7 ; Check upper bound BHI CCLR ; Not a number BR CSET ; Number - set carry ; .END MC2 ; End of dispatcher code