Home > Mainframe > Backup a bit…

Backup a bit…

About a million years ago, actually 1976, I started in the computer industry as an operator. My job interview was with the managing director of the ‘computer department’ because it wasn’t ‘Information Technology’ yet! One thing that I have always remembered from that interview is him saying that I shouldn’t worry about making mistakes because it can always be fixed. I think he probably said it as much to reassure my novice self as anything else, but it always stuck with me.

And for the most part, he was right. But I have to qualify the general statement by saying that fixing it is a lot easier if you’ve got a backup of everything!

This comes to mind because a backup saved my bacon a few days ago.

I’ve been working on a little side project for a good while now, just a fun little thing I’ve been playing around with and while it’s not a lot of code as such, it is pretty involved. Now I still work quite a bit on a good old green screen in ISPF where I tend to use the 3.4 data set list option because I can easily switch from browse of a member to edit and back without having to switch ISPF screens.

The one thing I have never liked about the data set list function and the resultant member list display for a data set though, is that you can easily enter a D (for delete!) against either a data set or member. While it does prompt you to confirm the action (unless you’ve turned it off) it is pretty easy to be not paying attention, press enter on the confirm screen and it’s gone.

At this point you go ‘Oh F***k’ or words to that effect.

I know this because that’s exactly what happened to me the other day. Not paying attention, something popped up, I hit enter and it was only when the word ‘deleted’ appeared beside the member name that I realized I’d screwed up!

 

Now I’ve been working on this project for a while. In fact I last touched it a few years ago, got to a ‘sticky’ point where the coding was neither fun nor easy and put it aside until recently when I decided to pick it up again.

In all that time I kept thinking I really should start taking backups of the work. Fortunately for me, that’s exactly what I had done the previous day. I spent some time to write some jobs to back everything up so when I screwed up, thankfully I had a backup that I was able to restore the missing member from.

Had this happened a day earlier and it would have been a whole different story.

An after effect of this is that I wrote my own little data set list function that does NOT allow me to do a delete either against the data set or a data set member. Again, this was something I’ve often thought about, just never gotten around to until this happened and I got ‘motivated’ as it were.

My ISPF 3.4 alternative can be down loaded from ===> here. <===

Unzip the file and upload the exec and panel to your ISPF REXX and ISPPLIB panel library using a text transfer to convert back to EBCDIC. Edit the exec to specify the name of the panel library or remove the LIBDEFs for the panel library if it is already allocated to your ISPF ISPPLIB DD.

Then just run the exec, @34. It takes two parameters:

  • A mask to specify the datasets to list, just like the real 3.4
  • One or more exclude strings. Any data set name in the result list that matches one of these strings will not be show.

Line commands against data sets are:

  • B or S – Browse
  • E – Edit
  • Z – Compress

Line commands against a member in a member list are:

  • S – Whatever what entered against the data set, E or B.
  • E – Edit
  • B – Browse
  • SUB – Submit the member
  • =  Repeat the previous command

 

It’s very basic. A lot of the error messages are just issued as say statements. If you use it, feel free to modify it to your needs.

This is the exec source:

/* rexx */
/* Custom ISPF 3.4 function */
/* pfx is dataset prefix to list */
/* excl is one or more exclude masks */
/* David E Ellis April 2020 */

parse arg pfx excl
if pfx = '' then pfx = sysvar(syspref)

address ISPEXEC

/* "CONTROL ERRORS RETURN"*/

"LIBDEF ISPPLIB DATASET ID('DAVE.ISPPLIB')"

"TBCREATE @34 NAMES(DSNAME DSTYPE) NOWRITE"
if rc <> 0 then do
say "TBCREATE RC="rc
signal exit
end

rc=Build_list(pfx)
if rc <> 0 then signal exit

do forever
'TBTOP @34'
'TBDISPL @34 PANEL(@34)' ,
'AUTOSEL(NO)' ,
'ROWID(ROW)'

if rc > 7 then leave

'TBQUERY @34 POSITION(row)'
if row = 0 then row=1

do ztdsels

if sel <> '' then do
upper sel
select
when sel='S' then do
rc=doit('B') /* default */
end
when sel='B' then do
rc=doit('B')
end
when sel='E' then do
rc=doit('E')
end
when sel='Z' then do
rc=compress(dsname,dstype)
end
otherwise do
zerrsm = 'Invalid option'
zerrlm = 'Invalid option for this line'
zerralrm = 'NO'
'SETMSG MSG(ISRZ002)'
end
sel=''
end

end /* if sel <> '' */

if ztdsels = 1 then iterate
'TBDISPL @34'

end /* do ztdsels */

end

/*----------------------------------------------------*/
exit:
"CONTROL ERRORS RETURN"
"TBEND @34"
"LIBDEF ISPPLIB"
return 0

/*----------------------------------------------------*/
Build_list:
parse arg pfx
myrc=0

"LMDINIT LISTID(DSID) LEVEL("pfx")"
if rc <> 0 then do
say "LMDINIT RC="rc
myrc=4
signal Build_list_exit
end

