/* REXX */ /* */ /* AUTHOR: Mark Zelden */ /* */ /* Trace ?r */ /*********************************************************************/ /* EXEC: SDSFPRT */ /* */ /* FUNCTION: To take all or selected output from the spool and */ /* copy it to a PDS via SDSF "PRINT" commands. */ /* */ /* Each job is created in the PDS as a member name with */ /* the JOBID - JOBnnnnn, TSUnnnnn or STCnnnnn. */ /* In addition, an member named "$$$INDEX" is created */ /* in the output PDS that has a list of the JOBNAMEs, */ /* JOBIDs, MAXRCs, OWNERIDs, Programmer Names, Start */ /* Times, Start Dates, End Times and End Dates. */ /* */ /* JOBID / member names could also be Jnnnnnnn, Tnnnnnnn */ /* or Snnnnnnn if you are using Job numbers over 5 digits. */ /* */ /* The default output PDS data set name is userid.PRINT. */ /* If it doesn't exist it will be created with LRECL(255) */ /* RECFM(VBA) DIR(500) BLKSIZE(0) SPACE CYL(100,100) */ /* */ /* By default all jobs in the spool with an owner that */ /* is the same as your userid are processed. */ /* */ /* If using an existing output PDS and there is already */ /* a $$$INDEX member, any new JOBIDs will be merged into */ /* the existing $$$INDEX member. If existing JOBIDs */ /* are printed again, the duplicate information is */ /* discarded. */ /* */ /* If you want to edit the $$$INDEX member for any */ /* reason, you must ensure the job information starts */ /* on line 5 or it will break the index merge code. */ /* */ /*********************************************************************/ /* EXECUTION SYNTAX: */ /* */ /* SDSFPRT owner_mask jobname_mask output_pds numcyl */ /* */ /* owern_mask = Jobname ownwer mask (default is your userid) */ /* jobname_mask = Jobname prefix mask (default is "*" - all jobs) */ /* output_pds = output PDS data set name */ /* numcyl = mumber of primary and secondary cylinders */ /* to allocate if the PDS doesn't exist */ /* */ /* No parms are required but in order to use the 2nd parm, */ /* the first one must be specified. In order to use the 3rd */ /* parm, the first and second ones must be specified, in */ /* order to use the 4th parm, the first, second and 3rd */ /* parms must all be specified. */ /* */ /* */ /* DEFAULTS (no parms but the exec name) */ /* SDSFPRT userid * userid.print 100 */ /* */ /* EXAMPLES: */ /* */ /* %SDSFPRT */ /* (O/P to "USERID.PRINT", select all jobs with owner=userid */ /* */ /* %SDSFPRT USERA* */ /* (O/P to "USERID.PRINT", select all jobs with owner=USERA* */ /* */ /* %SDSFPRT * JOBNM* */ /* (O/P to "USERID.PRINT", select "JOBNM*" jobs, all owners */ /* */ /* %SDSFPRT USERB INST* */ /* (O/P to "USERID.PRINT", select INST* jobs with owner=USERB */ /* */ /* %SDSFPRT * JOBNM* USERID.PRINT.PDS */ /* (O/P to "USERID.PRINT.PDS", select "JOBNM*", all owners */ /* */ /* %SDSFPRT * MYJOBS* USERID.PRINT.PDS 300 */ /* (O/P to "USERID.PRINT.PDS", select "MYJOBS*", CYL(300,300) ) */ /* */ /* */ /* Sample JCL to execute in batch: */ /* */ /* //MYJOB JOB (ACCT),CLASS=A,... */ /* //S1 EXEC PGM=IKJEFT01 */ /* //SYSEXEC DD DSN=pds.with.this.exec,DISP=SHR */ /* //SYSTSPRT DD SYSOUT=* */ /* //SYSTSIN DD * */ /* %SDSFPRT OWNER* JOBNM* USERID.PRINT.PDS 300 */ /* /* */*/ /* */ /*********************************************************************/ /* Sample output found in the $$$INDEX MEMBER: */ /* (start/end times and dates columns not shown in the sample) */ /* */ /* The following jobs were successfully processed: */ /* */ /* JOBNAME MEMBER MAXRC OWNER PROGRAMMER NAME */ /* -------- -------- ---------- -------- -------------------- */ /* MZELDENT JOB05067 CC 0012 MZELDEN MARK ZELDEN */ /* MZELDENR JOB05226 CC 0000 MZELDEN MARK ZELDEN */ /* MZELDENT JOB05229 CANCELED MZELDEN MARK ZELDEN */ /* MZELDENB JOB05434 CC 0004 MZELDEN MARK ZELDEN */ /* REORG JOB05521 CC 0000 MZELDEN MARK ZELDEN */ /* COPYFILE JOB05607 CC 0000 MZELDEN MARK ZELDEN */ /* MZELDENQ JOB05634 CC 0000 MZELDEN MARK ZELDEN */ /* */ /*********************************************************************/ /* Updates: */ /* */ /* 05/06/2020: Created exec, modified from "SDSF@DR" */ /* */ /*********************************************************************/ Arg isfowner isfprefix outdsn numcyl . /**********************************************/ /* House keeping */ /**********************************************/ uid = sysvar('SYSUID') /* tso userid */ If isfowner = '' then isfowner = uid /* onwer jobs to sel */ If isfprefix = '' then isfprefix = '*' /* job names to sel */ If outdsn = '' then outdsn = uid ||.PRINT /* output dsn */ If numcyl = '' then numcyl = '100' /* dflt space in cyl */ existing_idx = 0 /* flag for existing $$$INDEX member (0=false) */ tot_failed = 0 /* total # of jobs that failed and can't be printed */ /*********************************************************************/ /* Make sure output dsn exists and is a PDS */ /*********************************************************************/ junk = outtrap('on') "LISTD '" || outdsn || "'" junk = outtrap('off') If rc <> 0 then do Say 'Output dataset ''' || outdsn || ''' not found. Allocating...' Say ' ' "ALLOC FI($$$OUTFL) DA('" || outdsn || "') NEW REUSE" , "UNIT(SYSALLDA) CYL SPACE("NUMCYL","NUMCYL") DIR(500)" , "LRECL(255) RECFM(V B A) BLKSIZE(0)" "FREE FI($$$OUTFL)" End Else do Say 'Existing output dataset ''' || outdsn || ''' will be used.' junk = outtrap('MBR.') /* capture output to MBR. stem */ "LISTD '" || outdsn || "' MEMBERS" /* issue LISTD cmd against PDS */ junk = outtrap('off') /* stop capturing output */ /*********************************************************************/ /* Ensure output dataset is partiioned. */ /*********************************************************************/ If MBR.0 = 5 then do /* no members in PDS */ Say 'ERROR -' outdsn 'is not a PDS!' /* issue error msg */ Exit 12 /* exit RC=12 */ End /*********************************************************************/ /* Check for existing $$$INDEX member and if it exists read */ /* member information into stem variables. */ /*********************************************************************/ Do I = 1 to MBR.0 /* loop to get past vol info */ If MBR.I = "--MEMBERS--" then leave /* if member section, exit loop*/ End Do J = I+1 to MBR.0 /* loop to execute edit macro */ Parse var MBR.J IDXMEM . /* get rid of alias info */ If Substr(idxmem,1,8) == '$$$INDEX' then do /* check IDX numbers */ /*****************************************/ /* $$$INDEX exists, save existing info */ /*****************************************/ existing_idx = 1 /* flag for existing $$$INDEX member (1=true) */ "ALLOC FI($$$INDEX) DA('" || outdsn || "($$$INDEX)') SHR REUSE" "EXECIO * DISKR $$$INDEX (STEM CURIDX. FINIS" End End /* end do J */ Say ' ' End /**********************************************/ /* Start of main code */ /**********************************************/ Say 'SDSFPRT processing parameters used for this run:' Say ' Output dataset =' outdsn If isfowner = '*' then , Say ' Owner to process = ''*'' (all owners will be processed)' Else , Say ' Owner to process =' isfowner If isfprefix = '*' then , Say ' Jobs to process = ''*'' (all jobs will be processed)' Else , Say ' Jobs to process =' isfprefix If existing_idx = 1 then , Say ' Index member $$$INDEX already exists and new data' , 'will be merged.' Say ' ' /* blank line to make more readable */ rc=isfcalls('ON') /*************************/ /* Access the ST display */ /*************************/ /* isfsort = 'JNAME A JOBID A' */ /* sort/process in jobname order */ isfsort = 'JOBID A' /* sort/process in jobid order */ Address SDSF "ISFEXEC ST (DELAYED)" /* ST command */ Drop jname. /* get rid of results from first time */ Address SDSF "ISFEXEC ST (DELAYED)" /* may not catch the */ /* batch job running this if not issued a 2nd time */ lrc=rc call msgrtn if lrc<>0 then exit 20 /**********************************************************/ /* 1st loop to display all jobs returned via "ST" command */ /**********************************************************/ Say 'The following' jname.0 'jobs were returned from the "ST"' , 'command and will be processed:' do dis_jobs=1 to jname.0 Say ' ' Left(jname.dis_jobs,8) ' ' jobid.dis_jobs end Say ' ' Say ' ' Say ' ' /**********************************************************/ /* 2nd loop to print all jobs returned via "ST" command */ /**********************************************************/ "ALLOC FI($$$INDEX) DA('" || outdsn || "($$$INDEX)') SHR REUSE" queue ' The following jobs from the ST command were' , 'successfully processed:' queue ' ' queue ' JOBNAME MEMBER MAXRC ' , ' OWNER PROGRAMMER NAME ' , ' STRTTIME STRTDATE END TIME END DATE' queue ' -------- -------- ----------' , ' -------- --------------------' , ' -------- -------- -------- --------' Say 'Processing jobs ...' Say ' ' goodct = 0 /* initialize counter for index records to write */ do ix=1 to jname.0 call Setup_print_vars Say 'Attempting to print output to DSN=' || , Strip(Translate(isfprtdsname,"","'")) || , /* remove quotes */ "("jobid.ix") - JOBNAME" jname.ix /******************************************/ /* Issue the XDC action against the job */ /******************************************/ Address SDSF "ISFACT ST TOKEN('"TOKEN.ix"') PARM(NP XDC)" lrc=rc call msgrtn if lrc = 0 then do goodct = goodct+1 if Substr(timee.ix,2,1) = ':' then , timee.ix = ' ' || timee.ix if Substr(timen.ix,2,1) = ':' then , timen.ix = ' ' || timen.ix timen.ix = Substr(timen.ix,1,8) /******************************************/ /* queue the index line to the data stack */ /******************************************/ thisidx.goodct = ' ' Left(jname.ix,8) '' Left(jobid.ix,8) , '' Left(retcode.ix,10) '' Left(ownerid.ix,8) , '' Left(pname.ix,20) , '' Left(timee.ix,8) '' datee.ix , '' Left(timen.ix,8) '' daten.ix end /* if lrc<>0 then exit 20 */ end /* end do ix=1 */ /**********************************************************/ /* No $$$INDEX exists, queue index info before writing it */ /**********************************************************/ If existing_idx = 0 then do Do ix2=1 to goodct /* index records from this run */ queue thisidx.ix2 /* index stem var */ End End /**********************************************************/ /* IF $$$INDEX exists, merge new info into new stem, */ /* bubble sort by JOBID and delete any duplicates. */ /**********************************************************/ Else do /* $$$INDEX already exists */ mrgct = 0 /* initialize counter of total records merged */ Do ix2=1 to goodct /* index records from this run */ mrgct = mrgct + 1 /* bump up counter */ mrgidx.mrgct = thisidx.ix2 /* merged index stem var */ End Do ix3 = 5 to curidx.0 /* start at record 5 of existing $$$INDEX */ mrgct = mrgct + 1 /* bump up counter */ mrgidx.mrgct = curidx.ix3 /* merged index stem var */ End /**********************************************************/ /* bubble sort by the JOBID */ /**********************************************************/ sort_done = 0 sort_recs = mrgct Do while sort_done = 0 sort_done = 1 Do bbl1 = 1 to sort_recs - 1 bbl2 = bbl1 + 1 /* JOBID is at column 13 for 8 characters */ If Substr(mrgidx.bbl1,13,8) > Substr(mrgidx.bbl2,13,8) then do sort_done = 0 temp_sort = mrgidx.bbl2 mrgidx.bbl2 = mrgidx.bbl1 mrgidx.bbl1 = temp_sort End /* if */ End /* do i=1 to sort_recs */ sort_recs = sort_recs - 1 End /* do while sort_done */ /**********************************************************/ /* Delete duplicate index information */ /**********************************************************/ currln = 1 /* initialize counter */ Do while currln < mrgct + 1 data1 = Substr(mrgidx.currln,13,8) nextln = currln + 1 data2 = Substr(mrgidx.nextln,13,8) If data1 == data2 then currln = currln + 1 Else do queue mrgidx.currln currln = currln + 1 End End /* do while */ End /* else do - $$$INDEX exists */ /**********************************************************/ /* Write $$$INDEX member and free $$$INDEX DD */ /**********************************************************/ queue '' /* end data stack with a null */ "EXECIO * DISKW $$$INDEX (FINIS" "FREE FI($$$INDEX)" rc=isfcalls('OFF') Say ' ' Say ' ' Say ' ' Say '***********************************' Say ' Program totals' Say ' ' Say ' Total JOBs processed =' jname.0 Say ' Total JOBs printed =' jname.0 - tot_failed Say ' Total JOBs failed =' tot_failed Say '***********************************' exit 0 /**********************************************/ /* End of main code */ /**********************************************/ /*============================================*/ /* S U B R O U T I N E S */ /*============================================*/ /*************************************/ /* Subroutine to list error messages */ /*************************************/ msgrtn: procedure expose isfmsg isfmsg2. tot_failed jname. jobid. ix /************************************************/ /* The isfmsg variable contains a short message */ /************************************************/ if isfmsg = '' | Strip(isfmsg) = 'PRINT CLOSED' , | Strip(isfmsg) = '*BOTTOM OF DATA REACHED*' , then nop /* normal messages from print */ else do Say ' ** Error processing' jname.ix jobid.ix Say ' **' isfmsg tot_failed = tot_failed + 1 /* add 1 to failed total */ /****************************************************/ /* The isfmsg2 stem contains additional descriptive */ /* error messages */ /****************************************************/ /* do ix=1 to isfmsg2.0 Say "isfmsg2."ix "is:" isfmsg2.ix end */ end return /**********************************************************************/ /* Setup required vars for printing */ /**********************************************************************/ Setup_print_vars: isfprtdisp = 'SHR' isfprtdsname = "'" || outdsn || "'" isfprtmember = jobid.ix return