A bit of a follow on to my article in July last year about checking the date of source against your program. I have a customer who for their sins continues to run a V5R4 partition, part of the reason for this is if you run ANZOBJCVN you’ll kill a small forest with the number of exceptions that get printed off!
Using the general method I mentioned in July I’ve written a program to dump the results to file rather than doing a SQL select. I now have an output file called “EXPPGMINF” (exception program information) if either there’s no match between the DSPFD and DSPOBJD, or there’s a source/program date conflict.
One quick change to the procedure as I described it last time, I’m now using type(*MBR) on the DSPFD rather than *MBRLIST. This means that instead of using MLCHGD (Last change date) I can use MBUPDD (Last source update date) which gives a more reliable result on the source itself being changed as opposed to the file/member generally. The customer in question moved servers a couple of years ago so there’s a lot of files with a change date showing the day that move happened, but checking MBUPDD gives an older date.
I can now compare this to the ANZOBJCVN results and see how many of the objects that fail to compile I have source for and how likely it is that the source is a match.
As an example, I have a library with 154 programs in it that would fail to convert where all of them I have a potential source member match but the source update date is more recent than the source date stamped in the program. As you might imagine given the age of the programs we’re dealing with CLP/RPG here rather than CLLE/RPGLE so these are all single module.
I can review the source member and look for lines with a date greater than the source date in the program, example of doing this through PDM.
I wonder how many of you were coding in 1994? I think at the time the most advanced I was doing was QBASIC on a PC DOS machine.
The problem here, as noted in my previous article, is if some awkward person has deleted a line out of the source member. So rather than tripping over the same problem again when the users come to test, I decided to take a different approach.
29/154 of those programs are CLs, this is where RTVCLSRC comes into play, for those not familiar with it the name is self-explanatory.
Screenshot from a V5R4 system, on newer releases you get some additional keywords to play with.
You tell it the program name, the source file/member to save to and cross your fingers that it works as depending on how the program was compiled it might be that you’ll be out of luck!
Example above of a developer who doesn’t like you / is protective of their code!
Now I could sit here and run the RTVCLSRC command manually for each object, but that seems like a lot of effort, particularly as I have some libraries 4x the size of my example and a couple of hundred libraries to review. So instead let’s write a program to do it for me!
This is obviously the quick and dirty version, where we’re simply running a DSPOBJD and trying RTVCLSRC for every CLP object in the library we passed in. You could make a few changes depending on the environment:
- Check CLP and CLLE objects (the IF condition) – in my example I know all the programs are old enough that I’m only going to find CLP, but on a slightly more modern application you might find both.
- Report on results – in my example above you don’t get any kind of return on how well/badly the loop did until you look in the source file and compare to how many you expected to get. You could write results into an output file, or at least return a message to the user on completion.
- Pass in an alternate library for the source – if you keep your source and programs in different libraries then you might want to pass both in. In the example above you create the source in the same library as your program.
In this example all 29 RTVCLSRC commands executed successfully, so I can now compare my retrieved source to QCLSRC (or wherever I found the original source) and decide what to do with it. If I didn’t find any source originally and RTVCLSRC worked then bonus as I can just recompile and wander off to look at the next program.
There are two approaches you could take here:
- Compare the retrieved CL to the one I already found, if the code is a line-for-line match then delete the retrieved source and recompile from the one I found earlier.
- If you’re feeling lazy, as I often am, recompile from the retrieved source. End result is the same but a little less elegant, particularly if you choose to keep both the old & new source member it can get a tad messy.
Using this approach, I’m knocking a few hundred objects off of my exception report across the partition (344 at time of writing, 373 once I’ve reviewed the library I’m using as an example here, 185 of which I had no source for before running RTVCLSRC.)
I said at the beginning of the article that it’s the customers sins that brought me to this point, given the amount of time/effort I’m putting in perhaps it’s more appropriate to say they’re my own….if only I knew what the sins were, answers in the comments? 😉