	Program Big_Brother
c
c Author:             Mark R. Vevle
c                     X-Ray Crystallographic Core Facility
c                     University of Alabama at Birmingham
c                     244 BHS, THT 79
c                     University Station
c                     Birmingham, Alabama  35294
c                     (205) 934 - 1973/2657
c
c Description:        Big_Brother - A dynamic,  user  information,  display
c                     program.
c
c                     This  program  is  terminal  independent, but can use
c                     special keys on the VT100 and VT200 series terminals.
c                     Keys   can   be   redefined/added  by   modifing  the
c                     Process_Input routine.
c
c Function:           o To  provide  detailed  information  about  users on
c                       the system.
c
c Disclaimer/rights:  This   software  is  in  the  public  domain  and  is
c                     provided  free  though  DECUS or other channels.  The
c                     information  in  this  software  is subject to change
c                     without  notice  and  should  not  be  construed as a
c                     commitment  by the author or his employer. The author
c                     and  his  employer  assumes no responsibility for the
c                     use,  the  correctness,  or  the  reliability of this
c                     software. THIS SOFTWARE IS PROVIDED AS IS.
c
c Environment:        VAX/VMS V4.0 or later
c
c Privledges Needed:  ALTPRI, CMKRNL, and WORLD
c
c                     ALTPRI - so  it  can  boost  it's  own  priority (not
c                              required).
c                     CMKRNL - to get the idle times from the UCB's.
c                     WORLD  - so it can do GETJPI's on all processes.
c
c                     Note: CMKRNL is required. If this program is run
c                           without CMKRNL privledge it will bomb out.
c
c Modification History (VMS V4):
c
c                     Note: Modifications  made to RMDemo under VAX/VMS V3
c                           can be found at the end of this file.
c
c                     V4.0  - Major modifications  made to correct problems
c                             caused by VAX/VMS V4. Some (not all) changes
c                             are listed below.
c
c                           - Move all common  blocks to seperate files and
c                             INCLUDEd them into the program.
c
c                           - Use the  NULL  process to  determine  correct
c                             amount of idle time and  total amount of idle
c                             time since the  system was booted.  I  assume
c                             the  first  two  processes  returned  by  the
c                             GETJPI utility are 1) NULL and 2) SWAPPER.
c
c                           - Schedule  wakeups BEFORE assignning a channel
c                             to get input.  A bug was  found when HELP was
c                             requested  before wakeups were scheduled (the
c                             program would not return from hibernation.)
c
c                           - MRV.  May 15, 1985
c
c                   V4.1.1  - Correct  display  for   processes   that  are
c                             swapped  out or  suspended.  Display only the
c                             information   that   is  available  for  that
c                             process. Treat processes that are in MWAIT as
c                             if they were swapped out.
c
c                           - MRV. May 20, 1985
c
c                   V4.1.2  - Replace  the  LIB$ screeen routines  with the
c                             SMG$ routines. Change to a 132 column display
c                             and add some more information.
c
c                           - *** Clean up code ***
c
c                           - MRV. June 25, 1985
c
c                   V4.2.1  - When a  process is  swapped  out and back in,
c                             part of  the "-- Swapped --" was left between
c                             the columns. Cleaned this up under  VMS V4.2. 
c
c                           - MRV. September 5, 1985
c
c                   V4.2.2  - Got the HELP screen operational using the SMG
c                             routines and  the ALERT  message is displayed
c                             when an unknown command is entered.
c
c                           - MRV. January 30, 1986
c
c                   V4.3.3  - Add the ability to select processes from the
c                             display and interactively delete them.  This
c                             feature uses the FIND and DO keys (VT2xx) or
c                             the ^F and ^D keys (on other terminals.)
c
c                           - MRV. March 31, 1986
c
c                   V4.3.4  - Remove  the  "Vol"  column  and  add to the
c                             display  the  average  percent of CPU  used
c                             ("Avg_%"). Also  made changes  so  that CPU
c                             time is calculated only for processes being
c                             displayed currently.
c                                 Clean up logic...
c                                 Remove unneeded and redundent code...
c                                 Speed up to lessen overhead...
c                             Wish DEC would  do something  with the SMG$
c                             routines, they are CPU pigs...
c
c                           - MRV. June 17, 1986
c
c                   V4.4.1  - Fix problems introduced by VMS V4.4 update.
c                             The  timer  routine   returns  delta  times
c                             rather than elapsed times  (delta times are
c                             negitive).  Took absolute value to maintain
c                             downward compatability.  The  SMG$  routine
c                             would  not initilize with an outstanding IO
c                             request,  so  moved  the SMG$ initilization
c                             routine before the first QIO is issued.
c
c                           - MRV. June 22, 1986
c
c                           - My special thanks to
c
c                             J. Michael Finn
c                             University of Illinois at Urbana-Champaign
c                             Champaign, IL
c                                     
c                             for pointing out these problems to  me last
c                             month  which  made these  fixes  quick  and
c                             painless.
c
c                   V4.4.2  - Display the  batch queue  name as is rather
c                             than  changing it to lower case.  Trying to
c                             lessen the CPU demand.
c
c                             Modify the CPU time calculations so that if
c                             more than 24 hours of CPU are used, the CPU
c                             time is displayed as DDD HH:MM  rather than
c                             HHH:MM:SS (avoiding overflows).
c
c                             Change calls to the intrinsic function NINT
c			      to "+ .5". Trying to lessen the CPU demand.
c                             Didn't help much if at all.
c
c                           - MRV. July 29, 1986
c


	Include 'UsrTbl.For'
	Data User_Table / 384* 0 /
c
	Include 'Hiber.For'
c
	Include 'Disply.For'
	Data Screen / 128* ' ' /
c
	Include 'JpiStr.For'
	Include 'JpiVal.For'
	Include 'JpiLen.For'
	Include 'JpiPrm.For'
c
	Include 'SyiVal.For'
	Include 'SyiPrm.For'
c
	Include 'CurPri.For'
c
	Include 'Flags.For'
	Data Page_Number / 1 /
	Data Page_Index  / 1 /
c
	Include 'InQio.For'
	Data Input_Flag / 3 /
c
	Integer*4	Ctrl_Status
c
c *** Boost my priority
c
	Call Init_Boost
c
c *** Setup all of SMG$ stuff
c
	Call SMG$_Setup
c
c *** Set up QIO for input.
c
	Call Setup_Qio
c
c *** Schedual wakeups in 3 second intervals to begin with.
c
	Sleeping = .False.
	Sleep_Time = 3
	Call Modify_Sleep
c
c *** Setup the GETJPI request (a onetime call)
c
	Call Setup_Getjpi
c
c *** Get System information (a one time call)
c
	Call Get_System_Info
c
c *** Go into the display loop
c
	User_Flag = .True.
c
	Call Display_Loop
c
c *** All Finished
c
	Call Modify_Priority_By( -( My_Current_Priority - My_Base_Priority ) )
c
	Ctrl_Status = Lib$Enable_Ctrl( '02100000'X )
	If ( .not. Ctrl_Status ) Then
	    Call Exit ( Ctrl_Status )
	End If
c
	End



	Subroutine Init_Boost
c
	Include '($JPIDEF)'
	Include 'CurPri.For'
c
	Call Lib$GetJpi	(	Jpi$_Prib		! item-code
	1		,				! process-id
	1		,				! process-name
	1		,	My_Base_Priority	! out-value
	1		,				! out-string
	1		,				! out-len
	1		)
c
	My_Current_Priority = Max( (My_Base_Priority + 2), 6)
c
	Call Sys$SetPri( 	,
	1			,	%Val( My_Current_Priority )
	1			,
	1			)
c
	Return
	End



	Subroutine SMG$_Setup
c
	Include '($SMGDef)'
	Include	'Pstbrd.For'
c
c *** Create a pasteboard
c
	Call SMG$Create_Pasteboard ( Pasteboard_ID )
c
c *** Change to wide screen
c
	Call SMG$Change_PBD_Characteristics ( Pasteboard_Id, 132 )
c
c *** Create the needed Virtual Displays
c
	Call SMG$Create_Virtual_Display (  20, 132, User_Display )
	Call SMG$Create_Virtual_Display (  18, 130, Help_Display )
	Call SMG$Create_Virtual_Display (   4, 132, System_Display )
	Call SMG$Create_Virtual_Display (   8,  45, Author_Display )
	Call SMG$Create_Virtual_Display (   2, 130, Killer_Display )
c
c *** Fill the Help Display now so we only need to paste and unpaste it.
c
	Call Make_Help
