Google
 

Trailing-Edge - PDP-10 Archives - CFS_TSU04_19910205_1of1 - update/t20src/diuque.b36
There are 4 other files named diuque.b36 in the archive. Click here to see a list.
%TITLE 'DIUQUE - Queue Handling Routines'

MODULE DIUQUE (IDENT = '252',
               LANGUAGE(BLISS36),
               ENTRY(q$init,   ! Open the queue file and set things up
                     q$enter,  ! Enter a request in the queue
                     q$delete, ! Delete a request
                     q$modify, ! Modify a request
                     q$find,   ! Find a request, return req. block(s)
                     q$pick,   ! Pick a request for processing
                     q$reque   ! Reque a (already picked) request
                    )
              ) =
BEGIN
!++
!	COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1986.
!	ALL RIGHTS RESERVED.
!
!	THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED  AND
!	COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH
!	THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE.   THIS  SOFTWARE  OR
!	ANY  OTHER  COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE
!	AVAILABLE TO ANY OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE
!	SOFTWARE IS HEREBY TRANSFERRED.
!
!	THE INFORMATION IN THIS SOFTWARE IS  SUBJECT  TO  CHANGE  WITHOUT
!	NOTICE  AND  SHOULD  NOT  BE CONSTRUED AS A COMMITMENT BY DIGITAL
!	EQUIPMENT CORPORATION.
!
!	DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF
!	ITS SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
!
! FACILITY:    DIU-10/20. (Data Interchange Utility)
!
! ABSTRACT:    This module provides queue management for DIU-10/20.
!
! ENVIRONMENT: BLISS-36 V4, XPORT V4, RMS-10/20 V3
!              TOPS-10 V7.03 or TOPS-20 V6.1
!
!   The queue is maintained as an RMS relative file.  The request-ID is
!   the record number of the request record.  Record 1 is a header record,
!   with pointers to two record chains:  the chain of pending requests,
!   ordered by priority, and the chain of deleted records.  Deleted records
!   are never actually deleted from the RMS file, but are reused.
!
! AUTHOR: Rick Fricchione      CREATION: August 10, 1984
! HISTORY:
!
!  252	Remove library of CONDIT.
!	Sandy Clemens  1-Jul-86
!
!  234  Change library of RMSUSR to RMSINT.
!       Gregory A. Scott 17-Jul-86
!
!  174  Remove library of TOPS20, use routine wild_match instead of wild jsys.
!       Gregory A. Scott 20-May-86
!
!  160  If the queue file was written  by another version we got all  confused.
!       The problem was that  if the $GET  for record 1  wouldn't work then  we
!       decided that the queue  file didn't exist.  Now  we check for  RMS$_RNF
!       error to determine that  the queue file is  virgin, which is the  right
!       way to do it.
!       Gregory A. Scott 14-May-86
!
!  152  Routines kill_job and q$copy_req_block were defined  as  external  here
!       but were never called.  Make queue initializing message a real event.
!       Gregory A. Scott 11-May-86
!
!  127  Remove hack to Q$MODIFY where if you were given a negative prerequisite
!       request id then you  would turn on the  SEQ_CONTINUE bit.  This is  all
!       removed because of the new (sensible) use of /PREREQ and /SEQUENCE.
!       Gregory A. Scott 26-Apr-86
!
!  122  Protect the QUE file 0 under TOPS-20.
!       Gregory A. Scott 22-Apr-86
!
!  111	Change queue file initialization messge.
!	Andy Puchrik	3-Apr-86
!
!  102  Change routine Q$FIND_NODE to Q$FNODE so that LINK doesn't grab Q$FIND.
!       Gregory A. Scott 28-Mar-86
!
!     DPR0001 V01-04		Doug Rayner			29-Jul-85
!	      Some minor changes for TOPS-10.  Put the QUE file in SYS:.
!	      Replace WILD% JSYS with call to routine that emulates it.
!	      Support [P,Pn]'s in find routine.
!
!     RDF0001 V01-03          Rick Fricchione                 21-Aug-1984
!             Modify for DIU.  Make it work with the new RMS-20. Fix some
!             bugs in the dependency code, and clean up to be readable!
!
!     AWN0001 V01-02          Andrew Nourse                   - no date -
!             Put in entry points, and clean up code.
!
!--
!**************************************************************************
!            L I B R A R Y   A N D   R E Q U I R E   F I L E S 
!**************************************************************************

LIBRARY 'DIU';                          ! DIU Data structures
LIBRARY 'RMSINT';                       ! RMS symbols
LIBRARY 'BLI:XPORT';                    ! XPORT symbols
!****************************************************************************
!                  F O R W A R D    R O U T I N E
!****************************************************************************

FORWARD ROUTINE
    q$init,                             ! Open the queue file and set things up
    q$enter,                            ! Enter a request in the queue
    q$delete,                           ! Delete a request
    q$modify,                           ! Modify a request
    q$find,                             ! Find a request, return req. block(s)
    q$$find_ch,                         ! Condition handler for q$find
    q$pick,                             ! Pick a request for processing
    q$reque,                            ! Reque a (already picked) request
    q$$lower_priority,                  ! Test priority of two requests
    q$$assign_sequence_no,              ! Assign a new sequence number
    q$$match_block;                     ! See if two request records match
!*****************************************************************************
!**                           M A C R O S
!*****************************************************************************

MACRO
    queue$$_filespec =
    %IF NOT %SWITCHES(DEBUG)
        %THEN %IF %SWITCHES (TOPS20)          ! Production version of file
                  %THEN 'SYSTEM:DIU.QUE;P000000'        ! Protection 0
              %FI
              %IF %SWITCHES (TOPS10)
              %THEN 'STD:DIU.QUE'
              %FI
        %ELSE %IF %SWITCHES (TOPS20)
                  %THEN 'SYSTEM:DIUDEB.QUE;P000000'     ! Protection 0
              %FI

              %IF %SWITCHES (TOPS10)
                  %THEN 'STD:DIUDEB.QUE'
              %FI
     %FI %,

! The header record uses certain fields as pointers to records.  Here
! are the correspondences.

    HDR$H_DELETED_CHAIN = DIU$H_DEPENDENT_ID %,
    HDR$H_PENDING_CHAIN = DIU$H_NEXT_RECORD %,
    HDR$H_LENGTH = DIU$H_LENGTH %,
    HDR$H_FIRST_FREE = DIU$H_PREV_RECORD %;

