IBM z/OS ISPF Smart Practices: Volume 2 ISPF Programmer’s Guide 9783110407617, 9783110407532

This book is intended to support ISPF application programmers to become professional in the smart programming of ISPF ap

209 26 1MB

English Pages 320 [322] Year 2015

Report DMCA / Copyright

DOWNLOAD PDF FILE

Table of contents :
Preface
Contents
1. Introduction
2. Introduction to the REXX programming language
3. The REXX commands
4. The REXX functions
5. The TSO/E REXX commands
6. Execute REXX programs
7. Introduction to ISPF programming
8. Data set processing using ISPF
9. Messages – Definition, setting, output
10. Panels – create and use
11. Skeletons – Design and use
12. Tables – Create and edit
13. Variables – Definition and using
14. Edit macros – Create and apply
15. The SMART ISPF utilities
List of programs
List of tables
List of screens
Bibliography
Index
Recommend Papers

IBM z/OS ISPF Smart Practices: Volume 2 ISPF Programmer’s Guide
 9783110407617, 9783110407532

  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
File loading please wait...
Citation preview

Franz Lanz IBM z/OS ISPF Smart Practices

Also of Interest IBM z/OS ISPF Smart Practices, Vol. 1 Franz Lanz, 2015 ISBN 978-3-11-037548-0, e-ISBN (PDF) 978-3-11-037559-6, e-ISBN (EPUB) 978-3-11-039788-8, Set-ISBN 978-3-11-037560-2

Industrial Software Applications Rainer Geisler, 2015 ISBN 978-3-11-037098-0, e-ISBN (PDF) 978-3-11-037099-7, e-ISBN (EPUB) 978-3-11-039678-2

Entrepreneurship for Engineers Helmut Kohlert, Dawud Fadai, Hans-Ulrich Sachs, 2013 ISBN 978-3-486-73298-6, e-ISBN (PDF) 978-3-486-76972-2

Analog Computing Bernd Ullman, 2013 ISBN 978-3-486-72897-2, e-ISBN 978-3-486-75518-3

Franz Lanz

IBM z/OS ISPF Smart Practices

Volume 2: Programmer’s Guide

Author Franz Lanz Panoramaweg 27 72658 Bempflingen Germany [email protected]

ISBN 978-3-11-040753-2 e-ISBN (PDF) 978-3-11-040761-7 e-ISBN (EPUB) 978-3-11-040765-5 Set-ISBN 978-3-11-040762-4 Library of Congress Cataloging-in-Publication Data A CIP catalog record for this book has been applied for at the Library of Congress. Bibliografische Information der Deutschen Nationalbibliothek The Deutsche Nationalbibliothek lists this publication in the Deutsche Nationalbibliografie; detailed bibliographic data are available on the Internet at http://dnb.dnb.de. © 2015 Walter de Gruyter GmbH, Berlin/Boston Cover illustration: OlgaYakovenko/iStock/thinkstok Typesetting: PTP-Berlin Protago-TEX-Production GmbH, Berlin Printing and binding: CPI books GmbH, Leck ♾ Printed on acid-free paper Printed in Germany www.degruyter.com

Preface Since approximately 1980, I worked many times with the Interactive System Productivity Facility (ISPF) (a subsystem of z/OS driven by TSO) during my activities as external advisor, programmer and lecturer in the IBM host. As the name already says, this subsystem is designed to help the users in the IBM Mainframe host environment to a higher productivity at their work in IBM z/OS. I can promise you, ISPF fulfils this task very well. As soon as I was more familiar with ISPF and so had outgrown to the beginners stage, the desire emerged in me to automate and accelerate some recurring operational sequences if possible. I have looked around myself on the book market which book can support me with the realization of the desire on a high level. However, I found no book, which would be suitable. Since I developed at home and abroad a set of procedures and programs during my lecturer, adviser and programming activities in different enterprises, which brought me often a substantial accelerations of my work in z/OS, I decided to publish my experiences in developing ISPF applications as well as the developed programs in this book. This program collection is SMART ISPF UTILITIES called. The procedures and programs described in this book can be from internet downloaded. This book will support you to reach your full potential in using ISPF as an application programmer, a system programmer or another z/OS-ISPF user. You will learn how you use the ISPF programming facilities to develop professional ISPF application programs. Additionally you can enhance your programming skills by referencing the programs of SMART ISPF UTILITIES available on internet, in order to become a skillful ISPF application programmer.

Bempflingen, Mars 2015

Franz Lanz

Contents Preface | V 1 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 1.3.4

Introduction | 1 Users of this book | 1 The significance of the REXX programming language in z/OS | 1 Brochures for programming ISPF applications | 1 The REXX programming literature | 2 ISPF reference books | 3 TSO reference books | 5 The ISPF services | 5

2 2.1 2.2 2.2.1 2.2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 2.9.3

Introduction to the REXX programming language | 7 What is REXX? | 7 Overview of REXX under TSO | 8 Recognizing a REXX procedure by the TSO | 8 Running REXX procedures in the TSO | 9 Compile REXX procedures | 11 Performance of REXX procedures | 11 The syntax of the REXX language | 12 Variables in REXX | 14 Data types of REXX variables | 15 Operators of the REXX language | 15 String operators | 16 Arithmetic Operators | 16 Compare operators | 17 Logical operators | 19 Stems in REXX | 19 Initialize stems with null string | 21 File processing in connection with stems | 22 Multi-unit Stems | 22

3 3.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.2

The REXX commands | 25 ADDRESS – Connection to the subsystems | 25 The host command environments | 25 The active host command environment | 27 The temporary addressing of external commands | 27 Special case ISPEXEC and ISREDIT | 29 The main host command environments | 30 ARG – Retrieve the parameter string | 31

VIII | Contents

3.3 3.4 3.4.1 3.4.2 3.5 3.6 3.7 3.8 3.9 3.9.1 3.9.2 3.9.3 3.9.4 3.10 3.10.1 3.10.2 3.11 3.11.1 3.11.2 3.12 3.13 3.14 3.15 3.16 3.17 4 4.1 4.1.1 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.2 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5

CALL – Call other programs | 35 DO groups and DO loops | 36 The DO group | 36 The DO loop | 37 EXIT and RETURN – leaving the REXX procedure | 39 IF and WHEN – check conditions | 41 INTERPRET – generate REXX commands dynamically | 42 NUMERIC – set computing options | 44 PARSE – text fragmentation | 46 PARSE ARG | 48 PARSE VALUE ….. WITH | 48 PARSE VAR | 51 PARSE SOURCE | 51 PROCEDURE – Option for internal subroutines | 52 Internal subroutines with PROCEDURE statement | 52 Internal subroutines without PROCEDURE statement | 53 QUEUE – Working with the TSO stack | 53 The TSO/E data stack | 53 Use options for the TSO/E Data Stack | 54 SAY – Print texts | 57 SELECT – Conditionally call alternative instructions | 57 NOP – No operation | 60 PULL – Enter data on the screen | 60 TRACE – The strong debugging aid | 61 SIGNAL – Jumping when errors | 62 The REXX functions | 63 General functions | 64 ADDRESS – Get the active host command environment | 64 ARG – Input parameter test or take | 65 DATE – Date functions | 65 TIME – Time functions | 68 QEUED – Number of records in the data stack | 69 SOURCELINE – Return a program line | 69 USERID – Return the TSO user ID | 70 VALUE – Create variable names dynamically | 70 Arithmetic functions | 72 ABS – absolute value of a number | 72 DIGITS, FORM, FUZZ – Query options for arithmetic operations | 72 MIN, MAX – Minimum and maximum value | 73 RANDOM – Generate random numbers | 73 SIGN – Return of the sign | 74

Contents | IX

4.3 4.3.1 4.3.2 4.4 4.4.1 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.5 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.5.6 4.6 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.6.6 4.6.7 4.6.8 4.6.9 4.6.10 4.7 4.7.1 4.7.2 4.7.3 4.7.4 4.7.5 4.8 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5

Comparison Functions | 74 COMPARE – Compare texts | 74 DATATYPE – Determine data type | 75 Conversion functions | 77 C2D – Character to decimal | 77 C2X – Character to Hexadecimal | 79 D2C – Decimal to Character | 79 D2X – Decimal to Hexadecimal | 80 X2B – Hexadecimal to Binary | 80 X2C – Hexadecimal to Character | 81 X2D – Hexadecimal to Decimal | 81 Formatting functions | 82 CENTER – Centering a string | 82 COPIES – Reproduce texts | 83 FORMAT – Format numbers | 83 JUSTIFY – Formatting a string | 83 LEFT – Rearrange text left-justified | 84 RIGHT – Arrange text right- justified | 84 String functions | 85 DELSTR – Delete substrings | 85 INSERT – Insert text | 85 SCHANGE – Change of texts | 86 LENGTH – Length of a text | 86 OVERLAY – Superimpose text | 87 POS – Search for text | 87 STRIP – remove border characters | 87 SUBSTR – Extract part of a text | 88 TRANSLATE – translate characters | 89 VERIFY – verify text | 90 Word functions | 90 WORD – return of a word | 90 WORDINDEX – return the starting position of a word | 91 WORDLENGTH – return the length of a word | 91 WORDPOS – search for a word | 91 WORDS – number of words in a string | 92 System functions | 92 LISTDSI – List data set information | 93 MSG – control of the TSO messages | 93 MVSVAR – Return z/OS system information | 94 OUTTRAP – take TSO messages | 94 SYSDSN – check data set status | 96

X | Contents

4.8.6 4.8.7

SYSVAR – get system Information | 96 STORAGE – read and write memory contents | 98

5 5.1 5.2 5.3 5.4

The TSO/E REXX commands | 101 EXECIO – Read and write data sets | 101 DELSTACK – delete data stack contents | 103 DROPBUF – Delete data stack buffers | 103 TSO Commands | 103

6 6.1 6.1.1 6.1.2

Execute REXX programs | 105 Execution of programs in a TSO/ISPF environment | 105 Online execution | 106 Batch execution | 107

7 7.1 7.2 7.3 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.4 7.5 7.5.1 7.5.2 7.5.3 7.5.4

Introduction to ISPF programming | 109 Programming languages useable in ISPF | 109 ISPF programming objects | 109 Some typical examples | 111 Example for use of ISPF panels | 111 Example for use of skeletons | 113 Example for use of tables | 115 Example for use of ISPF variables | 116 Example for data processing with TSO and ISPF | 118 Output of messages with ISPF | 121 LIBDEF – Dynamic linking of ISPF libraries | 123 ALTLIB – Dynamic linking of EXEC libraries | 126 Search sequence in the procedures libraries | 126 The ALTLIB command in ISPF | 128 Stacking of the APPLICATION level ALTLIBs | 129 The QUIET operand of the ALTLIB DISPLAY command | 130

8 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.1.5 8.1.6 8.1.7 8.1.8

Data set processing using ISPF | 133 The LM services | 133 Grouping of LM services | 133 LMINIT – Start of the data set processing | 136 LMFREE – Free a data set | 137 LMOPEN – Open a data set for processing | 137 LMCLOSE – Close a data set | 138 LMMFIND – Localize a member | 139 LMMREP – Replace a member | 140 LMMADD – Add a member | 141

Contents | XI

8.1.9 8.1.10 8.1.11 8.1.12 8.1.13 8.1.14 8.1.15 8.1.16 8.1.17 8.1.18 8.1.19 8.1.20 8.1.21 8.1.22 8.1.23 8.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 9 9.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.1.7

LMGET – Read a data records | 142 LMPUT – Output data records | 143 LMCOPY – Copy data | 145 LMMOVE – Move data | 146 LMMDEL – Delete members | 146 LMMREN – Rename members | 147 LMMSTATS – Display or change member statistics | 147 LMCOMP – Compress a PDS | 150 LMMLIST – Display a member list | 150 LMMDISP – Display and edit a member list | 153 LMDINIT – Initialize the LMDDISP service | 155 LMDDISP – Data set list service | 155 LMDLIST – List of data sets | 157 LMDFREE – Free a LISTID | 158 MEMLIST – member list dialog service | 158 Data set query services | 160 LMDLIST – Data set list service | 161 DSINFO – ISPF service which provides data set information | 162 LISTDSI – REXX function to list data set information | 164 QBASELIB – Query DSN information | 169 QLIBDEF – Query LIBDEF Information | 171 QUERYENQ – ENQs determination | 173 Messages – Definition, setting, output | 177 Error handling in ISPF | 177 Returning error messages | 178 Output of error messages | 178 SETMSG – Set next message | 180 Definition of ISPF messages | 180 Naming convention of the ISPF message IDs | 181 Definition of messages | 181 The standard message member ISRZ00 | 184

10 Panels – create and use | 189 10.1 The Dynamic Tag Language (DTL) | 189 10.2 Panel types in ISPF | 190 10.3 Definition of panels | 190 10.3.1 The structure of a panel | 191 10.3.2 Creation of panels and their call | 192 10.3.3 The panel definition sections | 192 10.3.4 Variables in panel definitions | 201

XII | Contents

10.3.5 10.3.6 10.3.7

Panel processing | 202 Help panels | 204 Panels to display ISPF tables | 205

11 11.1 11.2

Skeletons – Design and use | 211 Creating skeletons | 211 Steps to use the file-tailoring service | 214

12 12.1 12.2 12.3 12.4 12.5

Tables – Create and edit | 215 Locations for tables | 215 Reading ISPF tables | 215 Writing ISPF tables | 215 Commands of the table services | 216 Example of working with tables | 218

13 13.1 13.1.1 13.1.2 13.1.3 13.2 13.3 13.4 13.5 13.5.1 13.5.2

Variables – Definition and using | 223 Variables pools | 223 Function pool | 223 Shared pool | 224 Profile pool | 224 Saving the profile members | 225 Creating profile members | 225 Display of actually used profile member | 226 The System Profile Pool | 227 Frequently used ISPF variables | 228 Process ISPF variables | 229

14 14.1 14.1.1 14.1.2 14.2 14.3

Edit macros – Create and apply | 233 What is an edit macro? | 233 Naming conventions for edit macros | 233 Example of two very useful edit macros | 234 Table of edit macro commands | 241 Operands and abbreviations used in the edit macro commands | 247 14.4 Test aids in the creating macros | 248 14.4.1 Prototyping | 248 14.4.2 The REXX TRACE command as developing aid | 248 14.4.3 The program ISREMSPY | 249 14.5 System variables of the ISPF editor | 251 14.6 Passing parameters to macros | 252 14.7 Examples for editing and SUBMIT batch jobs | 255 14.8 Mnemonics for macro programming | 255

Contents | XIII

15 The SMART ISPF utilities | 257 15.1 Naming conventions | 257 15.2 The dynamic panel concept | 257 15.3 List of executable programs | 258 15.4 Program descriptions | 260 15.4.1 Edit macro ## – Execute a currently edited REXX procedure | 260 15.4.2 Edit macro #ALTXT – Realign line parts | 260 15.4.3 Edit macro #EDMEM – Edit of a member | 260 15.4.4 Edit macro #IMACROA – General ISPF edit macro | 261 15.4.5 Edit macro #IMACRO1 – Initial edit macro | 261 15.4.6 Edit macro #IMACRO2 – Edit session end macro | 262 15.4.7 Edit macro #ISPFB – Submit an ISPF batch job | 263 15.4.8 Edit macro #LCH – Perform long edit change commands | 263 15.4.9 Edit macro #SPLJ – SPLIT and JOIN lines | 263 15.4.10 Edit macro #SSS – Clear SCHFOR lists | 264 15.4.11 Edit macro #SSSCH – Mass update of members | 264 15.4.12 Edit macro #SU – Submit JCL without a JOB statement | 264 15.4.13 Edit macro #TSOB – Submit a TSO batch job | 265 15.4.14 Edit macro #VERASE – Erase ISPF profile variables | 266 15.4.15 Program SCURSOR – Calling a data set from an ISPF screen | 266 15.4.16 Program SDOC – Produce documentation members | 267 15.4.17 Program SLE – Display last edited data sets | 267 15.4.18 SLOGDSN – Data member containing DSNs for logon | 269 15.4.19 Program SLOGON – Personal logon procedure | 270 15.4.20 Program SPROFEDT – Store users ISPF profile variables | 270 15.4.21 SPROFVAR – Load user ISPF variables | 270 15.4.22 Program SSC – Super clone for data sets | 270 15.4.23 Program SSS – Perform a Super-Search | 271 15.5 Programming aids | 273 15.5.1 Edit macro #C – Compile and execute a REXX program | 274 15.5.2 Edit macro #RO – Online compile of a REXX program | 274 15.5.3 Edit macro #RC – Compile a REXX procedure with a batch job | 275 15.5.4 Edit macro #RCLOAD – Produce a load or a call module | 276 15.5.5 Edit macro #IE – Insert a call to ISPF_ERROR | 277 15.5.6 Subroutine ISPF_ERROR – Display ISPF error messages | 278 15.5.7 Edit macro #PAN – Execute a panel source code | 279 15.5.8 Subroutine DAYDIFF – Calculate number of days | 280 15.5.9 Subroutine ENDDAY – Calculate a target date | 281 15.5.10 Subroutine JULDATE – Translate a date to Julian and vise versa | 282 15.5.11 Subroutine LEAPYEAR – Return the leap year information | 283 15.5.12 REXX subroutine SCHANGE – REXX change function | 283

XIV | Contents

15.5.13 15.6 15.6.1 15.6.2 15.6.3 15.6.4

Program SDYNPAN – Convert a panel source code | 284 Installation of SMART ISPF utilities | 284 Download and unzip | 285 Installation | 286 ALTLIB command | 286 Make the SMART ISPF utilities ready to run | 289

List of programs | 291 List of tables | 292 List of screens | 293 Bibliography | 295 Index | 297

1 Introduction 1.1 Users of this book This book has been comprised for ISPF users with programming skills. You will learn how to insert and use your own functions in the ISPF using the procedure language REXX together with ISPF programming facilities.

1.2 The significance of the REXX programming language in z/OS Michael Cowlishaw and his team developed REXX in 1979 at the IBM laboratory in Hursley GB for the mainframe operating system MVS. Since this time many z/OS applications using the programming language REXX have been developed in IBM labs worldwide. Almost all of these applications run under the control of ISPF. This shows that IBM to the programming language REXX attaches great importance. Other REXX implementations: REXX is now available on all major computer platforms. I would particularly like to mention The REXX Language Association here. This association develops and maintains the object-oriented REXX version OOREXX. Use the internet link www.rexxla.org to get more information. I use OOREXX on my own Windows PC for many tasks, e.g., control of backups, printing of a list for all my stored movies.

1.3 Brochures for programming ISPF applications The following subchapters describe which brochures are needed for programming ISPF applications. The required books are divided into following groups. ‒ Books that describe the REXX language. ‒

Books that describe the ISPF programming facility enhancements.



One book that describes the TSO/E commands usable in REXX programs.

2 | 1 Introduction

1.3.1 The REXX programming literature There are many books on the market describing the REXX language. Now there are several implementations of the REXX language in a variety of computer systems available. For the use of REXX under TSO-E and ISPF, the official brochure of IBM is the most important one. I use for my REXX programming in ISPF the following two books:

1.3.1.1 TSO-E REXX Reference IBM form number SA22-7790. This book is the official REXX language publication of IBM. It contains descriptions of all aspects how REXX can be in the TSO-E environment used. First, this brochure contains the description of the REXX commands. In addition, the following topics are discussed in detail: ‒ Debug aids. ‒

TSO/E REXX programming services



TSO/E REXX customizing services



Language Processor Environments



Initialization and termination routines



Replaceable routines and exits

These chapters are only of interest to programmers who want to use REXX programs under special conditions as there are: ‒ Calling subroutines written in Assembler language. ‒

Calling REXX programs by programs that are written in other languages.



Writing REXX execs to perform MVS operator activities.

1.3.1.2 The REXX Language Published 1990 by Prentice-Hall Inc. ISBN 0-13-780651-5. The father of the REXX programming language Michael Cowlishaw wrote this book. It contains descriptions of all elements of the language without describing implementations in single carrier systems. I use this book often for creating REXX programs, because it is also helpful to create REXX programs under MS Windows just because it only contains the description of the REXX language and nothing else.

1.3 Brochures for programming ISPF applications | 3

1.3.2 ISPF reference books Of course, for such a big subsystem as the ISPF many reference books are available. You can find these books free of charge in IBMs internet book libraries. They are available in two types: 1. As PDF books for downloading to your PC. 2. For direct display with an internet browser. In the following chapter, I will show you where you can find all information to develop ISPF applications. Unfortunately, IBM changes methods from time to time to find a certain type of reference book. You can use the following steps: 1. With the following URL you reach the general z/OS literature frame: 2. http://www-03.ibm.com/systems/z/os/zos/library/bkserv/ 3. You can click on the line z/OS V2R1 documentation in PDF format. This action leads you to z/OS V2R1 Elements and Features selection menu. When a new release of z/OS appears, the text V2R1 may change. 4. Now press Cntrl+F and enter the search text ISPF. The browser positions the cursor on z/OS ISPF. 5. Click on this line and see the group of available ISPF publications. 6. Click on the book you want and the book is opened in your PDF reader. You can now save it on your PC for later use. There is a direct link to the ISPF Library http://www-01.ibm.com/software/awdtools/ispf/library/ Under this link, you will find ONLY ISPF reference books. However, also earlier releases are listed. The IBM form number: All books within the IBM z/OS library have a dedicated Form Number. The IBM form number consists of three blocks of information each separated by a hyphen: 1. The first part is a four-character item: two alpha characters and a two-digit number. e.g., SC19 stands for all ISPF books. 2. The second part is a four-digit number defining the book within its group. 3. The third part is a two-digit number continuously counted upward for this book. Table 1.1 on page 4 shows the ISPF reference books designed for ISPF programming purposes and their form numbers for z/OS release V2R1:

4 | 1 Introduction

Table 1.1: Reference books for the programming of ISPF applications

Title

Form number

z/OS ISPF Dialog Developer’s Guide and Reference

SC19-3619-00

z/OS ISPF Dialog Tag Language Guide and Reference

SC19-3620-00

z/OS ISPF Edit and Edit Macros

SC19-3621-00

z/OS ISPF Messages and Codes

SC19-3622-00

z/OS ISPF Reference Summary

SC19-3624-00

z/OS ISPF Services Guide

SC19-3626-00

1 Hint: If you are searching for a book using the form number, then you should use only the basic number without the release appendix. The system then shows all available titles and you can choose the proper exemplar.

The following listing shows such manuals you should have as an ISPF programmer:

1.3.2.1 Books for ISPF application programmers SC19-3621 → ISPF Edit and Edit Macros This book contains the normal handling procedures for the ISPF editor as well as the programming commands and rules for the development of Edit Macros. As you will see later, many edit macros are included in the SMART ISPF utilities. SC19-3624 → ISPF Reference Summary This manual contains short references for all commands and their parameters. This is the right book if a programmer is familiar in developing ISPF applications. SC19-3619 → ISPF Dialog Developer’s Guide and Reference This manual describes the development of applications in an ISPF environment. The description for producing panels does not contain the use of the Dialog Tag Language. SC19-3626 → ISPF Services Guide This manual contains descriptions of all facilities, rules and techniques used for ISPF programming.

1.3 Brochures for programming ISPF applications | 5

1.3.3 TSO reference books As I mentioned above, ISPF is running under control of TSO. Sometimes you need the assistance of TSO, e.g. for data set access. Therefore, it is necessary to know where you can find information concerning TSO commands. You need only one book from the wide range of available TSO reference books: TSO/E Command Reference Form Number: SA22-7782

1.3.4 The ISPF services ISPF offers many services to program ISPF applications. To use these services in REXX application programs, ISPF offers dedicated commands for each service. Table 1.2 on page 5 shows the ISPF service groups and their usage: Table 1.2: ISPF service groups

Service Group

Used for

Display Service

display of panels and tables

LM Service

working with libraries (LM stands for Library Management)

Table Service

working with ISPF tables

FT Service

dynamic production of JCL by using skeletons

Q Service

query services

V Service

handling of ISPF variables

Commands to use these services in a REXX program are described in later chapters. 3 Conclusion concerning the theme ISPF literature released by IBM: I would first like to emphasize that the IBM literature for the entire z/OS system is very good. However, as always in the IBM brochures, all aspects of commands are explained in detail and for the beginner it is sometimes difficult in the application of commands to apply a command properly for the achievement of a specific purpose. One aspect of this book is to explain readers the commands always in connection with a specific goal. Finally, yet very important, this is a major reason why I have written this book.

2 Introduction to the REXX programming language 2.1 What is REXX? The IBM brochure TSO-E REXX Reference, form number SA22-7790 contains the following short description: The REstructured eXtended eXecutor (REXX) language is particularly suitable for: – Command procedures – Application front ends – User-defined macros (such as editor subcommands) – Prototyping – Personal computing. Individual users can write programs for their own needs. REXX is a general-purpose programming language like PL/I. REXX has the usual structured-programming instructions – IF, SELECT, DO WHILE, LEAVE, and so on – and a number of useful built-in functions. The language imposes no restrictions on program format. There can be more than one clause on a line, or a single clause can occupy more than one line. Indentation is allowed. You can, therefore, code programs in a format that emphasizes their structure, making them easier to read. There is no limit to the length of the values of variables, as long as all variables fit into the storage available. So far the short description contained in the official publication concerning the REXX language under z/OS. The following excerpt contained in the preface of Michael Cowlishaw’s book explains his basic ideas for developing REXX. See section 1.3.1.2 The REXX Language on page 2. The REXX programming language has been designed with just one objective. It has been designed to make programming easier than it was before, in the belief that the best way to foster high quality programs is to make writing them as simple and as enjoyable as possible. Each part of the language has been devised with this in mind; getting the design right for people to use is more important than providing for easy implementation. A programming language is a complex structure, typically characterized by its most visible aspect – its syntax. Of equal importance is its semantics, the meaning behind the instructions. But perhaps most important of all is the philosophy behind the language – the guiding principles that governed the decisions made as the language was designed.

8 | 2 Introduction to the REXX programming language

1 Guideline for the development of REXX I met Michael Cowlishaw at the 25th anniversary of REXX and he told me that during the development of REXX in the following sentence hung on the wall his office: Keep the language small!

Mike Cowlishaw gave us with REXX a language that really of a minimal vocabulary consists. The programs developed with REXX are indeed small.

2.2 Overview of REXX under TSO REXX is a procedural language. This means that you need an interpreter to execute a REXX procedure. The TSO contains a REXX procedure interpreter. That is, REXX programs runs in TSO like a TSO command. Before the REXX procedure language interpreter was integrated in the TSO, there was already the CLIST interpreter available. Therefore, a method had to be introduced where the TSO can be see that a program contains REXX code and it is not a CLIST.

2.2.1 Recognizing a REXX procedure by the TSO The TSO Command Processor interprets a procedure as a REXX program if the first line of the program contains the text REXX or rexx. When the first line misses one of the words REXX or rexx, then the TSO command processor assumes that it is a procedure of type CLIST and passes the procedure to the CLIST procedure processor. This requirement means that the first line of a REXX program executed in the z/OS TSO must always be a comment line containing the text REXX or rexx. As an example, here the program head of one of my REXX procedures: /* DOC: REXX TT */ /* DOC: Example for a test */ /*************************************************************/

2.2 Overview of REXX under TSO | 9

2.2.2 Running REXX procedures in the TSO Call and execute REXX procedures as follows in the TSO: 1.

Explicitly by the TSO EXEC command.

When using the TSO command EXEC to execute a REXX program member, it is determined directly in the EXEC command operands. This means that a member that contains a REXX procedure is executable from each PDS. Example:

TSO EXEC 'dsn(member)' The EXEC command still knows a number of options that are only interesting for special cases. See the command description in the manual TSO-E Reference in chapter EXEC Command. 2.

Implicitly by calling up as a TSO command.

In this case, there are several possibilities to call up a REXX program: ‒ Only the name of the REXX procedure as a TSO command is entered. E.g .: TSO pgm. In this case all allocated system and user load libraries are searched for this program name. If the name is not found there, then the SYSEXEC and SYSPROC libraries are scanned. ‒

To call a REXX program you can alternatively use the command TSO %name. In this case only the SYSEXEC and SYSPROC libraries are scanned for the program.



When a REXX program to be executed is not found in any of the existing allocated libraries, you can use the command ALTLIB to allocate the required library temporarily and then use one of the two methods mentioned above for calling. See chapter 7.5 ALTLIB – Dynamic linking of EXEC libraries on page 126.

3.

Implicitly by calling up as an ISPF command in a DSLIST display panel.

To execute this type of call see the following panel:

10 | 2 Introduction to the REXX programming language

Screen 2.1: Example of a command call in a DSLIST display panel Menu Options View Utilities Compilers Help ────────────────────────────────────────────────────────────────────── DSLIST - Data Sets MatchingPROX.PACKTIME.* Row 1 of 6 Command ===> Scroll ===> CSR Command - Enter "/" to select action Message Volume ----------------------------------------------------------------------PROX.PACKTIME.DB2P P0XYZ6 compdate / april KTIME.DGP1 P0XYZ6 PROX.PACKTIME.DGP2 P0XYZ6 PROX.PACKTIME.DGP3 P0XYZ6 ************************** End of Data Set list **********************

In this case, the following will happen: The program compdate is searched in all allocated LOAD and EXEC libraries. If it is found, it is executed and the DSN standing in this line and the text april are passed as parameters to the program. For this type of call, a slash (/) represents the DSN standing in this line. Depending on the position where the program expects the DSN in the takeover of the parameters, the slash is to be in accordance with the position. 4.

Implicitly invoked using the ISPF SELECT service

The following example shows the execution of a small REXX program using the ISPF SELECT service from a data set, which is temporary allocated by the TSO ALTLIB command. mem = "compdate" pp = " PROX.PACKTIME.DGP1 april" "ALTLIB ACTIVATE APPLICATION(EXEC) DDNAME(##DD)" "ISPEXEC SELECT CMD(%"mem strip(pp)")" "ALTLIB DEACTIVATE APPLICATION(EXEC)"

This is the same execution of the program compdate as shown in Screen 2.1 on page 10. For information about ISPF SELECT service, refer to the IBM ISPF Services Guide. Information on the use of ALTLIB command, see section 7.5 ALTLIB – Dynamic linking of EXEC libraries on page 126. The ALTLIB command also has a display option. I once had the above program executed without the ALTLIB DEACTIVATE command and then ran the command ALTLIB DISPLAY manually. I received the following display: Current search order (by DDNAME) is: Application-level EXEC DDNAME=##DD System-level EXEC DDNAME=SYSEXEC System-level CLIST DDNAME=SYSPROC

2.3 Performance of REXX procedures | 11

2.3 Compile REXX procedures In some z/OS systems, a REXX compiler is available. Therefore, you can compile REXX procedures before executing them. The REXX compiler is also able to produce genuine z/OS load modules. These load modules can be executed in a batch job using the JCL statement EXEC PGM=NAME. Since the focus of this book is the ISPF and the REXX, compiler topics would go beyond the scope of this book too far, unfortunately I have to refrain from treating the REXX compiler. However, you can find in the SMART ISPF utilities procedures to generate cexec and load modules using the REXX compiler. See section: 15.5 Programming aids on page 273 and the subsequent pages.

2.4 Performance of REXX procedures When running REXX procedures, each statement must be interpreted by the system. This, of course, requires computing time, which is added to the time of execution of the REXX commands. The currently available host processors are so fast that in practice hardly an execution time difference between an interpreted REXX procedure and a compiled program are detectable. If there is concern about the performance of REXX procedures, you should first take a closer look at the greatest performance brakes. The following operations normally slow down the execution of a REXX program the most: ‒ I/O operations. ‒

Loading of external procedures and load modules.



Calling external system functions.

Therefore, it is advisable to always start first at these points with actions for performance improvement. You should not expect too much of compiled REXX procedures because of the following reasons: Performance tips: 1.

Compiled programs:

The time needed to perform the called ISPF and TSO functions is usually much higher than the execution time required for the pure REXX code. Thus, it is usually not advisable to use compiled REXX procedures. I have gained this knowledge from working in a very large project with hundreds of compiled REXX programs.

12 | 2 Introduction to the REXX programming language

2.

Functions and subroutines

Functions and subroutines that do not belong to the scope of functions of REXX are loaded every time when they are called from the external data set. It is obvious that this can be a significant performance brake. I strongly recommend investigating your programs for such performance brakes and if necessary, copying the source code of these programs into the main program. The fastest way to detect such a speed brake is the execution of this program in a batch job. After the program execution, you can check the SDSF as to how many EXCPs the program has consumed. If the EXCP count is exorbitantly high, then it is obvious that a function or subprogram was continuously loaded.

2.5 The syntax of the REXX language The syntax of the REXX language is very simple and strongly influenced by PL/I: – A statement is normally always in a row. A semicolon normally terminates it. However, it does not have to be explicitly completed! – Multiple statements on one line must each be terminated with a semicolon except the last one. The last statement can of course also terminated with a semicolon. – If a statement is continued on the next line, then the preceding line must end with a comma (,). This also applies to literals. The continuation comma itself is always replaced by a blank. If this blank should be avoided, then the two literal parts must be concatenated with the concatenation operator (||). – Blank lines are allowed in the program code. – Comments always begin with /* and end always with */. All texts between these two limits belong to the comment even if they span multiple lines and contain REXX commands. Comments can be wherever a blank is allowed be placed within a statement and they can be nested. Note: When the pairing of the comments is interrupted, it may happen that the rest of the program remains as a comment. – Literals are put in paired quotation marks or apostrophes. There are three types of literals: – Text literals. These literals can contain any text, and it can be defined over several lines. One literal must not exceed 250 characters. – Hexadecimal literals. They can only contain hexadecimal digits and must be completed by the letter x or X. The individual bytes can be, separated by blanks, entered. – Binary literals. These can only contain 0 and 1 and must be completed by the letter b or B respectively. The individual bytes and half-bytes can be separated by blanks.

2.5 The syntax of the REXX language | 13

Examples of correct REXX statements: a = 5; B = "FF FF FF FF"x; L = "1111 0000 1111 0001 1111 0010"b X = 1 /* Set initial value for X */ do k = 1 to 50; m.k = 0; /* Set initial values to zero */ end k;

Here you see an example of continuation lines in the definition of text literals. Keep in mind that the continuation character in the resulting text appears as blank. Therefore, you should always define continuation lines of literals so that the resulting text contains a blank at this point anyway. if sysdsn(newdsn) "OK" then do zedlmsg = "The COPY data set does not exist.", "Copy operation is impossible!!", "Please enter the name of an existing data set", "or select another function." "ISPEXEC SETMSG MSG(ISRZ001)" msglvl1 = "Error at COPY" iterate ipanel end

Rules for inserting comments and blanks in REXX statements. After defining the rules, you will see a sample program that shows the applications of the rules. In the description of each rule there is always reference to the program line to which this rule applies. – In general, comments that are inserted in a statement will be removed before executing the statement. Lines 06, 07, 08. – If the statement after the removal of the comments is executable, it is executed. – If multiple blanks between the elements of a statement are present, they will be removed down to a single blank. Line 05. – For functions that contain parameters in a pair of parentheses, a blank is never allowed between the function name and the opening parenthesis. Line 10: The blank in column 30 that remains when the comment is removed, is not allowed. Program 2.1: Example for handling blanks and comments in REXX programs 01 /* DOC: TEST3 REXX MAIN */ 02 /*--------------------------------------------------------*/ 03 /* © FRANZ LANZ 2015 */ 04 /**********************************************************/ 05 say "First word" "Second word" 06 say "First word"/**/"Second word" 07 say "First word" /**/" Second word" 08 say "First word /**/ Second word" 09 say date/* date */()/**/time/* time */() 10 say date/* date */()/**/time /* time */() S>----+----1----+----2----+----3----+----4----+----5----+----611 exit

14 | 2 Introduction to the REXX programming language

If this program is running, the following output is displayed: First word Second word First wordSecond word First word Second word First word /**/ Second word 26 May 201516:44:17 10 +++ say date/* date */()/**/time /* time */() Error running TEST3, line 10: Unexpected "," or ")" ***

2.6 Variables in REXX Rules: – –

– – –



REXX variables cannot be explicitly defined before use. The type of a variable can only be CHAR or NUM. It is always defined by the content of the variable. The type is determined after each assignment of a value. This means that, REXX variable can continuously change their data type between CHAR and NUM depending on which data was assigned last. The length of the variable name can have a maximum of 250 characters. If a variable is used without a previously assigned value, then its content is always equal with the name in uppercase letters. A variable that is not the type NUM by functions or external input assigned must be explicitly assigned a numerical value before it can be used in an arithmetic operation. The length of a character string variable must not exceed 16MB.

3 Remark: One of the most elegant facilities in REXX is that variables do not need to be defined prior to use. I remember that using other programming languages, I very often got the error message Undefined variable during program execution. Sometimes I needed several test runs until I found all the missing variables.

Example: When you perform the statement: say hugo_is_my_boy_friend

The display is: hugo_is_my_boy_friend

When execute the following statement. hugo_is_my_boy_friend = "fred"

and you perform the above say statement again say hugo_is_my_boy_friend

The display is now: fred

2.7 Operators of the REXX language | 15

2.7 Data types of REXX variables As mentioned above in REXX knows only two data types of variables. These are NUM for a numerical content and CHAR for all other contents. As explained above, the data type is determined internally on each assignment of a value to a variable. It cannot be explicitly specified in the program, but the function DATATYPE(var) can used to query the data type of a variable. Here is a short list showing the data types of the variable HUGO after an appropriate assignment of values: Assignment to hugo hugo = "250" hugo = 250 hugo = "25 0" hugo = date() hugo = date("S") hugo = "F0 F1"x hugo = "C1 F1"x hugo = "1111 0001 1111 1001"b

Content/Value of hugo 250 250 "25 0" "14 May 2004 20040514 01 "A1" 19

Datatype NUM NUM CHAR CHAR NUM NUM CHAR NUM

1 Rule: The resulting data type is only NUM when an admissible number in the sense of REXX is assigned to it. Permissible blanks in HEX and BIN strings are removed by the REXX assignment command.

Null strings: A special type of data is the null string. This type of data is often assigned to variables if no result of an executed command is present. The null string is determined as a literal by two consecutive apostrophes. Null strings are of data type CHAR and have a data length of 0 (zero). Examples of definition and query of null strings: a = "" /* assign a null string to a */ if a = "" then do /* check a for null string */ /* processing the DO group */ end

2.8 Operators of the REXX language The operators define the operations which with variables and constants are to be performed. Types of operators: – String operators – Arithmetic operators – Comparison operators – Logical operators

16 | 2 Introduction to the REXX programming language

2.8.1 String operators Here we meet one of the greatest strengths of REXX. To merge text, you simply write the various constants and variables in one statement. The following rules apply: Rules: – –

– –

If in a statement between the constants and variables there is more than one blank, the result is at this point only a single blank. If you want to prevent the automatic insertion of blanks, elements with the concatenation operator (||) need to be connected. Blanks that stand on the left or right of the concatenation operator are ignored in this case. If you want to insert multiple blanks, they must be defined as a literal in quotation marks. The concatenation operator is not necessary when individual elements of the statements can be clearly recognized by the interpreter.

Examples: This program example shows how texts can be assembled. say "1" date() time() say "2" date()time() say "3" date() time() say "4" date()|| time() say "5" date()" "time() say "6" date(), time() say "7 The date of the present day is:"date() say "8 The date of the present day is:"||, date()

When executed, the program produces the following list output: 1 2 3 4 5 6 7 8

24 Mar 2015 18:29:24 24 Mar 201518:29:24 24 Mar 2015 18:29:24 24 Mar 201518:29:24 24 Mar 2015 18:29:24 24 Mar 2015 18:29:24 The date of the present day is:24 Mar 2015 The date of the present day is:24 Mar 2015

2.8.2 Arithmetic Operators The following table lists the arithmetic operators:

2.8 Operators of the REXX language | 17

Table 2.1: Arithmetic REXX operators Operator

Function

+ * / % // **

Addition Subtraction Multiplication Division Integer division. The rest is suppressed, the result is not rounded. Integer division with return of the rest. Potentiation. Only integers are as powers allowed.

The + and - signs can be set as a sign in front of variables and constants. Example: a = 3 b = a * 3 % 5 c = -a d = a * 3 // 5 say a b c d c+d a*100/10"%"

When executed, the program produces the following list output: 3 1 -3 4 1 30%

2.8.3 Compare operators Table 2.2: Compare operators Operator

Description

= > < >
= \ == \==, ¬==, /== >> >= \2)*2 +, (mm>1) + (mm>3) + (mm>5) + (mm>7) + (mm>8) + (mm>10) +, (mm>2) * ((yyyy // 4 = 0) - (yyyy // 100 = 0) +, (yyyy // 400 = 0)))

2.9 Stems in REXX | 19

This program produces the following printout: Day Day Day Day Day

in in in in in

the the the the the

year year year year year

of of of of of

date date date date date

2004.12.31 2005.12.31 1999.12.31 2020.03.01 2016.02.29

is: is: is: is: is:

366 365 365 61 60

See also Program 15.6: Subroutine JULDATE on page 282.

2.8.4 Logical operators The logical operators are usually only used in logical statements, such as IF, WHEN etc. The following table shows the logical operators: Table 2.3: Logical operators

Operator

Description

&

Returns 1 if both expressions are true.

!

Returns 1 if at least one of two expressions is true.

&&

Returns 1 if one of two expressions is true, but not both.

Prefix \¬

Negates a logical expression.

2.9 Stems in REXX Stem are something similar to dimensioned arrays in other programming languages. STEMS start with a variable name followed by a dot. The values behind the point are something similar indices. These indices can be numbers and any text. In the REXX literature, stems are also referred to as Compound Variables. This means that a variable hugo.1 as long as the content HUGO.1 has until it is be assigned a different value. In simpler terms: Each stem variable per se is a normal variable; it is only written differently. In addition, you can work based on composition by the details behind the points easier with a whole set of variables each with an own name. My experience is for understanding the stems, beginners in REXX are faced with greater difficulties. The following small examples show how this technology works.

20 | 2 Introduction to the REXX programming language

Example program for using stems: Task: The dataset user001.flight.data(flights) contains the flight log of the performed flights. I wanted to know how many flights I have on the individual aircraft types carried out and how many hours with each type. I did not know beforehand how many aircraft types were used in total. During the program run, the types must be successively detected and stored Program 2.2: Program FLIGHTS to explain the using stems and EXECIO /* DOC: FLIGHTS REXX MAIN */ /* DOC: Calculating the number of flights per aircraft type and the */ /* DOC: related total flight time in hours. */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ "alloc dd(in1) dsn('user001.flight.data(flights)') reuse shr" "execio * diskr in1(stem flights. finis" "free dd(in1)" types = "" /* String for collecting the airplane type names */ ft_nbr. = 0 /* Stem for adding the number of flights */ ft_hrs. = 0 /* Stem for adding the summary of flight hours */ do i = 1 to flights.0 /* Loop over all data set records read */ ft = word(flights.i,9) /* The airplane type is in the ninth word */ if wordpos(ft,types) = 0 then types = types ft /* This IF checks whether a airplane type is still in types string*/ /* and if not, the new name is added to the existing types */ ft_nbr.ft = ft_nbr.ft + 1 /* Count the number of flights/type */ ft_hrs.ft = ft_hrs.ft + translate(word(flights.i,6),'.',',') /* Add the flight times for this type */ end i /*-------------------------------------------------------------------*/ /* Print the results */ /*-------------------------------------------------------------------*/ do i = 1 to words(types) ft = word(types,i) out.i = left(ft,5) right(ft_nbr.ft,5) right(ft_hrs.ft,8) say out.i end i /*-------------------------------------------------------------------*/ /* Write the results into a data set member */ /*-------------------------------------------------------------------*/ "alloc dd(ut1) dsn('user001.flight.data(result4)') reuse shr" "execio "words(types)" diskw ut1(stem out. finis" "free dd(ut1)" exit

See the output of the program: C152 C172 TB20 TB09 TB10 PA28 C182 C310

336 140 80 16 26 28 56 4

96.02 85.66 74.31 8.18 28.15 43.87 51.23 5.70

2.9 Stems in REXX | 21

PN68 C210 BE36 PA44 PA34 PA46 C303 C340 C421 SR20 DA42

17 200 16 8 6 11 19 28 28 29 52

11.42 209.44 16.73 11.83 6.55 15.25 16.56 25.80 30.93 34.49 73.57

Explanation: There are three stems used in this program: flights.

This stem is of type CHAR and is filled by the EXECIO TSO command. It is used in the DO loop by addressing the single data records by the DO loop variable i. The variable flights.0 contains the number of read records. The EXECIO command fills this variable.

ft_nbr.

Due to the pre-definition statement ft_nbr. = 0 is this stem of type NUM. This allows that 1 can added continuously to count the number of flights. The index is always the name of an aircraft type.

ft_std.

Due to the pre-definition statement ft_std. = 0 is this stem of type NUM. This allows that the time of a single flight can be added continuously. The index is always the name of an aircraft type.

This example also shows how stems are used for data set processing!

2.9.1 Initialize stems with null string The following program example illustrates the effect of stems null string assignments: /* DOC: REXX NULLSTR */ /* DOC: Demonstration of nullstrings in stems */ /* © FRANZ LANZ 2015 */ /**********************************************************/ hugo. = "" /* Stem is initialized with null string */ hugo.1 = 10 hugo.3 = 20 jane.1 = 111 jane.2 = 222 do i = 1 to 5 say left(">"hugo.i""jane.i"25< >XXXX< >HUGO.1.3< > Will arrived at 8 Apr 2004< >HUGO.2.2< >finished
"hugo.i.k""p1""p2""p3""p4""a1""a2""a3""a4"read_data_lmget>" mvsvar("SYMDEF",SYS.I) end I

Example of UNTIL from a program to print error text: do ip = 1 by 72 until length(rest) < 72 ll = min(72,length(qq-ip+1) rest = substr(qq,ip,ll) io = io + 1 line.io = rest end ip

Mnemonics to the DO command –

The loop index, the incremental value and the final value can have negative contents and decimal numbers such as 0.3, 12.5 and so on.

3.5 EXIT and RETURN – leaving the REXX procedure | 39



– –



The LEAVE command is not applicable within DO groups. Therefore, if you want to leave a DO group with LEAVE, you should then create it as a DO loop, even if you do not need the loop index. You should get into the habit to always specify the loop index name in the END statement of a DO loop. This increases the overview immensely. The ITERATE command jumps to the end of the loop, calculates a new value for the loop index and then continues the DO loop. This makes it possible to jump from an inner level nested loop directly to the end of an outer level. Depending on the manner in which the loop is exited, the content of the loop index is as follows: – If the loop ends normally by reaching the final value and the calculation of the loop index variable has exactly the final value, the loop index contains the value: end value + increment. In all other cases, the loop index contains the value: Content on the last run + increment. – If the loop is exited due to the WHILE condition, the loop index contains the value: Content on the last run + increment. – If the loop is exited due to the UNTIL condition or a LEAVE statement, the loop index contains the current value.

3.5 EXIT and RETURN – leaving the REXX procedure Command syntax: EXIT expression

Use EXIT to leave a main program. If the EXIT command used is in an internal subroutine, the main program is exited. If there is an external procedure called, then only this will exited, but not the calling program. expression

This value is returned to the calling program. If the calling program is the TSO, then this value must be an integer number in the range of -2**31 to 2**31-1, because in this case the value is set in the register 15 and then to the TSO returned. If the REXX program was called in a TSO batch job, this return code is by the TSO as a step return code returned to the MVS.

Example: The following example illustrates this technique: I have written an external subroutine called TEXIT, which consists only of the EXIT 999 command. In the following program, this routine is once as a function and once called with CALL:

40 | 3 The REXX commands

/* DOC: REXX EXIT */ /* DOC: Example for return code setting by RETURN */ /* © FRANZ LANZ 2015 */ /********************************************************/ xxx = texit() say "Return value xxx from 'xxx = texit()': "xxx call texit say "Return value RESULT from 'call texit' : "result exit

When called, the program prints the following lines: Return value xxx from 'xxx = texit()': 999 Return value RESULT from 'call texit' : 999

As you can see when TEXIT is called as a function, the return value is returned in XXX and when called using CALL the return value is returned in the special variable RESULT. Command syntax: RETURN expression

If one wants to jump out of an internal subprogram to the parent program, RETURN must be used. The handling of the return code is the same as the EXIT command. Example The following internal procedure returns a 1 if the YEAR variable contains the number of a leap year. Otherwise, 0 is returned. Program 3.4: Function LEAPYEAR LEAPYEAR: ARG YYYY RETURN (YYYY // 4 = 0) - (YYYY // 100 = 0) +, (YYYY // 400 = 0)

Return codes at program start under ISPF batch: When you invoke a REXX program under ISPF batch, then the return code from the RETURN or EXIT command is not returned to the operating system. In this case, you have to use a special technique to make the ISPF return the desired return code to the TSO and so to the calling operating system. This technique is to store the return code into the ISPF variable ZISPFRC and write this variable in the ISPF function pool before leaving the REXX program. Program example statements: zispfrc = 16 "ISPEXEC VPUT (ZISPFRC)" exit

3.6 IF and WHEN – check conditions | 41

In this case, the ISPF step ends in a batch job with the RC = 16. See also section 6.1 Execution of programs in a TSO/ISPF environment on page 105.

3.6 IF and WHEN – check conditions The commands IF and WHEN have the same structure. The WHEN command, however, can only within a SELECT sequence used. The basic structure of these commands is: IF|WHEN expression THEN instruction ELSE instruction

expression

Any numeric or logical expression whose result can only be 0 or 1.

instruction

Each REXX command.

The operation and diversity of IF commands can best explained with examples. So here are some examples of IF queries from some of my programs: First example if pos(syst,"1") > 0 & pilot then do if (wordpos("COP",ingrps) > 0) then call cop if (wordpos("MAC",ingrps) > 0) then call mac end

Second example if syst = "1" , & emergency_paket & ^pilot_paket then do "FTINCL VINTEXTR" if rc > 0 then call ispf_error rc " from FTINCL VINTEXTR" else say exname time(), "Release step for ARCH jobs inserted" end

Third example if sql_ca_msg.0 > 0 then do ica = 1 to sql_ca_msg.0 say exname strip(sql_ca_msg.ica) end ica

In this example, you can see that in an IF command not only a DO group, but also a DO loop can start.

42 | 3 The REXX commands

3.7 INTERPRET – generate REXX commands dynamically The INTERPRET command generates a REXX command using constants and variables and executes it immediately. This allows you to generate and execute REXX commands dynamically. Command syntax INTERPRET expression expression

The content of expression dissolves and the resulting REXX command executes immediately. The expression is usually composed of literals and variables that make up the command to execute.

3 Note: A beginner in REXX programming may have some difficulties in defining INTERPRET commands correctly. So I am going to show the operation of the INTERPRET instruction using a few examples. As usual in this book, I take these examples from some of my practice programs.

First example for the INTERPRET command: The SMART ISPF utilities contain the edit macro #IMACRO1. For control purposes, some variables must be dynamically assembled to contain in its name the number of the logical ISPF screen where the program is running. This technique assures that the program can run parallel in some logical screens. The following statements show how this is realizable using the INTERPRET command: address "ISPEXEC" "VGET (ZSCREEN) SHARED" interpret "rcsave"zscreen" = 'NO'" interpret '"VPUT (RCSAVE'zscreen') PROFILE"' interpret "pasave"zscreen" = 'NO'" interpret '"VPUT (PASAVE'zscreen') PROFILE"'

As you can see, original REXX commands as well as ISPF commands are assembled. Since the latter have to be set in single quotes, the two delimiters (') and (") are alternately used for literals so that useful statements are developed. When the INTERPRET command translates and we assume that the ZSCREEN variable has the value 4, then the following command sequence would run: rcsave4 = 'NO' "VPUT (RCSAVE4) PROFILE" pasave4 = 'NO' "VPUT (PASAVE4) PROFILE"

3.7 INTERPRET – generate REXX commands dynamically | 43

Second example for the INTERPRET command: This example also comes from one of my applications. It is somewhat complex. Therefore, it is so beautiful! To help you understand the following example, I will explain the environment under which the program is running. This REXX program reads DB2 tables using an assembler subroutine and prints them. The operator enters the necessary SQL statements using an ISPF panel. These statements are passed to the assembler program. The assembler program stores the DB2 read results into stems that are in the REXX at return from the assembler program known. do row = 1 to sql_nrows io = io + 1 line.io = filler do col = 1 to SQL_CN.0 interpret "value = "sql_cn.col".row" line.io = line.io!!left("'"value"'",columnl.col-1)"," end col line.io = line.io!!' ' line.io = overlay(" ",line.io,lastpos(", ",line.io),2) end row

Explanation: Suppose, the loop index ROW is 5 and the loop index COL is 3. Then the following situation arises after the replacement of the control variables COL and ROW: SQL_CN.3 contains the text PRI_DATE. Thus, the following statement executes: value = PRI_DATE.5

PRI_DATE.5 contains, as shown in the printout below, the text: 20040421. --******************************************************************* --* Echoprint of the SELECT Statement --******************************************************************* --* SELECT PRI_OBJ, PRI_TYP, PRI_DATE, PRI_TIME FROM EPQMS.CROSS1 --* WHERE PRI_TYP = 'REXX' AND PRI_OBJ LIKE '#IM%' ORDER BY PRI_OBJ; --******************************************************************* --* DOC: SELECT-OUTPUT OF TABLE: EPQMS.CROSS1 --* DOC: FROM DB2 SUBSYSTEM: DBT1 Read records: 10 --* DOC: PRODCUCED: 21 APR 2004 14:47:28 --******************************************************************* --* PRI_OBJ PRI_TYP PRI_DATE PRI_TIME *-- '#IM ','REXX ','20031127','09:37:02' *-- '#IMACROA','REXX ','20040405','10:31:41' *-- '#IMACROI','REXX ','20020828','13:28:03' *-- '#IMACRO1','REXX ','20040421','14:06:30' *-- '#IMACRO2','REXX ','20040421','13:13:55' *-- '#IMACRO2','REXX ','20040421','13:13:55' *-- '#IMEXECE','REXX ','20020606','15:56:59' *-- '#IMEXECE','REXX ','20020606','15:56:59' *-- '#IMEXEC1','REXX ','20020708','18:21:40' *-- '#IMEXEC1','REXX ','20020708','18:21:40' ---------------------------------------------------------------------

44 | 3 The REXX commands

I hope I have been successful inspiring you for the INTERPRET instruction! You can use it when necessary to produce very elegant solutions. In addition, in some cases it is simply essential! You can find such a solution in the REXX program SPROFVAR --- Load user ISPF variables on page 270.

3.8 NUMERIC – set computing options In this chapter, I deal will with the following two commands: NUMERIC DIGITS number and NUMERI FUZZ number.

Before I turn to this issue, I have to tell you how the REXX data and here especially figures are internally stored. If you have ever programmed in a programming language other than REXX, you know the effort you have to do there to define your variables containing figures. Since there is binary data which may be stored in fields of 16, 32 or 64 bits, there is decimal data with up to 31 decimal digits. Add the different variants of the floating point data. Let alone the different variants of the floating-point numbers. Fortunately, you can forget it all in REXX. 3 How REXX figures internally stores: REXX puts all the data in EBCDIC text strings. So also the data that contain numbers. The numbers before they participate in arithmetic operations are converted to an appropriate format that the underlying system can handle and are converted back into text strings after completion of the arithmetic operation. This happens for each arithmetic operation within a command.

For this very simple rule, of course there must be a defined width for the figures so that the numerical representation remains manageable. Example: If the command X = 2/3 is executed then an infinite fraction occurs. As in the REXX fractional numbers are not stored in words such as Short Floating Point or Long Floating Point, where the number automatically by the word length is limited, but as unpacked figures in EBCDIC format, an infinitely long number would need to be stored here. This means, it must be set somewhere how many significant digits are to be stored in such a number. If the default width of NUMERIC DIGITS 9 were active, the number X would be stored as EBCDIC characters in: 0.666666667. That is, for the storage of X, 11 bytes are occupied internally. The NUMERIC command is available with three main functions, of which I will discuss only two.

3.8 NUMERIC – set computing options | 45

NUMERIC DIGITS number number

specifies how many significant digits are used to store numbers. This definition is always immediately active until a change with a new NUMERIC DIGITS is made or the program ends. Number must be a whole number. Of course, the specification using a variable is possible. The default value is. 9

3 Note: As long as the numbers remain in a program below ABS(999999999), you do not need to change the value of NUMERIC DIGITS. However, as soon as a number generated during the program runs and goes beyond this number space, you have the NUMERIC DIGITS to increase accordingly, or you get a program abort. If you read all of this, one might be tempted, at the beginning of each REXX program simply to enter the command NUMERIC DIGITS 50. This would be likely to be on the safe side. However, here we must remember that then all fractional numbers that have as many places stored after the decimal point with 50 significant digits, and even worse, of course, also be calculated using this width.

Example: The following commands produce this result: numeric digits 70 b = 10 + .5e-67 say b 10.00000000000000000000000000000000000000000000000000000000000000000005 NUMERIC FUZZ number

determines how many digits of a number to be rounded by decimal from the right before a comparison operation performs. This definition is always performed immediately and valid until a change with a new NUMERIC FUZZ statement is or the program ends. This must be a whole number. Of course, the specification using a variable is possible. The default value is 0. The number must always be less than the current number value of the NUMERIC DIGITS command.

The impact of NUMERIC FUZZ on the logical operations is better understand when we look at an example: numeric digits 5 numeric fuzz 0 if 4.9999 = 5 Result if 4.9999 < 5 Result numeric fuzz 1 if 4.9999 = 5 Result if 4.9999 < 5 Result

is not true is true is true is not true

46 | 3 The REXX commands

In order to understand this example, you have to realize that REXX normal comparison operations (not the exact with the double operator symbol) between two is performed such a way that first the second number is subtracted from the first and then the result is compared with zero. If we view the results shown in the above IF statements that are behind the NUMERIC FUZZ 1, then this is due to the following effect: Because FUZZ is less than DIGITS, the takes place before subtraction. From 4.9999 the integer is 5. 1 Tip: If you ever need to perform extensive calculations with REXX for which comparisons of fractional numbers happen to fail due to differences in the rear decimal places that you do not expect, then you remember NUMERIC FUZZ.

The currently active values for NUMERIC can be displayed as follows: say "NUMERIC DIGITS has the value: "digits() say "NUMERIC FUZZ has the value: "fuzz()

The display of these two commands is here: NUMERIC DIGITS has the value: 9 NUMERIC FUZZ has the value: 0

3.9 PARSE – text fragmentation The PARSE command is one of the strongest commands of the REXX language. You can use it to perform in an elegant way decompositions of texts, data read from the stack or from the terminal and get information about the currently running program. You have one of its variants already in the discussion of the ARG instruction in the section 3.2 ARG – Retrieve the parameter string seen on page 31. We will now look at other forms. Again, I would like to present a few examples from practice. First, here is an overview of the different variants of the parse command in the following table:

3.9 PARSE – text fragmentation | 47

Table 3.2: Table of PARSE types

PARSE type

Functions

PARSE ARG

Disassembles transfer input parameters at program calls.

PARSE EXTERNAL

Reads data from the terminal when programs execute online. In batch processing data are from DD SYSTSIN. If no data is available, then a null-string will be returned.

PARSE NUMERIC

Returns the currently active values for the three NUMERIC options DIGITS, FUZZ and FORM.

PARSE PULL

Reads the TSO data stack. If it is empty, this command works like PARSE EXTERNAL.

PARSE SOURCE

Returns information about the source code of the currently running program.

PARSE VALUE

Parses an expression.

PARSE VAR

Parses a variable.

PARSE VERSION

Returns information about the REXX interpreter, under which the program is running.

Rules: – –





In all PARSE commands, UPPER can be specified as the second word. Thus, the results are returned in uppercase. Just like the ARG instruction, too. In the data to be fractionized, the blank plays a special role: If no separator or placement points are given in the variable list, the separation is on the blanks in the performed text. In the variable list, the point (dot) can be as placeholders for variables used. For safety reasons, I always use the dot as the last variable position. This collects everything possibly in the text that is still behind the positions I need. Otherwise, this part would additionally be in the last assigned variable. Variables that have no values could be assigned during the fractionizing contain null strings.

Design possibilities of parse templates: There are several ways to control the fractionize process in PARSE commands. Use the following templates to control the fractionizing process of the PARSE command: – The Blank. – A string. – Variables containing delimiters. – Numbers that indicate the absolute or relative character position in the text. Let us now look at the different variants of the PARSE command in detail:

48 | 3 The REXX commands

3.9.1 PARSE ARG I have already dealt with this command in the ARG command. See section 3.2 ARG – Retrieve the parameter string on page 31. The PARSE ARG command is the only PARSE command, wherein a plurality of input variables can be resolved. This is necessary to permit the transfer of parameters to single variables in a subroutine or function.

3.9.2 PARSE VALUE ….. WITH The fractionized text can be an expression here. The default separator is a blank. Several blanks can stand between the individual words. Example: PARSE VALUE "My

name

is Hugo

" WITH v1 v2 v3 v4

The results of this command are: v1 = "My", v2 = "name", v3 = "is", v4 = " Hugo

"

Now the question comes up: Why does the variable W4 not only contain the word Hugo, but one blank before and four blanks behind while W3 includes only the text is, but also the three blanks before the word is? To answer this question we have to look at a special rule in the application of PARSE command now: 3 Rule: The last variable in the template of a PARSE command contains all characters that are still present after the assignment of the value of the penultimate variable. This rule applies to all versions of the parse command.

Why we have this rule? Based on the realization that you should have the opportunity in fractionizing texts, this rule has been created to proceed in several steps in order to completely fractionize differently structured texts. As a consequence, it may be well useful to always assign the last variable throughout the rest of the text without any compromises. You can then decompose this last variable in the next PARSE step. How do you get around this rule? This rule can be bypassed by inserting a dot as a dummy variable after the last regular variable. This would look like this: PARSE VALUE "My

name

is Hugo

" WITH v1 v2 v3 v4 .

The value in v4 is then only Hugo without the trailing blanks.

3.9 PARSE – text fragmentation | 49

Example of the use of PARSE VALUE …. WITH This example shows different variations for the dissection of DATA and TIME values. Program 3.5: Example showing variations for the dissection of DATA and TIME values 01 /* DOC: REXX PARSE1 */ 02 /* DOC: Some dissection examples using PARSE VALUE ? WITH */ 03 /* © FRANZ LANZ 2015 */ 04 /*************************************************************/ 05 say "05 " date() 06 say "06 " time() 07 /* The separation character is a blank. */ 08 parse value date("N") with day month year . 09 say "08 Separation char. is blank >"day""month""year""yyyy""mm""dd""yyyy""mm""dd""hrs""min""sec""hrs""min""sec""hrs""min""sec""hrs""min""sec" 0 then do zedlmsg = " Error: The variables ACCOUNT JOBCLASS MSGCLASS", "could not be read correctly from the profiles Pool.", "Procedure ends." address "ISPEXEC" "SETMSG MSG (ISRZ001)" exit end uid = userid() jobname = uid!!jobsuff() queue "//"jobname" JOB ("account"),'"uid" COMPRESS'," queue "// NOTIFY="uid",MSGLEVEL=(0,0),MSGCLASS="msgclass"," queue "// USER="uid",CLASS="jobclass queue "//COMPRESS EXEC PGM=IEBCOPY,REGION=20M" queue "//SYSPRINT DD SYSOUT=* " queue "//SYSUT1 DD DISP=SHR,DSN="dsn queue "//SYSUT2 DD DISP=SHR,DSN="dsn queue "//SYSUT3 DD UNIT=VIODA,SPACE=(CYL,(10,10))" queue "//SYSUT4 DD UNIT=VIODA,SPACE=(CYL,(10,10))" queue "//SYSIN DD DUMMY" queue /* This 'no value' queue statement is very important */ x = outtrap(text.) /* TSO messages are put into stem text. */ "submit *" x = outtrap("OFF") /* outtrap is switched off */ zedlmsg = text.2/* text.2 contains the submit confirm message */ "ISPEXEC SETMSG MSG(ISRZ001) COND" exit

Example 2: Exchange of data with an external subroutine In the following example, a file containing names will be read in a REXX main program. These names will be sorted in an external subprogram. The sorted names are returned to the main program. Here the main program is NAMSORT. The greyed lines are important:

56 | 3 The REXX commands

Program 3.8: Program NAMESORT to sort names /* DOC: REXX NAMSORT */ /* DOC: Example for the exchange of data between a main and a */ /* DOC: sub-program using the Data Stack */ /* (c) LANZT */ /******************************************************************/ "alloc dd(in) dsn('LANZT.NAMES.UNSORT') shr reuse" "execio * diskr in (finis" /* read names direct into data stack */ "free dd(in)" call nsort do i = 1 to queued() pull name say name end exit

Here the subroutine NSORT: Program 3.9: Subroutine NSORT /* DOC: REXX NSORT

*/

/* DOC: Subroutine for sorting a data set of unsorted names. */ /* DOC: The names are contained in the data stack and are returned*/ /* DOC: to the main program after sorting. */ /* © FRANZ LANZ 2015 */ /******************************************************************/ nsort: irec = queued() /* Get number of elements in the data stack. */ /******************************************************************/ /* Copy the data stack contents into stem t. */ /******************************************************************/ do i = 1 to irec; pull name; t.i = name; end i /******************************************************************/ /* Sort the stem i. using the bubble sort method */ /******************************************************************/ do l = 1 to irec do m = l+1 to irec s = t.l if t.m < s then do; t.l = t.m; t.m = s; end end m end l /******************************************************************/ /* Copy the content of the stem back to the data stack. */ /******************************************************************/ do i = 1 to irec; queue t.i; end i return

Tips: –

If the data stack is to be read by a command that expects this null string, never forget the final QUEUE command with no operands. See the last QUEUE command in Program 3.7: Assemble and submit a COMPRESS job on page 55. This error can make very unpleasantly: If you run the procedure online and an EXECIO or SUBMIT command reads the data stack, then the attempt to read the appropriate command terminates only upon reaching a null string entry. If this null entry is not found, then the command tries to read more data from

3.12 SELECT – Conditionally call alternative instructions | 57

– –

the terminal, namely your screen. You realize this because that on the screen nothing moves anymore after you have invoked the procedure which is a surprise. In this case, your screen will just stand and wait for an input. Because you do not know what is going on, you think that the system hangs. Only when you press ENTER, the read command gets its long-awaited null string and it continues. In the EXECIO command, you can omit the terminating null string if you write the command like this: "execio "queued()" diskw out (finis". This trick does not work on the SUBMIT command, because there is only the asterisk (*) specified in that command indicating that the data are read from the stack. However, you can mark the end of the data stream with a special end line that contains exactly two characters when using the SUBMIT command. The two characters in the last row are then specified when running the SUBMIT command: queue "XX" "submit * end(XX)".

3.12 SAY – Print texts With the SAY command, you can output any text from a REXX program. This command is very well suited as a debugging aid and for the issue of control information. If a REXX program runs in a batch job, the output of SAY messages happens via the DD statement SYSTSPRT. In the previous shown programs a number of SAY commands are contained. Therefore, I will refrain from giving more SAY examples.

3.13 SELECT – Conditionally call alternative instructions The SELECT statement can build very efficient condition controls. This command executes program parts selectively under certain conditions. In addition to the DO group, the SELECT statement is the most important element to generate GOTO free REXX code. Rules: – – –

The SELECT statement opens a set of condition queries. It must be terminated with an END. The condition queries can consist of any number of WHEN statements that run from top to bottom in sequence until one of the WHEN conditions is true. If the first WHEN condition is detected as true, then the following REXX command will be executed. The SELECT sequence is at the END left belonging to the SELECT statement.

58 | 3 The REXX commands

– – – –





If none of the WHEN conditions are true, then the REXX command in the OTHERWISE statements is executed. The OTHERWISE statement is mandatory. It must be inserted immediately before the END statement belonging to the SELECT. Behind OTHERWISE any number of statements can follow without requiring them to be included in a DO group. The interpreter only notices the absence of the OTHERWISE condition, if for any current program run none of the WHEN conditions is true. In this case, a program termination occurs. This means on this way you can install a time bomb in your program. Therefore, you should never forget the OTHERWISE statement before the END of a SELECT sequence. Once one of the WHEN conditions meets, then the following conditions are ignored and their program code will no longer go through. If these skipped commands errors contain such as wrong contents in numerical operations, these errors are only recognized when these commands are actually be executed. Behind the WHEN keyword all possibilities that the IF statement knows can be used.

Example 1: Simple SELECT structure This example shows a simple SELECT structure. select SELECT when substr(in.i,54,1) when substr(in.i,72,1) when substr(in.i,72,1) when substr(in.i,72,1) when substr(in.i,72,1) when substr(in.i,72,1) otherwise nop end /* Select */

= = = = = =

"A" "P" "M" "I" "S" "B"

then then then then then then

iobjtname iobjtname iobjtname iobjtname iobjtname iobjtname

= = = = = =

"CICSSUBR" "CICSMAIN" "CICSMASK" "INCLUDE" "TEXT" "DB2BIND"

Example 2: A slightly more complex SELECT structure: Here are the commands to execute in DO groups arranged. select when iobjtname = iobjname = iobjtname = iobjspname = end when iobjtname = iobjtname = iobjspname = end when iobjtname = iobjtname = iobjspname = end otherwise iterate end /* Select */

"CICSMAIN" then do "L"iobjname "LOADCICSMAIN" "LOAD" "CICSSUBR" then do "LOADCICSSUBR" "LOAD" "CICSMASK" then do "LOADCICSMASK" "LOAD" i

3.13 SELECT – Conditionally call alternative instructions | 59

Example 3: A complex SELECT sequence: Depending on the result of the SYSDSN function, various actions will be performed. sysdsnret = sysdsn("'"outdsn"'") select when sysdsnret = "OK" & reuse = "J" then do x = listdsi("'"outdsn"'") if sysdsorg = "PO" then do zedsmsg = "DSORG wrong" zedlmsg = "The specified data set is a PO data set. This is", "as an output data set not allowed." "ISPEXEC SETMSG MSG(ISRZ001)" return(4) end /***************************************************/ /* Determine possible ENQs on the source file */ /***************************************************/ enqs = "" x = outtrap(has.) address "TSO" "WHOHAS "outdsn whorc = rc x = outtrap("OFF") if whorc > 0 then do select when whorc = 11 then do zedsmsg = "ENQ are found!" zedlmsg = "There were more than 100 ENQs on that data set.", "This data set cannot be used for processing." "ISPEXEC SETMSG MSG(ISRZ001)" return(4) end otherwise do if has.0 > 11 then iend = 12 else iend = has.0 do iwh = 3 to iend enqs = enqs word(has.iwh,5) end iwh zedsmsg = "ENQ found!" zedlmsg = "The following ENQs are found on this data set.", enqs, "This data set cannot be used for processing." "ISPEXEC SETMSG MSG(ISRZ001)" return(4) end end /* select */ end "DELETE '"outdsn"'" "alloc dd(datout) dsn('"outdsn"') new reuse", "space("trk trk") tracks storclas("storclas")", "recfm(v b) lrecl("lrecl") blksize(27998)" end when sysdsnret = "OK" & reuse "J" then do "ISPEXEC ADDPOP" "ISPEXEC DISPLAY PANEL(INSMAKE1)" "ISPEXEC REMPOP" if relkz "J" then return(4) outdsn = outdsn".$" insdsn = outdsn "ISPEXEC VPUT (INSDSN) PROFILE" "alloc dd(datout) dsn('"outdsn"') new reuse", "space("trk trk") tracks storclas("storclas")", "recfm(v b) lrecl("lrecl") blksize(27998)" end when sysdsnret = "DATASET NOT FOUND" then do "alloc dd(datout) dsn('"outdsn"') new reuse", "space("trk trk") tracks storclas("storclas")", "recfm(v b) lrecl("lrecl") blksize(27998)" end

60 | 3 The REXX commands

otherwise do zedsmsg = "SYSDSN Error " zedlmsg = sysdsnret "ISPEXEC SETMSG MSG(ISRZ001)" return(4) end end /* select */

1 Tip: I set behind END of the SELECT structure always the comment /* Select */. Sometimes I number the SELECT - END sequences within a program. This increases the overview in very long and nested sequences. Never forget the OTHERWISE statement!

3.14 NOP – No operation This is a very simple statement. NOP stands for "NO OPERATION", meaning that nothing is running. NOP is very often in OTHERWISE statements used. See the example in the previous tip.

3.15 PULL – Enter data on the screen The only reason why I am mentioning this command here is to warn you of the pitfalls of this command. This is a very rarely needed command in fact. The command operates as follows: – If the data stack contains data, then the PULL reads from the data stack. – Only when there is nothing in the data stack, then PULL reads from the terminal. If you want to read something from the terminal, you have two options: – You can define a small panel for the input of data. I always use this way when I want to enter the user data on the screen. This offers much better ways of setting of texts and the plausibility check of the entered values. – You tell the user using the command SAY what to enter now and then issue the command PULL. 1 Tip: If you believe that you must always use the PULL command, then I urge you to insert a query previously that determines whether the data stack is actually empty. If necessary, you can clear the data stack before you use the PULL command. It could look like this: do i = 1 to queued(); pull xxx; end i; /* Queue empty */ pull value /* Read from the terminal */

3.16 TRACE – The strong debugging aid | 61

3.16 TRACE – The strong debugging aid If you are involved in application development, you certainly know the various debugging aids. As REXX is an interpreted language, of course, the test aids can be very elegantly defined and used here. For a detailed description of the TRACE command, refer to the brochure TSO/E REXX Reference. I use in practice mostly the commands trace?i and trace ?r. By specifying the question mark (?), the interpreter stops after each executed command and you can then enter your own commands manually. These commands will be executed immediately. The possibility of direct entry of commands can also be used to disable a running TRACE with TRACE O. The program runs then so long without TRACE until another TRACE statement is executed in the program, or until the program ends. Program 3.10: POWER2 – Trace example /* DOC: REXX POWER2 *****************************************/ /* DOC: Procedure for generating a list of powers of 2 */ /* © FRANZ LANZ 2015 */ /*************************************************************/ trace ?i numeric digits 30 do I = 1 to 64 value = right("2**"i,10) right(strukt(2**i),30) queue value say value end i address TSO "alloc dd(ut) dsn('pevx.logon.rexx(bintab)')," "reuse shr" address TSO "execio "queued()" diskw ut (finis" "free dd(ut)"

When I run this procedure online, I get the following messages on the screen: 6 *-* numeric digits 30 >L> "30" +++ Interactive trace. ENTER to continue.

TRACE OFF to end debug,

7 *-* do I = 1 to 64 >L> "1" >L> "64" 8 *-* >L> >V> >O> >L> >F> >L> >V> >O> >F> >L> >F> >O>

value = right("2**"i,10) right(strukt(2**i),30) "2**" "1" "2**1" "10" " 2**1" "2" "1" "2" "2" "30" " 2" " 2**1 2"

62 | 3 The REXX commands

9 *-* >V> trace o 2**1 2**2 2**3

queue "

value 2**1

2" 2 4 8

I turned off tracing by the direct input of the command TRACE O. Thereafter, the program runs normally to the end. How you see the VALUE = ... TRACE from the calculation in the line, the individual calculation steps are listed in detail. 1 Tip: I strongly recommend to practice intensively the TRACE command, because it is a powerful aid in creating REXX applications.

3.17 SIGNAL – Jumping when errors There are three main forms of the SIGNAL command: SIGNAL label SIGNAL ON errortype NAME label SIGNAL VALUE expression

Using the first way you can jump directly to a label in the program. This use of the SIGNAL instruction corresponds to a GOTO in other programming languages. 3 Note: I cannot remember having ever used the SIGNAL command to jump to another location in the program, because I develop in REXX just GOTO free program code.

With the second type, at the beginning of the program traps can be set to cause the interpreter to jump there in the event of an error. The third type of command can be specified as an internal branch address of a program in expression. There is then jumped after EXPRESSION is resolved.

4 The REXX functions Functions play an important role in REXX. In particular, the functions for word and string processing. When you have worked through the next chapter, you might be amazed about what you can do with the REXX functions. So, have fun reading about the REXX functions! The REXX language we can use on z/OS TSO/E consists of two blocks of language elements: – The REXX commands, as we learned in chapter 3 The REXX commands on page 25. – The large stock of standard functions that belong to the REXX language and which we will discuss in this chapter. We now turn to the second part, the REXX functions. I will not discuss any function that is described in the brochure TSO/E REXX reference, but only those that are in my opinion often needed in practice. How functions are called, I have explained already in the section 3.3 CALL – Call other programs on page 35. There we already talked about the topics parameter input and return of the results. The REXX functions can be divided into groups by application area. I have made the following division into groups for the presentation of the REXX functions in this book. Table 4.1: REXX function groups

Function group

On page

General Functions

64 .

Arithmetic Functions

72 .

Comparison Functions

74 .

Conversion Functions

77 .

Formatting Functions

82 .

String Functions

85 .

Word Functions

90 .

System Functions

92 .

,

,

,

,

,

,

,

,

The number of available standard functions is larger than the number of instructions in the REXX language. This lets you know how important the knowledge of the functions in REXX is. Through internal and external programs, you can easily create your own, new features and thereby extend your pool of available functions arbitrarily.

64 | 4 The REXX functions

General rules for the use of functions: – – – –

The REXX interpreter recognizes a function call when parentheses follow the function name. The functions are usually called with parameters which are written in the parentheses. Some functions return a value even if no parameters have been entered. In this case, the parentheses must still be set. Then they remain empty. The left parenthesis must always follow immediately the function name without any blanks, otherwise the function name will be assumed as REXX command. If this rule is not adhered, then a program abort occurs.

In the headings of the following functional descriptions, I will omit the parentheses respectively.

4.1 General functions 4.1.1 ADDRESS – Get the active host command environment This function returns the name of the current host command environment. No parameters can be entered. Function: Returns the currently active host command environment. Format: name = address()

A host command environment, whose name was written by the ADDRESS function to a variable, can only be restored by using the following commands. – By setting the variable in surrounding parentheses. – By using the REXX VALUE function. The following example shows the two variants: envir = address() /* Save the current active HCE in envir */ /* processing */..... address (envir) /* These both commands restores the HCE */ address value envir /* saved in envir */

HCE  Host Command Environment See also the section 3.1 ADDRESS – Connection to the subsystems on page 25.

4.1 General functions | 65

4.1.2 ARG – Input parameter test or take The ARG function has three application forms: – Determining the number of input parameters. – Testing for the presence of certain input parameters. – Taking single or all the parameters. Format: ARG(n,option) n

option

Means the nth parameter. If specifying this option, the contents of the nth parameter will returned. If this parameter is not set, a null string will be returned. e Returns 1 if the nth parameter is available. Otherwise, 0 is returned. o Returns 1 if the nth parameter is not available. Otherwise, 0 is returned.

Examples: /* Call name (no arguments) */ ARG() -> 0 ARG(1) -> '' ARG(2) -> '' ARG(1,'e') -> 0 ARG(1,'O') -> 1 /* Call name 'a',,'b'; /* (three arguments) na = ARG() -> 3 a1 = ARG(1) -> 'a' a2 = ARG(2) -> '' a3 = ARG(3) -> 'b' ARG(n) -> '' /* for n >= 4 */ ARG(1,'e') -> 1 ARG(2,'E') -> 0 ARG(2,'O') -> 1 ARG(3,'o') -> 0 ARG(4,'o') -> 1

*/

4.1.3 DATE – Date functions The DATE function returns the current date in many different forms. Moreover, you can perform with the DATE function also date calculations. Function: The DATE function is applicable for two purposes: – Return of the current date in different forms. – Calculation of date values.

66 | 4 The REXX functions

On the following pages, I will explain these two variants in detail. 1.

Return the current date

Returns today’s date back in different forms. Format: today_date = DATE(format)

It returns the current date in the notation defined in the format. The possible entries for format and the resulting return values are summarized in the following table. Only the first letter is entered to define the format. Table 4.2: Parameters of the DATE function

Format

Returned value

Base

Days since January 1, 0001 without the present day. The format wd = date("B") // 7 can be used to determine the current day of the week. 0 is Monday and 6 is Sunday.

Century

Days since January 1 of the current century, including today.

Days

Days since January 1 of the current year, including today.

European Date in European format: DD/MM/YY Julian

Date in the form: YYDDD this means Julian Day.

Month

English name of the month in upper and lower case. For example, January.

Normal

Date in the format: DD Mon YYYY. Mon is the short form of month: Jan, Feb, Mar, etc. This is the default setting, if no parameter is entered.

Ordered

Date in the format: YY/MM/DD.

Standard Date in the format: YYYYMMDD. Usa

Date in the American format: MM/DD/YY.

Weekday English weekday. Monday, Tuesday, etc.

Example DATE output: DATE() DATE('B') DATE('C') DATE('D') DATE('E') DATE('J') DATE('M') DATE('N') DATE('O') DATE('S') DATE('U') DATE('W')

--> --> --> --> --> --> --> --> --> --> --> -->

29 Apr 2004 731699 1581 120 29/04/04 04120 April 29 Apr 2004 04/04/29 20040429 04/29/04 Thursday

4.1 General functions | 67

2.

Date calculations using the DATE function

With the DATE function, you can perform some date conversion to another format and date calculations. Format: result = DATE(format1,input,format2)

Rule: The date specified in input is converted to the format specified in format1. Format2 is mandatory; it defines the format of input. Input can also be a DATE function.

To demonstrate these capabilities of the DATE function, I wrote and performed a small REXX procedure. See the result here: Todays date = 29 Apr 2004 Calculation: Today minus 200 days, result in N (DD Mon YYYY) Statement : date("N",date("B") - 200,"B") Result : 12 Oct 2003 Calculation: S date plus 100 days, result in S (YYYYMMDD) Statement : date("S",date("B",20040101,"S") + 100,"B") Result : 20040410 Calculation: Today plus 360 days, result in E (DD/MM/YY) Statement : date("E",date("B") + 360,"B") Result : 24/04/05 Conversion : S format (YYYYMMDD) in N format (DD Mon YYYY) Statement : DATE(,"20020609","S") Result : 9 Jun 2002 Conversion : N format (DD Mon YYYY) in B format Statement : DATE("B","25 Sep 2001") Result : 730752 Conversion : C format (DDDD) in N format (DD Mon YYYY) Statement : DATE("N","1000","C") Result : 26 Sep 2002 Conversion : O format (YY/MM/DD) in U format (MM/DD/YY) Statement : DATE("U","03/08/15","O") Result : 08/15/03 Conversion : J format (YYDDT) in E format (DD/MM/YY) Statement : DATE("E","01101","J") Result : 11/04/01

68 | 4 The REXX functions

3 Note: For conversions and calculations, formats C and J cannot be used as a result. This is a shame, because conversions into the J format are often necessary in practice.

4.1.4 TIME – Time functions The TIME function returns the current date in many different forms. Moreover, you can perform with the TIME function also date calculations. Function: The TIME function provides two ways to use it: – Returns the current time of day. – Starting and stopping the difference timing measurement. Format: Time = TIME(format)

The following table shows which options can be set with format and which results TIME then provides. Table 4.3: Options of the TIME function

Format

Return value

Civil

Time of day in the form HH:MMxx, where xx can be either am or pm. This is for American time information.

Elapsed Result is the time in the form SSSSSSSSS.UUUUUU, where seconds are before the decimal point and the decimals of seconds behind. With this form, the stopwatch is started. Each subsequent call with this form gives the elapsed time back since the first call. Hours

Returns the hour of day in one or two digits.

Long

Returns the time in the format HH:MM:SS.UUUUUU. The digits after the decimal point are microseconds.

Minutes Returns the minutes that have elapsed since midnight. Normal

Returns the time in the form HH:MM:SS. This is the default.

Reset

Specifies the time back since the start or the last reset of the timer and resets the stopwatch to zero.

Seconds Returns the seconds that have elapsed since midnight.

4.1 General functions | 69

Examples of the return time of day TIME() TIME('C') TIME('H') TIME('L') TIME('M') TIME('N') TIME('S')

--> --> --> --> --> --> -->

17:40:23 5:40pm 17 17:40:23.656081 1060 17:40:23 63623

Examples of the time measurement TIME('E') --> 0 TIME('R') --> 0.000530

Between the call with the format E and the call with the format R 530 microseconds have elapsed.

4.1.5 QEUED – Number of records in the data stack Function: Returns the number of records in the TSO data stack. Format: Number = QUEUED()

Returns the number of records currently contained in the data stack. No parameters can be entered. A return value of zero indicates an empty data stack.

4.1.6 SOURCELINE – Return a program line Function: – –

Returns the number of lines of source code. Returns the text of a line from the source code of the program.

Format: Number = SOURCELINE()

Returns the number of lines of the source code. Text = SOURCELINE(n)

Returns the contents of the nth row. n must be entered.

70 | 4 The REXX functions

Example: With the following DO loop, you can run through all lines of program code: do i = 1 to sourceline() line = sourceline(i) /* Processing the source line */ end i

4.1.7 USERID – Return the TSO user ID Function: Return of the TSO user ID. Format: user = userid()

4.1.8 VALUE – Create variable names dynamically Function: Generating a value, which consists of a combination of variables and constants. Format: value = VALUE("XYZ"var)

The VALUE function dynamically generates a value consisting of constant and variable parts. The variables are replaced by their contents. This command works similarly to the INTERPRET instruction. However, while INTERPRET always constitutes the entire command and then executes it, returns VALUE only the assembled value. Example: The edit macro #TSOB from the SMART ISPF utilities submits REXX procedures currently being edited to run in a batch. In this batch job either a variable number of STEPLIB DSNs and a variable number of SYSEXEC DSNs can occur. The SMART ISPF utilities program SPROFVAR stores this information into the ISPF user profiles. The organization of the variable is as follows: The profile variables SYSEXEC and STEPLIB each contains the number of existing DSNs for this type that are to be included in the batch job. The corresponding DSNs are then in the variables SYSEXECn and STEPLIBn, where n is from 1 to content of SYSEXEC and STEPLIB respectively.

4.1 General functions | 71

The following commands define the variables. That is their content in the profile pool. sysexec steplib sysexec1 sysexec2 sysexec3 sysexec4 steplib1 steplib2 steplib3

= = = = = = = = =

4 3 "PROX.LANZ.REXX" "PROX.LOGON.REXX" "SMQP.USER.CEXEC" "SMQP.PROD.CEXEC" "PROX.LOGON.LOAD" "DB2P.ALIAS.DSNLOAD" "SMQP.LOAD"

Subsequently, the program section from the edit macro #TSOB that reads the variables from the profile and includes them in the JCL: /******************************************************************/ /* Reading the environment variables */ /******************************************************************/ "ISPEXEC CONTROL ERRORS RETURN" "ISPEXEC VGET (SYSEXEC STEPLIB", "ACCOUNT JOBCLASS MSGCLASS) PROFILE" if rc > 0 then do zedlmsg = " Error: Variable could not correctly read from ", "profile pool. Procedure exits." if zerrlm "ZERRLM" then zedlmsg = zedlmsg strip(zerrlm) address "ISPEXEC" "SETMSG MSG(ISRZ001) COND" exit end /******************************************************************/ /* Assemble the batch job */ /******************************************************************/ jobname = userid()jobsuff() queue "//"jobname" JOB ("account"),'#TSOB: "mem"',CLASS="jobclass"," queue "// NOTIFY="userid()",MSGLEVEL=(0,0),MSGCLASS="msgclass"," queue "// COND=(0,LT),TIME=100,USER=SQMTP" queue "//"copies("*",68) queue "//* TSO-BATCH FROM: "dsn"("mem")" queue "//"copies("*",68) queue "//TSOBATCH EXEC PGM=IKJEFT01,REGION=80M,DYNAMNBR=99" if steplib > 0 then do "ISPEXEC VGET (STEPLIB1) PROFILE" if rc > 0 then call ispf_error rc "VGET STEPLIB1" queue "//STEPLIB DD DISP=SHR,DSN="steplib1 do i = 2 to steplib "ISPEXEC VGET (STEPLIB"i") PROFILE" if rc > 0 then call ispf_error rc "VGET STEPLIB"i queue "// DD DISP=SHR,DSN="value("steplib"i) end i end queue "//SYSEXEC DD DISP=SHR,DSN="dsn if sysexec > 0 then do i = 1 to sysexec "ISPEXEC VGET (SYSEXEC"i") PROFILE" if rc > 0 then call ispf_error rc "VGET SYSEXEC"i queue "// DD DISP=SHR,DSN="value("SYSEXEC"i) end i

The rest of the procedure is suppressed.

72 | 4 The REXX functions

4.2 Arithmetic functions In the following sections, I will discuss functions relating to various ways of treatment and control of arithmetic operations.

4.2.1 ABS – absolute value of a number Function: Returns the absolute value of a number. Format: result = ABS(number)

This function returns the unsigned absolute value of a number. The format of the returned number is obtained from the currently valid NUMERIC options. Examples: ABS(-2/3) 0.666666667 ABS('-0.307') 0.307

4.2.2 DIGITS, FORM, FUZZ – Query options for arithmetic operations These three functions query the values that apply just for performing arithmetic expressions. This information can also be obtained by the PARSE NUMERIC var command. Example: numeric digits 12 numeric fuzz 3 parse numeric nums dig = digits() fuz = fuzz() for = form() say "Values from PARSE say "Values from funktions

= "nums = "dig fuz for

Here the results when calling this procedure: Values from PARSE Values from functions

= 12 3 SCIENTIFIC = 12 3 SCIENTIFIC

4.2 Arithmetic functions | 73

4.2.3 MIN, MAX – Minimum and maximum value These functions return the minimum or maximum value of a set of numbers that are entered as a single parameter. In a parameter list, a maximum of 20 values can be entered. However, since these functions could be interleaved, a maximum of 20 × 20 = 400 numbers are possible in one function call.

4.2.4 RANDOM – Generate random numbers Function: This function generates a random number within a lower and an upper limit. Format: number = random(start,end[,ind]) start end ind

lower limit of the number space upper limit of the number space base number by which one can achieve the reproducibility.

Example: In this example, it is shown that with repeated calls always the same random numbers are received when using the same number for option ind. Program 4.1: RAMDOM – Generate random numbers /* DOC: REXX RANDOM */ /* DOC: Example for the generation of random numbers*/ /* © FRANZ LANZ 2015 */ /****************************************************/ nnn = "" do 10; nnn = nnn random(1,1000); end say nnn txt = random(1,1000,12) do i = 1 to 10; txt = txt random(1,1000); end i say txt seq = random(1,12,1) do i = 1 to 10; seq = seq random(1,12); end i say seq txt = random(1,1000,12) do i = 1 to 10; txt = txt random(1,1000); end i say txt seq = random(1,12,1) do i = 1 to 10; seq = seq random(1,12); end i say seq

This is the printout of the above program:

74 | 4 The REXX functions

311 976 3 8 976 3 8

886 509 2 6 509 2 6

265 230 967 115 390 676 577 161 127 16 332 637 364 595 134 852 333 5 11 2 4 12 5 9 127 16 332 637 364 595 134 852 333 5 11 2 4 12 5 9

As you can see, in rows 2 and 4 plus 3 and 5 respectively appear the same numbers, because in the corresponding RANDOM calls a base number was specified. It is irrelevant what base number you choose.

4.2.5 SIGN – Return of the sign Function: Returns the sign of a number. Format: value = sign(number)

SIGN returns the sign of the number specified by the following rules: number > 0  number = 0  number < 0 

value= 1 value= 0 value= -1

4.3 Comparison Functions Besides the possibility of comparisons using the IF command, there are some functions that you can use to perform comparisons in REXX. The most important function is DATATYPE, because without this function plausibility checks of numerical data could not be performed.

4.3.1 COMPARE – Compare texts Function: This function returns a zero if the two texts are equal. If the texts are not equal, the position of the character returns from where on the texts are not equal. Format: result = COMPARE(text1,text2[,filler]) text1,text2 filler

The texts to compare. The shorter of the two texts is expanded with the filler before comparison. The default character is a blank.

4.3 Comparison Functions | 75

3 Note: I have never needed this feature because this function can be carried out with the normal logical text comparisons operands, too. However, if you want to find the position from which the inequality begins, COMPARE is very useful.

4.3.2 DATATYPE – Determine data type Function: This is a very important function. It is always required to make sure before an arithmetic operation that all participating operands are of type NUM. Format: result = datatype(text,[type]) result

text type

It is NUM if text contains a number that can be used in arithmetic operations. It is CHAR in all other cases This is the text, which shall be examined. When only this parameter is specified, then the function returns the values NUM or CHAR. When type is specified, then the function returns 1 if the text contains only elements of the entered type property, otherwise 0.

With type, the following properties can be queried: Table 4.4: DATATYPE type options

Type

Properties

A

Text consists entirely of alphanumeric characters (a-z, A-Z, 0-9).

B

Text consists entirely of binary digits (0-1)

L

Text contains only lowercase letters (a-z)

M

Text contains only letters (a-z, A-Z)

N

Text is a valid REXX number

S

Text is a valid symbol in REXX (e.g. a variable name)

U

Text contains only uppercase letters (A-Z)

W

Text contains an integer

X

Text contains only hexadecimal digits (a-z, A-Z, 0-9) and blanks can stand between hex pairs. Null string is also a hexadecimal character.

76 | 4 The REXX functions

Example: The following program lines come from a program that performs date conversions of the format YYYY/MM/DD in the format YYYY/DDD (Julian date) and vice versa. Before in the program any arithmetic operations are be executed check whether all input values are numeric. See the following statements: 24 25 26 27 28

parse var indat yyyy"/"mm"/"dd . if (datatype(yyyy,"N") * datatype(mm,"N") *, datatype(dd,"N") = 0) then return("error") if mm > 12 | dd > 31 !, (yyyy * mm * dd = 0) then return("error")

The PARSE command in line 24 parses the number entered in the variables YYYY, MM and DD. The IF statement in line 25 checks whether all three values are numeric. It works like this: The DATATYPE function returns for all tests in which a correct number is found 1, otherwise 0. If only one of the tests provides 0, then the multiplication of all three tests is 0. This means that at least one value is not numeric. 4 Caution trap: If anyone thinks now "You can do this much better by contracting the two IF statements in lines 25 and 27 into one IF statement." Then I can only say, "You have traded with lemons!" Why does this not work properly? This does not lead until then to an error if the program is actually called with wrong input values. Because then the following happens: All arithmetic operations of IF statements are executed to determine the result. This means in our case that the multiply operation yyyy*mm*dd is executed to complete the IF statement. Therefore, if one of the values contains a nonnumeric character, the program will cancel. Therefore, if someone should resist the temptation to contract these two IFs in one thing, he has built a classic time bomb here. The issue works until an incorrect value actually appears.

So, remember the following rule: 3 Rule: Before you perform any arithmetic operations in a statement, you must previously perform tests in which no arithmetic operations occur, to ensure that all involved values are numerical!

By the way, what is the most embarrassing error in the programming? 4 The most embarrassing programming error: Suppose you installed an extensive plausibility test in your program and this breaks in the reasonableness test without reporting the user’s error. Then it is a bad thing for the user, because he does not know what he did wrong.

4.4 Conversion functions | 77

4.4 Conversion functions With these functions, you can convert texts and numbers in other internal representations. Normally, you do not really need these features since in the TSO/REXX environment everything is very simple: All internal data representations are essentially stored in EBCDIC format. This means that: – The number 1234567 is internally stored in seven bytes, with the following hexadecimal representation: "F1 F2 F3 F4 F5 F6 F7" X. In general, this representation is called the unpacked format. – The text "I am happy!" has internal a length of 11 bytes and consists of the following hexadecimal characters: " C9 40 81 94 40 88 81 97 97 A8 5A" X. The conversion functions are always very useful when values have to be converted into other forms of representation. Example: This small REXX program determines the job name directly from the system tables of z/OS. Screen 4.1: Read the job name from CVT /* DOC: REXX JOBNTSO */ /* DOC: Determine the job name using the CVT of z/OS */ /* DOC: CVT = Common Vector Table */ /* © FRANZ LANZ 2015 */ /***********************************************************/ CVT = STORAGE(10,4) /* FLCCVT-PSA DATA AREA */ TCBP = STORAGE(D2X(C2D(CVT)),4) /* CVTTCBP */ TCB = STORAGE(D2X(C2D(TCBP)+4),4) /* TCB */ TIOT = STORAGE(D2X(C2D(TCB)+12),4) /* TCBTIO */ SAY STRIP(STORAGE(D2X(C2D(TIOT)),8)) /* TIOCNJOB */ EXIT

If you have the necessary knowledge of the z/OS operating system, try to decipher the REXX commands. Find the necessary knowledge about the conversion instructions in the following subsections. Of course, here all people who have ever programmed in assembler have an advantage. This applies to all conversion functions.

4.4.1 C2D – Character to decimal Function: This function returns the decimal value of a text. By specifying a length, negative numbers can be converted.

78 | 4 The REXX functions

Format: number = C2D(text,[n]) text n

This text is as binary text considered whose decimal value returned is. If specified, this number indicates how many bytes are converted from text from the right. Is the first (i.e. the leftmost) bit of that number 1, then the number is output as a negative number in the two’s complement.

3 Advice: When using this function, it is important to ensure that NUMERIC DIGITS are set large enough. Otherwise, the call to C2D ends with an error.

In the following small program, I have compiled several calls to the C2D function. I think that you can understand the operation of C2D well. Program 4.2: Program to show C2D functionality /* DOC: REXX C2D *************************************************/ /* DOC: Examples of convert function C2D */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ numeric digits 22 say right(c2d("00000001"x),22) /* A number one */ say right(c2d("7fffffff"x),22) /* Largest positive number in word */ say right(c2d("7fffffff"x,4),22) /* Largest positive number in word */ say right(c2d("80000000"x,4),22) /* Largest negative number in word */ say right(c2d("7fffffff"x,1),22) /* Only the rightmost byte */ say right(c2d("7fffffff"x,2),22) /* Only the rightmost 2 bytes */ say right(c2d("00007fff"x,2),22) /* Largest positive nbr in halfword */ say right(c2d("00008000"x,2),22) /* Largest negative nbr in halfword */ say right(c2d("0000007f"x,1),22) /* Largest positive number in bytes */ say right(c2d("00000080"x,1),22) /* Largest negative number in bytes */ say right(c2d("000000ff"x ),22) /* Largest nbr in bytes without sign*/ say right(c2d("12345678" ),22) /* Binary value of EBCDIC 12345678 */ say right(c2d("ABCDEFGH" ),22) /* Binary value of EBCDIC ABCDEFGH */

I have run the program. See the results below: c2d("00000001"x)  c2d("7fffffff"x) c2d("7fffffff"x,4)  c2d("80000000"x,4)  c2d("7fffffff"x,1)  c2d("7fffffff"x,2)  c2d("00007fff"x,2)  c2d("00008000"x,2)  c2d("0000007f"x,1)  c2d("00000080"x,1)  c2d("000000ff"x )  c2d("12345678" ) c2d("ABCDEFGH" )

1 2147483647 2147483647 -2147483648 -1 -1 32767 -32768 127 -128 255 17434265340928784376 13961937044701104072

4.4 Conversion functions | 79

4.4.2 C2X – Character to Hexadecimal Function: This function returns the entered text in its hexadecimal notation. The output is then twice as long as the text entered. Format: number = C2X(text)

This text is an EBCDIC string, which is returned in hexadecimal representation.

text

Examples: say say say say

c2x("1234567890") c2x("ABCDEFGHIJ") c2x("abcdefghij") c2x("!'§$%&/()=")

/* /* /* /*

is is is is

in in in in

hex:F1F2F3F4F5F6F7F8F9F0*/ hex:C1C2C3C4C5C6C7C8C9D1*/ hex:81828384858687888991*/ hex:4F7D7C5B6C50614D5D7E*/

4.4.3 D2C – Decimal to Character Function: With this function, you can convert a decimal number to the EBCDIC character format. Format: chars = D2C(number,[n]) number n

This is a decimal number whose content is returned in EBCDIC characters. If specified, this number indicates how many bytes are returned after the conversion of number. If n is greater than the number has digits, then is left-padded with spaces. If in converting, more characters emerge as defined by n, characters are truncated on the left.

Example: numeric digits 22 say d2c(240,10) say d2c(249,10) say d2c(13961937044701104072,10) say d2c(17434265340928784376,10)

/* /* /* /*

result: result: result: result:

0 9 ABCDEFGH 12345678

*/ */ */ */

80 | 4 The REXX functions

4.4.4 D2X – Decimal to Hexadecimal Function: With this function, you can convert a decimal number to its hexadecimal format. Format: hexchar = D2X(number,[n]) number n

This is a decimal number whose content is returned in hexadecimal notation. If specified, this number indicates how many bytes are returned after the conversion of number. If n is greater than the output length resulting from the conversion, the result is left-padded with 00 if it is a positive number, it is filled with hex FF, if it is a negative number. If in converting, more characters emerge as defined by n, left standing characters are truncated.

Examples: numeric digits 22 say d2x(240,20) say d2x(249,20) say d2x(-16,20) say d2x(13961937044701104072,20) say d2x(17434265340928784376,20)

/* /* /* /* /*

result: result: result: result: result:

000000000000000000F0 000000000000000000F9 FFFFFFFFFFFFFFFFFFF0 0000C1C2C3C4C5C6C7C8 0000F1F2F3F4F5F6F7F8

*/ */ */ */ */

Due to specifying the length of 20, the shaded places were prefixed on the left

4.4.5 X2B – Hexadecimal to Binary Function: Convert a hexadecimal number into a binary string in text format. Format: bintext = X2B(hexnumber) hexnumber

The hexadecimal string is converted into a binary string. The output is four times as long as the input.

Examples: say x2b("ff") say x2b("11") say x2b("8AB1")

/* result: 11111111 /* result: 00010001 /* result: 1000101010110001

*/ */ */

4.4 Conversion functions | 81

4.4.6 X2C – Hexadecimal to Character Function: Convert a hexadecimal number to a string. Format: text = X2C(hexnumber) hexnumber

This hexadecimal number is converted to its decimal representation.

Examples: say say say say

x2c("f0f1f2f3f4f5f6f7f8f9") x2c("c1c2c3c4c5c6c7c8c9d1") x2c("81828384858687888991") x2c("4F7D7C5B6C50614D5D7E")

/* /* /* /*

result: result: result: result:

0123456789 ABCDEFGHIJ abcdefghij !'§$%&/()=

*/ */ */ */

4.4.7 X2D – Hexadecimal to Decimal Function: Convert a hexadecimal number to decimal. Format: decnum = X2D(hexnumber,[n]) hexnumber n

This hexadecimal number is to its decimal representation converted. If entered, this number indicates how many bytes are converted from hexadecimal value from the right. When the first (i.e. the leftmost) bit of number is 1, then the number is returned as a negative number in the two’s complement. If this number is zero, then the returned value will be a positive number.

3 Note: When using this function, it is important to ensure that NUMERIC DIGITS are set large enough. Otherwise, the call to X2D ends with an error.

82 | 4 The REXX functions

Program 4.3: Program to show X2D functionality /* DOC: REXX X2D ************************************************/ /* DOC: Examples of convert function X2D */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ numeric digits 22 say right(x2d("00000001"),22) /* a one*/ say right(x2d("7fffffff"),22) /* Largest positive nbr in the fullword*/ say right(x2d("7fffffff",4),22)/* Largest negative nbr in the fullword*/ say right(x2d("80000000",4),22)/* Largest positive nbr in the fullword*/ say right(x2d("7fffffff",1),22)/* Only the rightmost byte */ say right(x2d("7fffffff",2),22)/* Only the rightmost 2 bytes */ say right(x2d("00007fff",2),22)/* Largest positive number in halfword */ say right(x2d("00008000",2),22)/* Largest negative number in halfword */ say right(x2d("0000007f",1),22)/* Largest positive number in byte */ say right(x2d("00000080",1),22)/* Largest negative number in byte */ say right(x2d("000000ff" ),22)/* Largest number in bytes without sign.*/

I have run the program. See the result here: x2d("00000001")  x2d("7fffffff")  x2d("7fffffff",4)  x2d("80000000",4)  x2d("7fffffff",1)  x2d("7fffffff",2)  x2d("00007fff",2)  x2d("00008000",2)  x2d("0000007f",1)  x2d("00000080",1)  x2d("000000ff" ) 

1 2147483647 2147483647 -2147483648 -1 -1 32767 -32768 127 -128 255

4.5 Formatting functions These functions formatting data for output.

4.5.1 CENTER – Centering a string Function: With this function, a string can be arranged so that the string is in the middle and on the left and right with the pad character padded. Format: result = CENTER(intext,length,[pad]) intext length pad

Input text, extended or shortened as defined by the length parameter. Number of characters of the result text. Is length less than the length of intext, then the input text is equally shortened on both sides. Here, a fill character to specify which of the left and right of intext is added for an enlargement. Standard for the pad character is a blank.

4.5 Formatting functions | 83

4.5.2 COPIES – Reproduce texts Function: With this function a string can be duplicated n times. Format: text = COPIES(intext,n) intext n

Input text that is n times duplicated. Number of copies.

Example: say copies("*",10)  **********

4.5.3 FORMAT – Format numbers Function: Format numbers for output, as you like. Format: Text = FORMAT(number,before,after,expp,expt)

Table 4.5: Description of parameters for the FORMAT function

Parameter

Meaning

number

Expression or number, which will be formatted.

before

Number of digits before the decimal point.

after

Number of digits after the decimal point.

expp

Number of digits in the exponent.

expt

Limit of digits of number when the output is automatically switched to exponential representation.

4.5.4 JUSTIFY – Formatting a string Function: Block formatting of a string consisting of words by adding padding characters between the words.

84 | 4 The REXX functions

Format: text = JUSTIFY(intext,length[,pad]) intext length pad

Input text that normally consists of words, each separated by one or more blanks. Length of the result text. Character to be inserted between the words. Default is a blank.

Example: say justify("This say justify("Word

is a

Text",40,"-") ",40,"-")

These commands give the following texts: This---------is---------a-----------Text Wort------------------------------------

4.5.5 LEFT – Rearrange text left-justified Function: Left-align the input text and pad it on the right side with padding character. Default padding character is blank. Format: text = LEFT(intext,length[,pad]) intext length pad

Input text. Length of the resulting text. Padding character. Default is the blank.

4.5.6 RIGHT – Arrange text right- justified Function: Right-align the input text and pad it on the left side with padding character. Default padding character is blank. Format: text = RIGHT(intext,length[,pad]) intext length pad

Input text. Length of the resulting text. Padding character. Default is the blank.

4.6 String functions | 85

4.6 String functions The string functions form a powerful group of agents in the REXX programming. Except for a CHANGE function, I have yet to miss any string function. Therefore, I have written a long time ago a CHANGE function using REXX. The REXX source code of this CHANGE function is in the SMART ISPF utilities. The CHANGE function is described in section 4.6.3 SCHANGE – Change of texts on page 86.

4.6.1 DELSTR – Delete substrings Function: With this function, you can remove a portion of a text. The text will shortened by the deleted part. Format: text = DELSTR(intext,start[,number]) intext start

number

Input text. Starting position of the text to be deleted in intext. When the starting position is greater than the length of the intext then intext is returned unchanged. Number of characters, which are deleted. The text will be deleted up to the end when this parameter is not specified.

4.6.2 INSERT – Insert text Function: With INSERT, you can insert a text in another text. This is in a sense the inverse function of DELSTR. Format: text = INSERT(intext,text[,start][,length][,pad]) intext text start length pad

Inserted text. Text to which intext is inserted. Start position in text after the insertion is to occur. When the starting position is omitted or zero, then intext is inserted at the beginning of text. Number of characters which are inserted. When this parameter is not specified then the current length of intext is automatically used. If the entered length is greater than the current length of intext then this character expands intext on the right as defined in length.

86 | 4 The REXX functions

Example: See next function CHANGE.

4.6.3 SCHANGE – Change of texts This function is not part of TSO/E REXX. Rather more, I developed it because a change function in the daily work with REXX in the TSO/ISPF environment in my opinion is essential. This function is part of the SMART ISPF utilities. See section 15.5.12 REXX subroutine SCHANGE – REXX change function on page 283. Function: Change of texts. Format: text = SCHANGE(intext,searchtext[,replacement][,testtext]) intext searchtext replacement

testtext

Text to be changed. Search text. Change replaces all texts that are found with searchtext with the replacement text in a single call. This text should replace the search text. When the replacement text is omitted or contains a null string, then searchtext is only removed from intext. The CHANGE shall only take place if this text is included in the intext. Of course, it does not make sense when searchtext and testtext are equal. However, the function still runs properly.

4.6.4 LENGTH – Length of a text Function: With this function, the length of a text is determined. Format: n = LENGTH(text)

N is the length of a text. If a text is a null string, then is n = 0.

4.6 String functions | 87

4.6.5 OVERLAY – Superimpose text Function: With OVERLAY, you can insert a text into another text after the specified location. Format: text = OVERLAY(intext,text[,start][,length][,pad]) intext text start

length pad

Text inserted by overlay. Text to overlie beginning at start. Start position in text from which the insertion is to occur. When the starting position is missing, 1 is assumed. When the parameter start is specified, it must contain a positive integer. Number of characters to be overlaid. When this parameter is not specified, the current length of intext will automatically be used. If length is greater than the current length of intext, then this character will extend intext before the overlay is performed.

4.6.6 POS – Search for text Function: Search for a text within another text. The starting position of the found text within the input text will be returned. This function provides the same functionality as the INDEX function. According to literature, however, you should use POS. Format: n = POS(needle,haystack[,start]) needle haystack start

This text is searched for in the haystack Scanned text. From this position in the haystack, the search is started.

4.6.7 STRIP – remove border characters Function: When passing parameters and texts it often happens that these texts are featured at the front and at the rear with blanks or other characters which must be removed. This function removes leading and trailing (same) characters from a text. All same leading and trailing characters will removed. Since many operations, especially

88 | 4 The REXX functions

when passing parameters with leading and trailing blanks, STRIP is often used to remove these blanks. This function is often used just for precaution. Format: text = STRIP(intext[,option][,char]) intext option

char

This text will be stripped. This option specifies whether only leading, trailing, or characters from both ends should be removed from text. Both Removes the characters at both ends. This is the default value. Leading Removes leading characters only. Trailing Removes trailing characters only. These are the removed characters. Default is blank.

1 Tip: The STRIP function is often required in order to free DSNs from the surrounding single quotes ('). Sometimes it happens that a DSN is entered once with and once without the quotes. It often happens that you have to insert the DSN in a function that absolutely needs quotation marks. In such cases, I use the following statement: dsn = "'"strip(strip(dsn),,"'")"'" What does this statement? First, any existing single quotes will be removed. Thereafter, any existing blanks will be removed and finally the DSN will set back in quotes. Now it does not matter in which form the DSNs parameters are passed. With or without quotation marks and blanks. The result is always a DSN with quotation marks and without blanks.

4.6.8 SUBSTR – Extract part of a text Function: This function extracts a text part of a text. Format: teil = SUBSTR(text,n[,length][,pad]) text n length pad

Text from which the substring is taken. Starting position for extraction. Number of characters, which are extracted. When length is not specified, all characters will be taken up to the end of text. If length is greater than the available text, then the resulting text is extended with the padding character. The default pad is the blank.

4.6 String functions | 89

4.6.9 TRANSLATE – translate characters Function: This function translates individual characters of a text to other characters. Translation is done in such a way that the same characters in the translation table replace the characters found in the search table. Format: text = translate(intext[,replacetab][,searchtab][,pad]) intext replacetab searchtab pad

This is the text that will be translated. If only intext is specified, then this is translated to uppercase. This text contains characters that are replaced in intext if these characters are found in the search table. This text contains characters sought in intext. The fill character replaces such positions in intext where characters were found using the search table, but do not have a corresponding position in the replace table.

Examples: orgdsn = strip(translate(orgdsn," ","'"))

This command first replaces all apostrophes in orgdsn by blanks and then removes all surrounding blanks from orgdsn. arg1 = translate(arg(1))

With this command, the first argument that was passed by a calling program is set to uppercase. dsn1 = translate(dsn,"

",".'()")

This command replaces the characters dot, apostrophe, left and right brackets by blanks. The resulting string contains all qualifiers of the DSN and an eventually contained member name as single words. To get the member name, the following command can be used: mem1 = word(dsn1,words(dsn1))

90 | 4 The REXX functions

4.6.10 VERIFY – verify text Function: VERIFY checks whether a text only consists of characters of a second text or not. This function is very good to use for validation of texts such as DSNs. Format: n = VERIFY(text,checktext[,option][,start]) text

This is the text which is to be checked.

checktext

These characters are sought in TEXT. Here you can specify how to perform the check: Nomatch When specifying N, the function returns zero when ALL of the characters of text are also included in check text. Otherwise, the position of the first character that is not contained will be given back. Match When specifying M, the position of the first character in the text, which is also included in test text will back given. If no character from check text is found in text, then zero will be given back. Start position in text where the search begins.

option

start

4.7 Word functions One of the greatest strengths of REXX are the word functions. This is therefore so useful because just in the z/OS world very many terms appear in ISPF, programs, JCL, etc., as by blanks or special characters separated texts. From a text such as a DSN, you can very quickly use TRANSLATE to remove the special characters and you have a text that consists only of words. Definition of a word in REXX sense: – A word is a coherent text that does not contain blanks. – Words in a string are separated from each other by one or more blanks.

4.7.1 WORD – return of a word Function: WORD returns the nth word back from a string.

4.7 Word functions | 91

Format: wort = WORD(intext,position) intext position

String from which the addressed word is extracted by position. Position number of word to be returned. If position is greater than the number of words in intext then a null-string will be returned.

4.7.2 WORDINDEX – return the starting position of a word Function: WORDINDEX returns the position of the first character of the nth word of a string. Format: pos = WORDINDEX(intext,position) intext position

String in which the selected word is addressed by position. Number of the word within intext, of which the position of the first character is returned.

Examples are at the end of the section Word Functions found.

4.7.3 WORDLENGTH – return the length of a word Function: WORDLENGTH returns the length of the nth word in a string. Format: length = WORDLENGTH(intext,position) intext position

String in which the by position selected word is addressed. Number of the word whose length will be returned.

4.7.4 WORDPOS – search for a word Function: WORDPOS searches a word in a string and returns its position.

92 | 4 The REXX functions

Format: pos = WORDPOS(word,string[,start]) word string start

Searched word. If the word is not found in the string, zero will be returned String composed of several words. Word position where search starts.

4.7.5 WORDS – number of words in a string Function: WORDS returns the number of words contained in a string. Format: number = WORDS(intext) intext

String whose number of contained words are to be given back.

Program 4.4: WORDFUNC – Examples of WORD function /* DOC: WORDFUNC REXX MAIN */ /* DOC: Examples of the use of the word functions */ /*-------------------------------------------------------------------*/ /* © FRANZ LANZ 2015 */ /*********************************************************************/ dsn = "'PROX.SMART.REXX'" dsw = translate(dsn," ","'.'") /* Remove dots from DSN*/ say word(dsw,1)" = HLQ" say word(dsw,words(dsw))" = LLQ" say wordpos("SMART",dsw)" = Position of the word SMART" say wordlength(dsw,3)" = Length of the 3rd word"

This program produces the following list: PROX = HLQ REXX = LLQ 2 = Position of the word SMART 4 = Length of the 3rd word

4.8 System functions The system functions return information about the z/OS system and its resources under which control a REXX program is currently running. These functions are described in the literature as TSO/E External Functions. They can be found under this heading in the brochure TSO/E REXX Reference.

4.8 System functions | 93

4.8.1 LISTDSI – List data set information Function: This function returns a wealth of information concerning a data set. A detailed description of this function is found in section 4.8.1 LISTDSI – List data set information on page 93. If you need any information about a file, you must call up three functions. These are the functions LISTDSI, DSINFO and LMDLIST. Practical examples of all three functions can be found in the source code of the SMART ISPF utility SSC, in the section 15.4.23 Program SSS – Perform a Super-Search on page 271. See also section 8.2.2 DSINFO – ISPF service which provides data set information on page 162 and 8.2.1 LMDLIST – Data set list service on page 161.

4.8.2 MSG – control of the TSO messages Function: With MSG, you can specify whether the possibly during the program run occurring TSO messages are outputted directly or not. This is sometimes very helpful when you get TSO messages at a point in the program where you would like to suppress them. Format: msgstat = MSG("ON"|"OFF")

This call returns the status of MSG, which can be ON or OFF. This function is very useful when you wonder why TSO messages do not appear. x = msg("ON") x = msg("OFF")

This call switches the display of the TSO messages to ON. This call switches the display of the TSO messages to OFF.

Example: x = msg("OFF") address "TSO" "delete "ldsn x = msg("ON") 3 Note: The TSO DELETE command always produces a message. In this case, the active ISPF panel disappears and the delete message will be displayed. Since this is very annoying and I do not want to see the message from TSO DELETE, here I suppress the output of the message by setting x = msg("OFF").

94 | 4 The REXX functions

4.8.3 MVSVAR – Return z/OS system information MVSVAR returns various information about the z/OS system. A parameter keyword is mandatory defining the value you wish to receive. I have often used only one of these values. This is the name of the z/OS LPAR. That is the four-character logical partition name where my program is running. You get this value as follows: lpar = MVSVAR(SYSNAME)

If you need more information about this feature, view the detailed description of this function in the brochure TSO/E REXX Reference.

4.8.4 OUTTRAP – take TSO messages Function: OUTTRAP is a very frequently used function. REXX programs use OUTTRAP to store TSO outputted messages in a stem. You can use these TSO messages in your REXX as you like. Format: x = outtrap(name.)

This call ensures that from now on all TSO messages are written in the stem name. x = outtrap("OFF")

This call finishes writing of TSO messages in the stem name. TSO stores the number of rows of the stem in name.0. Example 1: Intercepting the messages of the SUBMIT command. 1 2 3 4

x = outtrap(text.) address TSO "SUBMIT * END($$)" x = outtrap("OFF") do i = 2 to text.0; say text.i; end i;

4.8 System functions | 95

Explanation of the REXX statements: Lines Explanation 1

With this statement, the TSO is informed that from now messages are no longer sent to SYSTSPRT, but instead written into the stem text.

2

TSO executes the SUBMIT command and writes the resulting messages in the stem text.

3

The trapping of the TSO messages will be switched off. The variable text.0 now contains the number of the TSO message lines in the stem text.

4

The messages from row two will be outputted. Since SUBMIT usually produces only two lines and the text that interests us is always in the second line, we only print this line. The output line might be: JOB LANZT373(JOB06586) SUBMITTED

Example 2: Outputting the file information and members list of a PDS.

Program 4.5: Example of calling the TSO function LISTDS /* DOC: REXX LISTDS */ /* DOC: Example of calling the TSO function LISTDS*/ /* © FRANZ LANZ 2015 */ /**************************************************/ x = outtrap("inmem.") "LISTDS 'PRTT.REXX' MEMBERS" x = outtrap("OFF") do i = 1 to inmem.0 say inmem.i end i

Printed output: PRTT.REXX --RECFM-LRECL-BLKSIZE-DSORG FB 80 27920 PO --VOLUMES-D1D115 --MEMBERS-$CONCAT §LPARS BNDUMSPP EINSATZS EXNAME TT 3 Remark: I will not describe the LISTDS function here in detail. The above example may suffice as information. The description of the TSO function LISTDS is contained in the brochure TSO-E Command Reference.

96 | 4 The REXX functions

4.8.5 SYSDSN – check data set status Function: Use SYSDSN to determine whether a file exists and that you can access it. Format: text = SYSDSN(DSN)

DSN must appoint a cataloged file. The SYSDSN function returns ONE of the following texts, which are selfexplanatory: OK /* data set is available and can be used */ MEMBER NOT FOUND MEMBER SPECIFIED, BUT DATASET IS NOT PARTITIONED DATASET NOT FOUND ERROR PROCESSING REQUESTED DATASET PROTECTED DATASET VOLUME NOT ON SYSTEM INVALID DATASET NAME, dsname MISSING DATASET NAME UNAVAILABLE DATASET

Example: The following program part allocates a data set. If the data set already exists, it is only allocated. If it does not exist, it will be created. address TSO if sysdsn(ldsn) = "OK" then "alloc dd("ddname")", "dsn("ldsn") old reuse" else "alloc dd("ddname")", "dsn("ldsn") new reuse space(15) tracks", "recfm(v b a) lrecl(133)" "execio "zl" diskw "ddname" (stem out. finis" "free dd("ddname")"

4.8.6 SYSVAR – get system Information Function: With SYSVAR, similar to MVSVAR, some system information can be retrieved. Here only two information points at run around procedures are of interest: Example 1: Does a program run in foreground or in background. foreground means: The program runs in the ISPF online. background means: The program runs under ISPF that is started as a batch job.

4.8 System functions | 97

3 Remark: It is important to know this operating mode, because maybe files are be assigned in a batch job via DD statement in the JCL, while in foreground mode the TSO alloc command must be used. On the other hand, any error messages in background mode differently than in foreground mode are outputted. For the query where the program runs, you can use the following statement: runenv = SYSVAR(SYSENV).

After this call, runenv contains FORE or BACK. FORE  The REXX program runs in foreground. BACK  The program runs in background in a batch job. Example: Program 4.6: Control messages display ONLINE and in BATCH dll_exit: arg rc text zedlmsg = "Error in procedure >read_data_lmget 0 then call ispf_error "QLIBDEF ISPSLIB TYPE(DEFTYP) ID(DSNS)" dsns = translate(dsns," ",",'") say "LIBDEF ISPSLIB chain" do i = 1 to words(dsns) say word(dsns,i) end i "QBASELIB ISPSLIB ID(ISPS)" isps = translate(isps," ",",'") say say "Standard ISPSLIB chain" do i = 1 to words(isps) say word(isps,i) end i "LIBDEF ISPSLIB" /* Restore LIBDEF */ exit

The output of the program (side by side): LIBDEF ISPSLIB chain PEVP.SKEL SMQP.PROD.SKEL SMQP.TEST.SKEL SMQP.USER.SKEL SQMT.DB2O.SKEL SQMT.DYNS.SKEL SQMT.PILOT.SKEL SQMT.USER.SKEL

Standard ISPSLIB chain DBT1.SDSQSLBE DBT1.DT1A.DSNSPFS SYST1.TSO.ISPSLIB ISP.SISPSLIB SYS1.DGTSLIB SYSPT.CAI.CAIISPS CBC.SCBCSKL ISP.SISPSENU

8.2 Data set query services | 173

8.2.6 QUERYENQ – ENQs determination Function: With QUERYENQ can you check whether any users are holding a particular resource. Format: QUERYENQ TABLE(table-name) QNAME(qname) RNAME(rname) REQ(pattern) WAIT LIMIT(limit) SAVE(list-id) XSYS TABLE

QNAME

RNAME

REQ

WAIT

LIMIT SAVE

XSYS

A freely chosen name for the ISPF table into which this service stores its information about the ENQs found. This table is returned to program in open state and it must not exist before calling QUERYENQ. The program must delete the table at the end of the program with TBEND. The user must define the type prior to the call of the QUERYENQ in this variable. Query types can be SYSDSN, SPFEDIT, SPFUSER etc. Normally, an asterisk (*) is assigned. This means that all query types are queried. Before calling QUERYENQ this variable must contain the name of the queried resource. This can also be a generic mask ending with an asterisk. The description for this value is very complex. I refrain from taking this opportunity to give a comprehensive explanation and always recommend to keep the characters %* for use. Look at the following example. If you specify this option, only the currently pending ENQ contentions will be issued. The information in rname and qname has no significance in this case. LIMIT is the number of rows that the function maximally returns. The default value is 5000. The specification of zero (0) cancels the limit. If you specify an up to eight digits long name of a DSN qualifier here, then the QUERYENQ service writes the results to a data set with the following name: prefix.userid.listid.ENQLIST. Indicates that the XSYS=YES parameter should be used on the GQSCAN macro call. This option causes that all available LPARs are searched for the resource, which may mean a lot of effort. If you are interested in this option, please look at the description of the GQSCAN macro.

174 | 8 Data set processing using ISPF

Functioning of the QUERYENQ function The QUERYENQ function generates an ISPF table which name is specified by the TABLE parameter. After a successful call to QUERYENQ rows in the table containing information on the ENQs are found. The following table is an excerpt from the brochure ISPF Services Guide. It contains the column names that appear in the returned ISPF table with their descriptions: Table 8.7: Variables description of the QUERYENQ ISPF table

Name

Size

Description

ZENJOB

8,

Job or address space name holding or requesting the ENQ

ZENQNAME

8,

Qname portion of the ENQ

ZENRNAME

255,

Rname portion of the ENQ

ZENDISP

5,

SHARE or EXCLU

ZENHOLD

4,

OWN or WAIT

ZENSCOPE

7,

SYSTEM or SYSTEMS

ZENSTEP

7,

STEP or blank

ZENGLOBL

6,

GLOBAL or blank

ZENSYST

8,

System name

ZENRESV

7,

RESERVE or blank

Return codes of QUERYENQ: The descriptions of the return codes that can occur after a call to QUERYENQ have also been taken from the above brochure: Table 8.8: QUERYENQ return codes

RC

Description

0

Table returned or data set written, but XSYS parameter was not specified and the system is running in STAR mode. The data returned may not reflect all ENQs on all systems.

2

Table returned or data set written.

4

Table returned but truncated due to limit.

8

No ENQs satisfy the request.

10

No ENQs satisfy the request, but XSYS parameter was not specified and the system is running in STAR mode. The data returned may not reflect all ENQs on all systems.

12

Table creation error, parameter or other termination error. See messages for more detail. This includes services not available due to configuration table restrictions.

14

The SAVE data set is in use by another user.

20

Severe error, including TBADD error or data set creation errors.

8.2 Data set query services | 175

3 Note: Please note that even if a RC>0 appears, quite useful results can be returned. When requesting the RC, you must always consider possible situations.

Example: The following program investigates whether a specific data set has any ENQs. Program 8.14: QUERYENQ example /* DOC: QUERYENQ REXX MAIN */ /* DOC: Example of displaying ENQs by QUERYENQ */ /* DOC: QUERYENQ. */ /* © FRANZ LANZ 2015 */ /* *************************************************************/ address "ISPEXEC" "CONTROL ERRORS RETURN" "TBEND TAB1" rname = "PROX.LOGON.CEXEC" qname = "*" "QUERYENQ TABLE(TAB1) RNAME(RNAME) QNAME(QNAME) REQ(%*) XSYS" if rc > 2 then do say strip(zerrlm) exit end "TBQUERY TAB1 ROWNUM(RN)" /* Get the number of table rows */ if rc > 4 then do say strip(zerrlm) exit end do i = 1 to rn "TBSKIP TAB1" say "ZENQNAME = >"zenqname""strip(zenrname)""zenjob""zendisp""zenhold""zenscope""zenstep""zenglobl""zensyst""zenresv""exname"< RC="rc, 16 "from statement:"copies(" ",60) srcline copies(" ",60) 17 if zerrlm "ZERRLM" then, 18 zedlmsg = zedlmsg" ISPF error message:" strip(zerrlm) 19 address "ISPEXEC" "SETMSG MSG(ISRZ001)" 20 end

Lines

Explanation

14:

This query is determined that the message is only outputted if the REXX program runs in FOREGROUND online under ISPF.

15+16

The text of the message is stored in the variable ZERRLM.

17+18

If ZERRLM contains an ISPF message, then the ISPF error message will be appended to the existing message text.

19

The message will be outputted and is displayed on the next screen.

Example 2: Excerpt from an edit macro. 67 68 69 70 71 72 73 74 75 76 77 78 79

if sysdsn(dsn) = "OK" then do address "ISPEXEC" "EDIT DATASET("dsn")" if rc > 4 then do address "ISPEXEC" "SETMSG MSG(ISRZ002)" "CURSOR = "cl cc exit end end else do zedsmsg = "Data set not found" zedlmsg = "The data set "dsn" could not be found." address "ISPEXEC" "SETMSG MSG(ISRZ001)" end

Line

Explanation

70

Because the ISPF EDIT command stores its messages when an error occurs in the variables ZERRSM and ZERRLM, then the message ID ISRZ002 can be used here.

78

Here, the variables ZEDSMSG and ZEDLMSG are filled with private texts. Therefore, ISRZ001 will be used here.

9.1 Error handling in ISPF | 187

3 Remark: The program from which the above excerpt is derived, is an edit macro. Therefore, the ISPF commands must be called using the form address "ISPEXEC". You cannot use the shape by prefixing the command with ISPEXEC here because the ISPF edit processor would not accept this. The shape with ISPEXEC before an ISPF command only understands the TSO command processor!

10 Panels – create and use In this chapter, I will explain how you can easily define and use ISPF panels. To control applications panels are suited much better than using the simple queries SAY and PULL. Therefore, if you want to create elegant applications in ISPF you should already dominate the creation and use of ISPF panels. The ISPF provides very simple methods and tools to create screens and to use these masks in programs. In ISPF, screens are referred consistently to as panels. There are two ways to create panels: – Use the Dialog Tag Language (DTL). – Use of panel definition statements.

10.1 The Dynamic Tag Language (DTL) The DTL was added to the ISPF later. Thus, you have the possibility to define the panel using a description language. This definition is converted using the Panel Conversion Utility in executable codes. The DTL is described in the brochure ISPF Dialog Tag Language Guide und Reference. That this is a very comprehensive tool, you can recognize by the fact that an extra brochure for this theme exists. Since the DTL is very extensive and we panel definitions for our purposes as quickly as possible, I will not use the DTL in this book. I do not want to deprive here, what benefits that IBM provides in the use of the DTL. That is why I copied the relevant passage from the DTL brochure below: Why the Dialog Tag Language (DTL)? If you are already familiar with a tag-based markup language, such as IBM Book Master*, you will find that DTL is very similar. We created DTL for many of the same reasons that we created Book Master: Markup tags are easy to use. Because tag names are short and relate directly to the structure of the dialog elements, they are also easy to remember. DTL lends flexibility to application development. Panels can be quickly changed without your having to tediously line up text and fields. This gives you greater control over application development and updates. DTL provides consistency when many programmers are working on the same application, or when programmers who are new to your company must update existing applications. Since each programmer is using the same tags, only minor adjustments may be needed to achieve complete uniformity. DTL techniques improve the way in which interactive programs, like ISPF applications, are developed. The language concentrates on the role of the various elements and their interrelationships, and ISPF takes care of their form and appearance at run time.

190 | 10 Panels – create and use

DTL also enforces some formatting rules defined by the Systems Application Architecture* Common User Access (CUA), so you do not have to be familiar with all of the CUA formatting rules. Therefore, the CUA skills required by programmers who are developing CUA-conforming applications are significantly reduced. DTL enables National Language Support (NLS) and the conversion utility provides NLS translations for certain key words. In other words, if you are looking for an application development and maintenance system that is sophisticated, flexible, and easy to use, that’s DTL. If you come to the conclusion that the DTL is the right tool for you to develop ISPF panels, you can use the DTL of course, because when calling the panel, there is no difference between the two development methods for panels.

10.2 Panel types in ISPF The following table shows which panel types in ISPF exist:

Type

Description

Standard panels

Standard panels in ISPF normally have a width of 80 characters and consist of up to 43 lines on a screen. When they are displayed, the currently displayed panel is completely replaced.

HELP panels

Help panels will be formed using certain instructions in the panel definition. They can contain any number of rows and they have their own scrolling mechanism.

POP UP panels

The dimensions of the pop-up panels are determined in the panel definition. When you call them, they will be embedded in the currently displayed panel. The rest of the underlying panel remains visible. POP Up panels can be moved while the display on the screen using the cursor. HELP panels are very often defined as POP UP panels.

10.3 Definition of panels In the following chapters, I will explain the key elements of the panel definition using the Panel Definition Statements. I will discuss only those definition items that I constantly use when I develop panels. The panel definition statements are described in the brochure ISPF Dialog Developer’s Guide and Reference.

10.3 Definition of panels | 191

10.3.1 The structure of a panel A panel definition generally consists of three elements: – The attribute characters – The text fields – The data fields The attribute characters Attribute characters always occupy only one character (byte). They determine the characteristics of the field behind them up to the next attribute character. The attribute character can consist of any characters. In practice, only special characters are used as an attribute character. 4 Attention: A sign that is defined as an attribute character can be used throughout the panel definition text only as an attribute character. In other words, when a character below the )ATTR statement in the )BODY section of the panel definition exists, it will be used always as an attribute character, irrespective of whether this is intended or not. Therefore, if you for example want to use a colon (:) in the panel text, you cannot this define as an attribute character.

How to specify the attribute characters; see section 10.3.3.1 The starting on page 193.

Attribute

section

The text fields They contain solid, non-rewritable texts. Text fields can be colored using attribute characters. How to specify the text fields; see section 10.3.3.2 The )BODY section on page 195. Data fields There are two types of data fields: – Input fields. These are defined for entering data. Input fields can also be used for output. – Output Fields. These fields are only defined for output of data. Output fields cannot be used for input. How to specify the data fields; see section 10.3.3.2 The )BODY section on page 195. The attribute character in front of the field defines the type of a data field.

192 | 10 Panels – create and use

10.3.2 Creation of panels and their call ISPF panels are typically created using the ISPF editor. In the edit sessions to create ISPF panels it is essential to ensure that NUMBER OFF is set. If panel definition lines include line numbers on the right, the display of this panel ends with an error. Panels will be executed as they were created. A compiler or other conversion process is not necessary. (Except DTL panels. However, we do not want to discuss this here). ISPF panels must be stored in a PDS/PDSE, which must be assigned during the execution of the panels under the DD name ISPPLIB. Panels can be displayed using the ISPF SELECT, DISPLAY or TBDISPL service. When called by the TBDISPL service, the panel must contain a )MODEL section. ISPF panels should have the following basic structure: – Line 1: Panel ID, Title, Short message area – Line 2: A command / option field and the scroll definition ┌───────────────────────────────────┬───────────────┐ │ Panel ID Title │ Short Message │ ├───────────────────────────────────┴──────┬────────┤ │ Command/Option │ Scroll │ └──────────────────────────────────────────┴────────┘

The remaining lines can be designed as desired. ISPF short messages are always displayed at the end of the first line from right to left in their current length. If necessary, parts of the title line are truncated on the right. Long messages will, if this is defined in the ISPF Settings menu, always be displayed at the bottom of the panel in a frame. The )BODY section defines the panel structure.

10.3.3 The panel definition sections A panel definition consists of several departments, the sections. Each section is intended for a very specific purpose. In the table below, I listed those sections that we want to deal with in this book. Each section starts at column one with a ) (right parentheses) character that is followed by a keyword identifying the type of section.

10.3 Definition of panels | 193

Table 10.1: Description of panel sections

Section

Description

)ATTR

The attr section defines the attribute characters for the fields of the panel.

)BODY

The body section defines the panel layout.

)MODEL

The model section defines a structure for the representation of variables of an ISPF table.

)INIT

The init section will go through before the panel is displayed. Here, initial values can be set.

)REINIT The reinit section will go through when the panel is repeatedly displayed. )PROC

The proc section will go through when the panel display is exited by a command. Here, the processing of the input values is performed. Typically, the plausibility checks of the input values are performed here.

)END

The end statement ends the panel definition. All lines behind this statement will be ignored.

10.3.3.1 The Attribute section The )ATTR line is usually the first line of a panel definition. However, it is not always necessary. This is the case when the standard character attribute for this panel are sufficient. The default attribute characters are as follows: % TYPE(TEXT) INTENS(HIGH) + TYPE(TEXT) INTENS(LOW) _ TYPE(INPUT) INTENS(HIGH)

These default attribute characters can be replaced by other characters using the option DEFAULT(xyz) in the )ATTR line. Example: )ATTR DEFAULT(?$§)

By defining this ATTR options, the following standard attribute characters are active in this panel: ? TYPE(TEXT) INTENS(HIGH) $ TYPE(TEXT) INTENS(LOW) § TYPE(INPUT) INTENS(HIGH)

The attribute characters can be defined in any number and any character in the )ATTR section. The following panel definition shows this:

194 | 10 Panels – create and use

Program 10.1: Panel definition of panel SLEP1 )ATTR /* DOC: PANEL SLEP1 ***********************************************/ /* DOC: Table display panel for procedure "SLE" */ /* DOC: Table $SLETAB is displayed */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ # type(text) intens(low) skip(on) color(red) % type(text) intens(low) skip(on) color(white) + type(text) intens(low) skip(on) color(green) * type(text) intens(high) skip(on) color(yellow) ( type(output) intens(high) skip(on) color(white) just(left) ; type(output) intens(high) skip(on) color(blue) just(left) ? type(input) intens(low) caps(on) color(turq) just(left) < type(input) intens(high) caps(on) color(yellow) pad(_) )BODY expand($$) (ZSYSID *$-$ Table display of recently edited data sets $-$ %COMMAND ===>_ZCMD $ $ %SCROLL ===>_ZSCR+ +Dynpan=?z +Compile state of SLE +Sort:%D=Date+or%N=Name?z+Max DSNs:?z +(sysdate (systime +Insert control for edited data sets ---->%All+or%Change:?z *C#Recent DSN in edit %Help with PF1 for all fields #Date Time #$-$ )MODEL _ZCMD $ $ %SCROLL ===>_ZSCR+ +Dynpan=?z +Compile state of SLE +Sort:%D=Date+or%N=Name?z+Max DSNs:?z +(sysdate (systime +Insert control for edited data sets ---->%All+or%Change:?z *C#Recent DSN in edit %Help with PF1 for all fields #Date Time #$-$

When the panel is displayed, it looks like this. SLEP1 S -------------- Table display of recently edited data sets Row 1 of 89 COMMAND ===> SCROLL ===> CSR Dynpan= YES-VIO Compile state of SLE Sort: D=Date or N=Name D Max DSNs: 89 NOT COMPILED Insert control for edited data sets ----> All or Change: ALL C Recent DSN in edit Help with PF1 for all fields Date Time ------------------------------------------------------------------------------

The first and the last line are shown expanded with the expand character - (hyphen). 3 Remark: The expansion characters must be unique (just like the attribute characters) within the panel definition. Therefore, this character can only be use for the definition of dynamic expanding.

10.3.3.3 The )INIT section In the )INIT section all measures can be taken that are necessary prior to the display of the panel. Such measures may include: – Fill variables with initial values. – Definition of the Z variables using the .ZVARS statement.

10.3 Definition of panels | 197

– –

Define the cursor position for the initial display of the panel. Specifying the general help panel. This panel appears when the PF1 key is pressed.

Coding 10.2: )INIT section example )INIT &zcmd .zvars

= ' ' = '(fchars recfm dirblk lrecl blksize + prim sec units dsntp)' .cursor = newdsn .csrpos = 2 .help = SSCPT00 if (&units = TRACK) &units = TRACKS if (&units = CYLINDER) &units = CYLINDERS )REINIT

3 Note: In the above .ZVARS definition can be seen how continuation lines are formed in panel definitions by the plus sign.

10.3.3.4 The )PROC section The )PROC section is run through when the input is terminated by pressing the ENTER or a PF key. In the )PROC section normally plausibility checks and some processing of the entered values are performed. For these purposes, a number of commands are available that are used for the following tasks. variable = value IF and ELSE VER VGET / VPUT

   

Assignments

Logical operations Verify Write and read of ISPF profile variables

When assignments are performed, the following functions are often used for the determination of the result: TRUNC TRANS

PFK

 Cut and build the rest  Translate  PF keys

If and ELSE: Because no THEN is available, another rule must exist how commands are defined when an IF statement as true ends. This rule is very simple:

198 | 10 Panels – create and use

3 Rule: If an IF query is recognized as true, then all the instructions in the following lines are executed that are indented at least one column to the right.

Again, it is beyond the scope of this book to discuss the above listed statements and functions in detail. To explain the design of an ISPF screen, I will use the screen SSCPP01. The SSCPP01 screen is one screen of the SMART ISPF utilities. The SSC program calls it. The panel has a complex format and is therefore a good example to explain the functionality of an ISPF screen structure: Coding 10.3: SSCPP01 – Panel definition example 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050

)ATTR /*********************************************************************/ /* DOC: SSCPP01 Panel ************************************************/ /* DOC: Panel number 1 for function SSC = SMART Super Clone */ /* DOC: Allocation, copy and restruction of data sets */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ /* */ + type(text) intens(low) color(blue) skip(on) " type(text) intens(low) color(yellow) skip(on) $ type(text) intens(high) color(white) skip(on) % type(text) intens(high) color(turq) skip(on) # type(output) caps(off) color(white) skip(on) ? Type(input) caps(on) color(red) intens(high) )BODY EXPAND(\\) $SSCPP01 \-\ Data set manager under ISPF \-\ +COMMAND ===>_ZCMD + Dynpan =#z +SysPlex =#zsysplex+Sysid =#zsysid +Node =#zsysnode + Model =#olddsn +Compile state of SSC " New =?newdsn #sysdate #systime " FUNCT =?z $ 8 then do zedlmsg = left("Error at call to panel SSCPP01-3, RC="RC,80) if zerrlm "ZERRLM" then zedlmsg = zedlmsg zerrlm "SETMSG MSG(ISRZ001)" exit end if panrc = 1 then leave ipanel

10.3 Definition of panels | 203

You can also see how the processing of the program is ended. When in panel SSCPP01 the PF3 key is pressed, then the variable PANRC is set to 1. At return from the panel display the IPANEL loop is left and the program exits (statement line 305). Example 2: Display of a POP UP panel When the program SSC copies a data set and records would be truncated, then a POP UP panel is issued which displays a warning and the operator can confirm the truncation and continue or exit the processing. if fchar2 = "O" then do if lrecl < syslrecl then do oldrecl = syslrecl /* these are used in panel */ newrecl = lrecl /* SSCPP02 */ "ADDPOP" "DISPLAY PANEL(SSCPP02)" "REMPOP" if comkz "Y" then do zedlmsg = "You do not approve shortening of data", "records. Copy is not performed!" "SETMSG MSG(ISRZ001)" iterate ipanel end end end

I simulated such a critical copy task. See the display of the POP UP panel: SSCPP01 --------------------- Data set manager under ISPF --------------------C *-----------------------------------------------------------------------* | SSCPP02 -------- Notice if target LRECL is lower than source -------- | | | | Dynpan= YES-VIO | | Source DSN: USER001.CMDSMOD.LIST | | LRECL: 138 | | | | Target DSN: USER001.CMDSMOD.LIST1 | | LRECL: 120 | | | | LRECL of target data set is lower than LRECL of source data set. | | | | At copy action the records on the target data set are truncated. | | | S | Would you continue copy operation? | | | E | N (Y/N) | | | | PFK 3 / END or Enter without Y cancels operation. | *-----------------------------------------------------------------------* REASON= ENQs= ----------------------- Yellow fields are input fields. -----------------------

1 Tip: You can use the cursor to move a pop-up panel within the totally available display to another position. Proceed as follows: Place the cursor to a point of the frame of the pop up panel and then press ENTER. Then the text Window move pending appears in the upper right corner of the screen. If you now move the cursor to any position in the screen and press ENTER, the entire pop up panel will be moved to the new position. Using this method, you can make invisible parts of the surrounding panel visible again.

204 | 10 Panels – create and use

10.3.5.2 The SELECT PANEL service The SELECT service can also be used to call up panels. These panels must have a special structure. They are normally used to start an application. One of the typical panels of this type is the panel to display the ISPF Primary Option Menu. Its name is normally ISR@PRIM. This panel has been created with the ISPF Dynamic TAG language. Therefore, I will not discuss the panel here.

10.3.5.3 The TBDISPL service The TBDISPL service not only calls the panel in question; but also the content of the underlying ISPF table will be displayed. See section 10.3.5.1 The DISPLAY Service on page 202 and the section 10.3.5.3 The TBDISPL service on page 204.

10.3.6 Help panels There are four types of help panels: – The general help panel for a screen. – Help panels, which are assigned to a field in the screen. – Full screen help panels. – POP UP help panels. 1.

The general help panel

Each screen definition may contain an entry for the display of a so called general help screen. The general help panel must be defined in the )INIT section. The general help screen is called when the PF1 key is pressed and the cursor is at a location of the screen for which no specific help panel is defined. 2.

Field assigned help panels

For each data field in a panel a specific help panel can be defined. Such a panel is called, when the cursor is at any position within the data field in question and PF1 is pressed. Field assigned help panels must be defined in the )HELP section. See lines 114 to 138 of the Coding 10.3: SSCPP01 – Panel definition example on page 198. 3.

Full screen help panels

As the name suggests, these panels replace the entire screen when they are displayed. This type is used the most for general help panels. 4.

POP UP help panels

This type of panels is mostly used for field assigned help panels. See section 10.2 Panel types in ISPF on page 190.

10.3 Definition of panels | 205

The basic structure of a help panel looks like this: Program 10.2: HELPMASK – Help panel template )attr # area(scrl) extend(on) /* DOC: PANEL HELPMASK ***********************************************/ /* DOC: Template for HELP panel creation */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ + type(text) intens(low) color(blue) skip(on) ? type(text) intens(low) color(red) skip(on) $ type(text) intens(high) color(yellow) skip(on) õ type(text) intens(high) color(white) skip(on) ! type(text) intens(high) color(green) skip(on) )body expand("") % TUTORIAL "-" Template for Tutorial and Help panel creations. "-" %Command ===>_zcmd + %End with PF3 or PF15,+Scrolling with$PF11 >%down+with$PF10 >%up +On the last page enter B and Enter to jump to the first page. +--------------------------------------------------------------------------#crhelp -------------------------------------------------------------------# )area crhelp +From here any number of lines can be as a help text entered. +The above-defined ATTR characters for color design can be used. )end

3 Remarks: To define help panels the grayed lines are needed. I always use this template when I need to create a new help panel. The general help panel is entered in the )INIT section of the panel definition. Please note that help panels specified in the )INIT section act as general help panels. They appear when PF1 is pressed and the cursor stands at any position in the panel and not in a field for which an own help panel exists.

General help panels are defined in the )INIT section as follows: .help = name

10.3.7 Panels to display ISPF tables Table display panels are used to display and edit ISPF tables. ISPF tables are twodimensional tables that are created by using ISPF table services. These services are also used for the data maintenance of the tables. A table display panel contains a )MODEL statement in which those variables from the ISPF table are defined which want to be displayed with this panel.

206 | 10 Panels – create and use

Example: The panel SLEP1 is a typical table display panel. The SMART ISPF utility program SLE uses it: Program 10.3: Definition of panel SLEP1 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 **

)ATTR /* DOC: PANEL SLEP1 ***********************************************/ /* DOC: Table display panel for procedure "SLE" */ /* DOC: Table $SLETAB is displayed */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ # type(text) intens(low) skip(on) color(red) % type(text) intens(low) skip(on) color(white) + type(text) intens(low) skip(on) color(green) * type(text) intens(high) skip(on) color(yellow) ( type(output) intens(high) skip(on) color(white) just(left) ; type(output) intens(high) skip(on) color(blue) just(left) ? type(input) intens(low) caps(on) color(turq) just(left) < type(input) intens(high) caps(on) color(yellow) pad(_) )BODY expand($$) (ZSYSID *$-$ Table display of recently edited data sets $-$ %COMMAND ===>_ZCMD $ $ %SCROLL ===>_ZSCR+ +Dynpan=?z +Compile state of SLE +Sort:%D=Date+or%N=Name?z+Max DSNs:?z +(sysdate (systime +Insert control for edited data sets ---->%All+or%Change:?z *C#Recent DSN in edit %Help with PF1 for all fields #Date Time #$-$ )MODEL 8 then do zedlmsg = exname":" zerrlm "SETMSG MSG(ISRZ001)" end otherwise nop end /* select */ address "ISREDIT" "DEFINE END RESET" "BUILTIN END" exit

208 | 10 Panels – create and use

Excerpt from program SLE: The following excerpt from program SLE shows the command, that displays the panel SLEP1 together with the contents of the table $SLETAB. /*----------------------------------------------------------------*/ /* Display table */ /*----------------------------------------------------------------*/ "TBTOP "tabname "TBDISPL "tabname" PANEL(SLEP1) AUTOSEL(NO)" /* Start error handling */ if rc > 8 then call ispf_error rc "//"||, "*TBDISPL *tabname* PANEL(SLEP1) AUTOSEL(NO)*//"||, "TBDISPL "tabname" PANEL(SLEP1) AUTOSEL(NO)" /* End error handling */ "VPUT (ALLCHA) PROFILE" /* save insert indicator ALL or CHANGED */ if prc = 1 then leave k /* PF3 was pressed, go to programs end */

Finally yet importantly, here is a display of panel SLEP1 with the data in table $SLETAB. Screen 10.1: Panel SLEP1 displayed by program SLE SLEP1 S -------------- Table display of recently edited data sets Row 1 of 20 COMMAND ===> SCROLL ===> CSR Dynpan= YES-VIO Compile state of SLE Sort: D=Date or N=Name D Max DSNs: 20 NOT COMPILED Insert control for edited data sets ----> All or Change: ALL C Recent DSN in edit Help with PF1 for all fields Date Time ------------------------------------------------------------------------------_ USER001.BOOK1.REXX(SLE) 15/05/08 16:00:42 _ USER001.BOOK1.REXX(#IMACRO2) 15/05/08 15:54:57 _ USER001.BOOK.PANELS(SLEP1) 15/05/05 07:52:47 _ USER001.BOOK1.REXX(SCURSOR) 15/05/04 15:12:34 _ USER001.BOOK1.REXX(SSC) 15/05/04 07:52:21 _ USER001.BOOK.PANELS(SSCPP01) 15/05/03 15:58:45 _ USER001.BOOK.PANELS(SSSP1) 15/05/03 08:23:26 _ USER001.BOOK.PANELS(SCURSOR) 15/05/03 08:23:04 _ USER001.BOOK.PANELS(LCHT) 15/05/03 08:22:02 _ USER001.BOOK.PANELS(LCHP) 15/05/03 08:21:53 _ USER001.BOOK.PANELS(IMACRO11) 15/05/03 08:21:34 _ USER001.BOOK.PANELS(#TSOB) 15/05/03 08:20:51 _ USER001.BOOK.PANELS(#ISPFB) 15/05/03 08:19:56 _ USER001.BOOK2.REXX(TEST2) 15/04/30 06:20:27 _ USER001.BOOK2.REXX(TEST1) 15/04/19 07:44:09 _ USER001.BOOK2.EXAMPLE.REXX(QBASELIB) 15/04/19 07:17:52 _ USER001.BOOK2.EXAMPLE.REXX(IOEXMPL2) 15/04/12 15:16:46 _ USER001.BOOK2.REXX(ALTLIB2) 15/04/12 09:48:44 _ USER001.BOOK2.REXX(TTT) 15/04/10 08:53:55 _ USER001.BOOK2.EXAMPLE.REXX(IOEXMPL1) 15/04/08 16:58:37 ******************************* Bottom of data ********************************

For each of the shaded boxes a dedicated help panel is defined.

10.3 Definition of panels | 209

Mnemonics to table display panels Behind the )MODEL statement up to eight model lines may be defined. – The table display panels are automatically SCROLLABLE. Therefore, you can handle ISPF tables of any length. – Scrolling is done with keys PF7 and PF8. PF7  backward, PF8  forward. – The display can only be performed in 80 columns. – If you want to also edit the contents of the tables, you should define the first column as an input field for the operation code. See the above panel SLEP1. – In the row behind the )MODEL line there is no need to be list all names of an ISPF table.

11 Skeletons – Design and use In this chapter, you will learn how you can create JCL members and other data elegantly by using ISPF skeletons. ISPF skeletons are members in a PDS/PDSE that are created with the editor. They are masks which are used for the management of any data structures. Skeleton members consist of basic texts, skeleton control statements and variable names. The variable names are replaced during processing of skeletons by the ISPF file-tailoring services by the actual values which are set in the processing REXX procedure. As with the panels, the variable names must not be longer than eight characters.

11.1 Creating skeletons For the creation of skeletons, the following commands are available: Table 11.1: Commands to create skeletons

Command

Function

)BLANK

)BLANK 5 inserts 5 blank lines into the skeleton, which is being edited.

)CM

With )CM, comment lines can be defined in the skeleton. These lines are not copied to the output component.

)DEFAULT

To control the skeleton processing, seven special characters are reserved by default. These are the characters: ), &, ?, !, . With the )DEFAULT command these characters can be changed temporarily

)DOT )ENDDOT

Using these two statements, a loop can be formed.

)IM

This statement inserts another skeleton. The variables of the inserted skeleton will be dissolved and the result is added to the output component.

)SEL )ENDSEL

With )SEL a condition can be queried. If this condition is satisfactory, all the rows are processed until the next )ENDSEL.

)SET

Assignments can be made by using this instruction.

)TB, )TBA Tab stops can be set by using this instruction.

Example: The following skeleton adds a step into a job which executes instructions for DB2 BIND PACKAGE commands. The BIND PACKAGE instructions will not be executed in this job step; they are executed in the called REXX procedure VINTPAC.

212 | 11 Skeletons – Design and use

JCL 11.6: Definition of a skeleton 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

//* DOC: RUNNING THE BIND PACKAGE INSTRUCTIONS //********************************************************************* //&STEPN EXEC PGM=IKJEFT01,REGION=4M //STEPLIB DD DISP=SHR,DSN=&DSNEXIT // DD DISP=SHR,DSN=&DSNLOAD // DD DISP=SHR,DSN=&VERLOAD //SYSPROC DD DISP=SHR,DSN=&VERREXX0 // DD DISP=SHR,DSN=&VERREXX1 )IM $ISPFDD NT //DBRMLIB DD DISP=SHR,DSN=&DBRMLIB //RUNLIB DD DISP=SHR,DSN=&DB2RUN //BGFILE DD DISP=SHR,DSN=&BGFILE //STAT DD DISP=MOD,DSN=&PACKSTAT..&DB2SYS //FEHL DD DISP=MOD,FREE=CLOSE, // DSN=&DB2FEHL..&DB2SYS..&GRP //SYSIN DD UNIT=VIODA,SPACE=(CYL,(10,10)), // DSORG=PS,RECFM=FB,LRECL=80,BLKSIZE=27920 //SYSPRINT DD UNIT=VIODA,SPACE=(CYL,(5,5)),DSORG=PS, // RECFM=FBA,LRECL=133,BLKSIZE=27950 //LISTE DD SYSOUT=* //SYSTSPRT DD SYSOUT=* //SYSTSIN DD * PROFILE NOPREFIX NOMSGID ISPSTART CMD(%VINTPAC &DB2SYS &SYST &PACKZEIT) END //INMEM DD *

Remarks: – – –

I have grayed all relevant places for a skeleton definition. In line 10 the skeleton $ISPFDD is inserted. This skeleton contains the necessary DD statements for execution of REXX procedures in an ISPF batch environment. If a skeleton variable should be connected to another skeleton variable, a point is used as concatenation operator. If the resulting string is a DSN, an additionally point will be inserted for separating the single DSN qualifiers. DSNs are built in the lines 14 and 16. Therefore, here two consecutive dots are used to assemble DSNs.

Here are the statements of the REXX procedure VINTSN that processes this skeleton: Coding 11.1: Skeleton processing 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222

/* Read values for SKELETON VINTPAC from LOCATIONS */ /*--------------------------------------------------------------------*/ say exname time() "Begin step PACRUN" dsnexit = read_lokation("VPROD"syst "DSNEXIT") dsnload = read_lokation("VPROD"syst "DSNLOAD") dbrmlib = read_lokation("VPROD"syst "DBR") db2run = read_lokation("VPROD"syst "DB2RUNLIB") bgfile = bgut db2sys = read_lokation("VPROD"syst "DB2SYS") bnderr = read_lokation("VPROD"syst "BNDERR") packtime= packcalc("PAC") stepn = "PACRUN" "FTINCL VINTPAC" if rc > 0 then call ispf_error rc " from FTINCL VINTPAC"

11.1 Creating skeletons | 213

In this part of the program, most skeleton variables are filled with values. Some have already been set earlier in the procedure. When the statement FTINCL VINTPAC in line 3221 is executed, the following happens: – The member VINTPAC will be searched in the data set chain associated with the DD name ISPSLIB and inserted in an internal area. – Thereafter, the file-tailoring service is called. This processes the skeleton line by line. – The contents of the variables from the REXX/ISPF variable pool replaces the variables. – Any existing file-tailoring statements are executed. In this skeleton only one )IM statement is contained. The member $ISPFDD is searched in the ISPSLIB chain and inserted in the JCL stream. The variables contained in the member will be replaced by the actual values. – When the file-tailoring service has conducted all processing, the result is added to the internal data stream that has been opened with the FTOPEN statement. – When all file-tailoring work that is necessary to form a JCL member is finished in the procedure VINTSN, the created JCL member is saved using the command FTCLOSE NAME(name) LIBRARY(ddname). If ddname is not specified ISPFILE is used. The job step created by the file-tailoring service looks as follows:

214 | 11 Skeletons – Design and use

JCL 11.7: Job step created by the file-tailoring service 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230

//* DOC: SKEL VINTPAC ************************************************ //* DOC: RUNNING THE BIND PACKAGE INSTRUCTIONS //********************************************************************* //PACRUN EXEC PGM=IKJEFT01,REGION=4M //STEPLIB DD DISP=SHR,DSN=DB2P.ALIAS.DSNEXIT // DD DISP=SHR,DSN=DB2P.ALIAS.DSNLOAD // DD DISP=SHR,DSN=PROX.LOAD //SYSPROC DD DISP=SHR,DSN=PROX.CEXEC // DD DISP=SHR,DSN=PROX.CEXEC //* DOC: SKEL $ISPFDD ****************** //ISPMLIB DD DISP=SHR,DSN=ISP.SISPMENU //ISPPLIB DD DISP=SHR,DSN=ISP.SISPPENU //ISPSLIB DD DISP=SHR,DSN=ISP.SISPSENU //ISPPROF DD DISP=(NEW,PASS),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3120), // SPACE=(TRK,(5,5,10),RLSE),UNIT=VIODA //ISPTLIB DD DISP=(SHR,PASS),DSN=*.ISPPROF,VOL=REF=*.ISPPROF // DD DISP=SHR,DSN=ISP.SISPTENU //ISPLOG DD DUMMY //****** ENDE $ISPFDD ****************** //DBRMLIB DD DISP=SHR,DSN=PRDXX.DBRMLIB //RUNLIB DD DISP=SHR,DSN=DB2P.ALIAS.RUNLIB.LOAD //BGFILE DD DISP=SHR,DSN=PRDXX.DB2PACK //STAT DD DISP=MOD,DSN=PROX.PACKSTAT.DB2P //FEHL DD DISP=MOD,FREE=CLOSE, // DSN=PROX.DB2BIND.ERROR.DB2P.PAC //SYSIN DD UNIT=VIODA,SPACE=(CYL,(10,10)), // DSORG=PS,RECFM=FB,LRECL=80,BLKSIZE=27920 //SYSPRINT DD UNIT=VIODA,SPACE=(CYL,(5,5)),DSORG=PS, // RECFM=FBA,LRECL=133,BLKSIZE=27950 //LIST DD SYSOUT=* //SYSTSPRT DD SYSOUT=* //SYSTSIN DD * PROFILE NOPREFIX NOMSGID ISPSTART CMD(%VINTPAC DB2P 0 91;47) END //INMEM DD *

In the previous image, I grayed all the locations where values were inserted by variable substitution and all inserted rows.

11.2 Steps to use the file-tailoring service 1. Use the ISPF editor to create a member in a PDS that is assigned under the DD name ISPSLIB for processing skeletons by a REXX procedure. 2. Create a REXX procedure where the variables are set used by the file-tailoring service to replace the corresponding variables of the skeletons. 3. Use in the REXX program the FTINCL service to insert a skeleton. 4. Use the FTCLOSE NAME(name) service to save the member name. 1 Tip: The file-tailoring service can also be used to generate any arbitrary data set.

12 Tables – Create and edit Here you will learn how to create, edit and view ISPF tables. The table service of ISPF provides the ability to create tables, to edit and to use them for your daily work. A row in the ISPF table consists of columns that are named by ISPF variables. Each line can be addressed using ISPF table service commands. After carrying out such a command, the names of the variables in the manufacturing procedure are known.

12.1 Locations for tables Tables can be created either temporarily or permanently. A temporary table only exists in virtual memory. It cannot be saved in a permanent data set. For processing, the entire table always resides in virtual memory. This means that an ISPF table is limited in its size by the available virtual memory. Normally tables are stored in memory above the 16-megayte-line. This allows ISPF tables to become quite large.

12.2 Reading ISPF tables A table is read from the ISPTLIB data set chain with the TBOPEN statement into the memory or it is created there temporarily. When a table is read from ISPTLIB with the WRITE option, then an ENQ is set on the member in which this table resides. This prevents that this table can be read a second time. The ENQ is cancelled when the table is closed with TBCLOSE. When reading with the NOWRITE option, the ENQ is only active during the read operation. Under the DD name ISPTLIB several PDS/PDSE are normally allocated. When executing the TBOPEN, the member is searched in this data set chain. The first occurring member of the name will be loaded.

12.3 Writing ISPF tables When writing ISPF table members, you cannot use the DD name ISPTLIB because under this DD name usually a chain of PDS/PDSE is allocated. Moreover, we have learned above, that we cannot write to a DD, which addresses a concatenated data set. The DD name ISPTABL is used to write tables. Therefore, always only one data set is allocated to ISPTABL. If this applies, you must consider that the following question naturally arises: How can I maintain a table if I cannot write back to the file of which I have read?

216 | 12 Tables – Create and edit

A small trick solve this problem: – You can read all the tables that are included in the PDS/PDSE concatenation of about the DD name ISPTLIB. – Tables can only be written into a data set that is associated with the DD name ISPTABL. – When the data set that is allocated with the DD name ISPTABL to write tables is also allocated as first data set in the ISPTLIB chain, then a recently written table will always be loaded with its latest contents.

This allocation looks in practice in my TSO user: T1T105

SHR,KEEP

T1T105 PLPRT1 PLPRT1 OST0A9 T1S001 OST0A9 OST0A9 OST0A9 OST0A9

SHR,KEEP SHR,KEEP SHR,KEEP SHR,KEEP SHR,KEEP SHR,KEEP SHR,KEEP SHR,KEEP SHR,KEEP

> > > > > > > > > > >

ISPTABL ISPTLIB

LANZT.ISPF.TLIBTAB.LPRT LANZT.ISPF.TLIBTAB.LPRT SYST1.TSO.ISPTLIB SYST1.JCLPLUS.ISPTLIB SYS1.DGTTLIB SYSPT.CAI.CAIISPT ISP.SISPTENU ISF.SISFTLIB SYS1.SBPXTENU EOY.SEOYTENU

3 Rule: When I write a table (whether new or read before), then it will be written via ISPTABL in the LANZT.ISPF.TLIBTAB.LPRT data set. When I read them afterwards, it is first found in the same physical data set under the DD name ISPTLIB and read from there. In order for the ongoing maintenance of a table will guaranteed.

12.4 Commands of the table services In ISPF, a number of commands for working with tables is available. We distinguish the commands that relate to an entire table and those, which relate to the processing within the tables:

12.4 Commands of the table services | 217

Table 12.1: Table services commands that refer to the entire table

Command

Description of the commands that refer to the entire table.

TBCLOSE

Closes a table and saves it in the output data set if it had been read before.

TBCREATE

Creates a new table and opens it for processing.

TBEND

Closes a table without saving them.

TBERASE

Deletes a table member in the ISPTABL data set.

TBOPEN

Opens an existing table for processing.

TBQUERY

Provides information about a table.

TBSAVE

Backs up a table in the member in ISPTABL without the table to close.

TBSORT

Sorts a table.

TBSTATS

Provides statistics information on the table.

Table 12.2: Table service commands that relate to individual rows

Command

Description of commands that relate to individual rows

TBADD

Inserts a new row in the table.

TBBOTTOM Sets the CRP (Current Row Pointer) on the last line of the table. TBDELETE Deletes a row from the table. TBEXIST

Tests if there is a line with a specific key.

TBGET

Stores the contents of the current row in the corresponding variables.

TBMOD

Changes the contents of an existing line or adds a new line.

TBPUT

Changes the contents of an existing line if it exists, and if the key matches.

TBSARG

Sets on a search argument for a subsequent TBSCAN or TBDISPL.

TBSCAN

Searches in the table for a row which is in accordance with the given arguments.

TBSKIP

Moves the CRP forward or backward by a specified number of rows and stores the values of the addressed row into the corresponding variables.

TBTOP

Sets the CRP at the beginning of the table.

TBVCLEAR Fills all the variables of the table with zero values.

Again, I will refrain from describing the above commands in detail. Instead, the following examples will show you how to create a table and how to use it.

218 | 12 Tables – Create and edit

12.5 Example of working with tables As I mentioned on several occasions, I wrote an ISPF application which displays the DSNs of the most recently edited data sets in a panel. The main program of this application is SLE which stands for Smart Last Edit. It is contained in the collection of the SMART ISPF utilities. All programs of this application are written in REXX. The following table shows the most important components that belong to this application: Table 12.3: Components of the SLE application

Name

Type

Function

SLE

Main program

This program is called as ISPF function. It displays the panel SLEP1 and performs the work initiated there.

#IMACROA Edit macro

If an edit session is started, this macro checks whether the IMACRO option is already set for the edited data set in the edit profile. If this is not the case, the option IMACRO is set to #IMACRO1.

#IMACRO1 Edit macro

This macro defines an ALIAS so, that at the end of the edit session #IMACRO2 is called.

#IMACRO2 Edit macro

This macro will be called automatically when an edit session ends. It inserts the DSN of the currently edited data set into the ISPF table $SLETAB. At the next call of SLE, the name of the recently edited data set is contained in the table $SLETAB and it will be displayed in the panel SLEP1.

SLEP1

ISPF panel

This is the main panel for execution of the SLE application. It shows the table $SLETAB and offers the ability to perform some actions with the shown data sets.

Many help panels are defined to assist the user in the working with the SLE application. However, these panels are not important for the function of the application and are therefore not named here. Here the part of the edit macro #IMACRO2, which shows the updating (or creation) of the ISPF table $SLETAB:

12.5 Example of working with tables | 219

Program 12.1: Excerpt from edit macro #IMACRO2 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

/*********************************************************************/ /* Insert the name of the edited data set into table $SLETAB */ /*********************************************************************/ in_tab: if edmem "" then dsn = eddsn"("edmem")" /* A member was edited */ else dsn = eddsn /* A sequential data set was edited */ address "ISPEXEC" "VGET (ZSYSID) SHARED" tabname = "$SLETAB" "TBOPEN "tabname" LIBRARY(ISPTABL) WRITE SHARE" openrc = rc FUNCTION = ""; DATE = date("O"); TIME = time(); select when openrc = 0 then do "TBMOD "tabname" ORDER" /* Updata table $SLETAB */ "TBSORT "tabname" FIELDS(DATE,C,D,TIME,C,D)" "TBCLOSE "tabname" LIBRARY(ISPTABL) REPLCOPY PAD(100)" end when openrc = 8 then do /* Table $SLETAB does not exist. Create it */ "TBCREATE "tabname" KEYS(DSN) NAMES(FUNCTION,DATE,TIME)" "TBADD "tabname" ORDER" "TBCLOSE "tabname" LIBRARY(ISPTABL) REPLCOPY PAD(100)" end when openrc > 8 then do zedlmsg = exname":" zerrlm "SETMSG MSG(ISRZ001)" end otherwise nop

Lines

Explanations

66

Table $SLETAB is opened. The RC is saved in openrc.

68

Some table variables are set.

70–74 When the table $SLETAB exists, it will be updated and written back to ISPTABL. 75–79 When the table $SLETAB does not exist it will be created and written into ISPTABLE as new member which then contains one row of data.

Here an excerpt of the panel description of panel SLEP1 where the )MODEL line defines the structure of the displayed rows of the table $SLETAB.

220 | 12 Tables – Create and edit

Coding 12.1: Excerpt from panel definition of the panel SLEP1 21 22 23 24 25 26 27 28 29

*C#Recent DSN in edit %Help with PF1 for all fields #$-$ )MODEL 8 then call ispf_error rc "//"||, "*TBDISPL *tabname* PANEL(SLEP1) AUTOSEL(NO)*//"||, "TBDISPL "tabname" PANEL(SLEP1) AUTOSEL(NO)" /* End error handling */ "VPUT (ALLCHA) PROFILE" /* save insert indicator ALL or CHANGED */ if prc = 1 then leave k /* PF3 was pressed, go to programs end */

12.5 Example of working with tables | 221

Here now a display of the panel SLEP1 containing the data of the table $SLETAB: Screen 12.1: Display of panel SLEP1 produced by the program SLE SLEP1 S -------------- Table display of recently edited data sets Row 1 of 13 COMMAND ===> SCROLL ===> CSR Dynpan= YES-VIO Compile state of SLE Sort: D=Date or N=Name D Max DSNs: 76 NOT COMPILED Insert control for edited data sets ----> All or Change: ALL C Recent DSN in edit Help with PF1 for all fields Date Time ------------------------------------------------------------------------------_ USER001.BOOK1.REXX(SLE) 15/04/08 13:50:44 _ USER001.BOOK1.REXX(SSS) 15/04/08 13:19:47 _ USER001.BOOK2.REXX(TEST2) 15/04/08 09:43:01 _ USER001.BOOK2.REXX(TEST1) 15/04/08 09:06:44 _ USER001.BOOK2.EXAMPLE.REXX(TEST2) 15/04/07 16:22:16 _ USER001.BOOK1.REXX(SPROFVAR) 15/04/07 16:17:28 _ USER001.BOOK2.EXAMPLE.REXX(DB2REXX2) 15/04/04 16:49:18 _ USER001.BOOK2.EXAMPLE.REXX(DB2REXX1) 15/04/04 16:44:19 _ USER001.IBM.REXX(DB2REXXT) 15/04/04 16:32:28 _ USER001.IBM.REXX(DB2REXX1) 15/04/04 16:30:03 _ USER001.IBM.REXX(DB2REXX2) 15/04/04 16:29:44 _ USER001.BOOK1.REXX(SLOGDSN) 15/04/03 15:45:47 _ USER001.REXX(TEST1) 15/04/03 15:44:02

13 Variables – Definition and using In this chapter, you will learn how to define and use ISPF variables. ISPF variables are either automatically known in REXX programs or they can be made known there. 3 Advice: If you intend to use a defined variable in REXX source code and in the called ISPF services, then the variable name must not be longer than eight characters.

The variables of the ISPF services are an important part of ISPF. Dialog variables are the primary communicator between the individual components of ISPF. Programs, procedures, panels, tables and skeletons can all share the variables from the three ISPF variable pools. The three ISPF variable pools are: – Function pool for implicit variables. – Shared pool. – Profile pool. The variables are combined in groups, which are associated with a particular service. Many variables are set only by certain ISPF services. Other variables must be filled with appropriate values before a service that requires these variables is called. A ISPF application ID is assigned to each pool of variables.

13.1 Variables pools As mentioned above, the ISPF variables are arranged in variables pools with the following subdivisions:

13.1.1 Function pool These variables are only known in the currently running function or group of procedures. These include, for example, all variables in a REXX procedure whch names are not longer than eight characters, and the variables of panels, skeletons etc. These variables are called function variables. Each function has its own set of variables. If an item within the ISPF in different logical screens is launched parallel, then the variable exist with the same name several times, but with different contents. These variables can only be exchanged with other functions when you write them in a function in the shared pool and are read in the other function from there.

224 | 13 Variables – Definition and using

When a new function will be started, ISPF creates a variables pool for this function. This pool of variables is deleted at the end of the function. A function is a program or a procedure that can be called with the SELECT service. This means you can exchange variables between these programs or procedures only via the shared or the profile pool.

13.1.2 Shared pool The shared pool contains variables that are used within an application. A variable in this pool is called shared variable. The SELECT service creates a shared pool when executing the commands ISPSTART or ISPF. The same happens when a SELECT is performed using the options NEWAPPL or NEWPOOL . One function may use the VPUT service to copy shared variables into the shared pool, and another function in the same application can use the VGET service to read these variables for using.

13.1.3 Profile pool The variables in this pool will be saved from session to session for each application. This means that the variables of this application are written in a member which is associated with the application in the profiles data set. When the application is started later again, the corresponding member will be read. If you need these variables in a function, you have to read them using the VGET service. To save them so that they are available again the next time you start a function, they must be re-written using the VPUT service into the profile pool before leaving the function. Thus, the variables of profiles pools can be made available from session to session and from application to application. Of course, a data set must exist in which these variables are saved. This data set must be assigned under the DD name ISPPROF as PDS/PDSE before starting the ISPF. If this data set is not assigned, ISPF cannot be started. As mentioned above, the variables in the profiles pool are stored separately for each ISPF application into a member in the profile data set. The name of this member is formed as follows: xxxxPROF, where xxxx is the up to four digits long name of the application. The profile members are created and processed as ISPF tables. The following figure shows an excerpt from the list of members in the ISPPROF data set of my TSO user:

13.2 Creating profile members | 225

Screen 13.1: Members of an ISPPROF data set BROWSE LANZT.ISPF.PROFILE.XYZ1 Command ===> Name Prompt Size . BKMPROF . BSSEDIT . BSSEDRT . BSSPROF . CA7EDIT . CA7PROF . ISFEDIT . ISFPROF . ISPPROF . ISREDIT . ISRPERT . ISRPLIST . ISRPROF . ISRRLIST . QWIKPROF . QWRFPROF **End**

Created

Row 00001 of 00029 Scroll ===> CSR Changed ID

The application dependent members are grayed.

13.2 Saving the profile members If an ISPF application is terminated normally, their profile variables are written back to the appropriate member of the profile data set. The member ISPPROF will only be written back if the ISPF itself terminates. 4 Attention: If ISPF, from whatever reason, is not properly completed or is aborted, then the currently active profile members will not be written back. This means that after a restart of ISPF, all changes made in the profile variables before the demolition are lost. The same applies if a single application aborts. In this case, the profile member containing the application variables will not be secured.

13.3 Creating profile members When ISPF or a new application starts, then ISPF searches for a profile member as follows: 1. First, the user profile associated with the DD name ISPPROF is searched for the member xxxxPROF. If the member is found there, then it is loaded and the profile variables contained therein are available for the application. This means you can now read variables with VGET and write back with VPUT. 2. If the profile member is not found in the ISPPROF chain, then the member will be searched in the ISPTLIB chain. If it is found there, it will used and written back in the ISPPROF data set when the application or ISPF is closed.

226 | 13 Variables – Definition and using

3. When also on the ISPTLIB chain no fitting member for the launched application is found, the default profile member will be read from ISPPROF and copied to the variable pool for this application. When closing the application, its profile member is written into the ISPPROF data set. Consideration: ISPF will be started at the end of the LOGON procedure. This can be done with three different commands: 1. ISPSTART PANEL(name) NEWAPPL(applid). 2. PDF 3. ISPF If called with PDF or ISPF, then the following command is issued internally: ISPSTART PANEL(ISP@PRIM) NEWAPPL(ISR).

This way of calling the ISPF causes the standard APPLID in the ISPF to be ISR. This means that the member ISRPROF is used as standard ISPF profile member. Therefore, if you want to operate your ISPF with the APPLID ISP, then you would have to start your ISPF with the following command: ISPSTART PANEL(ISP@PRIM) NEWAPPL(ISP).

13.4 Display of actually used profile member I have launched several ISPF applications in my TSO user. Then I looked which profile members are loaded now. Here is the first indication of the started applications. I created this display using the ISPF command SWAP LIST. Screen 13.2: List of started ISPF applications Menu Options View Utilities Compilers Help ┌─────────────────── ISPF Task List ────────────────────┐ │ Active ISPF Logical Sessions │ │ │ │ . Start a new screen │ │ . Start a new application │ │ Application Name │ │ _____________________________________________ │ │ │ │ ID Name Panelid Applid Session Type │ │ . 1 SDSF ISFPCU41 ISF 3270 │ │ . 2 ISRDDN ISRDENQG ISR 3270 │ │ . 3 PG92PRIM BSS 3270 │ │ . 4QWIKREFD QWIK 3270 │ │ . 5* $LANZT ISRUDSL0 ISR 3270 │ │ . 6 SMQPROD EQ2MMENU SMQP 3270 │ │ . │ └───────────────────────────────────────────────────────┘

13.5 The System Profile Pool | 227

When these applications are launched, then all members belonging to these applications profiles must be loaded. This can be checked very easily by looking up which ENQs exist on the data set containing the profile members. The easiest way to check this is using the utility DDLIST. Therefore, I called DDLIST and entered ENQ in the command line. In the appearing panel, I entered as minor name prefix the DSN of my profile data set LANZT.ISPF.PROFILE.LPRT and pressed ENTER. The following ENQs are displayed: System ENQ Status Command ===>

Row 1 of 12 Scroll ===> CSR

Scroll LEFT or RIGHT to see type or system name. Major name prefix . . . (SYSDSN, SPFEDIT, etc) Minor name prefix . . . LANZT.ISPF.PROFILE.LPRT (dsn etc) Address id prefix . . . (Job name, User id, etc) System prefix . . . . . (System name) Major Minor Job Name ┌──────────┬──────────────────────────────────────────────────────┬──────────┐ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT BSSPROF │ LANZT │ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT ISFPROF │ LANZT │ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT ISPPROF │ LANZT │ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT ISPSPROF │ LANZT │ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT ISREDIT │ LANZT │ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT ISREDRT │ LANZT │ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT ISRLLIST │ LANZT │ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT ISRPLIST │ LANZT │ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT ISRPROF │ LANZT │ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT SMQPPROF │ LANZT │ │ SPFEDIT │ LANZT.ISPF.PROFILE.LPRT QWIKPROF │ LANZT │ │ SYSDSN │ LANZT.ISPF.PROFILE.LPRT │ LANZT │ └──────────┴──────────────────────────────────────────────────────┴──────────┘

As you can see, the corresponding profile members are loaded and ENQed for all open applications.

13.5 The System Profile Pool ISPF contains own variables that can be used by the user, but not overwritten. These variables are always present. They are stored in the member ISPSPROF. This member is always loaded when ISPF starts. The system profiles pool is located behind the ISPF standard pool. Therefore, if you read a variable from the system profile pool, you can put it back in the standard profiles pool. However, you must observe the following: 4 Attention: When you read a variable from the system profile pool, you can change it and write it back. In this case, the changed variable be stored in the standard profile pool. Afterwards is it impossible to read the origin variable again from the system profile pool. If you delete the variable using the VERASE command, you can read then the origin variable from the system profile pool again.

228 | 13 Variables – Definition and using

1 Tip: In the brochure, ISPF Dialog Developer’s Guide and Reference there are several attachments, where all standard ISPF variables are described.

13.5.1 Frequently used ISPF variables As mentioned above, many ISPF variables are only provided when certain services are running. These variables can be found in the description of the respective services. However, there is a whole range of ISPF variables that you can make good use of when creating applications in ISPF. If you want to use these variables in a REXX program, then you can read the appropriate variables using the command ISPEXEC VGET (name1, name2, ...). In the two tables below, I listed several ISPF system variables that are used most frequently:

13.5.1.1 General ISPF variables Table 13.1: General ISPF system variables

Variable

Type Length Content

Z

Char 0

Null Variable. This variable is often used for comparisons.

ZCMD

Char 256

Contains the command entered in the command line of an ISPF panel, but only if this is not an ISPF command to branch to a particular panel (e.g. =3.14).

ZAPPLID

Char 8

Contains the name of currently active application.

ZDEL

Char 1

ISPF delimiter character.

ZENVIR

Char 32

ISPF environment description. e.g. ISPF 5.9MVS

ZISPFRC

Num 8

Used to pass the return code upon exiting an ISPF function.

ZLANG

Char 8

Contains the session language.

ZLOGON

Char 8

ZPANELID Char 8 ZPREFIX

Char 8

ZSCREENW Num 4

Step-name of the TSO logon procedure. Name of the currently displayed panel. TSO user prefix. Width of a line of the panel display

ZSCREENC Num 5

Position of the cursor within the string ZSCREENI.

ZSCREENI Char ?

Text string of the entire visible window.

TSO

13.5 The System Profile Pool | 229

13.5.1.2 System variables containing date and time in different variations Variable

Type Length Content

ZDATE

Char 8

ZDATEF

Char 8

Current date format. e.g. YY/MM/DD

ZDATEFD

Char 8

The date format in the national language format.

Current date in the form in which it is determined by ZDATEF and ZDATEFD.

ZDATESTD Char 8

Date of the year with four digits. e.g. 2015/05/12

ZDAYOFWK Char 8

Weekday

ZDAY

Char 2

Day in the month.

ZJDATE

Char 6

Julian Day in the form JJ.DDD.

ZJ4DATE

Char 8

Julian Day in the form JJJJ.DDD.

ZMONTH

Char 2

ZSTDYEAR Char 4

Month. Four-digit year.

ZTIME

Char 5

Time in the form HH:MM.

ZTIMEL

Char 11

Time in the form HH:MM:SS:zz. zz=1/100 Sek.

ZYEAR

Char 2

Two character year.

13.5.2 Process ISPF variables There are exactly three commands that you can use with REXX to work with ISPF variables. These are: VGET  Read variables VPUT  Write variables VERASE  Delete variables Formats of the three commands VGET (name-list) ASIS | SHARED | PROFILE ASIS SHARED PROFILE

The variable will initially be searched in the shared pool. If it is not found there, the search is continued in the profile pool. The variable is searched only in the shared pool. If it is not found there, the command ends with a RC=8. The variable will be searched only in profile pool. If it is not found there, the command ends with a RC=8 and a variable of the same name in the shared pool will be deleted.

VPUT (name-list) ASIS | SHARED | PROFILE ASIS

The variable is written to the pool, where it already exists. If it exists nowhere, it is written into the shared pool. If it already exists in the shared pool and in the profile pool, it is only changed in the shared pool.

230 | 13 Variables – Definition and using

SHARED PROFILE

The variable is only written to the shared pool. The variable is only written to the profile pool. A variable of the same name in the shared pool is deleted.

VERASE (name-list) ASIS | SHARED | PROFILE | BOTH ASIS SHARED PROFILE BOTH

The variable is deleted from the shared pool. If it does not exist there, it is tried to delete them from the profile pool. The variable is deleted from the shared pool. The variable is deleted from the profile pool. The variable is deleted from the shared and from the profile pool.

3 Remark: All REXX variables whose name is not longer than eight characters are automatically known in function pool. If you want to write a REXX variable into the shared or profile pool, you must explicitly use a VPUT command.

Example: I wrote a small REXX procedure to read and display some ISPF Z-variables: Program 13.1: ZVARS – Display some ISPF Z-variables /* DOC: ZVARS REXX MAIN */ /* DOC: Display some Z variables of ISPF */ /* © FRANZ LANZ 2015 */ /*************************************************************/ address "ISPEXEC" "VGET (ZDATE ZDATE ZDATEF ZDATEFD ZDATESTD ZDAYOFWK ZDAY ZJDATE", "ZJ4DATE ZMONTH ZSTDYEAR ZTIME ZTIMEL ZYEAR ZUSER ZLOGON ", "ZSYSID ZAPPLID ZDEL ZENVIR ZLANG ZPANELID ZPREFIX)" say say say say say say say say say say say say say say say say say say say say say say

"ZDATE "ZDATEF "ZDATEFD "ZDATESTD "ZDAYOFWK "ZDAY "ZJDATE "ZJ4DATE "ZMONTH "ZSTDYEAR "ZTIME "ZTIMEL "ZYEAR "ZUSER "ZLOGON "ZSYSID "ZAPPLID "ZDEL "ZENVIR "ZLANG "ZPANELID "ZPREFIX

= = = = = = = = = = = = = = = = = = = = = =

"ZDATE "ZDATEF "ZDATEFD "ZDATESTD "ZDAYOFWK "ZDAY "ZJDATE "ZJ4DATE "ZMONTH "ZSTDYEAR "ZTIME "ZTIMEL "ZYEAR "ZUSER "ZLOGON "ZSYSID "ZAPPLID "ZDEL "ZENVIR "ZLANG "ZPANELID "ZPREFIX

13.5 The System Profile Pool | 231

I executed this procedure and got the following result: ZDATE ZDATEF ZDATEFD ZDATESTD ZDAYOFWK ZDAY ZJDATE ZJ4DATE ZMONTH ZSTDYEAR ZTIME ZTIMEL ZYEAR ZUSER ZLOGON ZSYSID ZAPPLID ZDEL ZENVIR ZLANG ZPANELID ZPREFIX

= = = = = = = = = = = = = = = = = = = = = =

15/05/12 YY/MM/DD YY/MM/DD 2015/05/12 Tuesday 12 15.132 2015.132 05 2015 13:29 13:29:00.72 15 USER001 ESSUSER TESTMVS ISR ; ISPF 5.9MVS ENGLISH ISREDDE4

TSO

14 Edit macros – Create and apply In this chapter, you will learn how you create and use edit macros. With edit macros will recurring tasks are performed quickly and elegantly. To get the full benefit of the ISPF editor, edit macros in my opinion are indispensable. We have already extensively worked in the first part of this book on the operation of the ISPF editor; therefore, we now want get to know another very interesting part of the ISPF editor. There are many activities in ISPF where a certain automation may be helpful. These are, for example, the preparation and the SUBMIT batch jobs, the edit output lists, etc. For such tasks, the use of edit macro is a very nice aid. This recurring work can be always greatly accelerated and facilitated. The SMART ISPF utilities contains a series of such useful macros. In the literature collection for ISPF there is a brochure in which next to the description of the manual operation of the editor, also the creation of edit macro is described. This brochure is ISPF Edit and Edit Macros.

14.1 What is an edit macro? An edit macro is a REXX procedure that contains special commands for the ISPF editor beside the REXX commands. These edit commands are passed to the ISPF editor to run under the ADDRESS label ISREDIT. Of course, in an edit macro, all other commands are possible, which can occur in REXX procedures. Edit macros can be executed as follows: – Enter in the command line of ISPF editor the name of the edit macro procedure. This is the normal way to execute edit macro. – Use the command EDIT DATASET(dsn) MACRO(name) in a REXX procedure. – Define initial and/or end macros for editing data.

14.1.1 Naming conventions for edit macros The name of an edit macro must only correspond to those of REXX procedures. However, I have found in the course of my work in the ISPF that it may be well of advantage to use a naming convention for the edit macros. The advantage is that you can distinguish them from the rest of REXX procedures. I always start the name of my edit macro with the # character. This has the advantage that the names of my edit macro stand on the top in the REXX procedures data set directory consecutively.

234 | 14 Edit macros – Create and apply

Even if I look for a template for a new edit macro, I need only look up the members that start with #. In addition, it is abundantly clear that you can never call an edit macro like a normal procedure. The commands that are addressed to the editor are only executable when the REXX procedure runs under control of the editor. If an edit macro is called from within a REXX procedure using the EDIT command, I call it up the same way as calling the REXX procedure by prefixing the procedure name with the # character.

14.1.2 Example of two very useful edit macros Before we go into the details of programming edit macros, I want to show you a simple example what an edit macro can supply. The first macro #SSS The SMART ISPF utilities contain the program SSS. SSS stands for Smart Super Search. This program uses the standard ISPF program ISRSUPC to perform the search. This program produces a list output. This list is very elaborate. It contains many needless lines. I have therefore written an edit macro, which removes all unnecessary texts from this list. According to the naming conventions mentioned above, the name of the macro is #SSS. The second macro #SSSCH When the editor displays the resulting list of the search, you can change some lines in this list. If you then call the macro #SSSCH, the lines currently being edited replace the lines in the members. Using this technique, you can perform mass changes in all members of a PDS very easy and very quickly. The program SSS works as follows: 1. The program SSS is called by entering SSS in front of a DSN in a DSLIST display panel. The search will be performed for all members of this partitioned data set. 2. The program then displays a panel, which is designed to enter the search arguments. 3. After pressing ENTER, the program calls ISRSUPC and the search starts. The program ISRSUPC writes the search results in a temporary sequential data set. 4. The ISPF editor is called in the REXX program using the following statement "EDIT DATAID("UTID") MACRO(#SSS)" The DATAID UTID was established by a LMINIT command earlier in the program. 5. The macro #SSS removes all needless lines from the data set before the list is displayed.

14.1 What is an edit macro? | 235

Example for using of both above mentioned macros: Task: I would like to know in which programs of the SMART ISPF utilities the ISPF service QUERYENQ is used. Step 1: I enter SSS in front of the PDS where the SMART ISPF utility programs are located. The following panel will displayed. In the field 1. = I enter the search text QUERYENQ. Screen 14.1: Panel SSSP1 for entering search arguments SSSP1 --------------- Enter commands for Super-Search execution -------------COMMAND ===> DSN = 'USER001.BOOK1.REXX' 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

If the data set is a PDS all members are scanned!

= 'QUERYENQ' = = = = = = = = =

PO = ASIS____________________________________________________________________ Fill in here more process options. Press PF1 for help and then select a theme by number or press ENTER to scroll thru pages down continuously. MSG1= Press PF1 for Help, press ENTER to execute the search.

When enter is pressed, the search will performed and the following edit panel is displayed: Screen 14.2: Resulting panel after executing a SSS search ISREDDE4 SYS15133.T074428.RA000.USER001.R0172391 Columns 00001 00072 Command ===> Scroll ===> CSR ****** ***************************** Top of Data ****************************** 000001 ************************************************************************ 000002 * List is optimized by macro #SSS * 000003 * Use macro #SSSCH to store lines back * 000004 ************************************************************************ 000005 SRCH DSN: USER001.BOOK1.REXX ******************************************* 000006 SCURSOR 000007 205 s = queryenq(enqt) 000008 SLE 000009 7 /* 2014.10.21 QUERYENQ handling changed 000010 200 call queryenq "E" 000011 237 call queryenq "E" 000012 275 call queryenq "I" 000013 484 queryenq: procedure expose dsn zscreen enqs 000014 487 /* Paramter considerations for QUERYENQ calling: 000015 504 "QUERYENQ TABLE("enqtab") RNAME(ENQRN) QNAME(QNAME) REQ(%*)" 000016 SSC 000017 237 "QUERYENQ TABLE("enqtab") RNAME(OLDDSN) QNAME(QNAME) REQ(%*) X ****** **************************** Bottom of Data ****************************

236 | 14 Edit macros – Create and apply

The program ISRSUPC produces a list with LRECL=133. Therefore, the lines of this display are cut off on the right side. To see what lines by the macro #SSS were removed, here is the origin output of the program ISRSUPC: Screen 14.3: Original output list of program ISRSUPC ISREDDE4 USER001.SRCHFOR.LIST Columns 00001 00072 Command ===> Scroll ===> CSR ****** ***************************** Top of Data ****************************** 000001 1 ISRSUPC MVS/PDF FILE/LINE/WORD/BYTE/SFOR COMPARE UTILITY- ISPF 000002 LINE-# SOURCE SECTION SRCH DSN: USER001.BOOK1.REXX 000003 000004 000005 SCURSOR --------- STRING(S) FOUND ---------------000006 000007 205 s = queryenq(enqt) 000008 000009 SLE --------- STRING(S) FOUND ---------------000010 000011 7 /* 2014.10.21 QUERYENQ handling changed 000012 200 call queryenq "E" 000013 237 call queryenq "E" 000014 275 call queryenq "I" 000015 484 queryenq: procedure expose dsn zscreen enqs 000016 487 /* Paramter considerations for QUERYENQ calling: 000017 504 "QUERYENQ TABLE("enqtab") RNAME(ENQRN) QNAME(QNAME) REQ(%*)" 000018 000019 SSC --------- STRING(S) FOUND ---------------000020 000021 237 "QUERYENQ TABLE("enqtab") RNAME(OLDDSN) QNAME(QNAME) REQ(%*) X 000022 000023 1 ISRSUPC MVS/PDF FILE/LINE/WORD/BYTE/SFOR COMPARE UTILITY- ISPF 000024 SEARCH-FOR SUMMARY SECTION SRCH DSN: USER001.BOOK1.REXX 000025 000026 LINES-FOUND LINES-PROC MEMBERS-W/LNS MEMBERS-WO/LNS COMPARE-COLS L 000027 9 8101 3 31 1:80 000028 000029 PROCESS OPTIONS USED: ANYC 000030 000031 THE FOLLOWING PROCESS STATEMENTS (USING COLUMNS 1:72) WERE PROCESSED: 000032 SRCHFOR 'QUERYENQ' 000033 ****** **************************** Bottom of Data ****************************

As you can see, the list is reduced from 33 lines to 17 lines.

14.1 What is an edit macro? | 237

Step 2: As you can see in line 487 of the program SLE, the word Paramter is wrong. I will now correct this error. First, I remove all unneeded lines and correct the wrong word to Parameter. Then the following edit panel remains: ISREDDE4 SYS15133.T081411.RA000.USER001.R0172394 Columns 00001 00072 Command ===> #SSSCH Scroll ===> CSR ****** ***************************** Top of Data ****************************** 000001 ************************************************************************ 000002 * List is optimized by macro #SSS * 000003 * Use macro #SSSCH to store lines back * 000004 ************************************************************************ 000005 SRCH DSN: USER001.BOOK1.REXX ******************************************* 000006 SLE 000007 487 /* Parameter considerations for QUERYENQ calling: ****** **************************** Bottom of Data ****************************

I enter #SSSCH in the command line and press enter. The following display appears: ISREDDE4 SYS15133.T081411.RA000.USER001.R0172394 Columns 00001 00072 Command ===> Scroll ===> CSR ****** ***************************** Top of Data ****************************** 000001 ************************************************************************ 000002 * List is optimized by macro #SSS * 000003 * Use macro #SSSCH to store lines back * 000004 ************************************************************************ 000005 SRCH DSN: USER001.BOOK1.REXX ******************************************* 000006 SLE 000007 487 /* Parameter considerations for QUERYENQ calling: ****** **************************** Bottom of Data **************************** *-------------------------------* | 1 Lines changed in 1 members. | *-------------------------------*

What shall the macro #SSS do with the list produced by ISRSUPC? – Remove any blank lines. – Remove all lines that start with the following texts: ISRSUPC, PROCESS OPTIONS USED, THE FOLLOWING PROCESS. – Shift the lines where the name of the text SEARCH DNS: scanned data set appears together with the DSN as far to the left that the DSN text starts at column one. – Remove the lines that begin with LINES-FOUND together with the next line. – At the beginning of the revised text put a notice that this data set has been optimized by macro #SSS. – Inserting a row by pointing out that using the edit macros #SSSCH, the edited and possibly changed lines can be written back to the members. Here the source codes of both macros:

238 | 14 Edit macros – Create and apply

Program 14.1: Edit macro #SSS /* DOC: #SSS REXX MACRO */ /* DOC: Remove unnecessary parts from SCHFOR list. */ /* DOC: Parms: none */ /* © FRANZ LANZ 2015 */ /*---------------------------------------------------------------*/ /* Functional description: */ /* Delete all unnecessary lines from a list produced by the ISPF */ /* program ISRSUPC, which is called by the program SSS of the */ /* SMART ISPF utilities. The program SSS calls this macro as */ /* initial macro. If you have a manually search performed you */ /* can also use this macro to revise the list output. */ /*****************************************************************/ "ISPEXEC CONTROL ERRORS RETURN" address "ISREDIT" "MACRO" /*****************************************************************/ /* Remove all unnecessary lines. */ /*****************************************************************/ "exclude '"copies(" ",50)"' all 1 50" "exclude 'ISRSUPC' all word" "exclude 'PROCESS OPTIONS USED:' all" "exclude 'THE FOLLOWING PROCESS' all" "exclude 'SRCHFOR' 4 12 WORD all" "delete x all" "change '--------- STRING(S) FOUND -------------------' ' ' all" "cursor = 1 1" do i = 1 "find 'LINES-FOUND' next" if rc > 0 then leave i "(ll,cl) = CURSOR" "delete "ll ll+1 end i /*****************************************************************/ /* Insert listing haeder */ /*****************************************************************/ "line_before 1 = '"copies("*",72)"'" "line_before 1 = '*", center("Use macro #SSSCH to store lines back",68), "*'" "line_before 1 = '*", center ("List is optimized by macro #SSS",68), "*'" "line_before 1 = '"copies("*",72)"'" "RESET" "CURSOR = .ZF 1" /*****************************************************************/ /* Process SRCH DSN: lines */ /*****************************************************************/ do i = 1 "FIND 'SRCH DSN:' NEXT" if rc > 0 then leave i "(cl,cc) = cursor" if cc > 1 then "shift ( .zcsr "cc-1 "(Z) = LINE .ZCSR" "LINE .ZCSR = '"strip(z) copies("*",60)"'" "LABEL .ZCSR = .A" cl = cl + 1 "(NZ) = LINE "cl if word(nz,1) = "SRCHFOR" then do "LABEL "cl" = .B" "DELETE .A .B" "CURSOR = "cl-2 cc end else "RESET LABEL" end i

14.1 What is an edit macro? | 239

/*****************************************************************/ /* Delete all 'SRCH DSN:' lines except the first one. */ /*****************************************************************/ "CURSOR = 1 1" "FIND 'SRCH DSN:' FIRST" do i = 1 "FIND 'SRCH DSN:' NEXT" if rc > 0 then leave i "(cl,cc) = cursor" "DELETE.ZCSR" end i "UP MAX" "RESET" exit 1 /* Put cursor into Command Line */

Program 14.2: Edit macro #SSSCH /* DOC: #SSSCH REXX EDIT MACRO */ /* DOC: This edit macro can be used to restore the amended lines */ /* DOC: of a super search list back into the members of the PDS. */ /* © FRANZ LANZ 2015 */ /******************************************************************/ "ISPEXEC CONTROL ERRORS RETURN" "ISREDIT MACRO" "ISREDIT (ZL) = LINENUM .ZL" "ISREDIT (ZS) = LINE 5" if substr(zs,1,9) "SRCH DSN:" then do zedlmsg = "The 5th line does not contain the data set name.", "This list is probably not yet processed by macro #SSS.", "Type in #SSS in the Command line and press ENTER." "ISPEXEC SETMSG MSG(ISRZ001)" exit 1 end workdsn = word(zs,3) "ISREDIT (ZS) = LINE 6" mem = strip(zs) rem = "" /* String to save member names */ /******************************************************************/ /* Initiate files */ /******************************************************************/ "ISPEXEC LMINIT DATAID(IN) DATASET('"workdsn"') ENQ(SHR)" "ISPEXEC LMINIT DATAID(ut) DATASET('"workdsn"') ENQ(SHRW)" "ISPEXEC LMOPEN DATAID("IN")" "ISPEXEC LMOPEN DATAID("UT") OPTION(OUTPUT)" "ISPEXEC LMMFIND DATAID("IN") MEMBER("mem")" if rc > 0 then do zedlmsg = "Member "mem" was not found in PDS. You have probably", "changed the member name. Correct this and retry." "ISPEXEC SETMSG MSG(ISRZ001)" "ISREDIT FIND "mem" FIRST 3" call exit end imem = 0 irbeg = 1 /* Line counter for readimg members */ ich = 0 /* Change counter */ /******************************************************************/ /* Main processing routine */ /******************************************************************/ do izl = 6 to zl /* Loop to process edited lines */ "ISREDIT (Z) = LINE "izl z = strip(z,"T") if words(z) = 1 & datatype(word(z,1)) "NUM" then do do ir = 1 /* Copy the rest of the member */ "ISPEXEC LMGET DATAID("IN") MODE(LOCATE)", "DATALOC(ZADR) DATALEN(INL) MAXLEN(32760)" if rc = 8 then leave ir "ISPEXEC LMPUT DATAID("UT") MODE(MOVE)", "DATALOC(ZADR) DATALEN("INL")" end ir

240 | 14 Edit macros – Create and apply

"ISPEXEC LMMREP DATAID("UT") MEMBER("mem")" rem = rem mem /* Save member names for LMMSTATS */ mem = strip(z) "ISPEXEC LMMFIND DATAID("IN") MEMBER("mem")" if rc > 0 then do zedlmsg = "Member "mem" was not found in PDS.", "You have probably changed the member name.", "Correct this and retry." "ISPEXEC SETMSG MSG(ISRZ001)" "ISREDIT FIND "mem" FIRST 3" call exit end imem = imem + 1 irbeg = 1 iterate izl end inline = word(z,1) /* Get number of line to be changed */ do iread = irbeg /* Process lines of a member */ "ISPEXEC LMGET DATAID("IN") MODE(LOCATE)", "DATALOC(ZADR) DATALEN(INL) MAXLEN(32760)" if rc = 8 then leave iread if iread = inline then do rc = storage(d2x(zadr),inl,substr(z,11,inl)) ich = ich + 1 end "ISPEXEC LMPUT DATAID("UT") MODE(MOVE)", "DATALOC(ZADR) DATALEN("INL")" if iread = inline then do irbeg = iread + 1 iterate izl end end iread end izl do ir = 1 /* Copy the rest of the member */ "ISPEXEC LMGET DATAID("IN") MODE(LOCATE)", "DATALOC(ZADR) DATALEN(INL) MAXLEN(32760)" if rc = 8 then leave ir "ISPEXEC LMPUT DATAID("UT") MODE(MOVE)", "DATALOC(ZADR) DATALEN("INL")" end ir "ISPEXEC LMMREP DATAID("UT") MEMBER("mem")" rem = rem mem /* Collect member names for LMMSTATS */ zedlmsg = ich "Lines changed in "imem" members." "ISPEXEC SETMSG MSG(ISRZ001)" exit: "ISPEXEC LMCLOSE DATAID("IN")" "ISPEXEC LMFREE DATAID("IN")" "ISPEXEC LMCLOSE DATAID("UT")" /* Due to LMMREP, statistics are lost. */ /* Now set new one with USERID #SSCH. So we see #SSCH was here */ do i = 1 to words(rem) mem = word(rem,i) "ISPEXEC LMMSTATS DATAID("UT") MEMBER("mem") USER(#SSCH)" end i "ISPEXEC LMFREE DATAID("UT")" exit 1

3 Conclusion: With the program SSS of the SMART ISPF utilities and its edit macros, you have a very strong tool for searching and changing mass data. Additionally, these two edit macros are well suited to explain the using of edit macros.

14.2 Table of edit macro commands | 241

14.2 Table of edit macro commands Edit macro command types: The edit macro commands are generally divided into two types: First type: editor action command: "CURSOR = line col".

This command positions the cursor on line line and column col in the edited data. Second type: assignment commands This commands set values into variables: "(line,col) = cursor".

The variable line contains the cursor position of the current line and the variable col the column in the line of the data currently being edited. As you can see in the following table, many edit macro commands offer both possibilities. The following table is a condensed summary of the main edit macro commands as can be used in a REXX procedure. Of course, the IBM brochure Edit and edit Macros also contains a description of the edit macro commands. However, this is presented in a very confusing manner. Incidentally, this is one of the reasons why this book has been written. Therefore, I make an effort to present the reader a focused summary in the following table. Table 14.1: Edit macro commands

Commands

Description

AUTOLIST [ON ] [OFF] (var) = AUTOLIST

Turns AUTOLIST item on or off or sets its status in var.

AUTONUM [ON ] [OFF] (var) = AUTONUM

Turns AUTONUM item on or off or sets its status in var.

AUTOSAVE [ON] [OFF PROMPT] [OFF NOPROMPT] (var1,var2) = AUTOSAVE

Stores the AUTOSAVE mode or returns its status.

(var) = BLKSIZE

Stores the block size of the data set currently being edited into var.

BOUNDS [left-col right-col] (var1,var2) = BOUNDS

Sets the left and right text boundaries or puts these limits into variables.

242 | 14 Edit macros – Create and apply

Commands

Description

BROWSE member

Browses a member that is contained in the same PDS as the member currently being edited.

BUILTIN cmdname

Runs a macro command in its original form even if it has been implemented by DEFINE xxx ALIAS to another name.

CANCEL

Finishes the edit session without saving the data currently being edited.

CAPS [ON ] [OFF] (var) = CAPS

Sets the CAPS mode or stores its status in the variable var

CHANGE string-1 string-2 [label-range] [X] [NX][ALL] [NEXT] [CHARS] [col1 col2] [PREFIX] [SUFFIX] [FIRST] [LAST][WORD][PREV]

Changes data currently being edited. As you can see, this command offers many options. Do your own tests.

(var1,var2) = CHANGE_COUNTS

Returns from the last executed change command the number of successful changes in var1 and the unsuccessful changes in var2.

COMPARE {dsn|NEXT|SESSION|*} [{EXCLUDE} {SAVE} {SYSIN}]

Compares another data set with the data currently being edited.

COPY member {AFTER} lptr [linenum-range] (member) {BEFORE} dsn

Copies a member or a data set into the data currently being edited.

CREATE member lptr-range (member) {range} dataset(member) {range}

Creates a new member from the data currently being edited.

(var1,var2) = CURSOR CURSOR = lptr [col]

Stores row and column of the cursor position in two variables or positions the cursor on a specific location.

CUT [lptr-range] [DEFAULT|clipboardname] [REPLACE|APPEND]

Copies a selected number of lines into the edit clipboard.

(var) = DATA_CHANGED

Saves the DATA CHANGED status (YES | NO) in a variable.

(var) = DATA_WIDTH

Stores the line width of the data currently being edited into a variable.

(var) = DATAID

Stores the DATAID of the temporary internal data set of the editor into a variable.

(var1,var2,var3) = DATASET

Returns the DSN of the data set currently being edited.

DEFINE name {MACRO CMD {MACRO PGM } {ALIAS name-2} {NOP } {RESET } {DISABLED }

– – –

}



Assigns an alias to a macro or command. Blocks the use of a macro or command. Sets a macro name to a command of the same name. Identifies macros as such.

14.2 Table of edit macro commands | 243

Commands

Description

DELETE {ALL [lptr-range]} Deletes a number of lines of the data currently {[ALL] lptr-range X|NX } {lptr-range} being edited. (var1,var2) = DISPLAY_COLS

Returns the first and last column in the panel.

(var1,var2) = DISPLAY_LINES

Determines the first and last line when a macro ends.

DOWN amt

Moves the cursor down for amt lines.

EDIT member

Edits another member of the same PDS.

END

Exits the edit session and saves the data currently being edited.

EXCLUDE string [label-range] [NEXT ] [CHARS ] [col-1 [col-2]] [ALL] [PREFIX] [SUFFIX] [FIRST] [LAST] [WORD]

Makes the selected lines invisible. These can then be addressed by the X (= excluded) option in editing commands.

(var1,var2)=EXCLUDE_COUNTS

Returns the number of excluded line groups (var1) and the number of excluded lines (var2).

FIND string [label-range] [NEXT] Searches for the data given in STRING. If such [ALL] [X] [NX] [CHARS][col-1 [col-2]] data are found in excluded lines, these lines are [PREFIX] [SUFFIX] [FIRST][LAST ] included. [WORD] [PREV] (var1,var2) = FIND_COUNTS

Returns by a FIND or RFIND the number of values found in total (var1) and the number of lines in which values were found (var2).

FLIP [label-range]

Switches between the display of excluded and visible lines back and forth.

(var1,var2) = FLOW_COUNTS

Returns the values of the last TFLOW statement.

HEX [ON DATA] [ON VERT] [OFF] (var1,var2) = HEX

Sets the hexadecimal mode or returns its status.

HILITE [ON] [AUTO] [RESET] [PAREN] [FIND] [CURSOR] [SEARCH] [DISABLED] [OFF] [DEFAULT] [LOGIC] [OTHER] [IFLOGIC] [ASM] [DOLOGIC] [BOOK] [NOLOGIC] [C] [COBOL] [DTL] [JCL] [PANEL] [PASCAL] [PLI] [REXX] [SKEL]

Sets the HILITE characteristics. The COLORED code is set for the editor here. These defined characteristics are valid in all edit sessions of data sets with the same LLQ.

IMACRO {name|NONE} (var) = IMACRO

Defines an IMACRO or returns the macro name of the IMACRO or NONE.

INSERT lptr [numlines]

Inserts numlines blank lines for the input of data.

LABEL lptr = labelname [level] (var1,var2) = LABEL lptr

Sets or returns the values of the line pointer.

LEFT amt

Shifts lines to the left by amt columns.

LEVEL num (var) = LEVEL

Sets or returns the modification level of the data set currently being edited.

244 | 14 Edit macros – Create and apply

Commands

Description

LINE lptr = data (var) = LINE lptr

Replaces a line or transfers the data of a line in a variable.

LINE_AFTER lptr = data [DATALINE] [INFOLINE] [MSGLINE ] [NOTELINE]

Inserts a row after an existing row.

LINE_BEFORE lptr = data [DATALINE] [INFOLINE] [MSGLINE ] [NOTELINE]

Inserts a row before an existing row.

(var) = LINE_STATUS lptr

Determines the line status.

(var) = LINENUM label

Gets the line number of an addressed line.

LOCATE lptr LOCATE lptr-range] {CHANGE} {COMMAND} [NEXT] {ERROR} [PREV] [LAST] [FIRST] {EXCLUDED} {LABEL} {SPECIAL} {INFOLINE} {MSGLINE} {NOTELINE}

Moves the cursor to the beginning of a line, which is selected by the operand lptr.

(var) = LRECL

Returns the LRECL of the data set currently being edited.

MACRO [(var1 [,var2,...])] [PROCESS] [NOPROCESS]

Starts a macro in a REXX procedure.

(var) = MACRO_LEVEL

Returns the staggering depth of the called macros.

MASKLINE = data (var) = MASKLINE

Sets or gets a mask line structure.

(var) = MEMBER

Returns the name of the member currently being edited.

MODEL model-name [qualifier] {AFTER } {BEFORE} lptr [NOTES][NONOTES] MODEL CLASS class-name

Copies a dialogue model into the data currently being edited.

MOVE member {AFTER}{BEFORE} lptr (member) |data set name |data.set.name(member)

Moves an external data set into the data currently being edited.

NONUMBER

Switches the line numbering to OFF.

NOTES [ON ] [OFF] (var) = NOTES

Sets or returns the NOTES mode.

NULLS [ON STD] [ON ALL] [OFF] (var1,var2) = NULLS

Sets or returns the NULLS mode.

NUMBER [ON] [OFF] [STD] [DISPLAY] [COBOL] [STD COBOL] [NOSTD] [NOCOBOL] [NOSTD NOCOBOL] (var1,var2) = NUMBER

Sets or returns the NUMBER mode.

PACK [ON] [OFF] (var) = PACK

Sets or returns the PACK mode.

14.2 Table of edit macro commands | 245

Commands

Description

PASTE [AFTER] lptr [clipboardname] [BEFORE][KEEP]

Copies or moves data from the clipboard into the data currently being edited.

PRESERVE [ON][OFF] (var) = PRESERVE

Sets or returns the PRESERVE mode.

PROCESS [DEST] [RANGE cmd1 [cmd2]]

Determines when the entered data are activated.

PROFILE [name] [number] PROFILE {LOCK|UNLOCK} RESET (var1,var2) = PROFILE

Sets or returns PROFILE values.

(var) = RANGE_CMD

Identifies a line command which was processed by a macro.

RCHANGE

Repeats a CHANGE command.

(var) = RECFM

Returns the RECFM of the data set currently being edited.

RECOVERY [ON ] [OFF [WARN]] [OFF [NOWARN]] (var) = RECOVERY

Sets or returns the RECOVERY mode.

RENUM [ON] [STD] [DISPLAY] [COBOL] [STD COBOL]

Turns the NUMBER to ON and renumbers the data currently being edited.

REPLACE REPLACE REPLACE REPLACE

Replaces a data set or member through the data currently being edited.

member lptr-range (member) lptr-range dataset lptr-range dataset(member) lptr-range

RESET [CHANGE] [lptr-range] [COMMAND ] [ERROR ] [EXCLUDED] [FIND ] [LABEL ] [SPECIAL ]

Resets the status of the data set currently being edited.

RFIND

Repeats a FIND command to a previously deposed SEEK, FIND or CHANGE command.

RIGHT amt

Shifts the edited lines for amt columns to the right.

RMACRO {name | NONE} (var) = RMACRO

Saves the name of a recovery macro in the edit profile or returns its name in var.

SAVE

Saves the data currently being edited.

(var) = SAVE_LENGTH .lptr SAVE_LENGTH .lptr = value

Gets or sets the data length for saving the data in a VB data set.

SCAN [ON ] [OFF] (var) = SCAN

Switches the SCAN mode ON or OFF or returns its status.

SEEK string [label-range] The SEEK macro command finds one or more [NEXT ] [CHARS ] [X ] [col-1 [col-2]] occurrences of a search string without changing [ALL] [PREFIX] [NX] [FIRST] the exclude status of the line. [SUFFIX] [LAST] [WORD] [PREV]

246 | 14 Edit macros – Create and apply

Commands

Description

(var1,var2) = SEEK_COUNTS

Retrieves the values set by the most recently processed SEEK command and places them in variables.

(var1,var2) = SESSION

Identifies the type of session in which a macro is running.

SHIFT ( lptr [n] [2]

Shifts columns to the left.

SHIFT ) lptr [n] [2]

Shifts columns to the right.

SHIFT < lptr [n] [2]

Shifts data to the left.

SHIFT > lptr [n] [2]

Shifts data to the right.

SORT [sort-field1 ... sort-field5] [label-range] [X] [NX]

Sorts the data currently being edited.

STATS [ON ] [OFF] (var) = STATS

Switches the STATS mode ON or OFF or returns its value.

SUBMIT [lptr-range]

Submits the data currently being edited to run as a batch job.

TABS [ON ] [STD] [OFF] [ALL][tab-character] (var1,var2) = TABS

Switches the TABS mode ON or OFF or returns its values.

TABSLINE = data (var) = TABSLINE

Sets the TABSLINE respectively returns its contents.

TENTER lptr [numlines]

Switches the screen to enter mass data.

TFLOW lptr [col]

Restructures paragraphs.

TSPLIT [lptr col]

Moves part or all of a line of text to the following line.

UNNUMBER

Removes line numbers and sets the mode NUMBER OFF.

UP amt

Moves the cursor amt lines up.

(var) = USER_STATE USER_STATE = (var)

Returns or sets the user state.

VERSION = num VERSION num (var) = VERSION

Sets or gets the version number of the data set currently being edited.

VIEW member

Calls another member of the PDS currently being edited in VIEW mode.

(var1,var2) = VOLUME

Returns the VOLSER or VOLSERS where the data set currently being edited resides.

XSTATUS lptr = X | NX (var) = XSTATUS lptr

Sets or returns the EXCLUDE status of a line.

14.3 Operands and abbreviations used in the edit macro commands | 247

14.3 Operands and abbreviations used in the edit macro commands To help you work with the macro commands as listed in the table above, please find below a brief description of those operands and abbreviations that are not always self-explanatory by their name: Table 14.2: Operands and abbreviations of edit macro commands

Operands

Meaning

(var1,var2,..)

Here are some variables specified, depending on the function.

(var)

The name of a variable must be specified. This name must be not longer than 8 characters. If the (var) is on an assignment statement on the left side, the editor stores into the variable a value. If (var) is on the right side in an assignment statement, the REXX program must have been previously stored a value into the variable.

[FIRST] [LAST]

A search for the first or last occurrence of the text is performed in the data currently being edited.

[NEXT] [PREV]

Starts at the current cursor location and performs the operation forward [NEXT] or backward [PREV] in the data currently being edited.

[PREFIX] [SUFFIX]

The specified text is used in the search as a prefix or suffix.

[x] [nx]

The operation in question is performed only for EXCLUDED lines (x) or the NOT EXCLUDED lines (nx).

ALL

This operation will affect all lines of the data currently being edited.

amt

amt defines the relative number of elements in shift or jump operations. (amt = amount)

col-1 col-2 col1 col2

Two integers, which limits an operation on the designated columns.

data

Denotes a text enclosed in quotes.

labelname

Name of a labeled line. e.g. .AA, .XY etc.

label-range

Consists of two line labels of the form .LA and .LB. These can either be standard labels such as .ZF And .ZL or user-defined edit labels. The characters after the point may be just letters.

linenum-range

Two integer variable or constant that designate a start and an end line for an operation.

lptr col

Integers that contain a line number and a column number.

lptr-range

Two integers that specify the first and last line for an operation.

string

Text that does not have to be enclosed in quotation marks.

248 | 14 Edit macros – Create and apply

14.4 Test aids in the creating macros In this chapter, I will introduce the test facilities that can be used in the creation of edit macros.

14.4.1 Prototyping Unfortunately, there is no macro recorder for the ISPF editor available. I recommend the edit commands, before you use them it in a REXX program to test them by manually entering in the editor. Therefore, you should prototype commands after you have seen that the result is right, gather in a second data set using the clipboard, and then you can create the edit macro from this collection.

14.4.2 The REXX TRACE command as developing aid The undoubtedly most useful support facility in the creation of edit macro is the TRACE facility of REXX language. Here, mainly the variation of the TRACE command with the ?i option is helpful because it provides the complete development of contents of variables when executing a REXX command. By specifying ? you have instructed the REXX interpreter to stop after each command. This results in the ability to entering commands manually at this point. E.g. to display contents of any variables using the SAY command. Example: The following sample macro determines some values using macro commands. I inserted trace ?i at the beginning. Thus, the development of the variable is displayed and the macro stops after each command. I entered SAY commands to display contents of variables at the stop points. Program 14.3: #TT1 – Using the TRACE command in the macro development /* DOC: REXX #TT1 */ /* DOC: Example of using TRACE ?i on macro development.*/ /* © FRANZ LANZ 2015 */ /*******************************************************/ trace ?i address "ISREDIT" "MACRO" "(DSN) = DATASET" "(MEM) = MEMBER" "(B1,B2) = BOUNDS" "(L,C) = CURSOR" "(ZEILE) = LINE .ZCSR" exit

14.4 Test aids in the creating macros | 249

Here is the run of the macro. I have entered by hand (in gray) at some stops further macro commands. Of course, you can also enter any other REXX command there. +++ Interactive trace. TRACE OFF to end debug, ENTER to continue. +++ 6 *-* address "ISREDIT" 7 *-* "MACRO" >L> "MACRO" 8 *-* "(DSN) = DATASET" >L> "(DSN) = DATASET" say dsn PROX.UTIL.REXX 9 *-* "(MEM) = MEMBER" >L> "(MEM) = MEMBER" say mem $DOC 10 *-* "(B1,B2) = BOUNDS" >L> "(B1,B2) = BOUNDS" say b1 b2 00001 00080 11 *-* "(L,C) = CURSOR" >L> "(L,C) = CURSOR" say l c 00000004 00010 12 *-* "(ZEILE) = LINE .ZCSR" >L> "(ZEILE) = LINE .ZCSR" say zeile * DOC: am 26 May 2004 um 10:57:50 "(im) = imacro" say im #IMACRO1 13 *-* exit ***

I entered the shaded commands by hand each time when the TRACE stops. As you can see, the echo print of the REXX commands contain the REXX source line number.

14.4.3 The program ISREMSPY During run of the macro, you can use the program ISREMSPY to look at the data currently being edited at this time. This program is a purely formal TSO program. Therefore, it must be run under ADDRESS TSO. It can only be used within an edit session or during the execution of edit macros. To demonstrate the application of this program, I wrote the following small macro.

250 | 14 Edit macros – Create and apply

Program 14.4: Example program for using the macro testing aid ISREMSPY /* DOC: REXX #TT2 */ /* DOC: Example program for using the testing aid ISREMSPY*/ /* © FRANZ LANZ 2005 */ /**********************************************************/ address "ISREDIT" "MACRO" "FIND 'Dataset' ALL" address TSO "ISREMSPY" "CHANGE '*' '#' ALL" address TSO "ISREMSPY" "EXCLUDE 'DOC:' ALL" address TSO "ISREMSPY" exit

I called this macro in the edit session of the data set displayed on the following screen. On the pages thereafter, you will find the generated screens on each call of ISREMSPY. EDIT PROX.UTIL.REXX($DOC) - 01.02 Columns 00001 00072 Command ===> #tt Scroll ===> CSR ****** ***************************** Top of Data ****************************** 000001 ************************************************************************ 000002 * 000003 * DOC: Content description of this PDS. Produced by 'DOC' 000004 * DOC: on 26 May 2014 at 10:57:50 000005 * 000006 * Dataset Name : PROX.UTIL.REXX 000007 * Number of members: 2 000008 * 000009 ************************************************************************ 000010 ISPERROR --------------------------------------------------------------000011 ISPF_ERROR: Subroutine to issue ISPF errors ****** **************************** Bottom of Data ****************************

I received the following displays successively during the execution of the macro. The program ISREMSPY inserted the shaded lines. You can see that these panels are provided by ISREMSPY program. I left each these ads with PF3. Command: FIND 'DATASET' ALL ISREMSPY LINE 0 OF 11 ──────────────────────────────────────────────────────────────────────────── EDIT PROX.UTIL.REXX($DOC) - 01.02 Columns 00001 00072 Command ===> Scroll ===> PAGE 000001 ************************************************************************ 000002 * 000003 * DOC: Content description of this PDS. Produced by 'DOC' 000004 * DOC: on 26 May 2014 at 10:57:50 000005 * -----> * Data set name : PROX.UTIL.REXX 000007 * Number of members: 2 000008 * 000009 ************************************************************************ 000010 ISPERROR --------------------------------------------------------------000011 ISPF_ERROR: Subroutine to issue ISPF errors ****** **************************** Bottom of Data ****************************

14.5 System variables of the ISPF editor | 251

Command: CHANGE '*' '#' ALL ISREMSPY LINE 0 OF 11 ──────────────────────────────────────────────────────────────────────────── EDIT PROX.UTIL.REXX($DOC) - 01.02 Columns 00001 00072 Command ===> Scroll ===> PAGE ****** ***************************** Top of Data ****************************** ==CHG> ######################################################################## ==CHG> # ==CHG> # DOC: Content description of this PDS. Produced by 'DOC' ==CHG> # DOC: on 26 May 2014 at 10:57:50 ==CHG> # ==CHG> # Data set Name : PROX.UTIL.REXX ==CHG> # Number of members: 2 ==CHG> # ==CHG> ######################################################################## 000010 ISPERROR --------------------------------------------------------------000011 ISPF_ERROR: Subroutine to issue ISPF errors ****** **************************** Bottom of Data ****************************

Command: EXCLUDE 'DOC:' ALL ISREMSPY LINE 0 OF 11 ──────────────────────────────────────────────────────────────────────────── EDIT PROX.UTIL.REXX($DOC) - 01.02 Columns 00001 00072 Command ===> Scroll ===> PAGE ****** ***************************** Top of Data ****************************** ==CHG> ######################################################################## ==CHG> # - - - - - - - - - - - - - - - - - - - 2 Line(s) not Displayed ==CHG> # ==CHG> # Data set Name : PROX.UTIL.REXX ==CHG> # Number of members: 2 ==CHG> # ==CHG> ######################################################################## 000010 ISPERROR --------------------------------------------------------------000011 ISPF_ERROR: Subroutine to issue ISPF errors ****** **************************** Bottom of Data ****************************

14.5 System variables of the ISPF editor The system variables of the editor are valuable especially when creating an edit macro. The name of these variables is always preceded by a point. They can be used in the source code of the macro because they are actually line labels of the data currently being edited. I put these variables together in the following table: Table 14.3: System variables of the ISPF editor

Name

Content

.ZCSR

Contains the line number where the cursor is currently located.

.ZFIRST Contains the line number of the first row of the data currently being edited. You can abbreviate it with .ZF. .ZLAST

Contains the line number of the last row of the data currently being edited. You can abbreviate it with .ZL.

252 | 14 Edit macros – Create and apply

14.6 Passing parameters to macros If call parameters should be passed to a macro, you have to define the MACRO command with a parameter list. Format: MACRO (parm1,parm2,…)

The variable names in macro parameters must not be longer than eight characters. parm1 and parm2 are variables that must be known in the calling REXX program. Example: The edit macro #ALTXT of the SMART ISPF utilities requires two or four parameters. Program 14.5: #ALTXT – Use of parameter passing to edit macros /* DOC: #ALTXT REXX */ /* DOC: Edit macro to realign line parts within given column */ /* DOC: borders. */ /* DOC: Show description with #ALTXT ? */ /* DOC: Functional description: Enter #ALTXT ? */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ address "ISPEXEC" "VGET (DYNUNIT) PROFILE" if rc > 0 then dynunit = "SYSDA" address "ISREDIT" "MACRO (O1 O2 N1 N2) NOPROCESS" if o1 = "?" then do call info exit end if o1 = "" then do call info exit end if n1 = "" & n2 = "" then do; n1 = o1; n2 = o2; end; if (datatype(o1,"W") & datatype(o2,"W") &, datatype(n1,"W") & datatype(n2,"W")) = 0 then do zedlmsg = "To less parameters - enter at least two." address "ISPEXEC" "SETMSG MSG(ISRZ001)" Exit 12 end if o1 * o2 * n1 * n2 = 0 then do zedlmsg = "All paramters must be > 0." address "ISPEXEC" "SETMSG MSG(ISRZ001)" Exit 12 end if o1+30 > o2 then do zedlmsg = "The minimum difference of columns within pairs", "must be 30." address "ISPEXEC" "SETMSG MSG(ISRZ001)" Exit 12 end

14.6 Passing parameters to macros | 253

if n1+30 > n2 then do zedlmsg = "The minimum difference of columns within pairs", "must be 30." address "ISPEXEC" "SETMSG MSG(ISRZ001)" Exit 12 end "PROCESS RANGE C" Select when rc = 0 then do "(LINE1) = LINENUM .ZFRANGE" /* First line within block*/ "(LINE2) = LINENUM .ZLRANGE" /* Last line within block*/ end When rc 1 then lt = copies(" ",n1-1) else lt = "" tt = lt do m = 1 to words(si) if length(tt) + length(word(si,m)) + 1 > n2 then do parse value io+1";"tt with io";"to.io tt = lt end tt = substr(tt,1)word(si,m)" " if length(tt) > n2 then do parse value io+1";"substr(tt,1,n2) with io";"to.io parse value io+1";"substr(lt,1)substr(tt,n2+1) with io";"to.io tt = lt end end m /*********************************************************************/ /* Produce output of rests */ /*********************************************************************/ if tt lt then do parse value io+1";"tt with io";"to.io end /*********************************************************************/ /* Insert new lines bevore first CC */ /*********************************************************************/ do i = io to 1 by -1 "LINE_BEFORE "line1" = '"to.i"'" end exit

254 | 14 Edit macros – Create and apply

The Help panel of this edit macro: *--------------------------------------------------------------------------* | #ALTXT HELP ------------- Realign text lines within given columns -------| | | | More: + | | This edit macro realigns text lines within new column borders. | | One or two pairs of column numbers must be entered as parameters. | | | | 1st Pair: From this columns is the text in the source lines selected. | | 2nd Pair: Within this columns is the text in the output lines written. | | | | At call enter two pairs of column numbers: The first pair | | defines the columns for text selection. The second pair defines | | the columns within the selected text is new aligned. | | At least one pair of column numbers must be defined. In this case | | is the text within this pair of borders realigned. The affected | | lines must be selected using CC block commands. The result is | | written before the selected lines. | | the texts are separated on word borders. | | A hyphenation of words does not take place. | | | | Examples: | | #altxt 4 69 Columns 4 to 69 are selected from the range of | | lines which are defined by CC block commands | | the columns within the selected text is new aligned. | | At least one pair of column numbers must be defined. In this case | | is the text within this pair of borders realigned. The affected | | lines must be selected using CC block commands. The result is | | written before the selected lines. | | the texts are separated on word borders. | | A hyphenation of words does not take place. | | | | Examples: | | #altxt 4 69 Columns 4 to 69 are selected from the range of | | lines which are defined by CC block commands | | and written after realigning before the line of the | | first CC. | | #altxt 4 69 10 60 Columns 4 to 69 are selected from the range of | | lines which are defined by CC block commands | | and written after realigning in the columns 10 | | to 60 before the line of the first CC block | | command. | | ------------------------- End of #ALTXT-HELP ------------------------- | *--------------------------------------------------------------------------*

14.7 Mnemonics for macro programming | 255

14.7 Examples for editing and SUBMIT batch jobs Edit macros are often used to assemble and SUBMIT batch jobs. The SMART ISPF utilities contain three such macros: Table 14.4: Edit macros of SMART ISPF utilities to assemble and submit batch jobs

#ISPFB

Edit macro to submit a batch job to execute the REXX procedure currently being edited within an ISPF environment.

#TSOB

Edit macro to submit a batch job that executes the REXX procedure currently being edited within a TSO environment.

#SU

Submit a JCL containing no JOB statement.

Advice: Please look at these edit macros. Everything is included there. You need to create and SUBMIT batch jobs using edit macros.

14.8 Mnemonics for macro programming –

– –



If you do not yet have extensive experience in programming macros, remember to develop the complex statements by previous manual testing in an edit session. Use for testing the macros the REXX TRACE mechanism and the test program ISREMSPY. See section 14.4.3 The program ISREMSPY on page 249. Use the advantage the EXCLUDE statement offers. Most macro commands can be applied on both, the excludet lines (using the option X) as well as on the visible lines (using the option NX). If a command sequence does not have the desired success, perhaps it may be that the cursor is incorrectly positioned. This problem can be usually solved by examining the incorrect place of the cursor with a TRACE ?i pass and determining the position of the cursor manually as follows: "ISREDIT (L1,C1) = CURSOR" SAY L1 C1

15 The SMART ISPF utilities Since the early 1980ies, I have been working with ISPF. Over the time, I often missed some practical functions in ISPF. In the early 1980ies, no internet was available. Therefore, it was very difficult to find appropriate functions to fulfil my needs. In this situation, I began to develop these functions from time to time myself. Now a whole series of programs have accumulated that I use in my daily work in ISPF. They are all REXX programs in which I very often use the functions provided by ISPF. Often there are functions consisting of one program only. Sometimes it happens, however, that in order to fulfill the functions, more programs have to work together. Although there are many utilities for ISPF available on the internet, I think that my programs so far are still unique. In my two books on Smart Practices for ISPF, I make the SMART ISPF utilities available for you to download, so that these utilities provide good services.

15.1 Naming conventions All programs are written in REXX language. There are generally two types of programs: Edit macros: These program names all begin with character # (hash). Using these names rule, the macros are easily distinguishable from the other programs. Direct executable: These program names all begin with character S (stands for smart).

15.2 The dynamic panel concept All panels of SMART ISPF utilities are embedded in the programs REXX code and are automatically loaded in a temporary ISPPLIB of DD Name $$DYNPAN when a program executes. This technique has the advantage that you do not need a separate ISPPLIB version of ISPF panels to run SMART ISPF utilities. Another advantage of this procedure is that REXX programs using ISPF panels are easily distributable because the simultaneous distribution of a panel data set is not necessary. The following excerpt from a program of the SMART ISPF utilities shows the part where the decision is made to load the panels:

258 | 15 The SMART ISPF utilities

/*-------------------------------------------------------------------*/ /* Check loading dynamic panels */ /*-------------------------------------------------------------------*/ "VGET (DYNPAN) PROFILE" if rc > 0 then dynpan = "NO" if dynpan = "YES" then call store_panels /* Load embedded panels */ /*-------------------------------------------------------------------*/

To decide whether the panels are to be loaded dynamically, the variable DYNPAN from the ISPF profile will be read in. The program SPROFVAR loads this variable together with other variables needed by some SMART utility programs. Urgent recommendation: Before you can use the SMART ISPF utilities, you must edit the program SPROFVAR, the values contained therein, customize them and run the edit macro ##. This edit macro is executable without having to load the ISPF profile variables for the SMART ISPF utilities. See the following excerpt from program SPROFVAR:

jobclass msgclass dynpan dynunit

= = = =

"A" "H" "YES" "VIO"

/* /* /* /* /*

Job Run class Job message class Dynamic panel store indicator Unit to alloc dynamic panels data set.

*/ */ */ */ */

See also the description of the installation process on page 286.

15.3 List of executable programs The following table shows all programs and their functions: Table 15.1: List of the SMART ISPF utilities programs

Name

Usage

Description

##

stand alone

Edit macro to execute a currently edited REXX procedure immediately.

#ALTXT

stand alone

Realign documentation texts within given borders.

#EDMEM

stand alone

Edit a member which name is the first word in a line of a data currently being edited.

#IMACROA

assist SLE

General ISPF edit macro. Automatically executed by ISPF when an edit session starts even if no initial macro is set for the data set currently being edited.

#IMACRO1

assist SDOC

Initial macro to insert DOC: lines into a data set, which is called for editing.

#IMACRO2

assist SLE

This macro inserts the DSN of an edited data set into the table $SLETAB.

15.3 List of executable programs | 259

Name

Usage

Description

#ISPFB

stand alone

Edit macro to submit a batch job to execute the REXX procedure currently being edited within an ISPF environment.

#LCH

stand alone

Offers the possibility to perform an edit change command with a long parameter list.

#SSS

assist SSS

Purges unnecessary parts of a SRCHFOR list.

#SSSCH

assist SSS

This macro can be used when a super search list currently being edited to restore the displayed lines back into the members in which the searched lines were found.

#SPLJ

stand alone

This macro performs SPLIT and JOIN operations within an edit session.

#SU

stand alone

Submit a JCL that does not contain a JOB statement.

#TSOB

stand alone

Edit macro to submit a batch job that executes the currently edited REXX procedure within a TSO environment.

#VERASE

stand alone

Erase an ISPF variable from the profile and the shared pool.

SCURSOR

stand alone

Access to a data set by EDIT, VIEW, BROWSE, MEMLIST or DSINFO. The DSN must appear on an ISPF panel.

SDOC

stand alone

This program reads all members of a PDS and produces the $DOC member in the same PDS.

SHOSTPAC

stand alone

This macro grabs all members of a PDS and saves the result under the name of the data sets LLQ in the same PDS.

SHOSTUNP

stand alone

Unpack a packed member coming as an upload from a PC which was originally packed at a z/OS by the REXX program SHOSTPAC.

SICMD

stand alone

Maintaining ISPF command tables.

SIDCAMS

stand alone

Produce an IDCAMS LISTCAT of a data set and browse the list. Call in front of a DSN in a DSLIST display.

SJOBSUFF

function

Provide job suffix character for dynamic job assembly.

SLE

stand alone

Display recently edited data sets.

SLIBOFF

stand alone

Reset a LIBDEF.

SLISTC

stand alone

Produce an IDCAMS LISTCAT of a data set and browse the list. Call in front of a DSN in a DSLIST display.

SLISTRAC

stand alone

Produce a RACF LISTDSD of a data set and browse the list. Call in front of a DSN in a DSLIST display.

SLOGON

stand alone

SMART user logon procedure.

SPROFEDT

stand alone

Execute program SPROFVAR to store users ISPF profile environment variables into ISPF profile.

SPROFVAR

stand alone

Store the user’s environment variables into ISPF profile.

SSC

stand alone

SMART super clone function for data sets.

SSC01

assist SSC

Messages for panel SSCPP01 called by function SSC.

SSS

stand alone

Perform a super-search operation by entering SSS in front of a DSN in a DSLIST panel.

260 | 15 The SMART ISPF utilities

15.4 Program descriptions This chapter contains individual descriptions of the programs of SMART ISPF utilities. Most programs include extensive help descriptions displayable using the PF1 key. When calling up some programs, a question mark can be entered as parameter. In this case, the program will not run with its functionality. It will only display a description of its functions in a help panel. The following description of the programs points out the possibility of displaying a help panel using a question mark. Therefore, the following description of the programs is only a short one to show the basic function.

15.4.1 Edit macro ## – Execute a currently edited REXX procedure Edit macro to execute a currently edited REXX procedure. After typing ##, enter a parameter string which is transferred to the REXX program for execution. This program is executable without having to load the ISPF profile variables for the SMART ISPF utilities. Help display with ## ?

15.4.2 Edit macro #ALTXT – Realign line parts Edit macro to realign line parts within given columns. Help display with #ALTXT ?

15.4.3 Edit macro #EDMEM – Edit of a member Edit of a member which name is the first word in a line of a data set currently being edited. Description: The edited list can come from following sources: – A list output of the procedure SSS and processed by the #SSS macro. – A list output produced by ISPF function SRCHFOR in the resulting display list. – The member $DOC from a PDS. At call, the cursor must be in a line in which the member name occurs as first word. No further help available. 3 Note: For an optimal use of this macro, its call should be set on a PF key. E.g. PF22.

15.4 Program descriptions | 261

15.4.4 Edit macro #IMACROA – General ISPF edit macro General ISPF edit macro. Whenever you start an edit session, this macro will execute, regardless of whether an initial macro is defined for this data set or not. Activating of this macro: 1. Start an edit session in an ISPF environment. 2. Enter in line command ===> EDITSET or EDSET 3. Make the necessary entries in the appearing panel. See following panel: No further help available. Screen 15.1: Set activation of #IMACROA *-----------------------------------------------------------------------------* | ISREDSET Edit and View Settings | | Command ===> | | More: + | | Settings for current and future Edit and View sessions: | | | | User session initial macro . . . . . . . . . . . . . . #IMACROA | | Maximum initial storage allowed for Edit and View . . 0 | | Target line for Find/Change/Exclude string . . . . . . 2 | | Enter "/" to select option | | Always position Find/Change/Exclude string to target line | | / Remove action bars in ISPF edit and view panels | | Force ISRE776 if RCHANGE passed arguments | | | | CUT default . . 2 1. Append PASTE default . . 1 1. Delete | | 2. Replace 2. Keep | | | | Settings for future sessions. Select Apply Setting Immediately for the | | setting to affect the current session as well. | | | | Enter "/" to select option | | / Confirm Cancel/Move/Replace / Apply Setting Immediately | | / Preserve VB record length / Apply Setting Immediately | *-----------------------------------------------------------------------------*

15.4.5 Edit macro #IMACRO1 – Initial edit macro Initial macro to insert DOC: lines into edited members of partitioned data sets (PDS). When starting an edit session of a PDS member and no DOC lines are found in the edited member within the first 20 lines, this macro then displays a panel that offers the opportunity to insert DOC lines at the beginning of the member currently being edited. Help can be displayed via PF1 when the panel IMACRO11 appears. The following screen shows an example for inserting DOC and REM lines into a member.

262 | 15 The SMART ISPF utilities

Screen 15.2: Panel IMACRO11 for edit macro #IMACRO1 IMACRO11 ----------- Insert DOC: lines into edited data set ---------------COMMAND ===> Dynpan = YES-VIO SysPlex = TESTPLX Sysid = TESTMVS Node = ZOS19 Data-Set-Name = LANZUSR.BOOK.REXX(AAA) Comment-Prefix = *__ Comment-Suffix = ___ Caps = ON_ set CAPS ON or OFF data set type = REXX__ e.g. REXX, JCL, PANELS and so on Function type = MAIN_ e.g. MACRO, MAIN, COPY, SUBR Filling char. = * e.g. * (asterisk), - (hyphen) These DOC: and REM: lines are inserted at beginning of data set Author = © Franz Lanz 2015____________________________ 1. DOC = This is an example__________________________________________ DOC = how DOC lines are inserted__________________________________ DOC = in a new____________________________________________________ DOC = edited member_______________________________________________ DOC = of a PDS____________________________________________________ 2.

REM REM REM REM REM Compile

= Remarks_____________________________________________________ = can also____________________________________________________ = be inserted_________________________________________________ = These remarks are not inserted in the $DOC member of the PDS. = The $DOC member is produced using the program SDOC._________ status of #IMACRO1: NOT COMPILED

The greyed fields show the standard options inserted here by #IMACRO1 depending on LLQ. These options are changeable. The following screen shows the resulting contents of the new member after ENTER is pressed: ISREDDE4 LANZUSR.BOOK.REXX(AAA) - 01.00 Columns 00001 00072 Command ===> Scroll ===> CSR 000001 /* DOC: AAA REXX MAIN */ 000002 /* DOC: This is an example */ 000003 /* DOC: how DOC lines are inserted */ 000004 /* DOC: in a new */ 000005 /* DOC: edited member */ 000006 /* DOC: of a PDS */ 000007 /*-------------------------------------------------------------------*/ 000008 /* © Franz Lanz 2015 */ 000009 /*********************************************************************/ 000010 /* REM: Remarks */ 000011 /* REM: can also */ 000012 /* REM: be inserted */ 000013 /* REM: These remarks are not inserted in the $DOC member of the PDS. */ 000014 /* REM: The $DOC member is produced using the program SDOC. */ 000015 /*********************************************************************/ ****** **************************** Bottom of Data ***************************

15.4.6 Edit macro #IMACRO2 – Edit session end macro This macro inserts the DSN of an edited data set into the table $SLETAB. This macro is executed when an edit session ends in which the macro #IMACRO1 was executed. No further help available.

15.4 Program descriptions | 263

15.4.7 Edit macro #ISPFB – Submit an ISPF batch job Edit macro to submit a batch job to execute the REXX procedure currently being edited within an ISPF environment. When the macro is called, a parameter text can be added in the call statement. This text is as a parameter transferred to the executed REXX procedure. Help display with #ISPFB ?

15.4.8 Edit macro #LCH – Perform long edit change commands Perform edit change with long parameter texts. Function: When the "Command ===>" line in the normal edit panel is too short to contain the whole CHANGE command, you can use this program to solve the problem. This program opens a panel for input of two lines each with max 70 characters. The first line is the SEARCH argument for the change and the second line is the replacement value. Additionally, you can enter parameters for the CHANGE in a third line. E.g. 1, ALL, WORD...

15.4.9 Edit macro #SPLJ – SPLIT and JOIN lines This macro performs SPLIT and JOIN operations within an edit session. Functional description: When this macro is called, further processing of the position of the cursor depends on the following: 1. If the cursor is within a line and after this position, characters are on the line, these characters are moved to a new line after the current one. This is the split function. 2. If after the position of the cursor only blanks are on the line, the line after the current line moves to the current line after the cursors position. This is the join function. There is no other help available.

264 | 15 The SMART ISPF utilities

15.4.10 Edit macro #SSS – Clear SCHFOR lists Remove unnecessary parts from SCHFOR list. Functional description: Delete all unnecessary lines from a list produced by the Super Search Function of ISPF. The procedure SSS calls this macro as initial macro. If you have performed a manual search, you can also use this macro to revise the list output. There is no other help available.

15.4.11 Edit macro #SSSCH – Mass update of members This macro offers a very smart functionality: When you have performed a super search and you make some changes in the edited list, you can write back the displayed lines completely to its members. With this possibility, you can perform mass changes on many members in one step.

Purpose: This macro can be used, when a super search list is displayed in edit session, to restore the displayed lines back into the members in which the searched lines were found. There is no other help available. 3 Remarks: You can remove rows and members from the data set currently being edited. If you delete a member, all lines belonging to this member must also be deleted bulky. New rows cannot be inserted because the row numbers which are included in the displayed list, contain the relative position of these lines in the member. These line numbers will be used when the lines are written back to the member. The existing lines with the same number will be overwritten. If you do not want to write back changes in individual lines, you can of course delete these lines before calling #SSSCH.

15.4.12 Edit macro #SU – Submit JCL without a JOB statement Submit a JCL that does not contain a JOB statement. Parameters: MSGLEVEL in the form: 0,0 / 1,0 / 2,0 / 0,1 / 1,1 / 2,1. This MSGLEVEL is in the JOB statement set. Function description: The program assembles the job statement using user-defined variables from ISPF profile pool. Use the program SPROFVAR to store these variables into the ISPF profile pool.

15.4 Program descriptions | 265

#SU is usable at the following positions: – As an edit macro. – In front of a member in a DSLIST/M display. Special function: EXCLUDED lines of the edited data set are NOT inserted in the submitted job stream. 4 Attention: Due to using the TSO SUBMIT command, all lines of the edited data set are translated to UPPER CASE during SUBMIT. This is a regular effect of SUBMIT.

3 Author’s remark: During my years of consultant activity, I always had all my job statements adapted to varying conditions in the data centers. To have to not always do this, I developed the REXX program SPROFVAR. There, I have all the values that apply to a data center inserted as variables and stored them in the ISPF profile. When I installed the SMART ISPF utilities at a new customer, I adapted and executed only the member SPROFVAR. In all the jobs I had to run at the customer’s site, I was able to leave the job statement and start jobs with #SU.

No further help available.

15.4.13 Edit macro #TSOB – Submit a TSO batch job Edit macro to submit a batch job which executes the REXX procedure currently being edited within a TSO batch environment. A parameter text can be added to the macro call. This text is transferred to the executed REXX procedure. Attention: This macro does not save the source code of the data set currently being edited. Hence, the UNDO status of the edit session is not changed by this macro. Remarks: To avoid the SAVE command, the currently edited REXX procedure is stored to a work data set. The batch job will use this work data set to execute the REXX procedure. The description of the 'SUBMIT *' command in the manual TSO/E Command Reference contains the following note: The SUBMIT command converts all characters of the job stream to uppercase before the stream is submitted to the system.

266 | 15 The SMART ISPF utilities

3 Note: To avoid setting all JCL lines in uppercase by command SUBMIT * and thus also the line which contains the parameter text, this procedure writes the job stream to member JOB into a work data set and submits the job from this member by using the command: "SUBMIT '"workfile"(JOB)'". In this case, the lines of the member JOB will not be transferred to uppercase.

Help is available with #TSOB ?

15.4.14 Edit macro #VERASE – Erase ISPF profile variables With this edit macro, you can delete an ISPF variable from the profile and the shared pool. At call, you can enter only one variable name.

15.4.15 Program SCURSOR – Calling a data set from an ISPF screen With this program you can call a data set which name is somewhere in an ISPF screen. When calling, a small panel appears which allows you to select the type of file processing. Description: If a DSN of a data set appears on any ISPF screen, you can get access to this data set by positioning the cursor within the DSN and call SCURSOR. For a comfortable use of this function, I recommend to program a PF KEY with TSO %SCURSOR. If you have positioned the cursor at any position within a DSN and then pushed the PF key a panel appears to offer a range of access possibilities to the data set. There are some restrictions for displaying GDGs and VSAM data sets. This function can be used in many displays. Some examples: – – – – –

In an EDIT panel In a BROWSE panel In the SDSF display In a data set display In a POPUP panel

15.4 Program descriptions | 267

See the selection panel below: Screen 15.3: SCURSOR selection panel *---------------------------------------------------* | SCURSOR -------- Select Call Type --------------- | | DYN | | DSN: 'LANZUSR.BOOK.REXX(SCHANGE)' | | | | Select action: | | 1 1. Edit | | 2. View | | 3. Browse | | 4. Memlist | | 5. data set information | | | | Press END to cancel this action. | | | *---------------------------------------------------*

15.4.16 Program SDOC – Produce documentation members This program reads all members of a PDS and produces the $DOC member in the same PDS. Function: The program scans all members of the PDS for lines with keyword DOC: as the second word in a line. Only the first 200 lines in each member will be scanned. When during this scan no DOC: lines are found, then only the member name will be stored in the output. When the first DOC: line is found and there are more than five lines following the last found DOC: line without a DOC: the scan of this member ends.

15.4.17 Program SLE – Display last edited data sets Purpose: The program starts by input of SLE in the ISPF command line. It displays an ISPF table containing names of recently edited data sets. The program displays the ISPF table $SLETAB. The EDIT initial macro #IMACRO2 updates this table with DSNs of recently edited data sets. The display panel offers the ability to perform some functions on the data sets displayed. See the help panels available in the programs screen. Smart Last Edit offers the following functions:

268 | 15 The SMART ISPF utilities

Screentext 15.1: Description of SLE functionality 1. Col. C --> --> --> --> --> --> --> -->

D M E B V S R I

--> --> --> --> --> --> --> -->

Display the DSLIST panel (like 3.4) for this data set. Display MEMLIST of a PDS and NINE selection columns. Edit this data set or member. Browse this data set or member. View this data set or member. Display EDIT member list for this PDS. Remove this line from panel (multiple R are allowed). Display data set information.

2. The field Max lines shown shows the current lines in the table $SLETAB By entering a lower number here the lines in the table are reduced to this Note: The program itself NEVER reduces the number of lines held in the table. 3. In the COMMAND line the following commands may be used: a) f name ---> A find for name in column DSN is started. name must always be entered without apostrophe. b) sort DSN ---> The column DSN is temporarily sorted by name. This sorted display is reset to standard at next display. A permanent change of Ordering my be caused by entering it in the Sort: field. 4. After a) D b) N

Sort: D = Date or N = Name permanent Ordering is defined here ---> Ordering permanent for Date and Time descending. ---> Ordering permanent for DSN ascending.

The following screen shows the above-mentioned input fields: Screen 15.4: SLE working panel SLEP1 S -------------- Table display of recently edited data sets Row 1 of 73 COMMAND ===> SCROLL ===> CSR Dynpan= YES-VIO Compile state of SLE Sort: D=Date or N=Name D Max lines shown: 73 NOT COMPILED Insert control for edited data sets ----> All or Change: ALL C Recent DSN in edit Help with PF1 for all fields Date Time -----------------------------------------------------------------------------_ LANZUSR.BOOK.REXX(SLE) 15/01/23 08:55:55 _ LANZUSR.BOOK.REXX(#IMACROA) 15/01/23 08:48:25 _ LANZUSR.BOOK.REXX(#SSSCH) 15/01/23 08:46:46 _ LANZUSR.BOOK.REXX(#PAN) 15/01/23 08:43:03 _ LANZUSR.BOOK.REXX(##) 15/01/23 08:40:43 _ LANZUSR.BOOK.REXX(#ALTXT) 15/01/23 08:36:50 _ LANZUSR.BOOK.REXX(#BOX) 15/01/23 08:36:25 _ LANZUSR.BOOK.REXX(SSS) 15/01/23 08:30:30

3 Remark: Help screens are available for all greyed fields. Position the cursor in such a field and press PF1 to display the help. The general help screen appears, when the cursor is on any other position on the screen and PF1 is pressed.

1 Tip: Insert the following command in the ISPF command table to call the last edit function very fast when you type in SL in the ISPF command line. _ SLE 2 SELECT CMD(%SLE) REXX SLE CALL THE LAST EDIT FUNCTION

15.4 Program descriptions | 269

15.4.18 SLOGDSN – Data member containing DSNs for logon The member SLOGDSN contains DD names and the corresponding DSNs. The logon procedure SLOGON reads this member, looks for the already existing allocations by the same DDs and assembles a new structure in which the members referred to in SLOGDSN DSNs are respectively arranged in front of the existing DSNs of each affected DD. The program SLOGON then allocates this new structure using the REUSE option. This technique ensures that the DSNs specified by the user allocates in the member SLOGDSN BEFORE the previously existing DSNs in each affected DSN chain. DDs that are not found in the existing allocations will additionally allocated. Program 15.1: Member SLOGDSN * DOC: SLOGDSN Control member used by the procedure SLOGON of SMART * DOC: utilities. * © FRANZ LANZ 2015 *********************************************************************** * Description: * * This member contains DD names and DSNs assigned to these DD names. * The DD names and their assigned DSNs are used by the logon * procedure SLOGON to allocate these elements in front of existing * library allocations. If this member is missing there are no * additional allocations possible. * Lines beginning with an asterisk are skipped by the SLOGON program. *********************************************************************** * The definitions have the following structure: * * DDNAMEN1 DSN1 ONLY * DSN2 * DSN3 * DDNAMEN2 DSN1 * DSN2 * DSN3 *---------------------------------------------------------------------* Special cases: * If the third word in a DD line is ONLY, then all existing * allocations for this DD are discarded and only the here defined DD * and its DSNs are allocated. * If the HLQ is &USERID the logon procedure replaces this with the * real user-ID. *********************************************************************** *SYSPROC SYSTEM.LOGON.CLIST SYSEXEC &userid.BOOK.REXX &userid.REXX SYSTEM.REXX ISPPLIB &userid.BOOK.PANELS &userid.PANELS SYSTEM.PANELS ISPMLIB &userid.MSGS &userid.BOOK.MSGS SYSTEM.MSGS ISPLLIB &userid.LOAD SYSTEM.LOAD ISPSLIB &userid.SKELS

270 | 15 The SMART ISPF utilities

15.4.19 Program SLOGON – Personal logon procedure This is a personal logon procedure. It works as follows: 1. It reads all existing allocations of the TSO user and caches them. 2. It reads the control member SLOGDSN containing the DSNs that must allocated before the already existing DSNs. The new DSN chains are assembled in such a way that the DSNs read from the member SLOGDSN stay before the existing DSNs. 3. When in the member SLOGDSN new DDs and their DSNs are contained that are not present in the previous allocations, these chains will be added to the allocation stream. 4. SLOGON now performs the new allocations using the new allocation stream and the TSO ALLOC option REUSE. The REUSE option replaces the old allocations. For installing this logon procedure, see section 15.6.2 Installation on page 286. 3 Note: If SLOGDSN contains DSNs of not existing data sets, a warning message is displayed during SLOGON, but the logon process continues anyway. This ensures that the logon process is successfully performed and a working user environment is created. This is a very important advantage of the procedure SLOGON.

15.4.20 Program SPROFEDT – Store users ISPF profile variables Execute program SPROFVAR to store users ISPF profile environment variables into ISPF Profile. This program is called by ISPF command SPROFVAR.

15.4.21 SPROFVAR – Load user ISPF variables SPROFVAR defines and stores variables needed by the SMART ISPF utilities in the ISPF profile pool. Several SMART utility programs use these profile variables. The PF keys are also set. Each user can add his own profile variables as needed!

15.4.22 Program SSC – Super clone for data sets Purpose: This program uses a model data set to perform some functions on this data set or to create a new data set based on the model data set.

15.4 Program descriptions | 271

Smart Super Clone offers the following functions: – Allocate a new data set with the same or different attributes as the model data set has with optionally copying the data. – Restructure the model data set. Some attributes may be changed. – Copy the model data set into another data set. The target data set must exist. During this operation, the data set attributes cannot be changed. – The source data set can be a PDS and the target data set can be sequential. In this case, the program continuously writes the members into the sequential data set. – Only the following data set types can be processed with this program: Generally data sets on DASD and Sequential, PDS, PDSE and VSAM. Note: A sequential data set cannot be copied into a PDS member.

3

Screen 15.5: SSC working screen SSCPP01 --------- SSC: data set Manager under ISPF / LANZ GmbH ---------------COMMAND ===> Dynpan = YES-VIO SysPlex = TESTPLX Sysid = TESTMVS Node = ZOS19 Model = LANZUSR.BOOK.REXX Compile state of SSC New = LANZUSR.BOOK.REXX NOT COMPILED FUNCT = NO DSN = 'LANZUSR.BOOK.CEXEC' 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

If the data set is a PDS all members are scanned!

= 'VARDAT',W = = = = = = = = =

PO = ASIS____________________________________________________________________ Fill in here more process options. Press PF1 for help and then select a theme by number or press ENTER to scroll thru pages down continuously. MSG1= Press PF1 for Help, press ENTER to execute the search.

Remarks: – – – –

The program SSS calls the ISPF standard super search utility ISRSUPC to perform the search. The standard ISPF help facility for super search appears when PF1 is pressed on the SSS screen. SSS saves the entered search parameters in lines 1 to 10 automatically in the ISPF profile and redisplays them at the next call of SSS. The edit macro #SSS removes unnecessary output contents from the standard output list of the search before the list appears on the screen. The macro #SSS is indicated as initial macro when the editor is invoked for displaying the search results.

3 SSS special update function: SSS stores the optimized search results into a temporary data set and then displays this data set in the editor. This data set can be edited by using the normal editor functions. If individual lines of the data set are changed, these changes can restored into the individual members using the edit macro #SSSCH. See description of #SSSCH on page 264. This is one of the most important advantages of the program SSS.

15.5 Programming aids | 273

15.5 Programming aids This chapter includes program elements which are intended for programmers who develop programs using the REXX language. The following table shows these edit macros, programs and subroutines, which are contained in the programming aid package. Table 15.2: Programming aids

Program

Function

#C

This edit macro compiles the REXX program currently being edited and executes the compiled program immediately after the compile. One parameter can be added in the #c call statement. This parameter string will be passed to the compiled program to be used at execution time. To get an online tutorial description enter: #c ?

#RO

Online compile of the REXX program currently being edited. This procedure can be called as an edit macro or in front of a member name in a DSLIST/M display panel. Parms: When #RO is used as a macro additional compiler options may be passed as parameters.

#RC

Use this procedure to assemble and submit a batch job to compile a REXX procedure.

#RCLOAD

Assembly and SUBMIT a job to compile a REXX procedure and generate a LOAD module or a CALL module.

#IE

Edit macro to insert in an application program the call lines to the internal ISPF_ERROR subroutine. The inserted statements calls the ISPF error handling subroutine ISPF_ERROR in case an error appears. See the next row in this table.

ISPFERR

ISPF error handling routine This subroutine is called when a call to an ISPF service function ends with an error.

#PAN

The screen whose program code is currently being edited will be displayed immediately.

DAYDIFF

Calculates the number of days between two DATE values. DATE values are entered in the form dd.mm.yyyy.

ENDDAY

Calculates the target date for a period of days starting at a given date plus or minus a number of days.

JULDATE

This subroutine calculates for a standard date the JULDATE or vise versa.

LEAPYEAR Calculates whether the entered year is a leap year or not. This function returns a 1 if the entered year is a leap year, otherwise it returns 0. Caution: No plausibility checking of the entered year parameter is performed. SCHANGE

This REXX subroutine performs changes in any strings. See section 4.6.3 SCHANGE – Change of texts on page 86.

SDYNPAN

This program converts the source code of an ISPF panel so that the code can be embedded in a REXX procedure to be dynamically loaded from there into a temporary ISPPLIB for execution.

274 | 15 The SMART ISPF utilities

15.5.1 Edit macro #C – Compile and execute a REXX program If the REXX compiler is available in your installation of z/OS systems, you can use this macro to compile your REXX programs very easily. Program description: Edit macro #c: Edit macro to compile and execute the REXX procedure currently being edited. After the characters #c you can enter a string, which will be passed as parameter to the program for execution. Examples: #c #c xx 3 4

--> 0 Parameter --> 1 Parameter

4 Attention: The entered parameter string MUST NOT contain the ISPF delimiter character. This character is used for ISPF command stacking and your parameter will possibly be truncated at the delimiter character position. The ISPF delimiter character can be found in ISPF menu 0 in the line Command delimiter.

Processing flow: The REXX program currently being edited is written to a work data set. This data set is used for input to the REXXCOMP program. If compilation is successful, the CEXEC module is written to the online work data set with DDNAME ##DD. If the ##DD data set is not allocated, it will be allocated. If the compilation ends with a RC > 0, the compiler listing is immediately browsed. The compiled program will be executed using the ISPF SELECT CMD service. 3 Remark: Because the REXX program currently being edited is not stored to its data set for the purpose of compilation, the UNDO command can still be used.

15.5.2 Edit macro #RO – Online compile of a REXX program This procedure can be called as an edit macro or in front of a member name in a DSLIST/M display panel. If called as an edit macro the following rules exist. 1. The source code currently being edited is stored into a temporary data set and the compiler uses this data set as SYSIN file. When using this technique, the edi-

15.5 Programming aids | 275

tors save command will not be performed and the change status of the edited file remains unchanged. Hence, the UNDO command can still be used in the editor. 2. After #RO the user can add some additional parameters which will be transferred to REXX compiler as compiler options. 3. If the REXX source code contains TRACE statements, the compiler produces no XREF listing and the compilers output list will be written to a data set. If called in front of a member name in a DSLIST/M display: 1. The compiler reads the REXX source from this member. 2. No additional compiler options may be set. This is bacause at this point parameters cannot be added to the procedure call statement. 3. If the REXX source code contains TRACE statements, NO CEXEC output is produced and the compile ends with an error. The name of the output data set for the CEXEC code is set up as follows: The last qualifier of the input DSN is substituted by CEXEC Example: Input DSN Output DSN

 LANZ.LOGON.REXX  LANZ.LOGON.CEXEC

15.5.3 Edit macro #RC – Compile a REXX procedure with a batch job Functional description: Use this procedure to assemble and submit a batch job to compile a REXX procedure. This procedure can be called as follows: 1. As an edit macro. In this case will the currently being edited REXX procedure be saved and the batch job to compile the REXX procedure will submitted. 2. In a DSLIST/M in front of a REXX procedure member. 3. In a DSLIST/M display in the command line to compile all or a selected number of members, e.g.: sel ab* #rc --> all members which names are beginning with characters ab are compiled. At this type of call no NOTIFY=userid() parameter is inserted into the JOB statement. The name of the output data set for the CEXEC code is set up as follows: The last qualifier of the input DSN is substituted by CEXEC Example: Input DSN Output DSN

 LANZ.LOGON.REXX  LANZ.LOGON.CEXEC

276 | 15 The SMART ISPF utilities

15.5.4 Edit macro #RCLOAD – Produce a load or a call module Assembly and SUBMIT a job to compile a REXX procedure and generate a load module or a CALL module. This procedure can only be called as edit macro. Parms: none Attention: There are two things necessary in order to use this macro: 1. The REXX compiler REXXCOMP must be available in your system. You can check this using the DDLIST utility. 2. The REXXCL jcl procedure must be available in your system. Ask your system programming department where it is. Two different types of load modules can be generated: 1. A load module that can be executed in a batch job using the EXEC PGM=name statement. This type is called EXEC type. In this case the following comment line must be found in the source code: /* STUB: MVS */ 2. A load module which was added to a Function Package Lib needs to be called with a CALL command. (CALL type). In this case the following comment line must be found in the source code: /* STUB: EFPL */ After generating the load module of this call type, it has to be implemented in a Function Package. See the corresponding manual TSO/E REXX Reference. If you try to execute such a program directly, then the CALL ends with a return code 0C4. This means the program ends with a hard crash. Link library: If STUB: MVS is set, a file in the source code needs to be defined to where the load module is to be written. This load library is named by a comment line in the source code which is structured as follows: /* LNK: DSN of the load library */

Example: /* LNK: PEVX.LANZ.LOAD

*/

If no such row is found, then NO compile is performed.

15.5 Programming aids | 277

15.5.5 Edit macro #IE – Insert a call to ISPF_ERROR Preface: I have been looking for a method a long time to report errors when executing ISPF services elegantly and detailed. I think I have now found this method. This method consists of two parts which must be inserted into each program: First part of error handling: After each call to an ISPF service function, the return code RC will be checked. If this code signals an error, the error handling subroutine ISPF_ERROR will be called. The parameters in this call statement contain all information to report the error in detail. After each call to an ISPF service, the following five lines of code are inserted: Line Line Line Line Line

1: /* Start error handling */ 2: if rc > 0 then call ispf_error rc "//"||, 3:"*LMINIT DATAID(ID) DATASET('*dataset*') ENQ(SHR)*//"||, 4: "LMINIT DATAID(ID) DATASET('"dataset"') ENQ(SHR)" 5: /* End error handling */

The five lines must be manually inserted in the source code of a program as follows: 1. Enter #IE in the ISPF command line or program a PF key with #IE. 2. Move the cursor to the line containing the call to an ISPF service. 3. Press enter or the appropriate PF key which contains the command #IE. The above mentioned five lines will be inserted immediately behind the ISPF command line. Description of the lines: Lines 1 and 5 contain comments and are self-explanatory. Line Explanation 2

The RC returned by the ISPF service is passed as first parameter. Depending on the RC that was returned by the ISPF service, a call will be executed to the error handling subroutine ISPF_ERROR.

3

This line is passed as the second parameter to the subroutine ISPF_ERROR. It contains the original ISPF command line without the variables contained in the command line being resolved. This text is used by the subroutine ISPF_ERROR to find the original command line in the source code of the program by using the REXX command SOURCELINE().

4

This line is passed to ISPF_ERROR as third parameter. It contains the original ISPF command line with the variables contained in the command line being resolved.

These three parameters are used by the subroutine ISPF_ERRROR to print a comprehensive error report.

278 | 15 The SMART ISPF utilities

Second part of error handling: Insert the source code of the subroutine ISPF_ERROR manually into each program that contains calls to ISPF_ERROR. This is necessary because an externally called subroutine does not know the source code of the calling program. Therefore, the command SOURCELINE is not applicable to determine the line number of the line in the source code at which the error occurs. 3 Note: In large programs, it can happen that a certain ISPF command line at several points occurs with the same content. In such a case, it is important to know the number of the program line in which the error occurred.

Example: When using this method, errors in executing ISPF services are displayed as follows: *------------------------------------------------------------------------------* | ISPF execution error in source line 284, RC = 20 ISPF statement: | | LMINIT DATAID(ID) DATASET('faked DSN') ENQ(SHR) | | ISPF error message: A list of names was found where a list was not expected. | *------------------------------------------------------------------------------*

I replaced in the above example the contents of the variable DATASET by the text faked DSN to manually enforce the error. The statement where the error occurs is in line number 284 in the source code of the program.

15.5.6 Subroutine ISPF_ERROR – Display ISPF error messages I described above how the call to the subroutine ISPF_ERROR is performed. To complete the method, here is the source code of the subroutine ISPF_ERROR:

15.5 Programming aids | 279

Program 15.2: ISPF_ERROR subroutine /* DOC: ISPFERR REXX INTERNAL SUBROUTINE */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ ispf_error: procedure expose zerrlm /*********************************************************************/ /* ISPF Error handling routine */ /* This subroutine is called up when a call to an ISPF function */ /* service ends with an error. */ /* To display the statement in error and program line where the */ /* statement in error resides, a tricky programming is inserted into */ /* this subroutine. This trick works as follows: */ /* 1. The call to this subroutine contains a parameter consisting of */ /* three parts: */ /* a) The RC from the failing ISPF function call. */ /* b) A text string which is used by the subroutine to localize */ /* the failing ISPF function call within the main program. */ /* c) A text string containing the original ISPF function call */ /* statement. */ /* The parameters are each separated by //. */ /* 2. The subroutine localizes the line of the CALL using the text */ /* string and the REXX SOURCELINE function. */ /* The line before the CALL line is the failing ISPF function */ /* call. */ /* 3. An error message is assembled und displayed when ISPF displays */ /* the next screen. */ /* */ /* Caution: */ /* This program is only usable as an internal subroutine because an */ /* external subroutine cannot find a command line within the calling */ /* program. */ /* If you want to use this subroutine in your program, copy this */ /* code into your program. */ /*********************************************************************/ parse arg rc"//"org"//"new org = translate(org,'"','*') do i = 1 to sourceline () /* Search the failing program line */ if pos(org,sourceline(i)) > 0 then do zedlmsg = "ISPF execution error in source line "i", RC = "rc, "ISPF statement:" copies(" ",60) new copies(" ",60) if zerrlm "ZERRLM" then do zedlmsg = zedlmsg copies(" ",60) "ISPF error message:" zerrlm end "SETMSG MSG(ISRZ001)" leave i end end i exit

15.5.7 Edit macro #PAN – Execute a panel source code When developing ISPF panels it is very tedious to test this using the ISPF menu 7.2. Therefore, I wrote the macro #PAN to test a panel which source code is currently being edited. Please read the comment lines at the beginning of the source code. It will describe how to use the macro.

280 | 15 The SMART ISPF utilities

Program 15.3: Edit macro #PAN to test macros directly /* DOC: #PAN REXX MACRO */ /* DOC: This edit macro tests a panel currently being edited directly*/ /* © FRANZ LANZ 2015 */ /*-------------------------------------------------------------------*/ /* Parms: none */ /* */ /* Program flow: */ /* To perform the display of the panel the ISPF function 7.2 is used.*/ /* This means the program which is used in ISPF menu 7.2 of name */ /* ISPYXDR is called by ISPF SELECT service. */ /* Necessary variables to impact the program are set and written to */ /* ISPF profile pool. */ /* */ /* To optimize the using of this function you should set a PF-Key */ /* with this command: #PAN;2;;. (;) is the ISPF delimiter character. */ /* If you are currently being editing a ISPF panel and you would like*/ /* to test the panel then you press only this PF-Key and the panel */ /* will be immediately displayed. */ /* If the panel definition contains a WINDOW parameter in the )BODY */ /* statement the variable ISPYPOP is set to YES to force the panel */ /* display in a window. */ /*********************************************************************/ address ISREDIT "MACRO" "SAVE" "(MEM) = MEMBER" "(DSN) = DATASET" ispyppn = mem /* panel name in profile pool */ ispypop = "NO" /* Set display option for POPUP panel off */ "FIND )BODY FIRST" /* If the panel is a POPUP panel */ "FIND WINDOW( .zcsr .zcsr" /* set display option to force display*/ if rc = 0 then ispypop = "YES" /* to POPUP panel */ address ISPEXEC "CONTROL ERRORS RETURN" "VPUT (ISPYPPN ISPYPOP) PROFILE" /* Write to Profile Pool */ "LIBDEF ISPPLIB DATASET ID('"dsn"') STACK" zsavinp = 'SAVE' "VPUT (ZSAVINP) PROFILE" "VGET (ZAPPLID) SHARED" "SELECT PGM(ISPYXDR) PARM("zapplid") NOCHECK" "LIBDEF ISPPLIB" "VGET (ZSCREEN) SHARED" address ISREDIT "RESET" exit 1

15.5.8 Subroutine DAYDIFF – Calculate number of days Please see the source code to recognize the function of this subroutine. Program 15.4: Subroutine DAYDIFF /* DOC: DAYDIFF REXX UPRO ENGLISH VERSION */ /* DOC: Calculates number of days between two DATE values. */ /* DOC: DATE values are entered in the form dd.mm.yyyy. */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ DAYDIFF: procedure arg DAY1 DAY2 DAY1 = DATE("B",right(DAY1,4) || substr(DAY1,4,2) || left(DAY1,2),"S") DAY2 = DATE("B",right(DAY2,4) || substr(DAY2,4,2) || left(DAY2,2),"S") return abs(DAY2-DAY1)

15.5 Programming aids | 281

Example: The following call to DAYDIFF returns 365: say daydiff(15.05.2015 15.05.2014)

15.5.9 Subroutine ENDDAY – Calculate a target date Please see the source code to recognize the function of this subroutine. Program 15.5: Subroutine ENDDAY /* DOC: ENDDAY REXX MAIN ENGLISH VERSION */ /* DOC: Calculates the target date for a period of days starting at */ /* DOC: a given date plus or minus a number of days. */ /* DOC: The start date must be entered in the form dd.mm.yyyy. */ /* DOC: Enter the number of days with a negative sign when an earlier*/ /* DOC: date shall be calculated . */ /* DOC: For positive values is no plus sign necessary. */ /* DOC: If * (asterisk) is entered as first argument the current */ /* DOC: date is used as first argument. */ /* DOC: Examples: */ /* DOC: Input = "16.12.2009 90" --> Output = 16 Mar 2010 */ /* DOC: Input = "20.01.2009 -50" --> Output = 1 Dec 2008 */ /* DOC: Input = "* -50" --> Output = 21 Dec 2014 */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ parse arg dat1 days if dat1 = "" | days = "" then do say; say "Number of parameters is wrong"; say call wrongarg return end if dat1 "*" then do if datumok(dat1) "OK" then do say; say "1st parameter has a wrong format"; say call wrongarg return end end if datatype(days) "NUM" then do say; say "2nd parameter is not numeric"; say call wrongarg return end if dat1 = "*" then dat1 = date("B") else DAT1 = date("B",right(DAT1,4) || substr(DAT1,4,2) || left(DAT1,2),"S") eday = dat1 + days DAT2 = date("N",eday,"B") /* Output form: tt Mon yyyy */ return(dat2) wrongarg: say "Wrong arguments entered: >"dat1 days" calculate 16.12.2009 plus 90 days" say "20.01.2009 -50 --> calculate 16.12.2009 minus 50 days" say "* -50 --> calculate current date minus 50 days" return

282 | 15 The SMART ISPF utilities

15.5.10 Subroutine JULDATE – Translate a date to Julian and vise versa Please see the source code to recognize the function of this subroutine. Program 15.6: Subroutine JULDATE /* DOC: JULDATE REXX SUBROUTINE */ /* DOC: Julian date calculations. */ /* DOC: Function: */ /* DOC: This subroutine calculates to a specified standard date the */ /* DOC: JULDATE or vise versa. */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ /* Input: JULDATE = "YYYY/TTT" Output: DATE = YYYY/MM/TT */ /* Input: DATE = "YYYY/MM/TT" Output: JULDATE = YYYY/TTT */ /* If the input date is incorrect then 999 is returned. */ /* Caution: */ /* When the input is a literal, it must be enclosed in quotes. */ /* This is because REXX interprets the slash (/) as a division */ /* operator. *//*********************************************************************/ juldata: arg indate indate = strip(indate) select when substr(indate,5,1) = "/" &, /* Normal date entered */ substr(indate,8,1) = "/" &, length(indate) = 10 then do parse var indate yyyy"/"mm"/"tt . if (datatype(yyyy,"N") * datatype(mm,"N") *, datatype(tt,"N") = 0) then return("999") if mm > 12 | tt > 31 | (yyyy * mm * tt = 0) then return("999") ddd = date("B",date("B",yyyy||mm||tt,"S"), - date("B",yyyy"0101","S"),"B") + 1 retv = yyyy"/"right(ddd,3,"0") end when substr(indate,5,1) = "/" & length(indate) = 8 then do /* Juldate */ parse var indate yyyy"/"ddd . /* entered */ if (datatype(yyyy,"N") *, datatype( ddd,"N") = 0) then return("999") leap = ((yyyy // 4 = 0) - (yyyy // 100 = 0) + (yyyy // 400 = 0)) if ddd > (365+leap) | (yyyy * ddd = 0) then return("999") retv = date("S",substr(yyyy,3,2)||ddd,"J") retv = substr(retv,1,4)"/"substr(retv,5,2)"/"substr(retv,7,2) end otherwise return("999") end /* select */ return retv

15.5 Programming aids | 283

15.5.11 Subroutine LEAPYEAR – Return the leap year information Please see the source code to recognize the function of this subroutine. Program 15.7: REXX function LEAPYEAR /* DOC: LEAPYEAR REXX FUNCTION */ /* DOC: Calculates whether the entered year is a leap year or not. */ /* DOC: This function returns 1 if the entered year is a leap year; */ /* DOC: Returns 0 if not. */ /* DOC: Caution: No plausibilty checking of the year characters will */ /* DOC: be performed. */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ ARG year RETURN ((year // 4 = 0) - (year // 100 = 0) + (year // 400 = 0))

15.5.12 REXX subroutine SCHANGE – REXX change function Please see the source code to recognize the function of this subroutine. Program 15.8: REXX subroutine SCHANGE /* DOC: SCHANGE REXX SUBR */ /* DOC: This REXX subroutine performs changes in any strings. */ /* © FRANZ LANZ 2015 */ /*********************************************************************/ /* Call: result = change(input,target,new,only) */ /* result: Resulting string. */ /* input : Input string. */ /* target: Search string. */ /* new : String which replaces the TARGET string. */ /* only : The change will only take place if the text to be */ /* searched also contains this text. */ /* Remarks: */ /* */ /* The replacing text may be longer or shorter than the replaced */ /* text. */ /* If no replacement text is entered, the search text will be */ /* removed from the scanned string. */ /* All found search strings are replaced in the searched text by the */ /* replacement text. */ /*********************************************************************/ schange: parse arg input,target,new,onlyt if length(onlyt) > 0 & pos(onlyt,input) = 0 then return(input) ls = length(target) le = length(new) ip = 1 do i = 1 ii = pos(target,input,ip) if ii = 0 then return(input) if le = 0 then input = delstr(input,ii,ls) else input = insert(new,delstr(input,ii,ls),ii-1) ip = ii + le end i

284 | 15 The SMART ISPF utilities

15.5.13 Program SDYNPAN – Convert a panel source code To save space, I will refrain from the expressions of the entire source code. The comment lines at the beginning of the program include a detailed description of the function. The source code of SDYNPAN is very long. Therefore, only the functional description of the program is inserted below. Program 15.9: Program SDYNPAN /* DOC: SDYNPAN REXX MAIN */ /* DOC: This program converts an ISPF panel such that its contents */ /* DOC: can be embedded in a REXX procedure to be dynamically */ /* DOC: loaded from there into a temporary ISPPLIB for the execution.*/ /* © FRANZ LANZ 2015 */ /*-------------------------------------------------------------------*/ /* Call this program by entering its name in front of a panel name */ /* in a DSLIST display of a panels data set. */ /* */ /* This technique, panels dynamically during the run of a REXX */ /* program to load, has the advantage that you do not need a */ /* separate ISPPLIB version of the ISPF panels, where the panels are */ /* stored. Therefore, a simultaneous distribution of a panel data */ /* set is not necessary. The converted panel definitions are stored */ /* in a sequential data set. The LLQ of this data set is the panel */ /* name. This procedure uses the panel SDYNPAN. */ /*********************************************************************/

3 Remark: I used this program to convert all panels of the SMART ISPF utilities to load them dynamically when a program is started, which contains panels.

15.6 Installation of SMART ISPF utilities To use the smart utilities, you must install them in your TSO/ISPF system. Before you start transferring programs and panels, you need to make an important decision: 3 Note: The REXX procedures of the SMART ISPF utilities contain all required panel definitions in their source code. Therefore, you do not have to transfer the panels to your ISPPLIB. The installation program SPROFVAR that stores the ISPF environment variables in the ISPF PROFILE POOL, contains the variable dynpan. If you set dynpan to YES before you execute SPROFVAR, then the REXX procedures uses imbedded panels when executed.

15.6 Installation of SMART ISPF utilities | 285

15.6.1 Download and unzip Perform the following steps to install the SMART ISPF utilities: 1. Download the SMART ISPF utilities ZIP file from the DeGruyter website www.degruyter.com. 2. Unzip the file to a folder in your PC. After unzipping, the following data sets are in the folder: REXX The REXX program package. PANELS The ISPF panel package. SHOSTUNP REXX program to unpack REXX programs and ISPF PANELS into their libraries on z/OS host. The two files REXX and PANELS contain all procedures and all panels of the SMART ISPF utilities in packed form. After transferring into the appropriate libraries on the z/OS/ system, they must be unpacked using the REXX program SHOSTUNP. This REXX program is the only program that is usable to unpack the data sets because the packed data sets have a proprietary format. Upload and unpack the members to z/OS host: 1. Use the 3270 emulation software you have on your PC to upload the three members to the z/OS host into a PDS or PDS-E with RECFM=FB and LRECL=80. 2. Then use the program SHOSTUNP to extract the packed members into the appropriate libraries. Use the Command Shell (menu 6) of ISPF to execute the program SHOSTUNP. The following screen shows these commands: Screen 15.7: Examples of unpacking SMART ISPF utilities members Menu List Mode Functions Utilities Help --------------------------------------------------------------------------ISPF Command Shell Enter TSO or Workstation commands below: ===>

Place cursor on choice and press enter to Retrieve command => => => => =>

ex 'usrlanz.smart.rexx(shostunp)' 'usrlanz.smart.rexx(rexx)' ex 'usrlanz.smart.rexx(shostunp)' 'usrlanz.smart.panels(panels)' IND$FILE PUT 'usrlanz.book.rexx(shostunp)' ASCII CRLF IND$FILE PUT 'usrlanz.book.rexx(rexx)' ASCII CRLF IND$FILE PUT 'usrlanz.book.panels(panels)' ASCII CRLF

3 Note: The last three lines in the above panel show the commands automatically executed under TSO while the upload was running.

286 | 15 The SMART ISPF utilities

15.6.2 Installation For the installation of the SMART ISPF utilities, multiple scenarios concerning your TSO/ISPF user environment are possible: 1. You still have an own ISPF library environment with an own logon procedure. This is the ideal case. You can copy the REXX procedures of the SMART ISPF utilities directly into your SYSEXEC or SYSPROC library and unpack them there. If you want to use a panel library for the panels, you can copy the panels to the ISPPLIB chain. Additionally, you can decide whether you want to use the SLOGON procedure of the SMART ISPF utilities together with the member SLOGDSN to make your logon process more variable and convenient. 2. You get the TSO READY prompt when you leave ISPF. In this case, you can call the logon procedure SLOGON at the READY PROMPT using the command EX 'dsn(SLOGON)'. First, you must only adjust the member SLOGDSN so that there the correct data set names are included. 3. Your TSO user is completely logged off when you leave ISPF and you have no chance to start an own logon procedure. In this case, you can still use the SMART ISPF utilities. However, installation of the call environment is somewhat more complex. You can use the command ALTLIB. While there is a restriction that makes the process somewhat inconvenient: If you have performed an ALTLIB command, the calling environment thus created is always only available in the logical screen in which the ALTLIB command was executed. See the description of the ALTLIB command below.

15.6.3 ALTLIB command Excerpt from the IBM manual TSO-E Reference concerning ALTLIB: Use the ALTLIB command to: – Define alternative application-level libraries of REXX execs or CLISTs. – Indicate that user-, application-, and system-level libraries of REXX execs and CLISTs will be searched. – Exclude one or more library levels (user, application, system) from being searched. – Reset the search order to the system level. – Obtain a display of the search order that is in effect. Using ALTLIB in ISPF: When using ALTLIB when ISPF is active, you can define the libraries (user, application, and system) that are active for each application. Libraries that you define while running an application are in effect only while that application has control.

15.6 Installation of SMART ISPF utilities | 287

When the application completes, the previous libraries (user, application, and system) will automatically be reactivated. If you are in split-screen mode in ISPF and you issue the ALTLIB command from a one-screen session, the changes affect only that screen session. The ALTLIB search order is not valid across split screens. To execute the ALTLIB command, enter the following command in an ISPF command line: TSO ALTLIB ACT APPLICATION(EXEC) DSNAME('dsn')

dsn is the data set where your REXX procedures reside. If you have installed the REXX procedures of SMART ISPF utilities into this dsn, the utilities are also executable. Recommendation: Program a PF key with this ALTLIB call. When you open a new logical screen in ISPF, then you can execute the command immediately by pressing the PF key.

Example: The following screen shows the assignment of keys PF18 and PF19 for execution of the ALTLIB command. Screen 15.8: PF key setting to execute ALTLIB PF Key Definitions and Labels - Alternate Keys Command ===> Note: Definitions and labels below apply only to terminals with 24 PF keys. PF13 PF14 PF15 PF16 PF17 PF18 PF19 PF20 PF21 PF22 PF23 PF24 PF13 PF16 PF19 PF22

. . . . . . . . . . . .

. . . . . . . . . . . .

HELP SWAP LIST END RETURN TSO %SYSID tso altlib act application(exec) dsname('userid.rexx') tso altlib display DOWN #SPLJ #EDMEM RIGHT TSO %SCURSOR

label label label label

. . . .

. . . .

PF14 PF17 PF20 PF23

label label label label

. . . .

. . . .

PF15 PF18 PF21 PF24

label label label label

. . . .

Press ENTER key to display primary keys. Enter END command to exit.

. . . .

288 | 15 The SMART ISPF utilities

The command ALTLIB DISPLAY shows the current ALTLIB chain. After pressing PF18 and then PF19, the following display appears: Current search order (by DDNAME) is: Application-level EXEC DDNAME=SYS00278 System-level EXEC DDNAME=SYSEXEC System-level CLIST DDNAME=SYSPROC ***

I used DDLIST to find the DDNAME SYS00278 and found it in the following screen: Current Data Set Allocations Command ===>

Row 111 of 148 Scroll ===> CSR

Volume DMTCAT

Disposition Act DDname Data Set Name Actions: B E V M F C I Q SHR,KEEP > SYSTCPD CENTER.PARMLIB(DATA00) NEW,DEL > SYSTERM ---------- Allocated to the terminal -----DMTU08 SHR,KEEP > SYS00278 USERID.REXX -------------------------- End of Allocation List ----------------------------

Remarks concerning the ALTLIB command: – – –

ALTLIB commands can occur in a stacked manner. Only the procedures of the first level in a chain of stacked ALTLIB chains are reachable. Use the command altlib deact application(exec) to remove the top level of the chain.

Example: I pressed PF18 four times and then I pressed PF19. The following chain appears: Current search order (by DDNAME) is: Application-level EXEC DDNAME=SYS00284 Stacked DDNAME=SYS00283 Stacked DDNAME=SYS00282 Stacked DDNAME=SYS00281 System-level EXEC DDNAME=SYSEXEC System-level CLIST DDNAME=SYSPROC *** 3 Note: The command ALTLIB DISPLAY shows in opposition to the command ISPLIBD only the DD names of the allocated data sets. If you want to see the corresponding DSNs, you can view them with the utility DDLIST as shown below.

NEW,DEL > SYSTERM ---------- Allocated to the terminal -----DMTU08 SHR,KEEP > SYS00281 USERID.SMART1.REXX DMTU08 SHR,KEEP > SYS00282 USERID.SMART1.REXX DMTU08 SHR,KEEP > SYS00283 USERID.SMART1.REXX DMTU08 SHR,KEEP > SYS00284 USERID.SMART1.REXX ------------------------- End of Allocation List ----------------------------

15.6 Installation of SMART ISPF utilities | 289

15.6.4 Make the SMART ISPF utilities ready to run Before you can use the SMART ISPF utilities, there are still some steps necessary: 1. If you can fully use an own logon procedure, you must adapt the members SLOGON and SLOGDSN and perhaps copy the procedure SLOGON into an appropriate library. See section 15.6.2 Installation on page 286. 2. Edit the member SPROFVAR, perform the necessary changes and execute it using the edit macro ##. This program is executable without having to load the ISPF profile variables for the SMART ISPF utilities. The following profile variables are important to have appropriate values: account jobclass msgclass dynpan dynunit

= = = = =

"UNIVER" "A" "H" "YES" "VIO"

sortunit maclib sysproc sysexec steplib ispslib db2sys cexec storclas mgmtclas dataclas maclib1 maclib2 sortlib userlnk rexxload sysexec1 sysexec2 steplib1 AMT

= = = = = = = = = = = = = = = = = = = =

"VIO" 2 0 2 1 0 "" "NO" "USRBASE" "USRMGMT" " " "SYS1.MACLIB" "SYS1.MODGEN" "SYS1.LINKLIB" USERID()".LOAD" userid()".CEXEC" userid()".REXX" "ALLUSR.REXX" "ALLUSR.LOAD" "CSR"

/* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /*

Account number for job statement Job Run class Job message class Dynamic panel store indicator Unit to alloc dynamic panels data set. SYSDA or VIO SORT Workfile Unit Number of Maclibs Number of SYSPROCs Number of SYSEXECs Number of STEPLIBs Number of Skel-Libs Standard DB2 Server REXX compile YES|NO SMS:Standard Storage Class SMS:Standard Management Class SMS:Standard Data Class Assembler Maclib No 1 Assembler Maclib No 2 SORT Linklib User Linklib CEXEC library Execs Execs Steplibs

*/ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */

3 Conclusion: After having performed all mentioned steps above, the SMART ISPF utilities should work fine and I wish you much success with it.

List of programs Program 2.1: Program 2.2: Program 3.1: Program 3.2: Program 3.3: Program 3.4: Program 3.5: Program 3.6: Program 3.7: Program 3.8: Program 3.9: Program 3.10: Program 4.1: Program 4.2: Program 4.3: Program 4.4: Program 4.5: Program 4.6: Program 4.7: Program 5.1: Program 6.1: Program 6.2: Program 7.1: Program 7.2: Program 7.3: Program 7.4: Program 7.5: Program 7.6: Program 7.7: Program 8.1: Program 8.2: Program 8.3: Program 8.4: Program 8.5: Program 8.6: Program 8.7: Program 8.8: Program 8.9: Program 8.10: Program 8.11: Program 8.12: Program 8.13: Program 8.14: Program 9.1: Program 9.2: Program 9.3:

Example for handling blanks and comments in REXX programs | 13 Program FLIGHTS to explain the using stems and EXECIO | 20 Examples of ADDRESS command | 26 ARGTEST – Example of the parameter handling in REXX | 31 LMGREAD read a data set using ISPF LM functions | 33 Function LEAPYEAR | 40 Example showing variations for the dissection of DATA and TIME values | 49 PARSE2 – Example for PARSE SOURCE | 51 Assemble and submit a COMPRESS job | 55 Program NAMESORT to sort names | 56 Subroutine NSORT | 56 POWER2 – Trace example | 61 RAMDOM – Generate random numbers | 73 Program to show C2D functionality | 78 Program to show X2D functionality | 82 WORDFUNC – Examples of WORD function | 92 Example of calling the TSO function LISTDS | 95 Control messages display ONLINE and in BATCH | 97 PROGNAME examples for using STORAGE function | 99 EXECIOT – Example for the TSO function EXECIO | 102 TEST1: Simple program using the TSO environment only | 105 TEST2: Simple program using the ISPF environment | 106 Panel definition of panel SSSp1 | 112 IOEXMPL1 – Read records using EXECIO of TSO | 119 IOEXMPL2 – Read records using LM services of ISPF | 120 LIBDEF example | 125 ALTLIB1: Example of the application of the command ALTLIB | 127 Stacking ALTLIB commands | 129 ALTLIB3 – Using of ALTLIB DISPLAY QUIET command | 131 LMOPEN example | 138 LMMFIND example | 140 LMGET – Read data records | 143 LMPUT – Writing a member with setting the statistic information | 144 LMCOPY example | 146 LMMSTATS example | 149 LMMLIST example | 152 LMMDISP example | 154 LMDDISP – Display data sets in a panel | 156 LMDLIST example | 158 Display a MEMLIST consisting of two data sets | 159 Test of QBASELIB in an online call | 169 QLIBDEF example | 172 QUERYENQ example | 175 TEST2 – Output of messages when a program runs online or in batch | 179 Messages definition member ISRZ00 | 180 MSGTEST – Test of messages outputting | 183

292 | List of programs

Program 9.4: Program 10.1: Program 10.2: Program 10.3: Program 12.1: Program 13.1: Program 14.1: Program 14.2: Program 14.3: Program 14.4: Program 14.5: Program 15.1: Program 15.2: Program 15.3: Program 15.4: Program 15.5: Program 15.6: Program 15.7: Program 15.8: Program 15.9:

Standard message member ISRZ00 | 184 Panel definition of panel SLEP1 | 194 HELPMASK – Help panel template | 205 Definition of panel SLEP1 | 206 Excerpt from edit macro #IMACRO2 | 219 ZVARS – Display some ISPF Z-variables | 230 Edit macro #SSS | 238 Edit macro #SSSCH | 239 #TT1 – Using the TRACE command in the macro development | 248 Example program for using the macro testing aid ISREMSPY | 250 #ALTXT – Use of parameter passing to edit macros | 252 Member SLOGDSN | 269 ISPF_ERROR subroutine | 279 Edit macro #PAN to test macros directly | 280 Subroutine DAYDIFF | 280 Subroutine ENDDAY | 281 Subroutine JULDATE | 282 REXX function LEAPYEAR | 283 REXX subroutine SCHANGE | 283 Program SDYNPAN | 284

List of tables Table 1.1: Table 1.2: Table 2.1: Table 2.2: Table 2.3: Table 3.1: Table 3.2: Table 4.1: Table 4.2: Table 4.3: Table 4.4: Table 4.5: Table 7.1: Table 7.2: Table 8.1: Table 8.2: Table 8.3: Table 8.4: Table 8.5: Table 8.6: Table 8.7: Table 8.8: Table 10.1: Table 10.2: Table 11.1:

Reference books for the programming of ISPF applications | 4 ISPF service groups | 5 Arithmetic REXX operators | 17 Compare operators | 17 Logical operators | 19 REXX host command environments | 30 Table of PARSE types | 47 REXX function groups | 63 Parameters of the DATE function | 66 Options of the TIME function | 68 DATATYPE type options | 75 Description of parameters for the FORMAT function | 83 ISPF system variables concerning error messages | 121 Search sequence in the procedures libraries | 126 Grouping of LM commands necessary for a particular type of data processing | 134 Data set query services | 161 Variables returned by the LMDLIST service | 161 DSINFO variables content | 162 LISTDSI – Variables and their contents | 165 LISTDSI – Description of reason codes | 168 Variables description of the QUERYENQ ISPF table | 174 QUERYENQ return codes | 174 Description of panel sections | 193 )ATTR definitions list | 195 Commands to create skeletons | 211

List of screens | 293

Table 12.1: Table 12.2: Table 12.3: Table 13.1: Table 14.1: Table 14.2: Table 14.3: Table 14.4: Table 15.1: Table 15.2:

Table services commands that refer to the entire table | 217 Table service commands that relate to individual rows | 217 Components of the SLE application | 218 General ISPF system variables | 228 Edit macro commands | 241 Operands and abbreviations of edit macro commands | 247 System variables of the ISPF editor | 251 Edit macros of SMART ISPF utilities to assemble and submit batch jobs | 255 List of the SMART ISPF utilities programs | 258 Programming aids | 273

List of screens Screen 2.1: Screen 4.1: Screen 7.1: Screen 7.2: Screen 7.3: Screen 8.1: Screen 8.2: Screen 10.1: Screen 12.1: Screen 13.1: Screen 13.2: Screen 14.1: Screen 14.2: Screen 14.3: Screen 15.1: Screen 15.2: Screen 15.3: Screen 15.4: Screen 15.5: Screen 15.6: Screen 15.7: Screen 15.8:

Example of a command call in a DSLIST display panel | 10 Read the job name from CVT | 77 Panel SLEP1 displayed by the program SLE | 116 ISPF variables display using ISPF menu 7.3 | 117 ISPLIBD – Display the current active LIBDEF assignment | 125 LMMDISP panel display | 154 MEMLIST display | 160 Panel SLEP1 displayed by program SLE | 208 Display of panel SLEP1 produced by the program SLE | 221 Members of an ISPPROF data set | 225 List of started ISPF applications | 226 Panel SSSP1 for entering search arguments | 235 Resulting panel after executing a SSS search | 235 Original output list of program ISRSUPC | 236 Set activation of #IMACROA | 261 Panel IMACRO11 for edit macro #IMACRO1 | 262 SCURSOR selection panel | 267 SLE working panel | 268 SSC working screen | 271 SSS input panel | 272 Examples of unpacking SMART ISPF utilities members | 285 PF key setting to execute ALTLIB | 287

Bibliography This bibliography contains excerpts from some IBM manuals concerning the z/OS TSO/ISPF complex: TSO/E Publications – – – – – – – – – – – – – – –

z/OS TSO/E Administration, SA22-7780 z/OS TSO/E CLISTs, SA22-7781 z/OS TSO/E Command Reference, SA22-7782 z/OS TSO/E Customization, SA22-7783 z/OS TSO/E General Information, SA22-7784 z/OS TSO/E Guide to SRPI, SA22-7785 z/OS TSO/E Messages, SA22-7786 z/OS TSO/E Primer, SA22-7787 z/OS TSO/E Programming Guide, SA22-7788 z/OS TSO/E Programming Services, SA22-7789 z/OS TSO/E REXX Reference, SA22-7790 z/OS TSO/E REXX User’s Guide, SA22-7791 z/OS TSO/E System Programming Command Reference, SA22-7793 z/OS TSO/E System Diagnosis: Data Areas, GA22-7792 z/OS TSO/E User’s Guide, SA22-7794

z/OS MVS Publications – z/OS MVS Planning: APPC/MVS Management, SA22-7599 – z/OS MVS Programming: Writing Transaction Programs for APPC/MVS, SA227621 – z/OS MVS Initialization and Tuning Reference, SA22-7592 – z/OS MVS Programming: Authorized Assembler Services Guide, SA22-7608 – z/OS MVS Programming: Authorized Assembler Services Reference ALE-DYN, SA22-7609 – z/OS MVS System Messages, Vol 1 (ABA-AOM), SA22-7631 – z/OS MVS System Messages, Vol 2 (ARC-ASA), SA22-7632 – z/OS MVS System Messages, Vol 3 (ASB-BPX), SA22-7633 – z/OS MVS System Messages, Vol 4 (CBD-DMO), SA22-7634 – z/OS MVS System Messages, Vol 5 (EDG-GFS), SA22-7635 – z/OS MVS System Messages, Vol 6 (GOS-IEA), SA22-7636 – z/OS MVS System Messages, Vol 7 (IEB-IEE), SA22-7637 – z/OS MVS System Messages, Vol 8 (IEF-IGD), SA22-7638 – z/OS MVS System Messages, Vol 9 (IGF-IWM), SA22-7639 – z/OS MVS System Messages, Vol 10 (IXC-IZP), SA22-7640 – z/OS MVS System Codes, SA22-7626

296 | Bibliography

ISPF Publications – – – – – – – –

z/OS ISPF Dialog Developer’s Guide and Reference, SC19-3619-00 z/OS ISPF Dialog Tag Language Guide and Reference, SC19-3620-00 z/OS ISPF Edit and Edit Macros, SC19-3621-00 z/OS ISPF Messages and Codes, SC19-3622-00 z/OS ISPF Reference Summary, SC19-3624-00 z/OS ISPF Services Guide, SC19-3626-00 z/OS ISPF User’s Guide Vol I, SC19-3627-00 z/OS ISPF User’s Guide Vol II, SC19-3628-00

Index "ISPEXEC" 29 "ISREDIT" 29 #C 273 #IE 273 #IMACRO1 42, 262 #IMACRO2 219, 262, 267 #IMACROA 261 #ISPFB 263 #LCH 263 #RC 273 #RCLOAD 273 #RO 273 #SPLJ 263 #SSS 272 #SSSCH 237 #SU 264 #TSOB 71, 265 #VERASE 266 $$DYNPAN 257 $DOC 267 $SLETAB 193, 218, 219, 221, 262, 267 &USERID 269 )AREA 205 )ATTR 191, 193 )BLANK 211 )BODY 191, 193, 195, 205 – definitions 195 – EXPAND 196 )CM 211 )DEFAULT 211 )DOT 211 )END 193, 206 )ENDDOT 211 )HELP 193, 199, 206 )IM 211 )INIT 193, 196, 205 )MODEL 193, 205, 206, 209, 219 )PROC 193 )REINIT 193 )SEL 211 )SET 211 )TB 211 )TBA 211 .ATTR 199 .CSRPOS 197, 198 .CSRROW 193, 206

.CURSOR 198, 199 .HELP 193, 198, 205, 206 .RESP 199, 200 .TRAIL 200 .ZCSR 238, 251 .ZF 251 .ZFIRST 251 .ZL 251 .ZLAST 251 .ZVARS 193, 196, 197, 201, 202, 206 ABS 72 ACCOUNT 289 ADDPOP 60, 62, 203 ADDRESS 22, 25, 26, 27, 28, 33 – subsys 27 ADDRESS() 33, 64 ALLOC 22, 59, 60, 61, 62, 104 ALTLIB 10, 126, 286, 287 – ACT 127 – ACTIVATE APPLICATION(EXEC) 127 – command 10 – DEACTIVATE SYSTEM(CLIST) 127 – DISPLAY 10, 127, 130 – purpose 126 – QUIET 130 – RESET 127 Application-level 288 ARG 31, 65 Assembler language 2 C2D 77, 78 C2X 79 CALL 32, 34, 35 CENTER 82, 238 CHANGE 86, 250 Command delimiter 274 COMPARE 74 comparison functions 74 concatenation operator (||) 16 CONTROL ERRORS RETURN 33, 71, 125, 178 conversion functions 77 COPIES 83 Cowlishaw, Michael 1, 8 CURSOR 238, 239 CVT 77, 98 D2C 79 D2X 77, 80

298 | Index

DATA 49 Data set query – DSINFO 162 – LISTDSI 164 – LMDLIST 161 – QBASELIB 169 – QLIBDEF 171 – QUERYENQ 173 DATA STACKS 53 DATATYPE 75, 76 – type options 75 DATE 15, 16, 65, 66 – calculations 67, 280 – call options 66 – parameters 66 day of the week 66 DAYDIFF 273, 280 DD 104 DDLIST 288 DELETE 239 DELSTACK 103 DELSTR 85 DIGITS() 46, 72 DISKR 102 DISKW 102 DISPLAY 192 DISPLAY PANEL 60, 62, 202 DO 36, 37 – FOREVER 37 – group 36 – I = A TO B BY C 37 – increment 39 – ITERATE 39 – LEAVE 37, 39 – loop 37 – loop index 39 – UNTIL 37, 38, 39 – UNTIL condition 38 – WHILE 37, 38, 39 – WHILE condition 38 DOC line 267 DROPBUF 103 DSINFO 93, 161 – variables content 162 DSLIST – display panel 10, 106 DYNPAN 284, 289 DYNUNIT 289 Edit commands

– abbreviations 247 – AUTOLIST 241 – AUTONUM 241 – BOUNDS 241 – BROWSE 242 – BUILTIN 242 – CANCEL 242 – CANGE_COUNTS 242 – CAPS 242 – CHANGE 242, 250 – COMPARE 242 – COPY 242 – CREATE 242 – CURSOR 242 – CUT 242 – DATA_CHANGED 242 – DATA_WIDTH 242 – DELETE 243 – DISPLAY_COLS 243 – DISPLAY_LINES 243 – EXCLUDE 243, 250 – EXCLUDE_COUNTS 243 – FIND 243, 250 – FIND_COUNTS 243 – FLIP 243 – FLOW_COUNTS 243 – HEX 243 – HILITE 243 – IMACRO 243 – INSERT 243 – LABEL 243 – LEFT 243 – LEVEL 243 – LINE .ZCSR 248 – LINE_AFTER 244 – LINE_STATUS 244 – LOCATE 244 – MACRO 244, 252 – MACRO_LEVEL 244 – MASKLINE 244 – MEMBER 244 – MODEL 244 – MOVE 244 – NONUMBER 244 – NOTES 244 – NULLS 244 – NUMBER 244, 245 – PACK 244 – PASTE 245

Index | 299

– PROCESS 245 – PROFILE 245 – RCHANGE 245 – RECFM 245 – RECOVERY 245 – RENUM 245 – REPLACE 245 – RFIND 245 – RIGHT 245 – RMACRO 245 – SAVE 245 – SAVE_LENGTH 245 – SCAN 245 – SEEK 245 – SEEK_COUNTS 246 – SESSION 246 – SHIFT 246 – SORT 246 – STATS 246 – SUBMIT 246 – table of commands 241 – TABS 246 – TABSLINE 246 – TENDER 246 – TFLOW 246 – TSPLIT 246 – UNNUMBER 246 – UP 246 – USER_STATE 246 – VERSION 246 – VIEW 246 – VOLUME 246 – XSTATUS 246 EDIT DATASET 28, 186 Edit macros – ## 258 – #ALTXT 252, 258 – #C 274 – #EDMEM 258 – #IE 273, 277 – #IMACRO1 258 – #IMACRO2 258 – #IMACROA 258 – #ISPFB 255, 259 – #LCH 259 – #PAN 273, 279 – #RC 273, 275 – #RCLOAD 273, 276 – #RO 273

– #RO 274 – #SPLJ 263 – #SSS 259, 264 – #SSSCH 259 – #SU 255, 259, 264 – #TSOB 255, 259, 265 – #VERASE 259, 266 – print message 186 – Table of operands 247 Edit value – BOUNDS 248 – CURSOR 248 – DATASET 248 – MEMBER 248 EDSET 261 ENDDAY 273 English weekday 66 ENQ 215 EXCLUDE 238, 250, 255 EXECIO 22, 28, 54, 55, 57, 101, 102 – empty a data set 102 – read a data set 102 EXIT 35, 39 EXPOSE 52 FIELD 193, 199, 206 FIND 238, 250 FORM 72 FORMAT 83 – parameters 83 formatting functions 82 FREE 104 FTCLOSE 213, 214 FTINCL 41, 114, 212, 214 function pool 223 FUZZ() 46, 72 HELP panels 190, 205 HILITE 36 HILITE(REVERSE) 199 Host Command Environment 25, 104 IBM form number 3 IEBCOPY 55, 150 IF 41 IKJADM 130 IKJEFT01 113, 114 IMACROA – activation 261 INSERT 85 INTERPRET 34, 42, 43, 70 ISFPROF 225

300 | Index

ISPF V, 224 – Batch Job 170 – SELECT CMD service 10 ISPF basics – brochures 109 – create and edit tables 215 – create panels 189 – data set services 118 – data sets 110 – edit macros 4, 233 – error handling 177 – ISPF start commands 226 – ISPF system variables 228 – LM services 120, 133 – locations of tables 215 – manuals 3 – messages 110 – naming convention of the message IDs 181 – panel types 190 – panels 110 – pools for variables 223 – programming languages 109 – reading tables 215 – reference books 4 – service groups 5 – skeletons 110 – system variables 116, 117, 121 – tables 111 – user variables 116 – variables 111, 116 – writing tables 215 ISPF Batch Job 170 ISPF messages display – SETMSG 13, 55, 115, 122, 123, 178, 180 ISPF messages library – ISPMLIB 124, 180, 181, 184, 269 ISPF messages member – define a member 182 – ISRZ00 180 – ISRZ000 185 – ISRZ001 13, 123, 185, 186 – ISRZ002 185, 186 – ISRZ003 185 ISPF messages variables – ZEDLMSG 180 – ZEDSMSG 180 – ZERRALRM 180 – ZERRHM 180

– ZERRLM 180 – ZERRSM 180 – ZERRTP 180 ISPF SELECT 192 ISPF system variables 228 ISPF tables – commands for editing tables 217 – commands that affect the entire table 217 – services commands 216 ISPF tables commands – TBADD 115, 217 – TBBOTTOM 217 – TBCLOSE 115, 215, 217 – TBCREATE 217 – TBDELETE 217 – TBDISPL 116, 192, 208, 220 – TBEND 175, 217 – TBERASE 217 – TBEXIST 217 – TBGET 217 – TBMOD 115, 217 – TBOPEN 115, 215, 217 – TBPUT 217 – TBQUERY 175, 217 – TBSARG 217 – TBSAVE 217 – TBSCAN 217 – TBSKIP 175, 217 – TBSORT 115, 217 – TBSTATS 217 – TBTOP 116, 208, 217, 220 – TBVCLEAR 217 ISPF Task List panel 226 ISPFERR 273 ISPFILE 124 ISPLIBD 125 ISPLLIB 28, 124 ISPMLIB 181 ISPPLIB 124 ISPPROF 224, 225, 226 – data set 225 ISPSLIB 124, 214 ISPSPROF 227 ISPSTART 224 ISPTABL 115, 124, 216 ISPTLIB 124, 215, 216, 225, 226 ISPYXDR 280 ISR@PRIM 204 ISREDIT 238

Index | 301

ISREDIT MACRO 29 ISREMSPY 249 ISRPROF 225, 226 ISRSUPC 234, 236, 272 ISRZ00 184 JOB example – COMPRESS 55 JOBCLASS 289 JOBSUFF() 55 JULDATE 273 Julian Day 66 JUSTIFY 83, 84 LABEL 238 LASTPOS 43 LEAPYEAR 40, 273 – calculation 40 LEAVE 36, 37 LEFT 51, 84 LENGTH 86 LIBDEF 28, 123 – STACK option 124 LIBDEF ISPPLIB 280 LINE 238 LINE_BEFORE 238 LINENUM .ZFRANGE 253 LINENUM .ZL 239 Link library 276 LISTCAT 104 LISTDS 95 LISTDSI 93, 161, 164, 169 – description of reason codes 168 – Table of variables 165 LLQ 262 LM services – grouping 133 – LMCLOSE 138, 143, 240 – LMCOMP 135, 150 – LMCOPY 134, 145, 146 – LMDDISP 135, 155 – LMDFREE 158 – LMDINIT 155 – LMDINIT 155 – LMDINIT 155 – LMDLIST 157, 161 – LMFREE 28, 137, 138, 143, 240 – LMGET 34, 134, 142, 144 – LMGREAD 33 – LMINIT 28, 34, 136, 137, 144, 146 – LMMADD 143

– LMMDEL 135, 146 – LMMDISP 153, 154 – LMMFIND 34, 134, 139, 143, 144 – LMMLIST 135, 150, 152 – LMMOVE 134, 146 – LMMREN 135, 147 – LMMREP 134, 140, 143, 144 – LMMSTATS 28, 135, 147, 240 – LMOPEN 34, 137, 138, 144, 146 – LMPUT 134, 143, 144 – MEMLIST 135 LMDLIST 93, 157, 158, 161 – variables 161 MACRO 238, 239, 248, 250, 252, 280 – testing aid ISREMSPY 250 MEMLIST 158 MIN, MAX 73 MSG 93 MSGCLASS 289 MVSVAR 94 NEWAPPL 224 NEWPOOL 224 NOP 58, 60 NOWRITE 215 NUMERIC 44 – DIGITS 44, 45 – DIGITS examples 45, 61, 72 – FUZZ 44, 45 – FUZZ examples 45, 72 OOREXX 1 OTHERWISE 58, 115, 123 OUTTRAP 55, 59, 94, 95, 104 OVERLAY 43 Panels 190 – )ATTR 193 – )BODY 193, 196 – )BODY WINDOW 196 – )END 193 – )INIT 193 – )MODEL 193 – )PROC 193 – )REINIT 193 – attribut options 194 – attribute characters 191 – attribute section 193 – creation 192 – data fields 191 – display 192 – DISPLAY 202

302 | Index

– HELP 205 – sections description 193 – SELECT 202 – SSSP1 235 – structure 191 – TBDISPL 202 – text fields 191 PARSE 32, 46, 279 – ARG 48 – NUMERIC NUMS examples 72 – rules 47 – SOURCE 51 – SOURCE examples 51 – templates 47 – types 47 – UPPER 47 – VALUE 48 – VALUE … WITH 48 – VALUE WITH example 49 – VAR 33, 51 PDS 101 PDSE 101 PFK 197 PF-Keys – PF18 288 – PF19 288 POP UP panels 190 POS 41, 87, 279 PROCEDURE 52 – EXPOSE 32, 52 profile pool 223, 224 Program examples – #TT1 macro 248 – #TT2 macro 250 – ADDRESS 26 – ALTLIB1 127 – ALTLIB2 129 – ALTLIB3 130 – ARGTEST 31 – C2D 78 – COMPRESS 55 – EXECIOT 102 – HELPMASK 205 – IOEXMPL1 119 – IOEXMPL2 120 – JD2 18 – JOBNTSO 77 – LIBDEF 125 – LISTDS 95

– LMCOPY 146 – LMDDISP 156 – LMDLIST 158 – LMGET 142 – LMMDISP 154 – LMMFIND 139 – LMMLIST 152 – LMMSTATS 149 – LMOPEN 138 – LMPUT 144 – MSGTEST 184 – NAMSORT 55 – NSORT subroutine 56 – NULLSTR 21 – output of messages 179 – panel definition of panel SLEP1 193 – POTENZ2 61 – QBASELIB 169 – QLIBDEF 172 – QUERYENQ 175 – RANDOM 73 – VINTPAC 113, 114 – WORDFUNC 92 – X2D 82 – ZVARS 230 Programming aids 273 – #C 274 – #IE 277 – #PAN 279 – #RCLOAD 276 – DAYDIFF 273, 280 – ENDDAY 281 – ENDDAY 273 – ISPF_ERROR 278 – JULDATE 273, 282 – LEAPYEAR 273, 283 – SCHANGE 273, 283 – SDYNPAN 273, 284 PULL 54, 55, 60 PUSH 54 QBASELIB 34, 127, 131, 169 QLIBDEF 172 QSAM 101 QUERYENQ 122, 175 QUEUE 53, 54, 55, 56 QUEUED() 56, 61, 69 RANDOM 73 REMPOP 60, 62, 203 RESET 239

Index | 303

RESULT 35 – example on return 40 RETURN 35, 39 REXX – Language Association 1 – Reference 2 REXX basics – arithmetic functions 72 – arithmetic operators 17 – binary literals 12 – blank lines 12 – blanks 13 – call of functions 13 – calling procedures 9 – CHAR variables 14 – comments 12, 13 – compare operators 17 – comparison functions 74 – comparison result 18 – compiled programs 11 – compiler 11 – concatenation example 43 – continuation lines 12 – hexadecimal literals 12 – host command environments 30 – IF THEN DO 36 – interpreter 8 – literals 12 – logical operators 19 – multiple statements on a line 12 – null strings 15 – NUM variables 14 – operators 15 – performance 11 – performance tips 11 – procedure recognition 8 – rules for variables 14 – STEMS 19 – string functions 85 – string operators 16 – syntax 12 – system functions 92 – table of host command environments 30 – text literals 12 – using DB2 110 – variable name length 14 – WHEN 36 – word functions 90 REXX commands 25

– ADDRESS 25 – ARG 32 – CALL 35 – DO 36, 37 – EXIT 39 – INTERPRET 42 – NOP 60 – NUMERIC 44 – PARSE 46 – PARSE ARG 32 – PARSE VALUE 32 – PROCEDURE 52 – PROCEDURE EXPOSE 32 – PULL 60 – QUEUE 53 – RETURN 39 – SELECT 41, 57 – SIGNAL 62 – TRACE 61 – WHEN 41 REXX functions 63 – ABS 72 – ADDRESS() 28 – ARG 31 – C2D 77 – C2X 79 – CENTER 82 – CHANGE 86 – COMPARE 74 – COPIES 83 – D2C 79 – D2X 80 – DATATYPE 75 – DATATYPE 15 – DELSTACK 103 – DELSTR 85 – DIGITS() 46 – DIGITS, FORM, FUZZ 72 – DROPBUF 103 – EXECIO 101 – FORMAT 83 – FUZZ() 46 – general 64 – INSERT 85 – JUSTIFY 83 – LEFT 84 – LENGTH 86 – LISTDSI 93, 164 – MIN, MAX 73

304 | Index

– MSG 93 – MVSVAR 94 – OUTTRAP 94, 104 – OVERLAY 87 – POS 87 – QUEUED 69 – RANDOM 73 – RIGHT 84 – SIGN 74 – SOURCELINE 69 – STORAGE 98 – STRIP 88 – SUBSTR 88 – SYSDSN 96 – SYSVAR 96 – TRANSLATE 89 – USERID 70 – VALUE 70 – VERIFY 90 – WORD 90 – WORDINDEX 91 – WORDLENGTH 91 – WORDPOS 91 – WORDS 92 – X2B 80 – X2C 81 – X2D 81 REXX host command environments 30 REXX subroutines – DAYDIFF 281 – ENDDAY 281 – JULDATE 282 – LEAPYEAR 283 – SCHANGE 283 REXXCL 276 REXXCOMP 274, 276 RIGHT 84 SAY 57, 178 SCHANGE 273 SCURSOR 266 SDYNPAN 273 SELECT 41, 57, 58, 115, 224 – and DO group 58 – CMD 274 – OTHERWISE 58, 60 – PANEL 204 – WHEN 57 SELECT CMD 10 SELECT PGM 280

shared pool 223, 224 SHOSTUNP 285 SIGN 74 SIGNAL 62 Skeletons 212 – commands 211 SLE 267 SLEP1 194, 220 SLOGDSN 270, 286, 289 SLOGON 270, 286, 289 SMART ISPF utilities 4, 257 – ## 260 – #ALTXT 260 – #C 274 – #EDMEM 260 – #IE 277 – #IMACRO2 262 – #IMACROA 261 – #ISPFB 263 – #RC 275 – #RCLOAD 276 – #RO 274 – #SPLJ 263 – #SSS 264 – #SSSCH 264 – #SU 264 – #TSOB 265 – #VERASE 266 – DAYDIFF 280 – DYNPAN 258 – DYNUNIT 258 – edit marco names 257 – ENDDAY 281 – installation 286 – ISPF_ERROR 278 – JULDATE 282, 283 – naming conventions 257 – profile variables 258 – programs list 258 – SCHANGE 283 – SCURSOR 259 – SDOC 267 – SDOC 259 – SDYNPAN 284 – SHOSTPAC 259 – SICMD 259 – SIDCAMS 259 – SJOBSUFF 259 – SLE 259, 267

Index | 305

– SLIBOFF 259 – SLISTC 259 – SLISTRAC 259 – SLOGON 259 – SPROFEDT 259, 270 – SPROFVAR 70, 259, 270 – SSC 93, 259 – SSC01 259 – SSS 259 – the dynamic panel concept 257 SOURCELINE() 69, 279 SPLIT and JOIN 263 SPROFVAR 264, 270, 284, 289 SSS 264 standard panels 190 STEMS 19, 23 STEPLIB 70 STORAGE 77, 98, 99, 240 string functions 85 STRIP 10, 88, 178 STUB – EFPL 276 – MVS 276 SUBMIT 54, 57, 265 SUBMIT * 55, 94 Subroutines – ISPF_ERROR 279 SUBSTR 88, 253 SWAP LIST 226 SYSADIRBLK 167 SYSALLOC 166 SYSBLKSIZE 165 SYSBLKSTRK 167 SYSCREATE 166 SYSDATACLASS 167 SYSDSN 13, 34, 59, 96 SYSDSNAME 165 SYSDSORG 165 SYSDSSMS 167 SYSENV 179 SYSEXDATE 166 SYSEXEC 9, 70, 126, 286 SYSEXEC 137 SYSEXTENTS 166 SYSKEYLEN 166 SYSLRECL 165 SYSMEMBERS 167 SYSMGMTCLASS 167 SYSMSGLVL1 166

SYSMSGLVL2 166 SYSPASSWORD 166 SYSPRIMARY 166 SYSPROC 9, 126, 286 SYSRACFA 166, 167 SYSREASON 166 SYSRECFM 166 SYSREFDATE 166 SYSSECONDS 166 SYSSTORCLASS 167 System variables – ZCREEN 42 – ZEDLMSG 13, 59, 115 – ZEDSMSG 59 – ZERRLM 115 – ZISPFRC 97 – ZSYSID 115 System variables of the editor 251 SYSTRKSCYL 166, 167 SYSTSPRT 57 SYSUDIRBLK 167 SYSUNIT 165 SYSUNITS 166 SYSUPDATED 166, 167 SYSUSED 166 SYSUSEDPAGES 166 SYSVAR 28, 96, 97, 179, 186 – SYSENV 28, 97 – SYSISPF 97 SYSVAR 28 SYSVOLUME 165 TIME 16, 49, 68, 69 – call options 68 – measurement 69 – parameters 68 TRACE 61 – ?i 61 – ?r 61 – O 61 TRANS 197, 206 TRANSLATE 33, 89, 169, 279 TRUNC 197, 200, 206 TSO V, 9 – ALLOC 104, 133 – ALLOC REUSE option 270 – ALTLIB 10, 126 – ALTLIB DISPLAY 126 – commands 5, 103 – data Stack 54

306 | Index

– EXEC 9 – EXECIO 133 – LISTCAT 104 – READY prompt 286 – reference book 5 – REXX interpreter 8 – STACK 53 UP 239 URL – DB2 processing example 110 – ISPF library 3 – z/OS literature 3 USERID() 70 VALUE 64, 71 VER 193, 206 VERASE 227, 229, 230 VERIFY 90 VGET 55, 115, 118, 225, 229 VOLS 162 VPUT 42, 224, 225, 229 WHEN 41, 58, 115 WORD 91, 92 WORDINDEX 91 WORDLENGTH 91, 92 WORDPOS 41, 91, 92 WORDS 92 X2B 80 X2C 81 X2D 81 Z 228 z/OS – literature 3 ZAPPLID 228 ZCMD 228 ZDATE 229 ZDATEF 229 ZDATEFD 229 ZDATESTD 229 ZDAY 229 ZDAYOFWK 229 ZDEL 228 ZDLBLKSZ 161 ZDLCDATE 161 ZDLDEV 161 ZDLDSNTP 161 ZDLDSORG 161 ZDLEDATE 161 ZDLEXT 161 ZDLLRECL 161

ZDLMIGR 161 ZDLMVOL 161 ZDLRDATE 161 ZDLRECFM 161 ZDLSIZE 161 ZDLSPACU 161 ZDLUSED 161 ZDLVOL 161 ZDS#MEM 163 ZDS1EX 162 ZDS2EX 162 ZDS2SPC 162 ZDSBLK 162 ZDSCB1 163 ZDSCDATE 162 ZDSDC 163 ZDSDEVT 162 ZDSDIR 163 ZDSDIRA 163 ZDSDIRU 163 ZDSDSNT 162 ZDSEXTA 163 ZDSEXTU 163 ZDSLREC 162 ZDSMC 163 ZDSORG 162 ZDSPAGU 163 ZDSPERU 163 ZDSRDATE 162 ZDSRF 162 ZDSSC 163 ZDSSEQ 162 ZDSSPC 162 ZDSTOTA 162 ZDSTOTU 162 ZDSVOL 162 ZDSVTAB 163 ZDSXDATE 162 ZEDLMSG 13, 59, 122, 123, 185, 186 ZEDSMSG 59, 122, 185 ZENVIR 228 ZERRALRM 121 ZERRHM 121 ZERRLM 121, 122, 123, 178, 186 ZERRMSG 121 ZERRSM 121, 178 ZISPFRC 34, 40, 228 ZJ4DATE 229 ZJDATE 229

Index | 307

ZLANG 228 ZLOGON 228 ZMONTH 229 ZPANELID 228 ZPREFIX 228 ZSCREEN 42 ZSCREENC 228

ZSCREENI 228 ZSCREENW 228 ZSTDYEAR 229 ZTIME 229 ZTIMEL 229 ZYEAR 229