ISPF Edit Macros, an Introduction . . .
You want to put a series of Edit commands together into an EXEC so you can make the same edit changes to several members? Write an ISPF Edit macro. It's easier than it sounds.
You need to have a dataset where you can put your EXEC members (CLISTs and REXX EXECs). You only need one; You can put your edit macros into the same dataset with your other CLISTs and REXX EXECs. As discussed in the previous post here, your EXEC library should be allocated to the ddname SYSUPROC(*see footnote for other options). Allocate SYSUPROC (with a U in the middle) at the time when you Logon, before you start ISPF; Do this by using a CLIST that runs automatically every time you Logon TSO – a CLIST that contains the ALLOCATE for SYSUPROC. The first part of the previous article (How to Write a Clist) explains how you set up a CLIST to execute at LOGON to TSO..
So let’s put a really simple edit macro into your EXEC library, just to get the ball rolling. Create a member called UCXX. This member will change lowercase text to uppercase text, but only in eXcluded lines. UCXX will have the following few lines:
ISREDIT MACRO NOPROCESS
ISREDIT CAPS OFF
ISREDIT CHANGE P'<' P'>' ALL X
ISREDIT LEFT MAX
Every line starts with ISREDIT. That tells the command handler to pass the line over to ISPF edit for processing.
The first line contains ISREDIT MACRO to indicate that this is a macro. The MACRO line is a requirement. Specifying NOPROCESS enables you to limit the range of lines that are affected by line commands within your macro (this will be more apparent in the second example). In this first example we use “ALL X” (all excluded lines) as a quick and easy substitute for specifying the line range.
The second line contains an actual edit command. If your edit profile for this type of dataset has CAPS mode turned ON, this CAPS OFF will turn it OFF. This does the same thing as entering CAPS OFF on the command line, but here you are putting the command into your macro instead, and hence you preface it with the mandatory ISREDIT lead-in.
The next line also contains an actual edit command, Change (which can be abbreviated C — I just write it out as Change to make the meaning obvious at a glance).
Change is an edit command you already know. P means “picture”, and there are various picture possibilities: P with the Less-than sign enclosed in apostrophes ( P‘<’ ) means lowercase text, and P with the Greater-than sign enclosed in apostrophes ( P‘>’ ) means uppercase. So this change command will change lowercase letters to uppercase letters, but since it says “all X”, it will make the change only on eXcluded lines.
The final line of the macro just straightens up the display a bit, and is not strictly necessary. If the last character that gets changed by the macro happens to be at the far right of a long line, then without a corrective adjustment like this, the cursor may end up at the far right of a line, so the screen display may look funny. This last line just shifts the display back to the left. You could also add an ISREDIT RESET line, but then you wouldn't see highlighting of the changed lines.
Assume you have now entered the sample lines into a new EXEC member called UCXX, and saved it. If your EXEC library was automatically allocated to SYSUPROC at Logon, you should just go into split screen mode now and use your second “screen session” to edit some other dataset. Pick a C program or some text – anything containing some lowercase.
To test this macro, you will exclude a block of lines by typing XX over the lefthand line numbers at the start and end of a block of lines that contain lowercase, thus excluding them from the display. Then type UCXX on the command line, press enter, and bingo, your macro should do the change command as specified, immediately changing all lowercase letters to uppercase letters within all excluded lines.
Okay, that worked. Just put CAN (or cancel) on the command line to get out of EDIT without saving the changes (assuming you’re doing this just to test for your macro).
This is actually easy, right?
As an exercise, you can make a modified version of the macro and call it UCNX, and set it up so it makes the specified changes to all the lines that are NOT eXcluded. (The opposite of “all X” is “all NX”, if you don’t use that feature often enough to recall the syntax offhand.)
As another exercise, you can make yet another copy of the macro and call it DENUM, setting it up to change all numbers in columns 73 through 80 to blanks. You would of course only use such a macro on 80-byte fixed-length records. The Picture code for numeric data is P’#’ and blank is just a blank enclosed in apostrophes. Some people don't like to use the blank enclosed in apostrophes because it isn't totally easy to read; You can use X'40' instead if you prefer, since hexadecimal 40 equates to the character blank. For example you might use a line like this:
ISREDIT CHANGE P'#' ' ' 73 80 ALL NX
ISREDIT CHANGE P'#' X'40' 73 80 ALL NX
If you want to know the rest of the picture codes, consult Picture string examples and Picture strings (string, string1) in the Links to IBM Documentation at the end of this post.
Now let’s do something that specifies a range of lines without relying on eXclude.
Here’s one that I prepared earlier — a modified version of the UCXX macro. Let’s call it UC## (or some other unused name of your own choosing):
ISREDIT MACRO NOPROCESS
ISREDIT CAPS OFF
ISREDIT PROCESS RANGE Q /
ISREDIT CHANGE P'<' P'>' .ZFRANGE .ZLRANGE ALL
ISREDIT LEFT MAX
Enter the above lines into a member named (for example) UC## in your same EXEC library. Save the member, and swap back to your other split screen session. Edit the same thing you just cancelled out of after using UCXX. This time, instead of eXcluding lines, put // over the lefthand line numbers at the start and at the end of the block of lines to be processed by the macro. Instead of XX, you use //, basically. Then you enter UC## on the command line, press enter, and again voila, the text should be changed just like it was before with the UCXX macro.
So, we ask, how is the second macro, UC##, different from the first macro, UCXX ? Right, It has that PROCESS RANGE statement, and then, on the CHANGE command, instead of “ALL X”, it has .ZFRANGE and .ZLRANGE. What does it mean? Well, F means First (in .ZFRANGE) and L means Last. RANGE obviously means, uh, range: the range of lines to be affected by the change So, the line number of the first line where you put // becomes .ZFRANGE, and the last line where you put // becomes .ZLRANGE. What does .Z mean? IBM reserves .Z for their own ISPF editor label names. In general in ISPF, names that start with Z are generally IBM ISPF names, so if you are making up a name for anything, it’s safer if you pick a name that doesn't start with Z.
So in the second macro we have the same Change command, but a different way of specifying the range of lines to be processed. We told it to “PROCESS RANGE Q /”, and when we executed the macro, we used the slash (/) when we designated a block of lines delineated by // ; using QQ instead of // should work the same way – the “PROCESS RANGE Q /” means that either Q or / can be used (but you can’t mix them).
You can choose the two characters (you don’t have to use Q and /), but there are rules. Per IBM, you can choose “any alphabetic or special character except blank, hyphen (-), apostrophe ('), or period (.)” and also no numbers. That quoted part was a direct quote from the “Edit and Edit Macros” manual, but personally I wouldn’t use the letter A or X or other letters that might lead to ambiguity, and wouldn’t use a plus sign or an ampersand or anything that looks like it might possibly ever lend itself to an alternate interpretation. But that’s just me. If you do try some character that looks like it ought to work, but it doesn’t, you can open a problem with IBM with full confidence that IBM is very good about responding to that sort of thing with a documentation change when appropriate.
I always pick the slash because the slash is used a lot for selection in ISPF, so it’s easy to remember.
In fact more often I revert to the “XX” style because it lets me set up several excluded sections and then issue the command once. You can, for example, put an X on the line numbers to exclude lines 5, 7, and 9, but you cannot do that with the .ZFRANGE, .ZLRANGE method of doing things. However, you might have a situation where you need to eXclude various lines for other reasons, and in that case the // style might suit your purpose.
Anyway, having seen the PROCESS statement in action, you see how it relates to the NOPROCESS on the MACRO statement at the beginning.
Moving ahead, the following sample macro is a simple template you can use to create other macros. It inserts 3 lines at the point where the cursor is when you press enter. So you can copy this into your EXEC library and give it member name #TRYTHIS. Then you edit something. Type #TRYTHIS on the command line, but don’t press enter yet. Place your cursor on any line in the source you're editing, and then press enter. The three lines will be inserted after the line where your cursor was. Of course, the three lines will say Line 1, Line 2, and Line 3, if you enter the macro exactly as shown here, but you can change the macro to insert some more useful text. This is an actual situation that comes up a lot, you have to insert the same block of lines into a number ofl source members. You can modify the macro to insert four or five lines, as an exercise, and supply some better lines – insert a new JCL step into a JOB, for example, or just insert a block of comments. Here's the basic example:
ISREDIT MACRO NOPROCESS
ISREDIT (ROW,COL) = CURSOR
ISREDIT (LINE) = LINENUM .ZCSR
SET &LINE = &LINE + 0
ISREDIT LINE_AFTER &LINE = +
'Line 3 '
ISREDIT LINE_AFTER &LINE = +
'Line 2 '
ISREDIT LINE_AFTER &LINE = +
'Line 1 '
For a more elaborate version of this same idea, with error handling, see the IBM sample edit macro ISRBOX, which draws a little comment box at the place where it finds the cursor when you press enter, with attention to the column as well as the row; it even places the cursor inside the added comment box for you. (ISRBOX in Edit-related sample macros in the Links to IBM Documentation at the end of this article).
Want yet more sample edit macros? If you remember TSO ISRDDN, enter TSO ISRDDN on any ISPF command line and look for ddname SYSPROC. In the command entry 1-byte field, next to the first dataset on SYSPROC, put a B for Browse (or an E for Edit). This should put you into Browse (or Edit) for the entire SYSPROC concatenation, which is usually several libraries. On the command line in Browse (or Edit), put in the command SRCHFOR ISREDIT and press enter. That should identify every "live" edit macro you have available. It's kind of like reading an encyclopedia, but you can copy pieces of macros to modify for slightly different uses.
Since this is just an introductory article, we’ll leave it at that for now (except for the following discussion of Initial Macros, which you don’t need if you aren’t planning to use them). Check out some of those IBM-supplied sample macros when you’ve finished playing around with modified versions of the quite simple macro examples included above.
We can’t leave the topic of ISPF edit macros without discussing Initial Macros.
Well, I can’t, because people often ask about initial macros; on the other hand, you can if you wish, because the succinct truth is that in most cases they’re probably more trouble than they’re worth — complicated and unnecessary, plus they slow you down getting into edit. Still, people seem to want to try them, until they’ve actually done so. So the remainder of this article is about initial macros, followed by any Footnotes , followed at the very end by some Links to the IBM Documentation on edit macros (which is worth looking at, even if all you want is the sample macros).
An initial macro is a macro that executes automatically whenever you go into ISPF edit AND certain conditions are met.
First, note that an initial macro runs after the data to be edited is read, but before it is displayed on the screen. This means that your initial macro cannot contain any commands that reference “display values” such as UP, Down, DISPLAY_anything, and so on, because, there being no display yet, these “display values” have no meaning yet. The IBM manual on ISPF Edit and Edit macros gives the example of a good initial macro as one containing the command CAPS ON, which would be okay because it would not depend on the display; it’s a profile setting actually.
In the simplest case, the main condition you need to keep in mind is that when you edit a dataset you are using an ISPF Edit Profile that is based on the dataset type. That particular ISPF Edit Profile needs to specify your chosen initial edit macro. If you remember the post “Profile on: ISPF Edit Profiles” (why, of course you do) then you remember that each dataset you edit has an edit profile determined by the last part of the dataset name – what would be called a “file extension” on the PC, and on the mainframe is called a “low level qualifier”, or suffix, or dataset type. So if you have one dataset named ‘userid.allround.CLIST’ and another dataset named ‘userid.batch.JCL’, they each use a different default profile (named CLIST and JCL respectively), and hence each could have a different initial macro specified (or more commonly, no initial macro).
If you want to specify an initial macro to be associated with a particular ISPF Edit Profile, first edit some dataset that uses that Edit Profile (based on the last part of the name). Enter PROFILE on the command line (and press enter) just so you can see your profile settings displayed. Next enter IMACRO whatever on the command line, replacing “whatever” with the name of the macro you want to have assigned as the initial macro. That should work, and the lines displaying your edit profile settings should show IMACRO as whatever; That is, as long as the Profile settings do not show that this edit profile is locked. In that case you want to unlock the edit profile before setting IMACRO, and then lock it again.
There are also Application-wide macros as a possibility, which will execute the same initial macro for all dataset types. You specify an application-wide macro with ZUSERMAC in your ISPF variables. The easy way to do that is to use ISPF option 7.3 and insert a line that specifies ZUSERMAC.
To insert a new variable in ISPF 7.3, type the letter i (for insert) on the far left of any line, to the left of one of the Variable names, and press enter. A blank line appears. Put the word ZUSERMAC for the Variable name, put P in the P column, leave the A column blank, and under Value you put in the name of your preferred initial macro. Save and exit. (If you want to delete it later using 7.3 again, you can use D for delete in much the same way you used I for insert.) The Application-wide macro you specified will then be executed after any site-wide initial macro (if any exists) but before any initial macro associated with your ISPF Edit Profile for the specific dataset type.
Not complex enough yet? Wait, there’s more. When something like a CLIST (or any EXEC or program) uses ISPF dialog services to invoke ispf edit, it can specify an initial macro name there too:
ISPEXEC EDIT DATASET(‘dsn(member)’) MACRO(macname)
That last bit, incidentally, can be more useful than it looks. As you may (or may not) know (or have guessed), you can run the ISPF editor from a batch job, and in that case you can specify an initial macro which is not only the initial macro, it is the only macro or anything else to happen in that edit session. But that can wait until we have a post on Running TSO in Batch jobs.
You can also specify the name of the initial macro in the INITIAL MACRO field on the edit panel, the same panel where you specify the name of the dataset you want to edit. More importantly, you can type NONE in that field to suppress the initial macro that would normally be executed for that edit profile.
That’s your introduction to ISPF edit macros. There are some Links to IBM Documentation at the very end, if you page down.
* footnote about alternatives to SYSUPROC:
SYSUPROC is not a typo for SYSPROC. Usually SYSPROC has a bunch of datasets concatenated together, and you need for those datasets to be there, or various TSO things will stop working, such as most of ISPF. The ddname SYSUPROC. with that extra U in the middle, was invented precisely so people could leave SYSPROC for the system. The U in SYSUPROC stands for User, and SYSUPROC is processed AHEAD OF anything from SYSPROC.
If you don’t want to use ddname SYSUPROC, you can concatenate your EXEC library together with the system libraries on ddname SYSPROC, but doing that yourself via an ALLOCATE in a CLIST is not as reliable, mainly because SYSPROC usually points to a whole list of library datasets, and whoever maintains your z/OS system can change the dataset names in that list anytime without telling you; If that happens then you would be left using your modified copy of the old list, and other TSO things might not work right (or at all). You can get around the outdated-list problem by using the IBM-supplied CLIST SPROC (rather than ALLOCATE) to concatenate your own CLIST library at the start of the SYSPROC concatenation (see IBM doc on the SPROC concatenation). Similarly, you might have a command called CONCAT that does much the same thing as SPROC.
For further discussion of some of the options, see the IBM Doc.
That doc also mentions a third option, ALTLIB. So, why not use ALTLIB, you might ask? After all, you can use it once you’re already in ISPF. Yeah, but it’s more complicated than it sounds; For one thing, if you issue ALTLIB while you’re in split screen mode, it will only apply to the one “screen session” where you issue it; ALTLIB allocation does not carry over to your other split screen(s). Also the allocation goes away when you exit the session where you issued ALTLIB. To see more, read “Using ALTLIB in ISPF”
On balance, allocating SYSUPROC in a Logon CLIST is the simplest thing to do, if that works for you. If that doesn’t work for you for whatever reason, try running SPROC in your Logon CLIST.
Links to IBM Documentation