LITERAL
    minute = %O'1000000' / (24*60),     ! One minute, universal date/time form
    requeue_time = 10*minute;           ! Ten minutes -- requeue interval

OWN
    q_fab : $FAB_DECL;                  ! FAB for the queue file
!*************************************************************************
!                   E X T E R N A L   R O U T I N E S 
!*************************************************************************

EXTERNAL ROUTINE
    wild_match,				! Do a WILD% JSYS or a simulation
    l$event : NOVALUE,                  ! Write event to system log file
    q$req_block_init : NOVALUE,         ! Init a request block
    q$release_chain  : NOVALUE,         ! Release chain of blocks in heap space
    q$valid_req_block,                  ! Validate a request block
    q$fnode,                            ! Find a node in a filespec buffer
    s$time,                             ! Return current system date/time
    DIU$ABORT,                          ! DIU conditon handler
    rms$efail        : NOVALUE,         ! RMS error message printer
    rms$failure      : NOVALUE;         ! Default RMS failure handler
!***********************************************************************
!                 D E B U G G I N G   R O U T I N E S
!***********************************************************************
%IF %SWITCHES (DEBUG)
%THEN
ROUTINE q$$debug_routine (arg) = 0;
%FI
!*************************************************************************
!                            Q $ I N I T 
!*************************************************************************
GLOBAL ROUTINE q$init =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!   This routine opens the queue file, checks to see if the header
!   record exists and creates it if it doesn't, and sets up various
!   module-wide parameters.
!
! FORMAL PARAMETERS:
!   NONE
!
! IMPLICIT INPUTS:
!   NONE
!
! IMPLICIT OUTPUTS:
!   NONE
!
! ROUTINE VALUE and
! COMPLETION CODES:
!   DIU$_NORMAL         - queue initialized OK
!   some RMS code       - RMS error prevented queue initialization
!
! SIDE EFFECTS:
!   NONE
!
!--

LOCAL rab : $RAB_DECL,
      req_block : $DIU_BLOCK,
      next_record;

ENABLE DIU$ABORT;                       ! Enable condition handler

! Initialize the queue $FAB

$FAB_INIT (FAB=q_fab,            FNA=queue$$_filespec, 
           FAC=(GET,PUT,DEL,UPD),ORG=REL,
           SHR=(GET,PUT,DEL,UPD),FOP=CIF,
           RAT=BLK,              MRS=DIU$K_CHAR_COUNT);

! Initialize the queue $RAB 

$RAB_INIT (RAB=rab, FAB=q_fab, RAC=KEY);

! Create or open the file as appropriate

$CREATE (FAB=q_fab);
IF NOT $RMS_STATUS_OK (q_fab)
THEN SIGNAL (DIU$_DAMAGED, .q_fab[FAB$H_STS]);

! Connect RAB to FAB

$CONNECT (RAB=rab);
IF NOT $RMS_STATUS_OK (rab)
THEN SIGNAL (DIU$_DAMAGED, .rab[RAB$H_STS]);

! Look up record 1 (header record).

$RAB_STORE (RAB=rab, KBF=(UPLIT (1)), UBF=req_block, USZ=DIU$K_LEN);
$GET (RAB=rab);

! Check the status returned from the $GET.  If it was record not found, then
! we must have created a new queue file here.

IF .rab[RAB$H_STS] EQL RMS$_RNF         ! If it was record not found
THEN BEGIN                              ! Then we must have a new queue file
     L$EVENT (DIU$_INIT_QUEUE, 0, 0);   ! Give message to log file
     q$req_block_init (req_block);      ! Get a clean request block

     ! Header record is considered to be deleted.  There is as yet no
     ! chain of deleted records so DIU$H_NEXT_RECORD is set to zero.
     ! DIU$H_REQUEST_ID is set to 2 (the first available record).

     req_block[DIU$V_DELETED]       = 1;
     req_block[HDR$H_DELETED_CHAIN] = 0;
     req_block[HDR$H_PENDING_CHAIN] = 0;
     req_block[HDR$H_FIRST_FREE]    = 2;
     req_block[HDR$H_LENGTH]        = DIU$K_LEN;
     $RAB_STORE (RAB=rab, RBF=req_block, RSZ=DIU$K_CHAR_COUNT);
     $PUT (RAB=rab);                    ! Put the header record there
     IF NOT $RMS_STATUS_OK (rab)        ! Punt if the put didn't work
     THEN SIGNAL (DIU$_DAMAGED, .rab[RAB$H_STS]);
     END

! The status returned wasn't record not found.  Make sure that the $GET worked,
! the length is proper, and the queue file is the proper version.

ELSE IF NOT ($RMS_STATUS_OK (rab)
             AND .req_block[HDR$H_LENGTH] EQL DIU$K_LEN
             AND .req_block[DIU$H_VERSION] EQL DIU$K_VERSION)
     THEN SIGNAL(DIU$_ANOTHER_VERSION, .rab[RAB$H_STS]);

! Now scan through the chain, requeuing any active requests (presumably
! left over from a system crash).  Signal errors if there is/was a punt

next_record = .req_block[HDR$H_PENDING_CHAIN];
WHILE .next_record NEQ 0 
DO BEGIN
   $RAB_STORE (RAB=rab, KBF=next_record, UBF=req_block, USZ=DIU$K_LEN);
   $GET (RAB = rab);
   IF NOT $RMS_STATUS_OK (rab)
   THEN BEGIN
        $DISCONNECT (RAB = rab);
        SIGNAL (DIU$_DAMAGED, .rab[RAB$H_STS])
        END;
   next_record = .req_block[DIU$H_NEXT_RECORD];
   IF .req_block[DIU$V_ACTIVE]
   THEN BEGIN                           ! Free record so requeue can hack on it
        $FREE (RAB = rab, ERR = rms$failure);
        Q$REQUE(.req_block[DIU$H_REQUEST_ID]);
        END;
   END; %(while more records)%

! Disassociate ourselves with the file and return OK

$DISCONNECT (RAB=rab, ERR=rms$failure);

RETURN (DIU$_NORMAL);

