Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Ability to pull job information from MVS environment

2,533 views
Skip to first unread message

Wagner, David --- Senior Programmer Analyst --- CFS

unread,
Jul 26, 2010, 1:59:59 PM7/26/10
to
Another question is can I use Rexx to get information concerning
a particular job and know if it has run today and/or whether it was
successful or not..

I am trying to gather information on particular jobs that are
running, but want to do this dynamically. We have a third party setup
(JHS), but have never been able to find an interface that would allow me
to enter job(s) and return the status on them dynamically..

So is it possible to pull the start/end/status of a job that has
or has not run(obviously if not run, then not found) today??

If you have any questions and/or problems, please let me know.
Thanks.

Wags ;)
David R. Wagner
Senior Programmer Analyst
FedEx Services
1.719.484.2097 Tel
1.719.484.2419 Fax
1.408.623.5963 Cell
http://Fedex.com/us


----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to LIST...@VM.MARIST.EDU with the message: INFO TSO-REXX

Bob Stark

unread,
Jul 26, 2010, 3:35:03 PM7/26/10
to
Base TSO REXX does not have such an interface. You could look to see if a job was running at this particular instant (using the storage() function to look at the ASCB), but not a "historical" lookup.

But don't lose hope just yet.

If you run some console automation software (e.g. AF Operator), it could watch for job end messages and save the date/time/maxCC in a variable, which you could query later via TSO REXX. The specifics of this approach vary based on which console automation software you run (BMC AutoOPERATOR, CA OPS-MVS, SA z/OS, AF Operator, etc.). Write back with that info for additional details.

If this is a production batch job submitted by a job scheduler, you can use the scheduler's REXX API to look up job history. Not every job scheduler has a REXX API, so again, post back with details on what job scheduler you use, if any.

You can also use the REXX API to SDSF, CA SysView, or IOF (and probably others) to examine either the job output, or the syslog, via REXX. As long as the syslog wasn't written out, or the job output purged, you could find the job there.

Regards,

Bob Stark

ProTech - When you're serious about Systems Management
Consulting, Software, and Training for z/OS, UNIX and Internet
www.protechtraining.com 800-373-9188 x151 Cell: 412-445-8072

--
If this email is spam, report it here:
http://www.onlymyemail.com/view/?action=reportSpam&Id=Mzg3MzE6MTEyODE3NDU5MTpic3RhcmtAcHJvdGVjaHB0cy5jb206ZGVsaXZlcmVk

Jeff Byrum

unread,
Jul 26, 2010, 3:52:13 PM7/26/10
to
This is just a quick reply; I can provide more detail later if you need it.

You can actually run SDSF as a batch job (EXEC PGM=SFSF), and there's a manual that describes how to set up the input commands (sorry, I don't have the reference handy right now). It's a little tricky, and took me a fair amount of experimentation to get the right commands for what I wanted to do. It's not intuitively obvious, even if you know SDSF fairly well.

So basically anything you can see using SDSF, you can get by running a batch job.

So from there, it's only a small step to creating a REXX exec that sets up the needed commands, allocates the input and output files, and then invokes "SDSF": ADDRESS LINKMVS "SDSF SDSFPARM" (in my case SDSFPARM was null, and all the logic was in the input commands).

You can run a REXX Exec online that does this, but I even got it working so that I could submit a batch job, which was a REXX program running under batch ISPF, that could query its own status.

Again, the way I got this all working was by experimenting over and over with a batch job that just executed SDSF directly (EXEC PGM=SDSF), and then once I got the right set of commands for what I needed, I incorporated them into the REXX Exec.

Again, sorry this is so sketchy -- let me know if you need more info.

Jeff

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf Of Wagner, David --- Senior Programmer Analyst --- CFS
Sent: Monday, July 26, 2010 1:58 PM
To: TSO-...@VM.MARIST.EDU
Subject: Ability to pull job information from MVS environment

Wagner, David --- Senior Programmer Analyst --- CFS

unread,
Jul 26, 2010, 4:16:13 PM7/26/10
to
>-----Original Message-----
>From: TSO REXX Discussion List [mailto:TSO-...@vm.marist.edu] On Behalf Of
>Bob Stark
>Sent: Monday, July 26, 2010 13:34
>To: TSO-...@vm.marist.edu
>Subject: Re: [TSO-REXX] Ability to pull job information from MVS
>environment
>
>Base TSO REXX does not have such an interface. You could look to see if a
>job was running at this particular instant (using the storage() function to
>look at the ASCB), but not a "historical" lookup.
>
>But don't lose hope just yet.
>
>If you run some console automation software (e.g. AF Operator), it could
>watch for job end messages and save the date/time/maxCC in a variable,
>which you could query later via TSO REXX. The specifics of this approach
>vary based on which console automation software you run (BMC AutoOPERATOR,
>CA OPS-MVS, SA z/OS, AF Operator, etc.). Write back with that info for
>additional details.
>
We are running under CA7 Scheduler (at least that is the terminology used by Computer Operations) and as stated in the initial email, the data is not around at the completion of a 'production job', but moved in 99% of the processing, so the jcl history can be reviewed by JHS software ( SystemWare ).

Steve Comstock

unread,
Jul 26, 2010, 4:41:37 PM7/26/10
to
Wagner, David --- Senior Programmer Analyst --- CFS wrote:
> Another question is can I use Rexx to get information concerning
> a particular job and know if it has run today and/or whether it was
> successful or not..
>
> I am trying to gather information on particular jobs that are
> running, but want to do this dynamically. We have a third party setup
> (JHS), but have never been able to find an interface that would allow me
> to enter job(s) and return the status on them dynamically..
>
> So is it possible to pull the start/end/status of a job that has
> or has not run(obviously if not run, then not found) today??
>
> If you have any questions and/or problems, please let me know.
> Thanks.
>
> Wags ;)
> David R. Wagner
> Senior Programmer Analyst
> FedEx Services
> 1.719.484.2097 Tel
> 1.719.484.2419 Fax
> 1.408.623.5963 Cell
> http://Fedex.com/us

Well, can't you OUTTRAP the results of STATUS and OUTPUT commands
and parse the result? Seems like it would be a low overhead approach.

ST
ST jobname
ST jobname(Jjobid)

return one of:

NO JOBS FOUND
JOB NOT FOUND
JOB WAITING EXECUTION
JOB EXECUTING
JOB ON OUTPUT QUEUE

then if the job is on the output queue, issue

OUTPUT (jobname[Jjobid]) PRINT({*|dsname})

where the * option will put output to the terminal, and dsname
will put the output to <hlq>.<dsname>.OUTLIST where you can then
process it.


--

Kind regards,

-Steve Comstock
The Trainer's Friend, Inc.

303-393-8716
http://www.trainersfriend.com

* To get a good Return on your Investment, first make an investment!
+ Training your people is an excellent investment

Wagner, David --- Senior Programmer Analyst --- CFS

unread,
Jul 26, 2010, 4:52:23 PM7/26/10
to
>-----Original Message-----
>From: TSO REXX Discussion List [mailto:TSO-...@vm.marist.edu] On Behalf Of
>Steve Comstock
>Sent: Monday, July 26, 2010 14:37
>To: TSO-...@vm.marist.edu
>Subject: Re: [TSO-REXX] Ability to pull job information from MVS
>environment
>
That is the problem in that the output is saved immediately at the completion of the job into the world as it is known by JHS ( JCL Output Archiver ). I am not a REXX programmer, but one who gathers existing reports, works with the reports and generates internal emails for our organization. I currently have an unique trigger dsn created which is then processed by other programs from another site. Instead of the trigger dsn, I was attempting to come up with a simple approach looking at my current list of say 30-45 jobs, gather the start, stop and condition code of the processing. Check if today and have not processed yet, then generate the process to do the work on email A. Then loop on this data until complete, starting other processes as needed, write out the jobs that were worked on with the date/time/condtion, so I know whether to do the work or not. They for the most part run once a day spread out over the day.
The current setup has been working well, but running into some other issues and was looking to see if there was alternative to what I am doing...

As they say, I have a enough knowledge to be dangerous, but not enough to possibly get the job done.

That is what is going on in a nutshell. I was thinking it should not be that big a thing, but obviously it is and can be.

I appreciate the insight and the time..



      Thanks.
 
Wags ;)
David R. Wagner
Senior Programmer Analyst
FedEx Services
1.719.484.2097 Tel
1.719.484.2419 Fax
1.408.623.5963 Cell
http://Fedex.com/us


>

Robert Zenuk

unread,
Jul 26, 2010, 5:26:04 PM7/26/10
to
While there are several round about ways to find this stuff, they are all
dependent on the tools you have in your shop. Most likely FEDEX has a job
scheduling product that could be queried for a specific jobname. That is
probably the best and most expedient way to get your answer.

If the job is not a scheduled job, your best bet is probably looking at the
spool for SYSOUT from the job. using the SDSF/REXX API is probably your
best bet here.


In a message dated 7/26/2010 10:59:49 A.M. US Mountain Standard Time,
david....@FEDEX.COM writes:

Another question is can I use Rexx to get information concerning
a particular job and know if it has run today and/or whether it was
successful or not..

I am trying to gather information on particular jobs that are
running, but want to do this dynamically. We have a third party setup
(JHS), but have never been able to find an interface that would allow me
to enter job(s) and return the status on them dynamically..

So is it possible to pull the start/end/status of a job that has
or has not run(obviously if not run, then not found) today??

If you have any questions and/or problems, please let me know.
Thanks.

Wags ;)
David R. Wagner
Senior Programmer Analyst
FedEx Services
1.719.484.2097 Tel
1.719.484.2419 Fax
1.408.623.5963 Cell
http://Fedex.com/us

Farley, Peter x23353

unread,
Jul 26, 2010, 5:27:31 PM7/26/10
to

You might check out the JHS Utilities manual for the print utility program (JHSPRINT). The drawback (at least in the JHS we run here) is that you have to know the job number as well as the job name, but if you have another way to determine what the job number is, then you can "print" DSID(2) for that job name and number, which is the DSID for the JESMSGLG output collected by JHS. Write the output to a file and then you could read the file using REXX and extract all the information you have requested.

Here is a simple example that I can share; replace the <...> bracketed information with your installation and job names/numbers:

//GETSYSLG EXEC PGM=JHSPRINT
//STEPLIB DD DSN=<your-JHS-library-HLQ>.JHSLIB,DISP=SHR
//SYSPRINT DD SYSOUT=*
//OUTFILE DD DISP=(NEW,CATLG,CATLG),DSN=&SYSUID..<jobname>.JESMSGLG,
// UNIT=SYSDA,SPACE=(TRK,(15,15),RLSE),
// DSORG=PS,RECFM=VBA,LRECL=259,BLKSIZE=0
//SYSIN DD *
OPTIONS OUTFILE(OUTFILE)
LOGON SYSTEM(<systemname of your JHS>) FROMSYS(<jobname of your JHS>)
TEXT
TEXT
PRINT JOB(<yourjobname>) JOBNUMBER(<yourjobnumber>) DSID(00002)
//*

HTH

Peter


This message and any attachments are intended only for the use of the addressee and
may contain information that is privileged and confidential. If the reader of the
message is not the intended recipient or an authorized representative of the
intended recipient, you are hereby notified that any dissemination of this
communication is strictly prohibited. If you have received this communication in
error, please notify us immediately by e-mail and delete the message and any
attachments from your system.

Robert Zenuk

unread,
Jul 26, 2010, 5:30:35 PM7/26/10
to
While there are many ways to try and skin that cat using several different
tools, it is all dependent on the tools you have in house. The real
answer is probably to find out how to interface with your job scheduler package.

If the job is not scheduled, here is some quick and dirty REXX using the
SDSF/REXX API to list all the jobs matching your provided jobname in the
HOLD queue and an attempt to look for them currently running.

Not perfect, but a start...

000001 /* rexx */
000002 arg jobname .

000003 if isfcalls('ON') <> 0 then exit 99

000004 isfprefix = jobname

000005 isfsort = 'dsdate d'

000006 address SDSF "ISFEXEC H"

000007 say isfrows 'Held Jobs matching' jobname',RC='RC

000008 say

000009 say 'JOBNAME JOBNUM DATE TIME RECORDS MAX-RC'

000010 say '---------------------------------------------------------'

000011 do h=1 to isfrows

000012 say left(jname.h,8) jobid.h dsdate.h right(reccnt.h,10)
retcode.h
000013 end

000014 say

000015 drop isfsort

000016 address SDSF "ISFEXEC DA"

000017 say isfrows 'Active Jobs matching' jobname',RC='RC

000018 say

000019 say 'JOBNAME JOBNUM'

000020 say '-----------------'

000021 do a=1 to isfrows

000022 say left(jname.a,8) jobid.a

000023 end

000024 call isfcalls 'OFF'

Rob

In a message dated 7/26/2010 10:59:49 A.M. US Mountain Standard Time,
david....@FEDEX.COM writes:

Another question is can I use Rexx to get information concerning
a particular job and know if it has run today and/or whether it was
successful or not..

I am trying to gather information on particular jobs that are
running, but want to do this dynamically. We have a third party setup
(JHS), but have never been able to find an interface that would allow me
to enter job(s) and return the status on them dynamically..

So is it possible to pull the start/end/status of a job that has
or has not run(obviously if not run, then not found) today??

If you have any questions and/or problems, please let me know.
Thanks.

Wags ;)
David R. Wagner
Senior Programmer Analyst
FedEx Services
1.719.484.2097 Tel
1.719.484.2419 Fax
1.408.623.5963 Cell
http://Fedex.com/us

Robert Zenuk

unread,
Jul 26, 2010, 5:41:14 PM7/26/10
to
It sounds like you should have the Job owner(s) or possibly Job Scheduling
folks add an SMTP email step to the end of the jobs or use a CA-7 option
based on the successful completion condition to send you an email that you
can use as a worklist...