DSN = ''
do forever
"LMDLIST LISTID("dsid") OPTION(LIST) DATASET(DSN)" ,
"STATS(YES)"
if rc = 4 then do
say 'Nothing found for 'pfx
myrc=4
leave
end
else
if rc = 8 then leave /* end of list */
else
if rc <> 0 then do
say "LMDLIST RC="rc
myrc=4
leave
end

exclrc=0 /* RC=0 means do NOT exclude */
if excl<>'' then do
exclrc=CheckExcl(dsn,excl)
end
if exclrc=0 then do
dsname=dsn
dstype=zdldsntp
"TBADD @34"
end
end

Build_list_exit:
"LMDLIST LISTID("dsid") OPTION(FREE)"
"LMDFREE LISTID("dsid")"
return myrc

/*----------------------------------------------------*/
doit:
myrc=0
parse arg option

if strip(dstype) = "" then do /* unknow org, let ispf handle */
option" DATASET('"dsname"')"
signal doit_exit
end
else
myrc=mlist(option)

doit_exit:
return myrc

/*----------------------------------------------------*/
mlist:
myrc=0
parse arg mlistopt
/* mlistopt just controls default action if S entered for mbr */

"LMINIT DATAID(MLID) DATASET('"dsname"') ENQ(SHR)"
if rc<>0 then do
say "LMINIT Rc="rc
say ZERRLM
myrc=4
signal mlist_exit
end

"LMOPEN DATAID("mlid") OPTION(INPUT)"
if rc<>0 then do
say "LMOPEN Rc="rc
myrc=4
signal mlist_exit
end

mbr=""
do forever

prevcmd=""

"LMMDISP DATAID("mlid") OPTION (DISPLAY) COMMANDS(ANY)" ,
"TOP("mbr") FIELD(9)"
if rc=0 then nop
else
if rc=4 then do
say " Empty dataset"
leave
end
else
if rc=8 then leave
else do
say "LMMDISP DISPLAY RC="rc
say ZERRLM
leave
end

mbr=strip(zlmember)
rc=procmbr(mbr,zllcmd)

do forever
"LMMDISP DATAID("mlid") OPTION(GET)"
getrc=rc
if getrc=0 then nop
else
if getrc=8 then leave
else do
say "LMMDISP GET RC="getrc
say ZERRLM
leave
end
mbr=strip(zlmember)
rc=procmbr(mbr,zllcmd)
end

"LMMDISP DATAID("mlid") OPTION(FREE)"

end

mlist_exit:
"CONTROL ERRORS RETURN"
"LMCLOSE DATAID("mlid")"
"LMFREE DATAID("mlid")"
return myrc

/*----------------------------------------------------*/
procmbr: Procedure Expose mlistopt dsname prevcmd
myrc=0
parse arg mbr,cmd

if cmd = "S" then do
prevcmd=mlistopt
myrc=procmbr(mbr,mlistopt)
end
else
if cmd = "B" then do
prevcmd="B"
"BROWSE DATASET('"dsname"("mbr")')"
end
else
if cmd = "E" then do
prevcmd="E"
"EDIT DATASET('"dsname"("mbr")')"
end
else
if cmd = "SUB" then do
prevcmd="SUB"
address TSO "SUBMIT ('"dsname"("mbr")')"
end
else
if cmd = "=" then do
myrc=procmbr(mbr,prevcmd)
end
else do
prevcmd=cmd
say "Invalid command "cmd
end

return 0

/*----------------------------------------------------*/
CheckExcl: Procedure
/* If any of the string in excl are in the dsn return rc=4 */
/* else returns rc=0 (excl strigs NOT in dsn) */

parse arg dsn , excl
upper dsn
upper excl

do i = 1 to words(excl)
if pos(word(excl,i),dsn) > 0 then return 4
end

return 0

/*----------------------------------------------------*/
compress: Procedure
parse arg dsname, dstype

if dstype <> 'PDS' then do
say 'Invalid dataset type'
signal compress_exit
end

"LMINIT DATAID(LMIID) DATASET('"dsname"') ENQ(EXCLU)"
if rc <> 0 then do
say "LMINIT RC="rc
say ZERRLM
signal compress_exit
end

"LMCOMP DATAID("lmiid")"
if rc=0 then do
say "Compressed"
end
else do
say "LMCOMP RC="rc
say ZERRLM
end

"LMFREE DATAID("lmiid")"

compress_exit:
return 0

 

And this is the panel definition:

)PANEL KEYLIST(ISRSPBC,ISR)
)ATTR
@ TYPE(OUTPUT) INTENS(LOW) COLOR(YELLOW)
)BODY EXPAND(//)
%--/-/-- Dataset List --/-/--
%Command ==> _ZCMD / / +Scroll ===>_ZAMT+

+DSLIST - Data Sets Matching@Z +

)MODEL
_Z+ @Z +
)INIT
.ZVARS = '(PFX SEL DSNAME)'
&zamt=csr
&zcmd=''
&sel=''
.HELP=ISR00003

)REINIT
IF (.MSG = ' ')
&SEL = ' '
REFRESH (SEL)

)PROC
IF (&ZTDSELS ^= 0000)
VER (&SEL, LIST, B, b, E , e , S , s, Z, z)

)END

 

 

 

 

 

Categories: Mainframe
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: