Up to the computing page. Send Feedback.

Last-modified: 01 Aug 2004 Version: 1.4q

TSO-REXX Frequently Asked Questions Contents
1.

2.

3.

Introduction 1. Changes made to the FAQ at this release 2. To Do Using Rexx. 1. How do I Run My Rexx Exec. 2. How do I allocate Exec libraries and other datasets to my TSO or ISPF session. 3. Where can I find Rexx manuals and documentation. 4. How do I find or access the current level of a GDG. 5. How do I access data in control blocks such as jobname. 6. How can I access a calling execs variables. 7. How do I implement job control with (and for) Rexx 8. Where are the Standard Rexx I/O functions. 9. How do I replicate CLIST's WRITENR functionality. 10. Why does Outtrap() not trap all output. 11. EXECIO, why does it require 'Enter' more than once. 12. How do I List Datasets and PDS members. 13. How do I access data held on the JES spool. 14. What do unusual return codes such as -3 and 0196 mean. 15. How do I pass parms to my ISPF Edit macro. 16. Why are my procedure arguments in upper case. Rexx and Different environments. 1. OS/390 Unix Systems Services 2. ISPF Services 3. ISPF Services in Batch 4. Load Modules (I.e. Assembled programs) 5. SQL 6. Console Command Environment 7. Rexx aware editors 8. Rexx Compilers 9. Using Rexx as CGI programs with the Web Server.

4.

Style.
1. What are the most effective ways to use comments? 2. EXECIO. 3. What case should I program in, upper or lower? 4. Functions and procedures 5. Logical (Boolean) variables and functions. 6. Symbolic names. 7. Internal and external calls 8. How can I improve performance of my exec? 9. How can my systems programmer improve performance? 10. What obscure coding tricks are there? 11. Using Non-Alphanumeric characters. 12. Are there any other style hints?

5.

Appendices. 1. Code Examples 2. Other Sources of Information 3. Subscribing to the TSO-REXX List 4. Glossary Introduction

This FAQ is for REXX/MVS, that is, REXX for IBM mainframes (MVS, OS/390 and VM). It is unofficial and based on questions asked in the TSO-REXX listserv group based at LISTSERV@VM.MARIST.EDU. As is the case with all FAQs, this document is a work in progress. Additions, corrections, and comments are very welcome. Please send any correspondence to webspace@neilhancock.co.uk If this FAQ or the List Archivedoes not answer your Rexx questions, do not email me, but instead subscribe to the TSO-REXX List where your questions will be usually be answered promptly by many knowlegable people. Thanks for contributions from: Jon Alexander, Stephen Bacher, Tim Larsen, John McDonald, and all those who posed and answered questions on the mail list. In coding examples, screen output is indicated by ==> within a comment. Latest edits are marked in bold in the contents section.

Changes made to the FAQ at this release.
• • • • • • • • • • •

1.4q - Update links and whatnot, add EXECIO tip, add PARSE ARG. 1.4p - New coding trick. Assorted submissions and updates (Thanks!). 1.4o - Assorted minor things from the list, edit macro parms. 1.4n - R.I.P. Deja. ReMarQ too. Code examples moved external to FAQ. 1.4m - Performance updated. Coding tricks added. 1.4l - LIBDEF/ALLOC/ALTLIB question and sample. 1.4k - Subscription Info added. 1.4j - Rexx in Batch added. More info added to. RXSQL noted. Docs question added. 1.4i - More reformatting, Some answers reviewed and amended. 1.4h - Minor formatting. 1.4g - Corrections submitted by Peter Tillier. Reinstated rexx information sources To Do

• • • •

Is Posix (USS) info still up to date and correct? Inline JCL technique with IEBGENER to temp PDS. XMLify. Scare up some useful google keywords. Using Rexx. How do I Run My Rexx Exec.

Most of this is described in the User Guide, or in the guide for the appropriate environment. For the TSO environment:
• • • •

Make sure the Exec starts with the /* REXX */ comment. TSO EXEC 'hlq.your.dsn(member)' runs Rexx in exactly the same way as it would a CLIST. TSO EX yourlib(member) E uses a suffix of EXEC and the TSO profile prefix to form a full DSN of 'your_prefix.yourlib.EXEC(member)' The SYSEXEC concatenation can be used to run execs using TSO execname. The SYSPROC concatenation will do just as well, but is really intended for CLISTS.

TSO %execname parameter_string allows you to pass a parameter string to the exec, note that this string is only a single argument, not multiple arguments as can be used when calling from within an exec. The '%' instructs TSO to not use loadlib concatenations when constructing the search path.

For running Rexx in batch:
• • • • • •

Create a batch environment for the Exec to run in with PGM=IRXJCL, PGM=IKJEFT01 or PGM=IKJEFT1B IRXJCL is a straight batch environment IKJEFT01 and IKJEFT1B are the TSO in batch programs. Put the Rexx exec libraries in the SYSEXEC DD concatenation. Call your exec via the PARM='yourprog' or as input in the SYSTSIN DD See the Code Examples appendix for examples.

For more information, RTFM. How do I allocate Exec libraries and other datasets to my TSO or ISPF session.

ALTLIB ACTIVATE can be used to dynamically add an Exec or Clist library to the search path. I don't know whether these ATLIBs are stacked in the way LIBDEFs can be. LIBDEF can be used to dynamically allocate other libraries, such as ISPF panel libraries. Use the STACK option to avoid corrupting the environment for nested calls to applications. An example LIBDEF/ALTLIB is in an appendix. Your allocations at logon are controlled by the JCL procedure used to initiate your TSO environment. This is called your TSO LOGON PROCEDURE, and it will be under the control of your systems programmer. To override the LOGON proc and allocate your own SYSEXEC, ISPPLIB, etc concatenations, the TSO ISRDDN command can create a handy CLIST to use as your base. To generate the TSO ALLOC commands needed to replicate your current allocations, type the CLIST command on the command line. Edit and save the Clist created, and run it at logon (outside of ISPF) to allocate your own environment. Where can I find Rexx manuals and documentation.

Thanks whoever you are . /* REXX Get taskname from TCB */ cvt = storage(10. How do I find or access the current level of a GDG. See RXGDGV() in the appendices. How do I access data in control blocks such as jobname? Use the Storage() function to extract the data from control blocks.4) tiot = storage(d2x(c2d(tcb)+12). Interfaces for other applications will be documented with that application. There is a manual for Rexx in the Unix System Services environment. ISPF interfaces ( E.4) /* CVTTCBP */ tcb = storage(d2x(c2d(tcbp)+4).IBM Online Library in HTML and PDF form. ISPF Edit Macro commands) are documented in the ISPF section. Use PARSE ARG args and RETURN value).NWH */ How can I access a calling execs variables. A classic example of this is creating an exec to sort the contents of a stemmed symbol. Rexx doesn't allow an exec to access the symbols used by another exec. The Rexx Reference and Guide are in the TSO section. Refer to the IRXEXCOM macro interface in the IBM Rexx manuals. Some suggested methods are: • • • Use ISPF variable pools to pass values across execs Pass all symbols as arguments and returned values (I.8)) /* TIOCNJOB */ /* I have lost the original author of this code.4) /* TCBTIO */ say strip(storage(d2x(c2d(tiot)).4) /* FLCCVT-PSA data area */ tcbp = storage(d2x(c2d(cvt)). Use Outtrap() on the output of TSO LISTCAT. clisk on the 'elements and features' links.e. Create your own function in assembler to pass stems across. .g.

