	.TITLE	LCU
	.SBTTL	Specification and resources
	.IDENT	/100001/
	.ENABLE	MCL
	.NLIST	BEX
;
; List Common Users
;
; Utility to find users of a common area
;
; Written by J.P.Simoons, december 1986
;	HCS Industrial Automation B.V.
;	Apeldoorn (Holland)
;
; Syntax:
; LCU<Carriage return>        - list all tasks having 1 or more commons
;			        with all the common names.
; LCU xxxxxx<Carriage return> - List all tasks which use common xxxxxx
;
; Remarks:
; Task uses vectored Exec, to be transportable.
; RSXMC.MAC is included for CALL macro for CALL $SWSTK
;
; Modified:	26-feb-88	Ident --> 100001			;PS026
;		Prevent odd address trap on odd addresses from PCB pointers
;
	.INCLUDE /LB:[200,200]RSXMC.MAC/
	.TITLE	LCU
	.LIBRARY /LB:[1,1]EXEMC.MLB/
	PCBDF$			; Define partition control block offsets
	TCBDF$			; Define task control block offsets
	.PAGE
	.SBTTL	Initialyse vector table and get commandline
	.PCODE
START:
	QIOW$S	#IO.ATT,#1,#1		; Attach terminal
	DIR$	#TRNVEC			; Initialyse exec vector table
	BCC	20$			; O.K.
10$:
	JMP	VECERR			; Report error and exit
20$:
	TST	EXEVEC			; Vector table o.k.?
	BEQ	10$			; No
	DIR$	#GCMD			; Get command line
	TST	$DSW			; valid input?
	BMI	110$			; No, list complete
	CMP	$DSW,#5			; At least "LRU x"?
	BLO	110$			; No
;
; Find common name and convert into Rad 50
;
	MOV	$DSW,R0			; Get #input chrs
	MOV	#GCMD+G.MCRB,R1		; Point to MCR buffer
30$:
	CMPB	(R1)+,#40		; A space?
	BEQ	40$			; Yes, found terminator to common
	SOB	R0,30$
	BR	110$			; Not found
40$:
	MOV	R1,COMPNT		; Save pointer to ascii name
	DEC	R0			; Adjust counter for space
	CMP	R0,#6			; Complete name left?
	BHIS	60$			; Yes
	MOV	R1,R2			; Copy pointer to name
	ADD	R0,R2			; Point after input
	SUB	#6,R0			; Calculate
	NEG	R0			; ... #spaces to add
50$:
	MOVB	#' ,(R2)+		; Add a space
	SOB	R0,50$
60$:
	MOV	R1,R0			; Copy input pointer
	MOV	#1,R1			; Dot is valid R50 chr
	CALL	$CAT5B			; Convert common name into R50
	BCS	130$
	MOV	R1,REFR50		; Save
	MOV	#1,R1
	CALL	$CAT5B
	BCS	130$
	MOV	R1,REFR50+2
;
; Check if common known to system
;
	CLR	REFPCB			; Common not found yet
	CALL	$SWSTK,100$		; Switch to system state
	MOV	CBDHD,R0		;; Common block directory header
	MOV	(R0),R0			;; Get address of first common PCB
	BEQ	90$			;; None there
70$:
	BIC	#1,R0			;; Don't use odd addresses	;PS026
	CMP	P.NAM(R0),REFR50	;; Check first half common name
	BNE	80$			;; No match
	CMP	P.NAM+2(R0),REFR50+2	;; Check second half
	BNE	80$			;; No match
	MOV	R0,REFPCB		;; Save address of common PCB
	BR	90$			;; Ready
80$:
	MOV	P.CBDL(R0),R0		;; Try next common PCB (if any)
	BNE	70$
90$:
	RETURN				;; From system syate
100$:
	TST	REFPCB			; Found common?
	BEQ	140$			; No
	BR	120$			; Go look for tasks