END;                                ! End of q$init
!*********************************************************************
!*                       Q $ E N T E R 
!*********************************************************************
GLOBAL ROUTINE q$enter (p_req_block) =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!   Enter a request in the queue.  The information in the request block
!   is copied to a record which is written to the RMS file containing
!   the queue.  The new record is linked into the chain of pending
!   requests in front of the first request with lower priority (i.e.,
!   the chain is orderd by priority).
!
! FORMAL PARAMETERS:
!   p_req_block         - pointer to request block
!
! IMPLICIT INPUTS:
!   NONE
!
! IMPLICIT OUTPUTS:
!   The RMS queue file is updated with the new entry.
!   DIU$H_REQUEST_ID is updated with the sequence number assigned
!   to this request.
!
! ROUTINE VALUE and
! COMPLETION CODES:
!   DIU$_NORMAL                 - request entered OK
!   DIU$_INVALID_REQUEST        - the request block is invalid
!   DIU$_RMS_ERROR              - unexpected RMS error
!
! SIDE EFFECTS:
!   The header record is updated to reflect the sequence number assigned.
!
!--

BIND
        req_block = .p_req_block : $DIU_BLOCK;

LOCAL
        rab       : $RAB_DECL,
        tmp_block : $DIU_BLOCK,
        previous,
        next,
        req_id,
        retcode;

IF .req_block[DIU$H_REQUEST_ID] NEQ 0
   THEN SIGNAL (DIU$_INVALID_REQUEST);
! They can't give us the id, we assign it.


IF NOT (retcode = Q$VALID_REQ_BLOCK(req_block))
   THEN RETURN (SIGNAL (.retcode));
! Validate the contents of the block

req_id = req_block[DIU$H_REQUEST_ID] = Q$$ASSIGN_SEQUENCE_NO();
IF .req_ID EQL -1
    THEN RETURN (DIU$_QUEUE_FULL);
! Get the id and return if the queue was full

$RAB_INIT (RAB=rab, FAB=q_fab, RAC=KEY);
$CONNECT (RAB=rab, ERR=rms$failure);
$RAB_STORE (RAB=rab, RBF=req_block, RSZ=DIU$K_CHAR_COUNT,KBF=req_id);
$FIND (RAB=rab, ERR=rms$failure);
$UPDATE (RAB=rab, ERR=rms$failure);
! Assign the next sequence number, stuff into record, stuff current
! date/time into record, and write the record to the queue file.


! Now scan the list of pending requests looking for the first of
! lower priority.  First get the header record, which anchors the chain.

$RAB_STORE (RAB=rab,KBF=(UPLIT (1)),UBF=tmp_block,USZ=DIU$K_LEN);
$GET (RAB=rab,ERR=rms$failure);
! Get the header record, and prepare to scan the chain of pending requests
! looking for the first one with lower priority.

previous = 1;                       
next = .tmp_block[HDR$H_PENDING_CHAIN];
! Note the header and first *real* record

WHILE .next NEQ 0 DO
   BEGIN
      $RAB_STORE (RAB=rab,KBF=next,UBF=tmp_block,USZ=DIU$K_LEN);
      $GET (RAB=rab,ERR=rms$failure);
      IF Q$$LOWER_PRIORITY (tmp_block, req_block)
      THEN BEGIN
             req_block[DIU$H_PREV_RECORD] = .previous;
             req_block[DIU$H_NEXT_RECORD] = .next;
             ! We found one lowlier than us.  Point to previous
             ! and next records.

             $RAB_STORE(RAB=rab,KBF=req_id,RBF=req_block,RSZ=DIU$K_CHAR_COUNT);
             $FIND (RAB=rab, ERR=rms$failure);
             $UPDATE (RAB=rab, ERR=rms$failure);

             $RAB_STORE (RAB=rab,KBF=previous,UBF=tmp_block,USZ=DIU$K_LEN);
             $GET (RAB=rab,ERR=rms$failure);
             tmp_block[DIU$H_NEXT_RECORD] = .req_id;
             $UPDATE (RAB=rab,ERR=rms$failure);
             ! Get previous record and make us its next

             ! Get next record and make us its previous
 
             $RAB_STORE (RAB=rab, KBF=next);
             $GET (RAB=rab, ERR=rms$failure);
             tmp_block[DIU$H_PREV_RECORD] = .req_id;
             $UPDATE (RAB=rab, ERR=rms$failure);
             $DISCONNECT (RAB=rab, ERR=rms$failure);
             RETURN (DIU$_NORMAL)

            END; %(found lower priority)%

        next = .tmp_block[DIU$H_NEXT_RECORD];
        previous = .tmp_block[DIU$H_REQUEST_ID];
        ! Were it guys...

   END; %(while)%

$RAB_STORE (RAB=rab,KBF=req_id,RBF=req_block,RSZ=DIU$K_CHAR_COUNT);
$FIND (RAB=rab,ERR=rms$failure);
req_block[DIU$H_PREV_RECORD] = .previous;
req_block[DIU$H_NEXT_RECORD] = 0;
$UPDATE (RAB = rab, ERR = rms$failure);
$RAB_STORE (RAB=rab,KBF=previous,RBF=tmp_block,RSZ=DIU$K_CHAR_COUNT);
$FIND (RAB=rab,ERR=rms$failure);
tmp_block[DIU$H_NEXT_RECORD] = .req_id;
$UPDATE (RAB=rab,ERR=rms$failure);
$DISCONNECT (RAB=rab,ERR=rms$failure);
! If we fell out of the loop, we are the lowliest guy.  Just point
! previous at us and return.

RETURN (DIU$_NORMAL);

END;                                ! End of q$enter
!************************************************************************
!                     Q $ D E L E T E 
!************************************************************************
GLOBAL ROUTINE q$delete (request_ID) =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!   Delete a request from the queue.
!
! FORMAL PARAMETERS:
!   request-ID          - the request-ID (record no.) of the req. to be deleted
!
! IMPLICIT INPUTS:
!   NONE
!
! IMPLICIT OUTPUTS:
!   The entry is marked as deleted and is inserted at the head of the
!   deleted entry queue.
!
! ROUTINE VALUE and
! COMPLETION CODES:
!   DIU$_NORMAL                 - request entered OK
!   DIU$_INVALID_REQUEST        - invalid request block presented
!   DIU$_REQ_NOT_FOUND          - request not found in queue
!
! SIDE EFFECTS:
!   NONE
!
!--

    LOCAL
        rab       : $RAB_DECL,
        req_block : $DIU_BLOCK,         ! Request block being deleted
        hdr_block : $DIU_BLOCK,         ! Header block
        previous,
        next;