Rob

In a message dated 7/26/2010 1:52:20 P.M. US Mountain Standard Time,
david....@FEDEX.COM writes:

>-----Original Message-----
>From: TSO REXX Discussion List [mailto:TSO-...@vm.marist.edu] On Behalf
Of

>Steve Comstock
>Sent: Monday, July 26, 2010 14:37
>To: TSO-...@vm.marist.edu

>Subject: Re: [TSO-REXX] Ability to pull job information from MVS
>environment
>

>Wagner, David --- Senior Programmer Analyst --- CFS wrote:
>> Another question is can I use Rexx to get information concerning
>> a particular job and know if it has run today and/or whether it was
>> successful or not..
>>
>> I am trying to gather information on particular jobs that are
>> running, but want to do this dynamically. We have a third party setup
>> (JHS), but have never been able to find an interface that would allow me
>> to enter job(s) and return the status on them dynamically..
>>
>> So is it possible to pull the start/end/status of a job that has
>> or has not run(obviously if not run, then not found) today??
>>
>> If you have any questions and/or problems, please let me know.
>> Thanks.
>>
>> Wags ;)
>> David R. Wagner
>> Senior Programmer Analyst
>> FedEx Services
>> 1.719.484.2097 Tel
>> 1.719.484.2419 Fax
>> 1.408.623.5963 Cell
>> http://Fedex.com/us
>

>Well, can't you OUTTRAP the results of STATUS and OUTPUT commands
>and parse the result? Seems like it would be a low overhead approach.
>
>ST
>ST jobname
>ST jobname(Jjobid)
>
>return one of:
>
>NO JOBS FOUND
>JOB NOT FOUND
>JOB WAITING EXECUTION
>JOB EXECUTING
>JOB ON OUTPUT QUEUE
>
>then if the job is on the output queue, issue
>
>OUTPUT (jobname[Jjobid]) PRINT({*|dsname})
>
>where the * option will put output to the terminal, and dsname
>will put the output to <hlq>.<dsname>.OUTLIST where you can then
>process it.
>
>
>

That is the problem in that the output is saved immediately at the
completion of the job into the world as it is known by JHS ( JCL Output Archiver
). I am not a REXX programmer, but one who gathers existing reports, works
with the reports and generates internal emails for our organization. I
currently have an unique trigger dsn created which is then processed by other
programs from another site. Instead of the trigger dsn, I was attempting to
come up with a simple approach looking at my current list of say 30-45 jobs,
gather the start, stop and condition code of the processing. Check if
today and have not processed yet, then generate the process to do the work on
email A. Then loop on this data until complete, starting other processes as
needed, write out the jobs that were worked on with the date/time/condtion,
so I know whether to do the work or not. They for the most part run once a
day spread out over the day.
The current setup has been working well, but running into some other
issues and was looking to see if there was alternative to what I am doing...

As they say, I have a enough knowledge to be dangerous, but not enough to
possibly get the job done.

That is what is going on in a nutshell. I was thinking it should not be
that big a thing, but obviously it is and can be.

I appreciate the insight and the time..

Thanks.

Wags ;)
David R. Wagner
Senior Programmer Analyst
FedEx Services
1.719.484.2097 Tel
1.719.484.2419 Fax
1.408.623.5963 Cell
http://Fedex.com/us


>


>--
>
>Kind regards,
>
>-Steve Comstock
>The Trainer's Friend, Inc.
>
>303-393-8716
>http://www.trainersfriend.com
>
>* To get a good Return on your Investment, first make an investment!
> + Training your people is an excellent investment
>

Kopischke, David G.

unread,
Jul 26, 2010, 8:30:41 PM7/26/10
to
David,
It sounds like you've got some experience with taking report text apart and reformatting it into something useful. This JCL produces a history report out of CA-7. You'll have to track down your CA-7 log files or archive files. The timing of those being available might be a problem depending on how current you need the data.

Anyway, find those datasets, change "<JOBNAM>" in the SYSIN card to a JOB name you want information for and run this and see if it produces something useful for what you're trying to do.

Thanks,
Dave K.


P.S. The comments at the end of this explain what the control card fields are in case you want to query for this JOB within specific run times or ranges or whatever.


//REPORT EXEC PGM=SASSHIS8,PARM='O,100000'
//*
//SYSLIST DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,8)
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,8)
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,8)
//SORTWK04 DD UNIT=SYSDA,SPACE=(CYL,8)
//SORTWK05 DD UNIT=SYSDA,SPACE=(CYL,8)
//SORTWK06 DD UNIT=SYSDA,SPACE=(CYL,8)
//CNTLREPT DD SYSOUT=*,DCB=BLKSIZE=133
//UCC7HIST DD DUMMY, DSN=CA7.LOG.DATASET.NAME,
// DISP=SHR
//*
//UCC7ARCH DD DSN=CA7.ARCHIVE.DATASET.NAME,
// DISP=SHR
//SYSIN DD *
06HIST RPT <JOBNAM> 123INDEX
/* |_______||_______|
//* POS 1 - 2 REPORT ID = 06
//* POS 3 - 10 REQUEST ID LITERAL (BANNER DATA)
//* POS 11 - 15 FROM DATE
//* POS 16 - 19 FROM TIME
//* POS 20 - 24 TO DATE
//* POS 25 - 28 TO TIME
//* POS 29 - 36 JOBNAME
//* POS 37 - 38 RESERVED
//* POS 39 - 41 SORT ORDER
//* 1 = DATE/TIME THE LOG RECORD WAS WRITTEN
//* 2 = JOB NAME
//* 3 = SYSTEM ID
//* POS 42 - 46 LITERAL "INDEX" - ONE LINE INDEX ENTRY PER JOB IS PRINTED
//* POS 47 - 50 SMFID TO REPORT ON
//* POS 51 - 80 USER COMMENTS
//*

>
>
We are running under CA7 Scheduler (at least that is the terminology used by Computer Operations) and as stated in the initial email, the data is not around at the completion of a 'production job', but moved in 99% of the processing, so the jcl history can be reviewed by JHS software ( SystemWare ).
 

------------------------------------------------------------------------------
This e-mail transmission may contain information that is proprietary, privileged and/or confidential and is intended exclusively for the person(s) to whom it is addressed. Any use, copying, retention or disclosure by any person other than the intended recipient or the intended recipient's designees is strictly prohibited. If you are not the intended recipient or their designee, please notify the sender immediately by return e-mail and delete all copies. OppenheimerFunds may, at its sole discretion, monitor, review, retain and/or disclose the content of all email communications.
==============================================================================

Donald Johnson

unread,
Jul 27, 2010, 8:48:46 AM7/27/10
to
This request sounds like it is really two requests:
1. Capture and store information from a job (date/timestamp, return codes)
2. Query information about a job (Did it run? What was the RC?)

From my experience you have a couple options (maybe already touched on
here),
1. If the JCL is up for change, add a control step to the end of the job to
update a database file of some sort with the relevant information (Jobname,
Run Times, High CC, etc.). This has applicability beyond just this need.
2. If you have an automation tool, have it capture the relevant messages
(Submitted/Started, Step CC, Max CC, etc.) and update a DB file in the same
manner.
3. Is there a Jes Exit that can be used to filter on jobname and to fire on
your selected jobs to retrieve the data for you and store it?
Options 2 and 3 are the least likely to bypass the process, as the
programmer could easily remove the recording step when running the job
manually. However, if you are dependent on the jobname as the filter,
changing that will bypass the process, too.

These are a couple ideas to mix in the pot of stew offered by lots of others
so far...

*dj*

> //UCC7HIST DD DUMMY, DSN=CA7.LOG.DATASET.NAME<http://ca7.log.dataset.name/>
> ,
> // DISP=SHR
> //*
> //UCC7ARCH DD DSN=CA7.ARCHIVE.DATASET.NAME<http://ca7.archive.dataset.name/>

Mickey

unread,
Jul 30, 2010, 7:36:38 AM7/30/10
to
I would more look into the automated operator here than the job scheduler.
Most shops have either CA/OPS or AUTO-OPER. The latter has a native Rexx
interface, if wouldn't take much to set it up to capture certain info about
jobs and put them to a file.

Mickey

--------------------------------------------------
From: "Robert Zenuk" <Robz...@AOL.COM>
Sent: Monday, July 26, 2010 5:25 PM
To: <TSO-...@VM.MARIST.EDU>


Subject: Re: [TSO-REXX] Ability to pull job information from MVS environment

> While there are several round about ways to find this stuff, they are all

Robert Zenuk

unread,
Jul 30, 2010, 10:32:37 AM7/30/10
to
First of all, I agree. It would be simple with any REXX aware automation
product (including Netview/SA, SysRexx, ACC and some defunct products like
Zack and AF/Oper) to capture IEF403I/IEF404I (or others) and do stuff.

I guess I was coming from my perspective in a large shop and projecting
that onto FEDEX as another large shop... We would never entertain a
"one-off" automation request for a single job unless it was a critical path job
that had enterprise-wide significance. We would have thousands of these.
Having averaged over a million scheduled batch jobs per month for the last
10 years, this would be an unmanageable stream of requests.

All batch customers have access to the Job Scheduler, Restart Manager and
Sysout Management products and are provided with training on the online
query tools and provided JCL examples for batch utilities. Without a self
help approach, we would be inundated with requests. This mandated several
features in the products selected to insure it was possible to get the self
help. Things like user customization (notifications, email alerts, pager
alerts, etc) had to be easy for a customer to accomplish. Online history and
query tools were also a high priority in product selection.

Most customers that need extra/enhanced application specific runtime
information will tack extra steps on the end of their jobs to post details to a
database, send an SMTP email or log to a history file or something. Many
jobs will write all reports to DASD and have post scraper steps to generate
the required results. However, the desired approach is to modify the
original program to implement the new function. Since project schedules and
delivery dates are driven by others, this can mean interim solutions.

So, trying to stay off the soap-box and provide some value I provides my
SDSF/REXX suggestion...

Rob

In a message dated 7/30/2010 4:36:11 A.M. US Mountain Standard Time,

Bob Welch

unread,
Aug 24, 2010, 9:36:39 AM8/24/10
to
> mick...@COMCAST.NET writes:
>
> I would  more look into the automated operator here than the job scheduler.
> Most  shops have either CA/OPS or AUTO-OPER. The latter has a native  Rexx
> interface, if wouldn't take much to set it up to capture certain info  about
> jobs and put them to a  file.
>
> Mickey
>
> --------------------------------------------------
> From:  "Robert Zenuk" <Robze...@AOL.COM>

> Sent: Monday, July 26, 2010 5:25  PM
> To: <TSO-R...@VM.MARIST.EDU>

> Subject: Re: [TSO-REXX] Ability to  pull job information from MVS
> environment
>
>
>
>
>
>
>
> > While there are several  round about ways to find this stuff, they are all
> > dependent on the  tools you have in your shop.  Most likely FEDEX has a
> job
> >  scheduling product that could be queried for a specific jobname.  That
> is
> > probably the best and most expedient way to get your  answer.
>
> > If the job is not a scheduled job, your best bet is  probably looking at
> > the
> > spool for SYSOUT from the job.   using the SDSF/REXX API is probably your
> > best bet  here.
>
> > In a message dated 7/26/2010 10:59:49 A.M. US  Mountain Standard Time,
> > david.wag...@FEDEX.COM writes:
>
> >  Another question is can I use Rexx to get information concerning
> >  a  particular job and know if it has run today and/or whether it   was
> > successful or not..
>
> > I am trying to gather   information on particular jobs that are
> > running, but want to do  this  dynamically. We have a third party setup
> > (JHS), but have  never been able to  find an interface that would allow me
> > to  enter job(s) and return the status  on them dynamically..
>
> >  So is it possible to pull the  start/end/status of a job that has
> >  or has not run(obviously if not run,  then not found)  today??
>
> > If you have  any questions and/or problems,  please let me know.
> > Thanks.
>
> > Wags ;)
> > David R.  Wagner
> > Senior Programmer  Analyst
> > FedEx Services
> >  1.719.484.2097 Tel
> > 1.719.484.2419 Fax
> > 1.408.623.5963   Cell
> >http://Fedex.com/us
>
> >  ----------------------------------------------------------------------
> >  For  TSO-REXX subscribe / signoff / archive access instructions,
> >  send email to  LISTS...@VM.MARIST.EDU with the message: INFO   TSO-REXX

>
> >  ----------------------------------------------------------------------
> >  For TSO-REXX subscribe / signoff / archive access instructions,
> > send  email to LISTS...@VM.MARIST.EDU with the message: INFO  TSO-REXX

>
> ----------------------------------------------------------------------
> For  TSO-REXX subscribe / signoff / archive access instructions,
> send email to  LISTS...@VM.MARIST.EDU with the message: INFO  TSO-REXX

>
> ----------------------------------------------------------------------
> For TSO-REXX subscribe / signoff / archive access instructions,
> send email to LISTS...@VM.MARIST.EDU with the message: INFO TSO-REXX- Hide quoted text -
>
> - Show quoted text -

David, you should definitely contact the Systemware Technical support
folks, and tell them what you want, and ask them for the best
solution. I've had the opportunity to do just that with them in the
past, and they are fairly good to work with. We utilize the Xptr (now
CS/z side of their software, so I am not as familiar with the JHS
offering. I do know, they have multiple ways of setting up 'report
distribution'/bundling in it, and would not be surprised to see it in
the JHS offering. If it is in there, they also have email drivers,
where you may be able to set up index programs to look at the job as
it is being captured into JHS and cause automatic emails to come out,
and possibly to write to MVS dsns at the same time (if you want to).
We do that with the CS Z offering, with the information that is
collected into their JHSLOG for the started task.

Regards,
Bob

Thom Stone

unread,
Sep 9, 2010, 12:22:47 PM9/9/10
to
Hello,
I have the following short sample of code that I want to use in a
larger project, but I'd prefer not to use interpret if possible.

/* REXX */
CALL RUNMON GACHKACB
SAY 'NTV309I MYRC='MYRC
EXIT


