;-*-Midas-*-

	Title :ARGUS - The Dog (ticktick) of One Hundred Eyes

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;	Format:
;;;
;;;	:ARGUS <uname1>,<uname2>, . . . ,<unameN>
;;;
;;;	Output:
;;;
;;;	[Here is FOOMAN]		or, if two logins,
;;;	[Here are FOO and AHEM] 	or, for polylogins,
;;;	[Here are JOE, ED and LOUISE]
;;;
;;;	For departures: Change "Here are/is" to "There go/goes"
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

A=1	;General porpoise
B=2
C=3
D=4
T=5	;Temp
TT=6
T3=7
Q=10	;Counter for various loops
J=11	;Pointer to JCL
NA=12
U=13	;Accumulated username in GetJCL
BP=14
TL=15
P=17	;Pointer to basic you-know-what PDL

PDLen==20			;Length of PDL
MaxUsr==100.			;Max # users allowed to look for
JCLen==<MaxUsr*7>/5+10		;This had BETTER be enough.  Right, Devon?

TTYo==1
CLIo==2		;CLI chnl to be used to send you messages
USRi==3		;For checking if an Argus job already exists
CLAi==4		;For receiving updates/hoodunnit list
USRc==5		;To tell when the creating diety goes away.

DEFINE SYSCAL OP,ARGS
	.CALL [SETZ ? SIXBIT /OP/ ? ARGS ((SETZ))]
	TERMIN

Define EVAL *string*,ac=0
	Move A,[Squoze 0,string]
	.Eval A,
	  .Lose %LsSys
IFN ac,	Add A,[(ac)]
	Movem A,string
Termin

DEFINE OUTCHR LOCS
IRP FOO,,[LOCS]
	Movei T,FOO
	Idpb T,BP
	Addi TL,1
TERMIN TERMIN

Define OUTSTR &string
	Move T,[440700,,[Asciz string]]
	Pushj P,SavStr
Termin

PDLIST:	-PDLEN,,.	;The usual.  Make room for PDL
	BLOCK PDLEN

Tsint:	Loc 42
	-TsintL,,Tsint
Loc Tsint
	P
	%PiCLI ? 0 ? %PiCLI ? 0 ? GotCLI
	0 ? 1_USRc ? 0 ? 0 ? Die
TsintL==.-Tsint

JCLBUF:	BLOCK JCLEN	;Again, the usual stuff.  Room for JCL
	-1

UUNAME:	0		;Your uname/jname will go here
UJNAME:	0

YUNAME:	0		;Who sent us an update request
YJNAME:	0

HooTo:	0
FUNAME:	0

Argusp:	0		;Are we the real & original Argus?
nUsers:	0		;Number of current users (last value of SUSRS)
UAOBJN:	0		;Static AOBJN-pointer to SEARCH list
TAOBJN:	0		;Likewise, but for TTYSTS table
EOJCL:	0		;Flag for while reading JCL.  Found end?
nMods:	0		;Number of modifications specified in JCL line
nTarge:	0		;# of targets

SEARCH:	BLOCK MAXUSR	;List of unames supplied from JCL
OSEEN:	BLOCK MAXUSR	;Initially +/- flags for original unames
NSEEN:	Block MaxUsr

LUBLK:	0			;Values of monitor symbols.
NCT:	0
TTYSTS:	0
MAXJ:	0
XUNAME:	0
JNAME:	0
SUSRS:	0

BEGIN:	MOVE P,PDLIST
	.Suset [-5,,[.rUNAME,,UUNAME
		     .rJNAME,,UJNAME
		     .sOPTION,,[(OptInt)]	;New-style interrupts
		     .sMASK,,[%PiCLI]	;Allow trapping of CLI interrupts
		     .sMSK2,,[1_USRc]]]
	.BREAK 12,[..RJCL,,JCLBUF]	;Load JCL into JCLBUF
	Setzb Q,EOJCL
	Setzm nMods
	MOVE J,[440700,,JCLBUF]

MAKEC:	MOVE C,[440600,,U]		;Where username accumulates.
	SETZ U,