c
c *** Fill the Author Display now so we only need to paste and unpaste it.
c
	Call Make_Author
c
c *** Get the control mode for the update
c
	Call SMG$Control_Mode ( Pasteboard_Id, , Mode )
c
c *** Set the mode to: Use buffering, Minimal updates, clear screen when
c *** the pasteboard is deleted, and do not use tab stops when doing the
c *** minimal updates.
c
	Mode = IBSet ( Mode, SMG$M_Buf_Enabled )
	Mode = IBSet ( Mode, SMG$M_MinUpd )
	Mode = IBSet ( Mode, SMG$M_Clear_Screen )
	Mode = IBSet ( Mode, SMG$M_NoTabs )
c
c *** Put mode changes into effect
c
	Call SMG$Control_Mode ( Pasteboard_Id, Mode )
c
c *** Move to the lower left corner of the pasteboard (screen)
c
	Call SMG$Set_Physical_Cursor ( Pasteboard_Id, 24, 1 )
c
c *** That's a wrap for this routine
c
	Return
	End



	Subroutine Setup_Qio
c
	Include '($IODef)'
	Include 'InQio.For'
c
	Integer*4	Sys$Assign
	Integer*4	Ctrly_Code,	Ctrlc_Code
c
c *** Declare the AST routine
c
	External	BigBro_Ctrl_Exit
c
c *** Get a channel to the terminal
c
	IAssign_Stat = Sys$Assign( 'TT', TT_Channel, , )
	If ( .Not. IAssign_Stat ) Then
	    Call Exit ( IAssign_Stat )
	End If
c
c *** Setup the QIO function codes
c
	input_code = jior( IO$_Readlblk, jior( IO$M_NoEcho,
	1				 jior( IO$M_Cvtlow,
	1				 jior( IO$M_Escape,
	1				 jior( IO$M_TrmNoEcho,
	1				       IO$M_NoFiltr ) ) ) ) )
	ctrly_code = jior( IO$_SetMode, IO$M_CtrlyAst )
	ctrlc_code = jior( IO$_SetMode, IO$M_CtrlcAst )
c
c *** Specify Ast routines for Control_Y and Control_C
c
	Call Sys$Qio( , %val( tt_channel ), %val( ctrly_code ),
	1		    , , , BigBro_ctrl_exit, , , , , )
	Call Sys$Qio( , %val( tt_channel ), %val( ctrlc_code ),
	1		    , , , BigBro_ctrl_exit, , , , , )
c
c *** Issue first (async) read 
c
	Call Get_Input
c
	Return
	End



	Subroutine BigBro_Ctrl_Exit
c
	Include 'CurPri.For'
	Include 'Pstbrd.For'
c
	Integer*4	Lib$Enable_Ctrl,	Ctrl_Status
c
c *** Restore Cursor
c
	Call SMG$Delete_PasteBoard ( Pasteboard_Id, 1 )
	Call Modify_Priority_By( -( My_Current_Priority - My_Base_Priority ) )
c
	Ctrl_Status = Lib$Enable_Ctrl( '02100000'X )
	If ( .Not. Ctrl_Status ) Then
	    Call Exit ( Ctrl_Status )
	End If
c
	Call Exit
c
	End



	Subroutine Get_Input
c
	Include 'InQio.For'
c
c *** Declare AST routine to handle input
c
	External	Process_Input
c
	Call Sys$Qio( %val( input_flag ), %val( tt_channel ),
	1		    %val( input_code ), input_iosb,
	1		    process_input, , input_buffer,
	1		    %val( 20 ), , , , )
c
	Return
	End



	Subroutine Process_Input
c
	Include '($SMGDef)'
	Include 'Flags.For'
	Include 'Hiber.For'
	Include	'Pstbrd.For'
c
	Integer*4	input_code,	input_flag
	Integer*2	tt_channel,	Input_Iosb( 4 )
	Logical*1	input_buffer( 20 )
c
	Common /InQio/	input_code,	input_flag,	input_iosb,
	1		tt_channel,	input_buffer
c
	Character*20	Command_Line
	Character*1	Esc / 27 /
c
	Integer*2	Terminator
c
	Equivalence(	Command_Line,	Input_Buffer	)
c
	Terminator = Input_Iosb( 3 )
c
	If ( Exit_Flag ) Return
