Wow3 ISPF cut and paste can do so much more

You can use the ISPF cut command

EDIT       COLIN.PDSE2(AA) - 01.07
Command ===> cut
****** ********************************* Top of D
000100 ddd
000200 bbbb
cc0300 44444
000400 5555
cc0500 666
000600 777

and this copies the lines into a working area, then use the paste command to insert the text, in the same or a different file.

What is in the clipboard?

The command cut display gave me

┌────────────────────────────────────────────────────────────────┐
│ Clipboard manager │
│ │
│ B - Browse C - Clear O - Toggle Read-only │
│ E - Edit R - Rename D - Delete │
│ │
│ Name Lines User Comment │
│ │
│ _ DEFAULT 3 ISPF Default Clipboard │
│ │

You can now enter B into the line command before DEFAULT to display the contents. This gave me

 BROWSE    CLIPBOARD:DEFAULT
Command ===>
********************************
44444
5555
666

Multiple clipboards

The command cut AAAA followed by CUT DISPLAY showed all the clipboards I have. This shows the clip board AAA I just created

 ┌────────────────────────────────────────────────────────────────┐
│ Clipboard manager │
│ │
│ B - Browse C - Clear O - Toggle Read-only │
│ E - Edit R - Rename D - Delete │
│ │
│ Name Lines User Comment │
│ │
│ _ DEFAULT 3 ISPF Default Clipboard │
│ _ AAA 2 │
│ │

You can have up to 11 clip boards.

Other clever things

  • You can append or replace the data.
  • You can have the data converted to ASCII, EBCDIC or UTF8 as part of the copy.
  • You can select eXcluded or Not eXcluded (x or NX) lines.

Paste

You can use the PASTE , or the PASTE AA command to put the value from the specified (or defaulted) clipboard into your data.

You could use

paste AA After .zlast

to paste the data after the end of the file.

How do I change all members of a PDS? Easy – use an edit macro

I looked on the internet, to find something that would allow me to make the same change to all members of a PDS, and there seemed to be several options, IPOUPDTE, CPPUPDTE, PDSUPDTE, written in assembler many years ago.

I had written an equivalent program in C, but I no longer have the source. I found it as quick to write a solution using Rexx and an ISPF edit, than to find a solution on the internet. The solution is much more flexible, and can do so much more.

The processing has two stages

  • Code to iterate over each member of the PDS, and invoke ISPF EDIT on each member
  • An edit macro to make the changes.

Code to iterate over each member

ISPF 3.4 DSLIST displays data sets

DSLIST - Data Sets Matching COLIN.J*       
Command ===>

Command - Enter "/" to select action
-------------------------------------------
AA COLIN.JCL
COLIN.JCL.DCOLLECT.OUTPUT

You can enter local commands at the front of each line. The commands can be ISPF special (D for Delete, C for Catalog, R for Rename), or TSO commands, where a TSO command can be a Rexx exec in the ISPEXEC concatenation. (You can use the TSO ISRDDN command to display the data sets allocated to your session)

I have a Rexx exec called AA.

Access the parameters passed to the rexx

/* rexx */                                           
ADDRESS ISPEXEC "VGET (ZDLDSN) SHARED"
ADDRESS ISPEXEC "VGET (ZDLCMD) SHARED"
ADDRESS ISPEXEC "VGET (ZDLLCMD) SHARED"
say "ZDLDSN " ZDLDSN
say "ZDLCMD " ZDLCMD
say "ZDLLCMD " ZDLLCMD

With the line command

Command - Enter "/" to select action  
--------------------------------------
AA 99 COLIN.JCL

The Rexx produces

ZDLDSN    COLIN.JCL
ZDLCMD AA 99
ZDLLCMD AA 99 'COLIN.JCL'
  • ZDLDSN is the data set name
  • ZDLCMD is the line command and any data
  • ZDLLCMD is the (Long) combined command and the data set

With the line command

aa 99 / Zyx

The dataset name is substituted for /, and the output is

ZDLDSN    COLIN.JCL
ZDLCMD AA 99 / Z
ZDLLCMD AA 99 'COLIN.JCL' Zyx

This means you can pass parameters to your Rexx.

Process every member

The data set name is in variable ZDLDSN. When you use it, you should quote it because your userid may/may not have prefix on, which puts your userid on the front of every data set you use. Without quotes, it could not find dataset COLIN.COLIN.JCL

  • The LMINIT command returns a handle in the DATAID(handle) variable, to refer to the data set. My handle is called data1.
  • The LMOPEN command opens the dataset associated with the handle.
  • The LMMLIST command iterates through the list, starting with a blank member name which indicates start with the first.
  • The EDIT command invokes ISPF edit on the member, and passes the name of an ISPF EDIT macro to use. In my case the macro is called FOREACH.
Address ispexec "LMINIT DATAID(data1) dataset('"ZDLDSN"')" 
if rc <> 0 then
do /* report the errors */
say ZERRSM ZERRLM
return 8
end
Address ispexec 'LMOPEN DATAID('data1') OPTION(INPUT)'
member = ' '
lmrc = 0
/*********************************************************************/
/* Loop through all members in the PDS, issuing the EDIT service for */
/* each. */
/*********************************************************************/
Do i = 1 by 1
Address ispexec 'LMMLIST DATAID('data1') OPTION(LIST),
MEMBER(MEMBER) STATS(NO)'
If rc = 8 then leave /* not found */
If rc <> 0 Then
do
say ZERRSM ZERRLM
leave
end
else
do
Address ispexec 'EDIT DATAID('data1') MEMBER('member')
MACRO(FOREACH)'
end
End
/*********************************************************************/
/* Free the member list and close the dataid for the PDS. */
/*********************************************************************/
Address ispexec 'LMMLIST DATAID('data1') OPTION(FREE)'
Address ispexec 'LMCLOSE DATAID('data1')'
Exit 0

From the information passed to the Rexx exec, you could pass the edit macro as a parameter, such as

AA / MYMAC 

I was just lazy and hard coded the macro name.

An edit macro to make the changes

My basic macro just reports the member name, and the size of the file

ADDRESS ISPEXEC 'ISREDIT MACRO' 
"ISREDIT (last) = LINENUM .ZLAST"
"ISREDIT (member ) = MEMBER"
"ISREDIT (curr,orig,concat)= DATASET"
say "foreach " member last curr
"ISREDIT END"
  • The LINENUM command returns the line number of the specified line. You can create your own line labels. ISPF provides .ZFIRST and .ZLAST .ZCSR (the line where the cursor is currently.
  • The MEMBER command returns the member name
  • The DATASET command returns the current name of the dataset (and other information)

You can now do conditional processing, if the data set name starts with… then change…; if the member name starts with… then change…

You can use standard ISPF commands for example

/* */ 
/* trace e */
ADDRESS ISPEXEC 'ISREDIT MACRO'

"ISREDIT X ALL "
"ISREDIT FIND '//' ALL"
"ISREDIT CHANGE 'IBMUSER' 'COLIN' 1 10 ALL NX"
return
"ISREDIT END"

Without the return statement in the code, the code makes the changes and exits, it invisibly edits all of the members. With the return statement this gives you the opportunity to review the changes and to use end or cancel to leave the edit session.

Whoops – what happened there

To test the macros I use ‘view’ of the member, to edit it, but not save any changes. I then executed the macro.
I was trying to change a VOLSER to a symbol.

/* */ 
ADDRESS ISPEXEC 'ISREDIT MACRO'
"ISREDIT (member ) = MEMBER"
say member
"ISREDIT SCAN OFF"
if substr(member,1,6) <> "IEASYM" then
do
"ISREDIT CHANGE 'A3PRD1' '&&SYSP1.' ALL "
"ISREDIT CHANGE 'A3PRD2' '&&SYSP2.' ALL "
"ISREDIT CHANGE 'A3PRD3' '&&SYSP3.' ALL "
"ISREDIT CHANGE 'A3PRD4' '&&SYSP4.' ALL "
"ISREDIT CHANGE 'A3PRD5' '&&SYSP5.' ALL "
"ISREDIT CHANGE 'A3RES2' '&&SYSR2.' ALL "
"ISREDIT CHANGE 'A3SYS1' '&&SYSS1.' ALL "
"ISREDIT CHANGE 'A3CFG1' '&&SYSC1.' ALL "
end
return
"ISREDIT END"f

I wanted to change A3PRD1 to the symbol &SYSP1. I had use use &&, and SCAN OFF. Without these, ISPF treats &SYSP1 as an ISPF symbol, cannot find it, so replaces it with a null.

What is my ISPF screen size and other attributes?

I was trying to use a very large screen in ISPF, but I could only get 132 * 43.
You can display information about your screen using

  • ISPF option 0 Settings
  • top line, tab to environ
  • option 1 Environ settings…
  • tab down to Terminal Status (TERMSTAT)
  • option 2 Query terminal information

If gives information like

ISPF TERMINAL CHARACTERISTICS
14 BIT ADDRESSING = ON
16 BIT ADDRESSING = OFF
EXTENDED COLOR = ON
EXTENDED HIGHLITING = ON
DBCS = OFF
PRIMARY SCREEN SIZE - PARTITIONED MODE
SCREEN SIZE = 1,920 - x'00000780'
SCREEN DEPTH = 24 - x'00000018'
SCREEN WIDTH = 80 - x'00000050'

ALTERNATE SCREEN SIZE - PARTITIONED MODE
SCREEN SIZE = 3,564 - x'00000DEC'
SCREEN DEPTH = 27 - x'0000001B'
SCREEN WIDTH = 132 - x'00000084'

PARTITION SCREEN SIZE - PARTITIONED MODE
SCREEN SIZE = 0 - x'00000000'
SCREEN DEPTH = 0 - x'00000000'
SCREEN WIDTH = 0 - x'00000000'
PRIMARY SCREEN SIZE - NON-PARTITIONED MODE
SCREEN SIZE = 1,920 - x'00000780'
SCREEN DEPTH = 24 - x'00000018'
SCREEN WIDTH = 80 - x'00000050'
ALTERNATE SCREEN SIZE - NON-PARTITIONED MODE
SCREEN SIZE = 3,564 - x'00000DEC'
SCREEN DEPTH = 27 - x'0000001B'
SCREEN WIDTH = 132 - x'00000084'
ISPF TERMINAL BUFFER INFORMATION
TERMINAL BUFFER ADDR = x'000326A8'
TERMINAL BUFFER SIZE = 4,989 - x'0000137D'
PHYSICAL SCREEN SIZE = 3,564 - x'00000DEC'
PARTITION ARRAY ADDR = x'0001DAA0'
GTTERM INFORMATION
RETURN CODE = x'00000000'
PRIMARY ROW = 24 - x'00000018'
PRIMARY COL = 80 - x'00000050'
ALTERNATE ROW = 27 - x'0000001B'
ALTERNATE COL = 132 - x'00000084'
ATTRIBUTE BYTE = x'000000C9'
EBCDIC TERMINAL
EDS TERMINAL
GTSIZE INFORMATION
RETURN CODE = x'00000000'
ROWS = 27 - x'0000001B'
COLUMNS = 132 - x'00000084'

VTAM ACCESS METHOD

All the information says the screen is 27 rows and 132 columns.

Customising ISPF appearance

Screen size: using bigger screens.

  • Use x3270 -model 3279-5-E   to get 132*27 screen size.  It works for the console and ISPF terminal.
  • I could not get the -oversize 160*45 working. When I edited the .3270.pro file and added x3270.oversize: 160×45 it worked.
  • Logon and use ISPF =0  to set defaults.  Scroll down
    • To have command line at the top / Command line at bottom  remove the /
    •  Scroll down.  Screen format 3 1. Data 2. Std 3. Max 4. Part
    • Terminal Type 4 1. 3277 2. 3277A 3. 3278 4. 3278A though I think this field is ignored.

Other ISPF personalisation

  • Options
    _ Command line at bottom  remove the / to have the command line at the top
    / Tab to point-and-shoot fields so you can tap to column headers, press enter and sort by the column
  • Member list options
    / Scroll member list
    / Allow empty member list
    / Allow empty member list (nomatch)
    / Empty member list for edit only
  • pfshow off remove the PFKEYS at the bottom
  • ISPF  keys set PF12 to retrieve not cancel
  • ISPF set scroll to CSR not PAGE. You will need to do this in all applications
  • ISPF 3.4 use reflists list of the last 30 data sets used, or your own list
  • Setting the ISPF main panel.
    • Copy ADCD.Z24A.ISPPLIB(ISR@PRIM)  to USER.Z24A.ISPPLIB(MYMAIN).
    • Add extra content and comparisons at the bottom for example ISMF,’PGM(DGTFMD01) NEWAPPL(DGT)’ .
    • The following are already defined
      •  RACF,’PANEL(ICHP00)’
      • ISMF,’PGM(DGTFMD01) NEWAPPL(DGT)’
      • SMPE,’PGM(GIMSTART) PARM(&ZCMD) NOCHECK’
      • WLM,’CMD(%IWMARIN0)’
    • When you use the TSO Logon panel specify Command ===> ispf panel(MYMAIN)  

Can I easily make an ISPF edit line command macro?

The key word in the title is easily. If you search for “Working with an edit line command table”, the documentation gives you instructions on how to create a table, then add your definition, create your macro, and then use it. When you were expecting to do this invisibly for the end user, it is a lot of work.

A command line rexx program can process line commands. I created a command line program so when I use it, and use S or SS..SS line commands, the macro can extract the tagged lines, and so do things with the tagged data.

The command line Rexx

/* REXX */ 
address isredit
'MACRO (a) NOPROCESS '
'process range S '
IF RC = 0
THEN DO
"(first) = LINENUM .ZFRANGE"
"(last) = LINENUM .ZLRANGE"
data = ""
/* build up a long string from the tagged lines */
do i = first to last
"(l) = LINE (i)"
data = data || strip(l) || " "
end
l = data
address ispexec "edit dataset('COLIN.$$TEMP$$') macro(l2) parm(l)"
END

Where the lines of interest are

  • ‘MACRO (a) NOPROCESS ‘
    • Usually when a command line macro is processed, ISPF processes any outstanding line commands (such as D) before processing any commands in the rexx exec. The NOPROCESS says – hold off doing this until instructed.
    • a is the data passed in
  • ‘process range S ‘
    • This locates any line commands beginning with S, for a single line, or SS…SS for multiple lins.
  • if rc = 0 then do
  • “(first) = LINENUM .ZFRANGE”
    • get the line number of the First in the RANGE
  • “(last) = LINENUM .ZLRANGE”
    • get the line number of the Last in the Range.
  • data = “”
  • do i = first to last /* process the data build up the string */
    • “(l) = LINE (i)”
    • data = data || strip(l) || ” “
  • end
  • ldata = data
  • address ispexec “edit dataset(‘COLIN.$$TEMP$$’) macro(l2) parm(ldata)”
    • Invoke edit on a file – invoke macro l2, and pass the data in the rexx variable ldata
  • END

If the “process range” gives a non zero return code, set an error message

else do 
zedsmsg = 'You need to specify line prefix s|ss ss'
zedlmsg = 'You need to specify line prefix s|ss ss long message'
address ispexec 'SETMSG MSG(ISRZ001)'
end

This sets a Short message (zedSmsg) which is display at the top right of the display, and a long message (zedLmsg) if the user presses PF1 on the short message.

Macro L2

This macro is processed when the edit dataset(..) macro(l2) command is issued

/* REXX */ 
address isredit
'MACRO (a) '

say "Passed data" a
...

Old dogs, new tricks: ISPF cut and paste

I had many members with RACF commands within JCL, and wanted to rationalise them so the definitions were in a couple of files, one for userid information, one for define commands, one for permits etc.. I remembered someone once talking about ISPF cut and paste, and this proved to be very useful.

I had a member with

//S1  EXEC PGM=IKJEFT01,REGION=0M 
//* EPLIB DD DISP=SHR,DSN=SYS1.MIGLIB
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *,SYMBOLS=(JCLONLY)
SETROPTS GENERIC(MFADEF) GENCMD(MFADEF)
RDEF MFADEF FACTOR.AZFSTC OWNER(IBMUSER)
SETROPTS RACLIST(MFADEF) CLASSACT(MFADEF)

/*
/*

and wanted to copy the bold text from each file into other files.

Cut

I used the edit command cut .a .b define append with

000007 //SYSTSIN DD *,SYMBOLS=(JCLONLY) 
.a0008 SETROPTS GENERIC(MFADEF) GENCMD(MFADEF)
000009 RDEF MFADEF FACTOR.AZFSTC OWNER(IBMUSER)
.b0010 SETROPTS RACLIST(MFADEF) CLASSACT(MFADEF)
000011 /*

this copied the three lines into a clipboard called define.

You can also use the line commands cc..cc and mm..mm.

For a different file I used CUT add append

000006 //SYSTSIN DD * 
cc ADDUSER AZFSTC DFLTGRP(SYS1) OWNER(SYS1) -
000008 OMVS(AUTOUID) -
000009 NAME('MFA STC') -
000010 NOPASSWORD NOOIDCARD -
cc RESTRICTED
/*

and so on for each file.

If you use the line commands mm … mm it will delete it from the current file after the data has been copied to the clip board.

With PF12 set to retrieve it was easy to recall the cut command in each member.

Paste

After I had finished cutting the text I edited a member ADD and used the paste command. The basic syntax is paste clipboard

Command ===> paste add
A ********************************* Top of Data ***...
****** ******************************** Bottom of Data *...

This takes all the data from the “add” clipboard, and puts it >A<fter the top line. Similarly I edited the DEFS file, and used the “paste defs” command to retrieve the data in the clipboard.

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.

 

 

How do I compare the directories of two PDS(E)s?

I wanted to compare  two directories to find the differences.   I could see that the number of members was different, but it was hard to see what was missing.

I browsed the web, and found that this was a commonly asked question, and often the solution was to write some Rexx and use the ISPF LM* functions.  I felt this was the wrong way.  

I had used Superc to compare members of different files – could it tell me same information about the member list – yes!

SuperC has different compare types

  1. File –  Compares source data sets for differences, but does not show what
    the differences are.
  2. Line – Compares source data sets for line differences.  It is record-oriented and points out inserted or deleted lines.
  3. Word – Compares source data sets for word differences.  If two data sets contain the same words in the same order, SuperC considers them to be identical, even if those words are not
    on the same lines.
  4. Byte – Compares source data sets for byte differences.  This compare type is most useful for comparing  machine readable data.

Example output of the File comparison type.

NEW: COLIN.ZZZ.PROCLIB  OLD: HLQ.Y.ABCNPARU                                                                                     
MEMBER SUMMARY LISTING (FILE COMPARE)                                                                                     
DIFF SAME MEMBERS   N-BYTES O-BYTES N-LINES O-LINES  HASH1 HASH2 
                                                                                     
 **       ABC11111   171120  173200    2139    2165  78D5C 1113D
      **  ABC9999       640     640       8       8  AB58A AB58A 
     

We can see

  • ABC1111 is different because the “**” in the DIFF column, and the hash code at the right is different
  • ABC9999 is the same in each because the “**” is in the SAME column, and the hash value is the same

You also get a summary of differences

   10   TOTAL MEMBER(S) PROCESSED AS A PDS 
    1   TOTAL MEMBER(S) PROCESSED HAD CHANGES 
    9   TOTAL MEMBER(S) PROCESSED HAD NO CHANGES 
    9   TOTAL NEW FILE MEMBER(S) NOT PAIRED 
  179   TOTAL OLD FILE MEMBER(S) NOT PAIRED 

List of members not in both

MEMBER SUMMARY LISTING (FILE COMPARE)                                 
NON-PAIRED NEW FILE MEMBERS | NON-PAIRED OLD FILE MEMBERS               
     ABC$$$$$               |       ZAA$$$$ 
     ABCSCLRR               |       ZYZAPST5 
                            |       ZYZAPST6
  • Member ABC$$$$ and one other are in the “new” PDS, but not in the “old” PDS.
  • Member ZAA$$$$ and 2 others are in “old” PDS, but not in the “new” PDS.

Like most things – easy – once you know how do to it!

Using Line mode

When I used line mode I got output like

                                                  N-LN# O-LN# 
I - SYSNAME                      &SYSNAME.        00004 00003
D - SYSNAME                      S0W1 

For one member, the  “new-file” at line 4 was similar to the line in the “old-file” at line 3.

To get from the old file to the new file, delete the line with S0W1 in it and insert the line with &SYSNAME.