;***************************************************************************;
;*                                                                         *;
;*                                 PRINTQ                                  *;
;*           Displays dynamic print queue stats for all spoolers           *;
;*                                                                         *;
;***************************************************************************;

;                            Copyright (C) 1987
;                                    by
;                 Cherokee Information Management Services
;                            All Rights Reserved

;                         Written by: Larry Laurel
;
;Edit History:
;1.0  Feb 21, 1987 created. /LPL
;1.1  Feb 26, 1987 by Dave Heyliger - AMUS : Stack problem fixed

       VMAJOR=1
       VMINOR=1
       VSUB=0
       VWHO=0

       SEARCH  SYS
       SEARCH  SYSSYM
       SEARCH  TRM

       RADIX   16.

; The following offsets are for a queue block printer entry
       Q.QLINK = 00                    ; Link to next queue block
       Q.FLINK = 04                    ; Link to first file in queue
       Q.SPOOL = 08                    ; Spooler name
       Q.FORMS = 0C                    ; Forms ID
       Q.REMAN = 10                    ; Blocks remaining for this printer

; The following offsets are for a queue block print file entry
       F.FLINK = 00                    ; Link to next queue block
       F.PFILE = 04                    ; Name of print file
       F.DEVIC = 0A                    ; Device where file is located
       F.PPN   = 0C                    ; PPN where file is located
       F.DRIVE = 0E                    ; Drive number where file is located
       F.REMAN = 18                    ; Blocks remaining for this file

; Miscellaneous screen controls
       CLEAR   = 00                    ; Clear screen
       HOME    = 01                    ; Cursor to row 1, col 1
       CLREOL  = 09                    ; Clear to end of line
       LOW     = 0B                    ; Low intensity
       HIGH    = 0C                    ; High intensity
       GRAFIX  = 17                    ; Turn graphics on (text off)
       TEXT    = 18                    ; Turn text on (graphics off)
       CURON   = 1C                    ; Cursor on
       CUROFF  = 1D                    ; Cursor off
       REVERS  = 20                    ; Start reverse video
       NORMAL  = 21                    ; End reverse video

; Special graphics characters
       TLCORN  = 26                    ; Top-left corner
       TRCORN  = 27                    ; Top-right corner
       BLCORN  = 28                    ; Bottom-left corner
       BRCORN  = 29                    ; Bottom right corner
       TINTER  = 2A                    ; Top intersection
       RINTER  = 2B                    ; Right intersection
       LINTER  = 2C                    ; Left intersection
       BINTER  = 2D                    ; Bottom intersection
       HLINE   = 2E                    ; Horizontal line
       VLINE   = 2F                    ; Vertical line
       INTER   = 30                    ; Intersection

DEFINE  TAB     ROW,COL
       SAVE    D1
       MOVB    ROW,D1
       ROLW    D1,#8
       MOVB    COL,D1
       TCRT
       REST    D1

       ENDM

DEFINE  SCREEN  CODE
       SAVE    D1
       MOVW    #-1_8+CODE,D1
       TCRT
       REST    D1

       ENDM

PRINTQ:
       PHDR    -1,PH$REE!PH$REU       ; No privliges, re-entrant, re-uasble

       .OFINI
       .OFDEF  SNAME,8                 ; UNPACK buffer for RAD50 names
       .OFDEF  FNAME,1A                ; Output buffer for file names
       .OFSIZ  MEMSIZ

; Allocate impure area

       GETIMP  MEMSIZ,A5

; Set octal, image mode and no-echo
       JOBIDX
       MOVW    JOBTYP(A6),D4           ; Get the job type
       ANDW    #^C<J.HEX>,JOBTYP(A6)   ; Set OCTAL
       MOV     JOBTRM(A6),A6
       ORW     #T$IMI!T$ECS,T.STS(A6)

; Place text on the screen
       SCREEN  CUROFF                  ; Turn off cursor
       SCREEN  CLEAR                   ; Clear screen
       SCREEN  LOW                     ; Set reduced intensity
       TAB     #1,#19
       TYPE    Print Queue Status         Total of ALL Queues :
       TAB     #3,#3
       TYPE    Spooler   Forms    Remaining      Current File            Remaining    Run
       TAB     #4,#4
       TYPE    Name      ID      in Queue          Name                  in File    State
       SCREEN  HIGH                    ; Set normal intensity

