Multiple functions in COBOL Linkage - cobol

I'm a C++/Python developer dabbling in COBOL, using open-cobol (cobc) on Linux.
I have several related functions which I would like to keep together. Normally, in COBOL, there is only one function per linkage section. What I currently do is
CALL "GEAR-FUNCS" USING DO-SOMETHING PARAMS...
and it executes the relevant function depending on the value of DO-SOMETHING. This reduces the number of files but it means that I have to pass the same number of parameters every time, even though some of them are not relevant.
The ultimate aim is to reduce the number of files on the compile line. I don't want to end up with one big main file and lots of little linkage files which I have to pull in every time. I would like to have just a few linkage files. Currently, the only methods I know of are either my function lookup or to create a library which contains all the linkage functions.
I was wondering whether there is a better way of doing this. For instance, is there something that will allow multiple linkage sections or procedure divisions in a single source?

This is not an answer - the answer is in Can multiple Cobol subroutines be in the same modulehttps://stackoverflow.com/a/48949229/2041317. This is just a series of examples for reference. There are two functions defined - LN-FUNC and LN-OBJ-FUNC.
The COBOL-85 multiple program method
IDENTIFICATION DIVISION.
PROGRAM-ID. LN-FUNC.
DATA DIVISION.
LINKAGE SECTION.
77 VAR1 PIC 9(2).
77 VAR2 PIC 9(2).
77 RESULT PIC ZZ9.
PROCEDURE DIVISION USING VAR1, VAR2, RESULT.
COMPUTE RESULT = VAR1 + VAR2.
* This is the return statement
GOBACK.
END PROGRAM LN-FUNC.
********************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. LN-OBJ-FUNC.
DATA DIVISION.
LINKAGE SECTION.
01 VAR-OBJ.
02 OBJ-VAR1 PIC 9(2).
02 OBJ-VAR2 PIC 9(2).
77 RESULT PIC ZZ9.
PROCEDURE DIVISION USING VAR-OBJ, RESULT.
* Another function entry point
COMPUTE RESULT = OBJ-VAR1 + OBJ-VAR2.
* Alternative to GOBACK.
EXIT PROGRAM.
END PROGRAM LN-OBJ-FUNC.
Using nested programs. These need to be nested like
(AAA (BBB (CCC)))
not
(AAA (BBB) (CCC))
Example
IDENTIFICATION DIVISION.
PROGRAM-ID. NESTED.
PROCEDURE DIVISION.
DISPLAY "SURPRISE - THIS GOT EXECUTED?".
********************************************
* First nested linkage
********************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. LN-FUNC.
DATA DIVISION.
LINKAGE SECTION.
77 VAR1 PIC 9(2).
77 VAR2 PIC 9(2).
77 RESULT PIC ZZ9.
PROCEDURE DIVISION USING VAR1, VAR2, RESULT.
COMPUTE RESULT = VAR1 + VAR2.
* This is the return statement
GOBACK.
********************************************
* Second nested linkage
********************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. LN-OBJ-FUNC.
DATA DIVISION.
LINKAGE SECTION.
01 VAR-OBJ.
02 OBJ-VAR1 PIC 9(2).
02 OBJ-VAR2 PIC 9(2).
77 RESULT PIC ZZ9.
PROCEDURE DIVISION USING VAR-OBJ, RESULT.
* Another function entry point
COMPUTE RESULT = OBJ-VAR1 + OBJ-VAR2.
* Alternative to GOBACK.
EXIT PROGRAM.
END PROGRAM LN-OBJ-FUNC.
END PROGRAM LN-FUNC.
END PROGRAM NESTED.
Using entry
IDENTIFICATION DIVISION.
PROGRAM-ID. USE-ENTRY.
DATA DIVISION.
LINKAGE SECTION.
* For LN-FUNC
77 VAR1 PIC 9(2).
77 VAR2 PIC 9(2).
77 RESULT PIC ZZ9.
* For LN-OBJ-FUNC
01 VAR-OBJ.
02 OBJ-VAR1 PIC 9(2).
02 OBJ-VAR2 PIC 9(2).
PROCEDURE DIVISION.
* This never gets displayed
DISPLAY "Starting multi".
* This is a function entry point
ENTRY "LN-FUNC" USING VAR1, VAR2, RESULT.
COMPUTE RESULT = VAR1 + VAR2.
* This is the return statement
GOBACK.
* Another function entry point
ENTRY "LN-OBJ-FUNC" USING VAR-OBJ, RESULT.
COMPUTE RESULT = OBJ-VAR1 + OBJ-VAR2.
* Alternative return statement
EXIT PROGRAM.
END PROGRAM USE-ENTRY.

