Difference between revisions of "REXX"
DaveLClarkI (talk | contribs) (→Categories) |
Starbuck5250 (talk | contribs) (+ example Rexx to CL and back) |
||
(2 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
{{SeealsoWP|REXX}} | {{SeealsoWP|REXX}} | ||
− | {{AN}} is an acronym for {{bu|RE|structured}} e{{bu|X|tended}} e{{bu|X|ecutor}}, an interpreted scripting/programming language developed by IBM. It is simple to learn and is available on many platforms, including | + | {{AN}} is an acronym for {{bu|RE|structured}} e{{bu|X|tended}} e{{bu|X|ecutor}}, 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 | + | On IBM i, REXX source is stored in a source member, the default is {{code|QREXSRC}}. It is executed by {{code|STRREXPRC}}. It might be helpful to define a [[PDM]] or [[WDSC]] option to invoke the REXX interpreter: {{code|?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 {{keypress|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 | + | 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=== | ||
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== | ||
Line 20: | Line 164: | ||
==External links== | ==External links== | ||
− | * [http://publib.boulder.ibm.com/infocenter/iseries/v5r4/topic/rzahg/rzahgrexx.htm | + | * [https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/rzahg/rzahgrexx.htm IBM i 7.4 Rexx documentation] |
+ | * [http://publib.boulder.ibm.com/infocenter/iseries/v5r4/topic/rzahg/rzahgrexx.htm IBM i REXX V5R4M0 documentation] | ||
* [http://www-306.ibm.com/software/awdtools/rexx/library/index.html IBM general REXX information] | * [http://www-306.ibm.com/software/awdtools/rexx/library/index.html IBM general REXX information] | ||
* [http://www.rexxla.org/ REXX Language Association] | * [http://www.rexxla.org/ REXX Language Association] | ||
Line 30: | Line 175: | ||
==Categories== | ==Categories== | ||
[[Category:Programming languages]] | [[Category:Programming languages]] | ||
− | [[Category:REXX Examples]] | + | [[Category:REXX/400 Examples]] |
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.)
Contents
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
- Switching user profiles
- A ping sweep written in REXX for System i
- Capitalize A Sentence
- Factorial recursion
- Copy table to delimited file with headers
External links
- IBM i 7.4 Rexx documentation
- IBM i REXX V5R4M0 documentation
- IBM general REXX information
- REXX Language Association
- REXX tutorial
- Rex Swain's VM REXX page
- http://www.rexxinfo.org/
- "TechTip: Calling SQL from REXX" Written by Joe Pluta, Thursday, 24 February 2005