COBOL keyword REDEFINES - cobol

May I ask, what is the usage of the keyword REDEFINES in COBOL?
I can not understand the manual's definition.
What is the meaning of the following code?
01 WS_CHARGE_TXT_8X PIC X(08) VALUE "10000000".
01 WS_CHARGE_NUM_8 REDEFINES WS_CHARGE_TXT_8X.
05 WS_CHARGE_8 PIC 9(05)V9(03).
Thank you!

Basically Redefines reuses the spaces so in the above example WS_CHARGE_TXT_8X and WS_CHARGE_8 will point to the same block of memory. This allows you to look at a block of memory in different ways, in this case the variable can be viewed as a text PIC X and a signed numeric PIC S9. The -8X to -8 in the variable name is just stylistic to indicate the variable is being recast to another type or format to other programmers.
In the above example
the value of WS_CHARGE_TXT_8X is
"10000000"
the value of WS_CHARGE_8 is
of 10000.000.
If you moved 123.456 to WS_CHARGE_8 the value of WS_CHARGE_TXT_8X "00123456".
A more useful example is
03 Birth-Date-YYYYMMDD pic 9(8).
03 filler redefines Birth-Date-YYYYMMDD.
05 Birth-Date-YYYY pic 9(4).
05 Birth-Date-MM pic 99.
05 Birth-Date-DD pic 99.
In this case you can access the whole date Birth-Date-YYYYMMDD or the year / month / day individually (Birth-Date-YYYY etc).

It is analogous to union in 'C'.
It saves working storage space, and MOVE statements, and is also useful for transposing arrays of PIC(X), or accessing repeated fields as an array.
In the OP's case a numeric "type" is being created for the char contents of the prototype field.

A REDEFINES allows a different data description for storage which has already been defined.
That might be to allow entirely different data to be held there.
05 RL-AGENT-DATA.
...
05 RL-CUSTOMER-DATA REDEFINES RL-AGENT-DATA.
...
Or to give a description which allows a use of a part of the data, as in Bruce's example.
Or to use a piece of data that is the same, but for a different purpose:
05 INPUT-AMOUNT PIC X(10).
05 INPUT-AMOUNT-NUMERIC REDEFINES PIC 9(8)V99.
Whatever is in INPUT-AMOUNT it can be reported without problem, but only if it is a valid numeric (by testng it for NUMERIC), is INPUT-AMOUNT-NUMERIC used for some purpose.
Note that each 01 subsequent to the first under an FD is an "implicit REDEFINES".
Note also that items in the LINKAGE SECTION have the effect of "redefining" "something", even though if the address of the data is from a CALLing program, the definition is often the same as the original definition, and should usually at least match the PICtures of the original.

Related

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).

Converting a date in COBOL