; Draw graphics border
       SCREEN  GRAFIX                  ; Turn on graphics

; Place horizontal lines on screen
       TAB     #2,#1                   ; Position cursor
       MOV     #4F,D0                  ; Set up counter for 79. columns
5$:     SCREEN  HLINE                   ; Make a line
       SOB     D0,5$                   ; Loop
       TAB     #5,#1                   ; Position cursor
       MOV     #4F,D0                  ; Set up counter for 79. columns
10$:    SCREEN  HLINE                   ; Make a line
       SOB     D0,10$                  ; Loop
       TAB     #18,#1                  ; Position cursor
       MOV     #4F,D0                  ; Set up counter for 79. columns
15$:    SCREEN  HLINE                   ; Make a line
       SOB     D0,15$                  ; Loop

; Place vertical lines on screen
       MOV     #01,D2
       CALL    VERTLN
       MOV     #0B,D2
       CALL    VERTLN
       MOV     #14,D2
       CALL    VERTLN
       MOV     #20,D2
       CALL    VERTLN
       MOV     #3B,D2
       CALL    VERTLN
       MOV     #47,D2
       CALL    VERTLN
       MOV     #4F,D2
       CALL    VERTLN
       BR      CORNER

; Put in corners and intersections
CORNER:
       TAB     #2,#1                   ; Position cursor
       SCREEN  TLCORN                  ; Put in the upper left corner
       TAB     #2,#4F                  ; Position cursor
       SCREEN  TRCORN                  ; Put in the upper right corner
       TAB     #18,#1                  ; Position cursor
       SCREEN  BLCORN                  ; Put in the lower left corner
       TAB     #18,#4F                 ; Position cursor
       SCREEN  BRCORN                  ; Put in the lower right corner

       TAB     #2,#0B                  ; Position cursor
       SCREEN  TINTER                  ; Place a top intersection
       TAB     #2,#14                  ; Position cursor
       SCREEN  TINTER                  ; Place a top intersection
       TAB     #2,#20                  ; Position cursor
       SCREEN  TINTER                  ; Place a top intersection
       TAB     #2,#3B                  ; Position cursor
       SCREEN  TINTER                  ; Place a top intersection
       TAB     #2,#47                  ; Position cursor
       SCREEN  TINTER                  ; Place a top intersection

       TAB     #5,#0B                  ; Position cursor
       SCREEN  INTER                   ; Place an intersection
       TAB     #5,#14                  ; Position cursor
       SCREEN  INTER                   ; Place an intersection
       TAB     #5,#20                  ; Position cursor
       SCREEN  INTER                   ; Place an intersection
       TAB     #5,#3B                  ; Position cursor
       SCREEN  INTER                   ; Place an intersection
       TAB     #5,#47                  ; Position cursor
       SCREEN  INTER                   ; Place an intersection

       TAB     #18,#0B                 ; Position cursor
       SCREEN  BINTER                  ; Place a bottom intersection
       TAB     #18,#14                 ; Position cursor
       SCREEN  BINTER                  ; Place a bottom intersection
       TAB     #18,#20                 ; Position cursor
       SCREEN  BINTER                  ; Place a bottom intersection
       TAB     #18,#3B                 ; Position cursor
       SCREEN  BINTER                  ; Place a bottom intersection
       TAB     #18,#47                 ; Position cursor
       SCREEN  BINTER                  ; Place a bottom intersection

       TAB     #5,#1                   ; Position cursor
       SCREEN  LINTER                  ; Place a left intersection
       TAB     #5,#4F                  ; Position cursor
       SCREEN  RINTER                  ; Place a right intersection

       SCREEN  TEXT
10$:
       CLR     D0                      ; Init spooler counter
       CLR     D3                      ; Init total block count
       MOV     LPTQUE,A0               ; Get pointer to 1st printer
       CMP     A0,#00                  ; Anybody there?
       JEQ     DONE                    ; No spoolers

