How to use file descriptions in cobol? - cobol

I have seen in some of the tutorials that the records are declared only in file description(FD) and in some tutorials they have declared the record in Working storage section and used it.What is the difference between the both.
In some programs it is like this
FD STUDENT
01 FS-EMP-REC.
02 FS-EMP-ID PIC X(07).
02 FS-EMP-NAME PIC X(20).
02 FS-EMP-ACCT PIC X(06).
01 WS-EMP-REC.
02 WS-EMP-ID PIC X(07).
02 WS-EMP-NAME PIC X(20).
02 WS-EMP-ACCT PIC X(06).
In some tutorials it is (FD alone)
01 FS-EMP-REC.
02 FS-EMP-ID PIC X(07).
02 FS-EMP-NAME PIC X(20).
02 FS-EMP-ACCT PIC X(06).
What is the difference?

It can be a question of coding style. Some people just always use READ ... INTO ... or do a MOVE of the 01 under the FD to an 01 in the WORKING-STORAGE. Often the 01 in the FILE SECTION will just be defined with an elementary FILLER to describe the length of the input record.
Sometimes there is a specific need to do this, if the particular COBOL being used limits the use of the data in the FD (in Enterprise COBOL you can't SET an address for something in the FILE SECTION, and DB2 requires a known address, so can't be in the FILE SECTION, for instance).
People tend to think it is "safer" to use the WORKING-STORAGE, but this is not the case. People also think it easier to locate information in the WORKING-STORAGEwhen a program fails.
The READ ... INTO ... requires an extra transfer of the data, so will be "slower", but that is only a problem in extreme situations.
You'll see both in programs, as you already have done, and there is no hard-and-fast answer as to why one program uses on, and another the other. Mostly it will just make no difference at all.
With READ ... INTO ... the record will still also be available in the FILE SECTION.
Unless necessary, I don't use READ ... INTO ... myself, but many people think programs won't work properly if you don't use it :-)
Just be aware of the two different ways, and use the way that those you are coding with use.

Related

What does "$CICS ON" in a legacy IBM COBOL program mean?

I have some IBM COBOL of 2006 vintage. It contains "$CICS ON" and "$CICS OFF". I'm generally familiar with IBM COBOL "EXEC CICS" statements and directives, but I've never seen this pair.
What do these commands do, and where are they documented (IBM reference manual name would be ideal answer)? Searching the web didn't show an obvious result.
COBOL program fragment below:
000750 01 WG-YOB.
000760 05 FILLER PIC X(4).
000770 05 WX-YOB PIC X(2).
000780$CICS ON.
000790$CICS OFF.
000800$COPY CMPLDBF.
000810$COPY CMPLDBH.
000820 LINKAGE SECTION.
000830 01 DFHCOMMAREA.
000840 COPY COMMAREA.
000850 PROCEDURE DIVISION.
EDIT: This is a code base of about 1000 programs ~~ 450K SLOC. The only $ commands I find across this entire code base are:
$CICS ON.
$CICS OFF.
$COPY <filename>.
$BLOCK.
$BlOCKS.
If it helps, the copy libs referenced by $COPY contain nonstandard COBOL declarations (note "COMMBLOCK" and "FORM" starting in column 7)
000100COMMBLOCK OF HCPDSDB.
000110 01 HCPDSDB-DB.
000120 05 RECORD-NAME.
000130 05 RETURN-KODE.
000140 05 FREE.
000150 05 LAST-RECORD-FLAG.
000160 05 PASSWD.
000170 05 NO-OF-RECORDS.
...
000380FORM YYMMDD.
000390 05 C4-RED REDEFINES C4.
000400 07 C4-YY PIC 99.
000410 07 C4-MM PIC 99.
000420 07 C4-DD PIC 99.
000430 05 C5 PIC 9(11).
000440 05 C6 PIC 9(6).
Converting comment to an answer at OP request.
May be System 2000 references. V1 PDF from 20+ years ago includes $CICS ON and $CICS OFF directives. I cannot locate any V2 documentation that includes these directives.
From comments, OP found a more helpful manual at https://support.sas.com/resources/papers/proceedings/pdfs/s2k/PLEX.pdf which "appears to contain all the $xxxx directives mentioned" in the question.
I'm glad I was able to at least point in a helpful direction.

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 )

Can I write more than one structure in file?