possibly running a Rexx exec at the end of each job to perform error recovery. HOWEVER.. How do I implement job control with (and for) Rexx The obvious answer is to use JCL condition code processing. E. You must "schedule" this routine to run after every single batch task. Use the stack. and possibly try to exploit one of the following: . etc.COM> writes: SDSF offers a batch interface. If you can. DELSTACK.• • Generate executable code as the returned string and use INTERPRET on it to make the variables available in the external program. see NEWSTACK. Let's say that you want to monitor the majority of your batch work. QUEUE. Another solution if the JCL is part of a single application is to pass checkpoint information between an application server and executing tasks in a dataset. PULL. but I'm not sure you really want to change your production scheduler just to solve this one problem. message issuing.g. in the manual. etc. then you can build a set of REXX to call this interface from within a TSO environment. and then submit a job that updates the dataset with diagnostic information that the server will interrogate when the job has finished. PUSH. So. you must still consider how you will implement this facility. I can't swear that you can "interrogate" sysout data or condition codes from this interface. I don't have the documentation here at home. and also provides an interface to their "SDSF counterpart" called SYSVIEW/E which will definitely allow you to display sysout text and conditions codes. See the ISPF in batch discussion for more information. so you will need to validate this also. CA's (formerly Legent's) JOBTRAC scheduling product provides a facility to run a REXX routine at the termination of each batch event.. They distribute a sample REXX with their maintenance tape that provides most of the code for what you would want to do. I would recommend that you get away from looking at the SDSF data. to make a long answer even longer. A server may create and prime a checkpoint dataset. This is not an easy task from within CA-7. but it can be found as a whole chapter in the SDSF Users Guide (Chapter 15 seems to stick out in my head). inputting the jobname and JES number for the SDd. Jon Alexander <johnalex@AOL.

See if you can exploit CA-11 or CA-7 as far as a user exit point or extracting their database info. and your program will be of more use in a Rexx environment. Use PUTLINE when writing assembler programs. Lineout().Implement your own IEFACTRT exit (there are a lot of samples out there) to perform the actions you need (yeah. I/O can be done using the functionality of EXECIO. The free utility XWRITENR (and also XPROC) are available from ftp. . I know. but only traps output from the PUTLINE macro. have not been implemented in MVS/Rexx *as far as I am aware*. I'd rather do it in REXX also) . . However this I/O function is not implemented in MVS/Rexx.Implement the SHARE sample of an IEFACTRT exit that generates WTOs with step condition code results.Get with your CA rep and see if CA-7 will be incorporating any of the REXX technology that CA-JOBTRAC currently uses and possibly a time frame on the availability Where are the Standard Rexx I/O functions Linein(). How do I replicate CLIST's WRITENR functionality? The Rexx say command places a carriage return and line feed at the end of each say command execution.mackinney. Stream() etc. Use CHAROUT(). and take actions based on that . and use your local automation package to intercept the WTO and perform an automation process. A function package giving I/O functions for the OE environment only is available from IBM's Download website.com and the CBT tape Why does Outtrap() not trap all output The Outtrap() function does not trap output written directly to the screen by the TPUT macro. Some suggestions for creating a say command that behaves in the same way as CLIST's WRITENR are: Use a CLIST call..

who will have to look things up in the TSO manuals.TSO Session Manager can be used to trap and manage all output that is normally written to the screen. There are various methods for listing datasets and PDS members. Session Manager may require some setting up by your Systems Programer. A PDS directory can be allocated (LRECL=256) and read with EXECIO. Create your own access routines in assembler using the BPAM access method.ISPF library management utilities. "EXECIO "queued()" DISKW DDNAME (FINIS)" will write the entire stack without requiring a null line to terminate output. E. why does it require 'Enter' more than once When using "EXECIO * DISKW DDNAME". Use the LINKMVS environment to use it. Use the Queued() built in function instead of '*'. See ISPF services manual for details. A high performance catalog search routine shipped by IBM.g. So a users will have to hit enter once to generate a null line.TSO dataset list command.Catalog Search Interface. Use the MEMBERS subcommand to get the members of a PDS. EXECIO. • • • • • LISTDS . How do I List Datasets and PDS members. This method does not work with PDSEs and cannot be guaranteed to work in the future. "EXECIO 1 DISKR DDNAME (FINIS)" will only read a single line from the stack or terminal input. LM utilities . . Rexx will continue pulling input from the stack and from terminal input (depending on the users TSO PROMPT() value) until it gets a null line. Solutions are: • • • • Queue a null line before writing data from the stack. Only EXECIO the required number of lines from terminal input. CSI . EXECIO of the PDS directory. Use LMMLIST with LMINIT to list the members. See also EXECIO under Style.

Try looking at the CBTTape for examples. The TSO STATUS command gives limited information about jobs on the spool. arg02 /* Arguments parsed with no uppercasing */ ARG arg01. JES3 sites can extract data off of the JES3 spool using E-JES. E. It may be because you are using ARG instead of PARSE ARG PARSE ARG arg01 . The TSO CANCEL command can be used to stop jobs. arg02 /* arguments are uppercased */ Also note that the command line on most panels has CAPS(ON) set. and TSO SUBMIT to them. Notable execptions (where case is preserved) are ISPF edit and ISPF 6. This is explained further in the Rexx manuals. Brave souls can try the JES interface macros. -3 indicates external environment not found. 0196 is decimal for hex 0C4.g. How do I access data held on the JES spool. How do I pass parms to my ISPF Edit macro. The TSO OUTPUT command can reteive some data from the spool. Innovations FDR package supplies a tool for reporting upon datasets (FDREPORT) that can be customised for use with Rexx under TSO.• FDR . From command line calls use ISPEXEC "MACRO (parms)" From ISPEXEC EDIT call use VPUT and VGET Why are my procedure arguments in upper case. .Dataset management tools. JES2 users can brave the perils of SDSF in batch or other third party products What do unusual return codes such as -3 and 0196 mean? Basically they are either decimalised abend codes or indicate a problem with the environment.

but through new symbols retval and errno. stems. Some specific areas covered by ISPF services are: .Rexx and Different environments. From outside of the shell use the Syscall() function to activate the environment. So RXGDGV() will work whilst rxgdgv() will fail not found.' (or whatever its called this week). The syscall environment initialises __argv. and __environment. ISPF Services address ISPEXEC is detailed in the REXX and ISPF manuals. OS/390 Unix System Services address SYSCALL and address SH give you the ability to run execs that use OpenEdition MVS services. See Manual 'Using REXX to Access Unix System Services.g.TEST. mount example. Newly created executables may need to be made executable with a 'chmod' command. See MTM_RDWR in the mount example below. Examples can be found using the MODELcommand in the ISPF editor. There are some pitfalls in this environment: • • • • External names are uppercased. The syscall environment initialises some variables which may be the same as those you use.MOUNT' address SYSCALL "mount (path) (dsn) HFS "MTM_RDWR say 'Rc='rc 'Retval='retval 'Errno='errno • • Command return codes are not exactly passed via the usual rc symbol. /* REXX mount example */ path = /tmp/testpath/mountpoint dsn = 'HFS. E. The method of passing variables into the environment calls is different from 'classic' MVS calls.

ADDPOP. the termination will pass a zero RC back to the batch job. causing the TSO FREE to fail. /* REXX . where a freed table may not be truly free (its ISPF trying to be eficient). I suggest setting RC=4 as normal completion. then return control to the Rexx */ say 'Setting CONTROL ERRORS RETURN' "CONTROL ERRORS RETURN" . Firstly. most terminations can be controlled using ISPEXEC CONTROL. ADDRESS ISPEXEC "TBOPEN FAKETAB LIBRARY(FAKELIB) NOWRITE" ISPF Services in Batch ISPF services can be used by a batch job. the ISPF RC has to be passed back via profile variable ZISPFRC. There is a known problem in ISPF table services. open a fake table. To avoid the problem. and others. and treating RC=0 as an abend in the job control. TBSCAN to find a table record. Lastly. of course) don't appear to be controlled by CONTROL. ISPF table access with the TB utilities.• • • • PDS interrogation and manipulation using the LM utilities E.g. BDISPMAX and BREDIMAX errors. LMCOPY to copy datasets and PDS members. often caused by ISPF trying to display a panel (which it can't in batch. see below for an example. as the Rexx RC is ignored by ISPF. e. E.g.g. although panel display and user interaction may be a little limited. Secondly. There can be some difficulties when ISPF return codes >=8 cause ISPF to terminate. and cause abending programs to return zero RCs to the batch job. Use ISPSTART running under IKJEFT01 to initiate the ISPF environment. Panel services with DISPLAY.Controlling ISPF errors example */ address ISPEXEC /* If an ISPF error occurs. Edit and Browse with ISPF EDIT and ISPF EDIT macros. see the manuals for this.

I cannot get this to return control to the Rexx. which causes ISPF to cancel and is thus influenced by the CONTROL ERRORS RETURN */ say 'Calling LMINIT' "LMINIT DATAID(PIGLET) DATAFISH('HADDOCK')" say 'LMINIT rc='rc /* Call EDIT with a non existent edit macro. Returns rc = 20 . which is not usually terminated by ISPF anyway */ say 'Calling LMFREE' "LMFREE DATAID(EEYORE)" say 'LMFREE rc='rc /* Call LMOPEN with a bad parameter.EXEC(ISPFTEST)') MACRO(MCGYVER)" say 'EDIT rc='rc . The JCL completion code is an not very useful '00' */ say 'Calling EDIT' "EDIT DATASET('NWH./* Call LMFREE for a nonexistent dataid.GENERAL. Returns rc = 10 . and it terminates here with the 'ISPP330 BDISPMAX exceeded' message.