RUNMON:
ARG TMPMON
INTERPRET 'MYRC='TMPMON||'(VTHOM)'
RETURN MYRC

This is going to be a dynamic routine that calls a monitor. In this
case I simply hardcoded GACHKACB. In the real world the routine will
lookup the routine name and pass it to the code so I have to be able
to interpret TMPMON somehow at runtime. Does anyone have any
thoughts? Thanks for your ideas. I do have the CALL VALUE in my
solution package, but I do not see how this will get me closer to a
solution in this case.


Thanks,
Thom Stone
Deere & Company
Capacity Planning and Performance
NetView Automation Team
StoneT...@JohnDeere.com
ston...@mchsi.com
ts2...@gmail.com
"Run Smart... Run Fast... Run Lean with our Great Machines"

Thom Stone

unread,
Sep 9, 2010, 1:32:35 PM9/9/10
to
Hello,
I have the following short sample of code that I want to use in a larger project, but I'd prefer not to use interpret if possible.

/* REXX */
CALL RUNMON GACHKACB
SAY 'NTV309I MYRC='MYRC
EXIT


RUNMON:
ARG TMPMON
INTERPRET 'MYRC='TMPMON||'(VTHOM)'
RETURN MYRC

This is going to be a dynamic routine that calls a monitor. In this case I simply hardcoded GACHKACB. In the real world the routine will lookup the routine name and pass it to the code so I have to be able to interpret TMPMON somehow at runtime. Does anyone have any thoughts? Thanks for your ideas. I do have the CALL VALUE 'GA.JOBNAME.'PTR, MBRNAME in my solution package, but I do not see how this will get me closer to a solution in this case.

Thanks,
Thom Stone
Deere & Company
Capacity Planning and Performance
NetView Automation Team
StoneT...@JohnDeere.com

"Run Smart... Run Fast... Run Lean with our Great Machines"

----------------------------------------------------------------------

Thom

unread,
Sep 9, 2010, 1:39:29 PM9/9/10
to
Hello,
I have the following short sample of code that I want to use in a
larger project, but I'd prefer not to use interpret if possible.

/* REXX */
CALL RUNMON GACHKACB
SAY 'NTV309I MYRC='MYRC
EXIT


RUNMON:
ARG TMPMON
INTERPRET 'MYRC='TMPMON||'(VTHOM)'
RETURN MYRC

This is going to be a dynamic routine that calls a monitor. In this
case I simply hardcoded GACHKACB. In the real world the routine will
lookup the routine name and pass it to the code so I have to be able
to interpret TMPMON somehow at runtime. Does anyone have any

thoughts? Thanks for your ideas. I do have the CALL VALUE in my

Vitonis, Tony

unread,
Sep 9, 2010, 2:12:29 PM9/9/10
to
Does the code below do what you're expecting?

Tony

/* REXX */

CALL RUNMON GACHKACB
SAY 'NTV309I MYRC='MYR

EXIT

RUNMON:
ARG TMPMON
MYRC=TMPMON||'(VTHOM)'
RETURN MYRC

Thom

unread,
Sep 9, 2010, 2:35:54 PM9/9/10
to
> StoneThom...@JohnDeere.com

> "Run Smart... Run Fast... Run Lean with our Great Machines"
>
> ----------------------------------------------------------------------
> For TSO-REXX subscribe / signoff / archive access instructions,
> send email to LISTS...@VM.MARIST.EDU with the message: INFO TSO-REXX- Hide quoted text -
>
> - Show quoted text -

Not quite:
NTV309I MYRC=GACHKACB(VTHOM)
but I'll try and massage it a bit more.

Thom

unread,
Sep 9, 2010, 2:54:45 PM9/9/10
to
On Sep 9, 1:12 pm, Tony.Vito...@CA.COM (Vitonis, Tony) wrote:
> StoneThom...@JohnDeere.com

> "Run Smart... Run Fast... Run Lean with our Great Machines"
>
> ----------------------------------------------------------------------
> For TSO-REXX subscribe / signoff / archive access instructions,
> send email to LISTS...@VM.MARIST.EDU with the message: INFO TSO-REXX- Hide quoted text -
>
> - Show quoted text -

This works if you are returning Return Codes:


/* REXX */
CALL RUNMON GACHKACB
SAY 'NTV309I MYRC='MYRC
EXIT


RUNMON:
TRACE O
ARG TMPMON
TMPVAR=TMPMON 'VTHOM'
TMPVAR
MYRC=RC
RETURN MYRC


I'll have to keep thinking about this for values.

Paul Gilmartin

unread,
Sep 9, 2010, 4:42:15 PM9/9/10
to
On 09/09/10 12:11, Vitonis, Tony wrote:
> Does the code below do what you're expecting?
>
> Tony
>
> /* REXX */
>
> CALL RUNMON GACHKACB
> SAY 'NTV309I MYRC='MYR
> EXIT
>
> RUNMON:
> ARG TMPMON
> MYRC=TMPMON||'(VTHOM)'
> RETURN MYRC
>
No, because it does not call the function whose name is stored
in TMPMON.

> -----Original Message-----
> From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf Of Thom Stone
> Sent: Thursday, September 09, 2010 1:32 PM
> To: TSO-...@VM.MARIST.EDU
> Subject: Help with INTERPRET
>
> Hello,
> I have the following short sample of code that I want to use in a larger project, but I'd prefer not to use interpret if possible.
>
> /* REXX */
> CALL RUNMON GACHKACB
> SAY 'NTV309I MYRC='MYRC
> EXIT
>
>
> RUNMON:
> ARG TMPMON
> INTERPRET 'MYRC='TMPMON||'(VTHOM)'
> RETURN MYRC


-- gil

Glenn Knickerbocker

unread,
Sep 9, 2010, 5:21:46 PM9/9/10
to
On 09/09/2010 01:32 PM, Thom Stone wrote:
> /* REXX */
> CALL RUNMON GACHKACB
> SAY 'NTV309I MYRC='MYRC
> EXIT

(Note that here you're using the variable MYRC that was set in the
RUNMON routine, and ignoring the result that it returned. The value it
returns is put in the variable RESULT.)

> RUNMON:
> ARG TMPMON
> INTERPRET 'MYRC='TMPMON||'(VTHOM)'
> RETURN MYRC

Does the monitor exec return anything other than a number, and does it
care how it was called? If not, how about just issuing it as a command?

RunMon:
Arg tmpMon
tmpMon vthom
Return rc

If you do need to handle non-numeric results, or if the exec is
sensitive to whether it's called as a command or a function, you're
stuck with either INTERPRET or a hardcoded list of monitor names:

RunMon:
Arg tmpMon
Select
When tmpMon = 'GACHKACB' then myrc = 'GACHKACB'(vthom)
When tmpMon = 'BLAHBLAH' then myrc = 'BLAHBLAH'(vthom)
...
End
Return myrc

If they were internal routines, you could use SIGNAL VALUE to pass
control to them:

RunMon:
Arg tmpMon
Signal Value tmpMon

GACHKACB:
...
Return ...

BLAHBLAH:
...
Return ...

But function and subroutine calls just don't have any comparable way to
specify the name of the routine as an expression.

¬R

Vitonis, Tony

unread,
Sep 9, 2010, 5:25:23 PM9/9/10
to
Oho! I missed that wrinkle.

Classic REXX doesn't have a CALL [variable] construct. Not sure about added-value versions out there.

Tony

-----Original Message-----
From: Paul Gilmartin
Sent: Thursday, September 09, 2010 4:40 PM
To: TSO-...@VM.MARIST.EDU

Subject: Re: Help with INTERPRET

No, because it does not call the function whose name is stored in TMPMON.

On 09/09/10 12:11, Vitonis, Tony wrote:


> Does the code below do what you're expecting?
>
> Tony
>
> /* REXX */
>
> CALL RUNMON GACHKACB

> SAY 'NTV309I MYRC='MYRC
> EXIT
>
> RUNMON:
> ARG TMPMON

> MYRC=TMPMON||'(VTHOM)'
> RETURN MYRC

Thom Stone

unread,
Sep 9, 2010, 8:31:06 PM9/9/10
to

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf Of

Glenn Knickerbocker
Sent: Thursday, September 09, 2010 4:21 PM
To: TSO-...@VM.MARIST.EDU

GACHKACB:
...
Return ...

BLAHBLAH:
...
Return ...

¬R

Thanks for the thoughts. I am not certain the monitors will always return a
number. It would be nice, but one never knows. At the moment I am sticking
with one of the versions on INTERPRET unless I figure out another way to do
this. Sorry about the mutiple posts. Had some issues posting from work and
finding them in google groups. But I learned, I hope.

Itschak Mugzach

unread,
Sep 10, 2010, 1:55:56 AM9/10/10
to
Did you try myrc=tmpmon||'('Value(VTHOM)')' ?

ITschak

> ŹR

Paul Gilmartin

unread,
Sep 10, 2010, 10:26:38 AM9/10/10
to
On Sep 9, 2010, at 15:21, Glenn Knickerbocker wrote:

> On 09/09/2010 01:32 PM, Thom Stone wrote:
>> /* REXX */
>> CALL RUNMON GACHKACB
>> SAY 'NTV309I MYRC='MYRC
>> EXIT
>
> (Note that here you're using the variable MYRC that was set in the
> RUNMON routine, and ignoring the result that it returned. The value it
> returns is put in the variable RESULT.)
>
>> RUNMON:
>> ARG TMPMON
>> INTERPRET 'MYRC='TMPMON||'(VTHOM)'
>> RETURN MYRC
>
> Does the monitor exec return anything other than a number, and does it
> care how it was called? If not, how about just issuing it as a command?
>
> RunMon:
> Arg tmpMon
> tmpMon vthom
> Return rc
>

Despite the concern over INTERPRET (well founded unless the
programmer has complete control of its argument), issuing as
a command a string over which the programmer has no better
control is similarly risky.

> If you do need to handle non-numeric results, or if the exec is
> sensitive to whether it's called as a command or a function, you're
> stuck with either INTERPRET or a hardcoded list of monitor names:
>
> RunMon:
> Arg tmpMon
> Select
> When tmpMon = 'GACHKACB' then myrc = 'GACHKACB'(vthom)
> When tmpMon = 'BLAHBLAH' then myrc = 'BLAHBLAH'(vthom)
> ...

otherwise report error.

> End
> Return myrc
>
> If they were internal routines, you could use SIGNAL VALUE to pass
> control to them:
>
> RunMon:
> Arg tmpMon
> Signal Value tmpMon
>

Danger Will Robinson! This allows a maliciously crafted argument
to pass control to an arbitrary label within the EXEC.

-- gil

Stan Weyman

unread,
Sep 10, 2010, 11:24:36 AM9/10/10
to
<< Danger Will Robinson! >>

I just love references to 1960's campy shows... "Oh the pain, the pain...."

Stan Weyman
Senior Software Engineer
stan....@emc.com
EMC² (508)249-3966
where information lives
It is wise to keep in mind that neither
success nor failure is ever final...


-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@vm.marist.edu] On Behalf Of Paul Gilmartin
Sent: Friday, September 10, 2010 10:26 AM
To: TSO-...@vm.marist.edu
Subject: Re: [TSO-REXX] Help with INTERPRET

Bob Bridges

unread,
Sep 13, 2010, 6:58:39 AM9/13/10
to
I don't think that's the way to do it, Itzchak; I'm looking for

return value(tmpmon'(VTHOM)')

Still don't know whether VALUE is willing to call whatever routine whose
name was passed to tmpmon, though.

---
Bob Bridges, rhb...@attglobal.net, cell 336 382-7313
work bob.b...@libertymutual.com, 317 581-6487

/* Everyone is someone's wierdo. -Scott Adams, creator of "Dilbert" */

-----Original Message-----
From: Itschak Mugzach
Sent: Friday, September 10, 2010 01:56

Did you try myrc=tmpmon||'('Value(VTHOM)')' ?

-----Original Message-----
From: Thom Stone
Sent: Thursday, September 9, 2010 13:32

I have the following short sample of code that I want to use in a
larger project, but I'd prefer not to use interpret if possible.

/* REXX */


CALL RUNMON GACHKACB
SAY 'NTV309I MYRC='MYRC
EXIT

RUNMON:


ARG TMPMON
INTERPRET 'MYRC='TMPMON||'(VTHOM)'
RETURN MYRC

This is going to be a dynamic routine that calls a monitor. In this case I


simply hardcoded GACHKACB. In the real world the routine will lookup the
routine name and pass it to the code so I have to be able to interpret
TMPMON somehow at runtime. Does anyone have any thoughts? Thanks for your
ideas. I do have the CALL VALUE 'GA.JOBNAME.'PTR, MBRNAME in my solution
package, but I do not see how this will get me closer to a solution in this
case.

----------------------------------------------------------------------

Itschak Mugzach

unread,
Sep 13, 2010, 8:20:42 AM9/13/10
to
The use of Value function is to enable the single interpretation phase rexx
uses, to resolve the function name.
ITschak

Paul Gilmartin

unread,
Sep 13, 2010, 10:42:00 AM9/13/10
to
On Sep 13, 2010, at 04:57, Bob Bridges wrote:

> I don't think that's the way to do it, Itzchak; I'm looking for
>
> return value(tmpmon'(VTHOM)')
>
> Still don't know whether VALUE is willing to call whatever routine whose
> name was passed to tmpmon, though.
>

No. The argument to VALUE must be a legal (possibly compound)
variable name; the parentheses violate that. But it's pointless.
Giving the caller the ability to cause your code to call an
arbitrary function introduces the same risks as INTERPRET.
You're just trying to introduce INTERPRET under another name.

