Difference between revisions of "REXX"

From MidrangeWiki
Jump to: navigation, search
(System i to IBM i, 7.4 documentation links)
(+ example Rexx to CL and back)
 
Line 11: Line 11:
 
  say 'Hello, world!'  
 
  say 'Hello, world!'  
 
  return               
 
  return               
 +
 +
=== Rexx and CL ===
 +
Rexx can interact with CL via use of an API called QREXQ, It's not the same as CALL/PARM, so it needs coding on the
 +
CL side to add entries to the Rexx External Data Queue, and pull them off. Following is an example that demonstrates CL adding a library name to the queue, calling a Rexx program that does ADDLIBLE, then uses the Db2 service to retrieve the library list. Rexx puts the library list entries back onto the queue, then returns to the CL which pulls them off into CL variables.
 +
 +
<pre>
 +
REXXCLP *CLP
 +
 +
/* Pass 'parameters' back and forth to Rexx */
 +
pgm
 +
 +
dcl &len *int (4) value(10)
 +
dcl &rc *int (2)
 +
dcl &toCLP *char (10)
 +
 +
dcl &buffer *char (100)
 +
dcl &lib *char (10)
 +
dcl &type *char (15)
 +
dcl &text *char (50)
 +
 +
dcl &work_msg *char (50)
 +
 +
/* this is a demonstrator of passing info from CL to Rexx and back */
 +
/* This CLP will pass a library name to Rexx */
 +
/* Rexx will ADDLIBLE it and then pass back the current library list */
 +
 +
/* Yes, this can all be done in CL but the idea is to show how */
 +
/* the interface between CL and Rexx works */
 +
/* Additionally, it'll show how Rexx can use SQL directly */
 +
 +
/* Pass to Rexx */
 +
/* Can't use call/parm; use the API QREXQ instead */
 +
/* 'A' pushes an entry onto the Rexx external data queue */
 +
/* Rexx will pull parse from this into Rexx variables */
 +
/* https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_61 */
 +
/* /books_web/sc415729.pdf?view=kc */
 +
 +
chgvar &toCLP 'QSYS38'
 +
chgvar &len %size(&toCLP)
 +
call QREXQ ('A' &toCLP &len 0 &rc)
 +
 +
/* execute the Rexx program */
 +
/* it will read the 'parameter' from the External Data Queue */
 +
strrexprc rexxclp srcfile(buck/qrexsrc)
 +
 +
/* the diags are in the REXX queue */
 +
/* pull them out one by one */
 +
chgvar &len %size(&buffer)
 +
 +
loop_top:
 +
  /* pull a 'parameter' struc from the external data queue */
 +
  /* one entry per library in *LIBL */
 +
  call QREXQ ('P' &buffer &len 0 &rc)
 +
  if (&rc *ne 0) (goto endpgm)
 +
 +
    /* convert the buffer into individual variables */
 +
    /* this obviously needs to be matched up with the Rexx program */
 +
    chgvar &lib %sst(&buffer 1 10)
 +
    chgvar &type %sst(&buffer 12 15)
 +
    chgvar &text %sst(&buffer 28 50)
 +
 +
    /* in a real program we'd do something with this info */
 +
    /* here, let's display it */
 +
    chgvar &work_msg (&lib *cat ' ' *cat +
 +
                      &type *cat ' ' *cat +
 +
                      %sst(&text 1 22))
 +
    sndpgmmsg &work_msg
 +
  goto loop_top
 +
 +
endpgm:
 +
  return
 +
 +
endpgm
 +
 +
</pre>
 +
 +
<pre>
 +
REXXCLP Rexx program
 +
 +
/* rexxclp */
 +
 +
/* NOTE: STRREXPRC will not run this if it's open in RDi for editing */
 +
 +
/* example of passing 'parameters' from CL to Rexx and back */
 +
/* https://public.dhe.ibm.com/systems/power/docs/systemi/v6r1 */
 +