So im reading a mmddyyyy (01012000) date into a pic x (8) and im wondering how I can create a new variable with the previous variables info into yyyymmdd (20000101) format. Im sure there must be some way to do this with substrings or what not?
#ScottNelson has provided the "using substrings" part of the answer, following is the "or what not" part of the answer.
01 mmddyyyy.
05 mm pic xx.
05 dd pic xx.
05 yyyy pic xxxx.
01 yyyymmdd.
05 yyyy pic xxxx.
05 mm pic xx.
05 dd pic xx.
move corresponding mmddyyyy to yyyymmdd
In working storage:
77 mmddyyyy-date pic x(8).
77 yyyymmdd-date pic x(8).
In your procedure division logic:
move mmddyyyy-date(1:2) to yyyymmdd-date(5:2)
move mmddyyyy-date(3:2) to yyyymmdd-date(7:2)
move mmddyyyy-date(5:4) to yyyymmdd-date(1:4)
01 a-name-to-describe-the-source-date.
05 antdtsd-dd PIC XX.
05 antdtsd-mm PIC XX.
05 antdtsd-yyyy PIC XXXX.
01 a-name-to-describe-the-destination-date.
05 antdtdd-yyyy PIC XXXX.
05 antdtdd-mm PIC XX.
05 antdtdd-dd PIC XX.
Or
01 a-name-to-describe-the-source-date PIC X(8).
01 FILLER
REDEFINES a-name-to-describe-the-source-date.
05 antdtsd-dd PIC XX.
05 antdtsd-mm PIC XX.
05 antdtsd-yyyy PIC XX.
01 a-name-to-describe-the-destination-date.
01 FILLER
REDEFINES a-name-to-describe-the-destination-date.
05 antdtdd-yyyy PIC XX.
05 antdtdd-mm PIC XX.
05 antdtdd-dd PIC XX.
Then
MOVE antdtsd-dd TO antdtdd-dd
MOVE antdtsd-mm TO antdtdd-mm
MOVE antdtsd-yyyy TO antdtdd-yyyy
Firstly, you are overstating things if you call this "conversion". It is a simple rearrangement of data.
Secondly, there are many ways to do this. Which way do you do it? COBOL tends to be coded by "teams", and if you do this for a job, you will be best served by doing it how others on your team do it.
You've been shown two ways: reference-modification and using CORRESPONDING (which, if you see it in real code, will often be abbreviated to CORR - who's going to type CORRESPONDING if the intent is not to type much...?).
How otherwise to chose between them? Performance? They'll likely generate identical code. So the compiler is out of it. Understandability to the human reader? For me, that is very important in COBOL (or any language).
Two problems with the reference-modification. Typo? No problem, code will compile and execute. And you'll find it in testing. Won't you? At some point? And wasting all the time expended until you find it. The second is, what does (5:4) mean? When someone tells you "that program is doing something odd with years", you have to first find that the year is disguised as (5:4). Oh, and (1:4). Great, you've not even started looking for the issue with the program yet, and you still have to check the positions and lengths are correct. OK, a date is a trivial example, but reference-modification-users presumably apply it to everything they can (if not, why apply it to a date)? So, have fun reading.
Oh, and COBOL doesn't have "strings", it has fixed-length fields. Reference-modification creates fields
The CORR. Using this saves lots of typing (the it's reason it exists is probably due to punched-cards, and the way many COBOL programs would process input data and create new output data. Programs on punched-cards, so a genuine reason to reduce typing - for punched-card programs).
Well, tis modern times now.
Let's say you want to use the "month" as a subscript to get the month-name if the year is 2005.
IF yy OF yyyymmdd EQUAL TO "2005"
MOVE month-name-in-table ( mm OF yyyymmdd ) TO ...
END_IF
(that assumes mm OF yyyymmdd is defined as numeric).
Do you want to scatter "qualification" (the use of OF or IN to make a name unique by referring to something it belongs to) throughout a program, just so you can use CORR?

Is it possible to MOVE to a variable name created during runtime?

I am writing a program that changes the colour of a field if is it a duplicate record. To do this I am using a nested perform to compare each item to each other. When it finds a duplicate I would like to MOVE DFHRED to that specific field for example CRS1AC. My issue is that I don't know how to reference the field I am trying to change the colour of once I've found that is it a duplicate, how do I do this? Here are the fields which are in the MAP file that I am trying to move the colour to if a duplicate exists...
01 CRS1AC PIC X.
01 CRS1BC PIC X.
01 CRS2AC PIC X.
01 CRS2BC PIC X.
01 CRS3AC PIC X.
01 CRS3BC PIC X.
01 CRS4AC PIC X.
01 CRS4BC PIC X.
01 CRS5AC PIC X.
01 CRS5BC PIC X.
here is my table setup...
01 TABLES.
05 TBL-CRS-ENTRIES PIC S9(3) COMP-3 VALUE 5.
05 TBL-CRS-VALUES PIC X(4) OCCURS 10 TIMES.
05 CRS-TBL REDEFINES TBL-CRS-VALUES
PIC X(8) OCCURS 5 TIMES.
05 SUB-1 PIC S9(3) COMP-3 VALUE 1.
05 SUB-2 PIC S9(3) COMP-3 VALUE 1.
& here is the code that checks for duplicates
PERFORM VARYING SUB-1 FROM 1 BY 1 UNTIL SUB-1 > TBL-CRS-ENTRIES
PERFORM VARYING SUB-2 FROM 1 BY 1 UNTIL SUB-2 > SUB-1 - 1
IF CRS-TBL(SUB-1) = CRS-TBL(SUB-2)
*if there is a match it should change the colour to red.
* for example a match at CRS1AC & CRS1BC match CRS3AC & CRS3BC
*this is my attempt at trying make the variable name.
MOVE DFHRED TO CRS(SUB-1)AC
MOVE DFHRED TO CRS(SUB-1)BC
MOVE DFHRED TO CRS(SUB-2)AC
MOVE DFHRED TO CRS(SUB-2)BC
PERFORM 999-DUPLICATE-RECORD
END-IF
END-PERFORM
END-PERFORM.
GOBACK.
So, if 'PSYC 1000' = 'PSYC 1000' & the name of those fields are..
'CRS1AC+CRS1BC = CRS3AC+CRS3BC' <--- these are the fields I want to change the color of.
I've researched this heavily & still cannot find a solution.
Hope this makes sense I know its all over the place, for further clarification please ask & if complete program code is required I can provide it.
No, it is not possible to do what you want how you want.
COBOL is a compiled language. What is relevant about that is that you cannot make up the names of identifiers (variables) at run-time. Once a COBOL program is compiled, that is it, no more changes to the source for that executable version.
Where to go then?
You say this is part of your MAP.
01 CRS1AC PIC X.
01 CRS1BC PIC X.
01 CRS2AC PIC X.
01 CRS2BC PIC X.
01 CRS3AC PIC X.
01 CRS3BC PIC X.
01 CRS4AC PIC X.
01 CRS4BC PIC X.
01 CRS5AC PIC X.
01 CRS5BC PIC X.
But, because of those level-numbers of 01 those aren't part of anything, except the SECTION they belong to within the DATA DIVISION.
So you need to show your full, actual, MAP.
There is not an especially cute way, so what you have to do is REDEFINES the entire MAP, with an OCCURS which represents each screen-line for this portion of the screen (or entire screen, depends on the design) and define those attribute bytes within the OCCURS item.
What is really exciting about this is getting it all to line-up, by hand.
Now your program.
Your loops are wrong. You execute the inner-loop five times for each iteration of the outer-loop. Which means you are doing far more comparisons than necessary.
This is unwieldy:
SUB-2 > SUB-1 - 1
For that line of code, this would be better:
SUB-2 EQUAL TO SUB-1
The fifth outer-iteration is not required at all, because there are no values to compare to other than those which have already been compared (so the result will be the same, so why bother?).
Consider changing the definition of the identifiers (variables) you are using as subscripts and your total of entries to BINARY or COMP or COMP-4 (they all mean the same thing).
Consider giving them more meaningful names than SUB-1, SUB-2. It will make the code "read" better, which always helps.
Here's your data-defintion:
01 TABLES.
05 TBL-CRS-ENTRIES PIC S9(3) COMP-3 VALUE 5.
05 TBL-CRS-VALUES PIC X(4) OCCURS 10 TIMES.
05 CRS-TBL REDEFINES TBL-CRS-VALUES
PIC X(8) OCCURS 5 TIMES.
05 SUB-1 PIC S9(3) COMP-3 VALUE 1.
05 SUB-2 PIC S9(3) COMP-3 VALUE 1.
Some other things to make things easier for yourself:
Don't code identifiers (variables) after an OCCURS. It doesn't greatly matter in itself when there is no DEPENDING ON on the OCCURS, but since it does matter for that, why not be consistent (consistency is great, because when you are looking for a problem and you find inconsistency, it tells something about the writer of that particular bit of code).
Don't REDEFINES items which are defined with OCCURS. Even if you are using an old compiler (either you've put incorrect code here, or you are doing that) that gives you at least a Caution message. Try an experiment. Show that definition to a colleague, and ask them "what does this actually do?" Then show to another. And a third. If they all immediately reply, accurately, what it does, then you have a site with outstanding knowledge. You haven't, so don't do that.
Don't make identifiers signed, unless they can contain negative values. Then the reader can look at the definition and know it can't contain a negative value. Don't fall for "oh, we do it for performance". Name the compiler and show the compile options, and I'll show you what it is "gaining", or losing.
Don't use VALUE clauses for initial values of identifiers used as subscripts. Set them to their initial value before you use them. Unless you have tortuous code setting the value at the end of the current processing so it is ready for the next processing, all you are doing is confusing the human-reader. If there is a VALUE clause, it should be necessary.
Do give everything a good, descriptive, name, if it is being used. If something does not need a name, use FILLER to define it (often).
Your definition could be done like this:
01 some-meaningful-name
05 TBL-CRS-ENTRIES BINARY PIC 9(4) VALUE 5.
05 also-meaningful BINARY PIC 9(4).
05 meaningful-also BINARY PIC 9(4).
05 another-meaningful-name.
10 FILLER OCCURS 10 TIMES.
15 TBL-CRS-VALUES PIC X(4).
05 FILLER REDEFINES another-meaningful-name.
10 FILLER OCCURS 5 TIMES.
15 CRS-TBL PIC X(8).
Source code is for two things: for the compiler to convert into executable code; for the human reader to understand what has been coded. The compiler does not care about formatting the code. So format the code for the human reader. Even little things help:
IF CRS-TBL(SUB-1) = CRS-TBL(SUB-2)
Vs
IF CRS-TBL ( W-ORIGINAL-ITEM )
EQUAL TO CRS-TBL ( W-NEW-ITEM )