IF .request_ID LEQ 1 THEN SIGNAL (DIU$_INVALID_REQUEST);
! Can't delete record 0 or the header record..

$RAB_INIT(RAB=rab,FAB=q_fab,RAC=KEY);
$CONNECT(RAB=rab,ERR=rms$failure);
$RAB_STORE(RAB=rab,KBF = request_ID,UBF=req_block,USZ=DIU$K_LEN);
$GET(RAB=rab,ERR=rms$failure);
! Get the request they wish to delete...

IF (NOT $RMS_STATUS_OK (rab)) OR .req_block[DIU$V_DELETED]
   THEN BEGIN
          $DISCONNECT (RAB = rab);
          SIGNAL (DIU$_REQ_NOT_FOUND);
          RETURN (0);
        END;
! If its already deleted, or its not there, just fail

req_block[DIU$V_DELETED] = 1;
$UPDATE (RAB = rab, ERR = rms$failure);
! Mark the request as deleted.

previous = .req_block[DIU$H_PREV_RECORD];
next = .req_block[DIU$H_NEXT_RECORD];
! Get ready to de-link the record

IF .previous NEQ 0
   THEN BEGIN
          $RAB_STORE(RAB=rab,KBF=previous);
          $GET(RAB=rab,ERR=rms$failure);
          ! Get the previous record

          req_block[DIU$H_NEXT_RECORD] = .next;
          $RAB_STORE(RAB=rab,KBF=previous,RBF=req_block,RSZ=DIU$K_CHAR_COUNT);
          $UPDATE(RAB=rab,ERR=rms$failure);
          ! Update the pointer and put it back
        END;


IF .next NEQ 0
   THEN BEGIN
          $RAB_STORE(RAB=rab,KBF=next);
          $GET(RAB=rab,ERR=rms$failure);
          ! Get the next record

          req_block[DIU$H_PREV_RECORD] = .previous;
          $RAB_STORE(RAB=rab,KBF=next,RBF=req_block,RSZ=DIU$K_CHAR_COUNT);
          $UPDATE(RAB=rab,ERR=rms$failure);
          ! Update the pointer and put it back
        END;

$RAB_STORE(RAB=rab,KBF=request_ID);
$GET(RAB=rab,ERR=rms$failure);
! Get the deleted record back

$RAB_STORE(RAB=rab,KBF=(UPLIT(1)),UBF=hdr_block,USZ=DIU$K_LEN);
$GET(RAB=rab,ERR=rms$failure);
! Get the header record back

req_block[DIU$H_NEXT_RECORD] = .hdr_block[HDR$H_DELETED_CHAIN];
hdr_block[HDR$H_DELETED_CHAIN] = .request_ID;
! Point this record at head of chain, and record 1 at this record.

$RAB_STORE(RAB=rab,KBF=request_ID,RBF=req_block,RSZ=DIU$K_CHAR_COUNT);
$FIND(RAB=rab,ERR=rms$failure);
$UPDATE(RAB=rab,ERR=rms$failure);
! Write this record out first (so system crash doesn't result
! in record 1 pointing to empty chain, thus losing deleted records)

$RAB_STORE(RAB=rab,KBF=(UPLIT(1)),RBF=hdr_block,RSZ=DIU$K_CHAR_COUNT);
$FIND(RAB=rab,ERR=rms$failure);
$UPDATE(RAB=rab,ERR=rms$failure);
$DISCONNECT(RAB=rab,ERR=rms$failure);
! NOW write the header record

RETURN(DIU$_NORMAL);

END;                                ! End of q$delete
!**********************************************************************
!**                    Q $ M O D I F Y 
!**********************************************************************
GLOBAL ROUTINE q$modify (req_ID, item_code, new_value) =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!       Modify a parameter  of a  request in  the queue.   Since modifying  the
!       priority, /AFTER,  or /DEADLINE  parameters is  likely to  result in  a
!       reordering of the queue, MODIFY is implemented as a DELETE followed  by
!       an ENTER.  We know  the ENTER will assign  the same request ID  because
!       deleted request ID's are maintained in a LIFO stack.
!
! FORMAL PARAMETERS:
!       req_ID: request ID number
!       item_code: code identifying item to change
!       new_value: new value of item
!
! IMPLICIT OUTPUTS:
!
!       The queue  file entry  is  modified.  If  the modification  alters  the
!       relative priority of the request, it will move to an appropriate  place
!       in the queue.
!
!
! ROUTINE VALUE and
! COMPLETION CODES:
!       DIU$_NORMAL: successful completion
!       DIU$_INVALID_FUNCTION: invalid item code
!       DIU$_ACTIVE: can't modify an active request
!
!--

LOCAL
        retcode,
	chain_head,
        original_req_ID,
        req_block_template : $DIU_BLOCK,
        req_block : REF $DIU_BLOCK;

! Cannot modify header record..

Q$REQ_BLOCK_INIT (req_block_template);
IF (original_req_id = req_block_template[DIU$H_REQUEST_ID] = .req_ID) LSS 2
THEN RETURN (DIU$_INVALID_REQUEST);

! Find this request

IF NOT (retcode = Q$FIND (req_block_template, chain_head))
THEN RETURN (.retcode);

! We had better have only one request block in the chain.

IF ..chain_head NEQ 0 THEN RETURN (DIU$_BUG);

! Address the request block proper

req_block = .chain_head + %UPVAL;

SELECTONE .item_code OF
SET
   [DIUQ$K_AFTER]           : req_block[DIU$G_AFTER]           = .new_value;
   [DIUQ$K_PRIORITY]        : req_block[DIU$B_PRIORITY]        = .new_value;
   [DIUQ$K_DEADLINE]        : req_block[DIU$G_DEADLINE]        = .new_value;
   [DIUQ$K_HOLDING]         : req_block[DIU$V_HOLDING]         = .new_value;
   [DIUQ$K_DEPENDENT_ID]    : req_block[DIU$H_DEPENDENT_ID]    = .new_value;
   [DIUQ$K_NOTIFY]          : req_block[DIU$Z_NOTIFY]          = .new_value;
   [DIUQ$K_SEQUENCE]        : req_block[DIU$V_SEQ_CONTINUE]    = .new_value;
   [DIUQ$K_PREREQUISITE_ID] : req_block[DIU$H_PREREQUISITE_ID] = .new_value;
   [DIUQ$K_LOG_FILESPEC]    :
            BEGIN
            MAP new_value : REF $STR_DESCRIPTOR ();
            CH$MOVE (.new_value[STR$H_LENGTH],
                     .new_value[STR$A_POINTER],
                      CH$PTR (req_block[DIU$T_LOG_FILESPEC]));
            req_block[DIU$H_LOG_FILESPEC] = .new_value[STR$H_LENGTH];
            END;
   [OTHERWISE]              : RETURN (DIU$_INVALID_REQUEST);