I have FD
FD CR1
LABEL RECORD IS STANDARD
DATA RECORDS ARE FIRSTSTR, SECONDSTR, THIRDSTR.
and 3 structures
01 FIRSTSTR.
05 FIRSTFIVE PIC X(05).
05 SECONDFIVE PIC X(05).
01 SECONDSTR.
05 FIRSTTWO PIC X(02).
05 SECONDONE PIC X(01).
05 THIRDFOUR PIC X(04).
01 THIRDSTR.
05 FIRSTTHREE PIC X(03).
05 SECONDTHREE PIC X(03).
05 THIRDTHREE PIC X(03).
Can I write all info in file like this:
WRITE FIRSTSTR, SECONDSTR, THIRDSTR.
And read from file in 3 structures like this:
READ CR1 INTO FIRSTSTR, SECONDSTR, THIRDSTR AT END
Yes, you can write more than one type of record to a file, but no, you can't do it the way you want to.
The record-definitions (structures) under the FD all occupy the same storage, meaning the all the 01-levels start at the same byte address. The individual records cannot simultaneously contain different data.
This is called an "implicit REDEFINES".
The READ ... INTO ... is to read and at the same time copy the current record to the INTO item (singular) that you specify. The INTO item would usually be in the WORKING-STORAGE (although they could also be in LOCAL-STORAGE). It would be exotic to use the LINKAGE SECTION and very, very, odd to use something in the FILE SECTION as a target for a READ ... INTO....
You only READ one record at a time. Unless you file has a set, fixed-in-stone, sequence of different records, we'd usually READ the file, identify the record, and then process that particular type of record.
You can only specify one receiving item for READ ... INTO ... and only one source item for WRITE ... FROM ....

cobol move statement

say i have one 02 level variable as a part of cobybook (testcopy)
02 level-1-var
05 var-1
05 var-2
05 var-3
05 var-4
I use this copybook twice in my program.
01 usage-1.
copy testcopy.
01 usage-2.
copy testcopy.
I now want to move only 2 level 05 varibale of usage-1 to usage-2.
is there any way i can avoid 2 move statements?
and use something like
MOVE (var-2, var-3) of usage-1 TO
(var-2, var-3) of usage-2
I am new to cobol and was wondering if this could be done.. this can save a lot of move statements in my program..(improve performance)
No, not in standard COBOL, although some implementations may well have extensions for that sort of thing. If concise code is one of your requirements, I probably wouldn't have picked COBOL as the ideal language :-)
You probably need to do it in two:
move var-2 of usage-1 to var-2 of usage-2.
move var-3 of usage-1 to var-3 of usage-2.
If you're willing to do a bit of a change to your copybook, something like (a):
02 level-1-var
05 var-1
05 var-2-and-3
09 var-2
09 var-3
05 var-4
you may find that you can then do it with:
move var-2-and-3 of usage-1 to var-2-and-3 of usage-2.
(a) Obviously, I've just mirrored what you had in the question. You'll almost certainly need pic clauses on that data (and probably some more . characters).
This type of requirement is directly answered by the MOVE CORRESPONDING verb. MOVE CORRESPONDING takes group levels for its operands and moves like-named elementary items from one to the other, with several restrictions, which include like data classes (i.e., no mixed alphanumeric and numeric). The Fine Manual for your implementation contains all the restrictions.
If I remember correctly, MOVE CORRESPONDING is also an optional feature, so some compilers may not support it.
MOVE CORRESPONDING and your request is one of those things that triggers strong opinions in the COBOL world. Some say that you should use COPY REPLACING to generate unique data names and code all the MOVEs. Others say what you are doing is fine. My view is that "it depends". If it's a very simple program, I might take the MOVE CORRESPONDING path, but if there is significant business logic, then I would rather code everything.
Your best bet is to make your copybook such that you can have a "prefix" for each field, and then use REPLACING to provide different prefixes for the different COPY statements. Then you don't have to code OF/IN for all the fields, and it will make the program and the listing clearer.
Paxdiablo's is the neatest way to do what you want, although the reason you want to do it would have been interesting.
I'm surprised no-one mentioned "reference modification":
MOVE usage-1 ( 3 : 5 ) TO usage-2 ( 3 : 5)
Where 3 is the start position in the data and 5 is the length. I much prefer Paxdiablo's defintion to this.
Not so surprised that no-one suggested RENAMES.
01 A-TABLE.
05 A-T-1 PIC XX.
05 A-T-2 PIC X.
05 A-T-3 PIC 9.
05 A-T-4 PIC XXX.
05 A-T-5 PIC X(4).
66 A-TABLE-EXTRA RENAMES A-T-2 THRU A-T-3.
01 B-TABLE.
05 B-T-1 PIC XX.
05 B-T-2 PIC X.
05 B-T-3 PIC 9.
05 B-T-4 PIC XXX.
05 B-T-5 PIC X(4).
66 B-TABLE-EXTRA RENAMES B-T-2 THRU B-T-3.
MOVE A-TABLE-EXTRA TO B-TABLE-EXTRA
Like the MOVE CORRESPONDING, this is to be avoided (same reasons as my comment, plus no-one uses Level 66's, so no-one knows what they do).
Another way is by REDEFINES for each of your Level 01s, but why even go to that bother.

COBOL keyword REDEFINES

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.

Resources