27
Fri, Dec
0 New Articles

Simon's Solutions: Talk with REXX Programs

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Learn how to exchange data with REXX programs via the REXX external data queue.

 

During the years in which Simon Coulter posted on the midrange.com forums, he taught the IBM i community a lot about the REstructured eXtended eXecutor (REXX) language. For example, in the following post in the RPG400-L mailing list, Simon demonstrated the simplicity and ease of use of this powerful scripting language vividly via a couple of interesting example Rexx programs.

 

What is Rexx? (Was: Outputting a very specific character)

 

   * Subject: What is Rexx? (Was: Outputting a very specific character)

   * From: "Simon Coulter" <shc@xxxxxxxxxxxxxxxxx>;

   * Date: Fri, 28 Jul 00 10:09:51 +1000

 

 

Hello Rob,

 

You wrote:

>What member type is this, REXX?

 

Rexx is the SAA Procedure Language. It has been available on the AS/400 since at least VRM130 -- a looooong time. It is singularly underrated and ignored by most AS/400 programmers. It has better string handling than CL, better loop control, supports subroutines, and is available on all IBM platforms and there are even versions of it for Microsquib's so-called operating systems. The PC versions also have an object-oriented dialect (ObjectRexx) and there is a version that works with the Web (NetRexx).

 

You can imbed CL commands, run SQL, and slice and wrap cheese (OK, I lied about the last part). Rexx is well worth a look. Trivial examples follow:

 

<-------------- example 1 ----------------->

parse source system .

 

arg user

say system

select

       when system = 'OS/400' then 'dspusrprf usrprf('user')'

       otherwise say 'don''t know the system'

end

 

<------------- example 2 ------------------->

 

/* Rexx the wonder dog */

tally = 0;

number = 0;

say ' ';

say date('w') center("System Calculator", 54) date();

say ' ';

say "Type an arithmetical expression, RESET, or press Enter to end.";

say ' ';

do n = 1 to 400;

pull expression;

if expression = '' then exit(0);

interpret 'tally='expression;

if expression = 'RESET' | ,

     expression = 'R'     | ,

     expression = 'r' then tally = 0;

say expression " = " tally;

end

 

Regards,

Simon Coulter.

 

The sources of these examples are available as hosttype.rexx and wonder-dog.rexx, respectively. To run the example REXX programs, upload them to your QSYS.LIB file system and run them via the Start REXX Procedure (STRREXPRC) command. For example:

 

STRREXPRC SRCMBR(HOSTTYPE) SRCFILE(MYSRCLIB/MYSRCFILE) PARM(A_USER)

 

In the first example, the PARSE SOURCE instruction (one of the variants of the PARSE instruction) is used to retrieve the name of the system on which the program is running. Please refer to Chapter 5, Parsing, of the REXX/400 Reference. In the second example, Simon demonstrated a calculator program composed of only 16 lines of REXX code. The central task of the calculator program, evaluating a string expression at runtime and executing the evaluated string as REXX instructions, is achieved by the INTERPRET instruction (see Chapter 3, Keyword Instructions, of the REXX/400 Reference).

 

In a 2002 post, Re: Rexx/400 and CL was Encryption packages and Encryption Algorithm, Simon mentioned the REXX external data queue as an effective and easy-to-use method of receiving data from REXX programs.

 

Re: Rexx/400 and CL was Encryption packages and Encryption Algorithm

 

   * Subject: Re: Rexx/400 and CL was Encryption packages and Encryption Algorithm

   * From: "Simon Coulter" <shc@xxxxxxxxxxxxxxxxx>;

   * Date: Thu, 17 Jan 02 11:17:49 +1100

 

Hello Howard,

 

You wrote:

All of the examples in the books show me how to get variables into Rexx, but either I am blind or brain-dead, but I can not get Rexx to pass a variable back into the CL, here is what I am doing, a bit jumbled at the moment out of frustration. How do I get the result back into the CL?

 

Since you just need a random number you can invoke the C-runtime srand() and rand() functions, or the ILE CEERAN0 function. These functions have been discussed here before (and in the RPG list) so search the archives for details. If you really want to learn something about Rexx then read on . . .

 

Rexx is intended to be used as the job control language. It has support for calling other programs and for invoking CL commands and retrieving values from CL via RTNVAL(*YES) parameters. The Rexx Programmer's Guide discusses returning data from C to Rexx. That method should work with any ILE language. It also discusses using the Rexx queue to return data from non-ILE languages. In all these cases Rexx is the driver.

 

You are using CL as the driver and invoking Rexx via STRREXPRC. The PARM keyword maps directly to the Rexx ARG list which implicitly means it is input only (think of it as pass by VALUE) so no changes in Rexx will be reflected in CL variables specified on PARM.

 