JRecord - Handling duplicate columns in cobol copybook

I am using CopybookInputFormat on git https://github.com/tmalaska/CopybookInputFormat/ to generate hive table definition from COBOL copybook. My copybook has many Fillers (duplicate columns)
but it looks like JRecord is not handling duplicate column name correctly.
For below copybook, when I iterate columns, JRecord only prints second Filler and ignores first filler.
05 Birth-day PIC X(002)
05 Filler PIC X(008)
05 Birth-Month PIC X(002)
05 Filler PIC X(008)
05 Birth-year PIC X(004)
Does anyone have any solution for this? I know JRecord 0.80.6 onward is handling duplicate columns, but method getUniqueField("FIRST-NAME", "PRESIDENT") needs a group name.. but what if group has duplicate columns?
You should not need to import a Filler. In Cobol, a Filler can not be directly accessed. In Cobol a Filler say's Ignore this Field (or access it by another method).
A Cobol-Copybook is like a mask over a block of memory; A filler is used to skip some memory.
Data !##........##........## (# - accessible bytes; . - inaccessible bytes)
^ ^ ^
! ! !
Birth-day ---+ ! !
Filler ! !
Birth-Month -------------+ !
Filler !
Birth-year -----------------------+
A filler can be used to:
Mask fields that are no longer used.
Used mask data in a redefines
Create a simplified version of a copybook when you do not need all the fields
Initializing an output field i.e
05 report-Birth-date
10 dd pic 99.
10 filler pic '/'.
10 mm pic 99.
10 filler pic '/'.
10 yyyy pic 9999.
setting up Table data
05 codes.
10 code occurs 5 pic 99.
05 filler redefines codes pic x(10)
value '0204050612'.
I would ask the Cobol specialists where you work what is going on ???. Possible answers could be:
The filler data may not be needed.
You should be using a different more complicated Copybook.
The copybook should be updated with the Fillers given real names.