but briefly. and a message appears in the SYSTSPRT output */ exit 12 See the Appendices for an example JCL procedure. TSOCMDxx PARMLIB member for TSO command authorisation. As ISPF is active. Creating and accessing Rexx external functions using compilers and assembler is also documented in the Rexx manuals. LINKMVS. It is well worth understanding APF authorisation for load modules. APF authority abends are usually a result of the loss of an authorised environment caused by 'dirty' programs in the user address space or non APF authorised libraries in the STEPLIB concatenation. it is overridden with the value of ZISPFRC. Some items to look out for are: • • • The SETPROG console command. ATTCHMVS. Assembled programs) address MVS. Examples of using the IRXEXCOM interface are on the CBTTape. Assembling programs with AC=1 . Read the manuals for full details.e. but it would have if just TSO was involved. are detailed in REXX manuals. Load Modules (I./* Pass the current value of rc back to job control */ zispfrc = rc address ISPEXEC "VPUT (ZISPFRC)" /* This EXIT return code will not make it back past ISPF. etc. These allow the user to pass parameter lists into the load module.

*/ Exit . You must run under TSO. The interface supplies the DSNREXX environment (as in ADDRESS DSNREXX "EXECSQL SELECT FROM yadda. REXX provides a host command environment. */ Address CONSOLE "CART(REXXMVS)" /* Establish a CART token. RETURN CODE IS" GETCODE Address TSO "CONSOLE DEACTIVATE" /* stop the console session.60) /* get response */ If getcode = 0 then /* got response? */ Do i = 1 to prtmsg.. and described in the latest IBM DB2 manuals. A problem program is any non APF authorised program. either interactive or batch. I've attached a simple example. Console Command Environment Kevin McGrath writes: MVS TSO/REXX will issue MVS commands using TSO's MCS console support.0 Say prtmsg.i /* do something with response */ End Else Say "GETMSG ERROR RETRIEVING MESSAGE. /* REXX under TSO */ Parse arg command Address TSO "CONSOLE ACTIVATE" /* start a console session. SQL DB2 for zOS has a Rexx interface.'REXXMVS'.'. Look in Appendix "D" and "E" of the TSO/E REXX Reference.• 'Problem' programs.'sol'. introduced with DB2 version 5. */ Address CONSOLE command /* Issue command. */ getcode = GETMSG('prtmsg.yadda").

Note that solicited messages are not necessarily available from subsystems such as JES. A freeware utility that converts Rexx source into a tokenised form (as is used by LLA / VLF) is rumoured to exist. Use SYSCALL "write . cgiutils for writing http headers (for passing html versions and cookies to the browser. For pre OS/390 V1 R3 systems. the Rexx say command wraps at 80 characters. There are also user profile OPERPARM segments involved. Note that use of interpret to extract parms is insecure. RACF. and process unsolicited messages to retrieve information from subsystem commands. You may have to issue the command. Some browsers convert special characters to an escaped notation. and the parms can be extracted with the parse command. including forms data. Rexx can be used to create CGI programs that access MVS based resources for Web browser based users." instead. This can be done using the Rexx say command. Ask on the newsgroup for Information on what is currently available. and Kate (part of KDE) uses a simple XML markup that allows highlighting of any language. ISPF edit also supplies models for ISPEXEC services. Using Rexx as CGI programs with the Web Server. etc. A user may manage to pass raw rexx commands into the CGI exec. The BonusPak supplies two shell commands. the CGI parameters are available in environment variable QUERY_STRING. Rexx Compilers There are Rexx compilers available. Rexx aware editors ISPF edit supplies a color hilite facility that is a must if it is available.Neil Hancock adds: Your security setup may restrict use of the console environment. All the Rexx program is doing is to write a dynamic html page to the POSIX sysout stream. For the GET CGI method. including one from IBM. etc). andcgiparse for reading environment variables. Environment variables are available in the Rexx stemmed variable __environment. .. The relevant RACF profile is listable using RLIST TSOAUTH CONSOLE ALL. although you may have to adjust the style to your own. Many *nix editors understand Rexx.