Related

COBOL: syntax error, unexpected SORT, expecting Identifier and continuation character expected

I just started using COBOL for my COBOL class and I don't know what's wrong with lines 9, 30, and 62. Hope you could help me. Thank you.
******************************************************************
* Author: Emil
* Date: 12/02/21
* Purpose: Sorting and Debugging
* Tectonics: cobc
******************************************************************
PROGRAM-ID. InputSort.
PROCEDURE DIVISION
Using SORT and INPUT PROCEDURE. The program accepts records
* from the user and RELEASEs them to the work file
* where they are sorted. This program
* allows student records to be entered in any order but
* produces a file sequenced on ascending StudentId.
ENVIRONMENT DIVISION
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT StudentFile ASSIGN TO "SORTSTUD.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT WorkFile ASSIGN TO "WORK.TMP".
DATA DIVISION.
FILE SECTION.
FD StudentFile.
01 StudentDetails PIC X(30).
* The StudentDetails record has the description shown below.
* But in this program we don't need to refer to any of the items in
* the record and so we have described it as PIC X(32)
* 01 StudentDetails
* 02 StudentId PIC 9(7).
* 02 StudentName.
* 03 Surname PIC X(8).
* 03 Initials PIC XX.
* 02 DateOfBirth.
* 03 YOBirth PIC 9(4).
* 03 MOBirth PIC 9(2).
* 03 DOBirth PIC 9(2).
* 02 CourseCode PIC X(4).
* 02 Gender PIC X.
SD WorkFile.
01 WorkRec.
02 WStudentId PIC 9(7).
02 FILLER PIC X(23).
PROCEDURE DIVISION.
Begin.
SORT WorkFile ON ASCENDING KEY WStudentId
INPUT PROCEDURE IS GetStudentDetails
GIVING StudentFile.
STOP RUN.
GetStudentDetails.
DISPLAY "Enter student details using template below."
DISPLAY "Enter no data to end.".
DISPLAY "Enter - StudId, Surname, Initials, YOB, MOB, DOB, Course, Gender"
DISPLAY "NNNNNNNSSSSSSSSIIYYYYMMDDCCCCG"
ACCEPT WorkRec.
PERFORM UNTIL WorkRec = SPACES
RELEASE WorkRec
ACCEPT WorkRec
END-PERFORM.
General note: Watch your periods (full stops). They mean something. In COBOL many of them are optional but some are not. Be consistent about where you put them. In the procedure division, this is especially important!
Line 8, PROCEDURE DIVISION. Okay, this is the first problem. The divisions are IDENTIFICATION, ENVIRONMENT, DATA and PROCEDURE, in that order. Having PROCEDURE DIVISION here is way out of order and was missing the required period. Perhaps you meant IDENTICATION DIVISION. but even then it should be the first statement but for comments.
Line 9 and following: Typically remarks such as these are proceeded by a REMARKS. heading, or make them all (including line 9) into comments.
Line 30: I don't see a problem with a comment. Did you mean some other line?
Line 62: I don't see a problem. What was the error message?
BUT your perform loop will either never start or never end because nothing inside of the loop (PERFORM through END-PERFORM) changes WorkRec. Perhaps you want add an additional ACCEPT statement inside of the loop, use the WITH TEST AFTER clause on the PERFORM statement and move the ACCEPT statement into the loop.