TES; %(select)%

! Delete the existing version of the request

IF NOT (retcode = q$delete (.req_ID))
THEN BEGIN
     q$release_chain (.chain_head);
     RETURN (DIU$_BUG);
     END;

! Zero the request id, and re-enter on the queue.  Since we take from the
! deleted chain first, it should get the same request id.

req_block[DIU$H_REQUEST_ID] = 0;

IF NOT (retcode = Q$ENTER (.req_block))
THEN BEGIN
     Q$RELEASE_CHAIN (.chain_head);
     RETURN (DIU$_BUG);
     END;

! Release the chain of request(s)

Q$RELEASE_CHAIN (.chain_head);

! Make sure it assigned the same request id.

IF .req_block[DIU$H_REQUEST_ID] NEQ .original_req_ID
THEN RETURN (DIU$_BUG);
  
RETURN (DIU$_NORMAL)                    ! Return OK
  
END;                                    ! End of q$modify
  
!**********************************************************************
!**                    Q $ F I N D 
!**********************************************************************
GLOBAL ROUTINE q$find (p_req_block, chain_returned) =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!   Find a request record, or records.  Caller can specify:
!       1) A specific request-ID (at most one record will be returned)
!       2) A wildcarded request-block (matching records are returned)
!       3) An empty (zero) request-block (all request blocks are returned)
!
! FORMAL PARAMETERS:
!   p_req_block         - pointer to a request block.
!   chain_returned      - address to store pointer to chain of request
!                         blocks.  The chain is of request blocks with
!                         one word prepended to the front of the block
!                         which is a pointer to the next block, or zero.
!                         The blocks are allocated in heap space with
!                         $XPO_GET_MEM and MUST BE FREED BY THE CALLER!
!
! IMPLICIT INPUTS:
!   NONE
!
! IMPLICIT OUTPUTS:
!   NONE
!
! ROUTINE VALUE and
! COMPLETION CODES:
!   DIU$_NORMAL                 - successful completion
!   DIU$_INVALID_REQUEST        - request block invalid
!   DIU$_QUEUE_EMPTY            - queue is empty
!   DIU$_REQ_NOT_FOUND          - can't find the request
!   DIU$_RMS_ERROR              - unexpected RMS error
!   DIU$_NO_MEMORY              - insufficient heap space to satisfy request
!
! SIDE EFFECTS:
!   NONE
!
!--
BIND
        req_block = .p_req_block : $DIU_BLOCK;

LOCAL
        rab        : VOLATILE $RAB_DECL,
        chain_head : VOLATILE,
        hdr_record : $DIU_BLOCK,
        req_ID,
        last_block,
        this_block,
        this_record : REF $DIU_BLOCK,
        next_record_number;

ENABLE
        Q$$FIND_CH(chain_head, rab);

$RAB_INIT(RAB=rab,FAB=q_fab,RAC=KEY);
$CONNECT(RAB=rab,ERR=rms$failure);
! Init our RMS blocks

! Handle the case where they gave us a specific request id.  Allocate a 
! memory chain of one, and return that to the user.

IF .req_block[DIU$H_REQUEST_ID] NEQ 0
   THEN BEGIN
        IF NOT $XPO_GET_MEM(UNITS=DIU$K_LEN+%UPVAL,RESULT=this_block)
           THEN SIGNAL (DIU$_NO_MEMORY);
        ! Get one block in heap space

        (.this_block) = 0;              
        ! Zero next pointer (since only one should come back)

        this_record = .this_block + %UPVAL;
        ! Address the request block proper

        req_ID = .req_block[DIU$H_REQUEST_ID];
        $RAB_STORE(RAB=rab,KBF=req_ID,UBF=.this_block+%UPVAL,USZ=DIU$K_LEN);
        $GET(RAB=rab);
        ! Look up the record

        IF (NOT ($RMS_STATUS_OK (rab))) OR .this_record[DIU$V_DELETED]
          THEN BEGIN
               $DISCONNECT(RAB=rab,ERR=rms$failure);
               $XPO_FREE_MEM(BINARY_DATA=(DIU$K_LEN+%UPVAL,.this_block,UNITS));
               (.chain_returned) = 0;
               RETURN (DIU$_REQ_NOT_FOUND);
                END;
        ! If there's no record, or if the record is deleted, fail. Set the
        ! return chain address to zero.

        (.chain_returned) = .this_block;
        $DISCONNECT (RAB = rab, ERR = rms$failure);
        RETURN (DIU$_NORMAL)
        ! OK, return address of block allocated to caller

        END; %(request id specified)%

! Request-ID not specified:  we have to search the queue file for matches.
! Get the header record, which contains the pending record chain pointer.

$RAB_STORE(RAB=rab,KBF=(UPLIT(1)),UBF=hdr_record,USZ=DIU$K_LEN);
$GET(RAB=rab,ERR=rms$failure);
next_record_number = .hdr_record[HDR$H_PENDING_CHAIN];
! Get header record and find pending chain

IF .next_record_number EQL 0
   THEN BEGIN
          $DISCONNECT (RAB = rab, ERR = rms$failure);
          (.chain_returned) = 0;
          RETURN (DIU$_QUEUE_EMPTY);
        END;
! No pending requests in the queue.. sorry Jack


last_block = chain_head;
! The absence of a dot is intentional

! Now scan the chain of pending records, reading each one into a block
! in heap space.  If the record matches what the caller specified, it
! is linked into the chain we're building.  Otherwise the heap space
! is released and reused.