-- gil

Mark Wheeler

unread,
Sep 13, 2010, 11:46:58 AM9/13/10
to

> Date: Mon, 13 Sep 2010 08:36:27 -0600
> From: PaulGB...@AIM.COM


> Subject: Re: [TSO-REXX] Help with INTERPRET

> To: TSO-...@VM.MARIST.EDU


>
> On Sep 13, 2010, at 04:57, Bob Bridges wrote:
>
> > I don't think that's the way to do it, Itzchak; I'm looking for
> >
> > return value(tmpmon'(VTHOM)')
> >
> > Still don't know whether VALUE is willing to call whatever routine whose
> > name was passed to tmpmon, though.
> >
> No. The argument to VALUE must be a legal (possibly compound)
> variable name; the parentheses violate that. But it's pointless.
> Giving the caller the ability to cause your code to call an
> arbitrary function introduces the same risks as INTERPRET.
> You're just trying to introduce INTERPRET under another name.
>
> -- gil

INTERPRET in this instance would be safe so long as you filter the variable "tmpmon" for valid values first. Perhaps using something like
if wordpos(tmpmon,list_of_valid_dsns) > 0 then
interpret "return" tmpmon"('VTHOM')"
else
do
say 'Invalid value for tmpmon'
return /* Invalid value for tmpmon */
end

Mark Wheeler
UnitedHealth Group

Hardee, Charles H

unread,
Sep 13, 2010, 12:31:58 PM9/13/10
to
I agree with Mark.

The original post:

<quote>
Hello,


I have the following short sample of code that I want to use in a larger project, but I'd prefer not to use interpret if possible.

/* REXX */
CALL RUNMON GACHKACB
SAY 'NTV309I MYRC='MYRC
EXIT

RUNMON:
ARG TMPMON
INTERPRET 'MYRC='TMPMON||'(VTHOM)'
RETURN MYRC

This is going to be a dynamic routine that calls a monitor. In this case I simply hardcoded GACHKACB. In the real world the routine will lookup the routine name and pass it to the code so I have to be able to interpret TMPMON somehow at runtime. Does anyone have any thoughts? Thanks for your ideas. I do have the CALL VALUE in my solution package, but I do not see how this will get me closer to a solution in this case.

Thanks,
Thom Stone
<\quote>

Notice Thom indicated that the routine (I am assuming by "routine" he means the REXX he is developing) will look up the routine to call. If that is the case, AND the user does not have the ability to change that control table, then INTERPRET would be fine to use with little to no exposure. At least that's how I interpret what Thom wants.

Chuck


Charles Hardee
CA technologies
Sr Sustaining Engineer
Tel:  +1-952-838-1039
Charles...@ca.com

Glenn Knickerbocker

unread,
Sep 13, 2010, 12:50:37 PM9/13/10
to
On 09/13/2010 11:46 AM, Mark Wheeler wrote:
>> From: PaulGB...@AIM.COM

>> No. The argument to VALUE must be a legal (possibly compound)
>> variable name

Not necessarily a variable name, but a symbol.
VALUE('123abc') will always return '123ABC'. (*)

>> Giving the caller the ability to cause your code to call an
>> arbitrary function introduces the same risks as INTERPRET.

> INTERPRET in this instance would be safe so long as you filter the
> variable "tmpmon" for valid values first.

But that seems to be exactly what Thom is trying to avoid. I'm guessing
he wants the user to be able to add new monitor execs without having to
update his main exec to recognize them.

If the user specifies just the monitor name and Thom's exec fills in the
argument, then the way to validate the name before doing the INTERPRET
would just be to check that it's a valid symbol:

If Symbol(tmpmon) = 'BAD' then
/* the value of TMPMON is not a symbol,
so we can't use it as a function name */

ŹR

Glenn Knickerbocker

unread,
Sep 13, 2010, 3:07:59 PM9/13/10
to
On 09/13/2010 12:50 PM, I wrote:
> VALUE('123abc') will always return '123ABC'. (*)

but forgot to fill in the footnote:

(*) except in implementations where this is broken! I tried it out
just to double-check, and didn't happen to be logged onto VM or
TSO, so I used ooRexx (v3.2.0)--and came out with some nonsense
starting with a dot instead!

Thom Stone

unread,
Sep 13, 2010, 8:44:28 PM9/13/10
to

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf Of

Glenn Knickerbocker
Sent: Monday, September 13, 2010 11:50 AM
To: TSO-...@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Help with INTERPRET

ŹR

To Itsak reply, I tried it and it did not execute the routine, it seemed to
only evaluate it.

To Glenn, yes, I want this to be dynamic, and I then I guess I have some
give and take with someone playing games as I indicate below.

Actually the monitors will be specified in a configuration file and read
into global variables because my environment is NetView. Then when an
automation routine decides to run a monitor it will read the global
variables for a specific task and run the named monitor. Granted if one is
wise enough he could outfox the automation and update the global variables
or figure out how to run a monitor with a fudged monitor/task name or maybe
even update the configuration file in the first place, but perhaps a company
shouldn't hire those types. :-) But I guess even management can make a
mistake. Thank the powers that be for RACF or whatever security product we
use. I've heard some say security by obscurity. Looking at it now I think
I probably do not need to return rtnval, but I think I'll leave well enough
alone until I can do more testing at work.

Anyway this is what I decided to do:

do ptr=1 to thismon.0
call runmon thismon.ptr
/* do what you will with rtnval */
thisvar='GA.'thisitem'.MON.'ptr'.STAT'
call saveglbl thisvar rtnval
end
RETURN
/*------------------------------------------------------------------*/
RUNMON:
trace o
arg tmpmon
parse var tmpmon mon parms
interpret 'rtnval='mon'('parms')'
return rtnval
/*------------------------------------------------------------------*/
SAVEGLBL: Procedure Expose STGSEP DELIM
ARG VARNAME VALUE
'PIPE (STAGESEP 'STGSEP') LIT 'DELIM''VALUE''DELIM ,
STGSEP' VAR (COMMON) 'VARNAME
RETURN
/*------------------------------------------------------------------*/

Lindy Mayfield

unread,
Sep 14, 2010, 2:42:55 AM9/14/10
to
I have found that INTERPRET is a very useful statement. One example I used it for was some xml-ish code which I wrapped around ISPF panels, like this:

<panel name=ispfpnl1>
blah blah
</panel>

I simply stripped off the ><'s and interpreted the "name=ispfpnl1". Also my Rexx runs in a user's TSO address space so it doesn't do anything that a user cannot do directly.

Having said that, can someone give a real world example of how INTERPRET can be misused? I hear a lot about why not to use it, but I cannot think of any example.

Best regards,
Lindy

adrianstern

unread,
Sep 14, 2010, 5:17:27 AM9/14/10
to
On Jul 26, 7:59 pm, david.wag...@FEDEX.COM (Wagner, David --- Senior

Programmer Analyst --- CFS) wrote:
>         Another question is can I use Rexx to get information concerning
> a particular job and know if it has run today and/or whether it was
> successful or not..
>
>         I am trying to gather information on particular jobs that are
> running, but want to do this dynamically. We have a third party setup
> (JHS), but have never been able to find an interface that would allow me
> to enter job(s) and return the status on them dynamically..
>
>         So is it possible to pull the start/end/status of a job that has
> or has not run(obviously if not run, then not found) today??
>
>          If you have any questions and/or problems, please let me know.
>          Thanks.
>
> Wags ;)
> David R. Wagner
> Senior Programmer Analyst
> FedEx Services
> 1.719.484.2097 Tel
> 1.719.484.2419 Fax
> 1.408.623.5963 Cellhttp://Fedex.com/us
>
> ----------------------------------------------------------------------
> For TSO-REXX subscribe / signoff / archive access instructions,
> send email to LISTS...@VM.MARIST.EDU with the message: INFO TSO-REXX

What I did many years ago was to add a step to every job that ALWAYS
ran (check cond codes for how to do that). The step wrote the sysout
file I wanted (SYSMSGS I think it was) to a daily pds usung the
jobname as member name - the pds being created by the first job to
complete that day.

I already had a normative pds with members for all the jobs that
should run - running a simple compare job produced a daily list of the
status - jobs run, result jobs NOT run.

Pretty simple and robust and cheap!

I may have some code still if you need help

Adrian

Mickey

unread,
Sep 14, 2010, 6:31:13 AM9/14/10
to
I too have heard this canard for years, and I disagree wholeheartedly. There
are two downsides to INTERPRET, and both are fairly moot. The first is that
it isn't as easily readable as most REXX code. This can be easily overcome
by good commenting. The second issue is that some compilers cannot handle
it. This is really an absurd point, as the speed increase from compiled Rexx
only really matters when you have an extremely complex program that is
processing huge amounts of data. The difference between 12 MS and 15 MS on
99.98% of REXX processes is hardly a reason to compile code.

Mickey

--------------------------------------------------
From: "Lindy Mayfield" <lindy.m...@SSF.SAS.COM>
Sent: Tuesday, September 14, 2010 2:42 AM
To: <TSO-...@VM.MARIST.EDU>


Subject: Re: [TSO-REXX] Help with INTERPRET

> I have found that INTERPRET is a very useful statement. One example I

Paul Gilmartin

unread,
Sep 14, 2010, 7:05:36 AM9/14/10
to
On Sep 14, 2010, at 00:42, Lindy Mayfield wrote:
>
> Having said that, can someone give a real world example of how INTERPRET can be misused? I hear a lot about why not to use it, but I cannot think of any example.
>
It depends on what you control. Consider:

/* Rexx */
'EXECIO 1 DISKR SYSUT1 (STEM X.'
INTERPRET X.1

Would you run this EXEC on your user ID letting me supply the
content of SYSUT1?

-- gil

Lindy Mayfield

unread,
Sep 14, 2010, 8:25:33 AM9/14/10
to
I don't have an answer. I'm caught between saying "Point taken" and "Something about your answer isn't right but I don't know what it is, yet." I have to think about it.

Once many years ago I created some utility that had a PARM file something like this:

DNSNAME=MY.DNSNAME
FLAG1=Y
FLAG2=N
TRACE=N

and so on.

It was very simple to first set defaults and then INTERPRET each statement.

How would you do this without INTERPRET?

/Lindy


-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf Of Paul Gilmartin
Sent: Tuesday, September 14, 2010 2:02 PM
To: TSO-...@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Help with INTERPRET

Matan Cohen

unread,
Sep 14, 2010, 8:46:13 AM9/14/10
to
on way to do this is to create two parameters:
varname = 'DNSNAME FLAG1 FLAG2 TRACE'
varvalue = 'DEF.DSNAME DEFFLG1 DEEFFL2 DEFAULT '
then you read the PARM file and use WORDPOS to find what is the position of
the vraiable name and replace accordingly
the value in var value.


On Tue, Sep 14, 2010 at 2:25 PM, Lindy Mayfield
<lindy.m...@ssf.sas.com>wrote:

--
best regards,
matan cohen
MF System Administrator.

Lindy Mayfield

unread,
Sep 14, 2010, 9:30:50 AM9/14/10
to
except if I have something like?

ERORMESSAGE1="TÄMÄ ON VIRHE"

Lindy Mayfield

unread,
Sep 14, 2010, 9:40:02 AM9/14/10
to
Also, I can use comments:

/* This is the translated error message text for xyz */
ERRORMESSAGE1="Miksi teit näin"

I think I understand my problem with Gil's example. If you purposely give my Rexx exec something that will cause damage or whatnot in my TSO session, you'll most likely get fired. There are a number of ways to do such things other than hacking a Rexx exec.

I see a lot of sites that have . in the PATH. That happens to be on my mind because I saw this at this customer site where I am now.

Robert Zenuk

unread,
Sep 14, 2010, 11:28:23 AM9/14/10
to
This technique is commonly used for parameter files for several
applications. The file usually contains variable=value records. Granted this could
be done with PARSE and CALL VALUE. The first place I saw this technique
was in IBM's APPC/MVS (about 20 years ago). I remember staring at it for a
while trying to figure out what it did then being astonished at the
simplicity and effectiveness (I think I actually had a religious experience) and
adopted the technique.

In all cases I have seen this technique the parameter file is protected
since it's importance to the application requires consistency before we even
talk about maliciousness...

I agree with the other posters. While I try to use CALL VALUE when
possible, sometimes INTERPRET is the answer. I also find that CALL VALUE is less
known to the casual REXX users (that may have to support my code at some
point) and requires more documentation than INTERPRET...

I also think the FUD surrounding INTERPRET has been overblown. Since BOTH
INTERPRET and CALL VALUE create difficult to read code both require lots
of documentation. The only warning should be to test thoroughly with
INTERPRET and insure user input can not interject an unexpected command.

My two cents.

Rob


In a message dated 9/14/2010 4:04:54 A.M. US Mountain Standard Time,

Steve Comstock

unread,
Sep 14, 2010, 11:38:30 AM9/14/10
to
On 9/14/2010 12:42 AM, Lindy Mayfield wrote:
> I have found that INTERPRET is a very useful statement. One example I used it for was some xml-ish code which I wrapped around ISPF panels, like this:
>
> <panel name=ispfpnl1>
> blah blah
> </panel>
>
> I simply stripped off the><'s and interpreted the "name=ispfpnl1". Also my Rexx runs in a user's TSO address space so it doesn't do anything that a user cannot do directly.
>
> Having said that, can someone give a real world example of how INTERPRET can be misused?
> I hear a lot about why not to use it, but I cannot think of any example.
>
> Best regards,
> Lindy

Lindy,

Here's a little exec that can cause a problem:

/* rexx */
clrscrn
say "Enter calculation request ..."
parse pull variable
interpret variable
/* ----------------------------------- */

When you run this, if the user is malicious, they could enter
a TSO command; for example:


Enter calculation request ...
del bunk.dirlist
IDC0550I ENTRY (A) SCOMSTO.BUNK.DIRLIST DELETED
***

--

Kind regards,

-Steve Comstock
The Trainer's Friend, Inc.

303-393-8716
http://www.trainersfriend.com

* To get a good Return on your Investment, first make an investment!
+ Training your people is an excellent investment

Paul Gilmartin

unread,
Sep 14, 2010, 11:48:53 AM9/14/10
to
On Sep 14, 2010, at 09:27, Robert Zenuk wrote:
>
> I also think the FUD surrounding INTERPRET has been overblown. Since BOTH
> INTERPRET and CALL VALUE create difficult to read code both require lots
> of documentation. The only warning should be to test thoroughly with
> INTERPRET and insure user input can not interject an unexpected command.
>
Certainly. I have an Edit macro which INTERPRETs a string
entered on the command line. It's the user's gun; the user's
foot. (And AFAIK, I'm the only user.)

CALL VALUE has its own hazards, allowing the supplier of the
parameter to modify arbitrary variables in the EXEC. Rather
than:

parse pull Name Content
call value Name, Content

I prefer to use a compound variable:

parse pull Name Content
Parms.Name = Content

quarantining the values modified to the Parms stem. Provided
the programmer understands compound variables. I've had
programmers insist that compound tails _must_ be numeric, and
that the array size _must_ be kept in the 0th element.

Lindy Mayfield

unread,
Sep 14, 2010, 11:56:43 AM9/14/10
to
What's the difference if I enter a command to the rexx or enter it explicitly?

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf Of Steve Comstock
Sent: Tuesday, September 14, 2010 6:38 PM
To: TSO-...@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Help with INTERPRET

Mark Wheeler

unread,
Sep 14, 2010, 12:03:20 PM9/14/10
to
> Date: Tue, 14 Sep 2010 08:42:39 +0200
> From: lindy.m...@SSF.SAS.COM

> Subject: Re: [TSO-REXX] Help with INTERPRET
> To: TSO-...@VM.MARIST.EDU
<snip>
> Having said that, can someone give a real world example of how INTERPRET can be misused? I hear a lot about why not to use it, but I cannot think of any example.
>
> Best regards,
> Lindy

The problem isn't limitted to sending imbedded commands into REXX "interpret". Any environment that can be tricked into running a command could be exploited. Take CMS/TSO Pipelines, for example:
/* BLORT EXEC */
arg filename
'PIPE <' filename '| ....' /* Looks innocent enough */

Now issue "blort some_file | hole | append (nefarious_command)" and stand back.

Clearly in this case, some checking should occur to make sure "filename" doesn't include any "pipe" (|) characters, especially if the exec will ever be invoked by a privileged userid.

Steve Comstock

unread,
Sep 14, 2010, 12:08:35 PM9/14/10
to
On 9/14/2010 9:56 AM, Lindy Mayfield wrote:
> What's the difference if I enter a command to the rexx or enter it explicitly?

Well, of course nothing.

A lot depends on context and whatever safeguards you
have in place. Suppose someone copies your dialog and
runs it somewhere else.

But, as Paul says, it's the user's gun and the user's
foot. I was just pointing out INTERPRET can be used to
enter unexpected commands unless you parse what the
user enters before you issue the INTERPRET.

Message has been deleted

Ted MacNEIL

unread,
Sep 14, 2010, 3:52:35 PM9/14/10
to
>I also think the FUD surrounding INTERPRET has been overblown.

I agree.
A few years ago, I worked in a shop that did not have SAS.
I needed to merge the DFHSTAT output from 5 AORs, and the fastest, best method, was a table update/merge.
I found that INTERPRET sped up programming and testing.

The same code was used over and over again.

I am loathe to duplicate code paths, because of the onus on the programmer to remember to fix/change all occurances.

In SAS, you do it with MACROs (their term).
In REXX, the closest equivalence is INTERPRET.

At first, I believed the FUD.
But, with time as a factor, I decided that the most important issue was to get the job done in time.

I don't find many uses for it, but it's now a screwdriver in my toolbox.

-
I'm a SuperHero with neither powers, nor motivation!
Kimota!

Ted MacNEIL

unread,
Sep 14, 2010, 4:00:05 PM9/14/10
to
> /* rexx */
> clrscrn


That has to be a home-grown command.

>say "Enter calculation request ..."
>parse pull variable
>interpret variable

Change that to

interpret SAY variable

The use of INTERPRET, like any 'dangerous' practice, is subject to discipline.

Just because I can do it, doesn't mean I shall do it.
Especially, if I like my job.

INTERPRET doesn't kill systems!
People kill systems.

Ted MacNEIL

unread,
Sep 14, 2010, 4:13:17 PM9/14/10
to
>I've had programmers insist that compound tails _must_ be numeric, and that the array size _must_ be kept in the 0th element.

That is a convention for things like EXECIO, but it is not a general requirement.

I do use the convention a lot; I do a lot of I/O in my EXECs, though.

Bob Bridges

unread,
Sep 14, 2010, 8:39:41 PM9/14/10
to
The web page would not accept ad-hoc commands when I run the REXX unless my
ID has the authority to get the web page to take ad-hoc commands. I'm still
with Lindy; so far, there's no harm that can be done that the user couldn't
do without the INTERPRET command.

That's the thing we keep forgetting (well, at least I do): If I write a
REXX with an INTERPRET command and the user executes it and inserts
something malicious, the REXX is running under his own ID and thus he can do
only what he can already do. The REXX doesn't give him any additional
authority, nor mask the source of the problem if he deletes a file or
something.

/* Everyone is someone's wierdo. -Scott Adams, creator of "Dilbert" */

-----Original Message-----
From: Mark Wheeler
Sent: Tuesday, September 14, 2010 12:27

The REXX exec could be a CGI script taking input from a web page. You
probably don't want your web server running ad hoc commands.

-----Original Message-----
From: Lindy Mayfield
Sent: Tuesday, September 14, 2010 11:56

What's the difference if I enter a command to the rexx or enter it
explicitly?

-----Original Message-----
From: Steve Comstock
Sent: Tuesday, September 14, 2010 6:38 PM

Lindy, Here's a little exec that can cause a problem:

/* rexx */
clrscrn


say "Enter calculation request ..."
parse pull variable
interpret variable

/* ----------------------------------- */

When you run this, if the user is malicious, they could enter a TSO command;
for example:

Enter calculation request ...
del bunk.dirlist
IDC0550I ENTRY (A) SCOMSTO.BUNK.DIRLIST DELETED
***

----------------------------------------------------------------------

Paul Gilmartin

unread,
Sep 14, 2010, 11:10:45 PM9/14/10
to
On Sep 14, 2010, at 18:39, Bob Bridges wrote:

> The web page would not accept ad-hoc commands when I run the REXX unless my
> ID has the authority to get the web page to take ad-hoc commands. I'm still

But that's just what CGI does. The author should know better
than to perform unfiltered INTERPRET. Better still to parse
the command string and perform operations without INTERPRET.

> with Lindy; so far, there's no harm that can be done that the user couldn't
> do without the INTERPRET command.
>
> That's the thing we keep forgetting (well, at least I do): If I write a
> REXX with an INTERPRET command and the user executes it and inserts
> something malicious, the REXX is running under his own ID and thus he can do
> only what he can already do. The REXX doesn't give him any additional
> authority, nor mask the source of the problem if he deletes a file or
> something.
>

Transparency. It's hard to tell reading an INTERPRET what it
might do. That's masking.

> -----Original Message-----
> From: Mark Wheeler
> Sent: Tuesday, September 14, 2010 12:27
>
> The REXX exec could be a CGI script taking input from a web page. You
> probably don't want your web server running ad hoc commands.

-- gil

Phil Smith III

unread,
Sep 15, 2010, 10:34:10 AM9/15/10
to
INTERPRET has its place. And of course it can be abused. There are several forces at work making the discussion complex:

- folks HAVE implemented INTERPRET statements that can be easily abused
- there are *usually* ways to avoid INTERPRET (VALUE being the most common replacement)
- programmers like to be clever, so in the early days of Rexx, it became something of a sport to find ways around using INTERPRET

Any such discussion always makes me think of http://xkcd.com/327/ -- if you don't know XKCD you should.

...phsiii

Vogtmann, Wallace B

unread,
Sep 15, 2010, 10:53:00 AM9/15/10
to

We're attempting to install CICS IA in our environment, utilizing our
"metered" DB2 for z/OS installation.
We do NOT have the DB2 Utilities package and so do not have the LOAD utility,
which CICS IA wants to use.

We've been told by IBM that "There is a possibility that you could write to a
CSV file and then load it into the database."

Anybody doing something similar to this via REXX? Any other options available
to us? Alternative DB2 load utility?

- Wally Vogtmann
----------------------------Disclaimer----------------------------
This email may contain privileged and/or confidential information that
is intended solely for the use of the addressee. If you are not the
intended recipient, you are strictly prohibited from disclosing, copying,
distributing or using any of the information contained in the transmission.
If you received this communication in error, please contact the sender
(“Company”) immediately and destroy the material in its entirety,
including all electronic and hard copies.

This communication may contain nonpublic personal information about
consumers which is subject to restrictions under the Gramm-Leach-Bliley
Act and the Sarbanes-Oxley Act. You may not directly or indirectly reuse
or disclose such nonpublic personal information for any purpose other than
to provide the services for which you are receiving the information.

There are risks associated with the use of electronic transmission. The
sender of this information does not control the method of transmittal or
any service providers and the sender assumes no duty, liability, or
obligation for the security, receipt, or any third party interception of
this transmission.

The Company reserves the right to amend statements made herein in the event
of a mistake. Unless expressly stated herein to the contrary, only agreements
in writing signed by an authorized officer of the Company may be enforced
against it.

Mickey

unread,
Sep 15, 2010, 11:22:39 AM9/15/10
to
Many commands in MANY languages can be abused, if that is the sole criterion
we use, we will have nothing but read it, write it programs. Just in REXX
alone, there exists the storage command, which can be misused (either
accidently or on purpose) just as quickly as can interpret. When all is said
and done, it always comes back to having people with personal integrity and
professional pride.

Mickey

--------------------------------------------------
From: "Phil Smith III" <li...@AKPHS.COM>
Sent: Wednesday, September 15, 2010 10:32 AM


To: <TSO-...@VM.MARIST.EDU>
Subject: Re: [TSO-REXX] Help with INTERPRET

> INTERPRET has its place. And of course it can be abused. There are several

Mickey

unread,
Sep 15, 2010, 11:24:50 AM9/15/10
to
If the question here is, have I every written a process to parse a CSV and
load the data to DB2 via Rexx, then the answer is yes, and always in less
than 100 lines of code.

Mickey

--------------------------------------------------
From: "Vogtmann, Wallace B" <wvog...@TCFBANK.COM>
Sent: Wednesday, September 15, 2010 10:51 AM
To: <TSO-...@VM.MARIST.EDU>
Subject: [TSO-REXX] CICS IA and DB2 LOAD Utility

----------------------------------------------------------------------

Vitonis, Tony

unread,
Sep 15, 2010, 1:25:46 PM9/15/10
to
I use INTERPRET to call an external routine that'll sort a stem for me:

INTERPRET SORTSTEM("Stem")

It's easy to understand, and it hides the implementation details.

Tony

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf

Of Phil Smith III
Sent: Wednesday, September 15, 2010 10:33 AM
To: TSO-...@VM.MARIST.EDU

Phil Smith III

unread,
Sep 16, 2010, 12:29:53 AM9/16/10
to
"Vitonis, Tony" wrote:
>I use INTERPRET to call an external routine that'll sort a stem for me:
> INTERPRET SORTSTEM("Stem")
>It's easy to understand, and it hides the implementation details.

FSVO "easy to understand". I assume that SORTSTEM returns a set of "Stem.1 = value;" pairs?

It sure does hide the implementation details!

Vitonis, Tony

unread,
Sep 16, 2010, 11:43:32 AM9/16/10
to
It returns a big ol long DO-END string that, when executed, shell-sorts
the members of the stem. The assumption is that Stem.0 contains the
count and Stem.n contains the nth value.

When I say "easy to understand", I mean that once you know the
constraints above, it takes roughly zero mental cycles to see what the
INTERPRET statement does. =)

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf
Of Phil Smith III
Sent: Thursday, September 16, 2010 12:29 AM
To: TSO-...@VM.MARIST.EDU
Subject: Re: Help with INTERPRET

"Vitonis, Tony" wrote:
>I use INTERPRET to call an external routine that'll sort a stem for me:
> INTERPRET SORTSTEM("Stem")
>It's easy to understand, and it hides the implementation details.

FSVO "easy to understand". I assume that SORTSTEM returns a set of
"Stem.1 = value;" pairs?

It sure does hide the implementation details!

----------------------------------------------------------------------

Robert Zenuk

unread,
Sep 16, 2010, 12:35:46 PM9/16/10
to
I think that wins the obfuscation award... ;-)

Rob

In a message dated 9/16/2010 8:42:43 A.M. US Mountain Standard Time,

Vitonis, Tony

unread,
Sep 16, 2010, 1:27:10 PM9/16/10
to
Meh, I suppose that's true on some level. Essentially I said "It's easy
to understand if you understand it." And it's in the nature of
programmers to crave knowledge of underlying details. Still, INTERPRET
SORTSTEM("Stem") itself is pretty straightforward, I think.

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf
Of Robert Zenuk
Sent: Thursday, September 16, 2010 12:35 PM
To: TSO-...@VM.MARIST.EDU
Subject: Re: Help with INTERPRET

I think that wins the obfuscation award... ;-)

Robert Zenuk

