This is a collection of hints, tips, and code samples that may be
useful to people who are thinking of developing in Rexx.
The usual disclaimers apply to all code samples (including the MACROs').
We have now made available a full working copy of some of our Rexx execs. it is available
here.
|
We would definitely recommend the use of Rexx over clist and we thoroughly recommend Michael Cowlishaw's book " The Rexx Language: A Practical Approach To Programming". It is a wonderful reference book, in it's own right and an invaluable learning tool when it comes to Rexx 'how to' type questions. |
| Fuss Free Dataset Name Format Checking | ||
|
upper dsname /* Make it upper case */ dsname = STRIP(dsname,,'''') /* Remove quotes */ x = MSG('OFF') TrapON=OutTrap('ON') Dsnstat = SYSDSN("'"dsname"'") /* Check dataset name */ TrapON=OutTrap('OFF') x = MSG('ON') if word(dsnstat,1) = 'INVALID' then do Say 'Dataset name invalid 'dsname Signal dosomething end |
The technique shown in this example will quickly let you know if the dataset
name passed in the variable is in a valid format or not.
You could use Case logic to trap so many more things but if you are just looking to see if the format of the dataset is valid, then this technique will do nicely. |
|
|
| ||
| Zeller's Congruence | ||
|
day.0 = Saturday day.1 = Sunday day.2 = Monday day.3 = Tuesday day.4 = Wednesday day.5 = Thursday day.6 = Friday temp1 = ((mm+1)*26)%10 temp2 = yy%4 temp3 = 6*(yy%100) temp4 = yy%400 temp1 = dd+temp1+temp2+temp3+temp4+yy if yy < 1751 then do temp1 = temp1 + 11 end if yy = 1752 then do if mm <= 3 then do if mm = 3 then do if dd <= 24 then do temp1 = temp1 - 11 end end temp1 = temp1 + 11 end end temp4 = temp1%7 temp2 = temp4*7 temp3 = temp1-temp2 say day.temp3 dd mm yy |
Zeller's Congruence (explained here)
will calculate the day of the week for a given date.
This sample code shows how to calculate Zeller's congruence in a way such that it is easier to follow the steps. The code alongside is stripped down for example purposes but a working copy is available here. |
|
|
|
||
| Discovering What LPAR You Are Running On | ||
|
CVTECVT=D2X(C2D(STORAGE(10,4))+140) lparname=STRIP(STORAGE(D2X(C2D(STORAGE(CVTECVT,4))+344),8)) permitted_on = "SYS2SYS3" /* only allow it on these systems */ If POS(lparname,permitted_on) = 0 then do say "Not allowed on "lparname end else do say "OK to run on "lparname end Example of how to use CPUCHECK cpucheck if rc = 0 then say ‘allowed’ else say ‘denied’ |
Sometimes you may want to restrict which LPAR a Rexx exec can execute on.
This code will allow to you find out which LPAR the exec is running on. The first two lines return the LPAR name and the next few lines show how to prevent/allow the exec to run. In this example we set a list of LPAR names that the exec is allowed to execute on (SYS2 & SYS3) so that we don't have to code lots of SELECTS just one simple POS. However you may have to reconsider the POS technique if you have an LPAR named anything that may get inadvertently matched e.g. YS2S Of course you could also flip the logic a little and make the name specified the name of the LPAR that this exec is not allowed to execute on. We have a Rexx EXEC named CPUCHECK (available here) that can be called by any Rexx EXEC and it will set a return code that indicates if the Rexx EXEC is running on an allowed system or not. An example of how to use this is shown here. It will save you having to repeat the checking code. Again you can always flip the logic if desired. It is important to note that CPUCHECK uses a system variable (sysname) that is set on our system. If you prefer you could navigate the control blocks in the example above. |
|
|
| ||
| Discovering What Jobname Is Running The Rexx Exec In Batch. | ||
|
CVT =
STORAGE(10,4) TCBP = STORAGE(D2X(C2D(CVT)),4) /* CVTTCBP */ TCB = STORAGE(D2X(C2D(TCBP)+4),4) TIOT = STORAGE(D2X(C2D(TCB)+12),4) /* TCBTIO */ job = STRIP(STORAGE(D2X(C2D(TIOT)),8)) /* TIOCNJOB */ |
This code can be used to discover the job name that is running the Rexx
exec in batch.
If you do it under TSO it will return your own TSO name. Once you have the jobname you can make lots of choices based on the jobname...like use it for a dataset level or, if you have good naming standards you can take a different logic flow based on whether it is a production or development job. |
|
|
|
||
| Discovering The Job Number of The Job Running The Exec. | ||
|
CVT = STORAGE(10,4) TCBP = STORAGE(D2X(C2D(CVT)),4) /* CVTTCBP */ TCB = STORAGE(D2X(C2D(TCBP)+4),4) JSCB = STORAGE(D2X(C2D(TCB)+180),4) /* JSCB */ SSIB = STORAGE(D2X(C2D(JSCB)+316),4) /* SSIB */ jobnum = STRIP(STORAGE(D2X(C2D(SSIB)+12),8)) /* Get jobnum */ |
This code can be used to discover the job number that is running the Rexx
exec in batch. If you do it under TSO it will return your own TSO number. |
|
|
|
||
| Replacing a String In a Rexx Exec | ||
|
/* Rexx */ input = 'my favorite color is red' input = strrepl(input,'red','green') say input exit StrRepl: Orig = ARG(1) Oldtxt = ARG(2) Newtxt = ARG(3) Newstr = '' Work = Orig Do while POS(Oldtxt,Work) > 0 Newstr = Newstr||SUBSTR(Work,1,pos(Oldtxt,Work)-1)||Newtxt Work= SUBSTR(Work,pos(Oldtxt,Work)+LENGTH(Oldtxt)) end Newstr = Newstr||SUBSTR(Work,1) return Newstr |
We use this routine in many of our Rexx execs.
It will replace the second value with the third value in the field specified by the first value. The string lengths don't matter so it makes this code pretty slick. In the example here we replace the sting 'red' with the string 'green' in the field 'input' which contains the string 'my favorite color is red'. Note: The StrRepl routine here is a subroutine and so it can be copied and pasted in its entirety into any exec and be ready to be used. A text version of StrRepl subroutine is available from here. |
|
|
|
||
| Finding The Name of The Current Exec | ||
|
/* Rexx */ dialogid = sysvar(sysicmd) parse source Exec_String excnme = word(Exec_String,3) /* Get EXEC's name */ say excnme ' Starting.' date() time() final = TIME('Reset ') say excnme 'Finished :' date() time() 'Elapsed time 'time(e) 'seconds' exit |
This snippet of code will return the name of the executing Rexx exec.
In this sample code we also demonstrate how to display the time that the Rexx exec took to execute. |
|
|
|
Convert A Month Number To Month Name | |
|
/* Rexx */ Mon.01="January" Mon.02="February" Mon.03="March" Mon.04="April" Mon.05="May" Mon.06="June" Mon.07="July" Mon.08="August" Mon.09="September" Mon.10="October" Mon.11="November" Mon.12="December" myDate= "1999/12/25" /* This is a sample date in yyyy/mm/dd format */ year = substr(myDate,1,4) /* Year portion (change as appropriate) */ day = substr(myDate,9,2) /* Day portion (change as appropriate) */ mon = substr(myDate,6,2) /* Month portion (change as appropriate) */ monname=MON.mon /* translate to name */ say day monname year /* show the date */ exit |
Sometimes a date is in all numeric format and you may want the full month
name in this case this sample code will do the trick.
Any value can be placed in the 'table'. In other words if you only want the first three characters, then simply enter them instead of the full month name. You will need to tweak the code to accommodate the date format if it isn't yyyy/mm/dd. A text version of this code can be found here. |
|
|
|
||
| Building a Delay Into a Rexx Exec (Sleep) | ||
|
/* Rexx */ parse upper arg time value If value <> "" then do value = substr(value,1,1) /* If you don't pass a value seconds are assumed otherwise:*/ /* use M for minutes or H for hours */ if value = "M" then time = time * 60 if value = "H" then time = time * 60 * 60 end if time = "" then time = '1' hit = 0 Do while hit < time hit = TIME('Elapsed ') end = lastpos('.',hit) hit = substr(hit,1,end) end exit |
Occasionally you may want to delay an Exec for a couple of seconds or
more. There is currently no inbuilt Rexx function for this. This Exec
will delay the execution of the calling Exec for the number of seconds,
minute or hours that are passed to it.
*** WARNING *** This Exec takes no prisoners! If you say sleep for an extended duration it will do just that and will lock out the TSO id or job for that long. A text version of this code can be found here. |
|
|
|
||
| Converting a String to Proper Name Format | ||
|
/* Rexx */ input = 'ABBYDALE' input = Proper(input) say input exit Proper: Orig = ARG(1) if length(orig) > 1 then do /* Ensure there is more than one char */ UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" LOWER = "abcdefghijklmnopqrstuvwxyz" tempName = TRANSLATE(Orig,LOWER,UPPER) build = substr(tempName,2,Length(tempName)-1) initial = substr(tempName,1,1) initial = TRANSLATE(initial,UPPER,LOWER) newname = initial||build end else do newname = Orig end return newname |
When you are dealing with proper names (People's name, place names etc.)
the correct format is to start them with a capital letter. Unlike some
languages there is no built in Rexx function for doing this therefore
we use this subroutine for achieving this.
In the example shown the name ABBYDALE will be converted to Abbydale by the subroutine. It should be noted that even if the name is already in lower case this routine will work. Note: The Proper routine here is a subroutine and so it can be copied and pasted in its entirety into any exec and be ready to be used. A text version of Proper subroutine is available from here. A brief demonstration is available here. |
|
|
|
||
| Dropping the Last Level From a Dataset Name | ||
| dsname = SUBSTR(dsname,1,(LASTPOS('.',dsname)-1)) |
If you ever want to drop the last level from a dataset name, you can
do it by using this code.
You can use this for generic LISTCATs etc. Looping through this process will drop you down more levels. |
|
|
|
||
| Obtaining the Current TSO PROFILE PREFIX | ||
|
/* rexx */ prof = getprof(prof) /* Get current prefix */ say "Value of prof="Prof /* Show answer */ "Profile noprefix" /* Profile NOPREFIX */ prof = getprof(prof) /* Get current prefix */ say "Value of prof="Prof /* Show answer */ "Profile PREFIX("userid()")" /* Set to our userid */ prof = getprof(prof) /* Get current prefix */ say "Current profile "prof /* Show answer */ "Profile noprefix" /* Set NOPREFIX */ "Profile" /* Show our profile */ say say "Value of prof="Prof /* Show answer */ say if Prof/='N' then do /* Prof = our userid */ "Profile PREFIX("Prof")" /* Reset prefix */ end "Profile" /* Show our profile */ exit |
It is sometimes useful to store the TSO PREFIX in use when a Rexx is
executing. It is extremely useful when you want to set the PROFILE
to NOPREFIX but want to reset it back to what it was when the exec
was called.
GETPROF can provide this function. The GETPROF routine is available from here. The code alongside is NOT GETPROF but a demonstration of how to use GETPROF. A copy of the code alongside is available from here. |
|
|
|
||
| Counting Occurrences of a String | ||
|
Usage x=CountStr(find,where) Sample of use:x = CountStr('.','ABBYDALE.ALLFREE.REXX') This would return 2 as the value of x. If you need to know if this is an odd or even number you can use: x = CountStr('.','ABBYDALE.ALLFREE.REXX')//2 if x > 0 say 'Odd' |
This function will count the number of times a passed string occurs in
another passed string.
This is useful if you want to count the number of levels in a dataset name. The COUNTSTR routine is available from here. |
|
Abbydale Systems LLC Lic. 802696149. All rights reserved.