ANYPARM job=![""]
#                                                                Version A.02
# The SHOWJ script displays one or more jobs based on one or more a user IDs
# and/or job IDs. User IDs can be wildcarded and a list of jobs and users to
# exclude can be specified.
#
# Syntax:
#   SHOWJ [jobID ... userID ... jobID...] [- jobID - userID...]
#         [;JOBQ=qname] [;DEV=ldev] [;IP=nn.nn.nn.nn]
#         [;EXEC] [;SCHED] [;WAIT] [;SUSP]
#
# See 'help' text below for parameter descriptions.
#
# Author: Jeff Vance, CSY, May 2004. Based on the ABORTJ script from 1998.
#
if pos('entry=',"!job") = 0 then
   # ** main entry **
   if '!job' = '?' then
      echo
      echo   Usage: ![word(hpfile,'.')] [jobIDs userIDs...] &
                                        [- jobIDs - userIDs...]
      echo                [;JOBQ= qname] [;DEV=ldev] [;IP=ip_addr]
      echo                [;EXEC] [;SCHED] [;WAIT] [;SUSP]
      echo
      echo   where: jobID   :: [#]J|Snnn
      echo          userID  :: [@J|S:][jobname,]username[.acctname] or
      echo                     @  or @J  or @S
      echo                   * a specified jobname, even '@', means that a
      echo                     jobname must be present to match.
      echo                   * an omitted jobname means the jobname does not
      echo                     affect the selection, it is ignored.
      echo                   * a null jobname ',' means a jobname must not be
      echo                     present in order to match.
      echo
      echo          qname   :: the name of a job queue (jobs only).
      echo          ldev    :: a valid LDEV number.
      echo          ip_addr :: an IP address in dotted form (sessions only).
      echo          EXEC    = show only executing jobs that match.
      echo          SCHED   = show only scheduled jobs that match.
      echo          WAIT    = show only waiting jobs that match.
      echo          SUSP    = show only suspended jobs that match.
      echo                    EXEC, SCHED, WAIT, SUSP can be combined, e.g.,
      echo                    ;exec ;wait
      echo
      echo  The default is to show all job/sessions that match the jobID &
            specifications.
      echo  If jobID is omitted '@' is assumed.
      echo
      echo  Note: jobname, username, acctname, qname, ldev and ip address can &
            be
      echo        wildcarded.
      echo  Note: the @S|J: format means to match only jobs or only sessions &
            for the
      echo        supplied user.acct.
      echo
      echo  Jobs/sessions matching IDs after a minus ('-') are skipped and &
            thus not
      echo  displayed.
      echo
      echo  Multiple jobIDs and userIDs can *only* be separated by a space &
            since a
      echo  comma is part of the userID specification.
      echo
      echo  The number of jobs and sessions as well as the number skipped (due &
            to
      echo  filtering) are reported at the end. Additionally, 3 CI variables &
            are set
      echo  to contain these values: SJ_NUM_SESSIONS, SJ_NUM_JOBS, and &
            SJ_NUM_SKIPPED.
      echo
      return
   endif

   setvar _sj_job ups("!job")
   if setvar(_sj_pos,pos(';',_sj_job)) > 0 then
      # remove spaces beyond the 1st semicolon for easier parsing
      setvar _sj_job repl(_sj_job,' ','',,_sj_pos)
   endif

   # initialze counters
   setvar _sj_cnt      0
   setvar _sj_j_cnt    0
   setvar _sj_s_cnt    0
   setvar _sj_skip_cnt 0

   # ** parse the command line. The strategy is to extract first the filters,
   #    such as IP= or ;EXEC. Then parse out minus job/sessions and last parse
   #    the target job/session ID(s) or user name(s).
   #
   # parse out JOBQ=
   setvar _sj_jobq_filter ''
   if setvar(_sj_pos,pos(';JOBQ=',_sj_job)) > 0 then
      setvar _sj_jobq_filter word(_sj_job,,2,,_sj_pos+1)
      # remove jobq= and queuename
      setvar _sj_job xword(_sj_job,,,,_sj_pos+1)
      setvar _sj_job xword(_sj_job,,,,_sj_pos+1)
   endif

   # parse out DEV= (or LDEV=)
   setvar _sj_ldev_filter ''
   if (setvar(_sj_pos,pos(';DEV=',_sj_job)) > 0) or &
      (setvar(_sj_pos,pos(';LDEV=',_sj_job)) > 0) then
      setvar _sj_ldev_filter word(_sj_job,,2,,_sj_pos+1)
      # remove dev= and ldev number
      setvar _sj_job xword(_sj_job,,,,_sj_pos+1)
      setvar _sj_job xword(_sj_job,,,,_sj_pos+1)
   endif

   # parse out IP=
   setvar _sj_ip_filter ''
   if setvar(_sj_pos,pos(';IP=',_sj_job)) > 0 then
      setvar _sj_ip_filter word(_sj_job,,2,,_sj_pos+1)
      # remove ip= and ip address
      setvar _sj_job xword(_sj_job,,,,_sj_pos+1)
      setvar _sj_job xword(_sj_job,,,,_sj_pos+1)
   endif

   # parse out ;EXEC ;SCHED...filter options
   setvar _sj_state_filter ''
   if setvar(_sj_pos,pos(';SCHED',_sj_job)) > 0 then
      setvar _sj_state_filter _sj_state_filter + 'SCHED '
      # remove filter option
      setvar _sj_job xword(_sj_job,,,,_sj_pos+1)
   endif
   if setvar(_sj_pos,pos(';WAIT',_sj_job)) > 0 then
      setvar _sj_state_filter _sj_state_filter + 'WAIT '
      # remove filter option
      setvar _sj_job xword(_sj_job,,,,_sj_pos+1)
   endif
   if setvar(_sj_pos,pos(';SUSP',_sj_job)) > 0 then
      setvar _sj_state_filter _sj_state_filter + 'SUSP '
      # remove filter option
      setvar _sj_job xword(_sj_job,,,,_sj_pos+1)
   endif
   if setvar(_sj_pos,pos(';EXEC',_sj_job)) > 0 then
      setvar _sj_state_filter _sj_state_filter + 'EXEC EXEC* '
      # remove filter option
      setvar _sj_job xword(_sj_job,,,,_sj_pos+1)
   endif

   # see if any jobs are being skipped (minus list)
   setvar _sj_skip_jobIDs ''
   setvar _sj_skip_users  ''
   setvar _sj_skip_types  ''
   if setvar(_sj_pos,pos('-',_sj_job)) > 0 then
      # create two separate lists of jobIDs and userIDs to be skipped
      setvar _sj_i 1
      while setvar(_sj_j,&
            word(_sj_job,'-',setvar(_sj_i,_sj_i+1),,_sj_pos)) <> "" do
         if setvar(_sj_char,lft(_sj_j,1)) = '#' or &
            ((_sj_char='J' or _sj_char='S') and numeric(rht(_sj_j,-2))) then
            # have a jobID
            setvar _sj_skip_jobIDs _sj_skip_jobIDs+" #"+(_sj_j-'#')
         elseif _sj_j = '@' then
            echo
            echo Minusing all (-@) means no job/sessions will be selected.
            echo
            escape
         else
            # have '[@S|@J:][jobname,]user[.acct]' or '@s' or '@j' or '@'
            if _sj_j = '@J' or _sj_j = '@S' then
               # convert to generic @J|S:jname,usr.acct format
               setvar _sj_j _sj_j+":@.@"
            endif
            # separate @J:/@S: from user.acct and place J,S,or @ into
            # its own "array" (_sj_skip_types).
            if pos(':',_sj_j) > 0 then
               setvar _sj_skip_types _sj_skip_types+str(_sj_j,2,1)+' '
               setvar _sj_j xword(_sj_j,':')
            else
               setvar _sj_skip_types _sj_skip_types+'@ '
            endif
            setvar _sj_skip_users _sj_skip_users + " " + _sj_j
         endif
      endwhile
      setvar _sj_job lft(_sj_job,_sj_pos-1)
   endif

   # if, after all of the above parsing and extracting, there is nothing left
   # set the jobID to '@' as the default
   if _sj_job = '' then
      setvar _sj_job '@'
   endif

   # parse target jobIDs and userIDs (non-skipped list). Note this is basically
   # the same code as used in the minusing logic above.
   setvar _sj_jobIDs ''
   setvar _sj_users  ''
   setvar _sj_types  ''
   setvar _sj_i 0
   while setvar(_sj_j,word(_sj_job,' ',setvar(_sj_i,_sj_i+1))) <> "" do
      if setvar(_sj_char,lft(_sj_j,1)) = '#' or &
         ((_sj_char='J' or _sj_char='S') and numeric(rht(_sj_j,-2))) then
         # have a [#]job or [#]session id
         setvar _sj_jobIDs _sj_jobIDs+"#"+(_sj_j-'#')+" "
      elseif numeric(_sj_j) then
         # common syntax error, skip this one
         setvar cierror 1509
         echo "!_sj_j": !hpcierrmsg ... or,
         setvar cierror 3080
         echo ![rpt(" ",len(_sj_j)+3)] !hpcierrmsg
      else
         # have '[@S|@J:][jobname,]user[.acct]' or '@s' or '@j' or '@'
         if _sj_j = '@' then
            # append @J and @S to orig jobID string and repeat loop
            setvar _sj_job _sj_job + " @J @S "
         else
            if _sj_j = '@J' or _sj_j = '@S' then
               # convert to generic @J|S:usr.acct format
               setvar _sj_j _sj_j+":@.@"
            endif
            # separate @J:/@S: from user.acct and place J,S,or @ into
            # its own "array" (_sj_types).
            if pos(':',_sj_j) > 0 then
               setvar _sj_types _sj_types+str(_sj_j,2,1)+' '
               setvar _sj_j xword(_sj_j,':')
            else
               setvar _sj_types _sj_types+'@ '
            endif
            setvar _sj_users _sj_users+" "+_sj_j
         endif
      endif
   endwhile

   # execute SHOWJOB @ ;JOBQ command redirected to disk
   errclear
   continue
   showjob ;jobq >sjtmp
   if hpcierr > 0 then
      echo !hpcierrmsg
      escape !cierror
   endif

   # display header line
   echo &
JobNum  State InPri JIn JList JobQ     Introduced  Job Name
   echo

   # read SHOWJOB output and display matches
   continue
   xeq !hpfile entry=alt_showjob <sjtmp

   # display final stats
   echo
   if _sj_cnt > 0 then
      echo     Number of sessions displayed: !_sj_s_cnt
      echo     Number of jobs     displayed: !_sj_j_cnt
      echo
   endif
   echo       Total: !_sj_cnt    Skipped: !_sj_skip_cnt
   echo

   # return these statistics to the user via CI variables
   setvar SJ_NUM_JOBS     _sj_j_cnt
   setvar SJ_NUM_SESSIONS _sj_s_cnt
   setvar SJ_NUM_SKIPPED  _sj_skip_cnt
   # cleanup
   deletevar _sj_@
   return


else
   # alternate entry points
   setvar _sj_entry word('!job',,-1)
   # remove entry=name from parm line
   setvar _sj_parm lft('!job',pos('entry=','!job')-1)

#### 'alt_showjob' entry ####
if _sj_entry = 'alt_showjob' then
   #   Returns: _sj_cnt, _sj_j_cnt and _sj_s_cnt, _sj_skip_cnt
   #   Redirection: input from :showjob ;jobq
   # This entry determines if each job record in SHOWJOB matches the user
   # criteria. If so, it is displayed to $stdlist. If not, it is quietly
   # skipped, though a skip count is tracked.
   #
   setvar _sj_eof finfo(hpstdin,'eof')
   setvar _sj_i 0
   while setvar(_sj_i,_sj_i+1) <= _sj_eof do
      # ** read each record of the showjob output file
      if lft(setvar(_sj_job,word(setvar(_sj_rec,rtrim(input())))),1) = '#' then
         # found a #J or #S job record
         # parse out the :showjob user string: '[jname,]user.acct'
         setvar _sj_usr word(_sj_rec," ",-1)
         # extract jobname from :showjob's user.acct
         if pos(',',_sj_usr) = 0 then
            setvar _sj_jn ''
         else
            setvar _sj_jn word(_sj_usr)
            setvar _sj_usr xword(_sj_usr)
         endif
         # extract :showjob job type as 'J' or 'S'
         setvar _sj_ty str(_sj_job,2,1)

         # does this showjob record match the target jobID
         setvar _sj_do_it pos(_sj_job+' ',_sj_jobIDs) > 0
         if not _sj_do_it and _sj_users <> '' then
            # no jobID match, check for userID match
            setvar _sj_skipx 0
            while not (_sj_do_it) and setvar(_sj_u,word(_sj_users,' ',&
                                         setvar(_sj_skipx,_sj_skipx+1)))<>'' do
               setvar _sj_do_it ( &
                          pmatch(word(_sj_types,,_sj_skipx),_sj_ty) and &
                          pmatch(word(_sj_u,',',-1),_sj_usr) and &
                          (pos(',',_sj_u) = 0 or &
                          ((_sj_jn = '' and pos(',',_sj_u) = 1) or &
                           (_sj_jn <> '' and pos(',',_sj_u) > 1) and &
                            (pmatch(word(_sj_u),_sj_jn)))) )
               # job types match, user.accts match, and jname match per the
               # version A.01 comments at the end of this script
            endwhile
         endif

         # ** process all jobID and userID minusing
         # skip job based on job number?
         setvar _sj_do_it (_sj_do_it and &
                           pos(_sj_job+' ',_sj_skip_jobIDs+' ') = 0)

         # skip job based on the userID skip list?
         if _sj_do_it and _sj_skip_users <> '' then
            # process user IDs to skip...
            setvar _sj_skipx 0
            while _sj_do_it and &
               setvar(_sj_u,word(_sj_skip_users,' ', &
                                   setvar(_sj_skipx,_sj_skipx+1)))<>''
               setvar _sj_do_it not ( &
                          pmatch(word(_sj_skip_types,,_sj_skipx),_sj_ty) and &
                          pmatch(word(_sj_u,',',-1),_sj_usr) and &
                          (pos(',',_sj_u) = 0 or &
                          ((_sj_jn = '' and pos(',',_sj_u) = 1) or &
                           (_sj_jn <> '' and pos(',',_sj_u) > 1) and &
                            (pmatch(word(_sj_u),_sj_jn)))) )
               # job types match, user.accts match, and jname match per the
               # version A.01 comments at the end of this script
            endwhile
         endif

         # ** process all other selection filters. Note: don't optimize for job
         #    type = 'S','J' or else the IP and JOBQ filters won't work
         #    correctly.
         # ;JOBQ= ?
         if _sj_do_it and _sj_jobq_filter <> '' then
            if _sj_ty = 'J' then
               setvar _sj_q word(_sj_rec,' ',-4)
            else
               setvar _sj_q ''
            endif
            setvar _sj_do_it pmatch(_sj_jobq_filter,_sj_q)
         endif

         # ;SCHED ; WAIT ;etc. ?
         setvar _sj_do_it (_sj_do_it and &
                (_sj_state_filter = '' or  &
                 pos(word(_sj_rec,' ',2),_sj_state_filter) > 0) )

         # ;IP= ?
         setvar _sj_ip ''
         if _sj_do_it and _sj_ip_filter <> '' then
            if _sj_ty = 'J' then
               setvar cierror 0
            else
               setvar _sj_ip jinfo(_sj_job,'ipaddr',cierror)
            endif
            setvar _sj_do_it (cierror = 0 and &
                              pmatch(_sj_ip_filter,_sj_ip) )
         endif

         # ;DEV= ?
         if _sj_do_it and _sj_ldev_filter <> '' then
            if _sj_ty = 'S' then
               setvar _sj_in word(_sj_rec,' ',-5)
            else
               setvar _sj_in word(_sj_rec,' ',-6)
            endif
            setvar _sj_do_it pmatch(_sj_ldev_filter,_sj_in)
         endif

         # ** display the matching job/session
         if _sj_do_it then
            echo !_sj_rec
            if _sj_ip <> '' then
               echo         !_sj_ip
            endif
            setvar _sj_cnt _sj_cnt+1
            if _sj_ty = 'S' then
               setvar _sj_s_cnt _sj_s_cnt+1
            else
               setvar _sj_j_cnt _sj_j_cnt+1
            endif
         else
            setvar _sj_skip_cnt _sj_skip_cnt+1
         endif
      endif
   endwhile
   return
endif
endif

# Version History:
 A.02 JV 05/19/04 Return the final counts (# sessions and job displayed and # of
         of J/S's skipped in the CI variables: SJ_NUM_JOBS, SJ_NUM_SESSIONS,
         SJ_NUM_SKIPPED.
 A.01 JV 05/16/04 Initial version.  Note on jobnames: jobname matching follows
         the same rules as for PAUSE and JOBCNT(). That is, if the jobname is
         specified then only job/sessions with jobnames will be considered for
         further matching. If the jobname is omitted then it is not used at all
         in determining which job/sessions match. If a null jobname is provided
         e.g. :showj @s:,foo@.ba@, then only job/sessions without jobnames are
         considered for further matching. These rules apply to both the
         selection step and the "minusing" step.

*** end of SHOWJ script ***