GETJCL:	ILDB A,J	;Get a char from JCL into A
	JUMPE A,EOL	;A null is final terminator
	CAIL A,"a	;Is this a lowercase character?
	  Trz A,40	;  Yup, so make it caps
	CAIE A,^C	;This a ^C?
	  CAIN A,^M	;What about ^M?  Both are semi-final delimiters.
	    JRST EOL	;  Yup!
	Caie A,40	;Space or
	  CAIN A,",	;  comma delimits
	    JRST STORE	;    a username.
	CAIGE A,40	;Is this some other random control char?
	  ADDI A,100	;  Sho nuf.  Normalify it.
	Tlnn C,770000	;Already written 6 characters for this one?
	  Jrst GetJCL	;  Yes, so don't store it.
	Jumpn U,6ate	;If not the first character of uname, just store it.
	Cain A,"+	;1st character a + (add to list)?
	  Jrst [Aos OSeen(Q)
		Aos nMods
		Jrst GetJCL]
	Cain A,"-	;Or a - (delete from list)?
	  Jrst [Setom OSeen(Q)
		Aos nMods
		Jrst GetJCL]
	Cain A,"*
	  Jrst [Setom HooTo
		Aos nMods
		Jrst GetJCL]
6ate:	SUBI A,40	;Yep.  Change to 6bit,
	IDPB A,C	;poke it into the appropriate place in SEARCH,
	JRST GETJCL	;and keep reading chars

EOL:	Setom EOJCL
STORE:	JUMPE U,Nextp	;If no letters in uname, keep reading (,,)
	Skipe HooTo
	  Jrst [Movem U,FUNAME
		Jrst Nextp]
	AOS Q		;Add 1 to # unames fully read
	CAIL Q,MAXUSR	;This less than the last allowed?
	  .Value [Asciz ": Too many usernames! KILL "]
	Movem U,Search-1(Q)
Nextp:	Setzm HooTo
	Skipn EOJCL		;End of the line?
	  JRST MAKEC		;  Naw, so keep grinding away
	Movem Q,nTarget		;# of targets
	Movss Q			;#users,,0
	Movnm Q,UAOBJN		;Static AOBJN pointer 

Change:	Skipe FUNAME
	  Jrst Chang0
	Move T,UJNAME
	Camn T,[Sixbit "ARGUS"]
	  Jrst Newp
	Setzm Argusp
	Move T,UUNAME
	Movem T,FUNAME
Chang0:	Syscal OPEN,[%Clbit,,.uii\10
		     %Climm,,USRi
		     [Sixbit "USR"]
		     FUNAME
		     [Sixbit "ARGUS"]]
	  .Value [Asciz ": Can't modify what don't exist - No Argus! KILL "]
	.Close USRi,		;Just wanted to make sure it was there.
	Syscal OPEN,[%Clbit,,.uio
		     %Climm,,CLIo
		     [Sixbit "CLI"]
		     FUNAME
		     [Sixbit "ARGUS"]]
	  .Lose %LsFil
	Skipn T,UAOBJN
	  Jrst Modif1
Modify:	Skipn OSeen(T)		;Want to modify this one?
	  Jrst Modif0		;  Naw, not specified with + or -
	.IOT CLIo,OSeen(T)	;Send type-of-modification flag word
	.IOT CLIo,Search(T)	;and then the username to be changed.
Modif0:	Aobjn T,Modify
Modif1:	.IOT CLIo,[Sixbit "*DONE*"]
	.Close CLIo,
	Movei T,30.*60.
	.Sleep T,
	.Value [Asciz ": No answer from Argus in one minute! KILL "]
	Jrst Die		;Just to be sure.

Newp:	Skipn UAOBJN
	  .VALUE [ASCIZ /: Do :ARGUS <uname1>,<uname2>,...,<unameN> KILL /]
	Setom Argusp
	Eval "LUBLK"
	Eval "NCT"
	Eval "TTYSTS"
	Movs T,NCT
	Movns T
	Hrr T,TTYSTS
	Movem T,TAOBJN
	Eval "MAXJ"
	Eval "XUNAME",TT
	Eval "SUSRS"
	Hrrz T,XUNAME
	Lsh T,-10.		;Get starting system page#
	Move TT,MAXJ
	IMul TT,LUBLK
	Add TT,XUNAME
	Tlz TT,-1		;Flush the ac field from XUNAME
	Lsh TT,-10.		;Ending page#
	Subi TT,-1(T)		;# pages in range
	Movss TT		;#pages,,0
	Movns TT		;-#pages,,0
	Hrr TT,T		;-#pages,,parallel page#
	Syscal CORBLK,[%Climm,,%CBNDR
		       %Climm,,%JSELF
		       %Clin,,TT
		       %Climm,,400000]
	  .Lose %LsSys
	Move T,SUSRS
	Lsh T,-10.
	Syscal CORBLK,[%Climm,,%CBNDR
		       %Climm,,%JSELF
		       %Clin,,T
		       %Climm,,400000]
	  .Lose %LsSys
	Move T,TTYSTS
	Lsh T,-10.
	Hrli T,-2		;Get 2 pages in case table wraps.
	Move TT,T
	Syscal CORBLK,[%Climm,,%CBNDR
		       %Climm,,%JSELF
		       %Clin,,T
		       %Climm,,400000]
	  .Lose %LsSys
	Syscal OPEN,[%Clbit,,.uii
		     %Climm,,USRc
		     [Sixbit "USR"]
		     UUNAME
		     [Sixbit "HACTRN"]]
	  .Lose %LsSys
	.VALUE [ASCIZ /:VKî/]	;:PROCEED - :DISOWN
	Setzm OSeen
	Move T,[OSeen,,OSeen+1]
	Move TT,nTarget
	BLT T,OSeen-1(TT)	;Make sure this is cleared to begin with
	Jrst Set