Your site may have its own conventions and these should take precedence over anything said here. Only open and close a comment that goes across many lines once. Commands can be run under TSO using the tsocmd shell command. Close any brackets. It makes little sense to comment every line no matter how trivial. especially CLIST. These style hints are mostly aimed at programmers from other MVS and TSO languages. particularly select statements and do loops that cover more than one screenfull of program. It seems sensible to take the opportunity to say something about what the program is about in this opening comment. and more importantly.Access to Classic MVS resources can be done by using Rexx function shcmd to trap the output from commands run under TSO. It makes the code look neater. which must also be a comment. This restricts the insertion of maintenance code. You then avoid unexpected occurances of rc(-3) when you run the exec under IRXJCL instead of IKJEFT01. Don't squeeze comments down the right hand side of the code. the restricted space causes the comments to become abbreviated past the point of becoming cryptic. . Use address MVS "EXECIO" in preference to address TSO "EXECIO". What are the most effective ways to use comments? • • • • • You must have REXX as part of the first line of Rexx. Both shcmd and tsocmd are available from the IBM Kingston ftp site. There are no real performance benefits in this. and that too is perfectly acceptable. Style. Consider commenting what is being terminated at an END statement. EXECIO. Rexx isn't assembler and most commands are self evident. only your code will contain fewer extraneous characters. You may also prefer to work in your own style. and this will help you see the wood for the trees.

haystack) then say 'Hello' versus: call Linein needle. 0 logically false.g. and to use mixed case for Rexx commands and symbols. Functions and procedures If a call returns a value that is not a return code. upper or lower? Readability can be improved by writing Rexx as if it were a human language and not as if it were JCL or assembly code. Consider: if Linein(needle. Symbolic (or variable) names are not limited to eight characters as in some other languages. Avoid having the entire program in upper case. E. It is common to write commands addressed to external environments in upper case. this allows more scope for meaningful names. this is known as shouting and does nothing to help readability.COM> writes: With DISKW .'NUM') then say 'Hello' /* Is OK */ if Pos(needle. Functions may return logical values. instead of a null-record and "*".haystack if result = 1 then say 'Hello' Make the names of functions and procedures meaningful Logical (Boolean) variables and functions.g. depending on the TSO PROFILE! E. Symbols with a value of 1 are logically true.haystack) then say 'Hello' /* May abend */ Symbolic names. The names used will . it may be better to call it as a function rather than a procedure. All other values give an error when tested for logical truth. E.Tim Larsen <DKDDBNGX@IBMMAIL. if Datatype(var.use the queued() built-in. If you forget the null-record ("QUEUE'') you will get a prompt. but don't confuse functions returning logical values with those that return numeric values.g. "EXECIO" queued() "DISKW DDNAME (FINIS)" What case should I program in.

This allows programmers to use prewritten modules.g.count. E. I often prefix variable names with '?' to stop variable substitution occurring if stemmed variables. such as logical.?YEAR = '1945' */ Bboolean = 1. E. and you may wish to supply a routine that is usable by other execs performing similar tasks. Here are some other points to consider: Some aspects of an exec may be relevant to other execs. . etc.g. Use long variable names and separate words with an underscore.) so that other developers may benefit from reduced development time. Table_name = 'MAILTAB' Underscores are a useful way of hiding variables from ISPF.2.depend largely on the programmers preferences and style of code writing. Exit external routines with RETURN rather than EXIT. This facilitates the copying of the routine into an exec for performance benefits. Use i. E. year = '1945' . if Bboolean then say 'hello' Fflag = 'A'. count = 2 .etc as loop control symbols.g. stem. numeric.j.?year = year /* STEM.g. flags. and to split large amounts of code up into manageable chunks. interfaces to data. etc. do i = 1 to 10 Prefix variable names with specific characters to show the type of data the variable contains. but here are some suggestions to consider.k. mail sending. Execs that do not hide symbols using the procedure command may suffer from reuse of loop control symbols. Consider creating external routines that supply a robust and generic service (e. However there is a performance overhead in doing this. if Fflag = 'A' then say 'hello' @address = STORAGE(something) #numeric = 10 + 12 See also the section on using non-alphanumeric characters Internal and external calls Rexx allows calls to be made to execs that reside outside of the currently executing exec. catalogue listing.

rather than searching through many stemmed vars.. 30% for string manipulation (using the string functions)..1). Use terse coding.8) Use a compiler.g. the resulting I/O will drop the exec performance.. For multiple calls to the same environment set the environment before entering into the multiple calls.. etc ) on a single very large string. do say 'Hello' end Embed function calls within each other rather than build up a variable over several lines of code.. E. address TSO "ALLOC FI(. avoid unnecessary commands. Address external environments directly using ADDRESS. . How can I improve performance of my exec? In general. and no real improvement when interfacing to external environments. Expect 100% improvement for number maniplulation (adding and whatnot). E.g. Using the string functions ( POS(). Consider: if symbol = 'FRED' then say 'Hello' Versus: if symbol = 'FRED' then . Then they won't have to be loaded and tokenised by the interpreter every time they are called.Userid()|| Random(999). LEFT().1. The inability to share variables across external procedures may lead you to choose to use internal procedures over external ones .) DA(. TSO/Rexx has some fast-path optimisation for code such as DO I = 1 to 1000.Don't use an external call to a routine that is called recursively. using an appropriate and well tuned algorythm/solution is better than using specific 'hacks'.) SHR" Internalise external routines that are called repeatedly. junk = Left(Overlay('A'. Use single letter vars for loop control. E.g.

myNumber . Use VLF.Performance test your code using the SYSVAR('SYSCPU') function and not the TIME() function. sign = TRANSLATE( (var<0) . Use a boolean check. like what is used when you TSO EXEC MYLIB(MYEXEC). hexChars . Supply well written external routines for non trivial tasks performed by user code. They can also speed things up.fgh. only the EXEC interface. 'abcdefghijklmnopqrstuvwxyz123456') Use functions such as DATE() to check if some data conforms to a type. junk = DATE(.testDate.opq.'S') /* Will give a syntax error is testDate is not a standard date */ The many variations of DO. parse value '1 2 3 6 4' with var1 var2 var3 var4 var5 . (Thanks to Doug Nadel) say TRANSLATE('ab.xyz' .ijk. How can my systems programmer improve performance. 'abcdefghijklmnopqrstuvwxyz') say TRANSLATE('abcdefgh ijklmnop qrstuvwx yz123456' . '01' ) boolvar = (test=true) Use the TRANSLATE() function to reorder or insert chars in a string. Use ON SYNTAX to trap the error. Read the Rexx Reference and Rexx Guide for inspiration. See IKJEXEC in Init and Tuning manual. as they can reduce the readability of the code. These tricks are not necessarily recommended. Use the environment tables in SAMPLIB if you have environments that are not part of the distribution tables.rst. What obscure coding tricks are there.cde. Use PARSE to initialise variables. This may deter users from writing inefficient code to perform the task themselves. '+-' . .uvw. particularly those tricks using PARSE. Note that VLF is not used for external procedure and function calls.lmn.

) non-alphameric characters (like ! # % ) in REXX variable names.. including object-oriented extensions.0 = 1 .2 x 1 1 stem. .1 = 'cheese' parse value with say say say say stem." .Use PARSE instead of SUBSTR(). =(colB) var2 +(lenB) .0+1 x stem. stem.lenA) var2 = SUBSTR(string.colC.. . */ */ */ */ . /* /* /* /* Using Non-Alphanumeric characters.colA.colB. stem.. the use of ..lenB) var3 = SUBSTR(string.0 ==> ==> ==> ==> '2' 'cheese' 'mice' '2' 'mice' stem... =(colC) var3 +(lenC) . with x80 2 x40 3 x20 4 x10 5 x08 6 x04 7 x02 8 x01 Use PARSE to increment a stem counter and assign a value to the new last stem (Attributed to Les Koehler @ IBM Tampa). is functionally equivalent to: var1 = SUBSTR(string.x . may use these characters.lenC) Use PARSE to split out bits from a string: parse value X2B(C2X('AA'x)) . Stephen Bacher writes on the subject of using non-alphanumeric characters: "I disagree strongly with (. Including them in variable names is asking for eventual breakage IMHO.0 stem. Extensions to REXX.1 stem. parse var string =(colA) var1 +(lenA) .

.RECFM=FBA) //* //SYSEXEC DD DISP=SHR.) is because these characters may have different display meanings in foreign EBCDIC chacacter sets.DSN=&PREFU. and will a casual reader know whether a symbol 'lstPointer' is referring to a 'list pointer' or a 'last pointer' See the Style Guide for a more detailed style discussion Appendices.CMD= //ISPF EXEC PGM=IKJEFT01. hash.DSN=&PREFU.SISPPENU //ISPMLIB DD DISP=SHR..SISPCLIB //ISPPLIB DD DISP=SHR..Another reason to avoid using the EBCDIC special characters (these include currency symbols.SISPSENU //ISPTLIB DD DISP=SHR.MSGS // DD DISP=SHR.DSN=&PREFS.DSN=&PREFS.DSN=&PREFS. at.EXEC // DD DISP=SHR. // PARM='ISPSTART CMD(&CMD)' //* //ISPPROF DD DISP=NEW. //ISPFPROC PROC PREFU='user.DSN=&PREFS.SPACE=(TRK.SISPMENU //ISPSLIB DD DISP=SHR.BLKSIZE=8000...DSN=&PREFU..SISPEXEC //SYSPROC DD DISP=SHR.(1.DSN=&PREFU.TABLES // DD DISP=SHR. etc. double quotes.UNIT=SYSSQ.DSN=&PREFS.DYNAMNBR=30. 'lst' and '1st' appear similar.1))..DSN=&PREFS..SKELS // DD DISP=SHR..TABLES . E. Are there any other style hints? • • • Leave space at the end of line for continuations and short 'date changed' comments.PREFS='SYS1'.DSN=&PREFU.SISPTENU //ISPTABL DD DISP=SHR..DSN=&PREFU.lib'. Code Examples This is a sample JCL procedure to run ISPF in batch. Avoid ambiguous or confusing abbreviations in symbol names and comments.g.1.PANELS // DD DISP=SHR... // DCB=(LRECL=80.