Create a TABLE in Cobol from a data structure?

I need to make a table out of the data structure below because I am not certain how many records that are each one line long will be in my input file. If I can make a table then I will be able to loop through them at a later time which is what I need to be able to do.
**Question: How to make a table out of the data structure before?
Part B: An array in Cobol is an OCCURS 100 TIMES
01 PRECORD.
05 JE.
10 NE PIC X(6) VALUE SPACES.
10 NM PIC X(2) VALUE SPACES.
05 FILL1 PIC X(16) VALUE SPACES.
05 TM PIC X(7) VALUE SPACES.
05 FILL2 PIC X(6) VALUE SPACES.
05 TT PIC X(7) VALUE SPACES.
05 FILL3 PIC X(13) VALUE SPACES.
05 TTY PIC X(10) VALUE SPACES.
05 FILL4 PIC X(13) VALUE SPACES.
01 PRECORD.
02 table-counter <-- this is used to hold the number of records
02 tTable occurs 300 times. <-- creates a table with three hundred occurences
05 JE.
10 NE PIC X(6) VALUE SPACES.
10 NM PIC X(2) VALUE SPACES.
05 FILL1 PIC X(16) VALUE SPACES.
05 TM PIC X(7) VALUE SPACES.
05 FILL2 PIC X(6) VALUE SPACES.
05 TT PIC X(7) VALUE SPACES.
05 FILL3 PIC X(13) VALUE SPACES.
05 TTY PIC X(10) VALUE SPACES.
05 FILL4 PIC X(13) VALUE SPACES.
The code above is update with how I think that table should look. The table has to have a counter at the top and then under than it will have to have a occur and how many times the table should occur.
The question that I was asking was how do you make a table like above actually a table I did not know that you had to create an Occurs and then put everything below that level of the occurs.
01 mytable.
02 counter...
02 tablevar occures 200 times.
05 var...
05 var2..
I just was not sure of the structure of a Cobol table. My question is what was the format of a Cobol data structure?
Your table-counter will need a PICture.
What PICture? Opinions vary.
There are three numeric formats which are useful for this, binary, packed-decimal, and display-numeric.
nn table-counter COMP/COMP-4/BINARY/COMP-5 PIC 9(4).
nn table-counter COMP-3/PACKED-DECIMAL PIC 9(3).
nn table-counter PIC 9(3).
The most efficient definition will be a binary one. If you use packed-decimal, the compiler will generate code to convert it to binary when used in comparison with anything you use for subscripting (except literals). When using display-numeric, the compiler will generate code to first convert to packed-decimal, then to binary.
Do these things matter with the speed of machines these days? Well, if they don't matter, may as well be efficient, but opinions do vary.
What size for the PICture? 9(4) for binary allows up to 9999 as a maximum value. You can code 999, but it does not give you much advantage (can't limit it to 300), so I go for optimal for the size (for a packed-decimal (COMP-3) it would be 999, as you don't get a fourth digit for nothing). Same if using display-numeric. Again, opinions vary.
If those are records, as Magoo has pointed out, you can't just add the count to the beginning of the record. You can't keep your table in the FILE SECTION under and FD. It will need to go into the WORKING-STORAGE SECTION.
Then there is the problem of keeping two structures "in step" for where they should match each other.
You probably have a copybook for the record-layout. The best is if you can parameterise the names in the copybook, so that you can use REPLACING on the COPY statement, allowing you to use the same copybook for the two different purposes. It would then be important that the copybook does not contain an 01-level. Again opinions vary on the inclusion of 01s in copybooks, but you may get lucky.
Which, given all the opinion, gets us to "well, what do I do?". What you do is the way they do it at your site. There should be documentation of local standards. This may not cover everything, you may have to seek the opinions of colleagues. If you all code in about the same way, it makes the code easier to understand.
Personally, I'd declare table-counter as a 77-level with a PIC 9(03). And you really should remove the VALUE clauses. Of course, this would need to be a WORKING-STORAGE entry, not an FD since the table isn't on the file. Other than that, what you've dome appears valid - but it's difficult to see what question you are asking.

Resources