unread,
Sep 16, 2010, 1:51:57 PM9/16/10
to
One of my mentors used to differentiate "clever code" from "good
supportable code". He wrote tons of clever code for himself and we would debate the
level of cleverness. However, anything that someone else would ever need
to support, he would restrict himself to writing only good supportable
code. The main difference being the readability and ease of understanding
factors for someone new... He found he spent less time on maintenance using
that approach... He also said that since he did not memorize every line of
code he ever wrote, it saved him time when he had to go back and decipher
his own cleverness...

I also adopted his philosophy. I also have several "sample" execs to test
or prove something clever works, but anything I turn over for production
usage and/or share as a production ready piece of code avoids "clever"
techniques. To be honest, sometimes (admittedly rarely) using clever code is
unavoidable. In these cases, I heavily document what is going on every place
I use them (if not in a subroutine or function - then they are documented
only once in there).

My two cents...

Rob

In a message dated 9/16/2010 10:27:00 A.M. US Mountain Standard Time,

Vitonis, Tony

unread,
Sep 16, 2010, 2:24:03 PM9/16/10
to
Understood and agreed about clever code. I suppose we'll just differ on
whether this particular bit of code is "clever". The invoked routine is
a straightforward implementation of the shell sort, and the invoking
code is in my opinion very easy to read and understand.

I think of SORTSTEM as corresponding to a public method of a published
class. If the stem were an object in typical OOP code, you might instead
see my_stem.sort(). Not at all clever or hard to maintain.

Kent Fiala

unread,
Sep 16, 2010, 2:59:35 PM9/16/10
to
I have to agree that initially I thought this was the opposite of easy
to understand. I also agree that once you understand it, it's simple.
It is really very similar to a macro in the C language, where such
things are established practice.

Kent Fiala

Paul Gilmartin

unread,
Sep 16, 2010, 4:31:38 PM9/16/10
to
On 09/16/10 11:49, Robert Zenuk wrote:
> One of my mentors used to differentiate "clever code" from "good
> supportable code". He wrote tons of clever code for himself and we would debate the
> level of cleverness. However, anything that someone else would ever need
> to support, he would restrict himself to writing only good supportable
> code. The main difference being the readability and ease of understanding
> factors for someone new... He found he spent less time on maintenance using
> that approach... He also said that since he did not memorize every line of
> code he ever wrote, it saved him time when he had to go back and decipher
> his own cleverness...
>
The parameter of "cleverness" is strongly cultural. I've
seen programmers accustomed to classic programming languages
(FORTRAN, COBOL, C) astonished to learn that compound variables,
which they had taken as Rexx's formulation of arrays, could use
any string as tails. Some of them go on to say that yes, but
using anything except an (unsigned) integer as a selector
transgresses "readability and ease of understanding ... for
someone new," and that they would therefore avoid the practice
and counsel others (perhaps their subordinates) against it.

How about:

if X==Y then
X_MATCHES_Y = 'TRUE'
else
X_MATCHES_Y = 'FALSE'
...
if X_MATCHES_Y=='TRUE' then do
something
end; else do
something_else
end

versus:

X_MATCHES_Y = ( X==Y )
...
if X_MATCHES_Y then do
something
end; else do
something_else
end

I will unhesitatingly employ the second construct. I rather
expect some reaction on this list that only the first is
acceptable. BASICthink. In (original, at least) BASIC,
relational expressions were allowed only in IF statements,
and only relational expressions had boolean values.

-- gil

Lindy Mayfield

unread,
Sep 17, 2010, 2:47:19 AM9/17/10
to
I don't write code that I cannot easily figure out months or years later. That's why I stay away from writing clever (if clever == difficult to understand) code. Each to their own I guess.

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf Of Vitonis, Tony
Sent: Thursday, September 16, 2010 9:24 PM
To: TSO-...@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Help with INTERPRET

Understood and agreed about clever code. I suppose we'll just differ on whether this particular bit of code is "clever". The invoked routine is a straightforward implementation of the shell sort, and the invoking code is in my opinion very easy to read and understand.

----------------------------------------------------------------------

Mickey

unread,
Sep 17, 2010, 8:28:26 AM9/17/10
to
I'm with you. I keep it very simple. I rarely even write a procedure that
won't fit on one screen.

--------------------------------------------------
From: "Lindy Mayfield" <lindy.m...@SSF.SAS.COM>
Sent: Friday, September 17, 2010 2:46 AM

Steve Comstock

unread,
Sep 17, 2010, 8:33:52 AM9/17/10
to
On 9/17/2010 12:46 AM, Lindy Mayfield wrote:
> I don't write code that I cannot easily figure out months or years later.
> That's why I stay away from writing clever (if clever == difficult to understand)
> code. Each to their own I guess.

Exactly. I'm sure everyone who's been in the business for
a year or more has had the experience of re-visiting code
they wrote earlier in their career only to find an
embarrasing string of almost incomprensible statements.

Code with the future maintainer in mind - it might be you!


>
> -----Original Message-----
> From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf Of Vitonis, Tony
> Sent: Thursday, September 16, 2010 9:24 PM
> To: TSO-...@VM.MARIST.EDU
> Subject: Re: [TSO-REXX] Help with INTERPRET
>
> Understood and agreed about clever code. I suppose we'll just differ on whether this particular bit of code is "clever". The invoked routine is a straightforward implementation of the shell sort, and the invoking code is in my opinion very easy to read and understand.


--

Kind regards,

-Steve Comstock
The Trainer's Friend, Inc.

303-393-8716
http://www.trainersfriend.com

* To get a good Return on your Investment, first make an investment!
+ Training your people is an excellent investment

----------------------------------------------------------------------

Vitonis, Tony

unread,
Sep 17, 2010, 5:00:17 PM9/17/10
to
I couldn't agree with you more. I didn't want to write the sort routine
more than once, and I wanted the calling code to be small and
self-documenting - so I didn't have to think about it later.

Tony

Bob Bridges

unread,
Sep 18, 2010, 12:23:50 PM9/18/10
to
I once worked in a shop where COBOL programmers objected to the STRING and
UNSTRING commands on the same grounds. I argued that since they were basic
tools of COBOL, it was no use saying some COBOL programmers weren't familiar
with them; it was the duty of COBOL programmers to know their jobs. No, no
... they just couldn't see it. Walk-throughs were a little unpleasant, at
times, at that company.

I agree with the subsequent emails: If I can come back six months later and
understand my code in five minutes one way and half an hour another, then
the five-minute technique usually wins. That's why I use the parens, same
as you did, in the statement

fX_matches_Y=(x=y)

The parens are unnecessary, but they make the statement easier to understand
for someone who never tried that sort of thing before.

One of my favorite techniques in REXX seems unaccountably to be almost
unknown, yet it's both clever AND simple:

idexists.=0
'EXECIO * DISKR DDIP (FINIS'
do queued()
parse pull 1 uid +8 143 can +3
if can<>'YES' then idexists.uid=1; end

The details vary, but in this case I've taken a few lines to create a quick
true-or-false table of non-canceled UIDs that my program can later consult
to know whether the user ID it's currently looking at is in that file:

if idexists.uid then iterate

I know a few of us here do that sort of thing, but I don't understand why
everyone doesn't. It isn't "clever" in the sense we've been discussing up
'til now, ie difficult to understand.

/* In science one tries to tell people, in such a way as to be understood by
everyone, something that no one ever knew before....in poetry, it's the
exact opposite. -Paul Dirac */

How about:

versus:

--- On 09/16/10 11:49, Robert Zenuk wrote:
> One of my mentors used to differentiate "clever code" from "good
> supportable code". He wrote tons of clever code for himself and we would
> debate the level of cleverness. However, anything that someone else would
> ever need to support, he would restrict himself to writing only good
> supportable code. The main difference being the readability and ease of
> understanding factors for someone new... He found he spent less time on
> maintenance using that approach... He also said that since he did not
> memorize every line of code he ever wrote, it saved him time when he had
> to go back and decipher his own cleverness...

----------------------------------------------------------------------

Bob Bridges

unread,
Sep 18, 2010, 12:42:18 PM9/18/10
to
I don't follow yet. If the user already had the ability to run ad-hoc
commands on the web server, then our hypothetical REXX with the unfiltered
INTERPRET command has not granted the user any new capability -- and
therefore I still don't understand the objection.

Let me spell this out, just in case it isn't already clear: Suppose I write
a REXX like this:

/* This REXX example is ridiculous. */
say 'What evil, malicious act would you like to perpetrate',
'upon this LPAR?'
pull evil_malicious_TSO_command
interpret evil_malicious_TSO_command

Along comes some evil, malicious user who runs EVILMAL and types in a DELETE
command, say, "DEL 'SYS1.BRODCAST'", which EVILMAL tries to execute.

Now, there are two possibilities. If the user has the authority to delete
SYS1.BRODCAST, then the command succeeds. But the program didn't give him
the ability to issue the command DEL 'SYS1.BRODCAST'; he could have done
that any time he wanted. Or if (more likely) the user does NOT have the
authority to delete 'SYS1.BRODCAST', then the INTERPRET command will fail;
the user hasn't the authority.

Why will it fail? Because no matter who wrote the REXX, at run-time the
REXX has the authority not of the author but of the user. It is the USER
who is running the program and attempting to delete the file, not the
author. The INTERPRET statement I included in the program when I wrote it
doesn't grant the user any authority he didn't already have.

Now, there may be other objections to INTERPRET. But I don't see how this
can be one of them.

/* Everyone is someone's wierdo. -Scott Adams, creator of "Dilbert" */

-----Original Message-----
From: Paul Gilmartin

Sent: Tuesday, September 14, 2010 23:10

But that's just what CGI does. The author should know better than to
perform unfiltered INTERPRET. Better still to parse the command string and
perform operations without INTERPRET.

--- On Sep 14, 2010, at 18:39, Bob Bridges wrote:
> The web page would not accept ad-hoc commands when I run the REXX unless
> my ID has the authority to get the web page to take ad-hoc commands.

> -----Original Message-----


> From: Mark Wheeler
> Sent: Tuesday, September 14, 2010 12:27
>
> The REXX exec could be a CGI script taking input from a web page. You
> probably don't want your web server running ad hoc commands.

----------------------------------------------------------------------

Robert Zenuk

unread,
Sep 18, 2010, 1:40:32 PM9/18/10
to
A couple comments...

The old OS/VS COBOL (COBOL 68) used to create a severe performance problem
and other nasty stuff in CICS if STRING and UNSTRING were used. So the
history is that some shops just banned the use of CICS prohibited COBOL
verbs... That restriction was removed in VS/COBOL II (over 20 years ago), but
many folks did not get the message...

The example being used in your email and Gil's email is an excellent use of
REXX. I use the non-numeric stem "flags" approach all the time for very
similar purposes. One of the examples that comes to mind is one of several
EXEC's I wrote for parsing the CICS CSD where I use MANY non-numeric stems
to keep track of which resources I have to worry about in which groups,
list or regions while doing my processing (not to mention numerous numeric
stems and counts as well). In fact in some cases I have 5 level stems to
keep track of CICS resources by resource TYPE within GROUP within LIST within
CICS GRPLIST within CICS region... In my mind this is a core feature of
REXX.

My original "clever" response was to the use of INTERPRET with a function
name. The reason ended up coming out, but my concern was the STEMSORT
token itself was a resolvable variable... I ALWAYS use SIGNAL NOVALUE in
anything other than demonstration code. Therefore, I was assuming (I know...
big problem in this case) that STEMSORT (since it wasn't quoted) was also
being substituted and if not a valid variable would have raised a NOVALUE
condition. My coding style is not to let REXX default an undefined variable to
the variable name. If everyone is writing small EXEC's with minimal code,
I can see people depending on this feature... I am guilty of assumptions
about an out of context code snippet and I withdraw my "obfuscation"
comment and "clever code" story.

Rob

In a message dated 9/18/2010 9:23:42 A.M. US Mountain Standard Time,
rhb...@ATTGLOBAL.NET writes:

fX_matches_Y=(x=y)

if idexists.uid then iterate

---

/* In science one tries to tell people, in such a way as to be understood


by
everyone, something that no one ever knew before....in poetry, it's the

exact opposite. -Paul Dirac */

-----Original Message-----
From: Paul Gilmartin

How about:

versus:

----------------------------------------------------------------------

Mickey

unread,
Sep 18, 2010, 11:55:57 PM9/18/10
to
I keep my code VERY simple, with one exception. If I am writing code which
for example, walks around the task control blocks, which I know will never
change, and I want to prevent from dingbat from screwing around with it in
the future, then I will make certain to do my best to write some truly
impenetrable code :)

Mickey

--------------------------------------------------
From: "Steve Comstock" <st...@TRAINERSFRIEND.COM>
Sent: Friday, September 17, 2010 8:33 AM

Paul Gilmartin

unread,
Sep 19, 2010, 1:44:42 AM9/19/10
to
On Sep 18, 2010, at 10:42, Bob Bridges wrote:
p

> I don't follow yet. If the user already had the ability to run ad-hoc
> commands on the web server, then our hypothetical REXX with the unfiltered
> INTERPRET command has not granted the user any new capability -- and
> therefore I still don't understand the objection.
>
Your first sentence is absolutely true. The concern is that the
web page author may create a text entry field in a web page. The
browser user, having NO authority on the web server, types something
in that field which is passed in a QUERY_STRING to a CGI script
which carelessly parses it and INTERPRETS part of it.

The easiest blunder for the web page author to commit is to
validate the input thoroughly with a Javascript on the browser
side and assume that therefore only query strings consisting of
valid input will be passed to the CGI script. In fact, the
browser user, malicious, mischievous, or merely curious may
enter an entire URL _including_the_QUERY_STRING_ and submit it
to the browser, entirely invalidated.

Long ago my employer had a time accounting system which required
each employee to enter his weekly time by project in an extremely
cumbersome form interface, entering a code in each of 8 hour
fields for each of 5 days. No entries were preset by a profile
or skeleton. That user interface then validatedthe input and
formatted an email which was sent to the payroll system which
received it automatically and processed it.