RECFM=FB) //ISPWRK2 DD DISP=NEW.BLKSIZE=2560.SPACE=(CYL.1)).(1.1)).exec.SPACE=(CYL.UNIT=SYSSQ.RECFM=FB) //* //SYSUDUMP DD DUMMY //SYSTSPRT DD SYSOUT=Q //SYSPRINT DD DUMMY //SYSTSIN DD DUMMY // PEND And run it thus: //TESTISPF EXEC ISPFPROC.BLKSIZE=129) //ISPLIST DD DUMMY.UNIT=SYSSQ.RECFM=FB) //ISPWRK1 DD DISP=NEW.BLKSIZE=129) //ISPLST1 DD DISP=NEW. // DCB=(LRECL=256.LRECL=125.BLKSIZE=800.(1.BLKSIZE=1210. // PREFU='ISP' //* or alternativly.1)).//ISPLOG DD DUMMY.(1.ISPF='ISPSTART CMD(%REXXPROG TESTPARM)'. //TESTISPF EXEC ISPFPROC.PARM='%execname' DD DISP=SHR.(1.UNIT=SYSSQ.UNIT=SYSSQ.SPACE=(CYL.library DD SYSOUT=* DD SYSOUT=* or TSO in batch: . // DCB=(LRECL=256.SPACE=(CYL.SPACE=(CYL. // DCB=(LRECL=121.SPACE=(CYL.BLKSIZE=1210.DCB=(RECFM=VA.DCB=(RECFM=VA.1)).RECFM=FB) //ISPCTL2 DD DISP=NEW.BLKSIZE=800.(1. try using IRXJCL: //IRXJCL1 //SYSEXEC //SYSPRINT //SYSTSPRT EXEC PGM=IRXJCL.RECFM=FBA) //ISPLST2 DD DISP=NEW.(1.UNIT=SYSSQ. // DCB=(LRECL=80. // DCB=(LRECL=121.DSN=your.UNIT=SYSSQ. // DCB=(LRECL=80.RECFM=FBA) //ISPCTL1 DD DISP=NEW. // PARM. // CMD='%TESTPROG TESTPARM' // PREFU='ISP' If ISPF is not needed.1)).1)).BLKSIZE=2560.LRECL=125.

address ISPEXEC "LIBDEF ISPPLIB DATASET ID('user.//IRXTSO EXEC PGM=IKJEFT01 //* You could use PARM='%execname testparms' on exec statement //SYSEXEC DD DISP=SHR.DSN=your. and then unstack the LIBDEFs.marist. search the IBM S390 Websiteto find them online in PDF and HTML formats. names).library //SYSTSPRT DD SYSOUT = * //SYSTSIN DD * %execname testparms /* //* You could run more than one exec sequentially from SYSTSIN //* You can also run straight TSO commands like TSO PROF PREF(FRED) This Exec shows how to temporarily LIBDEF ISPF datasets to your session. Try searching Amazon. call an ISPF application (under a new application Id to avoid name collisions with other ISPF profile var. Marist College hosts the ListServ Archives at http://www.EXEC')" address ISPEXEC "SELECT CMD(%yourexec "your exec options") NEWAPPL(yourappl) PASSLIB" address ISPEXEC "LIBDEF ISPTLIB" address ISPEXEC "LIBDEF ISPMLIB" address ISPEXEC "LIBDEF ISPPLIB" address TSO "ALTLIB DEACTIVATE APPLICATION(EXEC)" Other Sources of Information.PANELS') STACK" address ISPEXEC "LIBDEF ISPMLIB DATASET ID('user.MSGS') STACK" address ISPEXEC "LIBDEF ISPTLIB DATASET ID('user. ALTLIB an Exec library to your session.exec.TABLES') STACK" address TSO "ALTLIB ACTIVATE APPLICATION(EXEC) DATASET('user. .edu/htbin/wlvindex?tso-rexx Yahoo! has a Rexx category that lists several Rexx information sites. and deactivate the alternative Exec library. Rexx Book list. Rexx manuals.