When using a non-Rexx program as the driver I believe there are two ways of getting the data.

 

1/ If RETURN is used in a Rexx procedure that was NOT invoked via Rexx CALL or as a Rexx function then the RETURN value will be sent in message CPF7CFF. However that restricts the return value to a number between -32768 and 32767.

 

You are not using a seed value but you are setting a maximum limit on the range of random numbers. Your limit is a six-digit number based on time (you might want to rethink that because I don't think that's what you intended). Any RETURN value is likely to be too big for the range allowed by CPF7CFF.

 

2/ Put the return value on the Rexx queue (using PUSH) and retrieve it using the QREXQ API.

 

Since Rexx can be the CPP for a CL command it would be nice if we could use  RTNVAL(*YES) for the parameter and code something like:

 

CMD       PROMPT('Test Rexx Command')

 

PARM       KWD(RANDOM) TYPE(*CHAR) LEN(6) RTNVAL(*YES)

 

however RTNVAL(*YES) is not supported when Rexx is used as the CPP.

 

Regards,

Simon Coulter.

The Rexx External Data Queue

The following paragraphs quoted from Chapter 9, Using the Rexx External Data Queue, of the REXX/400 Programmer's Guide give a brief introduction to the REXX external data queue.

 

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. [1] 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.

 

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. [2]

 

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 [3]. The same operations can be performed within other programming languages through the queue services application programming interface (QREXQ). For more information on the QREXQ API, see the REXX/400 Reference. [4]

 

Notes

[1] Also note that, according to the REXX/400 Reference, lines that are longer than 32,767 bytes will be truncated with no error indication. And the maximum size of all the data contained in the queue is 15.5MB.

[2] In IBM i, the REXX external data queue is a temporary, automatically extensible MI space object named QREXXDATAQ. An MI space pointer addressing the start of the associated space of QREXXDATAQ is placed into the Process Communication Object (PCO) at offset hex 0100 (256 bytes into the PCO) at the beginning of an IBM i job. Therefore, you can find the QREXXDATAQ object easily via a DMPSYSOBJ *PCS command. The QREXXDATAQ space object of an IBM i job is destroyed at the end of the job. (At least at VRM540, a QREXXDATAQ space is not reserved for reusing by new jobs.)

[3] There is no REXX instruction or built-in function to directly operate REXX queue buffers. To operate queue buffers, a REXX program needs to issue the Add REXX Buffer (ADDREXBUF) command and/or the Remove REXX Buffer (RMVREXBUF) command.

[4] The QREXQ API can be invoked from programs written in any language to achieve any type of REXX queue operation. It is documented in details in the Queuing Interfaces section of Chapter 9, AS/400 System Interfaces, of the REXX/400 Reference.

 

The QREXQ API is a UDSS (User Domain/System State) OPM program that takes five parameters. The RPG prototype of QREXQ is the following:

 

     /**

     * RPG prototype of the QREXQ API.

     */

     d qrexq           pr                 extpgm('QREXQ')

     * Requested function code

     d  func                         1a

     * Data buffer

     d   buf                         1a   options(*varsize)

     * Length / Number

     d   len_num                     10u 0

     * Operation flag

     d   op_flg                       5u 0

     * Return code

     d   rc                           5u 0

 

The type of a requested REXX queue operation is specified by QREXQ's first parameter, requested function code (func) and optionally its fourth parameter, operation flag (op_flg). The following table maps each queue-related REXX instruction (or built-in function) to the corresponding invocation to the QREXQ API with proper func parameter (and optionally op_flg parameter).

 

Rexx Instruction (or Built-In)

Parameter func (and op_flg) of QREXQ

Function Description

QUEUE

'A',0

Place a given line at the end of the current queue buffer.

PUSH

'A',1

Place a given line at the front of the queue.

PULL

PARSE UPPER PULL

P

Retrieve a line from the front of queue or read from STDIN. [1]

QUEUED() [2]

Q

Query the number of lines in the queue.

address command 'ADDREXBUF &bufnum'

N

Create a new queue buffer.

address command 'RMVREXBUF 'bufnum

address command 'RMVREXBUF *ALL'

R

Remove a specific buffer or all buffers from the queue.

 

Notes

[1] If the REXX queue is currently empty, the QREXQ API will not read from STDIN (the REXX input stream). Instead, it will set the return code (@var rc) parameter to value 2 to indicate the queue is empty.

[2] QUEUED() is a REXX built-in function.

Examples of Using the QREXQ API

This section shows you some trivial RPG and CL examples of using the QREXQ API:

  1. 1.Program rexq01.rpgle (which is also the Command Processor Program (CPP) of the RTVREXQLN command) returns the number of lines in the REXX queue.
  2. 2.Program rexq02.rpgle pulls a line from the front of the REXX queue.
  3. 3.The OPM CL program rexq04.clp pulls all lines from the REXX queue by calling the REXQ02 program. REXQ04 uses the RTVREXQLN command to retrieve the current number of lines in the REXX queue.

 