c
	If ( ( Terminator .eq. 5 ) .or. ( Terminator .eq. 26 ) ) then
	    Exit_Flag = .True.
	    Sleep_Time = 1
	    Sleeping = .False.
	    Call Modify_Sleep
	    Return
	Else If ( terminator .eq. 1 ) then
	    Display_all_flag = .not. display_all_flag
	Else If ( ( ( terminator .eq. 21 ) .and. 
	1	    ( process_flag ) ) .or.
	1	  ( terminator .eq. 16 ) ) then
	    process_flag = .not. process_flag
	Else If ( ( terminator .eq. 21 ) .or.
	1	  ( index( command_line, esc // '[4~' ) .ne. 0 ) ) then
	    user_flag = .not. user_flag
	    process_flag = .false.
	Else If ( terminator .eq. 23 ) then
	    Redraw_Flag = .True.
	Else If ( ( terminator .eq. 31 ) .or.
	1	( index( command_line, esc // 'OQ' ) .ne. 0 ) .or.
	1	( index( command_line, esc // '[28~' ) .ne. 0 ) ) then
	    If (.not. Help_Flag) Then
		Help_Flag = .True.
		Unknown_Flag = .False.
		Call SMG$Begin_Pasteboard_Update ( Pasteboard_Id )
		Call SMG$Paste_Virtual_Display (	Help_Display,
	1						Pasteboard_ID, 6, 2 )
		Call SMG$Paste_Virtual_Display (	Author_Display,
	1						Pasteboard_ID, 16, 87 )
		Call SMG$Set_Physical_Cursor ( Pasteboard_Id, 24, 1 )
		Call SMG$End_Pasteboard_Update ( Pasteboard_Id )
	    End If
	Else If ( index( command_line, esc // '[A' ) .ne. 0 ) then
	    Call modify_priority_by( 1 )
	Else If ( index( command_line, esc // '[B' ) .ne. 0 ) then
	    Call modify_priority_by( -1 )
	Else If ( index( command_line, esc // '[C' ) .ne. 0 ) then
	    sleep_time = sleep_time + 1
	    Call Modify_Sleep
	Else If ( index( command_line, esc // '[D' ) .ne. 0 ) then
	    sleep_time = sleep_time - 1
	    Call Modify_Sleep
	Else If ( index( command_line, esc // '[2~' ) .ne. 0 ) then
	    display_all_flag = .true.
	Else If ( index( command_line, esc // '[3~' ) .ne. 0 ) then
	    display_all_flag = .false.
	Else If ( ( terminator .eq. 14 ) .or.
	1	  ( index( command_line, esc // '[6~' ) .ne. 0 ) ) then
	    If ( page_number .lt. 7 ) then
		page_number = page_number + 1
		page_index = 19 * ( page_number - 1 ) + 1
	    Else
		page_number = 1
		page_index = 1
	    End If
	Else If ( ( terminator .eq. 2 ) .or.
	1	  ( index( command_line, esc // '[5~' ) .ne. 0 ) ) then
	    If ( page_number .gt. 1 ) then
		page_number = page_number - 1
		page_index = 19 * ( page_number - 1 ) + 1
	    Else
		page_number = 7
		page_index = 115
	    End If
	Else If ( ( command_line( 1: 1) .eq. 'e' ) .or.
	1	  ( command_line( 1: 1) .eq. 'E' ) ) Then
	    Exit_Flag = .True.
	    Sleep_Time = 1
	    Sleeping = .False.
	    Call Modify_Sleep
	Else If ( ( terminator .eq. 6 ) .or.
	1	  ( index( command_line, esc // '[1~' ) .ne. 0 ) ) then
	    Call Mark_User
	Else If ( ( terminator .eq. 4 ) .or.
	1	  ( index( command_line, esc // '[29~' ) .ne. 0 ) ) then
	    If ( Mark_Flag .ne. 0 ) Call Wastem
	Else
	    Call Alert
	End If
c
	Call Get_Input
c
	Return
	End



	Subroutine Mark_User
c
	Include '($SMGDef)'
	Include	'Hiber.For'
	Include 'Flags.For'
	Include 'Pstbrd.For'
c
	Character*132	Mark_Line,	Old_line
c
	Integer		Row
c
	Old_Line = ' '
	Mark_line = ' '
	Row = Mark_Flag
c
c *** Turn off bolding if needed
c
	If ( Row .gt. 0 )
	1	Call SMG$Read_From_Display ( User_Display, Old_Line, , Row )
c
c *** Select next user
c
	Mark_Flag = Mark_Flag + 1
	Row = Mark_Flag
c
	Call SMG$Read_From_Display ( User_Display, Mark_Line, , Row )
c
	Call SMG$Begin_Pasteboard_Update ( Pasteboard_Id )
c
	If ( Old_Line ( : 1 ) .ne. ' ' )
	1    Call SMG$Put_Chars ( User_Display, Old_Line, Row-1, 1)
c
	If ( Mark_Line( : 1 ) .ne. ' ' ) Then
	    Call SMG$Put_Chars ( User_Display, Mark_Line, Row, 1, ,
	1			 SMG$M_Bold )
	Else
	    Mark_Flag = 0
	End If
c
	Call SMG$Set_Physical_Cursor ( Pasteboard_Id, 24, 1 )
	Call SMG$Paste_Virtual_Display ( User_Display,
	1			     Pasteboard_ID, 5, 1 )
	Call SMG$End_Pasteboard_Update ( Pasteboard_Id )
c
	Return
	End



	Subroutine Wastem
c
	Include '($JpiDef)'
	Include '($SMGDef)'
	Include 'Pstbrd.For'
	Include 'InQio.For'
	Include 'UsrTbl.For'
	Include 'Flags.For'
c
	Integer		G_List( 12 )
	Integer*2	S_List( 2, 12 )
	Equivalence (	G_List,	S_List	)
c
	Integer		Sys$DelPrc
	Integer		K_PID,		Status,		Sys$GetJpiW
	Integer		P_Length,	U_Length,	T_Length
c
	Character*15	P_Name
	Character*15	T_Name
	Character*12	U_Name
c
c *** Process Name
	S_List( 1, 1 )	= 15
	S_List( 2, 1 )	= Jpi$_PrcNam
	G_List( 2 )	= %Loc( P_Name )
	G_List( 3 )	= %Loc( P_Length )
c *** Terminal
	S_List( 1, 4 )	= 15
	S_List( 2, 4 )	= Jpi$_Terminal
	G_List( 5 )	= %Loc( T_Name)
	G_List( 6 )	= %Loc( T_Length )
c *** User name
	S_List( 1, 7 )	= 12
	S_List( 2, 7 )	= Jpi$_UserName
	G_List( 8 )	= %Loc( U_Name )
	G_List( 9 )	= %Loc( U_Length )
c *** Terminate
	G_List ( 10 )	= 0
	G_List ( 11 )	= 0
	G_List ( 12 )	= 0
c
c *** Extract the process ident
c
	K_PID = User_Index( Mark_Flag + Page_Index - 1 )
c
c *** Get info on the process to be sure we will kill the correct one
c
	Status = Sys$GetJpiW( , K_PID, , G_List, , , )
c
	If ( Status ) Then
	    Call SMG$Erase_Display ( Killer_Display )
	    Call SMG$Begin_Pasteboard_Update ( Pasteboard_Id )
	    Call SMG$Label_Border (	Killer_Display,
	1				' Delete Process ',
	1				, , SMG$M_Bold, SMG$M_Reverse )
	    Call SMG$Put_Chars ( Killer_Display,
	1			 'Process: ' // P_Name //
	1			 '	Username: ' // U_Name //
	1			 ' Terminal: ' // T_Name, 1, 1)
	    Call SMG$Put_Chars ( Killer_Display,
	1			 'Really delete this process [Y/N D:N]? ',
	1			 2, 1, , SMG$M_Bold )
c
	    Call SMG$Set_Physical_Cursor ( Pasteboard_Id, 23, 40 )
c
	    Call SMG$Paste_Virtual_Display ( Killer_Display,
	1				     Pasteboard_ID, 22, 2 )
c
	    Call SMG$End_Pasteboard_Update ( Pasteboard_Id )
c
	    Call Sys$QioW( %Val( Input_Flag ), %Val( TT_Channel ),
	1		   %Val( Input_Code ), Input_Iosb,
	1		   , , Input_Buffer, %Val( 1 ), , , , )
c
	    Call SMG$Begin_Pasteboard_Update ( Pasteboard_Id )
c
	    If ( ( Input_Buffer( 1 ) .eq. 'Y' ) .or.
	1	 ( Input_Buffer( 1 ) .eq. 'y' ) ) Then
		Call SMG$Erase_Display ( Killer_Display )
		Call SMG$Put_Chars (	Killer_Display,
	1				' Terminating Process ' //
	1				P_Name // ' . . . ', 1, 1, ,
	1				SMG$M_Bold .or. SMG$M_Blink )
	1				
c
		Call SMG$Set_Physical_Cursor ( Pasteboard_Id, 24, 1 )
		Call SMG$Paste_Virtual_Display ( Killer_Display,
	1					 Pasteboard_ID, 22, 2 )
c
		Call SMG$End_Pasteboard_Update ( Pasteboard_Id )
c
		Status = Sys$DelPrc ( K_PID, )
c
		Call SMG$Begin_Pasteboard_Update ( Pasteboard_Id )
c
		If ( Status ) Then
c
		    Call Smg$Put_Chars ( Killer_Display, ' Process ' //
	1				 P_Name( : P_Length ) //
	1				 ' has been deleted. ', 2, 1, ,
	1				 SMG$M_Bold .or. SMG$M_Reverse )
		Else
		    Call Smg$Put_Chars ( Killer_Display, ' Process ' //
	1				 P_Name( : P_Length ) //
	1				 ' has NOT been deleted' //
	1				 ' due to errors. ', 2, 1, ,
	1				 SMG$M_Bold .or. SMG$M_Reverse )
		End If
c
		Call SMG$End_Pasteboard_Update ( Pasteboard_Id )
c
		Mark_Flag = 0
		RemK_Flag = .True.
c
	    Else
		Call SMG$UnPaste_Virtual_Display (	Killer_Display,
	1						Pasteboard_ID )
		Call SMG$Set_Physical_Cursor ( Pasteboard_Id, 24, 1 )
		Call SMG$End_Pasteboard_Update ( Pasteboard_Id )
	    End If
c
	End If
c
	Return
	End



	Subroutine Modify_Sleep
c
	Include '($SMGDef)'
	Include 'Hiber.For'
	Include 'Flags.For'
	Include 'Pstbrd.For'
c
	Integer*4	binary_time( 2 ),	Sys$BinTim,	Sys$SchdWk
	Integer*4	bin_stat,	wakeup_stat,	Sys$CanWak
c
	Character*16	delta_time
	Character*2	sleep
c
10	format('0000 00:00:',i2,'.00')
20	format( i2 )
c
c	*** Set up continous wakeups in delta_time intervals
c
	If ( sleep_time .gt. 59 ) then
	    sleep_time = 1
	Else If ( sleep_time .lt. 1 ) then
	    sleep_time = 59
	End If
c
	Write ( delta_time, 10, IoStat=Ios ) Sleep_Time
c	
	Call Sys$CanWak( , )
	Call Sys$BinTim( Delta_Time, Binary_Time )
	Call Sys$SchdWk( , , Binary_Time, Binary_Time )
c
	If ( ( .not. Exit_Flag ) .and. ( Sleeping ) ) Then
	    Write( Sleep, 20, IoStat=Ios ) Sleep_Time
	    Call SMG$Begin_Pasteboard_Update ( Pasteboard_Id )
	    Call SMG$Put_Chars ( System_Display, Sleep, 3, 114 )
	    Call SMG$Paste_Virtual_Display ( System_Display,
	1				     Pasteboard_ID, 1, 1 )
	    Call SMG$Set_Physical_Cursor ( Pasteboard_Id, 24, 1 )
	    Call SMG$End_Pasteboard_Update ( Pasteboard_Id )
	End If
c
	Return
	End



	Subroutine Draw_System_Headers (	Current_Date_Time,
	1					Day_Of_Week,	Len	)
c
	Include '($SMGDef)'
	Include 'SyiVal.For'
	Include 'Pstbrd.For'
c
	Character*23	Current_Date_Time
	Character*9	Day_of_Week
c
	Integer*4	Len
c
	Call SMG$Begin_Pasteboard_Update ( Pasteboard_Id )
c
	Call SMG$Put_Chars (	System_Display,
	1			Sys_Type // ' - VMS ' //
	1			Sys_Version( : Sys_Version_Length ) // '.',
	1			1, 1, 0 )
	If ( Sys_Node_Length .gt. 0 )
	1	Call SMG$Put_Chars (	System_Display,
	1				'On Node ' // 
	1				Sys_Node_Name ( : Sys_Node_Length ),
	1				1, 25, 0 )
	Call SMG$Put_Chars (	System_Display,
	1			' Big Brother V4.4.2 ',
	1			1, 57, 0, SMG$M_Bold, SMG$M_Reverse )
	Call SMG$Put_Chars (	System_Display,
	1			Day_of_Week( :Len ) // ', ' //
	1			Current_Date_Time, 1, 99 + ( 9 - Len ), 0 )
	Call SMG$Put_Chars (	System_Display,
	1			'  Up Time' // '     ' //
	1			'Idle Time' // '     ' //
	1			'Avg Idle'  // '     ' //
	1			'Cur Idle'  // '     ' //
	1			'Inter' // '    ' //
	1			'Batch' // '    ' //
	1			'Network' // '    ' //
	1			'System' // '    ' //
	1			'Other' // '    ' //
	1			'Total' // '     ' //
	1			'Interval' // '     ' //
	1			'Page   ',
	1			2, 1, 0, SMG$M_Reverse )
	Call SMG$Put_Chars (	System_Display,
	1			'  Process       ' // 'Image_Name ' //
	1			'Terminal ' // 'Prior ' // 'State ' //
	1			' Login_Time  ' // 'File ' // 'Size ' //
	1			'Pg_Flts ' // 'Dir_I/O ' // 'Buf_I/O ' //
	1			'Imag ' // ' Grp ' // ' Cpu_Time ' //
	1			'Avg_% ' // 'Cur_% ' // 'Idle ',
	1			4, 1, 0, SMG$M_Reverse )
c
	Call SMG$Paste_Virtual_Display (	System_Display,
	1					Pasteboard_ID, 1, 1 )
c
	Call SMG$Set_Physical_Cursor ( Pasteboard_Id, 24, 1 )
	Call SMG$Paste_Virtual_Display (	User_Display,
	1					Pasteboard_ID, 5, 1 )
c
	Call SMG$End_Pasteboard_Update ( Pasteboard_Id )
c
	Return
	End



	Subroutine Display_Loop
c
	Parameter	Max_Units = 128
c
	Include '($SMGDEF)'
c
	Include 'JpiStr.For'
	Include 'JpiVal.For'
	Include 'JpiLen.For'
c
	Include 'Hiber.For'
	Include 'Disply.For'
	Include 'SyiVal.For'
c
	Include 'Flags.For'
	Include 'UsrTbl.For'
	Include 'Idle.For'
c
	Include	'Pstbrd.For'
c
	Character*132	Stat_Line
	Character*23	current_date_time
	Character*9	day_of_week
	Character*5	Idle
c
	Integer*4	Avg_Idle,	Len
	Integer*4	Sys$Hiber,	IStatus,	TT_UCB
	Integer*4	Total_Processes
c
10	Format ( 4x, I3, ' ', I2.2, ':', I2.2, 7x, I3, '%',
	1	9x, I3, '%', 8x, I3, 6x, I3, 7x, I3, 7x, I3,
	1	7x, I3, 6x, I3, 6x, I3, ' Sec', 7x, I2, '    ' )
c
	Do While ( .not. Exit_Flag )
c
	    Call Lib$Date_Time( Current_Date_Time )
	    Call Get_Weekday( Day_of_Week, Len )
c
	    Call SMG$Erase_Display ( System_Display )
	    Call SMG$Erase_Display ( User_Display )
	    Call SMG$Invalidate_Display ( System_Display )
	    Call SMG$Invalidate_Display ( User_Display )
c
	    Call Draw_System_Headers (	Current_Date_Time, 
	1				Day_of_Week,	Len	)
c
	    Redraw_Flag = .False.
	    Stat_Line( 1: 1 ) = ' '
c
	    Do While ( ( .not. Exit_Flag ) .and. ( .not. Redraw_Flag ) )
c
		Do Ip = 0, 4
		    Mode_Count( Ip ) = 0
		End Do
c
		Call Get_Users ( Total_Processes, ICount )
c
c		*** Call a kernel mode routine which makes a table of
c		    idle times and PIDs for allocated terminals
c
		IStatus = TT_UCB ( Idle_Table, Pid_Table, Device_Table,
	1			   Unit_Table, , Max_Units )
c
		Call Get_Up_Time( Stat_Line( : 10 ), Avg_Idle )
c
		Write ( Stat_Line( 11: ), 10, IoStat=Ios )
	1				Idle_Day,	Idle_Hou,
	1				Idle_Min,	Avg_Idle,
	1				Percent_Idle,	Mode_Count( 3 ),
	1				Mode_Count( 2 ), Mode_Count( 1 ),
	1				Mode_Count( 4 ), Mode_Count( 0 ),
	1				Total_Processes, Sleep_Time,
	1				Page_Number
c
		Call Lib$Date_Time( Current_Date_Time )
c
c		*** Begin batching output to the display
c
		Call SMG$Begin_Pasteboard_Update ( Pasteboard_Id )
c
		Call SMG$Put_Chars ( System_Display, Current_Date_Time,
	1				1, 110, 0 )
		Call SMG$Put_Chars ( System_Display, Stat_Line, 3, 1 )
c
		Call SMG$Paste_Virtual_Display ( System_Display,
	1					  Pasteboard_ID, 1, 1 )
c
		j = 1
		i = Page_Index
c
		Do While ( ( j .lt. 20 ) .and. ( i .le. ICount ) )
c
		    Call Get_Idle ( Screen( i )(  28:  35 ),
	1			    Screen( i )( 128: 132 ), i )
		    If ( j .ne. Mark_Flag ) Then
			Call SMG$Put_Chars ( User_Display, Screen( i ), j, 1 )
		    Else
			Call SMG$Put_Chars ( User_Display, Screen( i ), j, 1,
	1				     , SMG$M_Bold )
		    End If
c
		    i = i + 1
		    j = j + 1
c
		End Do
c
		If ( Mark_Flag .ge. j ) Mark_Flag = 0
c
		If ( ICount .ge. i ) Then
		    Call SMG$Put_Chars_Wide (	User_Display,
	1					' ** More ** ', 20, 54,
	1					0, SMG$M_Blink .OR.
	1					SMG$M_Reverse, )
		Else
		    Call SMG$Erase_Display ( User_Display, j, 1 )
		    Call SMG$Put_Chars ( User_Display, ' ', 20, 1 )
		End If
c
c	*** Paste display onto the pasteboard
c
		Call SMG$Paste_Virtual_Display (	User_Display,
	1						Pasteboard_ID,
	1						5, 1 )
c
		If ( RemK_Flag ) Then
		    Call SMG$UnPaste_Virtual_Display ( Killer_Display )
		    RemK_Flag = .False.
		End If
c
		If ( Help_Flag ) Then
		    Call SMG$UnPaste_Virtual_Display (	Help_Display,
	1						Pasteboard_ID )
		    Call SMG$UnPaste_Virtual_Display (	Author_Display,
	1						Pasteboard_ID )
		    Unknown_Flag = .False.
		    Help_Flag = .False.
		Else If ( Unknown_Flag ) Then
		    Unknown_Flag = .False.
		End If
c
		Call SMG$Set_Physical_Cursor ( Pasteboard_Id, 24, 1 ) 
		Call SMG$End_Pasteboard_Update ( Pasteboard_Id )
c
c	*** Wait for a wakeup call
c
		Sleeping = .True.
		Call Sys$Hiber()
		Sleeping = .False.
c
	    End Do
	End Do
c
c *** Restore screen
c
	Call SMG$Delete_PasteBoard ( Pasteboard_Id, 1 )
c
	Return
	End



	Subroutine Get_Idle( Terminal, Idle, Index)
c
c  Call a kernel mode routine which makes a table of idle times
c  for allocated terminals
c
	Parameter	Max_Units = 128
c
	Integer*4	Index
	Character	Terminal*(*)
	Character*5	Idle
c
	Include 'Usrtbl.For'
c
	Integer*4	I_Idle,		I_hr,	I_min
	Integer*4	I_Device( 4 ),	PID,	Found
	Byte		B_Device( 16 ),	B_Device_Len
	Character*15	C_Device
c
	Equivalence	(	I_Device,	B_Device )	
	Equivalence	(	B_Device( 1 ),	B_Device_Len )
	Equivalence	(	B_Device( 2 ),	C_Device )
c
	Pid = User_Index( Index )
	ii = 1
	Found = .False.
c
	Do While ( ( Pid_Table( ii ) .ne. 0 ) .and. ( .not. Found ) )
	    If ( PID .eq. Pid_table( ii ) ) Then
		I_Idle = Idle_table( ii )
		If ( Terminal( 1: 2 ) .eq. 'VT' ) Then
		    I_Device( 1 ) = Device_Table( 1, ii )
		    I_Device( 2 ) = Device_Table( 2, ii )
		    I_Device( 3 ) = Device_Table( 3, ii )
		    I_Device( 4 ) = Device_Table( 4, ii )
		    Terminal = C_Device( : B_Device_Len )
c
		    If ( Unit_Table( ii ) .eq. 0 ) Then
			n = 1
		    Else
			n = Log10 ( Float ( Unit_Table( ii ) ) + 0.5 ) + 1
		    End If
c
		    Write ( Terminal(	B_Device_Len + 1:
	1				B_Device_Len + 1 + n ),
	1				1001, IoStat=Ios ) Unit_Table( ii )
		End If
c
		Found = .True.
c
	    Else
		ii = ii + 1
	    End if
c
	End do
c
	If ( ( .not. Found ) .or. ( I_Idle .le. 0 ) ) Then
	    Idle = '     '
	    If ( Terminal( 1: 2 ) .eq. 'VT' ) Terminal = '<discon> '
	Else
	    I_Min = I_Idle / 60
	    I_Hr = I_Min / 60
	    I_Min = I_Min - ( 60 * I_Hr )
	    Write ( Idle, 1000, IoStat=Ios ) I_Hr, I_Min
	    If ( I_Hr .eq. 0 ) Then
		Idle( 1: 3 ) = '   '
		If ( I_Min .le. 0 ) Idle = '    .'
	    Else
		If ( Idle( 4: 4 ) .eq. ' ' ) Idle( 4: 4 ) = '0'
	    End if
	End If
	Return
c
1000	Format( I2, ':', I2 )
1001	Format( I<n>, ':' )
c
	End



	Subroutine Get_Up_Time( Up_Time, Avg_Idle )
c
	Include 'SyiVal.For'
	Include	'Idle.For'
c
	Character	Up_Time*(*)
c
	Integer*4	Avg_Idle,		Remainder
	Integer*4	Current_Time( 2 ),	Result( 2 )
c
c *** Calculte the amount of uptime
c
	Call Sys$GetTim ( Current_Time )
	Call Lib$Subx ( Sys_Boot_Time, Current_Time, Result )
	Call Sys$AscTim ( , Up_Time, Result, 0 )
c
c *** Calculte the average idle time
c
	Call Lib$EDIV ( 10000000, Result, Avg_Idle, Remainder )
	If (Avg_Idle .eq. 0) Then
	    Avg_Idle = 100
	Else
	    Avg_Idle = -((Float(NULL_CPU_Time) / Float(Avg_Idle)) + .5)
	End If
c
	Return
	End



	Subroutine Make_Author
c
	Include '($SMGDef)'
	Include 'Pstbrd.For'
c
	Call SMG$Label_Border	(	Author_Display,
	1			' Program Creator: Mark R. Vevle ',
	1			, , SMG$M_Bold, SMG$M_Reverse )
	Call SMG$Put_Chars (	Author_Display,
	1		    	'Address: University of Alabama at Birmingham'
	1			, 2, 1)
	Call SMG$Put_Chars (	Author_Display,
	1			'         244 BHS, THT 79', 3, 1 )
	Call SMG$Put_Chars (	Author_Display,
	1			'         University Station', 4, 1 )
	Call SMG$Put_Chars (	Author_Display,
	1			'         Birmingham, Alabama  35294', 5, 1 )
	Call SMG$Put_Chars (	Author_Display,
	1			'Phone:   (205) 934-1973 / 2657', 7, 1 )
c
	Return
	End



	Subroutine Make_Help
c
	Include '($SMGDef)'
	Include 'Pstbrd.For'
c
	Call SMG$Label_Border	(	Help_Display,
	1			' Big Brother Help ',
	1			, , SMG$M_Bold, SMG$M_Reverse )
c
	Call SMG$Put_Chars (	Help_Display, ' ^A ', 2, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display,
	1			' - Add/Remove system processes to/from the '
	1			// 'display or use ' )
	Call SMG$Put_Chars (	Help_Display,
	1			'INSERT HERE', , , , SMG$M_Underline )
	Call SMG$Put_Chars (	Help_Display, ' and ' )
	Call SMG$Put_Chars (	Help_Display, 'REMOVE', , , , SMG$M_Underline )
	Call SMG$Put_Chars (	Help_Display, ' (VT2xx only).' )
c
	Call SMG$Put_Chars (	Help_Display, ' ^B ', 3, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display, ' - Previous screen or use ' )
	Call SMG$Put_Chars (	Help_Display,
	1			'PREV SCREEN', , , , SMG$M_Underline )
	Call SMG$Put_Chars (	Help_Display, ' (VT2xx only).' )
c
	Call SMG$Put_Chars (	Help_Display, ' ^D ', 4, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display,
	1			' - Delete highlighted process or use ' )
	Call SMG$Put_Chars (	Help_Display, 'DO', , , , SMG$M_Underline )
	Call SMG$Put_Chars (	Help_Display, ' (VT2xx only).' )
c
	Call SMG$Put_Chars (	Help_Display, ' ^E ', 5, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display, ' - Exit.' )
c
	Call SMG$Put_Chars (	Help_Display, ' ^F ', 6, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display, ' - Highlight process or use ' )
	Call SMG$Put_Chars (	Help_Display, 'FIND', , , , SMG$M_Underline )
	Call SMG$Put_Chars (	Help_Display, ' (VT2xx only).' )
c
	Call SMG$Put_Chars (	Help_Display, ' ^N ', 7, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display, ' - Next page or use ' )
	Call SMG$Put_Chars (	Help_Display,
	1			'NEXT SCREEN', , , , SMG$M_Underline )
	Call SMG$Put_Chars (	Help_Display, ' (VT2xx only).' )
c
	Call SMG$Put_Chars (	Help_Display, ' ^P ', 8, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display,
	1			' - Show/Remove process identifications.' )
c
	Call SMG$Put_Chars (	Help_Display, ' ^U ', 9, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display,
	1			' - Switch from Username to Process' //
	1			' name and back or use ' )
	Call SMG$Put_Chars (	Help_Display, 'SELECT', , , , SMG$M_Underline )
	Call SMG$Put_Chars (	Help_Display, ' (VT2xx only).' )
c
	Call SMG$Put_Chars (	Help_Display, ' ^W ', 10, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display, ' - Refresh screen.' )
c
	Call SMG$Put_Chars (	Help_Display, ' ^Z ', 11, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display, ' - Exit.' )
c
	Call SMG$Put_Chars (	Help_Display, ' ^? ', 12, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display,
	1			' - Help or use a keyboard help key (ie. ' )
	Call SMG$Put_Chars (	Help_Display, 'HELP', , , , SMG$M_Underline )
	Call SMG$Put_Chars (	Help_Display, ' or ' )
	Call SMG$Put_Chars (	Help_Display, 'PF2', , , , SMG$M_Underline )
	Call SMG$Put_Chars (	Help_Display, ')' )
c
	Call SMG$Put_Chars (	Help_Display,
	1			' Up Arrow ', 14, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display,
	1			' - Increase your base priority. ' )
c
	Call SMG$Put_Chars (	Help_Display,
	1			' Dn Arrow ', 15, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display,
	1			' - Decrease your base priority. ' )
c
	Call SMG$Put_Chars (	Help_Display,
	1			' Rg Arrow ', 16, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display,
	1			' - Increase time between screen updates.' )
c
	Call SMG$Put_Chars (	Help_Display,
	1			' Lf Arrow ', 17, 6, , SMG$M_Reverse )
	Call SMG$Put_Chars (	Help_Display,
	1			' - Decrease time between screen updates.' )
c
	Return
	End



	Subroutine Alert
c
	Include '($SMGDEF)'
	Include	'Pstbrd.For'
c
	Call SMG$Ring_Bell ( User_Display, 2 )
	Call SMG$Put_Chars_Wide (	User_Display,
	1	' ** Type ^? or any keyboard HELP key for Help ** ',
	1	20, 15, 0, SMG$M_Blink .or. SMG$M_Reverse, )
	Call SMG$Set_Physical_Cursor ( Pasteboard_Id, 24, 1 )
c
	Return
	End



	Subroutine NULL_Process
c
	Include 'UsrTbl.For'
	Include 'Disply.For'
	Include 'JpiVal.For'
	Include 'JpiPrm.For'
	Include 'Idle.For'
c
	Character*4	Cpu_String
c
	Integer*4	Sys$GetJpiW,	Jpi_Status
c
c	*** Calculate amount of CPU time used
c
	Call Cpu_Usage ( 0 )
c
c	*** Calculate the amount of accumulated idle time
c
	NULL_CPU_Time = Cpu_Time
	Idle_Sec = Cpu_Time / 100
	Idle_Min = Idle_Sec / 60
	Idle_Sec = Idle_Sec - ( 60 * Idle_Min )
	Idle_Hou = Idle_Min / 60.0
	Idle_Min = Idle_Min - ( 60 * Idle_Hou )
	Idle_Day = Idle_Hou / 24
	Idle_Hou = Idle_Hou - ( 24 * Idle_Day )
c
c	*** Get the next process (The SWAPPER process)
c
	Jpi_status = Sys$GetJpiW( , Pid, , GetJpi_List, , , )
c
	Return
	End



	Subroutine Get_Users( Total_processes, User_Count )
c
c *** include system return codes
c
	Include '($SSDef)'
c
	Include 'UsrTbl.For'
	Include 'Disply.For'
c
	Include 'JpiStr.For'
	Include 'JpiVal.For'
	Include 'JpiLen.For'
	Include 'JpiPrm.For'
c
	Include 'Flags.For'
c
	Character*4	Cpu_String
c
	Integer*4	Jpi_Status,	User_Count
	Integer*4	Sys$GetJpiW,	Total_Processes
c
10	Format ( i3,'%' )
20	Format ( 128(' ') )
c
	Total_Processes = 0
	Pid = -1
	User_Count = 0
c
c *** Get the first process (the NULL process)
c
	Jpi_Status = Sys$GetJpiW( , pid, ,
	1			 getjpi_list, , , )
c
	Call NULL_Process
c
c *** This is for the SWAPPER process ( Username is null )
c
	User_Name = 'Swapper'
	User_Length = 7
c
	Do While ( Jpi_Status .ne. SS$_NoMoreProc )
c
	    Total_Processes = Total_Processes + 1
c
	    If	( 	( .not. display_all_flag ) .and.
	1		( Process_Group .lt. 8 )   .and.
	1		( Process_Mode  .lt. 2 ) ) Then
c
		Call Cpu_Usage( -1 )
c
		If ( Process_Mode .eq. 0 ) then
		    Mode_Count( 4 ) = Mode_Count( 4 ) + 1
		Else
		    Mode_Count( 1 ) = Mode_Count( 1 ) + 1
		End If
c
	    Else
c
		User_Count = User_Count + 1
c
c	    *** Clear the line
c
		Write ( Screen( User_Count ), 20 )
c
c	    *** Calculate amount of CPU time
c
		Call Cpu_Usage( User_Count )
c
c	    *** Save the PID of this process
c
		User_Index( User_Count ) = Process_id
c
c	    *** Process the strings
c
		Call Process_Strings( Screen( User_Count ) )
c
c	    *** Process the numerics
c
		Call Process_Numbers( Screen( User_Count ) )
c
	    End If
c
c	*** Get the next process
c
	    jpi_status = Sys$GetJpiW( , pid, ,
	1			     getjpi_list, , , )
c
c	*** Keep going
c
	End Do
c
	Return
	End



	Subroutine Process_Numbers( Screen )
c
	Include 'JpiVal.For'
c
	Character*132	Screen
c
	Integer*4	cpu_min,	cpu_sec,	cpu_hou
	Integer*4	cpu_day,	Get_Queue_Name
	Integer*4	Swapped_Out,	k,	Rc,	Name_Length
c
	Character*8	Queue_Name
c
c *** Process state table
c
	Character*6	Find_State( 14 )
c
	Data Find_State /'ColPg ','MWait ','Cef   ','Pfw   ','Lef   ',
	1		 'LefO  ','Hiber ','HibO  ','Susp  ','SuspO ',
	1		 'Fpg   ','Com   ','ComO  ','Cur   ' /
c
10	Format ( i2, '/', i<j> )
20	Format ( i2 )
30	Format ( i4 )
40	Format ( i6 )
50	Format ( i3,':',i2.2,':',i2.2 )
55	Format ( i3,' ',i2.2,':',i2.2 )
60	Format ( i7 )
70	Format ( i5 )
80	Format ( o4 )
c
	Swapped_Out = .False.
	j = 1
	If ( base_priority .gt. 9 ) j = 2
c
	If ( ( Process_Group .le. 7 ) .and. ( Process_Mode .eq. 0 ) ) Then
	    Mode_Count( 4 ) = Mode_Count( 4 ) + 1
	Else
	    Mode_Count( Process_Mode ) = Mode_Count( Process_Mode ) + 1
	End If
c
	Screen( 43: 48 ) = Find_State( process_state )
c
	If ( ( process_state .eq.  2 ) .or.
	1    ( process_state .eq.  6 ) .or.
	1    ( process_state .eq.  8 ) .or.
	1    ( process_state .eq. 10 ) .or.
	1    ( process_state .eq. 13 ) ) Then
	    Swapped_Out = .True.
	    Screen(  17:  26 ) = '?         '
	    Screen(  49:  60 ) = '      ?     '
	    Screen(  72:  78 ) = '      ?'
	    Screen( 106: 114 ) = '        ?'
	    Screen( 116: 120 ) = '   ?%'
	Else If ( Process_State .eq. 9 ) Then
	    Screen(  17:  26 ) = '?         '
	    Screen(  49:  60 ) = '      ?     '
	    Screen( 116: 120 ) = '   ?%'
	Else
	    Call Get_Login( Screen( 49: 60 ), Login_Time )
	    Call Get_Load( Screen( 116: 120), Login_Time, Cpu_Time )
	End If
c
	If ( .Not. Swapped_Out ) Then
c
	    Write( Screen( 72: 78 ), 60, IoStat=Ios ) page_faults
c
	    cpu_sec = cpu_time / 100
	    cpu_min = cpu_sec / 60
	    cpu_sec = cpu_sec - ( 60 * cpu_min )
	    cpu_hou = cpu_min / 60
	    cpu_min = cpu_min - ( 60 * cpu_hou )
c
	    If ( cpu_hou .lt. 24 ) Then
		Write( Screen( 106: 114 ), 50 ) cpu_hou, cpu_min, cpu_sec
		If ( cpu_hou .eq. 0 ) then
		    Screen( 106: 109 ) = '    '
		    If ( cpu_min .lt. 10 ) Screen( 110: 110 ) = ' '
		End if
	    Else
		cpu_day = cpu_hou / 24
		cpu_hou = cpu_hou - (cpu_day * 24)
		Write( Screen( 106: 114 ), 55 ) cpu_day, cpu_hou, cpu_min
	    End If
c
	End If
c
	Write ( Screen(  37:  41 ), 10, iostat=ios )
	1				current_priority, base_priority
	Write ( Screen(  63:  64 ), 20, iostat=ios ) ( file_quota -
	1				     remaining_file_quota )
	Write ( Screen(  67:  70 ), 30, iostat=ios ) ( page_count +
	1					Gbl_Page_Count )
	Write ( Screen(  80:  86 ), 60, iostat=ios ) DirIO_Count
	Write ( Screen(  88:  94 ), 60, iostat=ios ) BufIO_Count
	Write ( Screen(  96:  99 ), 30, iostat=ios ) Image_Count
	Write ( Screen( 101: 104 ), 80, iostat=ios ) Process_Group

c
c	*** Process status flags
c
	If ( BJTest( Process_Status, 20 ) ) Then
	    Screen( 28: 35 ) = '-NoAth- '
	Else If ( Terminal_Length .eq. 0 ) Then
	    If ( BJTest( Process_Status, 14 ) ) Then
		Rc = Get_Queue_Name ( Process_Id, Queue_Name, Name_Len )
		Screen( 28: 35 ) = Queue_Name( : 8 )
	    Else If ( BJTest( Process_Status, 4 ) ) Then
		Screen( 28: 35 ) = '-NoSwp- '
	    End If
	End If
c
	Return
	End



	Subroutine Get_Load( Idle, Login_Time, Cpu_time)
c
	Character	Idle*(*)
c
	Integer*4	Login_Time( 2 ),	Cpu_Time
	Integer*4	Avg_Idle,		Remainder
	Integer*4	Current_Time( 2 ),	Result( 2 )
c
c *** Calculte the amount of uptime
c
	Call Sys$GetTim ( Current_Time )
	Call Lib$Subx ( Login_Time, Current_Time, Result )
c
c *** Calculte the average load
c
	Call Lib$EDIV ( 10000000, Result, Avg_Idle, Remainder )
	If (Avg_Idle .eq. 0) Then
	    Avg_Idle = 100
	Else
	    Avg_Idle = ( -(Float(Cpu_Time) / Float(Avg_Idle)) + .5 )
	End If
c
10	Format( I4, '%' )
c
	Write(Idle, 10, Err=100) Avg_Idle
c
100	Continue
c
	Return
	End



	Subroutine Process_Strings( Screen )
c
	Include 'JpiStr.For'
	Include 'JpiVal.For'
	Include 'JpiLen.For'
	Include 'Flags.For'
c
	Character*132	Screen
c
10	Format ( Z8.8,'       ' )
c
	If ( process_flag ) then
	    Write ( Screen( 1: 15 ), 10, IoStat=Ios ) process_id
	Else If ( user_flag ) then
	    Call Convert( User_Name( : User_Length ), Screen( 1: 15 ) )
	Else
	    Screen( 1: 15 ) = Process_Name( : Process_Length )
	End If
c
	If ( Terminal_Length .gt. 0 )
	1	Screen( 28: 35 ) = Terminal( : Terminal_Length )
c
	If ( Image_Length .ne. 0 ) then
	    j = index( image_name, ']' ) + 1
	    Do While ( j .gt. 1 )
		image_name = image_name( j : )
		j = index( image_name, ']' ) + 1
	    End Do
	    Image_Name = Image_Name( : Index( Image_Name, '.' ) - 1 )
	    Call Convert( Image_Name( :9 ), Screen( 17: 26 ) )
	End If
c
	Return
	End



	Subroutine Cpu_Usage( Row )
c
	Integer*4	Row
c
	Include 'UsrTbl.For'
	Include 'Disply.For'
	Include 'JpiVal.For'
	Include 'Idle.For'
c
	Integer*4	Elapsed_Time( 2 ),	Cpu_Used
	Integer*4	Old_Cpu_Time,		Percent_Cpu
	Integer*4	Calc_Cpu
c
	Integer*2	User_Ptr
c
10	Format ( i3,'%')
c
	User_Ptr = Process_Index
c
c *** Get elapsed time
c
	If ( User_Table( 1, User_Ptr ) .eq. 0 ) Then
	    Call Lib$Init_Timer( User_Table( 1, User_Ptr ) )
	    User_Table( 3, User_Ptr ) = Cpu_Time
	    If ( Row .eq. 0 ) then
		Percent_Idle = 100
	    Else If ( Row .gt. 0 ) Then
	    	Screen( Row )( 123: 126 ) = '  0%'
	    End If
	Else If ( Row .lt. 0 )  Then
	    Call Lib$Stat_Timer( 1, elapsed_time, user_table( 1,
	1				  user_ptr ) )
	    Call Lib$Init_Timer( user_table( 1, user_ptr ) )
c
	    If ( Process_State .ne. 2 ) Then
		User_Table( 3, User_Ptr ) = Cpu_Time
	    Else
		User_Table( 1, User_Ptr ) = 0
	    End If
c
	Else
	    Call Lib$Stat_Timer( 1, Elapsed_Time, User_Table( 1,
	1				  User_Ptr ) )
	    Call Lib$Init_Timer( User_Table( 1, User_Ptr ) )
c
	    If ( Process_State .ne. 2 ) Then
		Old_Cpu_Time = User_Table( 3, User_Ptr )
		User_Table( 3, User_Ptr ) = Cpu_Time
		Cpu_Used = ( Cpu_Time - Old_Cpu_Time ) * 100
		Percent_Cpu = Abs((Float(Elapsed_Time( 1 )) / 100000.0) + .5)
		If ( Percent_Cpu .gt. 0 ) 
	1	    Percent_Cpu = (Float(Cpu_Used) / Float(Percent_Cpu) + .5)
		If ( Row .eq. 0 ) then
		    Percent_Idle = Percent_Cpu
		Else
		    Write ( Screen( Row )( 123: 126 ),
	1		    10, IoStat=Ios ) Percent_Cpu
		End If
	    Else
		User_Table( 1, User_Ptr ) = 0
		Screen( Row )( 123: 126 ) = '  0%'
	    End If
	End If
c
	Return
	End



	Subroutine Get_Login ( String, Login_Time )
c
	Character	String*(*)
	Character*23	Date_Time_String
c
	Integer*4	Login_Time( 2 )
c
	Call Sys$AscTim ( , Date_Time_String, Login_Time, 0 )
	String( 1: 6 ) = Date_Time_String( 1: 6 )
	String( 7: ) = Date_Time_String( 12: )
c
	Return
	End



	Subroutine Get_Weekday( Day, Len )
c
	Character	Day*(*)
	Character*9	Day_Table( 7 )
c
	Logical*1	Size( 7 )
c
	Integer*4	Len,	Ptr
c
	Data Day_Table 	/  'Monday   ', 'Tuesday  ', 'Wednesday',
	1		   'Thursday ', 'Friday   ', 'Saturday ',
	1		   'Sunday   ' /
	Data Size	/  6, 7, 9, 8, 6, 8, 6 /
c
	Call Lib$Day_Of_Week ( , Ptr )
c
	Day = Day_Table( Ptr )
	Len = Size( Ptr )
c
	Return
	End



	Subroutine Get_System_Info
c
	Include 'SyiPrm.For'
	Include 'SyiVal.For'
c
	Character*10	Versions( 8 )
c
	Data Versions	/ 'VAX-11 780', 'VAX-11 750',
	1		  'VAX-11 730', 'VAX-11 790',
	1		  '   Scorpio', ' Nautilus',
	1		  '    uVAX I', '   uVAX II' /
c
d	Call Lib$Day( I, ,)
d	If ( I .gt. 'B670'X ) Call Get_Weekday( I, 8 )
c
	Call Sys$GetSyiW ( , , , GetSyi_List, , , )
c
	If (Sys_Node_Length .eq. 0) Then
	    iii = Lib$Sys_TrnLog ( 'SYS$NODE', Sys_Node_Length,
	1			   Sys_Node_Name, , , )
	End If
c
	If ( Sys_Type_Value .le. 8 ) Then
	    Sys_Type = Versions( Sys_Type_Value )
	Else
	    Sys_Type = 'NEW VAX!!!'
	End If
c
	Sys_Version_Length = Min( Sys_Version_Length,
	1			  Index( Sys_Version, ' ' ) - 1 )
c
	Return
	End



	Subroutine Modify_Priority_By( Amount )
c
	Include 'CurPri.For'
c
	Integer*4	Amount
c
	My_Current_Priority = My_Current_Priority + Amount
c
	If ( My_Current_Priority .lt. 1 ) Then
	    My_Current_Priority = 31
	Else If ( My_Current_Priority .gt. 31 ) Then
	    My_Current_Priority = 1
	End If
c
	Call Sys$SetPri( 	,
	1			,	%Val( My_Current_Priority )
	1			,
	1			)
c
	Return
	End



	Subroutine Convert( in, out )
c
c *** routine to convert uppercase characters to lowercase
c
	character	in*(*),	out*(*)
	character*26	upper, lower
c
	integer*4	Str$Translate,	iret_stat
c
	upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
	lower = 'abcdefghijklmnopqrstuvwxyz'
c
	out( 1:1 ) = in( 1:1 )
	Call = Str$Translate( out( 2: ), in( 2: ), lower, upper )
c
	Return
	End



	Subroutine Setup_GetJpi
c
c *** Job/Process information request type codes ***
c
	Include '($JpiDef)'
	Include '($SyiDef)'
c
	Include 'JpiStr.For'
	Include 'JpiVal.For'
	Include 'JpiLen.For'
	Include 'JpiPrm.For'
c
	Include 'SyiVal.For'
	Include 'SyiPrm.For'
c
	Integer*2	Short_List( 2, 72 ),	Sys_List( 2, 15 )
c
	Equivalence (	GetJpi_List,	Short_List	)
	Equivalence (	GetSyi_List,	Sys_List	)
c
c *** Set up the Jpi request (never changes) ***
c
c *** Current Priority
	Short_List( 1, 1 )	= 4
	Short_List( 2, 1 )	= Jpi$_Pri
	GetJpi_List( 2 )	= %Loc( current_priority )
	GetJpi_List( 3 )	= 0
c *** Base Priority
	Short_List( 1, 4 )	= 4
	Short_List( 2, 4 )	= Jpi$_Prib
	GetJpi_List( 5 )	= %Loc( base_priority )
	GetJpi_List( 6 )	= 0
c *** Open file count
	Short_List( 1, 7 )	= 4
	Short_List( 2, 7 )	= Jpi$_FilCnt
	GetJpi_List( 8 )	= %Loc( remaining_file_quota )
	GetJpi_List( 9 )	= 0
c *** Image Name
	Short_List( 1, 10 )	= 128
	Short_List( 2, 10 )	= Jpi$_ImagName
	GetJpi_List( 11 )	= %Loc( image_name )
	GetJpi_List( 12 )	= %Loc( image_length )
c *** Login Time
	Short_List( 1, 13 )	= 8
	Short_List( 2, 13 )	= Jpi$_LoginTim
	GetJpi_List( 14 )	= %Loc( login_time )
	GetJpi_List( 15 )	= 0
c *** Process Name
	Short_List( 1, 16 )	= 15
	Short_List( 2, 16 )	= Jpi$_PrcNam
	GetJpi_List( 17 )	= %Loc( process_name )
	GetJpi_List( 18 )	= %Loc( process_length )
c *** Current State
	Short_List( 1, 19 )	= 4
	Short_List( 2, 19 )	= Jpi$_state
	GetJpi_List( 20 )	= %Loc( process_state )
	GetJpi_List( 21 )	= 0
c *** Terminal
	Short_List( 1, 22 )	= 7
	Short_List( 2, 22 )	= Jpi$_terminal
	GetJpi_List( 23 )	= %Loc( terminal )
	GetJpi_List( 24 )	= %Loc( terminal_length )
c *** User name
	Short_List( 1, 25 )	= 12
	Short_List( 2, 25 )	= Jpi$_username
	GetJpi_List( 26 )	= %Loc( user_name )
	GetJpi_List( 27 )	= %Loc( user_length )
c *** File quota
	Short_List( 1, 28 )	= 4
	Short_List( 2, 28 )	= Jpi$_fillm
	GetJpi_List( 29 )	= %Loc( file_quota )
	GetJpi_List( 30 )	= 0
c *** Process status flags
	Short_List( 1, 31 )	= 4
	Short_List( 2, 31 )	= Jpi$_sts
	GetJpi_List( 32 )	= %Loc( process_status )
	GetJpi_List( 33 )	= 0
c *** Process identification
	Short_List( 1, 34 )	= 4
	Short_List( 2, 34 )	= Jpi$_pid
	GetJpi_List( 35 )	= %Loc( process_id )
	GetJpi_List( 36 )	= 0
c *** Cpu time
	Short_List( 1, 37 )	= 4
	Short_List( 2, 37 )	= Jpi$_cputim
	GetJpi_List( 38 )	= %Loc( cpu_time )
	GetJpi_List( 39 )	= 0
c *** Page count
	Short_List( 1, 40 )	= 4
	Short_List( 2, 40 )	= Jpi$_ppgcnt
	GetJpi_List( 41 )	= %Loc( page_count )
	GetJpi_List( 42 )	= 0
c *** Page faults
	Short_List( 1, 43 )	= 4
	Short_List( 2, 43 )	= Jpi$_pageflts
	GetJpi_List( 44 )	= %Loc( page_faults )
	GetJpi_List( 45 )	= 0
c *** Global Page Count
	Short_List( 1, 46 )	= 4
	Short_List( 2, 46 )	= Jpi$_GpgCnt
	GetJpi_List( 47 )	= %Loc( Gbl_Page_Count )
	GetJpi_List( 48 )	= 0
c *** Process Index
	Short_List( 1, 49 )	= 4
	Short_List( 2, 49 )	= Jpi$_Proc_Index
	GetJpi_List( 50 )	= %Loc( Process_Index )
	GetJpi_List( 51 )	= 0
c *** Buffered I/O count
	Short_List( 1, 52 )	= 4
	Short_List( 2, 52 )	= Jpi$_BufIO
	GetJpi_List( 53 )	= %Loc( BufIO_Count )
	GetJpi_List( 54 )	= 0
c *** Direct I/O count
	Short_List( 1, 55 )	= 4
	Short_List( 2, 55 )	= Jpi$_DirIO
	GetJpi_List( 56 )	= %Loc( DirIO_Count )
	GetJpi_List( 57 )	= 0
c *** Image Run-down count
	Short_List( 1, 58 )	= 4
	Short_List( 2, 58 )	= Jpi$_ImageCount
	GetJpi_List( 59 )	= %Loc( Image_Count )
	GetJpi_List( 60 )	= 0
c *** Count of mounted volumes
	Short_List( 1, 61 )	= 4
	Short_List( 2, 61 )	= Jpi$_Volumes
	GetJpi_List( 62 )	= %Loc( Volume_Count )
	GetJpi_List( 63 )	= 0
c *** Process Mode
	Short_List( 1, 64 )	= 4
	Short_List( 2, 64 )	= Jpi$_Mode
	GetJpi_List( 65 )	= %Loc( Process_Mode )
	GetJpi_List( 66 )	= 0
c *** Process UIC Group
	Short_List( 1, 67 )	= 4
	Short_List( 2, 67 )	= Jpi$_Grp
	GetJpi_List( 68 )	= %Loc( Process_Group )
	GetJpi_List( 69 )	= 0
c *** Mark end of options
	GetJpi_List( 70 )	= 0
	GetJpi_List( 71 )	= 0
	GetJpi_List( 72 )	= 0
c
c *** Define the GetSyi item list for system information
c
c *** Software Version
	Sys_List( 1, 1 )	= 8
	Sys_List( 2, 1 )	= Syi$_Version
	GetSyi_List( 2 )	= %Loc( Sys_Version )
	GetSyi_List( 3 )	= %Loc( Sys_Version_Length )
c *** Cpu Type
	Sys_List( 1, 4 )	= 4
	Sys_List( 2, 4 )	= Syi$_Cpu
	GetSyi_List( 5 )	= %Loc( Sys_Type_Value )
	GetSyi_List( 6 )	= 0
c *** System Boot time
	Sys_List( 1, 7 )	= 8
	Sys_List( 2, 7 )	= Syi$_BootTime
	GetSyi_List( 8 )	= %Loc( Sys_Boot_Time )
	GetSyi_List( 9 )	= 0
c *** System Node Name
	Sys_List( 1, 10 )	= 16
	Sys_List( 2, 10 )	= Syi$_NodeName
	GetSyi_List( 11 )	= %Loc( Sys_Node_Name )
	GetSyi_List( 12 )	= %Loc( Sys_Node_Length )
c
c *** Mark end of options
c
	GetSyi_List( 13 )	= 0
	GetSyi_List( 14 )	= 0
	GetSyi_List( 15 )	= 0
c
	Return
	End


c
c Modification History under VAX/VMS V3.xx
c
c                     V1.0  - The original version
c
c                     V1.1  - Added pages of display and increased number
c                             of  processes  that  can be displayed.  The
c                             maximum  number  of  process  that  can  be
c                             displayed  now  is  128  ( 19 per page with
c                             6+ pages ).  MRV. June 10, 1984
c
c                     V1.2  - Corrected  overflow  on  internal reads for
c                             the  display  of  page  faults  in  routine
c                             Process_Numbers  when  the  number  of page
c                             faults  are  larger than 999,999. The field
c                             is filled with "*".  MRV. August 24, 1984
c
c                     V1.3  - Corrected  overflow  on  internal reads for
c                             the  display of CPU times.  When the number
c                             CPU  hours is to  large the field is filled
c                             with "*".  MRV. November 12, 1984
c
c                     V1.4  - Modified the rmd_ctrl_exit routine to force
c                             an immediate exit on ^Y and on ^C.
c
c                           - Modified  the  modify_sleep_time routine so
c                             that   wake   ups   can  be  changed  while
c                             hibernating.  This allows one to get out of
c                             a long hibernation.
c
c                           - Modified  the process_input routine so that
c                             the  sleep  flag  is set to 1 when the exit
c                             flag is set.  This allows for a faster exit
c                             when the sleep time is large.
c
c                           - Added RMDEMO version number to the display.
c
c                           - MRV. December 27, 1984.
c
c                     V1.5  - Modified  the  GetJpi_Setup routine so that
c                             the  correct  process size is reported. ie.
c                             process   size   is   Process_Page_Count  +
c                             Global_Page_Count.
c
c                           - MRV. January 16, 1985.
c