Last-modified: 01 Sept 2000Version: Up to the computing page.nd. Rexx newsgroup comp. . See MVS/Using datasets. A label within an exec. An SGML markup language used to define ISPF panels.rexx can be found via Google ISPF has its own active listserv at ISPF-L@listserv.CbtTape. e. A standard Rexx function.edu. A TSO environment variable. either hidden (with PROCEDURE without EXPOSE). Send message text 'SUBSCRIBE ISPF-L Your Name' to LISTSERV@listserv.lang. High Level Qualifier. Profile prefix.g. e. An external Rexx function. DTL Dialog Tag Language. The first qualifier in a fully qualified dataset name.g. SUBSTR().nd.g. scroll to the bottom of the page. Built-in Function. e. SYSVAR(). or exposed. either supplied with TSO/E. or supplied in a PDS in Rexx source or Load Module form. and follow the instructions there. including a list of Listserv lists.org has many useful utilities. and a generation number referring to the generation required. Glossary Generation Data Group. External Function. A set of datasets referred to by their GDG base. DTL documents are converted into panels using the ISPDTLC compile utility. The users default HLQ.edu and await further instructions. Subscribing to the TSO-REXX List Go to the TSO-Rexx list archive. Internal Label. RXGDGV() in appendix C. prefixed to unqualified datasets to make a qulified DSN HLQ.

Using Comments. primarily aimed at Rexx in the OS/390 environment.Send Feedback. winged and boxed: /* This is a winged comment */ /**************************************\ * * This is a boxed comment * * \**************************************/ Boxed comments should be reserved to highlight major structural elements. such as the start of procedures. but useful comments cannot be conjured out of thin air. 1. Many of the points here have been raised at some time on the TSO-REXX listserv mailing list. Winged comments are useful for describing the purpose of the statement(s) immediatly adjacent to the comment. See the Calculate_Factorial() example. and to variants of Rexx such as NetRexx. This is a style guide for the Rexx programming language.3cAuthor: Neil Hancock Style Guide for Rexx Introduction. Correctly commenting code is one of the most useful things you can do when writing code. Comments come in two flavours. but application to Rexx on other platforms. Most style problems can be repaired with a formatter. .

and to handle change history information.> ---------------------------------------------. */ may be read by a suitable program. as realigning the border after text insertion is a tedious affair... so they are visible when the exec is opened. Here is an example: /* Rexx ----------------------------------------AUTOTOOL <A one line description for use by an indexing tool> ------------------------------------------------------Copyright: <You may want a copyright notice> Change History: <yy/mmm/dd Userid VersId Description> Description: <A long description of the purpose of the exec. put the most recent changes at the top.MEMNAME */ It is extremely useful to have a tool to handle the creation of a standard header. etc. . Also. An indexing tool that reads the short description and change history is also useful. A common use of boxed comments is for an informative header at the start of the exec. It may also be useful to have a version id to mark changed code in small comments later on. Consider using minus (-) or another lighter character instead. examples of call syntax. so make sure the header format supplies information that would be useful to an indexing tool. returned values. The use of asterisks (*) as the box border can make the comment too heavy. don't worry about closing the right hand vertical. You may have a Rexx reformatter that deals with this problem. Note the marker in the top right of the box that may be used by a tool to spot whether this is a standard header or not. Comments enclosed by /** . and used to automate the creation of external documentation for the program. Include invocation arguments.It may also be worth borrowing from the Javadoc idea. and the text within associated with the immediately following Rexx statement. In the change history.

Things to avoid when creating comments: • • • Stating the obvious. and tails refer to the whole and various parts of compound variables.It may not be worth putting some types of information in the header. E.i and score. stems..'. In Perform_Update_Function(). but would it be obvious from score. a loop index. The Rexx ANSI standard talks of Rexx 'symbols'. etc. 'variable name' and 'variable value'. Some programmers use a form of Hungarian Notation to show when a variable is boolean.teamIndex. It is obvious that i is the record number.g. and has other dissadvantages. the words 'perform' and 'function' tell us nothing useful.g. Using Symbols and Variables.g. E. Consider using i. numeric. Single character variable names show a performance improvment (My simple test measured nearly 10% improvement). string = TRANSLATE(STRIP(string)) /* Strip and uppercase string */ Using 'content free' phrases such as 'We call this Rexx program to get a returned value to the caller consisting of. E.. E. particularly data that ages poorly.j that i is the team and j is the event? . etc as loop control variables. Here I shall use the more familiar terms 'variable'. You have to rely on the stem name to indicate the meaning of the data in the compound variable. This may make your variable names not so easy to read. Always make your variable names useful and meaningful. j. try Update_Table() instead. k.eventIndex . /* prt opt pg len */ instead of /* print option .. Using acronyms and abbreviations to the point of crypticness.g. Compound variables names are shorter and less likely to make long statements cross onto multiple lines. Dataset names and pointers to external information are particularly prone to becoming incorrect. Consider compound var names record. Compound variables.page length */. This also applies to function names. There are advantages and disadvantages to this: Faster execution speed.i.