WHILE .next_record_number NEQ 0 DO
  BEGIN
        IF NOT $XPO_GET_MEM (UNITS=DIU$K_LEN+%UPVAL,RESULT=this_block)
           THEN SIGNAL (DIU$_NO_MEMORY);
        ! Allocate a block in heap space into which to read the record

        (.this_block) = 0;              
        ! Zero next pointer

        $RAB_STORE(RAB=rab,KBF=next_record_number,
                   UBF=.this_block+%UPVAL,USZ=DIU$K_LEN);
        $GET(RAB=rab,ERR=rms$failure);
        IF NOT $RMS_STATUS_OK (rab)
           THEN SIGNAL (DIU$_RMS_ERROR);
        ! Get this record

        this_record = .this_block + %UPVAL;
        next_record_number = .this_record[DIU$H_NEXT_RECORD];
        ! Found a record.  See if it matches what caller supplied.

        IF Q$$MATCH_BLOCK(req_block,.this_record)
        THEN BEGIN
               (.last_block) = .this_block;
               last_block = .this_block;
             END
             ! Record matches, link it in to the chain
        ELSE $XPO_FREE_MEM(BINARY_DATA=(DIU$K_LEN+%UPVAL,.this_block, UNITS));
             ! Record doesn't match, release the heap space

  END; %(while more requests)%

$DISCONNECT (RAB = rab, ERR = rms$failure);
! All done.  Pass address of chain of blocks to caller and return.

(.chain_returned) = .chain_head;
IF .chain_head NEQ 0
   THEN RETURN (DIU$_NORMAL)
   ELSE RETURN (DIU$_REQ_NOT_FOUND)


END;                                ! End of q$find
!**********************************************************************
!                     Q $ $ F I N D _ C H 
!**********************************************************************
ROUTINE q$$find_ch (sig, mech, enbl) =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!   Condition handler for q$find.  Our task is to release dynamic
!   memory acquired, disconnect the RAB, and cause q$find to return
!   the appropriate failure code to its caller, by unwinding.
!
! FORMAL PARAMETERS:
!   sig         - signal vector
!   mech        - mechanism vector
!   enbl        - enable vector
!
! IMPLICIT INPUTS:
!   NONE
!
! IMPLICIT OUTPUTS:
!   NONE
!
! ROUTINE VALUE and
! COMPLETION CODES:
!   NONE
!
! SIDE EFFECTS:
!   NONE
!
!--

MAP
        sig  : REF VECTOR,
        mech : REF VECTOR,
        enbl : REF VECTOR;

BIND
        completion_code = sig[1],
        chain_head      = .enbl[1],
        rab             = .enbl[2],
        retval          = mech[%BLISS16(1)
                               %BLISS32(3)
                               %BLISS36(1)];

IF .completion_code EQL STS$K_UNWIND
   THEN RETURN (0);
! Handle unwinds through us..

IF .chain_head NEQ 0 THEN Q$RELEASE_CHAIN (.chain_head);
! If we had a chain, deallocate it..

$DISCONNECT(RAB=rab);
retval = .completion_code;
! Set the return value to what was SIGNAL'd

SETUNWIND ()
! Unwind the sucker..

END;                                ! End of q$$find_ch
!*****************************************************************
!**                   Q $ P I C K 
!*****************************************************************
GLOBAL ROUTINE q$pick (p_req_block) =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!   Pick a request from the queue for processing.
!
! FORMAL PARAMETERS:
!   p_req_block         - pointer to request block
!
! IMPLICIT INPUTS:
!   DIU$H_REQUEST_ID must contain a valid request ID.
!
! IMPLICIT OUTPUTS:
!   The request is marked as active (DIU$V_ACTIVE), and the caller's request
!   block is filled in.
!
! ROUTINE VALUE and
! COMPLETION CODES:
!   DIU$_NORMAL         - success
!   DIU$_ACTIVE         - request already active
!   DIU$_REQ_NOT_FOUND  - no such request
!   DIU$_RMS_ERROR      - unexpected RMS error
!   DIU$_HOLD           - request is on hold by operator
!
! SIDE EFFECTS:
!   NONE
!
!--

BIND
        req_block = .p_req_block : $DIU_BLOCK;

LOCAL
        rab : $RAB_DECL,
        req_ID;

IF .req_block[DIU$H_REQUEST_ID] EQL 0
   THEN RETURN (DIU$_INVALID_REQUEST);
! Cannot pick request 0 out of the queue..

$RAB_INIT(RAB=rab,FAB=q_fab);
$CONNECT(RAB=rab,ERR=rms$failure);
! Init and connect the RMS blocks

req_ID = .req_block[DIU$H_REQUEST_ID];
$RAB_STORE(RAB=rab,RAC=KEY,KBF=req_ID,UBF=req_block,USZ=DIU$K_LEN);
$GET(RAB=rab,ERR=rms$failure);
IF (NOT $RMS_STATUS_OK (rab))
    THEN BEGIN
           $DISCONNECT (RAB = rab);
           RETURN (DIU$_RMS_ERROR)
        END;
! Get the record

IF .req_block[DIU$V_DELETED]
   THEN BEGIN
          $DISCONNECT (RAB = rab);
          RETURN (DIU$_REQ_NOT_FOUND)
        END;
! Sorry, its deleted..

IF .req_block[DIU$V_ACTIVE]
   THEN BEGIN
          $DISCONNECT (RAB = rab);
          RETURN (DIU$_ACTIVE)
        END;
! Its already being used...

req_block[DIU$V_ACTIVE] = 1;
$UPDATE (RAB = rab, ERR = rms$failure);
! Request passes all tests.  Set DIU$V_ACTIVE and return.

IF (NOT $RMS_STATUS_OK (rab))
   THEN BEGIN
          $DISCONNECT (RAB = rab);
          RETURN (DIU$_RMS_ERROR);
          END;
! Check to make sure it was updated
  
$DISCONNECT (RAB = rab);
! Let go of the queue

RETURN DIU$_NORMAL;
 
END;                                ! End of q$pick
!******************************************************************
!**                    Q $ R E Q U E U E 
!******************************************************************
GLOBAL ROUTINE q$reque (req_ID) =
BEGIN
!++
!
! FUNCTIONAL DESCRIPTION:
!
!   Requeue an already picked (q$pick) request.
!
! FORMAL PARAMETERS:
!   req_ID              - request ID no. of the request
!
! IMPLICIT INPUTS:
!   NONE
!
! IMPLICIT OUTPUTS:
!   DIU$V_ACTIVE is cleared.
!
! ROUTINE VALUE and
! COMPLETION CODES:
!   DIU$_NORMAL         - OK
!   DIU$_RMS_ERROR      - unexpected RMS error
!   DIU$_ACTIVE         - request was not active
!
! SIDE EFFECTS:
!   NONE
!
!--

