copybook misalignment in fileaid - cobol

I am trying to create a copybook structure for my data file.
Part of the data looks like this
C 0000.00
Since it has 0000.00 , in my copybook, we declared it as a PIC 9(04)v9(02).
but when i map it using fileaid, i get this error
15 EF-PURCH-FEE-AMT 6/AN 0000.0
15 EF-FILLER4 975/AN 0
The decimal point is considered as another byte and the last zero is spilling into the subsequent field
I have tried to define the picture clause as zoned decimal by giving value as PIC ZZZ9V99 as well. But its still spilling into next field.
Expected result. :
15 EF-PURCH-FEE-AMT 6/AN 0000.00
15 EF-FILLER4 975/AN 0
Actual result:
15 EF-PURCH-FEE-AMT 6/AN 0000.0
15 EF-FILLER4 975/AN 0
PIC definition as of now:
15 EF-PURCH-FEE-AMT PIC ZZZ9V99.
15 EF-FILLER4 PIC X(975).

Please refer to the documentation for the PICTURE clause of a data definition. There you will find that the V is a presumed or virtual decimal point, not a physical one. You may be able to attain your desired result with...
15 EF-PURCH-FEE-AMT PIC 9999.99.

Related

Array processing and Table handling with packed decimal in COBOL

I was practicing array processing and table handling and there's this output of my program that I don't understand.
01 TABLE-VALUES.
05 TABLE-ELEMENTS OCCURS 2 TIMES.
10 A-A PIC X(5).
10 A-B PIC S9(5)V99 COMP-3.
01 WS-STRING PIC X(10).
01 S PIC 99.
01 WS-COUNT PIC 99.
...
PROCEDURE DIVISION.
0000-MAIN.
DISPLAY 'HELLO WORLD'
MOVE '1234567890ABCDEFGHI' TO TABLE-VALUES
DISPLAY 'TABLE VALUES ' TABLE-VALUES
MOVE 0 TO WS-COUNT
INSPECT TABLE-VALUES TALLYING WS-COUNT FOR CHARACTERS
DISPLAY WS-COUNT
PERFORM 1000-PARA VARYING S FROM 1 BY 1 UNTIL S > 2
STOP RUN.
1000-PARA.
MOVE 'A-A(&&) = ' TO WS-STRING
INSPECT WS-STRING REPLACING FIRST '&&' BY S
DISPLAY WS-STRING A-A(S)
MOVE 'A-B(&&) = ' TO WS-STRING
INSPECT WS-STRING REPLACING FIRST '&&' BY S
DISPLAY WS-STRING A-B(S).
The output turned out to be:
HELLO WORLD
TABLE VALUES 1234567890ABCDEFGHI
18
A-A(01) = 12345
A-B(01) = 6 7 8
A-A(02) = 0ABCD
A-B(02) = 5 6 7
I don't understand how A-B(1) and A-B(2) turned out like that. Why are there spaces in between? Where did digit 9 go to?
Try removing the COMP-3 from the A-B definition, it should work better.
Cobol comp-3
Comp-3 is cobol's binary coded decimal format. Each 4 bytes (1/2 byte or nyble) represents a decimal digit with the sign held in the last digit. Moving a character string to a comp-3 value (like you do) will result in a invalid comp-3 value.
Normally the value 1234 would be stored as
`01234C`x
In your case (if using an EBCDIC machine) you are moving 6789 hex string 'f6f7f8f9'x
to the variable A-B(01). The F's are not valid decimal digits and 9 is not a valid comp-3 sign.
Move to Table Explanation
Explanation of
MOVE '1234567890ABCDEFGHI' TO TABLE-VALUES
in the above TABLE-VALUES is treated as a pic x(18). The move completely ignores the definitions of A-A and A-B.
Assuming a definition of
01 TABLE-VALUES.
05 TABLE-ELEMENTS OCCURS 2 TIMES.
10 A-A PIC X(5).
10 A-B PIC S9(5)V99.
The following would make more sense
MOVE 'A-A 100234567A-A 200234567' TO TABLE-VALUES
When doing a move to a group level, The string has to exactly match the
map of the fields in the Group.
For the above Cobol Layout, the fields are aligned like
Field Position Length
A-A(1) 1 5
A-B(1) 6 7
A-A(2) 13 5
A-B(2) 18 7
I don’t know which compiler and directives you are using, but I would have expected the original DISPLAY of the comp-3 usage to ABEND with a numeric exception.
As for the follow up question about the letters in the numeric field, you valued the field by moving a literal to a group item, TABLE-VALUES. Group items always are USAGE ALPHANUMERIC.