COBOL: Can a GDG file descriptor (FD) reference multiple generations?

I have a program which reads a GDG file and moves data to working storage. I am interested to know if it can be made to repeat this process for multiple generations of the GDG using a reference to the file definition. Perhaps there is a way to use subscripts on the file definition? My thought is there must be a method to move different file definitions into a reference variable from which to access the files.
Code Sample based on suggested, setenv solution
FILE-CONTROL.
SELECT DATAIN ASSIGN TO UT-S-DATAIN.
DATA DIVISION.
FILE-SECTION.
FD DATAIN
BLOCK CONTAINS 0 RECORDS
RECORD CONTAINS 133 CHARACTERS
LABEL RECORDS ARE STANDARD
DATA RECORD IS DATA-REC.
01 DATA-REC PIC X(133).
WORKING-STORAGE SECTION.
01 ENV-VARS.
02 ENV-NAME PIC X(9).
02 ENV-VALUE PIC X(100).
02 ENV-OVERWRITE PIC S9(8) COMPUTATIONAL VALUE 1.
PROCEDURE DIVISION.
MOVE Z"DATAIN" TO ENV-NAME
MOVE Z"DSN(PROGRAMMER.TEST.GDGFILE(-1)),SHR" TO ENV-VALUE
MOVE 1 TO ENV-OVERWRITE
CALL "setenv" USING ENV-NAME ENV-VALUE ENV-OVERWRITE.
Notes
Pay special attention when moving DSN value to ENV-VALUE. On my first swing I left out the closing parentheses, most likely because of JCL muscle memory.
Be sure to empty out your DD statement in JCL/Step.
In mainframe COBOL, the FD refers to a SELECT which refers to a DD statement attached to the EXEC PGM statement for your program in the invoking JCL. The DD statement may refer to one or many GDGs. This is determined at compile time.
What I think you are asking for is dynamic allocation of a file at runtime. There are a couple of ways to accomplish that, one is BPXWDYN.
Identification Division.
Program-ID. SOMETEST.
Environment Division.
Input-Output Section.
File-Control.
Select MY-FILE Assign SYSUT1A.
Data Division.
File Section.
FD MY-FILE
Record 80
Block 0
Recording F.
01 MY-FILE-REC PIC X(080).
Working-Storage Section.
01 CONSTANTS.
05 BPXWDYN-PGM PIC X(008) VALUE 'BPXWDYN '.
05 ALCT-LIT-PROC PIC X(035)
VALUE 'ALLOC FI(SYSUT1A) SHR MSG(WTP) DSN('.
05 FREE-LIT-PROC PIC X(016)
VALUE 'FREE FI(SYSUT1A)'.
05 A-QUOTE PIC X(001) VALUE "'".
01 WORK-AREAS.
05 WS-DSN PIC X(044) VALUE 'MY.GDG.BASE'.
05 WS-GDG-NB PIC 999 VALUE ZEROS.
05 BPXWDYN-PARM.
10 PIC S9(004) COMP-5 VALUE +100.
10 BPXWDYN-PARM-TXT PIC X(100).
Procedure Division.
* Construct the allocation string for BPXWDYN.
MOVE SPACES TO BPXWDYN-PARM-TXT
STRING
ALCT-LIT-PROC
DELIMITED SIZE
WS-DSN
DELIMITED SPACE
'(-'
DELIMITED SIZE
WS-GDG-NB
DELIMITED SIZE
')'
DELIMITED SIZE
INTO
BPXWDYN-PARM-TXT
END-STRING
CALL BPXWDYN-PGM USING
BPXWDYN-PARM
END-CALL
IF RETURN-CODE = 0
CONTINUE
ELSE
[error handling]
END-IF
[file I/O with MY-FILE]
MOVE SPACES TO BPXWDYN-PARM-TXT
MOVE FREE-LIT-PROC TO BPXWDYN-PARM-TXT
CALL BPXWDYN-PGM USING
BPXWDYN-PARM
END-CALL
IF RETURN-CODE = 0
CONTINUE
ELSE
[error handling]
END-IF
GOBACK.
This is just freehand, so there may be a syntax error, but I hope I've made the idea clear.
There is another technique, using the C RTL function setenv, documented by IBM here. It looks like it might be simpler but I've never done it that way.