LOCAL
        req_block : $DIU_BLOCK,
        rab       : $RAB_DECL;

$RAB_INIT(RAB=rab,FAB=q_fab,RAC=KEY);
$CONNECT(RAB=rab,ERR=rms$failure);
$RAB_STORE(RAB=rab,RAC=KEY,KBF=req_ID,UBF=req_block,USZ=DIU$K_LEN);
$GET(RAB=rab,ERR=rms$failure);
! Get the record

IF NOT $RMS_STATUS_OK (rab)
   THEN BEGIN
          $DISCONNECT(RAB=rab);
          RETURN (DIU$_RMS_ERROR)
        END;
! It had better be found...

req_block[DIU$V_ACTIVE] = 0;
! Turn off active flag

req_block[DIU$G_AFTER] = s$time () + requeue_time;
! Set /AFTER to 10 minutes from now, to avoid infinite resource hoggage

req_block[DIU$G_REQUEUE_COUNT] = .req_block[DIU$G_REQUEUE_COUNT] + 1;
! Increment requeue count

$UPDATE(RAB=rab,ERR=rms$failure);
IF NOT $RMS_STATUS_OK (rab)
   THEN BEGIN
          $DISCONNECT(RAB=rab);
          RETURN (DIU$_RMS_ERROR);
        END;
! Update the record..

$DISCONNECT(RAB=rab);
! Get rid of queue file

RETURN (DIU$_NORMAL)
! I don't think we're in Kansas anymore Toto...

END;                                ! End of q$reque
!************************************************************
!**            Q $ $ L O W E R _ P R I O R I T Y 
!************************************************************
ROUTINE q$$lower_priority (p_block1, p_block2) =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!   Test to see if block1 is of lower priority than block2.
!
! FORMAL PARAMETERS:
!   p_block1      - pointer to request block
!   p_block2      - pointer to request block
!
! IMPLICIT INPUTS:
!   NONE
!
! IMPLICIT OUTPUTS:
!   NONE
!
! ROUTINE VALUE and
! COMPLETION CODES:
!   1   - block 1 is of lower priority than block 2
!   0   - block 1 is not of lower priority than block 2
!
! SIDE EFFECTS:
!   NONE
!
!--

BIND
        block1 = .p_block1 : $DIU_BLOCK,
        block2 = .p_block2 : $DIU_BLOCK;

IF .block1[DIU$B_PRIORITY] LSS .block2[DIU$B_PRIORITY]
   THEN RETURN (1);
! If block1's priority code is lower, it is definitely of lower priority

IF .block1[DIU$B_PRIORITY] NEQ .block2[DIU$B_PRIORITY]
   THEN RETURN (0);
! If the priority codes are unequal (that is, block1 has higher priority
! code) there's no way block1 can be of lower priority, so return false.

IF .block1[DIU$G_AFTER] NEQ .block2[DIU$G_AFTER]
   THEN RETURN (0);
IF .block1[DIU$G_AFTER] GTR .block2[DIU$G_AFTER]
   THEN RETURN (1);
! The requests have equal priorities.  Test according to /AFTER.

IF .block2[DIU$G_DEADLINE] NEQ 0
   THEN IF .block1[DIU$G_DEADLINE] EQL 0
           THEN RETURN (1)
           ELSE IF .block1[DIU$G_DEADLINE] GTR .block2[DIU$G_DEADLINE]
                   THEN RETURN (1);
! The /AFTER switches are equal.  Check /DEADLINE.

RETURN (0)
! We failed all tests.  Report that block1 is NOT of lower priority.

END;                                ! End of q$$lower_priority
!********************************************************************
!**           Q $ $ A S S I G N _ S E Q U E N C E _ N O 
!********************************************************************
ROUTINE q$$assign_sequence_no =
BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!   Assign an unused sequence number.
!
! FORMAL PARAMETERS:
!   NONE
!
! IMPLICIT INPUTS:
!   The chain of deleted records (pointed to by record 1) is checked.
!   If it's nonempty, the first such record is delinked and returned
!   to the caller.  Otherwise, we append a record to the file and return
!   its ID.
!
! IMPLICIT OUTPUTS:
!   NONE
!
! ROUTINE VALUE and
! COMPLETION CODES:
!   The sequence number assigned is returned.  If the queue is full,
!   we return -1.
!
! SIDE EFFECTS:
!   NONE
!
!--

LOCAL
        rab : $RAB_DECL,                ! RAB for queue file
        hdr_record : $DIU_BLOCK,        ! Header record
        del_record : $DIU_BLOCK,        ! Deleted record
        tmp_pointer;

$RAB_INIT(RAB=rab,FAB=q_fab,RAC=KEY);
$CONNECT(RAB=rab,ERR=rms$failure);

$RAB_STORE(RAB=rab,KBF=(UPLIT(1)),UBF=hdr_record,USZ=DIU$K_LEN);
$GET(RAB=rab,ERR=rms$failure);
IF NOT $RMS_STATUS_OK (rab)
   THEN $XPO_PUT_MSG (SEVERITY = FATAL, STRING = 'Cannot find header record');
! Get the header record to see if we have a deleted chain

IF .hdr_record[HDR$H_DELETED_CHAIN] NEQ 0
   THEN BEGIN
        !
        ! We do have a deleted record chain.  Dequeue the first record
        ! and return its number to our caller.
        !
        LOCAL
            record_number;

        record_number = .hdr_record[HDR$H_DELETED_CHAIN];
        $RAB_STORE(RAB=rab,KBF=record_number,UBF=del_record,USZ=DIU$K_LEN);
        $GET(RAB=rab,ERR=rms$failure);
        IF NOT $RMS_STATUS_OK (rab)
           THEN $XPO_PUT_MSG (SEVERITY = FATAL,
                              STRING = 'Cannot find first deleted record');
        ! Get the first deleted record

        hdr_record[HDR$H_DELETED_CHAIN] = .del_record[DIU$H_NEXT_RECORD];
        $RAB_STORE(RAB=rab,KBF=(UPLIT(1)),RBF=hdr_record,RSZ=DIU$K_CHAR_COUNT);
        $FIND(RAB=rab,ERR=rms$failure);
        $UPDATE(RAB=rab,ERR=rms$failure);
        $DISCONNECT(RAB=rab);
        ! Update the pointer to the deleted chain and put back

        del_record[DIU$V_DELETED] = 0;
        del_record[DIU$V_ACTIVE] = 0;
        ! Clear the deleted and active flags

        RETURN (.del_record[DIU$H_REQUEST_ID]);
        ! Return, giving the request id

        END; %(deleted chain exists)%