/* /en_US/sc415729.pdf?view=kc&origURL=ssw_ibm_i_61/books_web/sc415729.pdf */
 +
 +
  /* get the 'parameter' that CLP previously put on the External Data Queue */
 +
  /* via the QREXQ API */
 +
  parse pull library_name
 +
 +
  /* do the ADDLIBLE */
 +
  signal on error name skip_lible /* if error in addlible, skip it */
 +
  cmd = "addlible " || strip(library_name);
 +
  address command cmd;
 +
 +
skip_lible:
 +
  signal off error
 +
 +
  /* we're going to be issuing Db2 instructions */
 +
  address execsql
 +
 +
  /* use the Db2 service to retrieve the LIBL */
 +
  /* the CAST gets rid of the UTF-8 CCSID and makes a fixed-length variable */
 +
  sql_stmt = ,
 +
    "select ",
 +
      "cast(system_schema_name as char(10)), ",
 +
      "cast(type as char(15)), ",
 +
      "cast(coalesce(text_description, ' ') as char(50)) ",
 +
    "from qsys2.library_list_info"
 +
 +
  execsql "prepare STMT from :sql_stmt"
 +
  execsql "declare LIBL_CSR cursor for STMT"
 +
  execsql "open LIBL_CSR"
 +
 +
  do while 1 = 1
 +
    execsql "fetch LIBL_CSR into ",
 +
            ":lib, :type, :text"
 +
 +
    /* for a production program better status checking is needed */
 +
    /* this is the barest minimum to detect end of cursor */
 +
    if rc <> 0 then do
 +
      if sqlstate = "02000" then
 +
        leave
 +
      else do
 +
        say "SQLSTATE = " sqlstate
 +
        leave
 +
      end /* sqlstate  */
 +
    end /* rc */
 +
 +
    /* construct an outgoing 'structure' to pass back to CLP */
 +
    buffer = lib"*"type"*"text"*"
 +
 +
    /* put the value on the external queue */
 +
    /* This will allow the calling CLP to retrieve it */
 +
    /* note that this is one 'parameter' per entry in *LIBL */
 +
    queue (buffer)
 +
 +
  end /* do forever*/
 +
 +
 +
return
 +
 +
</pre>
  
 
==Other System i REXX programs==
 
==Other System i REXX programs==

Latest revision as of 14:30, 20 August 2019

See also on Wikipedia: REXX

REXX is an acronym for REstructured eXtended eXecutor, an interpreted scripting/programming language developed by IBM. It is simple to learn and is available on many platforms, including IBM i. It was used as the macro language in the Code/400 GUI editor (precursor to WDSC and RDi.)

IBM i implementation

On IBM i, REXX source is stored in a source member, the default is QREXSRC. It is executed by STRREXPRC. It might be helpful to define a PDM or WDSC option to invoke the REXX interpreter: ?STRREXPRC SRCMBR(&N) SRCFILE(&L/&F); however, PDM recognizes source members that have source type REXX and will execute STRREXPRC against them when option 16 ("Run procedure") is entered. The question mark in front of the command signifies prompting, which will allow you to fill in any parameters you might want. If PDM option 16 is used, the F4 key will perform prompting.

According to most manuals, all REXX programs should begin with a comment; but this seems to be no longer required, at least under IBM i. (It is not required on most V5R3 and later systems. It is not clear when this was first allowed.) White space is for programmer convenience and can be added or omitted as desired.

Hello world

/* Hello, world */ 
say 'Hello, world!' 
return              

Rexx and CL

Rexx can interact with CL via use of an API called QREXQ, It's not the same as CALL/PARM, so it needs coding on the CL side to add entries to the Rexx External Data Queue, and pull them off. Following is an example that demonstrates CL adding a library name to the queue, calling a Rexx program that does ADDLIBLE, then uses the Db2 service to retrieve the library list. Rexx puts the library list entries back onto the queue, then returns to the CL which pulls them off into CL variables.

REXXCLP *CLP

/* Pass 'parameters' back and forth to Rexx */
pgm

dcl &len *int (4) value(10)
dcl &rc *int (2)
dcl &toCLP *char (10)