110$:
	JMP	LITKCO			; List all tasks which have commons
120$:
	JMP	LITK			; List tasks for a specified common
130$:
	DIR$	#R50LOG			; Print error message
	BR	EXIT
140$:
	MOV	COMPNT,R0		; Address of start of ascii common
	MOV	#NOCASC,R1		; Destination
	MOV	#6,R2
150$:
	MOVB	(R0)+,(R1)+
	SOB	R2,150$
	DIR$	#NOCLOG			; Print error message
EXIT:
	EXIT$S				; Ready
	.PAGE
	.SBTTL	List all tasks with their commons
;
; List all tasks with their commons
;
LITKCO:
;
; Scan task list in primary pool.
; keep: task name, no of commons, common names but only if 1 or more commons
;
10$:
	CALL	$SWSTK,60$		; Switch to system state
	MOV	TSKHD,R0		;; Pointer to system task directory
	MOV	#BUF,R1
	CLR	R2			;; No tasks found yet
	MOV	(R0),R0			;; Point to first TCB
	BEQ	50$			;; None there
20$:
	BIC	#1,R0			;; Don't use odd addresses	;PS026
	CMP	R1,#EOBUF-68.		;; Still space in buffer for taskname
					;; ... # commons, 15 common names?
	BHI	50$			;; No
	TST	T.NAM(R0)		;; Ckeck name for end of list
	BEQ	50$			;; Null task, end of list
	MOV	T.PCBV(R0),R3		;; Get pointer to common PCB vector
	BEQ	40$			;; None there
	MOVB	(R3)+,R4		;; Get #commons
	BEQ	40$			;; None there
	CMP	R4,#15.			;; More than 15. commons?
	BHI	50$			;; Exit, we might have lost track
	INC	R3			;; Skip high byte #commons
	MOV	T.NAM(R0),(R1)+		;; Save name
	MOV	T.NAM+2(R0),(R1)+	;; ...
	INC	R2			;; Count task
	MOV	R4,(R1)+		;; Save #commons
30$:
	MOV	(R3)+,R5		;; Get address of common PCB
	BIC	#1,R5			;; Don't use odd addresses	;PS026
	MOV	P.NAM(R5),(R1)+		;; Save common name
	MOV	P.NAM+2(R5),(R1)+	;; ...
	SOB	R4,30$
	BR	40$
40$:
	MOV	T.TCBL(R0),R0		;; Point to next task if any
	BNE	20$			;; EQ = none left
50$:
	MOV	R2,COUNT		;; Save #found tasks
	RETURN				;; From system state
60$:
	CALL	PRIBUF			; Print tasks with commons
;
; Scan prototype task list in secondary pool
; keep: task name, no of commons, common names but only if 1 or more commons
;
	CALL	$SWSTK,110$		; Switch to system state
	MOV	@APR6,-(SP)		;; Save KISAR6 mapping
	MOV	PTCBL,R0		;; Pointer to prototype task list
	MOV	#BUF,R1
	CLR	R2			;; No tasks found yet
	MOV	(R0),R0			;; Point to first TCB
	BEQ	100$			;; None there
;
; Map TCB in secondary pool
;
70$:
	MOV	R0,@APR6		;; Map into sec. pool
	MOV	#140000,R0		;; Let R0 point to TCB
	CMP	R1,#EOBUF-68.		;; Still space in buffer for taskname
					;; ... # commons, 15 common names?
	BHI	100$			;; No
	TST	T.NAM(R0)		;; End of list?
	BEQ	100$			;; Null task, end of list
	MOV	T.PCBV(R0),R3		;; Get pointer to common PCB vector
	BEQ	90$			;; None there
	MOVB	(R3)+,R4		;; Get #commons
	BEQ	90$			;; None there
	CMP	R4,#15.			;; More than 15 commons?
	BHI	80$			;; Ignore, we might have lost track
	INC	R3			;; Skip high byte #commons
	MOV	T.NAM(R0),(R1)+		;; Save name
	MOV	T.NAM+2(R0),(R1)+	;; ...
	INC	R2			;; Count task
	MOV	R4,(R1)+		;; Save #commons