Wait:	Move T,nUsers		;Wait until the # of users changes
	Camn T,@SUSRS
	  .HANG
Set:	Move T,@SUSRS
	Movem T,nUsers

GETLST:	Setzm NSeen
	Move T,[NSeen,,NSeen+1]
	Move TT,nTarget
	BLT T,NSeen-1(TT)

	Move T,TAOBJN
GetL0:	Hrre TT,(T)		;Get TTYSTS word
	Jumpl TT,GetL2		;If <0, nothing on this TTY
	Move A,@XUNAME		;Indexed through TT
	Move B,UAOBJN
GetL1:	Camn A,Search(B)
	  Aosa NSeen(B)		;Bump found-count
	    Aobjn B,GetL1
GetL2:	Aobjn T,GetL0

SENDP:	Move BP,[440700,,Buffer]
	Setzb C,TL
	OUTCHR [177]
	Move T,UAOBJN
Arrivp:	Skipe TT,NSeen(T)	;Someone here now?
	  Camg TT,OSeen(T)	;  That wasn't here before?
	    Jrst Arriv0		;    Whatever, ignore this one.
	Push P,T		;Save index
	Addi C,1		;Bump arrival count
Arriv0:	Aobjn T,Arrivp		;Loop over all users.
	Jumpe C,Deparp		;No new arrivals.
	CAIG C,1		;Only one arrival?
	  JRST [OUTSTR "[Here is "	;Singular,
		Pop P,A		;then print one-&-only uname.
		PUSHJ P,6TYPEc
		JRST ENDLNA]	;Finally, do the close bracket.
	OUTSTR "[Here are "
SAYIT:	Pop P,A			;Pop the uname off and put index in ac A
	PUSHJ P,6TYPEc		;Print it.
	Soje C,EndLNA		;If no more, tie off line.
	CAIG C,1		;If one more,
	  JRST [OutStr " and "	;  say "and", else
		Jrst Sayit]
	OUTSTR ", "		;say "," to separate unames.
	JRST SAYIT

ENDLNA:	OutStr "]
"

Deparp:	Move T,UAOBJN
	Setz C,
Depar0:	Move TT,NSeen(T)
	Caml TT,OSeen(T)
	  Jrst Depar1
	Push P,T
	Addi C,1
Depar1:	Aobjn T,Depar0
	Jumpe C,Yawner
	CAIG C,1
	  JRST [OutStr "[There goes "
		Pop P,A
		Pushj P,6Typeg
		Jrst ENDLNB]
	OUTSTR "[There go "

SENDIT:	POP P,A		;Get a departure uname into ac A
	PUSHJ P,6TYPEg	;Print it,
	SOJE C,ENDLNB	;Number-left in C
	CAIG C,1	;As before. Greater than 1, do ","
	  JRST [OutStr " and "
		Jrst SendIt]
	OUTSTR ", "
	JRST SENDIT

ENDLNB:	OutStr "]
"

YAWNER:	Caig TL,1		;Any message accumulated?
	  Jrst Wait		;  Nah, so nothing happened.
	SYSCAL OPEN,[%CLBIT,,.UAO
		     %CLIMM,,CLIo	;Open your CLI so we can report
		     [SIXBIT /CLI/]	;what has heppened.
		     UUNAME
		     [SIXBIT /HACTRN/]]
	  Jrst Wait
	Move A,[440700,,Buffer]
	Syscal SIOT,[%Climm,,CLIo
		     %Clin,,A
		     %Clin,,TL]
	  Jfcl
	.CLOSE CLIo,	;Would be fatal to leave this open
	Move T,[NSeen,,OSeen]
	Move TT,nTarget
	BLT T,OSeen-1(TT)
	Jrst Wait