20$:
       INC     D0                      ; Increment spooler counter
       MOV     D0,D2                   ; Spooler counter ==> screen position
       ADD     #5,D2                   ;       add offset from top of screen

; Process spooler name
       LEA     A1,Q.SPOOL(A0)          ; Address of RAD50 spooler name
       CALL    UNPK02
       TAB     D2,#3                   ; Position cursor
       TTYL    SNAME(A5)               ; Output name

; Process forms ID
       LEA     A1,Q.FORMS(A0)          ; Address of RAD50 forms ID
       CALL    UNPK02
       TAB     D2,#0D                  ; Position cursor
       TTYL    SNAME(A5)               ; Output name

; Process blocks remaining for this spooler
       TAB     D2,#17                  ; Position cursor
       CLR     D1                      ; Clear the register
       MOVW    Q.REMAN(A0),D1          ; Get the remaining block count
       ADDW    D1,D3                   ; Add it the grand total
       DCVT    5,OT$TRM!OT$ZER         ; Output it

; Process current file and blocks remaining for that file
       MOV     Q.FLINK(A0),A3          ; Pointer to first file entry
       CMP     A3,#0                   ; Any files in queue?
       JNE     30$                     ; Yes - output info
       CALL    CLRFIL                  ; No - Clear entries on screen
       JMP     40$                     ; Loop

; Output the device name, file name, and PPN
30$:
       LEA     A2,FNAME(A5)            ; Point to file name buffer
       PUSH    A2                      ; Save it
       MOV     #19,D1                  ; Init counter to 25.
35$:    MOVB    #20,(A2)+               ; Space
       DEC     D1                      ; Decrement counter
       BNE     35$                     ; Loop
       CLRB    @A2                     ; Null terminator
       LEA     A1,F.DEVIC(A3)          ; Address of RAD50 device name
       POP     A2                      ; Restore pointer to file name buffer
       UNPACK
       CLR     D1                      ; Clear the register
       MOVW    F.DRIVE(A3),D1          ; Get the drive number
       DCVT    0,OT$MEM                ; Move it into buffer
       MOVB    #3A,(A2)+               ; ":"
       LEA     A1,F.PFILE(A3)          ; Address of RAD50 file name
       UNPACK
       UNPACK
       MOVB    #2E,(A2)+               ; "."
       UNPACK
       MOVB    #5B,(A2)+               ; "["
       CLR     D5                      ; Clear the register
       MOVW    F.PPN(A3),D5            ; PPN
       CLR     D1                      ; Clear the register
       MOVW    D5,D1                   ; Move to D1 for manipulation
       ASRW    D1,#8                   ; Get the P
       AND     #0FF,D1                 ; Mask off low order byte
       OCVT    0,OT$MEM                ; Send it to the buffer
       MOVB    #2C,(A2)+               ; ","
       CLR     D1                      ; Clear the register
       MOVB    D5,D1                   ; Get the PN
       OCVT    0,OT$MEM                ; Send it to the buffer
       MOVB    #5D,(A2)+               ; "]"
       TAB     D2,#22                  ; Position cursor
       TTYL    FNAME(A5)               ; Output name

; Process blocks remaining for this file
       TAB     D2,#3F                  ; Position cursor
       CLR     D1                      ; Clear the register
       MOVW    F.REMAN(A3),D1          ; Get the remaining block count
       DCVT    5,OT$TRM!OT$ZER         ; Output it


; Find spooler run state and output it

40$:
       TAB     D2,#4A                  ; Position cursor
       MOV     JOBTBL,A1               ; Get address of job table
45$:    MOV     (A1)+,D7                ; Get next JCB address
       BEQ     45$                     ; No job allocated - loop
       CMP     D7,#-1                  ; End of job table?

       ;---    Stack adjustment here (1.1)
       BNE     47$                     ; nope
       PUSH                            ; bogus "stack adjust"
       JMP     65$                     ; NOW go here...
       ;---