Finding the process tedious, I intercepted one of the emails and
converted it to a script with instream data after I had modified
the few hourly entries which differed from the previous week.
I then typed "GO" and my script formatted and sent the email.
I was cautious; my entries were valid; the scheme worked well
for me. I boasted of it to a colleague, and even shared my
script with him. He adopted it, but made a typo. The payroll
system crashed. When he didn't receive a timely acknowledgment
that his time sheet had been accepted, he sent it again. The
payroll system crashed again ...

> Let me spell this out, just in case it isn't already clear: Suppose I write
> a REXX like this:
>
> /* This REXX example is ridiculous. */
> say 'What evil, malicious act would you like to perpetrate',
> 'upon this LPAR?'
> pull evil_malicious_TSO_command
> interpret evil_malicious_TSO_command
>
> Along comes some evil, malicious user who runs EVILMAL and types in a DELETE
> command, say, "DEL 'SYS1.BRODCAST'", which EVILMAL tries to execute.
>

What evidently isn't already clear to you is that the CGI script is running
on the server with the privileges of the HTTP daemon; evil malicious user
who has no authority to delete anything on the server is entering his command
remotely on a web browser.

Perhaps your mental block is in the presumption that no website author would
ever be so careless as to INTERPRET a QUERY string submitted by a browser
user without validating it completely.

Alas, similar things have happened. See my payroll example above.

-- gil

Paul Gilmartin

unread,
Sep 19, 2010, 1:50:35 AM9/19/10
to
On Sep 18, 2010, at 10:23, Bob Bridges wrote:
>
> One of my favorite techniques in REXX seems unaccountably to be almost
> unknown, yet it's both clever AND simple:
>
> idexists.=0
> 'EXECIO * DISKR DDIP (FINIS'
> do queued()
> parse pull 1 uid +8 143 can +3
> if can<>'YES' then idexists.uid=1; end
>
I do that regularly, usually to determine whether delimiter such as
a comma is present in the input string:

parse value S with head ',' +0 delim +1 tail
if delim==',' then

It's clever and NOT simple; it's easy for me simply because I use
it so frequently.

-- gil

Lindy Mayfield

unread,
Sep 19, 2010, 9:22:08 AM9/19/10
to
Most code that accesses control blocks is pretty much obfuscated as it is without any extra help.

This is one of my favorites. If I didn't know what it already does I would be digging into the documentation for quite a while.

/* Rexx */
Numeric Digits 10
Depth = 0
ASCB = Get_Stor('224'x)
ASCBRCTP = Get_Stor(ASCB,'7C'x)
Call Process_TCB ASCBRCTP
Return

Process_TCB: Procedure Expose Depth
Say Copies(".",Depth) C2X(Arg(1))
Daughter = Get_Stor(Arg(1),'88'x)
If C2D(Daughter) <> 0 Then Do
Depth = Depth + 1
Call Process_TCB Daughter
Depth = Depth - 1
End
Sister = Get_Stor(Arg(1),'80'x)
If C2D(Sister) <> 0 Then call Process_TCB Sister
Return

Get_Stor: Procedure
Parse Arg Area,Offset,Leng
If Arg(2,'O') Then Offset=0
If Arg(3,'O') Then Leng=4
If DataType(Area) = 'CHAR' Then Do
Area = C2D(Area)
End
If DataType(Offset) = 'CHAR' Then Do
Offset = C2D(Offset)
End
Return Storage((D2X(Area+Offset)),Leng)

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf Of Mickey
Sent: Sunday, September 19, 2010 6:55 AM
To: TSO-...@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Help with INTERPRET

I keep my code VERY simple, with one exception. If I am writing code which for example, walks around the task control blocks, which I know will never change, and I want to prevent from dingbat from screwing around with it in the future, then I will make certain to do my best to write some truly impenetrable code :)

Mickey

----------------------------------------------------------------------

Mickey

unread,
Sep 19, 2010, 1:11:51 PM9/19/10
to
Well, I also find that if I build code in tight little routines that have
but one function, I can often build a new program just by chopping out 6
routines from 6 existing ones, and writing a little code around them. My
method is to build bricks. Once I have bricks, building houses is easy.

Mickey

--------------------------------------------------
From: "Vitonis, Tony" <Tony.V...@CA.COM>
Sent: Friday, September 17, 2010 4:59 PM

Mickey

unread,
Sep 19, 2010, 1:16:45 PM9/19/10
to
I agree, but I will do my best to make it as untouchable as possible. I will
also add a comment block that states that the following code has been made
unreadbale by design, and as a warning that it is NEVER to be altered.

--------------------------------------------------
From: "Lindy Mayfield" <lindy.m...@SSF.SAS.COM>

Sent: Sunday, September 19, 2010 9:21 AM


To: <TSO-...@VM.MARIST.EDU>
Subject: Re: [TSO-REXX] Help with INTERPRET

> Most code that accesses control blocks is pretty much obfuscated as it is


> without any extra help.
>
> This is one of my favorites. If I didn't know what it already does I
> would be digging into the documentation for quite a while.
>
> /* Rexx */
> Numeric Digits 10
> Depth = 0
> ASCB = Get_Stor('224'x)
> ASCBRCTP = Get_Stor(ASCB,'7C'x)
> Call Process_TCB ASCBRCTP
> Return
>
> Process_TCB: Procedure Expose Depth
> Say Copies(".",Depth) C2X(Arg(1))
> Daughter = Get_Stor(Arg(1),'88'x)
> If C2D(Daughter) <> 0 Then Do
> Depth = Depth + 1
> Call Process_TCB Daughter
> Depth = Depth - 1
> End
> Sister = Get_Stor(Arg(1),'80'x)
> If C2D(Sister) <> 0 Then call Process_TCB Sister
> Return
>

----------------------------------------------------------------------

Bob Bridges

unread,
Sep 19, 2010, 2:23:02 PM9/19/10
to
Gil> What evidently isn't already clear to you is that the CGI script is
running on the server with the privileges of the HTTP daemon...

Ah, that would do it, yes. I was thinking in terms of REXX/TSO, running on
MVS, where no such thing could happen. In my defense, this is the TSO-REXX
forum, after all. About web design I know almost nothing.

I said it "couldn't happen" in MVS, but let's see: If I were to set up such
a REXX to run in production under the authority of some production ID or
even a started task ... Well, in that case it likely wouldn't be accepting
on-line use input, but it certainly could be pulling prepared user input
from a file somewhere. In that case if I set up an INTERPRET, yeah, the
same thing could happen.

Seems to me, then, that the rule of thumb is Never allow user input to an
INTEPRET statement in ~production~ REXX, where "production" applies to your
CGI thingy as well as to anything I write in MVS. Yeah, I get it (finally.
Khar fahm shodam?); thanks for keeping at it with me.

/* Ignorance is the mother of adventure. -Hagar the Horrible */

-----Original Message-----
From: Paul Gilmartin

Sent: Sunday, September 19, 2010 01:43

----------------------------------------------------------------------

Don Leahy

unread,
Sep 19, 2010, 5:52:26 PM9/19/10
to
I once worked with a programmer who liked to 'uglify' his Rexx code by
running a macro that stripped out all comments and indentation. He would
publish the ugly version in a public library and keep the real version in a
safe place.

Lindy Mayfield

unread,
Sep 20, 2010, 12:44:43 AM9/20/10
to
Why? Job security?

When I worked at the State of Connecticut people like that were moved to a corner and put in charge of "special projects".

-----Original Message-----
From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf Of Don Leahy
Sent: Monday, September 20, 2010 12:52 AM
To: TSO-...@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Help with INTERPRET

I once worked with a programmer who liked to 'uglify' his Rexx code by running a macro that stripped out all comments and indentation. He would publish the ugly version in a public library and keep the real version in a safe place.

----------------------------------------------------------------------

Robert Zenuk

unread,
Sep 20, 2010, 1:41:47 AM9/20/10
to
Agreed. I have about 200 of those little "bricks". They are wrappered
with special entry and exit logic (about 2 lines up front and in the back)
and special comments (above and beyond normal doc type comments). This is so
I can use an Edit Macro (called @REFRESH) to call in the needed routines
and/or refresh them with the most current versions (I prefer to use internal
subroutines/functions and have a single module to distribute). The entry
and exit logic provides some extra built in debugging features (indented
module trace with parms-line numbers-start/stop timestamps, command timings,
performance data, subroutine level tracing, standardized diagnostic output,
standardized "abend" logic, standardized logging, version control,
standard batch report headers, etc).

I started carving out my subroutines about 10 years ago and designed my
entry/exit code to make building new stuff easier as well as create a
consistent set of development/debugging features in all my code. I can easily
activate some of my debugging features when needed or leave them dormant.
Over the years I have refined many of my subroutines when one gets used a lot
and a module trace proves it is a performance hog. Then I focus on it and
streamline it. When it is finally performing well, I can refresh all the
EXEC's using it so everyone gets the benefits. Sometimes refinement means
adding more flexibility or splitting a routine into 2 or more flavors for
specialized purposes. Since I diligently try to avoid duplicating code, many
of my subroutines require/exploit other existing subroutines.

I have subroutines for several things; TSO commands, ISPF services, Edit
Macro services, CICS support, CPSM, DB2 support, FTP, HTML, MIM/GRS, INFOMAN
(we don't use it anymore), SMTP, MIME, SDSF, TCP/IP commands, Sockets,
Sorting, DSNREXX/SQL, Sysview, List Management, USS, Text/String/Number/Date
Formatting, Report formatting, Screen Management, Dataset Management, DASD
Management, Resource Allocation, Logging, Security, Control Block Chasing,
Stem management, SMF, etc.

I really came to like the concept of "wrappering" all calls to a specific
environment. This allows for standardized error logic that grows and you
maintain in only one place.. For example, every time I execute a TSO
command I call my TSOTRAP routine.

call tsotrap "ALLOC F(XXXX) DA(....."

It executes the command and captures all the output in a common stem name.
I can use the stem data if I need it. It will print the command and the
output if an unexpected return code is received along with an environmental
error report. If the EXEC is running in batch, the error report is
printed in SYSTSPRT. If the EXEC is running under ISPF, it puts the output in
the ISPF LOG. If I provide an optional numeric parameter as the first parm
as the expected non-zero return code, it can handle errors internally and
not produce the error report..

call tsotrap 12 "DELETE" dsn

or

if tsotrap(12 "DELETE" dsn) = 12 then....

My ISPWRAP is very similar for ISPF services. I don't create a wrapper
for every unique command, but I do have a wrapper for all ISPF commands that
provides similar features as above. The additional benefit of ISPWRAP is
that it returns any ZERRLM that may exist. If there was no expected return
code provided the program dies with the ISPF return code and displays the
failed command, the return code and the ZERRLM as a batch message in SYSTSPRT
or as a long message on the screen.

call ispwrap "LMINIT..."
call ispwrap 4 "TBCREATE..."
if ispwrap(8 "TBSKIP" table) = 8 then...

My XXXTRAP routines are for commands that execute and return data as well
as a return code. My XXXWRAP routines are for commands that only return a
return code and do not return data.

Since my subroutine entry code puts the subroutine name, the parms, the
start time and the line number on the stack and the exit code removes it, my
error report will show a "parentage report" or calling tree of where we came
from if there was an unexpected exit.

Some of my 'abend' logic uses interpret in a signal trap to re-execute the
failing portion of code with a trace active so I can see what happened and
how the variables resovled. This technique using interpret is not 100%
accurate, but it helps in over 90% of the cases.

Since I tend to keep a model member around with a common "starter set" of
my subroutines, my average production style EXEC starts with a minimum of
1000 lines. When I'm done, I simply remove the stuff in the starter set I
didn't use. However, there is a chunk of refreshable "framework" code that
is in every single EXEC. I have found I can churn out decent quality code
fairly quickly using this approach and when errors do occur, I have left
myself enough diagnostic information to usually figure out the problem without
having to recreate it.

So, yes, lots of small chunks of code (bricks), but I build a lot of houses
using several of those bricks each time I write a new EXEC.


Rob


In a message dated 9/19/2010 10:11:22 A.M. US Mountain Standard Time,
mic...@COMCAST.NET writes:

Well, I also find that if I build code in tight little routines that have
but one function, I can often build a new program just by chopping out 6
routines from 6 existing ones, and writing a little code around them. My
method is to build bricks. Once I have bricks, building houses is easy.

Mickey

--------------------------------------------------
From: "Vitonis, Tony" <Tony.V...@CA.COM>
Sent: Friday, September 17, 2010 4:59 PM

To: <TSO-...@VM.MARIST.EDU>
Subject: Re: [TSO-REXX] Help with INTERPRET

> I couldn't agree with you more. I didn't want to write the sort routine


> more than once, and I wanted the calling code to be small and
> self-documenting - so I didn't have to think about it later.
>
> Tony
>

> -----Original Message-----
> From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On Behalf

> Of Mickey
> Sent: Friday, September 17, 2010 8:28 AM
> To: TSO-...@VM.MARIST.EDU
> Subject: Re: [TSO-REXX] Help with INTERPRET
>

> I'm with you. I keep it very simple. I rarely even write a procedure
> that
> won't fit on one screen.
>

> --------------------------------------------------
> From: "Lindy Mayfield" <lindy.m...@SSF.SAS.COM>

> Sent: Friday, September 17, 2010 2:46 AM


> To: <TSO-...@VM.MARIST.EDU>
> Subject: Re: [TSO-REXX] Help with INTERPRET
>

>> I don't write code that I cannot easily figure out months or years
> later.
>> That's why I stay away from writing clever (if clever == difficult to
>> understand) code. Each to their own I guess.
>>

