The REXX external data queue provides a way to temporarily hold data which REXX, and any suitably tailored application programs, can use. The data on the queue is accessible by and visible to users as lines or as buffers. A buffer is a sub-grouping of lines within a queue, and lines are character strings of arbitrary lengths. Each line can contain up to 32,767 characters. The individual characters have no special meaning or effect to REXX. The external data queue can be used to replace user input.
The data on the queue can be used by REXX programs and user-written programs in an arbitrary manner. Thus, the REXX queue services can be used as a way of exchanging data between programs, providing a device for inter-program
communication.
Learning About the REXX External Data Queue
A REXX external data queue comes into existence when a job is started and persists until the job is ended. All programs that run under the same job have access to that external data queue.
The following operations can be performed on the REXX external data queue: A line can be placed at the end of the current queue buffer.
A line can be placed at the front of the current queue buffer. A line can be retrieved from the front of the queue.
The number of lines on the queue can be queried. A new queue buffer can be created.
A queue buffer can be removed. The entire queue can be cleared.
These operations are made available directly to a REXX program through REXX instructions and CL commands. The same operations can be performed within other programming languages through the queue services application program interface (QREXQ). For more information on this interface, see the REXX/400 Reference. Some examples are provided in the Appendix F, “Sample REXX Programs for the AS/400 System” on page 157.
Using the REXX Queue Services on the AS/400 System
REXX provides the following instructions and functions for working with the queue: QUEUE This instruction places a given line at the end of the
current queue buffer.
PUSH This instruction places a given line at the front of the queue.
PULL This instruction retrieves a line from the front of the queue or reads from STDIN.
PARSE UPPER PULL This instruction retrieves a line from the front of the queue or reads from STDIN.
QUEUED This built-in function determines the number of lines in the queue.
These provide all the necessary tools for working with the queue. In addition, the Add REXX Buffer (ADDREXBUF) and Remove REXX Buffer (RMVREXBUF)
commands are available to REXX programs for working with queue buffers. These commands extend the flexibility of the REXX queue instructions.
Starting Queuing Services
When a job is started, the queuing services are immediately made available to the job. These services remain available until the job ends. Similarly, entries placed on the queue will remain on the queue and be available until explicitly removed or until the job is ended. After starting a job, any program that is part of the job can continue to use any of the queuing services until the job ends. Thus, one program can place an entry on the queue and end. Another following program can then receive what was placed in the queue at a later time. This can serve as a device for inter-program communication.
Understanding Queue Management Instructions
This section discusses the instructions used to manage the REXX external data queue.
Using the PUSH Instruction
The PUSH instruction expects a REXX string which is then placed at the front of the queue. The PUSH instruction imitates pushing data onto a stack. That is, the last data placed by PUSH is the data at the front of the queue. The following example illustrates the use of the PUSH instruction.
/\ Using PUSH and PULL. \/
SAY 'To start with, the queue has' queued() 'elements.'
/\ QUEUED() returns ð elements \/
PUSH TIME() /\ Add the current time to the queue. \/
PUSH DATE() /\ Add the current date to the queue. \/
/\ This goes before what is already in the queue.\/ SAY 'Now the queue has' queued() 'elements.'
/\ QUEUED() returns 2 elements \/
PULL data1 /\ PULL gets the date off the queue. \/
PULL data2 /\ PULL gets the time off the queue. \/
SAY 'The first element on the queue was' data1 SAY 'The second element on the queue was' data2 SAY 'Now the queue has' queued() 'elements again.'
/\ QUEUED() returns ð elements. \/ EXIT
Using the QUEUE Instruction
The QUEUE instruction places a string at the end of the current queue buffer. The QUEUE instruction imitates the classical manner of placing information on a queue. That is, the last data placed by QUEUE is the data at the end of the queue and would be the last data available for a PULL. The following example illustrates the use of the QUEUE instruction.
Example 1: Using the PULL and QUEUE instructions SAY 'To start with, the queue has' queued() 'elements.'
/\ QUEUED() returns ð elements. \/ QUEUE TIME() /\ Add the current time to the queue. \/ QUEUE DATE() /\ Add the current date to the queue. \/ /\ This goes after what is already in the queue.\/ SAY 'Now the queue has' queued() 'elements.'
/\ QUEUED() returns 2 elements. \/
PULL data1 /\ PULL gets the time off the queue. \/
PULL data2 /\ PULL gets the date off the queue. \/
SAY 'The first element on the queue was' data1 SAY 'The second element on the queue was' data2 SAY 'Now the queue has' queued() 'elements again.'
/\ QUEUED() returns ð elements. \/ EXIT
Example 2: Using the PARSE LINEIN instruction.
/\ This program illustrates how PARSE LINEIN reads a response from \/ /\ the user, even when there are lines in the queue. \/ /\ Suppose you want to send a message to selected users of your \/ /\ system. And suppose you already have an external function which \/ /\ puts a list of all users into the REXX queue. This program shows \/ /\ how you can select some of the users listed by that function. \/ message = 'Please come to a meeting in my office at 1ð:ðð.'
CALL queryusers /\ Function queues a list of users.\/ DO QUEUED()
PULL userid
SAY 'Enter YES if you want to send the message to' userid PARSE UPPER LINEIN answer
IF answer = 'YES' THEN "SNDMSG MSG('"message"') TOUSR("userid")" END
Example 3: This example shows a CL command that uses a REXX program as its command processing program. This example copies the contents of a file into the REXX external data queue.
CMD PROMPT('Copy file to REXX data que')
PARM KWD(FROMFILE) TYPE(QUAL1) MIN(1) PROMPT('FROM + file')
PARM KWD(MBR) TYPE(\NAME) LEN(1ð) DFT(\FIRST) + SPCVAL((\FIRST)) MIN(ð) PROMPT('Member') PARM KWD(NMBRCDS) TYPE(\DEC) LEN(6) DFT(\ALL) + SPCVAL((\ALL 999999)) PROMPT('Number of + records to copy')
QUAL1: QUAL TYPE(\NAME) LEN(1ð) MIN(1) QUAL TYPE(\NAME) LEN(1ð) DFT(\LIBL) +
SPCVAL((\CURLIB) (\LIBL)) PROMPT('Library') /\ Command Processing REXX program for CPYFTOREXQ command. \/
/\ Parse out the library and file. \/ PARSE UPPER ARG 'FROMFILE(' lib '/' file ')'
/\ Parse out the member. \/
PARSE UPPER ARG 'MBR(' mbr ')'
/\ Parse out the number of records to copy. \/ PARSE UPPER ARG 'NMBRCDS(' count ')'
/\ Check if object exists. \/ 'CHKOBJ OBJ('lib'/'file') OBJTYPE(\FILE) MBR('mbr')'
IF rc ¬= 'ð' THEN
IF POS(rc,'CPF98ð1 CPF981ð') ¬= ð THEN DO
msg = 'File member specified:' lib'/'file mbr 'was not found' 'SNDPGMMSG MSG(&msg)'
EXIT END
IF count = '\ALL' THEN count = '999999999'
/\ Override STDIN to the LIB/FILE parms. \/ 'OVRDBF FILE(STDIN) TOFILE('lib'/'file') MBR('mbr')'
DO count
/\ Read data from STDIN. \/
PARSE LINEIN data IF data == '' THEN
LEAVE
/\ QUEUE data into REXX queue, FIFO order from PULL. \/ QUEUE data
END EXIT
Using the PULL Instruction
The PULL instruction retrieves a line from the front of the queue. This instruction is equal to PARSE UPPER PULL, which uppercases the line pulled from the queue. To pull from the queue without uppercasing, use PARSE PULL. The PULL instruction imitates pulling data from a stack. That is, the last data placed by the PUSH instruction would be the first retrievable data by the PULL instruction. The following example illustrates the use of the PULL instruction.
/\ The Pull instruction is a shorthand version of Parse Upper Pull. \/ test = 'This is a test'
PUSH 'test' PUSH 'test' PUSH 'test'
PARSE UPPER PULL input1 PULL input2
SAY 'Parse Upper Pull got' input1 SAY 'Pull got' input2
IF input1 == input2 THEN SAY 'The two different instructions work the same.' ELSE SAY 'You will never see this message.'
PARSE PULL input3
Whenever the queue is empty, the PULL instruction operates in a manner identical with the PARSE UPPER LINEIN instruction which reads lines from the STDIN. The PARSE UPPER LINEIN instruction can, however, be used directly even if the queue is not empty, when input from STDIN is also required or when there is data on the queue which must not be disturbed.
Using the Add REXX Buffer (ADDREXBUF) Command
The ADDREXBUF command expects a REXX variable into which the identification number of the newly created queue buffer would be returned. The command allows a REXX program to establish new buffers in the REXX external data queue. The ADDREXBUF command can only be used in REXX programs and CL programs. If the queue is not buffered with this command, it is treated as one large buffer. PUSH 'LINE ONE'
PUSH 'LINE TWO' PUSH 'LINE THREE' QUEUE 'LAST LINE'
Assuming a previously empty REXX external data queue, these instructions would result in the following on the queue:
┌─────────────────────┐%────────PUSH adds lines here │LINE THREE │────────5PULL takes this line ├─────────────────────┤ │LINE TWO │ ├─────────────────────┤ │LINE ONE │ ├─────────────────────┤ │LAST LINE │
└─────────────────────┘%────────QUEUE adds data here
Running this set of instructions affects the queue as shown: BUFFERNUM = ð
'ADDREXBUF &BUFFERNUM' QUEUE 'NEWBUF FIRSTQ' PUSH 'NEWBUF PUSH' QUEUE 'NEWBUF SECONDQ'
┌─────────────────────┐%──────────PUSH adds lines here │NEWBUF PUSH │──────────5PULL takes this line ├─────────────────────┤
│NEWBUF FIRSTQ │
├─────────────────────┤ │NEWBUF SECONDQ │
└─┬───────────────────┴─┐%────────QUEUE adds data here
│LINE THREE │ ├─────────────────────┤ │LINE TWO │ ├─────────────────────┤ │LINE ONE │ ├─────────────────────┤ │LAST LINE │ └─────────────────────┘
Figure 2. External data queue after ADDREXBUF
Using the Remove REXX Buffer (RMVREXBUF) Command
The Remove REXX Buffer(RMVREXBUF) command expects an identification number of the queue buffer which is to be removed. This command deletes buffers and any lines they may contain from the REXX external data queue.
Assuming the last example above, using ADDREXBUF, if the following REXX instructions were run:
'RMVREXBUF' buffernum PULL aline
The REXX external data queue would then look like this: ┌─────────────────────┐%────────PUSH adds lines here │LINE TWO │────────5PULL takes this line ├─────────────────────┤
│LINE ONE │
├─────────────────────┤
│LAST LINE │
└─────────────────────┘%────────QUEUE adds data here
Figure 3. External data queue after RMVREXBUF
Now, if instead of issuing a RMVREXBUF command after getting the queue into the state shown in Figure 2, you were to run the following set of REXX instructions:
PULL line1 /\ line1 = 'NEWBUF PUSH' \/ PULL line2 /\ line2 = 'NEWBUF FIRSTQ' \/ PULL line3 /\ line3 = 'NEWBUF SECONDQ' \/ PULL line4 /\ line4 = 'LINE THREE' \/
The queue would look the same as in the Figure 3. Buffer boundaries created with the ADDREXBUF command are ignored by the PULL instruction.
Specifying a buffer number on theRMVREXBUF command causes existing buffers created after the one whose number is specified to be destroyed. Thus, this command can be used to “cleanup” after a particularly unruly user of the REXX external data queue. Also, if you want to totally erase the queue, specify the *ALL value on the buffer parameter of theRMVREXBUF command. This will cause the queue to be cleared. In addition, if the queue is damaged, this command can be used to delete and re-create the queue.
The following example shows how to use ADDREXBUF and RMVREXBUF: /\ REXX program which demonstrate how to use the ADDREXBUF and \/ /\ RMVREXBUF commands with other REXX queuing services. \/ bufn = ð
'ADDREXBUF &BUFN' /\ Add buffer '1' to the queue. \/ PUSH 'Buffer' bufn ': Line 1 ' /\ Add a line to the queue. \/ PUSH 'Buffer' bufn ': Line 2 ' /\ Add a line to the queue. \/ PUSH 'Buffer' bufn ': Line 3 ' /\ Add a line to the queue. \/ 'ADDREXBUF &BUFN' /\ Add buffer '2' to the queue. \/ PUSH 'Buffer' bufn ': Line 1 ' /\ Add a line to the queue. \/ PUSH 'Buffer' bufn ': Line 2 ' /\ Add a line to the queue. \/
PULL entry /\ Pull a line from the queue. \/
SAY entry /\ Displays 'Buffer 2: line 2'. \/
'RMVREXBUF &BUFN' /\ Remove buffer '2' \/
/\ from the queue. \/
PULL entry /\ Pull a line from the queue. \/
SAY entry /\ Displays 'Buffer 1: line 3'. \/
'ADDREXBUF &BUFN' /\ Add buffer '2' to the queue. \/ PUSH 'Buffer' bufn ': Line 1 ' /\ Add a line to the queue. \/
'ADDREXBUF ' /\ Add buffer '3', \/
/\ do not save bufn. \/
PUSH 'Buffer' bufn + 1 ': Line 1 ' /\ Add a line to the queue. \/ 'RMVREXBUF &BUFN' /\ Remove buffer '2' from queue.\/ /\ Will remove '2' and '3'. \/
PULL entry /\ Pull a line from the queue. \/
SAY entry /\ Displays 'Buffer 1: line 2'. \/
'ADDREXBUF &BUFN' /\ Add buffer '2' to the queue. \/ PUSH 'Buffer' bufn ': Line 1 ' /\ Add a line to the queue. \/
'RMVREXBUF \CURRENT' /\ Remove buffer '2' \/
/\ from the queue. \/
/\ At this point, buffer 1 has 1 entry. \/
'ADDREXBUF &BUFN' /\ Add buffer '2' to the queue. \/ PUSH 'Buffer' bufn ': Line 1 ' /\ Add a line to the queue. \/
'ADDREXBUF &BUFN' /\ Add buffer '3' to the queue. \/ PUSH 'Buffer' bufn ': Line 1 ' /\ Add a line to the queue. \/ PUSH 'Buffer' bufn ': Line 2 ' /\ Add a line to the queue. \/
SAY QUEUED() /\ Displays '4', total of all \/
/\ entries for all buffers in \/
/\ the queue. \/
PULL entry /\ Pull a line from the queue. \/
SAY entry /\ Displays 'Buffer 3: line 2'. \/
PULL entry /\ Pull a line from the queue. \/
SAY entry /\ Displays 'Buffer 3: line 1'. \/
PULL entry /\ Pull a line from the queue. \/
SAY entry /\ Displays 'Buffer 2: line 1'. \/
PULL entry /\ Pull a line from the queue. \/
SAY entry /\ Displays 'Buffer 1: line 1'. \/
/\ Because the queue is empty, \/
/\ any further PULLs will pull from STDIN, not the queue. \/
PULL entry /\ Pull a line from STDIN. \/
SAY entry /\ Displays your entry. \/
'RMVREXBUF \ALL' /\ Clears all entries from the queue. \/ RETURN