?Page ?NOCODE, NOICODE, NOMAP, NOCROSSREF, NOSYMBOLS, NOINSPECT, NOSAVEABEND !############################################################################# !# # !# SPLSCAN : Version 1.00.00 # !# Mark Dickinson # !# 26 August 1999 # !# # !# (c)Mark Dickinson, all rights reserved. # !# Part of SPLUTIL; Mark Dickinson, 1997 # !# # !# Function : To scan all jobs in all spooler datafiles managed by a # !# spooler supervisor for a search string the user is looking # !# for. This can obviously take quite a while. # !# # !# SUPER Users may scan all jobs. # !# Non-super users will get security errors against jobs they # !# do not own, but we suppress error messages as they don't # !# need to know what they arn't allowed to look at. # !# # !# The spooler supervisor to be searched is provided as the # !# infile, the responses logged to the outfile. The program # !# will set appropriate error values in the stop message if # !# needed. # !# # !# Example useage: # !# run splscan /in $spls,name/ FIND THIS STRING # !# # !# Full enhanced syntax: # !# SPLSCAN/IN /[LATEST;][LOCATION #XX.XX;] # !# # !# Spooler notes: # !# To access a jobs data under the spooler the following steps are # !# required, and must be vigourously obeyed (and checked) at every step # !# ...open the spool supervisor # !# ...query the spool supervisor for data on the job # !# ...use the returned data to idendify the spool data file # !# ...open the spooler datafile # !# ...use the spooler to initialise a print control buffer # !# ...use printstart to acces the data stream # !# # !# # !# Changed # !# 26 Aug 1999 - Released. # !# 07 Oct 1999 - Check job FLAGS for abnormal close condition and treat # !# as a job STATE crash condition. We cannot process jobs # !# in this state. # !# 07 Oct 1999 - Added opened date and time to found message. Added # !# option to only return the most recent job containing # !# the search string. # !# 11 Oct 1999 - Added option to limit searches to jobs at a specific # !# report location also which will greatly decrease cpu # !# useage. Also added a help option. # !# # !############################################################################# ?Page "Globals" -- Constant information at offset 0 in ALL Marks programming for -- debugging purposes (to allow matchup with correct source files). String Version^ID[0:26] := ["SPLSCAN:V1.02.00:1999/10/10"]; -- Constants used. Literal True = -1, False = 0, -- Constants for completion code types. Fatal^Error^Code = 3, Warning^Error^Code = 1, No^Error^Code = 0, -- Constants for Search type Full^Results^Report = 0, Latest^Only^Report = 1; -- The output file for our results to be recorded in String Log^File^Name[0:36] := 37 * [0]; !from startup.outfile Int Log^File := -2, !file handle Log^File^Namelen := 0; !needed by io + msg calls -- The print supervisor process, use C Series compatible calls String Spool^Supervisor[0:36] := 37 * [0]; !from startup.infile Int Spool := -2, !Spool file number Spool^Name^Len, !needed by IO + msg calls -- Spooler interface buffers .SpoolBuff[0:127], !Spool comms buffer area .JobBuff[0:559], !Job Control buffer for perusal .JobPrintBuff[0:127], !Print Control Buffer for perusal .JobDataBuff[0:449], !Data buffer for perusal JobPage := 0; !Active page for perusal -- Stuff required to access the data for a specific job String Active^Data^Name[0:36] := 37 * [0]; !Current spooler datafile Int Active^Data^Namelen, !Used for IO + msgs routines Active^Data^File := -1; !Current Spooler datafile file num -- The Search String Information to be used Literal MAX^SEARCH^STRING^LEN = 133; String .Search^String[0:MAX^SEARCH^STRING^LEN]; Int Search^String^Len; -- General Purpose Int Error := 0, !Error variable .Buffer[0:559], !Misc I/O Buffer, Max Out Size 560 word I, Count^Read, Global^Job^Number^Being^Scanned := 0; Fixed TotalReportsFound := 0F; -- report type controls Int Current^Report^Type := Full^Results^Report, Use^Location^Searches := False; String .Location^To^Search[0:15]; -- Error info to pass pack to the caller by stop or abend. String Error^Text[0:127]; !Text passed back Int Error^Text^Len := 0, !true length of above to be passed back Completion^Code := 0; !0=Ok, 2=Warn etc. refer to Tandem prog !reference guide for details. -- Miscellaneous Pointers String .S^Buffer := @Buffer '<<' 1, .S^SpoolBuff := @SpoolBuff '<<' 1, .Ptr; -- The spooler data structure record we will be using. Struct Spooler^Job^Def(*); Begin Int Number, !job number State; !job state Struct location; Begin string group[0:7], destination[0:7]; End; String form^name[0:15], report^name[0:15]; Int Flags, page^size, owner^id, copies, pages, lines, time^opened[0:2], time^closed[0:2]; Struct data^file; begin int volume[0:3], subvolume[0:3], filename[0:3]; end; string collector^process^name[0:5]; int units^allocated; int gmom^crtpid^jobid[0:4]; ! Netbatch info written here int(32) max^lines, max^pages; int batch^name[0:15], batch^id; End; Struct .Most^Recent^Info; Begin Int Job^Number; !job number Fixed Opened^TimeStamp, !64 bit timestamp Closed^TimeStamp; !64 bit timestamp End; ! ! Defines used ! Define Blank( A, B ) = A ':=' " " & A For (B - 1)#; Define ZeroFill( A, B ) = A ':=' 0 & A For (B - 1)#; ?Page ?NOLIST ?Source $SYSTEM.SYSTEM.EXTDECS0( ?CANCEL, ?COMPUTETIMESTAMP, ?CONTIME, ?DEFINEINFO, ?FILEINFO, ?FILE_OPEN_, ?FILE_CLOSE_, ?FILE_GETINFOLISTBYNAME_, ?FNAMECOLLAPSE, ?INTERPRETTIMESTAMP, ?NUMIN, ?NUMOUT, ?PRINTREAD, ?PRINTSTART2, ?PROCESS_STOP_, ?READ, ?SHIFTSTRING, ?SPOOLEREQUEST2, ?SPOOLERSTATUS2, ?WRITE, ?WRITEREAD) ?LIST ?PAGE "Forward Declarations" Int Proc Do^All^Initialisation; Forward; Proc Process^All^Spooler^Jobs; Forward; Int Proc Access^Spooler^Datafile; Forward; Int Proc Do^Spooler^Query( Cmd^Code, Scan^Type ); Int Cmd^Code, Scan^Type; Forward; Int Proc Scan^All^Job^Pages( Opened, Closed ); Int .Opened, .Closed; Forward; Int Proc Open^Spool^Supervisor; Forward; Proc Spooler^Error( Error ); Int Error; Forward; PROC Write^Log^Message( io^msg:io^len ); STRING .io^msg; -- msg received at end of the wait INT io^len; -- length of the msg Forward; PROC Check^Search^Results; Forward; Int PROC Store^Location^Name( LocDesc ); String .LocDesc; Forward; ?Page "SPLSCAN^Mainline^991011" !############################################################################ !# # !# Procedure : SPLSCAN^Mainline^991011 # !# # !# This procedure calls the initialisation routine, and if OK calls the # !# procedure to handle scanning the spooler jobs. # !# On return from the spooler job stuff it checks to see if we had a # !# successful run, and if loops to delete all the jobs we printed OK. # !# It then closes all the open files and exists. # !# # !# All the rest of the code is just status/error message display. # !# # !# NOTE: We return a completion-code and text message when we exit the # !# program. These can be checked from within the TACL :_completion # !# var. # !# # !############################################################################ Proc SPLSCAN^Mainline^991011 MAIN; Begin If Do^All^Initialisation Then Begin !If we get startup and open files Completion^Code := No^Error^Code; Call Process^All^Spooler^Jobs; Call Check^Search^Results; !anything done ? End; !---- Close any files we have used ---- If (Active^Data^File > 0) Then Error := File_Close_(Active^Data^File); If (Spool > 0) Then Error := File_Close_( Spool ); If (Log^File > 0) Then Error := File_Close_( Log^File ); !---- Return an appropriate error code if required (for netbatch) ---- If Completion^Code = 0 Then Begin Error^Text ':=' ""; Error^Text^Len := 0; End; If Error^Text^Len > 80 Then Error^Text^Len := 80; -- max for stop call Error := Process_Stop_( !stop me!,1 !both process pairs!,0 !normal!, Completion^Code,,, Error^Text:Error^Text^Len ); If (Error <> 0) Then Begin -- we didn't stop, abend Error := Process_Stop_(!stop me!,1 !both process pairs!,1 !abend!, Completion^Code,,, Error^Text:Error^Text^Len ); End; End; ! End of proc SPLSCAN^Mainline^991011 MAIN ?Page "Do^All^Initialisation" !############################################################################ !# # !# Procedure : Do^All^Initialisation # !# # !# This procedure performs all initialisation for the program. # !# # !# It uses the startup.infile as the spooler collector to be searched. # !# The startup.outfile is used as the result reporting file. # !# # !# It will open the output file and call the routine to open the spooler # !# supervisor. # !# # !# If all is OK returns true, if error(s) returns false. # !# # !############################################################################ Int Proc Do^All^Initialisation; Begin String Rcv^name[0:7] := ["$RECEIVE"], .Sptr1, .SPtr2; Int Rcv := -2, In^File := -2, Out^Reclen, keywords^left := 0; String .TempPtr; ! Startup message structure STRUCT .^ci^startup; BEGIN INT msgcode; STRUCT default; BEGIN INT volume[0:3], subvol[0:3]; END; STRUCT infile; BEGIN INT volume[0:3], subvol[0:3], dname [0:3]; END; STRUCT outfile; BEGIN INT volume[0:3], subvol[0:3], dname [0:3]; END; STRING param[0:MAX^SEARCH^STRING^LEN-1]; END; -- Get the startup message from $receive Error := File_Open_( Rcv^Name:8, Rcv,,,,, 1 !don't get open/close etc! ); If (Error <> 0) Then Begin Error^Text ':=' "UNABLE TO OPEN $RECEIVE, ERROR nnn" -> @Ptr; Call Numout( Ptr[-3], Error, 10, 3 ); Completion^Code := Fatal^Error^Code; Error^Text^Len := @Ptr '-' @Error^Text; Call Write^Log^Message( Error^Text:Error^Text^Len ); Error := Process_Stop_( !stop me!,1 !both process pairs!,0 !normal!, Completion^Code,,, Error^Text:Error^Text^Len ); End; Call Read( Rcv, ^ci^startup, $len( ^ci^startup ), Count^Read ); If <> Then Begin Call Fileinfo( Rcv, Error ); If (Error <> 6) Then Begin -- not a system message Error^Text ':=' "FILE ERROR nnn ON $RECEIVE" -> @Ptr; Call Numout( Error^Text[11], Error, 10, 3 ); Completion^Code := Fatal^Error^Code; Error^Text^Len := @Ptr '-' @Error^Text; Call Write^Log^Message( Error^Text:Error^Text^Len ); Error := Process_Stop_( !stop me!,1 !both process pairs!,0 !normal!, Completion^Code,,, Error^Text:Error^Text^Len ); End; End; Call File_Close_( Rcv ); -- get the output file name and open it Log^File^Namelen := FNameCollapse( ^ci^startup.outfile, Log^File^Name ); Error := File_Open_( Log^File^Name:Log^File^NameLen, Log^File ); If (Error <> 0) Then Begin Completion^Code := Fatal^Error^Code; Error^Text ':=' "UNABLE TO OPEN " & Log^File^Name for Log^File^Namelen & ", ERROR nnn" -> @Ptr; Call Numout( Ptr[-3], Error, 10, 3 ); Error^Text^Len := (@Ptr '-' @Error^Text); Error := Process_Stop_( !stop me!,1 !both process pairs!,1 !abend!, Completion^Code,,, Error^Text:Error^Text^Len ); Return False; End; -- Ensure the user has passed a parameter for us to search on. There must -- be data left after we have killed off leading spaces. Scan ^ci^startup.param while " " -> @SPtr1; If $CARRY then begin Completion^Code := Fatal^Error^Code; Error^Text ':=' "A SEARCH STRING MUST BE PROVIDED !" -> @Ptr; Error^Text^Len := (@Ptr '-' @Error^Text); Call Write^Log^Message( Error^text:Error^Text^Len ); Return False; end; Scan SPtr1 Until 0 -> @SPtr2; Call ShiftString( Sptr1, (@SPtr2 '-' @SPtr1), 1 ); ! Extract any keywords in the parm string ! If a keyword is found followed by a ; its a keyword ! If a keyword is found without a ; assume search string started and that ! the search string includes the keyword and all following data. keywords^left := true; while keywords^left do begin -- keywords are separated by ; so if no ; then no more keywords Scan SPtr1 while " " -> @SPtr1; -- skip leading spaces scan sptr1 until ";" -> @TempPtr; if $CARRY then keywords^left := false -- else see if it is a valid keyword followed by a ; as first nonspace byte else begin -- // LATEST ; If (Sptr1 = "latest") Then Begin Scan Sptr1[6] While " " -> @TempPtr; If TempPtr = ";" then begin Current^Report^Type := Latest^Only^Report; @SPtr1 := @TempPtr '+' 1; end Else keywords^left := false; End -- latest -- // LOCATION #xxx.xxx ; Else If (Sptr1 = "location") Then Begin Scan Sptr1[8] While " " -> @TempPtr; If TempPtr = "#" then begin If Store^Location^Name( TempPtr ) Then Begin Scan TempPtr Until ";" -> @TempPtr; If $CARRY Then keywords^left := false Else Begin Use^Location^Searches := True; @SPtr1 := @TempPtr '+' 1; End; End Else keywords^left := false; end Else keywords^left := false; End -- latest -- // HELP or /? [ ; ] Else If ((Sptr1 = "help") OR (Sptr1 = "/?")) Then Begin Scan Sptr1[4] While " " -> @TempPtr; If ((TempPtr = ";") OR $CARRY) then begin Completion^Code := No^Error^Code; Error^Text ':=' "SYNTAX:"; Call Write^Log^Message( Error^text:7 ); Error^Text ':=' "SPLSCAN/IN /[LATEST;][LOCATION #XX.XX;]" -> @Ptr; Error^Text^Len := (@Ptr '-' @Error^Text); Call Write^Log^Message( Error^text:Error^Text^Len ); return False; end Else keywords^left := false; End; -- help end; -- end of keyword checks end; ! Then save the search string. -- check to ensure we still have data left Scan SPtr1 While " " -> @SPtr1; Scan SPtr1 Until 0 -> @SPtr2; -- if equal, nothing provided except the keywords so an error If (@Sptr1 = @Sptr2) then begin Completion^Code := Fatal^Error^Code; Error^Text ':=' "A SEARCH STRING MUST BE PROVIDED !" -> @Ptr; Error^Text^Len := (@Ptr '-' @Error^Text); Call Write^Log^Message( Error^text:Error^Text^Len ); Return False; end; Search^String^Len := $MIN((@SPtr2 '-' @SPtr1),MAX^SEARCH^STRING^LEN); Search^String ':=' SPtr1 for Search^String^Len; -- Better trap for a help entered without a ; as if it was entered -- alone it won't have done any keyword parsing. If ( ((Search^String^Len = 4) AND (Search^String = "help")) OR ((Search^String^Len = 2) AND (Search^String = "/?")) ) Then Begin Completion^Code := No^Error^Code; Error^Text ':=' "SYNTAX:"; Call Write^Log^Message( Error^text:7 ); Error^Text ':=' "SPLSCAN/IN /[LATEST;][LOCATION #XX.XX;]" -> @Ptr; Error^Text^Len := (@Ptr '-' @Error^Text); Call Write^Log^Message( Error^text:Error^Text^Len ); return False; End; -- help -- get the input filename now, and open the spooler supervisor Spool^Name^Len := FNameCollapse( ^ci^startup.infile, Spool^Supervisor ); If NOT Open^Spool^Supervisor Then Return False; -- OK, write start banner and then return true If (Current^Report^Type = Full^Results^Report) Then Begin Error^Text ':=' "USING SPOOLER SUPERVISOR " & Spool^Supervisor for Spool^Name^Len -> @Ptr; Error^Text^Len := (@Ptr '-' @Error^Text); Call Write^Log^Message( Error^text:Error^Text^Len ); Error^Text ':=' "SEARCHING FOR: " & Search^String for Search^String^Len -> @Ptr; Error^Text^Len := (@Ptr '-' @Error^Text); Call Write^Log^Message( Error^text:Error^Text^Len ); Call Write^Log^Message( Error^text:0 ); End; Most^Recent^Info.Job^Number := 0; Most^Recent^Info.Opened^TimeStamp := 0F; Most^Recent^Info.Closed^TimeStamp := 0F; Return True; End; ! end of int proc Do^All^Initialisation ?Page "Process^All^Spooler^Jobs" !############################################################################ !# # !# Procedure : Process^All^Spooler^Jobs # !# # !# This proc checks all the jobs under the user selected spool supervisor # !# to see if they are at a location matching those the user wishes us to # !# copy to disk. # !# If any matching jobs are found they will be copied to out disk file. # !# # !# Notes: Uses values in the GLOBAL Error variable. Ensure that when we # !# come back with an all-ok situation we reset this to zero # !# (as error statuses are used to detect end-of-peruse-output etc. # !# so error will be non-zero after a sucessful print). # !# # !############################################################################ Proc Process^All^Spooler^Jobs; Begin Int New^Job := -1, Peruse^Access^Granted, Matches^Search; String .P1, .P2, Local^Buffer[0:16]; Struct .Spooler^Job( Spooler^Job^Def ) = SpoolBuff; !We wish to search the entire spooler. Spooler^Job.Number := 0; Error := 0; While Not Error Do Begin If Do^Spooler^Query( 2, 1 ) Then Begin -- A job has been found. !Get the page size info and store the job numbers. !see if we are limiting searches by location If (Use^Location^Searches AND (Spooler^Job.location.group <> Location^To^Search for 16)) Then Matches^Search := False -- mismatch Else Matches^Search := True; -- match or not Use^Location^Searches ! check the flags, if the abnormal close is set then set the spooler ! job state to the crash-closed state so we can check it as if it ! were a normal job crash. ! Flag bit 6 indicates an abnormal close state If (Spooler^Job.Flags.<6>) Then Spooler^Job.State := 0; -- not useable ! states are, 0 = ? (crash-closed), 1 = open, 2 = ready, 3 = held, 4 = printing If (((Spooler^Job.State = 2) OR (Spooler^Job.State = 3)) AND -- job is in ready or held Matches^Search) Then Begin -- search limitations OK -- Store Job number globally so I can use it for messages -- in other procs. Global^Job^Number^Being^Scanned := Spooler^Job.Number; -- Peruse^Access^Granted := Access^Spooler^Datafile; If Not Peruse^Access^Granted Then Return -- false = failure Else If (Peruse^Access^Granted = -2) Then Begin -- -2 = security error -- THIS MUST BE DONE (or only we exit loop) Error := 0; -- reset the global error value End Else Begin -- true = OK -- say we are doing something If (Current^Report^Type <> Latest^Only^Report) Then Begin Error^Text ':=' 27 & "AJOB nnnnn BEING SCANNED" -> @Ptr; Call Numout(Ptr[-19], Spooler^Job.Number, 10, 5); Error^Text^Len := @Ptr '-' @Error^Text; Call Write^Log^Message( Error^Text:Error^Text^Len ); End; -- search the job If NOT Scan^All^Job^Pages( Spooler^Job.time^opened, Spooler^Job.time^closed ) Then Begin -- unable to process job Error^Text ':=' "ERROR PROCESSING SPOOLER JOB nnnnn" -> @Ptr; Call Numout(Ptr[-5], Spooler^Job.Number, 10, 5); Error^Text^Len := @Ptr '-' @Error^Text; Call Write^Log^Message( Error^Text:Error^Text^Len ); Return; End Else Begin -- else copied to disk -- THIS MUST BE DONE (or only one job is processed) Error := 0; -- reset the global error value End; End; -- of if we got access to the job End; End; -- Spooler^Job.Number := Spooler^Job.Number + 1; End; End; ! Proc Process^All^Spooler^Jobs ?Page "Spooler/Peruse Section : Access^Spooler^Datafile" !############################################################################ !# # !# Procedure : Access^Spooler^Datafile # !# # !# This routine uses information returned from the spool supervisor to # !# set up control buffers to access the job data in the spool datafile. # !# The spool datafile will be opened shared, the routine then sets up a # !# print control buffer and a job control buffer which will be used to # !# access the job data in the job list routines. # !# THE SPOOLBUF AREA MUST BE SETUP FOR THE CURRENT JOB. # !# # !############################################################################ Int Proc Access^Spooler^Datafile; Begin Struct .Spooler^Job( Spooler^Job^Def ) = SpoolBuff; !---- If data file has changed or is not open then open it ---- If ((Active^Data^Name <> Spooler^Job.Data^File.Volume For 12) OR (Active^Data^File < 0)) Then Begin If Active^Data^File > 0 Then !If a previous is open, close it Begin Call File_Close_( Active^Data^File ); Active^Data^File := -1; End; Active^Data^Namelen := FNameCollapse( Spooler^Job.Data^File, Active^Data^Name ); Error := File_Open_( Active^Data^Name:Active^Data^Namelen, Active^Data^File, 1 !read only!, 0 !shared! ); !as shared, sync 1 If Error Then Begin !Open failed Completion^Code := Fatal^Error^Code; Error^Text ':=' "ERROR-UNABLE TO OPEN PRINT DATA FILE - ERROR nnn" -> @Ptr; Error^Text^Len := (@Ptr '-' @Error^Text); Call Numout( Ptr[-3], Error, 10, 3 ); Call Write^Log^Message( Error^Text:Error^Text^Len ); Return False; End; End; !If data file changed !---- If we can access the data file then set up print control buffer ---- Error := Spoolerequest2( Spool, Spooler^Job.Number, JobPrintBuff ); If Error <> 0 Then Begin If (Error = %14014) then begin -- security, not users job and not a -- super user running the program -- Don't bother with a message. -- Error^Text ':=' 27 & "AJOB nnnnn ACCESS DENIED" -> @Ptr; -- Call Numout(Ptr[-19], Global^Job^Number^Being^Scanned,10,5); -- Error^Text^Len := (@Ptr '-' @Error^Text); -- Call Write^Log^Message( Error^Text:Error^Text^Len ); -- Call Write^Log^Message( Error^Text:0 ); -- Call Write^Log^Message( Error^Text:0 ); Return -2; end; Call Spooler^Error( Error ); Return False; End; !---- If print control buffer was set up then set up Job control buff ---- ! Note: Needs printer control buff to do this Error := PrintStart2( JobBuff, JobPrintBuff, Active^Data^File ); If Error <> 0 Then Begin Call Spooler^Error( Error ); Return False; End; Return True; !At last we have completed it. End; !End int proc Access^Spooler^Datafile ?Page "Spooler/Peruse Section : Open^Spool^Supervisor" !############################################################################ !# # !# Procedure : Open^Spool^Supervisor # !# # !# This routine is called to open a remote spool supervisor process. # !# It will display information about the supervisor process if the open # !# is successfull. # !# # !############################################################################ Int Proc Open^Spool^Supervisor; Begin Error := File_Open_( Spool^Supervisor:Spool^Name^Len, Spool ); If (Error <> 0) Then Begin Completion^Code := Fatal^Error^Code; Error^Text ':=' "UNABLE TO OPEN SPOOLER SUPERVISOR " & Spool^Supervisor for Spool^Name^Len & ": ERROR nnn" -> @Ptr; Error^Text^Len := @Ptr '-' @Error^Text; Call Numout( Ptr[-3], Error, 10, 3 ); Write^Log^Message( Error^Text:Error^Text^Len ); Spool := -2; Return False; End; Return True; End; !End of int proc open^spool^supervisor ?Page "Spooler/Peruse Section : List^One^Job^Page" !############################################################################ !# # !# Procedure : List^One^Job^Page # !# # !# This proc will list one page of a report from a spooled job into our # !# disk file. # !# It is called for each page from Scan^All^Job^Pages. # !# # !# It returns a few of the errors to the caller to handle. # !# # !############################################################################ Int Proc List^One^Job^Page( Opened, Closed ); Int .Opened, .Closed; Begin Int Bytes^Read, Error, Job^Page^Id, III, Opened^Time[0:7], Closed^Time[0:7]; Fixed Opened^TimeStamp, Closed^TimeStamp; String .Data^Ptr := @JobDataBuff '<<' 1; Error := 0; Job^Page^Id := JobPage; While Not Error Do Begin Error := PrintRead( JobBuff, JobDataBuff, 900, Bytes^Read, Job^Page^Id ); If < Then Return 0; !Assume end of page. If Error Then Begin If ((Error = %12000) Or (Error = %12001)) !End of file or end of copy Then Return Error Else If Error = %12002 Then Begin !Invalid data file format Completion^Code := Fatal^Error^Code; Error^Text ':=' "ERROR-INVALID DATA FILE FORMAT" -> @Ptr; Error^Text^Len := @Ptr '-' @Error^Text; Write^Log^Message( Error^Text:Error^Text^Len ); Return Error; End Else If Error = %12003 Then Error := 0 !Control found (form feed etc), ignore Else If Error = %12004 Then Error := 0 !Setmode found, ignore Else If Error = %12005 Then Error := 0 !Controlbuf found, ignore Else Begin Completion^Code := Fatal^Error^Code; Error^Text ':=' "ERROR-UNKNOWN PERUSAL ERROR: %nnnnnn" -> @Ptr; Error^Text^Len := @Ptr '-' @Error^Text; Call Numout( Ptr[-6], Error, 7, 6 ); Write^Log^Message( Error^Text:Error^Text^Len ); Return Error; End; End !Then Else Begin S^Buffer ':=' Data^Ptr For Bytes^Read -> @Ptr; -- Scan S^Buffer for the string we are searching for Call ShiftString( S^Buffer, Bytes^Read, 1 ); For III := 0 To (Bytes^Read - Search^String^Len) Do Begin -- If the scan string is found -- log it -- and set special error for no more scans on this job If (S^Buffer[III] = Search^String for Search^String^Len) Then begin Call Contime( Opened^Time, Opened[0], Opened[1], Opened[2] ); Opened^Time[7] := 0; Opened^Timestamp := ComputeTimestamp( Opened^Time, Error ); Error := 0; Call Contime( Closed^Time, Closed[0], Closed[1], Closed[2] ); Closed^Time[7] := 0; Closed^Timestamp := ComputeTimestamp( Closed^Time, Error ); -- Inserted checks for latest job, 7 Oct 1999 If (Current^Report^Type = Latest^Only^Report) Then Begin Error := 0; If (Opened^Timestamp > Most^Recent^Info.Opened^TimeStamp) Then Begin Most^Recent^Info.Job^Number := Global^job^Number^Being^Scanned; Most^Recent^Info.Opened^TimeStamp := Opened^TimeStamp; Most^Recent^Info.Closed^TimeStamp := Closed^TimeStamp; End; End Else Begin -- Advise the user we have found it. Error^Text ':=' ">>> STRING FOUND IN JOB nnnnn (OPENED yyyy/mm/dd hh:mm) <<<" -> @Ptr; Call Numout(Error^Text[24], Global^Job^Number^Being^Scanned,10,5); Call Numout(Error^Text[38], Opened^Time[0], 10, 4 ); Call Numout(Error^Text[43], Opened^Time[1], 10, 2 ); Call Numout(Error^Text[46], Opened^Time[2], 10, 2 ); Call Numout(Error^Text[49], Opened^Time[3], 10, 2 ); Call Numout(Error^Text[52], Opened^Time[4], 10, 2 ); Error^Text^Len := (@Ptr '-' @Error^Text); Write^Log^Message( Error^Text:Error^Text^Len ); Write^Log^Message( Error^Text:0 ); Write^Log^Message( Error^Text:0 ); End; -- don't search thru this job any longer Error := 999; TotalReportsFound := TotalReportsFound + 1F; End; -- if matched End; -- for III loop End; !Else Job^Page^Id := 0; -- indicate we wish to carry on getting data End; !While Return Error; End; ! End proc list^one^job^page ?Page "Spooler/Peruse Section : Scan^All^Job^Pages" !############################################################################ !# # !# Procedure : Scan^All^Job^Pages # !# # !# This procedure will list all the pages spooled in the job datafile. # !# It does so by repeatedly calling list^one^job^page until an end of # !# job error is returned from list^one^job^page. # !# # !# It returns true is all was OK, false if we had a problem. # !# # !############################################################################ Int Proc Scan^All^Job^Pages( Opened, Closed ); Int .Opened, .Closed; Begin Error := 0; JobPage := 1; While Not Error Do Begin Error := List^One^Job^Page( Opened, Closed ); If ((Error = %12000) Or (Error = %12001)) Then Return True -- end of job Else If Error = %12003 Then Begin End !Page skip Else If (Error = 999) Then Return True !String found, do no more on this job Else If (Error <> 0) Then Return False -- unknown error Else Begin Error := 0; !reset error JobPage := JobPage + 1; !and move to the next page End; End; Return False; !Should not get here End; ! end int proc Scan^All^Job^Pages ?Page "Spooler/Peruse Section : Do^Spooler^Query" !############################################################################ !# # !# Procedure : Do^Spooler^Query # !# # !# This routine is called to perform I/O to the spooler supervisor. It # !# will loop until the 'request completed' code or an error is detected. # !# Error %14016 is request in progress. This may be returned a couple of # !# times depending on how busy the spooler supervisor is. # !# # !# It returns false if we get an error, true if all was OK. # !# # !############################################################################ Int Proc Do^Spooler^Query( Cmd^Code, Scan^Type ); Int Cmd^Code, Scan^Type; Begin Error := %14016; !Set to request in progress so we loop until complete While Error = %14016 Do !Loop until state is no longer 'in progress' Begin Error := SpoolerStatus2( Spool, Cmd^Code, Scan^Type, SpoolBuff ); If ((Error <> 0) AND (Error <> %14016)) Then Begin If Error <> %14006 !Not normal end of data Then Call Spooler^Error( Error ); Return False; End; End; Return True; End; ! end of int proc do^spooler^query ?Page "Spooler/Peruse Section : Spooler^Error" !############################################################################ !# # !# Procedure : Spooler^Error # !# # !# This procedure is called for any error returned from the spooler # !# supervisor process. It will display a message indicating the error # !# that occured. # !# # !############################################################################ Proc Spooler^Error( Error ); Int Error; Begin If ((Error > %2777) AND (Error < %3400)) Then !File error in .<8:15> Begin Error := Error.<8:15>; Error^Text ':=' "SPLERR:FILE ERROR nnn ON SUPERVISER PROCESS " & Spool^Supervisor for Spool^Name^Len -> @Ptr; Call Numout( Error^Text[18], Error, 10, 3 ); End Else If Error = %10000 Then Error^Text ':=' "SPLERR:Missing Parameter" -> @Ptr Else If Error = %10001 Then Error^Text ':=' "SPLERR:Parameter In Error" -> @Ptr Else If Error = %14000 Then Error^Text ':=' "SPLERR:Invalid Command" -> @Ptr Else If Error = %14001 Then Error^Text ':=' "SPLERR:Command Parameter Missing" -> @Ptr Else If Error = %14002 Then Error^Text ':=' "SPLERR:Command Parameter In Error or Buffer addressing Error" -> @Ptr Else If Error = %14003 Then Error^Text ':=' "SPLERR:Invalid subcommand" -> @Ptr Else If Error = %14004 Then Error^Text ':=' "SPLERR:Subcommand missing" -> @Ptr Else If Error = %14005 Then Error^Text ':=' "SPLERR:Subcommand parameter in error" -> @Ptr Else If Error = %14007 Then Error^Text ':=' "SPLERR:ENTRY DOES NOT EXIST" -> @Ptr Else If Error = %14010 Then Error^Text ':=' "SPLERR:CANNOT ADD ENTRY TO TABLES" -> @Ptr Else If Error = %14011 Then Error^Text ':=' "SPLERR:CANNOT FIND ENTRY" -> @Ptr Else If Error = %14012 Then Error^Text ':=' "SPLERR:ENTRY IN IMPROPPER STATE FOR COMMAND" -> @Ptr Else If Error = %14013 Then Error^Text ':=' "SPLERR:ENTRY IN IN USE" -> @Ptr Else If Error = %14014 Then Error^Text ':=' "SPLERR:INSUFFIECIENT AUTHORITY FOR THE COMMAND" -> @Ptr Else If Error = %14015 Then Begin Error^Text ':=' "SPLERR:" & Spool^Supervisor for Spool^Name^Len & " IS NOT A SPOOLER SUPERVISOR" -> @Ptr; End Else If ((Error > %77777) AND (Error < %107500)) Then Begin Error^Text ':=' "SPLERR:NEWPROCESS ERROR nnn" -> @Ptr; Call Numout( Ptr[-3], Error, 10, 3 ); End; Error^Text^Len := (@Ptr '-' @Error^Text); Write^Log^Message( Error^Text:Error^Text^Len ); Completion^Code := Fatal^Error^Code; End; ! end of proc spooler^error ?Page "Utilities Section : Write^Log^Message" !############################################################################ !# # !# Procedure : Write^Log^Message # !# # !# Write a message to the output file. # !# # !############################################################################ PROC Write^Log^Message( io^msg:io^len ); STRING .io^msg; -- msg received at end of the wait INT io^len; -- length of the msg BEGIN INT .Buf; @Buf := @io^msg '>>' 1; Call Write( Log^File, Buf, io^len ); END; ! end of procedure Write^Log^Message PROC Check^Search^Results; BEGIN Int Opened^Time[0:7], Closed^Time[0:7]; Int(32) Junk; If (TotalReportsFound = 0F) Then Begin Error^Text ':=' "*WARNING* NO JOBS WERE FOUND MATCHING THE SEARCH STRING" -> @Ptr; Error^Text^Len := (@Ptr '-' @Error^Text); Write^Log^Message( Error^Text:Error^Text^Len ); Completion^Code := Warning^Error^Code; End -- We wish to show the latest job. Else If (Current^Report^Type = Latest^Only^Report) Then Begin Junk := Interprettimestamp( Most^recent^Info.Opened^Timestamp, Opened^Time ); Error^Text ':=' "nnnnn (yyyy/mm/dd hh:mm) IS THE MOST RECENT JOB CONTAINING SEARCH STRING" -> @Ptr; Call Numout(Error^Text, Most^Recent^Info.Job^Number,10,5); Call Numout(Error^Text[7], Opened^Time[0], 10, 4 ); Call Numout(Error^Text[12], Opened^Time[1], 10, 2 ); Call Numout(Error^Text[15], Opened^Time[2], 10, 2 ); Call Numout(Error^Text[18], Opened^Time[3], 10, 2 ); Call Numout(Error^Text[21], Opened^Time[4], 10, 2 ); Error^Text^Len := (@Ptr '-' @Error^Text); Write^Log^Message( Error^Text:Error^Text^Len ); End; END; ?Page "Utilities Section : Store^Location^Name" !############################################################################ !# # !# Procedure : Store^Location^Name # !# # !# Format a spool location into internal format. # !# Return true if it's legal, false if not. # !# # !############################################################################ Int PROC Store^Location^Name( LocDesc ); String .LocDesc; BEGIN String .P1, .P2; String .LocalStr[0:17]; Int Len1, Len2; Location^To^Search ':=' " "; -- initialise Scan LocDesc Until ";" -> @P1; If $CARRY -- if NOT ; terminated then not legal for Then return False; -- this particular program. LocalStr ':=' LocDesc for $MIN( 17, (@P1 '-' @LocDesc) ) & 0; -- If no . then only the first part Scan LocalStr Until "." -> @P1; If $CARRY Then Begin -- no . in the location Scan LocalStr Until 0 -> @P1; Len1 := (@P1 '-' @LocalStr); If (Len1 > 8) Then Return False; -- can only be 8 Location^To^Search ':=' LocalStr For $MIN( 8, Len1 ); Return True; End; -- If a . then need to scan two bits out Len1 := (@P1 '-' @LocalStr); If (Len1 > 8) Then Return False; -- can only be 8 Location^To^Search ':=' LocalStr For $MIN( 8, Len1 ); @P1 := @P1 '+' 1; Scan P1 Until " " -> @P2; If $CARRY Then Scan P1 Until 0 -> @P2; Len2 := @P2 '-' @P1; If (Len2 > 8) Then Return False; -- can only be 8 Location^To^Search[8] ':=' P1 For $MIN( 8, Len2 ); Call ShiftString( Location^To^Search, 16, 0 ); -- spooler uses uppercase Return True; END;