47$:    MOV     D7,A2                   ; Put that baby into an A register
       LEA     A3,Q.SPOOL(A0)          ; Get spooler name from spool queue
       LEA     A4,JOBNAM(A2)           ; Get job name from JCB
       CMP     (A3)+,(A4)+             ; Same?
       BNE     45$                     ; No - get next JCB
       CLR     D1                      ; Clear the register
       MOVW    JOBSTS(A2),D1           ; Get the run state
       PUSH    D1                      ; Save it for later
       ANDW    #J.IOW,D1               ; IO wait state?
       BEQ     50$                     ; No - check something else
       TYPE    IOW                     ; Output state
       JMP     65$                     ; Exit
50$:
       POP     D1                      ; Restore run state
       PUSH    D1                      ; Save it for later
       ANDW    #J.EXW,D1               ; External wait state?
       BEQ     55$                     ; No - check something else
       SCREEN  LOW                     ; Low intensity
       TYPE    exw                     ; Output state
       SCREEN  HIGH                    ; Restore intensity
       JMP     65$                     ; Exit
55$:
       POP     D1                      ; Restore run state
       PUSH    D1                      ; Save it for later
       ANDW    #J.MON,D1               ; At AMOS dot?
       BEQ     60$                     ; No - check something else
       TTYI                            ; Output state
       BYTE    08                      ; Backspace for reverse video
       BYTE    0
       EVEN
       SCREEN  REVERS                  ; Draw attention to this
       TYPE    mon                     ; Output state
       SCREEN  NORMAL                  ; Turn off reverse video
       JMP     65$                     ; Exit
60$:
       POP     D1                      ; restore run state
       PUSH    D1                      ; Save it for later
       ANDW    #1,D1                   ; Documented as J.ALC, but undefined
       BNE     65$                     ; Job is not in ordinary RUN state
       TYPE    RUN                     ; Output state
       JMP     65$                     ; Exit

; The JMP above is left in case we want to stick in more tests
65$:
       CTRLC   DONE
       TCKI                            ; Check for a keystroke
       BNE     70$                     ; None - carry on
       TIN                             ; Get the input into D1
       CMPB    D1,#1B                  ; Is it an escape?
       JEQ     DONE                    ; Yes - Adios

70$:
       POP                             ; Clean up the stack
       MOV     Q.QLINK(A0),A0          ; Get pointer to next spooler
       CMP     A0,#00                  ; Anybody there
       JNE     20$                     ; Loop for next spooler

       TAB     #1,#4A                  ; Position cursor
       MOV     D3,D1                   ; Set up to output the grand total
       DCVT    6,OT$TRM!OT$ZER         ; Output it
       SLEEP   #1388                   ; Snooze & give up some CPU
       JMP     10$                     ; Start over

DONE:
       JOBIDX
       MOVW    D4,JOBTYP(A6)           ; Restore the job type
       SCREEN  CURON
       SCREEN  CLEAR
       EXIT


;***************************************************************************;
;*                                                                         *;
;*                            Misc Subroutines                             *;
;*                                                                         *;
;***************************************************************************;
VERTLN:
       MOV     #3,D0                   ; Initial row number
5$:     TAB     D0,D2                   ; Position cursor
       SCREEN  VLINE                   ; Make a line
       INC     D0                      ; Increment row
       CMP     D0,#18                  ; End of screen?
       BNE     5$                      ; Loop
       RTN

UNPK01:                                 ; Routine to unpack 1 word
       LEA     A2,SNAME(A5)            ; Address of unpacking buffer
       UNPACK
       CLRB    @A2
       RTN

UNPK02:                                 ; Routine to unpack 2 words
       LEA     A2,SNAME(A5)            ; Address of unpacking buffer
       UNPACK
       UNPACK
       CLRB    @A2
       RTN

CLRFIL:                                 ; Clear file entries for a spooler
       TAB     D2,#22                  ; Position cursor
       TTYI
       ASCII   /                         /
       BYTE    0
       EVEN
       TAB     D2,#3F                  ; Position cursor
       TTYI
       ASCII   /     /
       BYTE    0
       EVEN
       RTN

       END