rexq01.rpgle

     /**

     * @file rexq01.rpgle

     *

     * Query the number of lines in the Rexx queue.

     */

 

     /**

     * RPG prototype of the QREXQ API.

     */

     d qrexq           pr                 extpgm('QREXQ')

     * Requested function code

     d   func                         1a

     * Data buffer

     d   buf                         1a   options(*varsize)

     * Length / Number

     d   len_num                    10u 0

     * Operation flag

     d   op_flg                       5u 0

     * Return code

     d   rc                           5u 0

 

     /**

     * Prototype of this program

     */

     d rexq01         pr                 extpgm('REXQ01')

     d                               11p 0

 

     d func           s             1a   inz('Q')

     d num             s             10u 0

     d op_flg         s             5u 0

     d rc             s             5u 0

 

     d rexq01         pi

    d   queued                     11p 0

 

     /free

           qrexq( func

               : *inlr

               : num

               : op_flg

               : rc );

 

           queued = num;

           *inlr = *on;

     /end-free

 

rexq02.rpgle

     /**

     * @file rexq01.rpgle

     *

     * PUSH one line from the QREXXDATAQ.

     */

     h dftactgrp(*no)

 

     /**

     * RPG prototype of the QREXQ API.

     */

     d qrexq           pr                 extpgm('QREXQ')

     * Requested function code

     d   func                         1a

     * Data buffer

     d   buf                         1a   options(*varsize)

     * Length / Number

   d   len_num                     10u 0

     * Operation flag

     d   op_flg                       5u 0

     * Return code

     d   rc                           5u 0

 

     /**

     * Prototype of this program

     *

     * Parameters:

     * - msg. Data of the line pulled from the REXX data queue (INTPUT).

     * - buflen. Length of the data buffer (INPUT).

     * - msglen. On return, it is set to the length of the pulled line

     *   data, or -1 if the REXX data queue is empty (OUTPUT).

     */

     d rexq02         pr                 extpgm('REXQ02')

     d   msg                         1a   options(*varsize)

     d   buflen                     11p 0

     d   msglen                     11p 0

 

     * System built-in _memcpy

     d memcpy          pr             *   extproc('__memcpy')

     d     target                     *   value

     d     source                     *   value

     d     length                   10u 0 value

 

     d func           s             1a   inz('P')

     d msg2           s             1a   based(msg@)

     d len             s             10u 0

     d op_flg         s             5u 0

     d rc             s             5u 0

 

     d rexq02         pi

     d   msg                         1a   options(*varsize)

     d   buflen                     11p 0

     d   msglen                     11p 0

 

     /free

           len = buflen;

           qrexq( func

               : msg

               : len

               : op_flg

               : rc );

          if rc = 5; // Data buffer too small

               msg@ = %alloc(len);

               qrexq(func : msg2 : len : op_flg : rc);

               memcpy(%addr(msg) : msg@ : buflen);

               dealloc msg@;

           endif;

           msglen = len;

 

         if rc = 2;

               msglen = -1;

           endif;

 

           *inlr = *on;

     /end-free

 

rexq04.clp

dcl &line *char 16

dcl &len *dec len(11 0) value(16)

dcl &msglen *dec len(11 0)

dcl &num *dec len(11 0)

 

       rtvrexqln &num

pull: if cond(&num *eq 0) then(goto end)

       call REXQ02 (&line &len &msglen)

       sndpgmmsg &line

       chgvar &line ' '

       rtvrexqln &num

       goto pull

 

end:   endpgm

 

It is handy to wrap a CL command, say RTVREXQLN, into REXQ01 to return the number of lines in the REXX queue. The command definition of RTVREXQLN is the following:

 

             CMD       PROMPT('Get Number of Rexx Q Lines')

            PARM       KWD(NUM) TYPE(*DEC) LEN(11 0) RTNVAL(*YES)

 

Compile the RTVREXQLN command and specify REXQ01 as its CPP. For example:

 

CRTCMD CMD(RTVREXQLN) PGM(REXQ01) SRCFILE(SRCLIB/SRCFILE) ALLOW(*BPGM *IPGM *BREXX *IREXX *BMOD *IMOD)

 

Now let's add a few lines of data to the REXX external data queue in FIFO order via a simple REXX program:

 

queue date()

queue time()

queue address()

 

Run the above REXX program via the Start REXX Procedure (STRREXPRC) command. Then call REXQ04 to pull all lines from the REXX queue. The output of REXQ04 might look like the following:

 

4 > call rexq04

     13 Dec 2013

     11:01:57

     COMMAND

 

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: