Old dogs, new tricks, ISPF compare

When looking for a comparison facility for Unix files, I stumbled across ISPF edit compare function.

If you are editing a file you can use the compare * command to show the changes you made to the file in the current session. This gave me

000001 line 1
====== line 3
.OAAAA line 2
.OAAAB line 4
.OAAAC line 5

Where

  • line 1 was unchanged
  • line 3 was deleted
  • line 2,4,5 were added

You can use the compare command, and be prompted for options.
I specified a Unix file, and could see the differences.

You can set the exclude option (at the bottom of the panel), which says exclude all the lines, but display ‘n’ lines around changes, where ‘n’ is specified at the top of the panel.

One funny….

I noticed that compare was display “blank” lines in Unix files as being changed. The original file had a null line, with just an end of line. When I customised the file and saved it, ISPF replaces an “end of line” with “blank end of line”. As these do not match, they show up as being changed.

The solution is to edit the original file with null lines, make a dummy change, and save the file. The file will no longer have null lines, and only your changes will be visible.

The power of exclude in ISPF edit

I hope most people know about the ISPF edit exclude facility.  You can issue commands like

X ALL /* exclude every thing */
F XXXX ALL
F YYYYY ALL WORD
DELETE ALL X /* delete everything which is excluded */
RESET
X ALL
F ZZZZ all
F AAAA all
FLIP /* make the excluded visible, and the displayed hidden */
CHANGE 'ABC' 'ZYX' ALL NX /* do not change hidden lines */

You can also exploit this in macros.  See ISREDIT XSTATUS.

/* rexx */ 
ADDRESS ISPEXEC
'ISREDIT MACRO'
"ISREDIT EXCLUDE 'AAA' ALL PREFIX" /* just like the command*/
"ISREDIT LOCATE .ZLAST" /* go to the last line */
"ISREDIT (r,c) = CURSOR" /* get the row and column number */
/* r has the row number of the last line */
do i = 1 to r
"ISREDIT (xnx) = XSTATUS "i
say "Line exclude status is" i xnx
"ISREDIT (line) = LINE " i /* extract the line */
if (...) then
"ISREDIT XSTATUS "i" = X" /* exclude it */
end

You can also see if a line has been changed this edit session:

"ISREDIT (status) = LINE_STATUS "i /* for line i */
if (substr(status,8,1) = '1') then
say "Line" i " was changed this session "

 

 

How to capture TSO command output into an ISPF edit session

One way of doing this, is to run a TSO command in batch, use SDSF to look at the output, and then use SE to edit the spool file.

This was too boring, so I wrote a quick macro ETSO

/* REXX /  parse source p1 p2 p3 p4 p5 p6 p7 env p9  
if env = "ISPF" then  
do    
  ADDRESS ISPEXEC    
  "ISREDIT MACRO (cmd ,REST)"  
end  
else  
do
    Say "This has to run from an ISPF edit session " 
   return 8;  
end  
/* prevent auto save … user has to explicitly save or cancel*/  
"ISREDIT autoSave off prompt"  
x = OUTTRAP('VAR.')  
address tso   cmd rest  
y = OUTTRAP('OFF')  
/* insert each record in turn last to first at the top of the file */ 
do i = var.0 to 1 by -1 
  "ISREDIT LINE_AFTER 0  = '"var.i"'" 
end 
exit

This macro needs to go into a dataset in SYSEXEC or SYSPROC concatenation – See TSO ISRDDN. I typed etso LU in an edit session, and it inserted the output of the TSO LU the top of the file.

For capturing long lines of output, you’ll need to be in a file with a long record length.

Neat!

To create a temporary dataset to run the above command I created another rexx called TEMPDSN

/* REXX */
parse source p1 p2 p3 p4 p5 p6 p7 env p9
if env = "ISPF" then
do
  ADDRESS ISPEXEC
  "ISREDIT MACRO (cmd ,REST)"
end
else
do
  Say "This has to run from an ISPF session "
  return 8;
end
u = userid()
address TSO "ALLOC DSN('"u".temptemp') space(1,1) tracks NEW DELETE ",
"BLKSIZE(1330) LRECL(133) recfm(F B) DDNAME(MYDD)"
if (rc <> 0) then exit
address ISPEXEC "EDIT DATASET('"u".temptemp')"
address TSO "FREE DDNAME(MYDD)"

You can then do even cleverer things by having TEMPDSN calling ETSO as a macro, and passing parameters using the ISPF variable support from the TSO command line.

Updated TEMPDSN, changes in bold.

/* REXX */ 
parse source p1 p2 p3 p4 p5 p6 p7 env p9
say "env" env
if env = "ISPF" then
do
ADDRESS ISPEXEC
"ISREDIT MACRO (cmd ,REST)"
end
else
do
Say "This has to run from an ISPF session "
return 8;
end
tempargs = ""
/* if we were passed any parameters */

parse arg args
if ( length(args) > 0) then
do
tempargs = args
"VPUT tempargs profile"
end

u = userid()
address TSO "ALLOC DSN('"u".temptemp') space(1,1) tracks NEW DELETE ",
"BLKSIZE(1330) LRECL(133) recfm(F B) DDNAME(MYDD)"
if (rc <> 0) then exit
address ISPEXEC "EDIT DATASET('"u".temptemp') MACRO(ETSO)"
address TSO "FREE DDNAME(MYDD)"

if ( length(tempargs) > 0) then
do
"VERASE tempargs profile"
end

and the macro ETSO has

/* REXX */ 
parse source p1 p2 p3 p4 p5 p6 p7 env p9
if env = "ISPF" then
do
ADDRESS ISPEXEC
"ISREDIT MACRO (cmd ,REST)"
end
else
do
Say "This has to run from an ISPF edit session "
return 8;
end
/* prevent auto save ... user has to explicitly save or cancel*/
"ISREDIT autoSave off prompt"
if (length(cmd) = 0) then
do
"VGET tempargs " PROFILE
if (rc = 0) then
cmd = tempargs
end
x = OUTTRAP('VAR.')
address tso cmd rest
y = OUTTRAP('OFF')
/* insert each record at the top of the file */
do i = var.0 to 1 by -1
"ISREDIT LINE_AFTER 0 = '"var.i"'"
end
EXIT

From ISPF 6, a TSO command line, I issued tempdsn racdcert list certauth  and it gave me the file with the output from the command, and the file has record length of 133.  If you try to  save the data,  the data set will be deleted on close.

 

 

How do I do things with a subset of PDS members matching a pattern?

There are some clever things you can do on a subset of members of a PDS.

If you use ISPF  (Browse) or ISPF 2 (Edit) you can specify a data set name of

  • ‘COLIN.AAA.PROCLIB(%%%%%%00)’ and it displays only the members ending in 00.
  • ‘COLIN.AAA.PROCLIB(*AH*)’ to display all member with an AH in the name.
  • ‘COLIN.AAA.PROCLIB’  for all of the members.

If you use ISPF 3;4 I havent found a way of doing the same.

Acting on a subset.

If you have a list of members, for example ISPF 1,2,3;4  you can issue a primary command

sel *99 e 

which says select all those members ending in  99, and use the command “e” in front.  Similary  sel %%%%%%00 b.

Sorting the list

You can sort the list by many fields, name, size last changed.  For example “Sort Name”.

I have “Tab to point-and-shoot fields” enabled.   I can tab to column headers, and press enter.   The rows are sorted by this column.

I often use “sort changed” to find the ones I changed recently, and “sort id” to see who else has been changing the members.

Srchfor

I use “srchfor ” or “srchfor value” to look for the members containing a string (or two).

When this command has completed tab to “prompt” and press enter, or enter “sort prompt” to sort the members with hit to the top of the list.

Refresh

If the member list has changed, you can use “refresh” to refresh it.