OBJNAM XFORCE.LIT ; extended replacement for FORCE.LIT command
VMAJOR=2 ; Created 12-Dec-84, last modified 19-Feb-86
VMINOR=2 ; By Irv Bromberg, Medic/OS Consultants
VEDIT=13. ; 78 Wildginger Way, Toronto, CANADA M3H 5X1
; Phone (416) 586-4499
IF EQ,1
Extensions implemented --
(1) -- delete vestigial error: AND @TCB,D3 prior to TRMICP
(2) -- allow control codes to be forced using ^ as leadin
(3) -- reduce waiting time if job locked in J.TOW state
(4) -- if job locked in J.TOW state then flush output for duration of force
(5) -- if flushing output queue wait for job to reach sleep or external wait
or terminal input wait state before restoring original terminal driver.
(6) -- don't force trailing spaces/tabs (even if followed by comment symbol)
(7) -- pause after each control code so TDV will not think multi-char sequence
WARNING -- If output could be immediately inhibited do not use KILL command
prior to FORCE as it will not finish -- use FLUSH command instead.
Application note: When forcing control codes consider what T.STS mode the
target job's terminal is in, else the forced control codes may be ignored or
may not have their desired effect. Often it is necessary to put forced control
codes on the next line after a monitor-level command, for example:
XFORCE JOB2
VUE FILNAM ; no control codes on this line -- T.STS is NIL, would be lost
^[^J^J^Z^[F^M ; this line is not forced until JOB2 reaches J.TIW state and
; by that time T.STS is DAT!ECS!XLT so control codes work.
Char=D1
JName=D3
Count=D3
Flags=D5
; 0 set for single-line force
; 1 set on error - job guarded or not attached and user is running CMD file
; 2 set if force is to self
; 3 set if output queue flushed through FLUSH.TDV
HT=9.
CR=13.
SPACE=32.
PHDR -1,0,PH$REE!PH$REU
SUBW #6,SP ; get some workspace
FILNAM @SP,XXX ; get job name
MOV @SP,JName
ADDW #6,SP
MOV JOBTBL,A3
CLR Flags
JOBIDX
CMP JName,JOBNAM(A6)
BNE NxtJob
BSET #2,Flags ; set = forcing to self
NxtJob: MOV (A3)+,D7
BEQ NxtJob ; skip unallocated jobs
CMP D7,#-1 ; end of job table?
BNE Srch
TYPECR <?Nonexistent job>
CALL ChkCMZ
BR Process
Srch: MOV D7,JCB
CMP JName,JOBNAM(JCB)
BNE NxtJob
MOV JOBTRM(JCB),TCB ; get TCB
MOV TCB,D7 ; test if attached
BNE Process
TYPECR <?No terminal attached to job>
CALL ChkCMZ
Process:BTST #2,Flags
BNE ModeChk
MOVW JOBTYP(JCB),D7
ANDW #J.GRD,D7
BEQ ModeChk
JOBIDX
CMPW JOBUSR(A6),#^H0102 ; OPR: can force to guarded job
BEQ ModeChk
TYPECR <?Guarded>
CALL ChkCMZ
ModeChk:BYP ; check if single or multi-line
LIN
BEQ NxtCmd
BSET #0,Flags ; set = single-line command
BTST #1,Flags
JNE Done
BR Force
NxtCmd: KBD Done ; get next command to force
BYP
CMPB @Buffer,#'; ; skip if comment
BEQ NxtCmd
LIN ; empty line?
BNE Force ; no, force it
Done: MOVB #CR,Char
TTY
BTST #3,Flags ; was output flushed through FLUSH.TDV?
BEQ Quit ; no, exit
; wait for job to reach SLP or EXW or TIW state before restoring TDV
; maximum wait = 10 seconds (50 x 200 ms)
MOVW #50-1,Count ; -1 for DBF loop
Loop: SLEEP #2000.
CTRLC More ; not done but do it anyway if ^C hit
MOVW JOBSTS(JCB),D7 ; test for SLP or EXW or TIW state
ANDW #<J.MSG!J.SLP!J.EXW!J.TIW>,D7
DBNE Count,Loop
BNE DoIt
More: TYPECR <?Output flush incomplete>
DoIt: POP T.TDV(TCB) ; then restore original terminal driver
Quit: EXIT
Force: BTST #1,Flags ; error from command file?
BNE NxtCmd ; yes, discard until empty line
BTST #2,Flags ; forcing to self?
JNE Move ; yes, know it's OK to do it
MOV #10.,Count ; try 0.5 x 10 = 5 seconds
ChkECC: TST T.ECC(TCB) ; don't force more until echo done
BNE Wait ; wait for echo to finish
MOVW #J.TIW,D7 ; wait until job is waiting for
ANDW JOBSTS(JCB),D7 ; terminal input
JNE Move ; yes, TIW state, go do TRMICP
Wait: CTRLC Done
SLEEP #5000. ; wait 1/2 sec and try again
SUB #1,Count
BNE ChkECC
MOVW #J.TOW,D7 ; check for TOW state lockup
ANDW JOBSTS(JCB),D7
BNE DoFlush ; yes, output locked, flush it
TST T.ECC(TCB) ; check for echo lockup
BNE DoFlush ; yes, echo locked, flush output
Busy: TYPECR <?Job busy>
CALL ChkCMZ
JMP Force
DoFlush:TYPECR <%Output inhibited -- flushing output queue>
BSET #3,Flags ; remember we did it
PUSH T.TDV(TCB) ; save terminal driver
LEA Atemp,FLUSH ; index FLUSH.TDV
MOV Atemp,T.TDV(TCB) ; switch to FLUSH.TDV
CLR T.ECC(TCB) ; discard echo count
JRUN J.TOW ; make locked job run & flush output
JMP Force ; go back to do output flush
NxtChr: ADD #1,Buffer
Move: MOVB @Buffer,Char
CMPB Char,#HT ; don't force trailing spaces/tabs
BEQ ChkTrl
CMPB Char,#SPACE
BEQ ChkTrl
CMPB Char,#'^ ; check for CTRL-code leadin
BNE ChkCmt
INC Buffer ; skip to next character
MOVB @Buffer,Char ; get char to be CTRL'ed
UCS ; normalize
CMPB Char,#'@ ; must be within range @ to _
BLO ChkCmt ; else pass through unchanged
CMPB Char,#'_
BHI ChkCmt
SUBB #'@,Char ; convert to control-code
BR Inp
ChkTrl: ; space/tab found, check if it is a trailing character, discard if so
MOV Buffer,SavPos ; save position in buffer
BYP ; bypass blanks/tabs
LIN ; end of line?
BEQ EndCmd ; yes, leave buffer pointing to end
MOV SavPos,Buffer ; restore position in buffer
BR Inp ; and force the legitimate space/tab
ChkCmt: CMPB Char,#'; ; don't force comments
BNE Inp
EndCmd: MOVB #CR,Char ; terminate command with CR
Inp: CMPB Char,#SPACE ; If char is a control-code then
BHIS Normal ; pause long enough so that TDV will
TRMICP ; not think it is a lead-in to a multi-
SLEEP #600. ; character sequence.
BR ChkLIN
Normal: TRMICP ; force input character
ChkLIN: LIN ; command line finished?
BNE NxtChr ; no, go back to move more
BTST #0,Flags ; was it a single-line command?
JEQ NxtCmd ; no, go back for more
JMP Done
ChkCMZ: JOBIDX User ; if command file in progress must
TSTW JOBCMZ(User) ; discard lines until empty line
BNE 10$
POP ; discard RTN address
JMP Done
10$: BSET #1,Flags ; signal error in command file
RTN
; FLUSH.TDV is like PSEUDO.TDV but has NULL output bit set in terminal
; attributes word:
WORD [FLU],[SH ] ; FLUSH driver name
FLUSH: WORD ^O300 ; null output, local echo
RTN ; No Input routine.
RTN ; No OUTPUT routine.
BR Echo ; ECHO routine.
RTN ; No CRT routine.
Echo: CLR T.ECC(TCB) ; cancel any echo characters
RTN