dcl &buffer *char (100)
dcl &lib *char (10)
dcl &type *char (15)
dcl &text *char (50)

dcl &work_msg *char (50)

/* this is a demonstrator of passing info from CL to Rexx and back */
/* This CLP will pass a library name to Rexx */
/* Rexx will ADDLIBLE it and then pass back the current library list */

/* Yes, this can all be done in CL but the idea is to show how */
/* the interface between CL and Rexx works */
/* Additionally, it'll show how Rexx can use SQL directly */

/* Pass to Rexx */
/* Can't use call/parm; use the API QREXQ instead */
/* 'A' pushes an entry onto the Rexx external data queue */
/* Rexx will pull parse from this into Rexx variables */
/* https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_61 */
/* /books_web/sc415729.pdf?view=kc */

chgvar &toCLP 'QSYS38'
chgvar &len %size(&toCLP)
call QREXQ ('A' &toCLP &len 0 &rc)

/* execute the Rexx program */
/* it will read the 'parameter' from the External Data Queue */
strrexprc rexxclp srcfile(buck/qrexsrc)

/* the diags are in the REXX queue */
/* pull them out one by one */
chgvar &len %size(&buffer)

loop_top:
   /* pull a 'parameter' struc from the external data queue */
   /* one entry per library in *LIBL */
   call QREXQ ('P' &buffer &len 0 &rc)
   if (&rc *ne 0) (goto endpgm)

     /* convert the buffer into individual variables */
     /* this obviously needs to be matched up with the Rexx program */
     chgvar &lib %sst(&buffer 1 10)
     chgvar &type %sst(&buffer 12 15)
     chgvar &text %sst(&buffer 28 50)

     /* in a real program we'd do something with this info */
     /* here, let's display it */
     chgvar &work_msg (&lib *cat ' ' *cat +
                       &type *cat ' ' *cat +
                       %sst(&text 1 22))
     sndpgmmsg &work_msg
   goto loop_top

endpgm:
   return

endpgm

REXXCLP Rexx program

/* rexxclp */

/* NOTE: STRREXPRC will not run this if it's open in RDi for editing */

/* example of passing 'parameters' from CL to Rexx and back */
/* https://public.dhe.ibm.com/systems/power/docs/systemi/v6r1 */
/* /en_US/sc415729.pdf?view=kc&origURL=ssw_ibm_i_61/books_web/sc415729.pdf */

  /* get the 'parameter' that CLP previously put on the External Data Queue */
  /* via the QREXQ API */
  parse pull library_name

  /* do the ADDLIBLE */
  signal on error name skip_lible /* if error in addlible, skip it */
  cmd = "addlible " || strip(library_name);
  address command cmd;

skip_lible:
  signal off error

  /* we're going to be issuing Db2 instructions */
  address execsql

  /* use the Db2 service to retrieve the LIBL */
  /* the CAST gets rid of the UTF-8 CCSID and makes a fixed-length variable */
  sql_stmt = ,
    "select ",
      "cast(system_schema_name as char(10)), ",
      "cast(type as char(15)), ",
      "cast(coalesce(text_description, ' ') as char(50)) ",
    "from qsys2.library_list_info"

  execsql "prepare STMT from :sql_stmt"
  execsql "declare LIBL_CSR cursor for STMT"
  execsql "open LIBL_CSR"

  do while 1 = 1
    execsql "fetch LIBL_CSR into ",
            ":lib, :type, :text"

    /* for a production program better status checking is needed */
    /* this is the barest minimum to detect end of cursor */
    if rc <> 0 then do
      if sqlstate = "02000" then
        leave
      else do
        say "SQLSTATE = " sqlstate
        leave
      end /* sqlstate  */
    end /* rc */

    /* construct an outgoing 'structure' to pass back to CLP */
    buffer = lib"*"type"*"text"*"

    /* put the value on the external queue */
    /* This will allow the calling CLP to retrieve it */
    /* note that this is one 'parameter' per entry in *LIBL */
    queue (buffer)

  end /* do forever*/


return

Other System i REXX programs

External links

Categories