Edit an alpha variable Cobol '12.3' to '12,30 '

How does Cobol to transform a variable of this format 1234,5 to 0000000001234,50.
01 VAR1 X(16) '1234,5'
01 VAR2 X(16)
01 VAROUT REDEFINES VAR2
03 VAROUT-INT X(13)
03 VAROUT-PNT X(01)
03 VAROUT-DEC X(02)
STRING VAR1 DELIMITED BY ',' INTO VAR-INT
I have used one of the general methods of editing a PICTURE clause - Simple Insertion editing - to achieve the expected result.
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO-WORLD.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-A PIC X(16) VALUE '1234,5'.
01 WS-B PIC 9999999999999,90.
PROCEDURE DIVISION.
MOVE WS-A TO WS-B.
DISPLAY WS-B.
STOP RUN.
Result:
0000000001234,50
This is the simplest way I know.
identification division.
program-id. dpic.
environment division.
configuration section.
special-names.
decimal-point is comma.
data division.
working-storage section.
1 var1 pic x(16) value "1234,5".
1 var2.
2 var2-num pic 9(13),99.
procedure division.
begin.
display var1
move function numval (var1) to var2-num
display var2
stop run
.
The result is:
1234,5
0000000001234,50

saving output in a file using COBOL language

I need help writing a small program in COBOL.
I wrote this piece of code:
IDENTIFICATION DIVISION.
PROGRAM-ID. CallC.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 INITBUF PIC X(10).
01 SHOWBUF PIC X(10).
01 BUF USAGE IS POINTER.
01 NUM PIC 9(10).
PROCEDURE DIVISION.
MOVE 10 to NUM.
CALL "getBuffer" USING BY VALUE NUM RETURNING BUF.
CALL "initBuffer" USING BY VALUE BUF RETURNING INITBUF.
CALL "showBuffer" USING BY VALUE BUF RETURNING SHOWBUF.
DISPLAY SHOWBUF.
STOP RUN.
How do I go about writing the DISPLAY result to a file?
Bill. Declare the file as in the example below. Move whatever you want to output into the output variable then Write outputVar
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT PARM-OUT ASSIGN TO PARMOUT.
*************************************************
DATA DIVISION.
FILE SECTION.
FD PARM-OUT
RECORDING MODE F.
01 PARMIN-REC.
05 PSID-IN PIC 9(09).
05 PCID-IN PIC 9(08).
05 IN-PCIDSEQ PIC 9(03).

Read a file with three records, only one of expected records output

