On 25/10/2017 2:51 AM, Tony Harminc wrote:
What's the obstacle (not to popularity, but to TSO toleration)?
One can certainly write a Rexx interpreter (or compiler, for that matter),
and run it under TSO and/or ISPF; in that sense it*tolerates* those
environments. But for reasons known only to IBM, the interfaces needed to
implement*integration* with the TSO/E and ISPF environments are
undocumented. It used to be possible to write one's own Terminal Monitor
Program (TMP), and there was even a book describing how to do so. With
TSO/E that book was dropped, and while one can guess at much of what needs
to be done, there are OCO control blocks and interfaces that inhibit
implementing interfaces like Address TSO and Address ISPF.
Of course the same thing inhibits implementing Lua or Python or <your
favourite interpreted language> in the TSO/E environment as much as it does
competitive Rexxs.
TSO is easy to integrate using IKJEFTSR in C Lua modules.
-- REXX --
call outtrap 'o.'
"LISTALC"
do i = 1 to o.0 say o.i end
-- Lua --
local o = tso.exec("LISTALC")
for line in o do print(line) end
ISPF is difficult. That's where the real integration with REXX works
nicely, the binding between REXX variables and the ISPF function
variable pool. And you're right, there's no published API
to do something similar. A service that could return a list similar to
option 7.3 would make this easy. But even then it's not ideal in
languages with lexical scoping to "pollute" the environment with global
variables. For Lua I decided to map ISPF variables to tables using the
VDEFINE service. The variables are cleaned up with VDELETE when the
garbage collector destroys the table or explicitly with a release()
function.
local row = ispf.bind {
{ "name", "char", 20 },
{ "age", "int" },
{ "addr", "char", 60 },
}
ispexec("TBCREATE TAB NAMES(NAME,AGE,ADDR) NOWRITE REPLACE")
row.name = "Sherlock"
row.age = 64
row.addr = "221b Baker Street"
ispexec("TBADD TAB")
Of course, this looks like a step down. It's more code and strings are
fixed length. But the real benefit over REXX comes with modules. I find
with REXX it's impossible to apply the DRY principle.
-- REXX --
"LMINIT DATAID(ID) DATASET(DSNAME) ENQ(SHR)"
"LMOPEN DATAID(&ID) OPTION(INPUT)"
member = ''
do forever
"LMMLIST DATAID(&ID) OPTION(LIST) MEMBER(MEMBER)"
if rc > 0 then leave
say member
end
"LMCLOSE DATAID(&ID)"
"LMFREE DATAID(&ID)"
-- Lua --
local ISPF = require("ISPF")
ISPF.MemberList(dsname, "SHR"):foreach(function (member)
print(member.name) end)
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [email protected] with the message: INFO IBM-MAIN