' /* set a list of stems that are global variables */ gl.j and k as loop control variables throughout your program without any side effects.i) end exit /* -------------------------------------Return the multiple (factorial) of all numbers between arg1 and arg2.endNum factorial = 1 do i = startNum to endNum factorial = factorial * i end return factorial This common problem occurs when a variable is assigned a value.testVar /* ==> This is a sample global variable. and allows the use of i. -------------------------------------. and its contents: An_Internal_Function: procedure expose (global) say gl. This hides the procedure's internal variables from the caller. at each procedure start. and the variable is then used in a compound variable: stem. */ return 0 Do use the procedure keyword with every defined procedure.Global variables can be handled in the following way: First.salutation = 'HELLO!' /* literally . expose this global.testVar = 'This is a sample global variable.*/ Calculate_Factorial: procedure parse arg startNum. in the opening section of your Exec. set a variable named global whose contents are the stem names of your global variables: global = 'gl.' Then. as in this example: do i = 5 to 10 say 'Number:'i 'Factorial:'Calculate_Factorial(2.

You could use non-alphanumeric characters such as ! or ? to prefix the variable name when its used in the compund tail. Large blocks of variable assignations can be split into columns.Bdebug on/off */ gl. such as Object-Oriented Rexx.salutation /* ==> STEM.!pageLength page length */ gl.stem. testVar = 'HELLO' stem.0testVar = testVar stem. .GOODBYE */ exit If you don't want this effect.salutation /* ==> HELLO! */ /* Set the tail of the compound variable to have a value */ salutation = 'GOODBYE' /* Now show an often unintended result */ say stem. The ISPF editor picks special characters (such as !) up in HILTE mode. by definition. you must use unassigned variable names in the compound variable.!testVar = testVar Numeric prefixes are better for code portability. what indentation is appropriate. or use a numeric prefix. as symbols starting with numerics are. and how we could break blocks of statements up. and are not portable to some Rexx extentions. constants. variable values.!pageWidth page width */ = 0 = 60 = 50 /* Turns debugging /* print option /* print option - Case. and winged comments: gl.SALUTATION = 'HELLO!' */ /* Output the intended result */ say stem. with variable names. Non-alphanumeric characters may not be portable to foreign EBCDIC character sets. Indentation and Block Structure. Here we discuss the case we could use for syntactic elements.

RETURN. Literal text.END and label: PROCEDURE . SELECT . including yourself. Variable names such as USERNAME. Internal functions such as MYINTERNALFUNCTION(). D2B(). We are trying to increase the readability of the code.END. Don't assume any knowledge of the inner workings of your code. We can improve readability by using techniques to differentiate and highlight elements within a statement. or USERCARDNUMBER. and TRANSLATE(). and lay out the code so that these relationships and statement elements are visible to the reader.END and WHEN cond THEN DO . The target audience should be anyone likely to need to change your code in the future. Other techniques to improve readability are:. and how do we go about achieving our aim. User supplied external functions such as MYFUNC(). it may be some years before you revisit it. Commands to external environments such as ADDRESS TSO "LISTCAT" Comments. Natural Blocks of statements that together perform a particular function. A reasonable knowledge of Rexx may be assumed. Implementation supplied builtin external functions such as MVSVAR() and LISTDSI().END. What are we trying to achieve. lower and Mixed case. Contitional Blocks such as IF cond THEN DO . Major Blocks such as DO count . show relationships between statements. Builtin function names such as POS(). Here are some elements that go to make up statements: • • • • • • • • • • • • Keywords such as IF. SELECT and CALL. even though the reader may be new to the language.But first. Here are some techniques to improve readability using case: • • • UPPER. Concatenated words with case differentiation such as ConcatenatedWords. . Everyone has to learn something sometime. Underscore separated words such as underscore_separated_words.

Keywords appear in isolation in the text. so they stand out without any help from the programmer. By using upper case for external function names. but are restricted by the fixed terminal size of 3270 systems. and all comments blue. must use upper case in the file names of external functions. Screen size influences how much code can be on the screen at one time. Aligning the start of a block with its end. Using boxed comments before major structural items. and also tend to appear at the start of statements.REXX. MYFUNC() may refer to PDS 'user. Using too many blank lines or splitting statements over multiple lines can move code out of the viewable area. can for instance turn all keywords red. when the editor can pick them out with colour. Constraints and Influences on Style Guide Rules There are some facts about the programming environment that influence what techniques may be most effective. A Rexx aware editor such as ISPF EDIT with the HILITE utility. or member names in partitioned datasets. There's no point in using upper case to highlight keywords. External function names are related to file names in a file system.• • • • • Indenting blocks or statements within blocks. you avoid having to quote function names to maintain lower case in the file name. You then. and by surrounding blocks of statements that perform a task with white space. Techniques that disperse statements over several lines work well on window based systems that allow the viewable area to be adjusted. The same is true for boxed comments. quoted strings and other elements. depending on your Rexx environment. Some editors are Rexx aware and can hilite Rexx code to show keywords.EXEC(MYFUNC)' or file name MYFUNC. We can do this by using procedures. Inserting blank lines between blocks. Splitting statements across more than one line. We are also concerned with breaking up the code into manageable and reusable units. . of course.

It tries to keep the code dense for 3270 displays. and most style rules should apply to it. An Example Set of Style Rules. external.g. myName counter fishType Internal function names with the initial letters of individual words in upper case. E. This differentiates them from function names. quoted text.DATASET') SHR REUSE". and relies heavily on a highlighting editor to differentiate between keywords. Rules specifically related to case: • • • Keywords in lower case. E. variable names. Commands being passed to external environments often have single quotes in them.. and other statement elements. We need to be able to differentiate variable names from function names.g. Optionally. Having said that NetRexx is a case insensitive language. For example: datasetName = STRIP(TRANSLATE(GetDsn(ddName)). NetRexx (and presumably other close relatives of Rexx) are sufficiently different from Rexx to make consideration of styles that apply to NetRexx irrelevant. you can also use underscore separators E.."'") or datasetName = STRIP(TRANSLATE(Get_Dataset_Name(ddName))."'") Literals should be quoted. unless you can be sure that the literal hasn't been used as a symbol elsewhere. builtin. which will all start with an upper case character. internal. and also differentiate between the various flavours of function. MyFunction() MyOtherFunction() Your_Function() . select do if end Variable names starting in lower case with the initial letters of concatenated words in upper case. etc.g. address TSO "ALLOC FI(TEST) DA('MY. E.Function and variable names tend to appear close together in code. Here is programming style that meets the above criteria in varying degrees.g. Let the editor highlight them.

Use a comment in the style of javaDoc before each procedure. myVar = 'test'. Use commas and not spaces to delimit your arguments. address TSO "ALLOC FI("ddName") SHR REUSE DA("dsName")" Rules for quoting: • • • Enclose commands to external environments in double quotes. MYFUNC() EXTFUNC() Builtin functions in upper case. address SH "cat myfile" Commands for external environments preferably in upper case.• • • • External function names in upper case. so that possible future 'rexxDoc' implementations will be able to pick up your comments.g.g. coming out of quotes to pass variables into the command. E. Rules for comments: • Use a standard machine readable header to document a synopsis of the exec. Create a tool to manage and extract useful information from these headers. E. change information.g.g. address TSO "X". Note that address treats the environment name as a constant. to avoid collisions between variable names in different procedures. See the Calculate_Factorial demo for an example. Never use myVar = test Use variables for quotes if building strings containing both single and double quotes to avoid the opening and closing becoming confusing: E. E. address TSO "ALLOC FI("ddName") SHR REUSE DA("dsName")" Always quote literal strings. E. Never rely on the string not being used as a variable name. E. SUBSTR() D2B() MVSVAR() External environment names in upper case.g. as the highlighting editor will mark them in a different colour to user supplied functions anyway. and does not perform symbolic substitution.g.g. myVar = dq||sq||'test'||sq||dq rather than myVar = '"'"'test'"'"' Rules for procedures: • • • Use the procedure keyword wherever possible. and any other useful information. This saves having to quote them. address ISPEXEC "FTCLOSE". This rule is pretty arbitrary. See the LZ78 demo for an example. E. unless the environment is case sensitive. . E. My_Function: procedure expose (global).g.

Use a boxed comment to mark where procedures begin. See the example in an earlier chapter.g. Style Example Here's an example program. with two similar internal functions present. Leaping from one style to another mid-procedure can hinder a readers understanding of the program. do loops.g. An aside on following a ruleset: One important comment that must be made. select blocks. Other miscellaneous rules: • • Use i. k. end /* select */. Comment what end statements are ending. Note how the uncompress function is easier to read when no colour highlighting is used. and the compress function becomes easier to read. but it is important that a set of rules is followed consistently in a piece of work. etc. E. E. is that it is not so important that one set of rules is followed in all cases. j.. Aim your comments at a reasonably competent programmer who is not familiar with your exec. Copy the program into a Rexx sensitive editor. as loop control variables. and other similar structures with between 1 and 3 spaces. Indicate what variables are to be used for when they are first assigned. See the LZ78 demo for an example. Indent do.• • • • • Comment logical groups of statements. select. The uncompress function follows a second consistent set of guidelines. and helps keep statements short. /* REXX --------------------------------------------------------SYNOPSIS : LZ78 compressor/decompressor demo VERSION : 1. The compress function follows the above example set of guidelines.0 CREATED : April 1999 NOTES : From the uberFish Rexx Style Guide. This can make your code run faster. -------------------------------------------------------- . in two slightly different styles. indicating what they do.

....' inString = 'If_I_were_a_Linesman....' say inString compString = Compress_LZ78(inString) say 'Compressed as.......Oogachacka.' say 'Compressing 'LENGTH(inString)' byte string ..' say compString decompString = Uncompress_LZ78(compString) say 'Decompressed as...' say decompString exit 0 /** ======================================================== ======== ...' inString = inString||inString||inString||inString inString = inString||inString||inString||inString say 'Compressing 'LENGTH(inString)' byte string ...Oogachacka._' ....------..' say compString decompString = Uncompress_LZ78(compString) say 'Decompressed as.' inString = 'Oogachacka.*/ /* Demo normal text compress/decompress */ say 'Normal text demo.' say decompString /* Demo Highly redundant text compress/decompress */ say say 'Highly redundant demo.' say inString compString = Compress_LZ78(inString) say 'Compressed as. || 'I_would_execute_the_players_who_applauded_my_offsides.

In reality.d) > 0 then do if outCode = '' then outString = LEFT(outString. Blank delimited 'words' Last used phrase Our current dictionary reference for /* For every char in the input string. etc */ output string Dictionary. ---------------------------------------------------------------. cos I use WORDPOS() to search the dictionary.g. queue up this dictionary reference to go into the output string */ if WORDPOS(thisPhrase. the output would be formatted to take up less space then the original. or a dictionary reference */ do i = 1 to LENGTH(inString) /* Get next input char.LENGTH(outString)-1) . E.*/ Compress_LZ78: procedure parse arg inString /* Initialise the outString = '' /* */ d = '' /* */ w = '' /* */ outCode = '' /* this phrase */ dictionary. or something. Oh. output string. output the char.1) thisPhrase = w||thisChar /* If the new phrase is in the dictionary.Demo LZ78 compressor. and it doesnt like spaces.i. in 9bit bytes. with the high order bit set on when the char is a dictionary reference. and make phrase */ thisChar = SUBSTR(inString.

d)'>' w = thisPhrase end /* If the new phrase wasnt in the dictionary.outCode = '<'WORDPOS(thisPhrase.1) /* If the char is a code.*/ Uncompress_LZ78: procedure parse arg inString /* Initialise stuff */ outString = '' d = '' w = '' /* Loop across each char in input string. Here Ive switched to another style for comparison. ---------------------------------------------------------------.i. building dictionary and output string as we go */ Do i = 1 To Length(inString) /* Get next char from input string */ thisChar = Substr(inString. . output it */ else do outString = outString||outCode||thisChar outCode = '' d = d thisPhrase w = thisChar end end /* return the compressed string */ return outString||outCode /** ======================================================== ========= Demo LZ78 uncompressor. then look up code in dictionary.

In ISPF it should be wrapped in whatever way is consistent with your treatment if IF THEN DO constructs: if outCode = '' then outString = LEFT(outString.inString.1) w = thisOut i = i + Length(thisCode) +1 outString = outString || thisOut End /* Else add phrase to dictionary and output the character */ Else Do d = d || ' ' || w || thisChar w = thisChar outString = outString || thisChar End End /* Return the uncompressed string */ Return outString Spot the line that is longer than 80 characters. You have to make people want to follow your guidelines. .thisCode) d = d || ' ' || w || Left(thisOut.i+1. There's little point in setting guidelines for writing programs if they're going to be ignored.Pos('>'.add new phrase to dictionary. Automate the process by supplying easy to use tools to manage internal documentation and format code.i)-i-1) thisOut = Word(d. Here are some ways of encouraging the use of programming standards: • • • Allow individuals to follow the guidelines as they see fit.LENGTH(outString)-1) Enforcing Programming Standards. Use management control. add phrase to output */ If thisChar = '<' Then Do thisCode = Substr(inString.

'eggs') say Status_Char(userStatus. Unexpected spaces can creep in when ommitting concatenation operators. It does allow creative and expert programmers the freedom to use systems they are comfortable and productive with. A tools led approach can be combined with other approaches. a handful of ISPF EDIT macros to perform various formatting tasks will suffice. Component elements of the string will be explicit to the reader. There are two schools of thought on whether to explicitly use the string concatenation operator ( || ) or not. Management control is particularly suited to organizations that have a Quality Assurance program. Points for ommiting the operator whenever convenient: . Generally. Points for the use of the concatenation operator: • • • Programmers supporting your code often do not use Rexx regularly.'eggs') say Status_Char(userStatus. Concatenating Strings. and some good reasons not to.' newString = oldString 'Some Text' MYFUNC('ham'. ||userName || ' is ' || userStatus say 'Omission of operators. There is some development effort to get tools into place.Relying on individuals can fail if lazy or naive programmers fail to follow guidelines. and the tools must be flexible and fit for their purpose. say 'Explicit use of operators' newString = oldString || ' Some Text ' || MYFUNC('ham'.'TEXT') || ': ' .'TEXT')':' userName 'is' userStatus There are some good reasons to use concatenation operators.

there is often little use in storing ISPF panel names in variables when address ISPEXEC "DISPLAY PANEL(MYPANEL)" pinpoints exactly where in your exec that panel MYPANEL is actually used. For instance. E. Otherwise you may have to create a new interface for your old shell if new LISTCAT data is needed. Adding new functionality to old code creates backwards compatibility problems. but its another thing entirely to place assignation statements in obscure parts of the exec.• • • • Less is more. var1 || ' ' || var2 versus var1 var2 Some Other Dos and Don'ts Don't use too many levels of indirection. The resulting code is tidier. Do end all internal procedures with an unconditional RETURN. so make sure that you comment what is going on if you do have to create a complicated structure. Your shell program should be able to control all arguments for LISTCAT. For instance. and return any information returned by LISTCAT to the caller. far away from where they will actually be used. This makes it clear to the reader when a procedure ends and may help code formatting tools to spot the end of internal procedures. Don't hide information in variables set far away from where they are used. Send Feedback Please drop me a line. and maintenance problems as the code becomes 'hairy' from unnecessary revisions. Do make sure abstracted procedures allow full access to the underlying data. and tell me about any improvements you think could be made to this page. Its one thing to have a nice block of commented assignations near the top of an exec or procedure. . There is less chance of the statement overrunning onto the next line. say you put a nice shell exec around TSO LISTCAT. Having functions call functions that call functions can equally make debugging an exec very tiresome indeed.g. The Hilite function of the editor makes the component elements clear enough anyway. You don't have to explicitly include spaces inserted between the strings.

• • • Was the information useful? Was the information complete and concise? Did you understand the information? .

Sign up to vote on this title
UsefulNot useful