IDENTIFICATION DIVISION.
PROGRAM-ID. PROGRAM1.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT EMP-GRADE ASSIGN TO 'input.txt'
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS WS-STATUS.
DATA DIVISION.
FILE SECTION.
FD EMP-GRADE.
01 NEWFILE.
05 FS-EMPID PIC 9(5).
05 FS-NAME PIC A(5).
05 FS-STREAM PIC X(5).
05 FS-GRADE PIC A(1).
05 FILLER PIC X(64).
WORKING-STORAGE SECTION.
01 WS-EOF PIC A(1) VALUE "N".
01 WS-STATUS PIC X(2).
PROCEDURE DIVISION.
MAIN-PARA.
OPEN INPUT EMP-GRADE.
PERFORM PARA1 THRU PARA1-EXIT UNTIL WS-EOF="Y".
CLOSE EMP-GRADE.
STOP RUN.
MAIN-PARA-EXIT.
EXIT.
PARA1.
READ EMP-GRADE
AT END MOVE "Y" TO WS-EOF
NOT AT END
IF FS-GRADE='A'
DISPLAY FS-EMPID , FS-NAME , FS-STREAM , FS-GRADE
END-IF
END-READ.
PARA1-EXIT.
EXIT.
input provided:
1234 sita comp A
2345 tina main B
5689 riya math A
but the output is coming :
1234 sita comp A
It is reading only the first record.
As Brian Tiffin is hinting at in the comments, it is your data which is the problem.
This:
05 FILLER PIC X(64).
Means that your records should be 64 bytes longer than they are.
If you have a fixed-length record, or only fixed-length records, under an FD, then the data all have to be the same length, and equal to what you have defined in your program.
It means, and behaviour depends on compiler, you only have one record as far as the COBOL program is concerned.
A good way to spot such things is to always count your input records, and count your output records, and records which should not be selected for output. You can then easily tell if anything has fallen between a crack.
Leaving that aside, here's your program with some adjustments:
IDENTIFICATION DIVISION.
PROGRAM-ID. PROGRAM1.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT EMP-GRADE ASSIGN TO 'input.txt'
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS WS-STUDENT-GRADE-STATUS.
DATA DIVISION.
FILE SECTION.
FD EMP-GRADE.
01 NEWFILE.
05 FS-EMPID PIC 9(5).
05 FS-NAME PIC X(5).
05 FS-STREAM PIC X(5).
05 FS-GRADE PIC X(1).
05 FILLER PIC X(64).
WORKING-STORAGE SECTION.
01 WS-STUDENT-GRADE-STATUS PIC X(2).
88 END-OF-STUDENT-GRADE-FILE VALUE "10".
88 ERROR-ON-STUDENT-GRADE-FILE VALUE ZERO.
PROCEDURE DIVISION.
OPEN INPUT EMP-GRADE
* perform a paragraph to check FILE STATUS field is zero, using an 88.
PERFORM PRIMING-READ
PERFORM PROCESS-STUDENT-GRADE-FILE
UNTIL END-OF-STUDENT-GRADE-FILE
CLOSE EMP-GRADE
* perform a paragraph to check FILE STATUS field is zero, using an 88.
GOBACK
.
PRIMING-READ.
PERFORM READ-STUDENT-GRADE
.
READ-STUDENT-GRADE.
READ EMP-GRADE
* perform a paragraph to check FILE STATUS field is zero, using an 88.
.
PROCESS-STUDENT-GRADE-FILE.
IF FS-GRADE='A'
* To see the problem with your data, DISPLAY the 01-level
DISPLAY NEWFILE
DISPLAY FS-EMPID
FS-NAME
FS-STREAM FS-GRADE
END-IF
PERFORM READ-STUDENT-GRADE
.
If you use the FILE STATUS field, you should check it. Since you use it, you can use it to check for end-of-file without the AT END. If you use a "priming read" you don't need the AT END/NOT AT END tangle. If you code the minimum of full-stops/periods in the PROCEDURE DIVISION, you won't have a problem with them. Commas are never needed, so don't use them. Format your program for human readability. Use good descriptive names for everything. The THRU on a PERFORM invites the use of GO TO. As a learning, avoid the invitation.
If your class itself enforces particular ways to code COBOL, you'll have to use those ways. If so, I'd suggest you do both. The first couple of times at least, submit both to your tutor. Even if they tell you not to do that, continue doing dual examples when given tasks (just don't submit them any more). There is no reason for you to start off with bad habits.
Keep everything simple. If your code looks bad, make it look good through simplification and formatting.
Remember also that COBOL is all about fixed-length stuff. Get's us back to your original problem.

Resources