Dynamic FORMS for printing AFP - cobol

I am trying to print AFP to sysout but the FORMS parameter is not known (and cannot be known) by the JCL. My current solution is to create dynamic JCL and spin it to INTRDR, but this is a weak solution because the job will not be under the control of our scheduler... and thus, an abend or other issue will go unnoticed by night-time operators.
I started concocting a way to print the AFP via a COBOL program. I use BPXWDYN to create the SYSOUT DD dynamically, which allows me to set the FORMS parameter however I want. But the next step is dumping the AFP to that DD.
I thought I could call IEBGENER dynamically from my COBOL program, but that pulls a S0C4.
I can move the AFP records from one DD to the other in the COBOL program, but that limits me to one LRECL... and I have many different LRECL definitions for AFP throughout my system, and COBOL MUST know the LRECL at compile time.
Any thoughts? Is it possible to call IEBGENER dynamically and not get the S0C4? Any other ideas I haven't thought of?
Thanks in advance...

Have you thought of writing a small assembler program? You can specify the LRECL in your BPXWDYN call, and the DCB does not need to specify an LRECL; it will get it from the DCB parameters at OPEN time. A program to simulate IEBGENER is quite trivial.
Alternatively, look at calling SORT with a FIELDS=COPY parameter. SORT doesn't need the LRECL either. Or write a REXX script.
There are many ways of doing this; you just need to look outside the COBOL box.

Your question is not extremely clear but I'm wondering if you should consider using the ACIF utility program called APKACIF instead of IEBGENR. The utility will merge your data and resolve the AFP FORMDEF, PAGEDEF objects to a dataset or print stream.

Related

Is there a way to substitute a small piece of code (e.g. a statement) with a more friendly alias in Delphi 10.4?

I'm working with Delphi 10.4.
At some places of my code I have to write long identifiers on long statements (e.g. ProductsForSale.fieldByName('quantity').asInteger * ..... / .... etc.). Is there a way to assign a friendly alias (e.g. TheCost) to this piece of code to substitute it everywhere in the application?
I don't want to use a variable or a function to do this. Only text substitution.
No, Delphi (and Pascal) knows
neither aliases (using a different name for a type/variable/function still needs you to define it anew),
nor macros (executing code in the compiler's context is very limited, mostly definings and conditions).
Even if, chances are you'd have to define it bound to a given context/scope: i.e. your favorite alias TooMuchToType might access three variables named one, two and three, but as per scope those variable's types can vary drastically. Its usage would be prone to obfuscated code and a lot of hassle the compiler has to go thru when trying to give you an error message he wants you to understand.
Why not doing exactly that at the end, but in the opposite way? First using a placeholder and when you're done you replace all of them with the actual code. Otherwise this is bascially what functions are there for, if you want it or not.

COBOL - Microfocus - Generic I/O

I am responsible for converting an old UNIX based COBOL batch application that was developed by a consultant back in the 1990s to a Windows environment but still in COBOL using Microfocus (Eclipse, etc).
This is a pretty straight-forward task except for one little glitch.
The old application never did any explicit file handling within the COBOL. That is there are no FDs, OPENs, READs, WRITEs or CLOSE commands in the COBOL programs. Instead they wrote a C program that would do one of those different functions based on parameters passed to it (including, but not limited to file name, rec length, and the function desired.)
I would like to rewrite that subroutine in COBOL, which would require very little modifications to the COBOL main programs being converted. That is, it would still call that subroutine, but it would now be in COBOL instead of C.
But the challenge is how to write that subroutine so that it is able to act on most any file. I would think I have to go the route of variable length records because they could literally be any length up to to-be-determined maximum size, but seems like it would be vulnerable to error (as it tries to open different types of files).
Does anybody have any experience on this or ideas on a task like this? If not,l I may have to go the blunt force route of replacing each call statement to that subroutine with the specific COBOL command (Open, Read, etc) that needs to be performed and obviously FD and SELECT for every file would need to be added to the main program.
Thanks in advance.
You might be able to
CALL "subprogram" USING fd-name
where fd-name is
FD fd-name.
...
So, yes? maybe?, you might be able to pull off a subprogram that can take generic COBOL files. But, then you get into matching record layouts and other fun things, so, be wary. This might not work COBOL to COBOL, but it does work COBOL to C and back, as you end up passing a reference to the file control block.
You'll likely be better off looking into stock system libraries. Things like CBL_OPEN_FILE and CBL_READ_FILE if they are available. This will give you a much closer match to streaming IO that will be assumed in the current C subprogram.
Or, as Bill is suggesting in the comments, try and figure out why C was used and if you don't want the foreign functions, just dig in and write new COBOL procedures, as that will likely read better in the end.

Passing SYSUID and JOB ID as parameter to COBOL program through JCL

I need to pass the SYSUID and JOBID to the cobol program for logging purpose, how is this possible?,
can the same be passed as an input for a query in a JCL.
Thanks in advance.
SYSUID is simple, you just add it to the PARM parameter of your EXEC statement.
//ASTEP EXEC PGM=A#PGM,PARM='&SYSUID'
JOBID isn't available as a parameter. You will have to write COBOL code to chain through z/OS control blocks (see the Data Areas books at that link) if you need it. This can be done, but I don't recommend it.
If you actually want to get the job number, you write code to go to the PSA control block, which is at relative memory location 0. From there you get a pointer to the current TCB which is in the PSATOLD field of the PSA, from the TCB you get the TCBJSCBB field which is a pointer to the JSCB, from the TCBJSCBB fielf in the JSCB you get a pointer to the SSIB which contains the SSIBJBID field which is the job number. All of these control blocks, PSA, TCB, JSCB, and SSIB are documented (for z/OS 2.4) at the link above. And I reiterate that I don't recommend doing this.
There's a tutorial on chaining through z/OS control blocks in two parts from Longpela.
I agree with #cschneid that you don't want to do all of the pointer chaining just to get the job number. But of course we did do it while creating a "banner page printing" program. We based ours off the code at http://gsf-soft.com/Freeware/COB2JOB.shtml.
If you are comfortable with using SET ADDRESS OF items in the LINKAGE SECTION, REDEFINE--ing POINTER and COMP-5 items, along with creating 01 level structurs from assembler DSECTs, then by all means do it. As a lightweight COBOL subroutine, it's not that much more overhead than an assembler routine (but assembler is better). If you are comfortable with the REXX STORAGE function, you can look at Dave Alcock's IPLINFO program.
However, if the COBOL language constructs I mentioned are unknown to you, then write an assembler subroutine, or ask someone to write it.

Erlang: Compute data structure literal (constant) at compile time?

This may be a naive question, and I suspect the answer is "yes," but I had no luck searching here and elsewhere on terms like "erlang compiler optimization constants" etc.
At any rate, can (will) the erlang compiler create a data structure that is constant or literal at compile time, and use that instead of creating code that creates the data structure over and over again? I will provide a simple toy example.
test() -> sets:from_list([usd, eur, yen, nzd, peso]).
Can (will) the compiler simply stick the set there at the output of the function instead of computing it every time?
The reason I ask is, I want to have a lookup table in a program I'm developing. The table is just constants that can be calculated (at least theoretically) at compile time. I'd like to just compute the table once, and not have to compute it every time. I know I could do this in other ways, such as compute the thing and store it in the process dictionary for instance (or perhaps an ets or mnesia table). But I always start simple, and to me the simplest solution is to do it like the toy example above, if the compiler optimizes it.
If that doesn't work, is there some other way to achieve what I want? (I guess I could look into parse transforms if they would work for this, but that's getting more complicated than I would like?)
THIS JUST IN. I used compile:file/2 with an 'S' option to produce the following. I'm no erlang assembly expert, but it looks like the optimization isn't performed:
{function, test, 0, 5}.
{label,4}.
{func_info,{atom,exchange},{atom,test},0}.
{label,5}.
{move,{literal,[usd,eur,yen,nzd,peso]},{x,0}}.
{call_ext_only,1,{extfunc,sets,from_list,1}}.
No, erlang compiler doesn't perform partial evaluation of calls to external modules which set is. You can use ct_expand module of famous parse_trans to achieve this effect.
providing that set is not native datatype for erlang, and (as matter of fact) it's just a library, written in erlang, I don't think it's feasibly for compiler to create sets at compile time.
As you could see, sets are not optimized in erlang (as any other library written in erlang).
The way of solving your problem is to compute the set once and pass it as a parameter to the functions or to use ETS/Mnesia.

How can I use IEBGENER?

I am having some trouble figuring out how to get IEBGENER working in the way that I want it to. I should preface all this by saying that I am running IEBGENER in a z/OS environment on an academic mainframe.
I have three JCL procedures (PROC) inline to some COBOL code that I am working with, and I need IEBGENER as one of the first steps to put my PROC into a "permanent procedure library under my MVS ID" as well as put my COBOL source "into a permanent sequential data set under my MVS ID".
The instructor mentions to "remember to code the correct LRECL and BLKSIZE information for these data sets."
I am not very familiar with IEBGENER and haven't found anything that really explains to me how to do what I am trying to do.
Any "Big Iron" people able to help?
As mentioned, IEBGENER is a copy program. It takes an input on SYSUT1 and "generates" it to output dataset SYSUT2. In your instance, since you are copying 2 files, its easiest to have 2 GENER steps, each one producing one output dataset.
The only tricky part here is to get the output datasets in the right format. So, to gener into the proclib, assuming that it is not currently cataloged, your SYSUT2 would look something like this:
//SYSUT2 DD DSN=&SYSUID.PROCLIB,
// DISP=(NEW,CATLG,DELETE),
// DCB=(RECFM=FB,LRECL=80,DSORG=PO)
The sequential dataset for the source output would look similar, but no DSORG subparameter on the DCB option. The option of PO there says to create a PDS as opposed to a QSAM file. On modern z/OS installations, BLKSIZE is not necessary to code, as the system will calculate the optimum size if you don't specify it.
this is how to use IEBGENER (as mentioned, should be on the IBM docs site):
//COPY EXEC PGM=IEBGENER
//SYSUT1 DD DSN=MY.INPUT.FILE,DISP=SHR
//SYSUT2 DD DSN=MY.OUTPUT.FILE,DISP=NEW,SPACE=....
//SYSIN DD DUMMY
IEBGENER is "just a" copy program and about all it takes is an input file, output file, and a control file
I'm not sure what you think is "specific", isn't it just a matter of knowing which names to use?
edit: if what you want is defining your input inline, try this:
//SYSUT1 DD *
...
/*
or better yet, if your input contains JCL as well:
//SYSUT1 DD DATA,DELIMITER=XX
...
XX
Still not exceptional JCL, though.
Here is the link to IBM Z/OS manuals
http://www-03.ibm.com/systems/z/os/zos/bkserv/v1r10books.html
search for JCL and you will find the manuals for JCL.
IEBGENER is a IBM supplied copy program to copy data from one dataset (file) to another dataset. You will have input file, output file and control file.
LRECL and BLKSIZe are dataset parameters. If the input file and output file parameters do not match, data may not get copied correctly. I didn't understand your questions completely. Can you elaborate on what exactly you need to do with IEBGENER.
A couple of minor points:
DCB=(RECFM=FB,LRECL=80,DSORG=PO)
DCB= is not required anymore, just code
RECFM=FB,LRECL=80,DSORG=PO
Also:
Because the records are fixed-format,
the BLKSIZE must be an even multiple
of 80. Very often, people use a value
of 3120. The reasons for this are
hidden in the mists of antiquity. I
tend to use 27920, to get the most
efficient space usage on a 3390
device.
It should not be necessary to specify a blocksize for a new DASD (disc) dataset. System determined blocksize will automatically give you the best blocksize (which would indeed be 27920 for a LRECL of 80 on a 3390)
Just so you don't need to worry about the DCB parameter, it's nice trick to point to the value from the input dataset.
//STEP100 EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD DISP=SHR,DSN=INPUT.FILE
//SYSUT2 DD DSN=OUTPUT.FILE,
// DISP=(,CATLG,DELETE),
// SPACE=(TRK,(300,50),RLSE),
// DCB=*.SYSUT1
//SYSIN DD DUMMY
It sounds as if your instructor is reminding you to give the correct LRECL and BLKSIZE to the "permanent procedure library" and "permanent sequential data set". Historically, such data sets are RECFM=FB, LRECL=80.
Because the records are fixed-format, the BLKSIZE must be an even multiple of 80. Very often, people use a value of 3120. The reasons for this are hidden in the mists of antiquity. I tend to use 27920, to get the most efficient space usage on a 3390 device.
IEBGENER is one of the most underrated and misunderstood utilities IBM has.
Here is the hyperlink for the best documentation: IEBGENER.
IEBGENER is not merely a file-to-file utility that only does copies. It can easily and more efficiently create variable blocked files. It can with the proper buffering actually be your fastest file-to-file copy utility as it used to not be internally buffered very well though now I believe it is so it is now automatically just about the fastest. The //SYSPRINT messages - sadly - are extremely cryptic if not actually annoyingly ridiculous. Many shops have an accelerator called BETERGENER as most programmers had no idea how to buffer IEBGENER and since IBM is catering to the pampered new programmers who want MVS to look like and act like Windows, using IEBGENER is more user friendly. yuck

Resources