80$:
	MOV	(R3)+,R5		;; Get address of common PCB
	BIC	#1,R5			;; Don't use odd addresses	;PS026
	MOV	P.NAM(R5),(R1)+		;; Save common name
	MOV	P.NAM+2(R5),(R1)+	;; ...
	SOB	R4,80$
90$:
	MOV	T.TCBL(R0),R0		;; Point to next task if any
	BNE	70$			;; EQ = none left
100$:
	MOV	R2,COUNT		;; Save #found tasks
	MOV	(SP)+,@APR6		;; Restore KISAR6 mapping
	RETURN				;; From system state
110$:
	CALL	PRIBUF			; Print tasks with commons
;
	JMP	EXIT	
;
; Subroutine to print tasks with commons
;
PRIBUF:
	MOV	COUNT,R2		; Recouver #found tasks
	MOV	R2,R5			; Copy count of found tasks
	BEQ	30$			; None, ready
	MOV	#BUF,R4			; Point to first entry
10$:
	MOV	#TSKNAM,R0		; Destination ascii
	MOV	(R4)+,R1		; Get task name first half
	CALL	$C5TA			; Convert to ascii
	MOV	(R4)+,R1		; Get second half name
	CALL	$C5TA			; Convert to ascii
	MOVB	(R4),R1			; Get no of commons
;
; Add common names to list
;	
	MOV	#COMS,R0		; Ascii destination
	MOV	R5,-(SP)		; Save task name loop counter
	MOV	(R4)+,R5		; Get common name loop counter
20$:
	MOVB	#' ,(R0)+		; Insert leading spaces
	MOVB	#' ,(R0)+		; Insert leading spaces
	MOV	(R4)+,R1		; Get common name first half
	CALL	$C5TA			; Convert to ascii
	MOV	(R4)+,R1		; Get second half name
	CALL	$C5TA			; Convert to ascii
	SOB	R5,20$			; Next common
	MOV	(SP)+,R5		; Restore task name loop counter
;
; Print task name with commons
;
	SUB	#MES1,R0		; Calculate size of message
	QIOW$S	#IO.WVB,#1,#1,,,,<#MES1,R0,#40>
	SOB	R5,10$
30$:
	RETURN
	.PAGE
	.SBTTL	List all tasks which use a particular common
;
; List all tasks which use a particular common
;
LITK:
	MOV	COMPNT,R0
	MOV	#REFASC,R1
	MOV	#6,R2
10$:
	MOVB	(R0)+,(R1)+
	SOB	R2,10$
	DIR$	#COMLOG
;
; Scan task list in primary pool and search for tasks using specified common
;
	CALL	$SWSTK,70$		; Switch to system state
	MOV	TSKHD,R0		;; Pointer to system task directory
	MOV	#BUF,R1
	CLR	R2			;; No tasks found yet
	MOV	(R0),R0			;; Point to first TCB
	BEQ	60$			;; None there
20$:
	BIC	#1,R0			;; Don't use odd addresses	;PS026
	CMP	R1,#EOBUF-4		;; Still space in buffer for taskname
	BHI	60$			;; No
	TST	T.NAM(R0)		;; Ckeck name for end of list
	BEQ	60$			;; Null task, end of list
	MOV	T.PCBV(R0),R3		;; Get pointer to common PCB vector
	BEQ	50$			;; None there
	MOVB	(R3)+,R4		;; Get #commons
	BEQ	50$			;; None there
	CMP	R4,#15.			;; More than 15. commons?
	BHI	60$			;; Exit, we might have lost track
	INC	R3			;; Skip high byte #commons
30$:
;;	CMP	(R3)+,REFPCB		;; Right PCB?			;PS026
	MOV	(R3)+,R5		;; Get PCB address from vector	;PS026
	BIC	#1,R5			;; Be shure not an odd address	;PS026
	CMP	R5,REFPCB		;; Right PCB?			;PS026
	BNE	40$			;; ...
	MOV	T.NAM(R0),(R1)+		;; Save task name using common
	MOV	T.NAM+2(R0),(R1)+	;; ...
	INC	R2			;; Count task
	BR	50$			;; Next task
40$:
	SOB	R4,30$			;; Try next common of this task
50$:
	MOV	T.TCBL(R0),R0		;; Point to next task if any
	BNE	20$			;; EQ = none left
60$:
	MOV	R2,COUNT		;; Save #found tasks
	RETURN				;; From system state
70$:
	CALL	PRBUF2			; Print tasks with commons
;
; Scan prototype task list in secondary pool
; keep: task name, no of commons, common names but only if 1 or more commons
;
	CALL	$SWSTK,130$		; Switch to system state
	MOV	@APR6,-(SP)		;; Save KISAR6 mapping
	MOV	PTCBL,R0		;; Pointer to prototype task list
	MOV	#BUF,R1
	CLR	R2			;; No tasks found yet
	MOV	(R0),R0			;; Point to first TCB
	BEQ	120$			;; None there
;
; Map TCB in secondary pool
;
80$:
	MOV	R0,@APR6		;; Map into sec. pool
	MOV	#140000,R0		;; Let R0 point to TCB
	CMP	R1,#EOBUF-4.		;; Still space in buffer for taskname
	BHI	120$			;; No
	TST	T.NAM(R0)		;; End of list?
	BEQ	120$			;; Null task, end of list
	MOV	T.PCBV(R0),R3		;; Get pointer to common PCB vector
	BEQ	110$			;; None there
	MOVB	(R3)+,R4		;; Get #commons
	BEQ	110$			;; None there
	CMP	R4,#15.			;; More than 15 commons?
	BHI	120$			;; Ignore, we might have lost track
	INC	R3			;; Skip high byte #commons
90$:
;;	CMP	(R3)+,REFPCB		;; Right PCB?			;PS026
	MOV	(R3)+,R5		;; Get PCB address from vector	;PS026
	BIC	#1,R5			;; Be shure not an odd address	;PS026
	CMP	R5,REFPCB		;; Right PCB?			;PS026
	BNE	100$			;; ...
	MOV	T.NAM(R0),(R1)+		;; Save name
	MOV	T.NAM+2(R0),(R1)+	;; ...
	INC	R2			;; Count task
	BR	110$			;; Next task
100$:
	SOB	R4,90$			;; Try next common of this task
110$:
	MOV	T.TCBL(R0),R0		;; Point to next task if any
	BNE	80$			;; EQ = none left
120$:
	MOV	R2,COUNT		;; Save #found tasks
	MOV	(SP)+,@APR6		;; Restore KISAR6 mapping
	RETURN				;; From system state
130$:
	CALL	PRBUF2			; Print tasks with commons
;
	JMP	EXIT	
;
; Subroutine to print tasks
;
PRBUF2:
	MOV	COUNT,R5		; Recover #found tasks
	BEQ	20$			; None, ready
	MOV	#BUF,R4			; Point to first entry
10$:
	MOV	#TKNAM,R0		; Destination ascii
	MOV	(R4)+,R1		; Get task name first half
	CALL	$C5TA			; Convert to ascii
	MOV	(R4)+,R1		; Get second half name
	CALL	$C5TA			; Convert to ascii
;
; Print task name with commons
;
	DIR$	#PRITSK
	SOB	R5,10$
20$:
	RETURN
	.PAGE
	.SBTTL	Error handling
;
; The vector table could not be initialysed
;
VECERR:	CALL	DSWERR
	DIR$	#VECLOG
	DIR$	#DSWLOG
	JMP	EXIT
;
; Convert an errorcode in $DSW into a printable number in DSWASC
;
DSWERR:	MOV	#DSWASC,R0			; Point to ascii field
	MOV	#6,R1				; 6 characters to initialyse
10$:
	MOVB	#' ,(R0)+			; Initialyse a byte
	SOB	R1,10$				; ... until all done
	MOV	#DSWASC,R0			; Point to ascii field
	MOV	$DSW,R1				; Get error code
	CLR	R2				; Specify zero suppression
	CALL	$CBDSG				; Do conversion
	RETURN
;
	.PAGE
	.SBTTL	Fixed data
	.PDATA
TRNVEC:	GIN$	GI.VEC,EXEVEC,EXEVCL
VECLOG:	QIOW$	IO.WVB,1,1,,,,<VECMES,VECMSL,40>
DSWLOG:	QIOW$	IO.WVB,1,1,,,,<DSWMES,DSWMSL,40>
COMLOG:	QIOW$	IO.WVB,1,1,,,,<COMMES,COMMSL,40>
R50LOG:	QIOW$	IO.WVB,1,1,,,,<R50MES,R50MSL,40>
NOCLOG:	QIOW$	IO.WVB,1,1,,,,<NOCMES,NOCMSL,40>
PRITSK:	QIOW$	IO.WVB,1,1,,,,<TKMES,TKMESL,40>
VECMES:	.ASCII	/LCU -- initialisation error./
	.BYTE	CR,LF
	.ASCII	/       Vector table could not be initialised./
VECMSL	=: . - VECMES
R50MES:	.ASCII	/LCU -- Illegal characters in input string./
R50MSL	=: . - R50MES
	.EVEN				; Allways end PSECTS even
	.PAGE
	.SBTTL	R/W data
	.IDATA
;
; Executive vector table
;
EXEVEC:
	.WORD	0			; Initialyse check word
CBDHD:	.WORD	$CBDHD			; Common block directory list header
TSKHD:	.WORD	$TSKHD			; Task list header
PTCBL:	.WORD	$PTCBL			; Prototype task control block header
APR6:	.WORD	KISAR6			; Data APR6 mapping register
EXEVCL	=: <<. - EXEVEC> / 2 >
;
; Command line
;
GCMD:	GMCR$
;
; Messages with a variable part
;
; Directive error : xxxxx
;
DSWMES:	.ASCII	/Directive error :/
DSWASC:	.BLKB	6
DSWMSL	=: . - DSWMES
;
; Common "xxxxxx" is in use by:
;
COMMES:	.ASCII	/Common "/
REFASC:	.BLKB	6			; Ascii name of common to search for
	.ASCII	/" is in use by:/
COMMSL	=: . - COMMES
;
; LCU -- Common "xxxxxx" not in system
;
NOCMES:	.ASCII	/LCU -- Common "/
NOCASC:	.BLKB	6
	.ASCII	/" not in system/
NOCMSL	=: . - NOCMES
;
TKMES:	.ASCII	/"/
TKNAM:
	.BLKB	6
	.ASCII	/"/
TKMESL	=: . - TKMES
;
; Task "xxxxxx" uses:  yyyyyy  yyyyyy  yyyyyy  yyyyyy
;
MES1:	.ASCII	/Task "/
TSKNAM:	.BLKB	6
	.ASCII	/" uses:/
COMS:	.BLKB	8.*15.
	.EVEN
;
; Variables
;
REFR50:	.BLKW	2			; Rad50 name of common to search for
REFPCB:	.BLKW	1			; Address of PCB of common to search
COUNT:	.BLKW	1			; Number of tasks  found
COMPNT:	.BLKW	1			; Pointer to ASCII common in MCR buf
BUF:	.BLKW	1000.
EOBUF:
;
	.EVEN				; Allways end PSECTS even
	.END	START