GotCLI:	Syscal OPEN,[%Clbit,,.uii	;Get our end of the pipe open.
		     %Climm,,CLAi
		     [Sixbit "CLA"]]
	  .Lose %LsFil
	.Iot CLAi,YUNAME
	.Iot CLAi,YJNAME
	Skipe Argusp
	  Jrst DoMods
	Syscal OPEN,[%Clbit,,.uao
		     %Climm,,TTYo
		     [Sixbit "TTY"]]
	  .Lose %LsFil
	Setz A,
ShoHoo:	.IOT CLAi,T
	Camn T,[Sixbit "*DONE*"]
	  Jrst Die
	Aos A			;This is the (A)th to go on this line.
	Caile A,8.
	  Jrst [.Iot TTYo,[^M]
		Movei A,1
		Jrst .+1]
	Pushj P,T6Type
	.Iot TTYo,[^I]
	Jrst ShoHoo

DoMods:	Hlre B,UAOBJN
	Movns B			;Current # targets.
	Move NA,UAOBJN
DoMod0:	.Iot CLAi,T		;Get flag word
	Camn T,[Sixbit "*DONE*"]
	  Jrst Report		;No more reports, report our status.
	.IOT CLAi,TT		;Get uname.
	Move A,NA
DoMod1:	Camn TT,Search(A)
	  Jrst Found
	Aobjn A,DoMod1
	Jumpl T,DoMod0		;Can't get rid of what ain't here.
	Cail B,MaxUsr		;Can handle another?
	  Jrst DoMod0		;  Nope, ignore it.
	Movem TT,Search(B)	;Save the new uname.
	Setzm OSeen(B)		;Say we've never seen them.
	Sub NA,[1,,0]
	Soja B,DoMod1		;and go for more.

Found:	Jumpg T,DoMod0		;Adding someone who's already here?
IRP table,,[Search,OSeen,NSeen]	;Nope, so remove them.
	Movsi C,table+1(A)	;Move down all the arrays.
	Hrri C,table(A)
	Movei D,table-1(B)
	BLT C,(D)
Termin
	Add NA,[1,,0]
	Aoja B,DoMod0		;and keep on truckin.

Report:	Movem NA,UAOBJN
	Hlre T,NA
	Movnm T,nTarget
	.Close CLAi,
	Syscal OPEN,[%Clbit,,.uio
		     %Climm,,CLIo
		     [Sixbit "CLI"]
		     YUNAME
		     YJNAME]
	  Jrst Repor1		;Oh well.
	Jumpe NA,[.Iot CLIo,[Sixbit "!! BYE"]
		  .Iot CLIo,[Sixbit "NOW !!"]
		  Jrst Repor0]
	Move B,UAOBJN
	.Iot CLIo,Search(B)
	Aobjn B,.-1
Repor0:	.Iot CLIo,[Sixbit "*DONE*"]
	.Close CLIo,
	Jumpe NA,Die
Repor1:	Syscal DISMIS,[P ? %Climm,,GetLst]
	  .Lose
	.Lose

T6Type:	Setz TT,
	Rotc T,6
	Addi TT,40
	.Iot TTYo,TT
	Jumpn T,T6Type
	Popj P,

DIE:	.LOGOUT 1,	;Suicide noisily

SavStr:	Ildb T3,T
	Jumpe T3,CPopj
	Idpb T3,BP
	Aoja TL,SavStr

6typeg:	move b,oseen(a)
	sub b,nseen(a)
	caie b,1
	  jrst 6types
	move b,oseen(a)
	caig b,1
	  jrst 6tc0
	ldb b,[360600,,search(a)]
	caie b,'a
	  cain b,'e
	    jrst 6tg0
	caie b,'i
	  cain b,'o
	    jrst 6tg0
	caie b,'u
	  skipa t,[440700,,[asciz "a "]]
6tg0:	    move t,[440700,,[asciz "an "]]
	pushj p,savstr
	jrst 6tc0

6types:	outstr "poly"
	jrst 6tc0

6typec:	move b,nseen(a)
	sub b,oseen(a)
	caie b,1
	  jrst 6types
	move b,nseen(a)
	caile b,1
	  jrst [outstr "another "
		jrst .+1]
6tc0:	move a,search(a)	;get the uname
;fall into
6TYPE:	SETZ B,			;6TYPE contents of ac A.  Zero B in preparation
	ROTC A,6		;Rotate a char from A into B
	ADDI B,40		;Make it full ASCII
	Idpb B,BP
	Addi TL,1
	Jumpn A,6Type
CPopj:	POPJ P,			;Return

Buffer:	Block 2*MaxUsr

	END BEGIN