>> -----Original Message-----
>> From: TSO REXX Discussion List [mailto:TSO-...@VM.MARIST.EDU] On
> Behalf

>> Of Vitonis, Tony
>> Sent: Thursday, September 16, 2010 9:24 PM

>> To: TSO-...@VM.MARIST.EDU
>> Subject: Re: [TSO-REXX] Help with INTERPRET
>>

>> Understood and agreed about clever code. I suppose we'll just differ
> on
>> whether this particular bit of code is "clever". The invoked routine
> is a
>> straightforward implementation of the shell sort, and the invoking
> code is
>> in my opinion very easy to read and understand.
>

Vitonis, Tony

unread,
Sep 20, 2010, 12:14:34 PM9/20/10
to
Yup. "Do one thing, and do it well" is a principle that most mature
programmers accept. Refactoring is painful only if you don't do it
regularly.

Tony

-----Original Message-----
From: Mickey
Sent: Sunday, September 19, 2010 1:11 PM
To: TSO-...@VM.MARIST.EDU
Subject: Re: [TSO-REXX] Help with INTERPRET

Well, I also find that if I build code in tight little routines that
have but one function, I can often build a new program just by chopping
out 6 routines from 6 existing ones, and writing a little code around
them. My method is to build bricks. Once I have bricks, building houses
is easy.

----------------------------------------------------------------------

Mickey

unread,
Sep 20, 2010, 12:59:29 PM9/20/10
to
These come in particularly useful in edit macros. I have the need to run
through a lot of COBOL, and I have these little bricks to do things like
find the next "good" line (not commented), find the next verb, find the data
definition for a variable, etc. I also have them for common services, like
ALLOCATE, FREE, LISTCAT (in many flavors), LISTDSI, SYSDSN, and a host of
others. Inventing the wheel was fun..... ONCE :)

Mickey

--------------------------------------------------
From: "Robert Zenuk" <Robz...@AOL.COM>
Sent: Monday, September 20, 2010 1:41 AM

Mickey

unread,
Sep 20, 2010, 6:08:33 PM9/20/10
to
And it sure helps with processes in which the specs are either a moving
target, or there is perpetual scope creep.

Mickey

--------------------------------------------------
From: "Vitonis, Tony" <Tony.V...@CA.COM>

Sent: Monday, September 20, 2010 12:14 PM

Bob Bridges

unread,
Sep 20, 2010, 8:01:42 PM9/20/10
to
In several languages I have a "program" that's really just a skeleton of
snippets of code. In REXXX I have the few lines I repeat in every program
to interpret arguments; a paragraph saved from a program long ago that uses
OUTTRAP; one for setting up ISPF skeletons; a list of PEEKs I may use
someday; the code I use to determine whether I was called as an Edit macro
or TSO command, so I can respond differently depending; something to trap
LISTALC so I can check to see whether certain DD names are already
allocated; some code to query DB2 and get the results; a sample XMITIP call,
that sort of thing. Then in skel.vbs I have a standard routine that checks
the volume name of the drive from which the VBS is running, so I can know
where to look for other code; an Include command so I can pull in other
subroutines as though I'd copied them into the file; a get-filename dialogue
that apparently works only in Win XP; some sample code that works with a
dictionary object; a few lines that fire up the Excel application in
preparation for me adding more lines to import, format etc. As you say,
it's fun discovering how to do something, but there's no real charm in doing
it again later.

/* Ignorance is the mother of adventure. -Hagar the Horrible */

-----Original Message-----
From: Mickey
Sent: Monday, September 20, 2010 12:59

These come in particularly useful in edit macros. I have the need to run
through a lot of COBOL, and I have these little bricks to do things like
find the next "good" line (not commented), find the next verb, find the data
definition for a variable, etc. I also have them for common services, like
ALLOCATE, FREE, LISTCAT (in many flavors), LISTDSI, SYSDSN, and a host of
others. Inventing the wheel was fun..... ONCE :)

--------------------------------------------------


From: "Robert Zenuk" <Robz...@AOL.COM>
Sent: Monday, September 20, 2010 1:41 AM

> Agreed. I have about 200 of those little "bricks". They are wrappered


> with special entry and exit logic (about 2 lines up front and in the back)
> and special comments (above and beyond normal doc type comments). This
> is so I can use an Edit Macro (called @REFRESH) to call in the needed
> routines and/or refresh them with the most current versions (I prefer to
> use internal subroutines/functions and have a single module to
> distribute). The entry and exit logic provides some extra built in
> debugging features (indented module trace with parms-line numbers-
> start/stop timestamps, command timings, performance data, subroutine level
> tracing, standardized diagnostic output, standardized "abend" logic,
> standardized logging, version control, standard batch report headers,

> etc)....

Paul Gilmartin

unread,
Sep 20, 2010, 9:44:57 PM9/20/10
to
On 09/20/10 18:01, Bob Bridges wrote:
>
> ... the code I use to determine whether I was called as an Edit macro
> or TSO command, so I can respond differently depending; ...
>
Of course ISPF makes this harder than it should be by not setting
the host command environment to a useful value on entry.

> ... something to trap


> LISTALC so I can check to see whether certain DD names are already

> allocated; ...
>
For some purposes, it's simpler to use BPXWDYN( '... rtddn(VAR) ...' )
and let DYNALLOC pick one for me so I needn't probe for a free one.
(BPXWDYN: it's not just for Unix any more!)

Like many coders, I have an elaborate wrapper for "address SYSCALL"
to analyze errors.

In some cases, I copy a member to a temporary DSN SYSEXEC from
SYSIN with my cliche functions concatenated.

-- gil

Mickey

unread,
Sep 20, 2010, 10:26:58 PM9/20/10
to
I also use BPX. If all I want to know is IF a DD is allocated, I will
usually use LISTDSI with the FILE option.

Mickey

--------------------------------------------------
From: "Paul Gilmartin" <PaulGB...@AIM.COM>
Sent: Monday, September 20, 2010 9:44 PM


To: <TSO-...@VM.MARIST.EDU>
Subject: Re: [TSO-REXX] Help with INTERPRET

> On 09/20/10 18:01, Bob Bridges wrote:

Paul Gilmartin

unread,
Sep 20, 2010, 11:31:16 PM9/20/10
to
On 09/20/10 20:26, Mickey wrote:
> I also use BPX. If all I want to know is IF a DD is allocated, I will
> usually use LISTDSI with the FILE option.
>
And how do you use LISTDSI to determine whether a file is allocated?
I've found it enormously unreliable:

READY
free dd(foo junk)
READY
allocate dd(junk) path('/etc/rc')
READY
rexx trace R; call LISTDSI 'junk file'; say sysreason
1 *-* call LISTDSI 'junk file'
>>> "junk file"
>>> "16"
*-* say sysreason
>>> "0002"
0002
READY
rexx trace R; call LISTDSI 'foo file'; say sysreason
1 *-* call LISTDSI 'foo file'
>>> "foo file"
>>> "16"
*-* say sysreason
>>> "0002"
0002
READY
allocate dd(junk) dummy
IKJ56246I FILE JUNK NOT ALLOCATED, FILE IN USE
IKJ56112A ENTER 'FREE' OR 'END'+-
end
READY
allocate dd(foo) dummy
READY

I hate LISTDSI!

Robert Zenuk

unread,
Sep 21, 2010, 1:06:57 PM9/21/10
to
LISTDSI does stand for LIST DataSet Information... Not USS file
information, SYSOUT information or DUMMY information... When used for the intended
purpose it does work fine. The return code and sysreason let you know you
have either used it for something it doesn't support or you have an
environmental issue that is keeping it from returning your data...

I've never understood trying to use an API for an unintended and
undocumented purpose and getting frustrated and/or complaining when it doesn't
work... I see it as a bonus when experimentation uncovers an unintended use and
it unexpectedly works.

I have found LISTALC STATUS to be the most reliable source of allocation
information when verifying non traditional allocations (uncataloged things).
Inserting code to walk the TIOT and JFCB is just too cryptic...

I have a DDLIST function that culls the DD's from LISTALC. My DDCHECK
routine first attempts a LISTDSI. If that fails it calls DDLIST and does a
wordpos against the returned DDLIST to determine if an allocation exists. If
more information is needed (like if the allocation is a PDS or VSAM or), I
use the LISTDSI information already available from DDCHECK. If it is a
USS file and I need to know if it is a directory or a file or pipe or
symlink, I call my USSEXIST routine that accepts the PATH does a stat call and
returns the stat.ST_TYPE value. The path is available in the LISTALC STATUS.
My companion DDDSNS routine builds a DSN list for every DD in a unique
stem dd.ddname (non numeric stem).

Rob

In a message dated 9/20/2010 8:30:18 P.M. US Mountain Standard Time,

Vitonis, Tony

unread,
Sep 21, 2010, 1:10:05 PM9/21/10
to
That's why I use a calculator to do arithmetic. =)

-----Original Message-----
From: Bob Bridges
Sent: Monday, September 20, 2010 8:01 PM
To: TSO-...@VM.MARIST.EDU

Subject: Re: Help with INTERPRET

... As you say, it's fun discovering how to do something, but there's no


real charm in doing it again later.

----------------------------------------------------------------------

Paul Gilmartin

unread,
Sep 21, 2010, 2:32:14 PM9/21/10
to
On Sep 21, 2010, at 11:05, Robert Zenuk wrote:

> LISTDSI does stand for LIST DataSet Information... Not USS file
> information, SYSOUT information or DUMMY information... When used for the intended

There is a passage in "Using Data Sets" which appears to
define a Data Set as anything that can be allocated to
a DDNAME: DASD, tape, card readers, punches, printers,
terminals, etc. I assume that extends to USS files allocated
to DDNAMEs.

And I did supply the FILE option. In TSO jargon FILE
generally refers to the allocation not to the underlying
backing storage.

> purpose it does work fine. The return code and sysreason let you know you
> have either used it for something it doesn't support or you have an
> environmental issue that is keeping it from returning your data...
>

But Mickey said that he uses LISTDSI to determine whether a
a DDNAME was allocated. I supplied a case in which RC and
SYSREASON are identical for an unallocated DDNAME and an
allocated DDNAME. I wonder how Mickey makes the determination.
As a minimum, LISTDSI ... FILE should return a unique
SYSREASON for "file unallocated."

> I've never understood trying to use an API for an unintended and
> undocumented purpose and getting frustrated and/or complaining when it doesn't
> work... I see it as a bonus when experimentation uncovers an unintended use and
> it unexpectedly works.
>

Times change. A driver of a modern automoble rightfully
complains when a highway engineered a century ago has curves
that can not be driven at greater than 15 MPH, regardless
that he's using the highway for " an unintended and
undocumented purpose. LISTDSI is stuck in the mid-20th
century. It needs to get better. Programmers shouldn't
be required to use a different interface for each device
type.

Don Williams

unread,
Sep 21, 2010, 5:05:00 PM9/21/10
to
> Times change. A driver of a modern automoble rightfully
> complains when a highway engineered a century ago has curves
> that can not be driven at greater than 15 MPH, regardless
> that he's using the highway for " an unintended and
> undocumented purpose. LISTDSI is stuck in the mid-20th
> century. It needs to get better. Programmers shouldn't
> be required to use a different interface for each device
> type.
>
> -- gil

YES! I agree. IBM has had more than enough time to modernize LISTDSI (and
many other interfaces as well) into a more effective interface.


Don Williams
DBWi...@unch.unc.edu
(919) 966-3968
UNC Hospitals
Information Services Division, 2nd Floor
321 Meadowmont Village Circle, Chapel Hill, NC 27517

"The time is always right to do what is right" -- Martin Luther King, Jr.

Bob Bridges

unread,
Sep 22, 2010, 12:08:46 AM9/22/10
to
Not that it matters, but when I check LISTALC what I'm looking for is not
free DDNs that I can use, but user-supplied DDNs that I should respond to.
For instance, if I tell the user that he can supply any number of DDs
"BOOKnnn" for input to a certain parm, I need to look through LISTALC to
detect and read them all.

When I want a free DDN for output, I have a subroutine that accepts a
prefix, say "TEST", and generates a few random numbers to see whether
LISTDSI thinks TEST0369 is free, then TEST1039, TEST9973 and so on. If it
hits 10 in a row already allocated, something's wrong and it fails. It's
kludgy, I guess, but I've been using it happily for a decade or so now. And
it's not the sort of thing that I'd ever need to use in a loop, so it
doesn't matter much if it could be faster. It just saves me having to make
up a name that might already be used by some other program that's also
running at the same time.

I've heard you guy's talking about this BPX...thingy; I never supposed it
was available outside OMVS so I never looked seriously at it. Should I?

/* Ignorance is the mother of adventure. -Hagar the Horrible */

-----Original Message-----
From: Mickey
Sent: Monday, September 20, 2010 22:27

I also use BPX. If all I want to know is IF a DD is allocated, I will
usually use LISTDSI with the FILE option.

-----Original Message-----
From: Paul Gilmartin
Sent: Monday, September 20, 2010 21:44

For some purposes, it's simpler to use BPXWDYN( '... rtddn(VAR) ...' )
and let DYNALLOC pick one for me so I needn't probe for a free one.
(BPXWDYN: it's not just for Unix any more!)

--- On 09/20/10 18:01, Bob Bridges wrote:
> ... something to trap LISTALC so I can check to see whether certain DD

> names are already allocated...

Paul Gilmartin

unread,
Sep 22, 2010, 12:25:24 AM9/22/10
to
On Sep 21, 2010, at 22:08, Bob Bridges wrote:
>
> I've heard you guy's talking about this BPX...thingy; I never supposed it
> was available outside OMVS so I never looked seriously at it. Should I?
>
Yes.

-- gil

Robert Zenuk

unread,
Sep 22, 2010, 12:36:57 AM9/22/10
to
It is loading more messages.
0 new messages