! No deleted record chain exists.  Append a new record to the file
! (hdr_record[DIU$H_REQUEST_ID] points to 1st unused record in file).
! The request ID is set to the relative record number.  If we're
! at record 250, though, the queue is full, so return -1.

tmp_pointer = .hdr_record[HDR$H_FIRST_FREE];
IF .tmp_pointer GEQ (250 + 3)
   THEN BEGIN
          $DISCONNECT(RAB=rab,ERR=rms$failure);
          RETURN (-1);
        END;
! Grab one from the free list

Q$REQ_BLOCK_INIT(del_record);
$RAB_STORE(RAB=rab,KBF=tmp_pointer,RBF=del_record,RSZ=DIU$K_CHAR_COUNT);
$PUT(RAB=rab,ERR=rms$failure);
! write the record 

hdr_record[HDR$H_FIRST_FREE] = 1 + 
                              (del_record[DIU$H_REQUEST_ID]=.rab[RAB$G_BKT]);
! Update first free record field in header record

$RAB_STORE(RAB=rab,KBF=(UPLIT(1)),RBF=hdr_record,RSZ=DIU$K_CHAR_COUNT);
$FIND(RAB=rab,ERR=rms$failure);
$UPDATE(RAB=rab,ERR=rms$failure);
! Put the header record back

$DISCONNECT(RAB=rab,ERR=rms$failure);

RETURN (.del_record[DIU$H_REQUEST_ID])

END;                                ! End of q$$assign_sequence_no
!********************************************************************
!                 Q $ $ M A T C H _ B L O C K 
!********************************************************************
ROUTINE q$$match_block (p_try_block, p_target_block) =
BEGIN
!++
! FUNCTIONAL DESCRIPTION
!
!   Test to see if a request block can match a given request block.
!   The "try" block can be very sparse (in fact, if it is totally zero,
!   this routine will return success).  If all data specified in try_block
!   match the corresponding data in target_block, success is returned.
!   Wildcarding is allowed.
!
!   If there is anything in the source filespec portion of the request block,
!   it is assumed to be the source node to match.  If anything in the
!   destination file, it is assumed to be the destination node.  Node names
!   must have colons ("::") attached.
!   
! FORMAL PARAMETERS
!
!   p_try_block         - pointer to the (partial) block to test for a match
!   p_target_block      - pointer to target block
!
! IMPLICIT INPUTS
!   NONE
!
! IMPLICIT OUTPUTS
!   NONE
!
! ROUTINE VALUE
!
!       TRUE: match
!       FALSE: no match
!--

MACRO matchwild [field_name]= 
BEGIN

LOCAL length;

IF (length = .try_block[%NAME ('DIU$H_', field_name)]) NEQ 0
THEN BEGIN
     LOCAL tlength,
           result,
           try_buff  : VECTOR [CH$ALLOCATION (40)],
           targ_buff : VECTOR [CH$ALLOCATION (40)];

           ! Check length of the fields first
           tlength = .target_block[%NAME ('DIU$H_', field_name)];
           IF (.length GTR 40) OR (.tlength GTR 40) THEN RETURN (0);

           ! Make the try buffer argument ASCIZ
           CH$COPY(.length,CH$PTR(try_block[%NAME('DIU$T_',field_name)]),
                   0,.length+1,CH$PTR(try_buff));

           ! Make the argument buffer ASCIZ
           CH$COPY(.tlength,CH$PTR(target_block[%NAME('DIU$T_',field_name)]),
                   0,.tlength + 1, CH$PTR (targ_buff));

           ! Test the ASCIZ strings.. and return false if no match
           IF NOT wild_match(CH$PTR(try_buff),CH$PTR(targ_buff))
           THEN RETURN FALSE;

           END;                         ! length not equal 0

END %;                                  ! macro matchwild

BIND try_block    = .p_try_block    : $DIU_BLOCK,
     target_block = .p_target_block : $DIU_BLOCK;

LOCAL src_node,
      dst_node,
      node : $STR_DESCRIPTOR(CLASS=DYNAMIC),
      buff : $STR_DESCRIPTOR(CLASS=DYNAMIC);
        
! If the target is deleted then return false

IF .target_block[DIU$V_DELETED] THEN RETURN FALSE;

! If the request id isn't zero and they don't match, return false

IF .try_block[DIU$H_REQUEST_ID] NEQ 0
THEN IF .try_block[DIU$H_REQUEST_ID] NEQ .target_block[DIU$H_REQUEST_ID]
     THEN RETURN FALSE;

%IF %SWITCHES (TOPS10) %THEN            ! TOPS-10 ONLY
! If the user id isn't zero and they don't match, return false
IF .try_block[DIU$G_USER_NUMBER] NEQ 0
THEN IF .try_block[DIU$G_USER_NUMBER] NEQ .target_block[DIU$G_USER_NUMBER]
     THEN RETURN FALSE;
%FI                                     ! END TOPS-10 ONLY

! Make sure the jobname and username match if they are specified

MATCHWILD (jobname,username);

! If they gave us a node name to match, try and find it in either the
! source or destination filespec buffers.  If it isn't there, fail.

IF (.try_block[DIU$H_SOURCE_FILESPEC] GTR 0)
THEN BEGIN
     IF NOT (Q$FNODE(target_block[DIU$T_SOURCE_FILESPEC],
                     .target_block[DIU$H_SOURCE_FILESPEC],
                     try_block[DIU$T_SOURCE_FILESPEC],
                     .try_block[DIU$H_SOURCE_FILESPEC])
             OR Q$FNODE(target_block[DIU$T_DESTINATION_FILESPEC],
                        .target_block[DIU$H_DESTINATION_FILESPEC],
                        try_block[DIU$T_SOURCE_FILESPEC],
                        .try_block[DIU$H_SOURCE_FILESPEC]))
     THEN RETURN FALSE;
     END;

! All identifying fields matched.  Return true.

RETURN TRUE;

END;                                ! End of q$$match_block

END 
ELUDOM