What is the significance of the code at right of variable declaration in COBOL?

I was studying COBOL code and I did not understand the number at the right of the code line:
007900 03 EXAMPLE-NAME PIC S9(17) COMP-3. EB813597
the first number is about position of that line in code, the second is about column's position (like how many 'tabs' you are using), the third is type of variable, but the fourth (COMP-3) and mainly the last (EB813597) I did not understand.
What does it mean?
Columns >= 72 are ignored. So EB813597 is ignored. It could be a change id from the last time it was changed or have some site specific meaning e.g. EB could be the initials of the person who last changed it.
Comp-3 - is the type of numeric. It is bit like using int or double in C/java. In Comp-3 (packed-decimal) 123 is stored as x'123c'. Alternatives to comp-3 include comp - normally big endian binary integer, comp-5 (like int / long in C)
007900 03 EXAMPLE-NAME PIC S9(17) COMP-3. EB813597
(a) (b) Field-Name (c) (d) Usage (numeric type)
a - line-number ignored by the compiler
b - level-number it provides a method of grouping fields together
01 Group.
03 Field-1 ...
03 Field-2 ...
field-1 and field-2 belong to group. it is a bit like struct in c
struct {
int field_1;
int field-2;
...
}
c) PIC (picture) tells us the field picture follows.
d) fields picture in this case it is a signed field with 17 decimal digits
Comp-3 - usage - how the field stored
So in summary EXAMPLE-NAME is a Signed numeric field with 17 decimal digits and it is stored as Comp-3 (packed decimal).

Decode a Binary Coded Decimal

I have a field pic X(03) with a date in it as X'160101' format yymmdd.
I will like to know how to convert it to pic x(06).
So far I tried to move it back to a 9(03) comp and move the
9(03) comp to a 9(06) but it didn't work.
How can I do this?
What you have is a Binary Coded Decimal (BCD). That is, the data is held in a binary field, but it is the decimal representation, not the binary, which is important for the value. X'160101' in would be 1,442,049. X'160201' would be 1,442,305. So if you were able to treat it as a binary field (you'd have to prepend a binary zero to make it the correct length for a binary field) you'd have to do some silly calculation.
So you do something different, and easier. BCD is not a native COBOL datatype. PACKED-DECIMAL (often the same as COMP-3/COMPUTATIONAL-3) is a BCD-type which includes a sign-value in the low-order (right-most) half-byte. So not quite a BCD, but you can treat your BCD as PACKED-DECIMAL like this:
01 BCD-TO-PACKED.
05 BTP-SOURCE-BCD PIC XXX.
05 BTP-PACKED-ZERO PACKED-DECIMAL PIC 9 VALUE ZERO.
01 FILLER
REDEFINES BCD-TO-PACKED.
05 BTP-PACKED-TO-MOVE
PAKCED-DECIMAL PIC 9(6)V9.
01 DATE-AS-PIC-X PIC X(6).
01 DATA-AS-CHARACTER-NUMERIC
REDEFINES DATE-AS-PIC-X PIC 9(6).
MOVE your-source-value TO BTP-SOURCE-BCD
MOVE BTP-PACKED-TO-MOVE TO DATA-AS-CHARACTER-NUMERIC
After that you can happily reference DATE-AS-PIC-X to do whatever you want with it.
BCD-TO-PACKED is a four-byte group field which, through the VALUE clause and through nothing ever changing, has, in the last by X'0F'. That's an unsigned packed-decimal field with one digit and a value of zero.
Then you do the X-to-X MOVE for BTP-SOURCE-BCD. BCD-TO-PACKED now looks like this: X'1601010F'. Which is perfectly valid for a packed-decimal field. You could divide that by 10 to get your date (REDEFINES it as PACKED-DECIMAL PIC 9(7)) but why waste CPU?
Instead, in the REDEFINES you define one decimal place (V9). When the compiler generates the code to MOVE that to another numeric field with no decimal places, the source decimal place(s) are just dropped off. Presto! Divide by 10 without dividing.
Note: The data-names chosen are to aid the explanation. You should make yours meaningful to the data, not just use "trite" names. "Character numeric" is called USAGE DISPLAY in COBOL, it is the default if a USAGE is not supplied. The word USAGE is rarely used itself. So USAGE DISPLAY is what you have when there is a PIC X or PIC 9 field with no other usage.
Note: You should probably not be using two-digit years. You won't be able to deal with dates earlier than 2000 or later than 2199. Historical use of two-digit years was due to expensive disk storage and "data redundancy" (all century values were 19, so why hold the value 19 80 different times for the same account). If using two-digit years, ensure that there is something somewhere which is relevant to the century.
Note: If you attempt to MOVE a PIC X field to a numeric field, the compiler will assume that you have valid character numbers in the field, which is one reason your original attempt failed.
If you search stackoverflow, you should find the answer (this has already been answered).
But Create a fields like (my-date-x holds the date):
03 my-date-x pic x(3).
03 my-date-9 pic 9(6).
03 date-ymdv0 pic 9(6)v9 comp-3.
03 date-x pic x(3) redefines date-ymdv0.
And the code is
Move 0 to date-ymdv0
Move my-date-x to date-x
Move date-ymdv0 to my-date-9
The reason it works is for 9(6)v9 comp3 160101 is stored as x'1601010c'
which is what you have (+ a 0c at the end).

Check a variable to make certain that it is all numbers?

How can I check Work-Trig to make sure that it is all digits?
code:
Work-Trig is --> 20140101
CHECK-TRIG.
IF WORK-TRIG IS NUMERIC THEN
MOVE "FALSE" TO ERR-TRIG
ELSE
MOVE "TRUE" TO ERR-TRIG
END-IF.
DISPLAY 'ERR-TRIG' ERR-TRIG.
X-CHECK. EXIT.
01 WORK-TRIG.
05 TRIG-YEAR PIC X(08) VALUE SPACES.
05 TRIG-MONTH PIC X(01) VALUE SPACES.
05 TRIG-DAY PIC X(01) VALUE SPACES.
05 FILLER PIC X(70) VALUE SPACES.
The problem is that WORK-TRIG is 80 bytes long. The first eight bytes contain your data, but the entire 80 bytes will be tested for being NUMERIC.
You have a data-name for the first eight bytes. If you test that instead of the group-item, your code will work.
CHECK-TRIG.
IF WORK-YEAR IS NUMERIC THEN
MOVE "FALSE" TO ERR-TRIG
ELSE
MOVE "TRUE" TO ERR-TRIG
END-IF.
DISPLAY 'ERR-YEAR' ERR-TRIG.
X-CHECK. EXIT.
If you have a data-name called WORK-YEAR, it should only contain a year. It should not contain an entire date. The point of good names for data is so that we, humans, can read and understand your code better. When looking for a problem, we find WORK-YEAR as eight bytes long, and have to spend time finding out if that is the correct length, or the correct name and a wrong length.
Given the code change, it would be good to use a different name for ERR-TRIG as well.
There are more obscure ways to test the first eight bytes of a group item, but since you already had a name, hopefully we'll keep reference-modification out of this one.
The following code example works and will check each position in you WORK-TRIG1 to see if that value is a NUMERIC. I tested this and it does work. This example uses a PERFORM VARYING loop to index through each "location" in the string to see if it is valid.
Should Work ALSO:
IF A IS NUMERIC THEN
//code here
END-IF
I do know that the below code works because I took it directly from a program that is running perfectly and has since 88 or 89.
Code:
CHECK-TRIG.
PERFORM VARYING SUB1 FROM 1 BY 1 UNTIL SUB1 > 8
IF WORK-TRIG(1:SUB1) IS NUMERIC THEN
MOVE 'FALSE' TO ERR-TRIG
ELSE
MOVE 'TRUE' TO ERR-TRIG
MOVE SUB1 TO SV-RTN-CODE
MOVE 9 TO SUB1
END-IF
END-PERFORM.
X-CHECK. EXIT.
--Code--New this does not work
PERFORM VARYING SUB1 FROM 1 BY 1 UNTIL SUB1 > 8
IF WORK-TRIG(SUB1:8) IS NUMERIC THEN
MOVE 'FALSE' TO ERR-TRIG
ELSE
MOVE 'TRUE' TO ERR-TRIG
MOVE SUB1 TO SV-RTN-CODE
MOVE ' TRIGGER CARD ERROR (SEE DATE BELOW)' TO
ERR-DET
MOVE 9 TO SUB1
END-IF
END-PERFORM.
Recently had experienced non-numeric being successfully processed into a numeric (COMP-3) field.
Value of 'FALSE99999999' moved into a COMP-3 field and became 6132599999999 and the program never encounter an S0C7 ABEND.
Looks like verifying each byte of the source field is the only way to identify such issue.

Copybook field start-positions

Does anyone have a quick method for finding a COBOL copybook start-positions for fields? For example:
000100 01 BGG-FILE-REC.
000200 03 BGG-RCD-KEY.
000300 05 BGG-DUDENAME PIC XXXX.
000400 05 BGG-DUDEADDR PIC XX.
000500 05 BGG-HAIRCOLOR PIC X(71).
000600 05 BGG-EYECOLOR PIC X(8).
The BGG-HAIRCOLOR column begins at column 7. However, the actual file I am handling has about 250 variables totalling to 3400 bytes. Slogging through and adding the PIC values with a hand calculator is hideous and not happening in my lifetime. The number would be nice to have in vi for when I am examining output from the system; i.e, does BGG-EYECOLOR value fall in the correct column?
I could write a perl script to annotate such a copybook but before I do it I wondered if anyone has a smoother way to get the same value?
If it is for the mainframe, you could use cb2xml to convert the copybook to xml
(with field Start).
Alternatively you can use the RecordEditor. Import the Cobol Copybook into
the RecordEditor (see RecordEditor-Cobol Notes). The RecordEditor will calculate
the field positions. You can copy and paste the fields from the RecordEditor-Layout to either Excell or a Text Editor, Alternatively you can export the record layout as Xml
The RecordEdityor willwork for several Cobol Dialects (Mainframe, OpenCobol).
If you are reading files in java, you should look at JRecord. JRecord will let you read a Cobol Data file in Java using a Cobol Copybook.
Also Legstar may be worth a look. Legstar originally start with dealloy with online data transfer but they have been branching out.
disclaimer : I maintain https://www.cobolcopybook.co.in
Hi, check the site https://www.cobolcopybook.co.in, This site is designed specially for the analyze COBOL copybooks.
for Eg.
Your input copybook is (as mentioned in question):
000100 01 BGG-FILE-REC.
000200 03 BGG-RCD-KEY.
000300 05 BGG-DUDENAME PIC XXXX.
000400 05 BGG-DUDEADDR PIC XX.
000500 05 BGG-HAIRCOLOR PIC X(71).
000600 05 BGG-EYECOLOR PIC X(8).
Then the output will be:
SR# LEVEL FIELD NAME PICTURE TYPE START END LENGTH
0 1 BGG-FILE-REC. # AN 1 85 85
1 3 BGG-RCD-KEY. # AN 1 85 85
2 5 BGG-DUDENAME XXXX. AN 1 4 4
3 5 BGG-DUDEADDR XX. AN 5 6 2
4 5 BGG-HAIRCOLOR X(71). AN 7 77 71
5 5 BGG-EYECOLOR X(8). AN 78 85 8
I hope this will solve your problem.
If you're on a mainframe, use option 8 of FileAid.
You are worried about how hard it is to line up the PIC clauses in the same column?
Open it in one of the many Eclipse variants and control-shift-F or whatever.
You know it compiles nicely regardless of columns, and has for almost 30 years, they really don't matter any more.
The low rent way would be to compile it and cut&paste your cross reference listing over your copybook.
If you are using Mainframes you can use "File aid - view".
From ISPF Primary Option Menu goto
G ==> General Utility
F ==> File-Aid Products
1 ==> File-AID
8 ==> VIEW
In the screen the below options will come:
Specify Record Layout Dataset to View:
Dataset name ===> 'XXXXXX.XXX.XXXX'
Member name ===> COPYZXY (Blank or pattern for member list)
Give your "Dataset name" and "Member name" (Dataset name : Your PDS and Member name : Your copy book name)
After pressing enter you will get a VIEW LAYOUT screen that describes about
Variable name, Clause, number, Start, end and length of each variable present in that copy book.

Resources