"COPY" statement with "REPLACING" in COBOL - cobol

I am getting compilation error as,
A "COPY" statement with "REPLACING" phrase was found within a nested "COPY".
This is our compilation setting that we can not use REPLACING verb in nested copy.
We have one copybook which is having multiple copy statements with replacing verb.
Can anyone help me to resolve this error?

Nesting COPYBOOKS in COBOL is a bit of a trick. In general
you may nest copybooks only if they do not
contain the REPLACING phrase and do not cause recursion.
Suppose you had the following two copybooks:
COPYBOOK ABC
01 :A:-VAR-A1 PIC X.
01 :A:-VAR-A2 PIC X.
COPY XYZ REPLACING ==:A:== BY ==B==.
and
COBPYOOK XYZ
01 :A:-VAR-X1 PIC X.
01 :A:-VAR-X2 PIC X.
The nesting in COPYBOOK ABC is not allowed because it contains a REPLACING phrase.
However, you can do the following. Drop RELACING from COPYBOOK ABC so
it becomes:
COPYBOOK ABC
01 :A:-VAR-A1 PIC X.
01 :A:-VAR-A2 PIC X.
COPY XYZ.
Now include COPYBOOK ABC into your source program as follows:
REPLACE ==:A:== BY ==B==.
COPY ABC.
REPLACE OFF.
The REPLACE directive causes all occurances of :A: to
be replaced by B until a REPLACE OFF directive is encountered, and these
replacements occur after all COPY directives have been actioned. The net
result of the above statements would be:
01 B-VAR-A1 PIC X. <== from ABC
01 B-VAR-A2 PIC X. <== from ABC
01 B-VAR-X1 PIC X. <== Nested copy of XYZ from ABC
01 B-VAR-X2 PIC X. <== Nested copy of XYZ from ABC
This is the only 'legal' way of performing replacements to nested copybooks
in COBOL that I am aware of.

While Neal's answer may be correct for the Cobol variant he and the OP are using, it is worth noting that some Cobol compilers will allow nested COPY ... REPLACING statements.
Indeed we have many instances where we use this in our code.
For example, I have many Cobol module programs that include a copymember in the following way:
COPY 'uwxxxxsel.prg' REPLACING
LEADING "xxxxSEL" BY "AREASEL".
and the 'uwxxxxsel.prg' copymember contains the following COPY of another file as follows:
COPY 'uwf8list.prg'
REPLACING LEADING 'XXXXXX-F8-' BY 'SELECT-F8-'
==FUNCTION-KEY== BY ==F8-FUNCTION-KEY==.
and this works fine.
I use this as a kind of 'inheritance' structure for common functionality.
There is one gotcha, though, with our Compiler. The higher level REPLACING does not continue after the nested REPLACING, but as long as the nested REPLACING is the last thing in the copymember, it is fine.

Related

INITIALIZE gives garbage value on PIC X and PIC S9 COMP variables

When initializing the following variables:
01 BATCH-REC.
03 BATCH-VERSION PIC X(2).
03 BATCH-FIELDS PIC X(682).
03 BATCH-REC-01 REDEFINES BATCH-FIELDS.
05 B01-OH-DTL-REC.
07 B01-PE-ID PIC X(12).
07 B01-PMT-DISC-TERMS PIC S9(4) COMP.
07 B01-PMT-DISC-AMT PIC S9(18) COMP.
using the command
INITIALIZE BATCH-REC.
the variables B01-PMT-DISC-TERMS is initialized to value +08224 and B01-PMT-DISC-AMT is initialized to +314885530818453536.
What could the reason be? Would it be a good idea to MOVE a blank space to those variables after initializing? I dont want to change that BATCH-REC code to add a default value on them.
The INITIALIZE statement will not initialize redefined fields. If you want the redefined fields to be initialized, you must identify them in some way. For example,
INITIALIZE BATCH-VERSION BATCH-REC-01
This will initialize the elementary fields to SPACES or ZEROS depending on their PICTURE. BATCH-FIELDS will not be initialized.
Item 3, below applies, in this case. From the 2002 standard for INITIALIZE:
5) The receiving-operand in each implicit MOVE or SET statement is determined by applying the following steps in order:
a) First, the following data items are excluded as receiving-operands:
Any identifiers that are not valid receiving operands of a MOVE statement, except data items of category data-pointer, object-reference, or program-pointer.
If the FILLER phrase is not specified, elementary data items with an explicit or implicit FILLER clause.
Any elementary data item subordinate to identifier-1 whose data description entry contains a REDEFINES or RENAMES clause or is subordinate to a data item whose data description entry contains a REDEFINES clause. However, identifier-1 may itself have a REDEFINES clause or be subordinate to a data item with a REDEFINES clause.
In this case I think you will find your INITIALIZE statement did initialize your PIC X data to spaces. The value you have for B01-PMT-DISC-TERMS is x'2020' and the value for B01-PMT-DISC-AMT is x'2020202020202020' with the leading digit cut off, possibly due to reporting of the value being limited to the picture clause of 18 digits.
Regardless, I agree with #RickSmith and believe he is correct in his solution to your problem.

Can level 49 be used for STRING purpose

As I'm new to cobol, please help me with the below piece of code.
WORKING-STORAGE SECTION.
01 BAS-REC.
02 INPT-REC.
49 INPT-LEN PIC S9(4) COMP.
49 INPT-TEXT PIC X(150).
02 INPT1-REC.
49 INPT1-LEN PIC S9(4) COMP.
49 INPT1-TEXT PIC X(150).
02 INPT2-REC.
49 INPT2-LEN PIC S9(4) COMP.
49 INPT2-TEXT PIC X(150).
77 VAR1 PIC X(5) VALUE 'APT'.
77 NUM1 PIC 9(1).
I'm using the level 49 for character varying here (to truncate trailing spaces)
Then I have cursor fetch.
After few modification under PROCEDURE DIVISION I'm doing the below.
PERFORM UNTIL SQLCODE=100
PERFORM VARYING NUM1 FROM 1 BY 1 UNTIL NUM1=6
STRING INPT-REC DELIMITED BY ' ',' ',
VAR1 DELIMITED BY ' ',' '
NUM1 DELIMITED BY ' ' INTO INPT2-REC
EXEC SQL
insert query here (which will run 5 times)
END-EXEC
END- PERFORM
END- PERFORM
but in the table the data got inserted only once but it shold have got inserted 5 times and also the INPT2-REC hasn't been concatenated. The INPT2 -REC just contains the value of INPT-REC alone
My question is this a special characteristic of level 49 or am I wrong somewhere?
Note that if you use INPT-REC2 as a host-variable for a VARCHAR-field you will only see the part from INPT-REC since you never update the length-field: it still contains the length it was assigned from INPT-REC.
So you'll have to somehow get the actual length of INPT2-TEXT (e.g. INSPECT the REVERSE of INPT2-TEXT for LEADING SPACES) and move it to INPT2-LENGTH before your EXEC SQL.
As I already said in my comment: there is nothing special about level 49 - you could as well use 48, 33,30 or 05 with the same results. The samples in the DB2 manual probably use 49 since it is the last valid level-number without any special meaning, so it is least likely to cause problems with any level-numbers already used in the program.
As for the query being executed only once: in your loop you are varying NUM1 but are checking whether I=6 - since we don't see I anywhere in your example I can only guess that it is already equal to 6 upon entering the loop.
Level 49 can be treated specially when Embedded SQL is involved, depending on system; this text is copied from the IBM Knowledge Center
Host structure declarations in COBOL must satisfy the following requirements:
COBOL host structures can have a maximum of two levels, even though the host structure might occur within a structure with multiple levels. However, you can declare a varying-length character string, which must be level 49.
A host structure name can be a group name whose subordinate levels name elementary data items.
If you are using the DB2® precompiler, do not declare host variables or host structures on any subordinate levels after one of the following items:
A COBOL item that begins in area A
Any SQL statement (except SQL INCLUDE)
Any SQL statement within an included member
When the DB2 precompiler encounters one of the preceding items in a host structure, it considers the structure to be complete.
So, this seems like a little implementation detail (level 49 for var char) that may spill over into other implementations of COBOL ESQL. Like many details buried in systems, Knowing that would require knowing that.
This particular detail is news to me as of a few minutes ago.
Looking more just now, this came up in the esqlOC contribution for GnuCOBOL recently. A level 49 specific tweak to ensure there was no need to worry about little end big end storage between host and service. So it seems to be a thing.
And an answer to the original question is; depends on compiler environment and ESQL preprocessor, but yeah maybe level 49 fields can be used for VARCHAR.

Cobol write form-feed char to file

I have file defined
select bankd-file assign to f-bankd-file
file status is wx-fstat
organization line sequential.
fd bankd-file.
****************
01 bankd-rec pic x(80).
And I am writing to this file line by line, just simple with write command. And on one line I need also write form-feed character. This character I have defined as
01 w-ff pic x value x'0C'.
But in output file, I have before form-feed char NUL char. Please how can I get rid of this NUL char? Other chars are written without any problems.
The question does not specify the used COBOL compiler therefore we can only guess. Different compilers include a x'00' before "non-text-data" to make sure it can be read in correctly (this is mainly done if someone tries to write a COMP item which may contain line breaks and/or form feeds).
This may not be possible with your compiler but normally you would do:
WRITE bankd-rec FROM SPACES BEFORE ADVANCING PAGE
(no need for the FROM SPACES when you do this BEFORE/AFTER the record you actually want to have the form-feed in)
For Micro Focus COBOL, you can turn off x"00" before non-test-data by using the INSERTNULL=OFF in the extfh.cfg

Reading floating-point numbers from file in COBOL

I have fixed-point numbers in file, one in each line, in this format S9(6)V9(2) but when they are actually read, I'm getting non numeric errors while trying to put them in math operations. What is more, when I try to display them in program, a number that is written in file as 567123.45 is saved in variable as +567123.04. And for example the number from file 123.45 is saved in variable as +123.45.00 and it provokes the following error 'WS-VALUE' not numeric: '123.45 0' during a math operation. Why is that?
I'm using OpenCobolIDE 4.7.4 for Windows.
EDIT:
File has records of the following form separated by new lines (read by READ operation record after record):
01 WS-OPERATION.
05 WS-ID PIC A(2).
05 WS-CLIENT PIC 9(5).
05 WS-COUNTRY PIC A(4).
05 WS-VALUE PIC S9(6)V9(2).
The reason is that you try to un-edit a field. 567123.45 in the data is not conforming to PIC S9(6)V9(2) but to -9(6).9(2). - internal stored data vs. print-data.
Simply changing the definition and use MOVE WS-VALUE TO WS-VALUE-INTERNAL (which is defined like you want to) may work with a specific compiler (and specific data) but I'd go a different route:
I'd suggest to always validate the data before doing something with it (the file may be broken or external edited).
At least check the simple numeric data like WS-CLIENT for IS NUMERIC and either do a full validation on the data field WS-VALUE or at least use MOVE FUNCTION NUMVAL(WS-VALUE) TO WS-VALUE-INTERNAL.

Get field names while running program

I have a copy book like :
01 MY-STRUCTURE.
05 STRUCTURE-NAME PIC X(20).
05 STRUCTURE-DATE PIC X(8).
05 STRUCTURE-LIB PIC 9(3).
How can I get the name of my fields?
I want to have a program that can get any copybook and write dynamically its fields and values.
I want to write it to an output file like this :
"STRUCTURE-NAME-> TOTO"
"STRUCTURE-DATE-> 19780301"
"STRUCTURE-LIB -> 123"
In the z/OS world, depending upon your compiler level, you can use the debugging information generated by the compiler to do introspection on your names. To do this, you will need to save your ADATA at compile time.
I have a two possible solutions:
You save the names of the fields of the copy in a internal table. And secuential reads the table for your write your output.
Dynamical allocation, is more complicated but it's possible. You allocate the copy in your program using bpxwdyn (subroutine IBM).
You create a subprogram, with name of copy, the length is fixed (80), the name of library of copys, and allocate this copy in subprogram. Then, You can fill a internal table with his datas.
Eg:
http://mainframe-tips-and-tricks.blogspot.com.es/2011/12/cobol-sample-program-for-dynamic-file.html

Resources