Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 93

Beginners programs

Shortest.cbl

This example program is almost the shortest COBOL program we can have. We could make it shorter still
by leaving out the STOP RUN.

$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. ShortestProgram.

PROCEDURE DIVISION.
DisplayPrompt.
DISPLAY "I did it".
STOP RUN.
Accept.cbl

The program accepts a simple student record from the user and displays the individual fields. Also shows
how the ACCEPT may be used to get and DISPLAY the system time and date.

$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. AcceptAndDisplay.
AUTHOR. Michael Coughlan.
* Uses the ACCEPT and DISPLAY verbs to accept a student record
* from the user and display some of the fields. Also shows how
* the ACCEPT may be used to get the system date and time.

* The YYYYMMDD in "ACCEPT CurrentDate FROM DATE YYYYMMDD."


* is a format command that ensures that the date contains a
* 4 digit year. If not used, the year supplied by the system will
* only contain two digits which may cause a problem in the year 2000.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 StudentDetails.
02 StudentId PIC 9(7).
02 StudentName.
03 Surname PIC X(8).
03 Initials PIC XX.
02 CourseCode PIC X(4).
02 Gender PIC X.

* YYMMDD
01 CurrentDate.
02 CurrentYear PIC 9(4).
02 CurrentMonth PIC 99.
02 CurrentDay PIC 99.

* YYDDD
01 DayOfYear.
02 FILLER PIC 9(4).
02 YearDay PIC 9(3).

1
* HHMMSSss s = S/100
01 CurrentTime.
02 CurrentHour PIC 99.
02 CurrentMinute PIC 99.
02 FILLER PIC 9(4).

PROCEDURE DIVISION.
Begin.
DISPLAY "Enter student details using template below".
DISPLAY "Enter - ID,Surname,Initials,CourseCode,Gender"
DISPLAY "SSSSSSSNNNNNNNNIICCCCG".
ACCEPT StudentDetails.
ACCEPT CurrentDate FROM DATE YYYYMMDD.
ACCEPT DayOfYear FROM DAY YYYYDDD.
ACCEPT CurrentTime FROM TIME.
DISPLAY "Name is ", Initials SPACE Surname.
DISPLAY "Date is " CurrentDay SPACE CurrentMonth SPACE CurrentYear.
DISPLAY "Today is day " YearDay " of the year".
DISPLAY "The time is " CurrentHour ":" CurrentMinute.
STOP RUN.
Multiplier.cbl

Accepts two single digit numbers from the user, multiplies them together and displays the result.

$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. Multiplier.
AUTHOR. Michael Coughlan.
* Example program using ACCEPT, DISPLAY and MULTIPLY to
* get two single digit numbers from the user and multiply them together

DATA DIVISION.

WORKING-STORAGE SECTION.
01 Num1 PIC 9 VALUE ZEROS.
01 Num2 PIC 9 VALUE ZEROS.
01 Result PIC 99 VALUE ZEROS.

PROCEDURE DIVISION.
DISPLAY "Enter first number (1 digit) : " WITH NO ADVANCING.
ACCEPT Num1.
DISPLAY "Enter second number (1 digit) : " WITH NO ADVANCING.
ACCEPT Num2.
MULTIPLY Num1 BY Num2 GIVING Result.
DISPLAY "Result is = ", Result.
STOP RUN.

Selection and Interation

2
IterIf.cbl

An example program that implements a primative calculator. The calculator only does additions and
multiplications.
 

$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. Iteration-If.
AUTHOR. Michael Coughlan.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 Num1 PIC 9 VALUE ZEROS.
01 Num2 PIC 9 VALUE ZEROS.
01 Result PIC 99 VALUE ZEROS.
01 Operator PIC X VALUE SPACE.

PROCEDURE DIVISION.
Calculator.
PERFORM 3 TIMES
DISPLAY "Enter First Number : " WITH NO ADVANCING
ACCEPT Num1
DISPLAY "Enter Second Number : " WITH NO ADVANCING
ACCEPT Num2
DISPLAY "Enter operator (+ or *) : " WITH NO ADVANCING
ACCEPT Operator
IF Operator = "+" THEN
ADD Num1, Num2 GIVING Result
END-IF
IF Operator = "*" THEN
MULTIPLY Num1 BY Num2 GIVING Result
END-IF
DISPLAY "Result is = ", Result
END-PERFORM.
STOP RUN.

Conditions.cbl
An example program demonstrating the use of Condition Names (level 88's).
 
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. Conditions.
AUTHOR. Michael Coughlan.
* An example program demonstrating the use of
* condition names (level 88's).
* The EVALUATE and PERFORM verbs are also used.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 Char PIC X.
88 Vowel VALUE "a", "e", "i", "o", "u".
88 Consonant VALUE "b", "c", "d", "f", "g", "h"
"j" THRU "n", "p" THRU "t", "v" THRU "z".
88 Digit VALUE "0" THRU "9".

3
88 ValidCharacter VALUE "a" THRU "z", "0" THRU "9".

PROCEDURE DIVISION.
Begin.
DISPLAY "Enter lower case character or digit. No data ends.".
ACCEPT Char.
PERFORM UNTIL NOT ValidCharacter
EVALUATE TRUE
WHEN Vowel DISPLAY "The letter " Char " is a vowel."
WHEN Consonant DISPLAY "The letter " Char " is a consonant."
WHEN Digit DISPLAY Char " is a digit."
WHEN OTHER DISPLAY "problems found"
END-EVALUATE
END-PERFORM
STOP RUN.

Perform1.cbl
An example program demonstrating how the first format of the PERFORM may be used to change the flow
of control through a program.
 $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. PerformFormat1.
AUTHOR. Michael Coughlan.
* Illustrates how the first format of the PERFORM may
* be used to change the flow of control through a program.
* Use the output of this program to get an understanding of how
* this format of the PERFORM works.

PROCEDURE DIVISION.
TopLevel.
DISPLAY "In TopLevel. Starting to run program"
PERFORM OneLevelDown
DISPLAY "Back in TopLevel.".
STOP RUN.

TwoLevelsDown.
DISPLAY ">>>>>>>> Now in TwoLevelsDown."
PERFORM ThreeLevelsDown.
DISPLAY ">>>>>>>> Back in TwoLevelsDown.".

OneLevelDown.
DISPLAY ">>>> Now in OneLevelDown"
PERFORM TwoLevelsDown
DISPLAY ">>>> Back in OneLevelDown".

ThreeLevelsDown.
DISPLAY ">>>>>>>>>>>> Now in ThreeLevelsDown".

Perform2.cbl

Demonstrates the second format of the PERFORM. The PERFORM..TIMES may be used to execute a
block of code x number of times.

4
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. PerformFormat2.
AUTHOR. Michael Coughlan.
* Demonstrates the second format of the PERFORM.
* The PERFORM..TIMES format executes a block of code x
* number of times.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 NumofTimes PIC 9 VALUE 5.

PROCEDURE DIVISION.
Begin.
DISPLAY "Starting to run program"
PERFORM 3 TIMES
DISPLAY ">>>>This is an in line Perform"
END-PERFORM
DISPLAY "Finished in line Perform"
PERFORM OutOfLineEG NumOfTimes TIMES
DISPLAY "Back in Begin. About to Stop".
STOP RUN.

OutOfLineEG.
DISPLAY ">>>> This is an out of line Perform".

Perform3.cbl
Demonstrates how the PERFORM..UNTIL (third format) may be used to process a stream of values where
the length of the stream cannot be determined in advance (although in this case there is a set maximum
number of values in the stream).

  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. PerformFormat3.
AUTHOR. Michael Coughlan.
* Demonstrates the use of the PERFORM..UNTIL.
* The PERFORM..UNTIL is most often used to process a
* stream of data where the length of the stream can not
* be determined in advance.
* Pay particular attention to the way the number stream is
* processed in this program.
* Note how the ON SIZE ERROR can be used to detect when the
* result of a computation is tot big for the data-item intended
* to hold it.
* The INITIALIZE verb sets a data-item to its initial or
* starting value.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 IterCount PIC 99 VALUE ZEROS.
88 MaxCountReached VALUE 99.
01 UserInput PIC 99 VALUE ZEROS.
88 EndOfUserInput VALUE ZEROS.
01 RunningTotal PIC 999 VALUE ZEROS.

5
01 AverageValue PIC 99 VALUES ZEROS.

PROCEDURE DIVISION.
Begin.
PERFORM UNTIL IterCount = 5
DISPLAY "IterCount = " IterCount
ADD 1 TO IterCount
END-PERFORM
DISPLAY "Finished in line Perform."

INITIALIZE Itercount

DISPLAY "Enter a stream of up to 99 numbers."


DISPLAY "Each number must be in the range 1-99. Enter 0 to stop."
DISPLAY "Enter number :- " WITH NO ADVANCING
ACCEPT UserInput
PERFORM GetUserInput UNTIL EndOfUserInput OR MaxCountReached

DISPLAY "The final total is - " RunningTotal


DISPLAY "The final count is - " IterCount
COMPUTE AverageValue = RunningTotal / IterCount
DISPLAY "The average value entered is - " AverageValue
STOP RUN.

GetUserInput.
ADD UserInput TO RunningTotal
ON SIZE ERROR DISPLAY "Error - new total too large for data-item."
NOT ON SIZE ERROR ADD 1 TO IterCount END-ADD
END-ADD
DISPLAY "Total so far is - " RunningTotal
DISPLAY "Count so far is - " IterCount
DISPLAY "Enter number :- " WITH NO ADVANCING
ACCEPT UserInput.

Perform4.cbl
Demonstrates how the PERFORM..VARYING and the PERFORM..VARYING..AFTER (fourth format)
may be used for counting iteration. Also introduces the WITH TEST BEFORE and WITH TEST AFTER
phrases.

  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. PerformFormat4.
AUTHOR. Michael Coughlan.
* An example program using the PERFORM..VARYING format.
* Pay particular attention to the values produced by the
* WITH TEST BEFORE and WITH TEST AFTER loops.
* Note that the PERFORM within a PERFORM produces the same
* results as the PERFORM..VARYING..AFTER

DATA DIVISION.
WORKING-STORAGE SECTION.
01 LoopCount PIC 9 VALUE ZEROS.
01 LoopCount2 PIC S9 VALUE ZEROS.

6
PROCEDURE DIVISION.
Begin.
DISPLAY "Start WHILE Iteration of LoopBody"
PERFORM LoopBody WITH TEST BEFORE
VARYING LoopCount FROM 1 BY 2
UNTIL LoopCount GREATER THAN 5.
DISPLAY "Finished WHILE iteration. LoopCount = " LoopCount.

DISPLAY "Start REPEAT Iteration of LoopBody"


PERFORM LoopBody WITH TEST AFTER
VARYING LoopCount FROM 1 BY 2
UNTIL LoopCount GREATER THAN 5.
DISPLAY "Finished REPEAT iteration. LoopCount = " LoopCount.

DISPLAY "Start inline loops"


PERFORM VARYING LoopCount FROM 1 BY 1
UNTIL LoopCount GREATER THAN 4
PERFORM VARYING LoopCount2 FROM 5 BY -2
UNTIL LoopCount2 LESS THAN ZERO
DISPLAY "InLine loop " WITH NO ADVANCING
DISPLAY "LoopCount = " LoopCount " LoopCount2 = " LoopCount2
END-PERFORM
END-PERFORM.
DISPLAY "Finished inline loops".

DISPLAY "Start PERFORM VARYING..AFTER".


PERFORM LoopBody VARYING LoopCount FROM 1 BY 1
UNTIL LoopCount GREATER THAN 4
AFTER LoopCount2 FROM 5 BY -2
UNTIL LoopCount2 LESS THAN ZERO.
DISPLAY "Finished PERFORM VARYING..AFTER".
STOP RUN.

LoopBody.
DISPLAY "LoopBody " WITH NO ADVANCING
DISPLAY "LoopCount = " LoopCount " LoopCount2 = " LoopCount2.

MileageCount.cbl
Demonstrates how the PERFORM..VARYING and the PERFORM..VARYING..AFTER (fourth format)
may be used to simulate a mileage counter.
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. MileageCounter.
AUTHOR. Michael Coughlan.
* Simulates a mileage counter

DATA DIVISION.
WORKING-STORAGE SECTION.
01 Counters.
02 HundredsCount PIC 99 VALUE ZEROS.
02 TensCount PIC 99 VALUE ZEROS.
02 UnitsCount PIC 99 VALUE ZEROS.

7
01 DisplayItems.
02 PrnHunds PIC 9.
02 PrnTens PIC 9.
02 PrnUnits PIC 9.

PROCEDURE DIVISION.
Begin.
DISPLAY "Using an out-of-line Perform".
DISPLAY "About to start mileage counter simulation".
PERFORM CountMilage
VARYING HundredsCount FROM 0 BY 1 UNTIL HundredsCount > 9
AFTER TensCount FROM 0 BY 1 UNTIL TensCount > 9
AFTER UnitsCount FROM 0 BY 1 UNTIL UnitsCount > 9
DISPLAY "End of mileage counter simulation."

DISPLAY "Now using in-line Performs"


DISPLAY "About to start mileage counter simulation".
PERFORM VARYING HundredsCount FROM 0 BY 1 UNTIL HundredsCount > 9
PERFORM VARYING TensCount FROM 0 BY 1 UNTIL TensCount > 9
PERFORM VARYING UnitsCount FROM 0 BY 1 UNTIL UnitsCount > 9
MOVE HundredsCount TO PrnHunds
MOVE TensCount TO PrnTens
MOVE UnitsCount TO PrnUnits
DISPLAY PrnHunds "-" PrnTens "-" PrnUnits
END-PERFORM
END-PERFORM
END-PERFORM.
DISPLAY "End of mileage counter simulation."
STOP RUN.

CountMilage.
MOVE HundredsCount TO PrnHunds
MOVE TensCount TO PrnTens
MOVE UnitsCount TO PrnUnits
DISPLAY PrnHunds "-" PrnTens "-" PrnUnits.

Sequential Files
SeqWrite.cbl
Example program demonstrating how to create a sequential file from data input by the user.
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. SeqWrite.
AUTHOR. Michael Coughlan.
* Example program showing how to create a sequential file
* using the ACCEPT and the WRITE verbs.
* Note: In this version of COBOL pressing the Carriage Return (CR)
* without entering any data results in StudentDetails being filled
* with spaces.

ENVIRONMENT DIVISION.

8
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT StudentFile ASSIGN TO "STUDENTS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD StudentFile.
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.

PROCEDURE DIVISION.
Begin.
OPEN OUTPUT StudentFile
DISPLAY "Enter student details using template below. Enter no data to end."

PERFORM GetStudentDetails
PERFORM UNTIL StudentDetails = SPACES
WRITE StudentDetails
PERFORM GetStudentDetails
END-PERFORM
CLOSE StudentFile
STOP RUN.

GetStudentDetails.
DISPLAY "Enter - StudId, Surname, Initials, YOB, MOB, DOB, Course, Gender"
DISPLAY "NNNNNNNSSSSSSSSIIYYYYMMDDCCCCG"
ACCEPT StudentDetails.

SeqReadno88.cbl
An example program that reads a sequential file and displays the records. This version does not use level
88's to signal when the end of the file has been reached.
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. SeqReadNo88.
AUTHOR. Michael Coughlan.
* An example showing how to read a sequential file without
* using condition names.
* See SeqRead.CBL for the definitive example.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT StudentFile ASSIGN TO "STUDENTS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

9
DATA DIVISION.
FILE SECTION.
FD StudentFile.
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.

PROCEDURE DIVISION.
Begin.
OPEN INPUT StudentFile
READ StudentFile
AT END MOVE HIGH-VALUES TO StudentDetails
END-READ
PERFORM UNTIL StudentDetails = HIGH-VALUES
DISPLAY StudentId SPACE StudentName SPACE CourseCode SPACE YOBirth
READ StudentFile
AT END MOVE HIGH-VALUES TO StudentDetails
END-READ
END-PERFORM
CLOSE StudentFile
STOP RUN.

SeqRead.cbl
An example program that reads a sequential file and displays the records. This is the correct version which
uses the Condition Name (level 88) "EndOfFile"to signal when the end of the file has been reached
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. SeqRead.
AUTHOR. Michael Coughlan.
* An example program showing how to read a sequential file.
* This is the definitive example

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT StudentFile ASSIGN TO "STUDENTS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD StudentFile.
01 StudentDetails.
88 EndOfStudentFile VALUE HIGH-VALUES.
02 StudentId PIC 9(7).
02 StudentName.
03 Surname PIC X(8).

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

PROCEDURE DIVISION.
Begin.
OPEN INPUT StudentFile
READ StudentFile
AT END SET EndOfStudentFile TO TRUE
END-READ
PERFORM UNTIL EndOfStudentFile
DISPLAY StudentId SPACE StudentName SPACE CourseCode SPACE YOBirth
READ StudentFile
AT END SET EndOfStudentFile TO TRUE
END-READ
END-PERFORM
CLOSE StudentFile
STOP RUN.
SeqInsert.cbl
Demonstrates how to insert records into a sequential file from a file of transaction records. A new file is
created which contains the inserted records.
$ SET SOURCEFORMAT "FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. InsertRecords.
AUTHOR. Michael Coughlan.
* This program updates the Students.Dat file with insertions
* taken from the Transins.Dat file to create a new file
* - Students.New - which contains the inserted records.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT StudentRecords ASSIGN "STUDENTS.DAT"
ORGANIZATION IS LINE SEQUENTIAL
ACCESS MODE IS SEQUENTIAL.

SELECT TransRecords ASSIGN "TRANSINS.DAT"


ORGANIZATION IS LINE SEQUENTIAL
ACCESS MODE IS SEQUENTIAL.

SELECT NewStudentRecords ASSIGN "STUDENTS.NEW"


ORGANIZATION IS LINE SEQUENTIAL
ACCESS MODE IS SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD StudentRecords.
01 StudentRecord.
88 EndOfStudentFile VALUE HIGH-VALUES.
02 StudentID PIC X(7).

11
02 FILLER PIC X(23).

FD TransRecords.
01 TransRecord.
88 EndOfTransFile VALUE HIGH-VALUES.
02 TransStudentID PIC X(7).
02 FILLER PIC X(23).

FD NewStudentRecords.
01 NewStudentRecord PIC X(30).

PROCEDURE DIVISION.
BEGIN.
OPEN INPUT StudentRecords
OPEN INPUT TransRecords
OPEN OUTPUT NewStudentRecords

READ StudentRecords
AT END SET EndOfStudentFile TO TRUE
END-READ

READ TransRecords
AT END SET EndOfTransFile TO TRUE
END-READ

PERFORM UNTIL (EndOfStudentFile) AND (EndOfTransFile)


EVALUATE TRUE
WHEN (StudentID < TransStudentID)
WRITE NewStudentRecord FROM StudentRecord
READ StudentRecords
AT END SET EndOfStudentFile TO TRUE
END-READ

WHEN (StudentID > TransStudentID)


WRITE NewStudentRecord FROM TransRecord
READ TransRecords
AT END SET EndOfTransFile TO TRUE
END-READ

WHEN (StudentID = TransStudentID)


DISPLAY "Error - " TransStudentId " already exists in file"
READ TransRecords
AT END SET EndOfTransFile TO TRUE
END-READ
END-EVALUATE
END-PERFORM

CLOSE StudentRecords
CLOSE TransRecords
CLOSE NewStudentRecords
STOP RUN.

12
SeqRpt.cbl
This program reads records from the student file, counts the total number of student records in the file and
the number records for females and males. Prints the results in a very short report.
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. StudentNumbersReport .
AUTHOR. Michael Coughlan.

*INPUT The student record file Students.Dat Records in this file


* are sequenced on ascending Student Number.
*OUTPUT Shows the number of student records in the file and the
* number of records for males and females.
*PROCESSING For each record read;
* Adds one to the TotalStudents count
* IF the Gender is Male adds one to TotalMales
* IF the Gender is Female adds one to TotalFemales
* At end of file writes the results to the report file.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT StudentFile ASSIGN TO "STUDENTS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT ReportFile ASSIGN TO "STUDENTS.RPT"
ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD StudentFile.
01 StudentDetails.
88 EndOfStudentFile VALUE HIGH-VALUES.
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.
88 Male VALUE "M", "m".

FD ReportFile.
01 PrintLine PIC X(40).

WORKING-STORAGE SECTION.
01 HeadingLine PIC X(21) VALUE " Record Count Report".

01 StudentTotalLine.
02 FILLER PIC X(17) VALUE "Total Students = ".
02 PrnStudentCount PIC Z,ZZ9.

01 MaleTotalLine.

13
02 FILLER PIC X(17) VALUE "Total Males = ".
02 PrnMaleCount PIC Z,ZZ9.

01 FemaleTotalLine.
02 FILLER PIC X(17) VALUE "Total Females = ".
02 PrnFemaleCount PIC Z,ZZ9.

01 WorkTotals.
02 StudentCount PIC 9(4) VALUE ZERO.
02 MaleCount PIC 9(4) VALUE ZERO.
02 FemaleCount PIC 9(4) VALUE ZERO.

PROCEDURE DIVISION.
Begin.
OPEN INPUT StudentFile
OPEN OUTPUT ReportFile

READ StudentFile
AT END SET EndOfStudentFile TO TRUE
END-READ
PERFORM UNTIL EndOfStudentFile
ADD 1 TO StudentCount
IF Male ADD 1 TO MaleCount
ELSE ADD 1 TO FemaleCount
END-IF
READ StudentFile
AT END SET EndOfStudentFile TO TRUE
END-READ
END-PERFORM

PERFORM PrintReportLines

CLOSE StudentFile, ReportFile


STOP RUN.

PrintReportLines.
MOVE StudentCount TO PrnStudentCount
MOVE MaleCount TO PrnMaleCount
MOVE FemaleCount TO PrnFemaleCount

WRITE PrintLine FROM HeadingLine


AFTER ADVANCING PAGE
WRITE PrintLine FROM StudentTotalLine
AFTER ADVANCING 2 LINES
WRITE PrintLine FROM MaleTotalLine
AFTER ADVANCING 2 LINES
WRITE PrintLine FROM FemaleTotalLine
AFTER ADVANCING 2 LINES.

Sorting and Merging


InputSort.cbl

14
Uses the SORT and an INPUT PROCEDURE to accept records from the user and sort them on ascending
StudentId.
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. InputSort.
AUTHOR. Michael Coughlan.
* An example program using the SORT and an
* 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.

15
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.
MaleSort.cbl
Sorts the student masterfile (sorted on ascending Student Id) and produces a new file, sorted on ascending
student name, containing only the records of male students.
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. MaleSort.
AUTHOR. Michael Coughlan.
* Uses the the SORT and an INPUT PROCEDURE to read
* the student masterfile (sorted on ascending Student Id)
* and from it to produce a file containing only the records of
* male students sorted on ascending student name.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT StudentFile ASSIGN TO "STUDENTS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

SELECT MaleStudentFile ASSIGN TO "MALESTUDS.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT WorkFile ASSIGN TO "WORK.TMP".

DATA DIVISION.
FILE SECTION.
FD StudentFile.
01 StudentRec PIC X(30).
88 EndOfFile VALUE HIGH-VALUES.

FD MaleStudentFile.
01 MaleStudentRec PIC X(30).

SD WorkFile.
01 WorkRec.
02 FILLER PIC 9(7).
02 WStudentName PIC X(10).
02 FILLER PIC X(12).
02 WGender PIC X.
88 MaleStudent VALUE "M".

PROCEDURE DIVISION.
Begin.
SORT WorkFile ON ASCENDING KEY WStudentName

16
INPUT PROCEDURE IS GetMaleStudents
GIVING MaleStudentFile.
STOP RUN.

GetMaleStudents.
OPEN INPUT StudentFile
READ StudentFile
AT END SET EndOfFile TO TRUE
END-READ
PERFORM UNTIL EndOfFile
MOVE StudentRec TO WorkRec
IF MaleStudent
RELEASE WorkRec
END-IF
READ StudentFile
AT END SET EndOfFile TO TRUE
END-READ
END-PERFORM
CLOSE StudentFile.

Merge.cbl
Uses the MERGE to insert records from a transaction file into a sequential master file. .
$ SET SOURCEFORMAT "FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. MergeFiles.
AUTHOR. MICHAEL COUGHLAN.
* Example program demonstrating the use of the MERGE.
* The program merges the file Students.Dat and
* Transins.Dat to create a new file Students.New.
* A problem with using the MERGE for inserting records is that
* duplicate records are not detected.
* See the example program - SeqInsert.cbl - for a more traditional
* approach to inserting records in a Sequential File.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT StudentFile ASSIGN TO "STUDENTS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

SELECT InsertionsFile ASSIGN TO "TRANSINS.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT NewStudentFile ASSIGN TO "STUDENTS.NEW"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT WorkFile ASSIGN TO "WORK.TMP".

DATA DIVISION.
FILE SECTION.
FD StudentFile.
01 StudentRec PIC X(30).

FD InsertionsFile.

17
01 InsertionRec PIC X(30).

FD NewStudentFile.
01 NewStudentRec PIC X(30).

SD WorkFile.
01 WorkRec.
02 WStudentId PIC 9(7).
02 FILLER PIC X(23).

PROCEDURE DIVISION.
Begin.
MERGE WorkFile
ON ASCENDING KEY WStudentId
USING InsertionsFile, StudentFile
GIVING NewStudentFile.
STOP RUN.

AromaSalesRpt.Cbl
Exam paper model answer. A program is required to produce a summary sales report from an unsorted
sequential file containing the details of sales of essential and base oils to Aromamora customers.
Read the program specification first.

Introduction

Aromamora PLC is a company which sells essential oils to Aromatherapists, Health Shops, Chemists and
other mass users of essential oils. Every month, details of sales to these customers are gathered together
into a Sales File (SALES.DAT). A program is required which will produce a summary report from this file
showing the quantity (in millilitres) and value of the essential oils purchased by each customer.
Although Aromamora sells both base and essential oils, the report should summarize sales of essential oils
only. The report should be printed, sequenced on ascending Customer-Name.
 
The Sales File
The Sales File contains details of sales to all Aromamora customers. It is a validated,
unsorted sequential file. The records in the Sales File have the following description:
Field Type Length Value
Customer-Id 9 5 0-99999
Customer-Name X 20 -
Oil-Id X 3 B01-B10 OR E01-E30
Unit-Size 9 1 2/5/9
Units-Sold 9 3 1 - 999
 

Notes

Oil-Ids that contain an "E" represent essential oils. Those that contain a "B" represent base oils.
Unit-Size is the size in millilitres of the oil container purchased.
Units-Sold is the number of units purchased.
The quantity of oil sold for a particular sale is :- Unit-Size * Units-Sold.
The value of a sale is :- Qty-Sold * Cost-Per-Ml.
The Cost-Per-Ml is obtained from a 30 element pre-defined table of values (see the program outline for

18
details). The first element of the table contains the cost of oil E01, the second - oil E02 and so on. Each
element of the table has the following description :- PIC 99V99.

The Sales Report

Numeric values must be printed using comma insertion and either zero suppression or the floating currency
symbol. There is no need to worry about controlling the change of page, so no line count need be kept and
the headings never have to be printed again.
See the print specification below for more report format details.
Line 1-6 Report Heading. To be printed on the first page of the report only.
Line 8 Detail line showing the Customer-Name.
Preceded by one blank line.
Sales is a count of the number of essential oil sales records for the customer.
Qty-Sold is the sum of the quantities of this oil (in millilitres) sold to this customer.
Sales-Value is the value of the oils sold to this customer.
Line 21-25 Final totals. These are the sum of the Customer-Totals.
To be printed at the end of the report.
Preceded by 2 blank lines.

$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. CS4321-95-COBOL-EXAM.
AUTHOR. Michael Coughlan.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT Sales-File ASSIGN TO "SALES.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

SELECT Work-File ASSIGN TO "SORT.TMP".

SELECT Summary-Report ASSIGN TO "AROMASALES.RPT"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT Sorted-File ASSIGN TO "SORTSALE.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD Sales-File.
01 Sales-Rec.
88 End-Of-Sales-File VALUE HIGH-VALUES.
02 SF-Cust-Id PIC X(5).
02 SF-Cust-Name PIC X(20).
02 SF-Oil-Id.
03 FILLER PIC X.
88 Essential-Oil VALUE "E".
03 SF-Oil-Name PIC 99.
02 SF-Unit-Size PIC 99.
02 SF-Units-Sold PIC 999.

19
SD Work-File.
01 Work-Rec.
88 End-Of-Work-File VALUE HIGH-VALUES.
02 WF-Cust-Id PIC X(5).
02 WF-Cust-Name PIC X(20).
02 WF-Oil-Id.
03 FILLER PIC X.
03 WF-Oil-Num PIC 99.
02 WF-Unit-Size PIC 99.
02 WF-Units-Sold PIC 999.

FD Summary-Report.
01 Print-Line PIC X(64).

FD Sorted-File.
01 Sorted-Rec PIC X(33).

WORKING-STORAGE SECTION.

01 Oils-Table.
02 Oil-Cost-Values.
03 FILLER PIC X(40)
VALUE "0041003200450050002910250055003900650075".
03 FILLER PIC X(40)
VALUE "0080004400500063006500550085004812500065".
03 FILLER PIC X(40)
VALUE "0060005500670072006501250085006511150105".
02 FILLER REDEFINES Oil-Cost-VALUES.
03 OIL-COST PIC 99V99 OCCURS 30 TIMES.

01 Report-Heading-Line PIC X(44)


VALUE " AROMAMORA SUMMARY SALES REPORT".

01 Report-Heading-Underline.
02 FILLER PIC X(13) VALUE SPACES.
02 FILLER PIC X(32) VALUE ALL "-".

01 Topic-Heading-Line.
02 FILLER PIC BX(13) VALUE " CUSTOMER NAME".
02 FILLER PIC X(8) VALUE SPACES.
02 FILLER PIC X(10) VALUE "CUST-ID ".
02 FILLER PIC X(8) VALUE "SALES ".
02 FILLER PIC X(11) VALUE "QTY SOLD ".
02 FILLER PIC X(11) VALUE "SALES VALUE".

01 Cust-Sales-Line.
02 Prn-Cust-Name PIC X(20).
02 Prn-Cust-Id PIC BBB9(5).
02 Prn-Cust-Sales PIC BBBBBZZ9.
02 Prn-Qty-Sold PIC BBBBBZZ,ZZ9.
02 Prn-Sales-Value PIC BBBB$$$,$$9.99.

01 Total-Sales-Line.

20
02 FILLER PIC X(33) VALUE SPACES.
02 FILLER PIC X(19) VALUE "TOTAL SALES :".
02 Prn-Total-Sales PIC BBBBBBZZ,ZZ9.

01 Total-Qty-Sold-Line.
02 FILLER PIC X(33) VALUE SPACES.
02 FILLER PIC X(19) VALUE "TOTAL QTY SOLD :".
02 Prn-Total-Qty-Sold PIC BBBBBZZZ,ZZ9.

01 Total-Sales-Value-Line.
02 FILLER PIC X(33) VALUE SPACES.
02 FILLER PIC X(19) VALUE "TOTAL SALES VALUE :".
02 Prn-Total-Sales-Value PIC B$$$$,$$9.99.

01 Cust-Totals.
02 Cust-Sales PIC 999.
02 Cust-Qty-Sold PIC 9(5).
02 Cust-Sales-Value PIC 9(5)V99.

01 Final-Totals.
02 Total-Sales PIC 9(5) VALUE ZEROS.
02 Total-Qty-Sold PIC 9(6) VALUE ZEROS.
02 Total-Sales-Value PIC 9(6)V99 VALUE ZEROS.

01 Temp-Variables.
02 Sale-Qty-Sold PIC 99999.
02 Value-Of-Sale PIC 999999V99.
02 Prev-Cust-Id PIC X(5).

PROCEDURE DIVISION.
Produce-Summary-Report.
SORT Work-File ON ASCENDING WF-Cust-Name
INPUT PROCEDURE IS Select-Essential-Oils
OUTPUT PROCEDURE IS Print-Summary-Report.

STOP RUN.

Select-Essential-Oils.
OPEN INPUT Sales-File.
READ Sales-File
AT END SET End-Of-Sales-File TO TRUE
END-READ.

PERFORM UNTIL End-Of-Sales-File


IF Essential-Oil
RELEASE Work-Rec FROM Sales-Rec
END-IF
READ Sales-File
AT END SET End-Of-Sales-File TO TRUE
END-READ
END-PERFORM.

CLOSE Sales-File.

Print-Summary-Report.

21
OPEN OUTPUT Summary-Report.
OPEN OUTPUT Sorted-File.
WRITE Print-Line FROM Report-Heading-Line AFTER ADVANCING 1 LINE.
WRITE Print-Line FROM Report-Heading-Underline AFTER ADVANCING 1 LINE.
WRITE Print-Line FROM Topic-Heading-Line AFTER ADVANCING 3 LINES.

RETURN Work-File
AT END SET End-Of-Work-File TO TRUE
END-RETURN.

PERFORM Print-Customer-Lines UNTIL End-Of-Work-File

MOVE Total-Sales TO Prn-Total-Sales.


WRITE Print-Line FROM Total-Sales-Line AFTER ADVANCING 3 LINES.

MOVE Total-Qty-Sold TO Prn-Total-Qty-Sold.


WRITE Print-Line FROM Total-Qty-Sold-Line AFTER ADVANCING 2 LINES.

MOVE Total-Sales-Value TO Prn-Total-Sales-Value.


WRITE Print-Line FROM Total-Sales-Value-Line AFTER ADVANCING 2 LINES.

CLOSE Summary-Report, Sorted-File.

Print-Customer-Lines.
MOVE ZEROS TO Cust-Totals.
MOVE WF-Cust-Id TO Prn-Cust-Id, Prev-Cust-Id.
MOVE WF-Cust-Name TO Prn-Cust-Name.

PERFORM UNTIL WF-Cust-Id NOT = Prev-Cust-Id


WRITE Sorted-Rec FROM Work-Rec
ADD 1 TO Cust-Sales, Total-Sales

COMPUTE Sale-Qty-Sold = WF-Unit-Size * WF-Units-Sold


ADD Sale-Qty-Sold TO Cust-Qty-Sold, Total-Qty-Sold

COMPUTE Value-Of-Sale = Sale-Qty-Sold * Oil-Cost(WF-Oil-Num)


ADD Value-Of-Sale TO Cust-Sales-Value, Total-Sales-Value

RETURN Work-File
AT END SET End-Of-Work-File TO TRUE
END-RETURN
END-PERFORM.

MOVE Cust-Sales TO Prn-Cust-Sales.


MOVE Cust-Qty-Sold TO Prn-Qty-Sold.
MOVE Cust-Sales-Value TO Prn-Sales-Value.

WRITE Print-Line FROM Cust-Sales-Line AFTER ADVANCING 2 LINES.

CSISEmailDomain.Cbl
Exam paper model answer. A program is required which will produce a file, sorted on ascending email
domain, from the unsorted GraduateInfo file.
Read the program specification first.

22
Introduction

Aromamora PLC is a company which sells essential oils to Aromatherapists, Health Shops, Chemists and
other mass users of essential oils. Every month, details of sales to these customers are gathered together
into a Sales File (SALES.DAT). A program is required which will produce a summary report from this file
showing the quantity (in millilitres) and value of the essential oils purchased by each customer.
Although Aromamora sells both base and essential oils, the report should summarize sales of essential oils
only. The report should be printed, sequenced on ascending Customer-Name.
 

The Sales File

The Sales File contains details of sales to all Aromamora customers. It is a validated,
unsorted sequential file. The records in the Sales File have the following description:
Field Type Length Value
Customer-Id 9 5 0-99999
Customer-Name X 20 -
Oil-Id X 3 B01-B10 OR E01-E30
Unit-Size 9 1 2/5/9
Units-Sold 9 3 1 - 999
 

Notes

Oil-Ids that contain an "E" represent essential oils. Those that contain a "B" represent base oils.
Unit-Size is the size in millilitres of the oil container purchased.
Units-Sold is the number of units purchased.
The quantity of oil sold for a particular sale is :- Unit-Size * Units-Sold.
The value of a sale is :- Qty-Sold * Cost-Per-Ml.
The Cost-Per-Ml is obtained from a 30 element pre-defined table of values (see the program outline for
details). The first element of the table contains the cost of oil E01, the second - oil E02 and so on. Each
element of the table has the following description :- PIC 99V99.

The Sales Report

Numeric values must be printed using comma insertion and either zero suppression or the floating currency
symbol. There is no need to worry about controlling the change of page, so no line count need be kept and
the headings never have to be printed again.
See the print specification below for more report format details.
Line 1-6 Report Heading. To be printed on the first page of the report only.
Line 8 Detail line showing the Customer-Name.
Preceded by one blank line.
Sales is a count of the number of essential oil sales records for the customer.
Qty-Sold is the sum of the quantities of this oil (in millilitres) sold to this customer.
Sales-Value is the value of the oils sold to this customer.
Line 21-25 Final totals. These are the sum of the Customer-Totals.
To be printed at the end of the report.
Preceded by 2 blank lines.

$ SET SOURCEFORMAT"FREE"

23
IDENTIFICATION DIVISION.
PROGRAM-ID. CSISEmailDomain.
* CS4312-99-Exam.
AUTHOR. Michael Coughlan.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CountryFile ASSIGN TO "COUNTRYCODES.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

SELECT GraduateInfoFile ASSIGN TO "GRADINFO.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT WorkFile ASSIGN TO "WORK.TMP".

SELECT SortedDomainFile ASSIGN TO "SORTEDDOMAIN.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD CountryFile.
01 CountryRec PIC X(28).
88 EndOfCountryFile VALUE HIGH-VALUES.

FD GraduateInfoFile.
01 GradInfoRecGF.
88 EndOfGradFile VALUE HIGH-VALUES.
02 StudentNameGF PIC X(25).
02 GradYearGF PIC 9(4).
02 CourseCodeGF PIC 9.
88 CSISGraduate VALUE 1 THRU 5.
02 EmailAddrGF PIC X(28).
02 EmailDomainGF PIC X(20).
02 CountryCodeGF PIC XX.

FD SortedDomainFile.
01 GradInfoRecSF.
02 EmailDomainSF PIC X(20).
02 StudentNameSF PIC X(25).
02 GradYearSF PIC 9(4).
02 CourseNameSF PIC X(25).
02 CountryNameSF PIC X(26).

SD WorkFile.
01 WorkRec.
88 EndOfWorkFile VALUE HIGH-VALUES.
02 StudentNameWF PIC X(25).
02 GradYearWF PIC 9(4).
02 CourseCodeWF PIC 9.
02 EmailDomainWF PIC X(20).
02 CountryCodeWF PIC XX.

WORKING-STORAGE SECTION.

24
01 CourseTable.
02 CourseValues.
03 FILLER PIC X(25) VALUE "Computer Systems".
03 FILLER PIC X(25) VALUE "Grad. Dip. Computing".
03 FILLER PIC X(25) VALUE "Grad. Dip. Localisation".
03 FILLER PIC X(25) VALUE "Grad. Dip. Music".
03 FILLER PIC X(25) VALUE "Computing with French".
02 FILLER REDEFINES CourseValues.
03 CourseName PIC X(25) OCCURS 5 TIMES.

01 CountryTable.
02 Country OCCURS 243 TIMES INDEXED BY Cidx.
03 CountryCode PIC XX.
03 CountryName PIC X(26).

PROCEDURE DIVISION.
Begin.
SORT WorkFile ON ASCENDING KEY EmailDomainWF
INPUT PROCEDURE IS SelectCSISGraduates
OUTPUT PROCEDURE IS MakeEmailDomainFile.
STOP RUN.

SelectCSISGraduates.
OPEN INPUT GraduateInfoFile
READ GraduateInfoFile
AT END SET EndOfGradFile TO TRUE
END-READ
PERFORM UNTIL EndOfGradFile
IF CSISGraduate
MOVE StudentNameGF TO StudentNameWF
MOVE GradYearGF TO GradYearWF
MOVE CourseCodeGF TO CourseCodeWF
MOVE EmailDomainGF TO EmailDomainWF
MOVE CountryCodeGF TO CountryCodeWF
RELEASE WorkRec
ELSE
DISPLAY "Rejected - " StudentNameGF SPACE CourseCodeGF
END-IF
READ GraduateInfoFile
AT END SET EndOfGradFile TO TRUE
END-READ
END-PERFORM
CLOSE GraduateInfoFile.

MakeEmailDomainFile.
PERFORM LoadCountryTable.
OPEN OUTPUT SortedDomainFile
RETURN WorkFile
AT END SET EndOfWorkFile TO TRUE
END-RETURN
PERFORM UNTIL EndOfWorkFile
MOVE StudentNameWF TO StudentNameSF

25
MOVE GradYearWF TO GradYearSF
MOVE CourseName(CourseCodeWF) TO CourseNameSF
MOVE EmailDomainWF TO EmailDomainSF
SET Cidx TO 1
SEARCH Country
AT END MOVE "Code not found" TO CountryNameSF
WHEN CountryCode(Cidx) = CountryCodeWF
MOVE CountryName(Cidx) TO CountryNameSF
END-SEARCH
WRITE GradInfoRecSF
RETURN WorkFile
AT END SET EndOfWorkFile TO TRUE
END-RETURN
END-PERFORM
CLOSE SortedDomainFile.

LoadCountryTable.
OPEN INPUT CountryFile
READ CountryFile
AT END SET EndOfCountryFile TO TRUE
END-READ
PERFORM VARYING Cidx FROM 1 BY 1 UNTIL EndOfCountryFile
MOVE CountryRec TO Country(Cidx)
READ CountryFile
AT END SET EndOfCountryFile TO TRUE
END-READ
END-PERFORM.
CLOSE CountryFile.

BestSellers.Cbl
Exam paper model answer. The Folio Society is a Book Club that sells fine books to customers all over the
world. A program is required to print a list of the ten best selling books (by copies sold) in the Book Club.
Read the program specification first

Introduction

The Folio Society is a Book  Club that sells fine books to customers all over the world.  Each time a book is
sold the Book-Number, the Number-of-Copies and a one character field indicating the Sale-Status (Normal
Sale, Free Gift, Reduced Price (N,F,R)) is written to a Book-Sales-File. 
A program is required to print a list of the ten best selling books (by copies sold) in the Book Club from the
Book-Sales-File.  Only Normal Sale books should be considered.

Files

Book Master File

The Book Master File is a sequential file sequenced on ascending Book-Number.  The
records have the following description;

FIELD TYPE LENGTH VALUE

Book-Number 9 5 00001-99999

26
Book-Title X 25 -

Author-Name X 25 -

Book Sales File

The Book Sales File is not in any particular sequence but we are guaranteed that a Book-
Number that occurs in the file will have a corresponding entry in the Book Master File.

FIELD TYPE LENGTH VALUE

Book-Number 9 5 00001-99999

Number-Of-Copies 9 2 1-99

Sale-Status X 1 N,F,R
 

Processing

Sort the Book Sales file throwing away unwanted records (F,R).  Accumulate the sales for a book.  If the
book is in the top ten get the Book-Title and Author-Name from the Book Master File.  When the Sorted
Book Sales File has been processed, print out the top ten best sellers.
 

Print Specification

          See print specification and example report.


          The Sales field should be zero suppressed and have commas inserted as appropriate.
 

$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. BestSellers.
AUTHOR. MICHAEL COUGHLAN.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT BookMasterFile ASSIGN TO "BOOKMF.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

SELECT BookSalesFile ASSIGN TO "BOOKSALES.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

27
SELECT WorkFile ASSIGN TO "TEMP.DAT".

SELECT ReportFile ASSIGN TO "BSLIST.RPT"


ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD BookMasterFile.
01 BMF-Record.
02 BMF-BookNum PIC X(5).
02 BMF-BookTitle PIC X(25).
02 BMF-AuthorName PIC X(25).

FD BookSalesFile.
01 BSF-Record.
88 EndOfBSF VALUE HIGH-VALUES.
02 BSF-BookNum PIC X(5).
02 BSF-Copies PIC 99.
02 BSF-SaleStatus PIC X.
88 NormalSale VALUE "N".

FD ReportFile.
01 PrintLine PIC X(75).

SD WorkFile.
01 WorkRec.
88 EndOfWorkFile VALUE HIGH-VALUES.
02 W-BookNum PIC X(5).
02 W-Copies PIC 99.
02 FILLER PIC X.

WORKING-STORAGE SECTION.
01 Heading1.
02 FILLER PIC X(20) VALUE SPACES.
02 FILLER PIC X(31)
VALUE "FOLIO SOCIETY BEST SELLERS LIST".

01 Heading2.
02 FILLER PIC X(19) VALUE SPACES.
02 FILLER PIC X(33) VALUE ALL "-".

01 Heading3.
02 FILLER PIC X(7) VALUE " RANK".
02 FILLER PIC X(17) VALUE "BOOK NO.".
02 FILLER PIC X(26) VALUE "BOOK TITLE".
02 FILLER PIC X(20) VALUE "AUTHOR NAME".
02 FILLER PIC X(5) VALUE "SALES".

01 Footing-Line.
02 FILLER PIC X(25) VALUE SPACES.
02 FILLER PIC X(21) VALUE "*** END OF REPORT ***".

01 Book-Rank-Line.
02 PrnRank PIC ZZ9.

28
02 FILLER PIC X VALUE ".".
02 FILLER PIC X(4) VALUE SPACES.
02 PrnBookNum PIC 9(5).
02 PrnBookTitle PIC BBBX(25).
02 PrnAuthorName PIC BBX(25).
02 PrnSales PIC BBZ,ZZ9.

01 Book-Rank-TABLE.
02 BookDetails OCCURS 11 TIMES.
03 BookNum PIC 9(5).
03 BookTitle PIC X(25).
03 AuthorName PIC X(25).
03 BookSales PIC 9(4) VALUE ZEROS.

01 Rank PIC 99.


01 PrevBookNum PIC X(5).
01 BookSalesTotal PIC 9(4).

PROCEDURE DIVISION.
BEGIN.
SORT WorkFile ON ASCENDING KEY W-BookNum
INPUT PROCEDURE IS Select-NormalSales
OUTPUT PROCEDURE IS PrintBestSellersList.
STOP RUN.

Select-NormalSales.
OPEN INPUT BookSalesFile.
READ BookSalesFile
AT END SET EndOfBSF TO TRUE
END-READ
PERFORM UNTIL EndOfBSF
IF NormalSale
RELEASE WorkRec FROM BSF-Record
END-IF
READ BookSalesFile
AT END SET EndOfBSF TO TRUE
END-READ
END-PERFORM
CLOSE BookSalesFile.

PrintBestSellersList.
OPEN INPUT BookMasterFile
OPEN OUTPUT ReportFile

WRITE PrintLine FROM Heading1 AFTER ADVANCING PAGE.


WRITE PrintLine FROM Heading2 AFTER ADVANCING 1 LINE.
WRITE PrintLine FROM Heading3 AFTER ADVANCING 3 LINES.

RETURN WorkFile
AT END SET EndOfWorkfile TO TRUE
END-RETURN

PERFORM GetBookRankings UNTIL EndOfWorkfile

29
PERFORM PrintBookRankings
VARYING Rank FROM 1 BY 1 UNTIL Rank > 10

WRITE PrintLine FROM Footing-Line AFTER ADVANCING 3 LINES.

CLOSE ReportFile,
BookMasterFile.

PrintBookRankings.
MOVE Rank TO PrnRank
MOVE BookNum(Rank) TO PrnBookNum
MOVE BookTitle(Rank) TO PrnBookTitle
MOVE AuthorName(Rank) TO PrnAuthorName
MOVE BookSales(Rank) TO PrnSales
WRITE PrintLine FROM Book-Rank-Line
AFTER ADVANCING 2 LINES.

GetBookRankings.
MOVE W-BookNum TO PrevBookNum
MOVE ZEROS TO BookSalesTotal
PERFORM UNTIL W-BookNum NOT EQUAL TO PrevBookNum
OR EndOfWorkfile
ADD W-Copies TO BookSalesTotal
RETURN WorkFile
AT END SET EndOfWorkfile TO TRUE
END-RETURN
END-PERFORM

PERFORM WITH TEST AFTER UNTIL BMF-BookNum = PrevBookNum


READ BookMasterFile
AT END DISPLAY "IN C-B-R END-OF-BMF ENCOUNTERED"
END-READ
END-PERFORM

PERFORM CheckBookRank
VARYING Rank FROM 10 BY -1 UNTIL Rank < 1.

CheckBookRank.
IF BookSalesTotal >= BookSales(Rank)
MOVE BookDetails(Rank) TO BookDetails(Rank + 1)
MOVE BMF-BookNum TO BookNum(Rank)
MOVE BMF-BookTitle TO BookTitle(Rank)
MOVE BMF-AuthorName TO AuthorName(Rank)
MOVE BookSalesTotal TO BookSales(Rank)
END-IF.

DueSubRpt.Cbl
Exam paper model answer. NetNews is a company which runs an NNTP server carrying the complete
USENET news feed with over 15,000 news groups. Access to this server is available to internet users all
over the world. Users of the system pay a subscription fee for access. A program is required to produce a
report showing the subscriptions which are now due. The report will be based on the Due Subscriptions
file.
 

30
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. DueSubsRpt.
AUTHOR. Michael Coughlan.
*CS4321-96-COBOL-EXAM.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT DueSubsFile ASSIGN TO "DUESUBS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

SELECT WorkFile ASSIGN TO "SORT.TMP".

SELECT DueSubsReport ASSIGN TO "DUESUBS.RPT"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT SortedSubsFile ASSIGN TO "SORTSUBS.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT CountryFile ASSIGN TO "COUNTRY.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD DueSubsFile.
01 DueSubsRec.
88 EndOfDueSubsFile VALUE HIGH-VALUES.
02 CustomerNameDS PIC X(22).
02 PayMethodDS PIC 9.
02 PayFreqDS PIC 9.
02 FILLER PIC X(24).
02 CountryCodeDS PIC XX.

SD WorkFile.
01 WorkRec.
88 EndOfWorkFile VALUE HIGH-VALUES.
02 CustomerNameWF PIC X(22).
02 PayMethodWF PIC 9.
02 PayFreqWF PIC 9.
02 CountryNameWF PIC X(25).
02 CountryCodeWF PIC XX.

FD DueSubsReport.
01 PrintLine PIC X(77).

FD SortedSubsFile.
01 SortedSubsRec.
88 EndOfSortedSubs VALUE HIGH-VALUES.
02 CustomerNameSS PIC X(22).
02 PayMethodSS PIC 9.
88 ByVisa VALUE 1.
88 ByAccess VALUE 2.
88 ByExpress VALUE 3.

31
88 ByCheque VALUE 4.
02 PayFreqSS PIC 9.
02 CountryNameSS PIC X(25).
02 CountryCodeSS PIC XX.

FD CountryFile.
01 CountryRec.
88 EndOfCountryFile VALUE HIGH-VALUES.
02 CountryCodeCF PIC XX.
02 CountryNameCF PIC X(25).
02 ExchangeRateCF PIC 9(5)V9(5).

WORKING-STORAGE SECTION.

01 MethodTable VALUE "VISA Access AmExpressCheque ".


02 PayMethodMT OCCURS 4 TIMES PIC X(9).

01 FreqTable VALUE "020100180".


02 SubsFT OCCURS 3 TIMES PIC 9(3).

01 CountryTable.
02 Country OCCURS 242 TIMES
ASCENDING KEY IS CountryCodeCT
INDEXED BY CIDX.
03 CountryCodeCT PIC XX.
03 CountryNameCT PIC X(25).
03 ExchangeRateCT PIC 9(5)V9(5).

01 ReportHeadingLine.
02 FILLER PIC X(18) VALUE SPACES.
02 FILLER PIC X(35) VALUE "NETNEWS DUE SUBSCRIPTIONS REPORT".

01 ReportUnderline.
02 FILLER PIC X(17) VALUE SPACES.
02 FILLER PIC X(37) VALUE ALL "-".

01 TopicHeadingLine.
02 FILLER PIC X(5) VALUE SPACES.
02 FILLER PIC X(12) VALUE "COUNTRY NAME".
02 FILLER PIC X(11) VALUE SPACES.
02 FILLER PIC X(13) VALUE "CUSTOMER NAME".
02 FILLER PIC X(8) VALUE SPACES.
02 FILLER PIC X(12) VALUE "PAY METHOD ".
02 FILLER PIC X(8) VALUE "SUBS ".
02 FILLER PIC X(7) VALUE "LC SUBS".

01 CustLine.
02 PrnCountryName PIC X(25).
02 PrnCustName PIC BX(22).

32
02 PrnPayMethod PIC BX(9).
02 PrnSubs PIC BBB$$$9.
02 PrnLCSubs PIC BBZZ,ZZZ,ZZ9.

01 VisaLine.
02 FILLER PIC X(41) VALUE SPACES.
02 FILLER PIC X(17) VALUE "VISA TOTAL ".
02 PrnVisaTotal PIC $$$,$$9.

01 AccessLine.
02 FILLER PIC X(41) VALUE SPACES.
02 FILLER PIC X(17) VALUE "ACCESS TOTAL ".
02 PrnAccessTotal PIC $$$,$$9.

01 AmExLine.
02 FILLER PIC X(41) VALUE SPACES.
02 FILLER PIC X(17) VALUE "AMEXPRESS TOTAL ".
02 PrnAmExTotal PIC $$$,$$9.

01 ChequeLine.
02 FILLER PIC X(41) VALUE SPACES.
02 FILLER PIC X(17) VALUE "CHEQUE TOTAL ".
02 PrnChequeTotal PIC $$$,$$9.

01 VisaTotalLine.
02 FILLER PIC X(35) VALUE SPACES.
02 FILLER PIC X(23) VALUE "FINAL VISA TOTAL ".
02 PrnVisaFinalTotal PIC $$,$$$,$$9.

01 AccessTotalLine.
02 FILLER PIC X(35) VALUE SPACES.
02 FILLER PIC X(23) VALUE "FINAL ACCESS TOTAL ".
02 PrnAccessFinalTotal PIC $$,$$$,$$9.

01 AmExTotalLine.
02 FILLER PIC X(35) VALUE SPACES.
02 FILLER PIC X(23) VALUE "FINAL AMEXPRESS TOTAL ".
02 PrnAMExFinalTotal PIC $$,$$$,$$9.

01 ChequeTotalLine.
02 FILLER PIC X(35) VALUE SPACES.
02 FILLER PIC X(23) VALUE "FINAL CHEQUE TOTAL ".
02 PrnChequeFinalTotal PIC $$,$$$,$$9.

01 SubTotals.
02 VisaTotal PIC 9(5).
02 AccessTotal PIC 9(5).
02 AmExTotal PIC 9(5).
02 ChequeTotal PIC 9(5).

01 FinalTotals.
02 VisaFinalTotal PIC 9(7) VALUE ZEROS.
02 AccessFinalTotal PIC 9(7) VALUE ZEROS.

33
02 AmExFinalTotal PIC 9(7) VALUE ZEROS.
02 ChequeFinalTotal PIC 9(7) VALUE ZEROS.

01 PrevCountryCode PIC XX.


01 ExchangeRate PIC 99999V99999.
01 LCSubs PIC 9(5).

PROCEDURE DIVISION.
ProduceSubscriptionsReport.
PERFORM LoadCountryTable

SORT WorkFile ON ASCENDING CountryNameWF, CustomerNameWF


INPUT PROCEDURE IS RestructureRecords
GIVING SortedSubsFile

OPEN INPUT SortedSubsFile


OPEN OUTPUT DueSubsReport

WRITE PrintLine FROM ReportHeadingLine AFTER ADVANCING PAGE


WRITE PrintLine FROM ReportUnderline AFTER ADVANCING 1 LINE
WRITE PrintLine FROM TopicHeadingLine AFTER ADVANCING 3 LINES
WRITE PrintLine FROM SPACES AFTER ADVANCING 1 LINE

READ SortedSubsFile
AT END SET EndOfSortedSubs TO TRUE
END-READ
PERFORM PrintReportBody UNTIL EndOfSortedSubs

PERFORM PrintFinalTotals

CLOSE SortedSubsFile, DueSubsReport.


STOP RUN.

LoadCountryTable.
MOVE HIGH-VALUES TO CountryTable
OPEN INPUT CountryFile
READ CountryFile
AT END SET EndOfCountryFile TO TRUE
END-READ
PERFORM VARYING CIDX FROM 1 BY 1 UNTIL EndOfCountryFile
MOVE CountryRec TO Country(CIDX)
READ CountryFile
AT END SET EndOfCountryFile TO TRUE
END-READ
END-PERFORM
CLOSE CountryFile.

RestructureRecords.
OPEN INPUT DueSubsFile
READ DueSubsFile
AT END SET EndOfDueSubsFile TO TRUE
END-READ
PERFORM UNTIL EndOfDueSubsFile
MOVE CustomerNameDS TO CustomerNameWF

34
MOVE PayMethodDS TO PayMethodWF
MOVE PayFreqDS TO PayFreqWF
MOVE CountryCodeDS To CountryCodeWF
SEARCH ALL Country
AT END DISPLAY "Name for " CountryCodeDS " not found."
WHEN CountryCodeCT(CIDX) = CountryCodeDS
MOVE CountryNameCT(CIDX) TO CountryNameWF
END-SEARCH
RELEASE WorkRec
READ DueSubsFile
AT END SET EndOfDueSubsFile TO TRUE
END-READ
END-PERFORM
CLOSE DueSubsFile.

PrintReportBody.
MOVE CountryNameSS TO PrnCountryName
MOVE CountryCodeSS TO PrevCountryCode
SEARCH ALL Country
AT END DISPLAY "Name for " CountryCodeSS " not found."
WHEN CountryCodeCT(CIDX) = CountryCodeSS
MOVE ExchangeRateCT(CIDX) TO ExchangeRate
END-SEARCH
MOVE ZEROS TO SubTotals

PERFORM PrintCountryLines UNTIL


CountryCodeSS NOT EQUAL TO PrevCountryCode
OR EndOfSortedSubs

MOVE VisaTotal TO PrnVisaTotal


MOVE AccessTotal TO PrnAccessTotal
MOVE AmExTotal TO PrnAmExTotal
MOVE ChequeTotal TO PrnChequeTotal

WRITE PrintLine FROM VisaLine AFTER ADVANCING 4 LINES


WRITE PrintLine FROM AccessLine AFTER ADVANCING 1 LINE
WRITE PrintLine FROM AmExLine AFTER ADVANCING 1 LINE
WRITE PrintLine FROM ChequeLine AFTER ADVANCING 1 LINE
WRITE PrintLine FROM SPACES AFTER ADVANCING 3 LINES.

PrintCountryLines.
MOVE CustomerNameSS TO PrnCustName
MOVE PayMethodMT(PayMethodSS) TO PrnPayMethod
MOVE SubsFT(PayFreqSS) TO PrnSubs
COMPUTE PrnLCSubs ROUNDED = SubsFT(PayFreqSS) * ExchangeRate

EVALUATE TRUE
WHEN ByVisa ADD SubsFT(PayFreqSS) TO VisaTotal, VisaFinalTotal
WHEN ByAccess ADD SubsFT(PayFreqSS) TO AccessTotal, AccessFinalTotal
WHEN ByExpress ADD SubsFT(PayFreqSS) TO AmExTotal, AmExFinalTotal
WHEN ByCheque ADD SubsFT(PayFreqSS) TO ChequeTotal, ChequeFinalTotal
END-EVALUATE

35
WRITE PrintLine FROM CustLine
AFTER ADVANCING 1 LINE
MOVE SPACES TO PrnCountryName

READ SortedSubsFile
AT END SET EndOfSortedSubs TO TRUE
END-READ.

PrintFinalTotals.
MOVE VisaFinalTotal TO PrnVisaFinalTotal
MOVE AccessFinalTotal TO PrnAccessFinalTotal
MOVE AmExFinalTotal TO PrnAmExFinalTotal
MOVE ChequeFinalTotal TO PrnChequeFinalTotal

WRITE PrintLine FROM VisaTotalLine AFTER ADVANCING 1 LINE


WRITE PrintLine FROM AccessTotalLine AFTER ADVANCING 1 LINE
WRITE PrintLine FROM AmExTotalLine AFTER ADVANCING 1 LINE
WRITE PrintLine FROM ChequeTotalLine AFTER ADVANCING 1 LINE.

Direct Access Files


Seq2Rel.cbl
Creates a direct access Relative file from a Sequential File. Note that Relative files are not standard ASCII
files and so cannot be created with an editor as Sequential files can.
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. Seq2Rel.
AUTHOR. MICHAEL COUGHLAN.
* Creates a Relative file from a sequential file.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SupplierFile ASSIGN TO "RELSUPP.DAT"
ORGANIZATION IS RELATIVE
ACCESS MODE IS RANDOM
RELATIVE KEY IS SupplierKey
FILE STATUS IS Supplierstatus.

SELECT SupplierFileSeq ASSIGN TO "SEQSUPP.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.

FD SupplierFile.
01 SupplierRecord.
02 SupplierCode PIC 99.
02 SupplierName PIC X(20).
02 SupplierAddress PIC X(50).

36
FD SupplierFileSeq.
01 SupplierRecordSeq.
88 EndOfFile VALUE HIGH-VALUES.
02 SupplierCodeSeq PIC 99.
02 SupplierNameSeq PIC X(20).
02 SupplierAddressSeq PIC X(50).

WORKING-STORAGE SECTION.
01 SupplierStatus PIC X(2).

01 SupplierKey PIC 99.

PROCEDURE DIVISION.
Begin.
OPEN OUTPUT SupplierFile.
OPEN INPUT SupplierFileSeq.

READ SupplierFileSeq
AT END SET EndOfFile TO TRUE
END-READ
PERFORM UNTIL EndOfFile
MOVE SupplierCodeSeq TO SupplierKey
MOVE SupplierRecordSeq TO SupplierRecord
WRITE SupplierRecord
INVALID KEY DISPLAY "Supplier status = " SupplierStatus
END-WRITE
READ SupplierFileSeq
AT END SET EndOfFile TO TRUE
END-READ
END-PERFORM.

CLOSE SupplierFile, SupplierFileSeq.


STOP RUN.
ReadRel.cbl
Reads the Relative file - RELSUPP.DAT - created in the previous example program and displays the
records. Allows the user to choose to read through and display all the records in the file sequentially, or to
use a key to read just one record directly.
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. ReadRelative.
AUTHOR. MICHAEL COUGHLAN.
* Reads a Relative file directly or in sequence

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SupplierFile ASSIGN TO "RELSUPP.DAT"
ORGANIZATION IS RELATIVE
ACCESS MODE IS DYNAMIC
RELATIVE KEY IS SupplierKey
FILE STATUS IS Supplierstatus.

DATA DIVISION.

37
FILE SECTION.
FD SupplierFile.
01 SupplierRecord.
88 EndOfFile VALUE HIGH-VALUES.
02 SupplierCode PIC 99.
02 SupplierName PIC X(20).
02 SupplierAddress PIC X(50).

WORKING-STORAGE SECTION.
01 SupplierStatus PIC X(2).
88 RecordFound VALUE "00".

01 SupplierKey PIC 99.

01 PrnSupplierRecord.
02 PrnSupplierCode PIC BB99.
02 PrnSupplierName PIC BBX(20).
02 PrnSupplierAddress PIC BBX(50).

01 ReadType PIC 9.
88 DirectRead VALUE 1.
88 SequentialRead VALUE 2.

PROCEDURE DIVISION.
BEGIN.
OPEN INPUT SupplierFile.
DISPLAY "Read type : Direct read = 1, Sequential read = 2 --> "
WITH NO ADVANCING.
ACCEPT ReadType.

IF DirectRead
DISPLAY "Enter supplier code key (2 digits) --> "
WITH NO ADVANCING
ACCEPT SupplierKey
READ SupplierFile
INVALID KEY DISPLAY "SUPP STATUS :-", SupplierStatus
END-READ
PERFORM DisplayRecord
END-IF

IF SequentialRead
READ SupplierFile NEXT RECORD
AT END SET EndOfFile TO TRUE
END-READ
PERFORM UNTIL EndOfFile
PERFORM DisplayRecord
READ SupplierFile NEXT RECORD
AT END SET EndOfFile TO TRUE
END-READ
END-PERFORM
END-IF

CLOSE SupplierFile.
STOP RUN.

38
DisplayRecord.
IF RecordFound
MOVE SupplierCode TO PrnSupplierCode
MOVE SupplierName TO PrnSupplierName
MOVE SupplierAddress TO PrnSupplierAddress
DISPLAY PrnSupplierRecord
END-IF.

Seq2Index.cbl
Creates a direct access Indexed file from a Sequential file. Note that Microfocus Indexed files actually
consist of two files - the data file and the index file (.idx).
To create the Indexed file you will need to download the supplier file SEQVIDEO.DAT
  $ SET SOURCEFORMAT "FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. Seq2Index.
AUTHOR. Michael Coughlan.
* Creates an indexed file from a sequential file.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT VideoFile ASSIGN TO "IDXVIDEO.DAT"
ORGANIZATION IS INDEXED
ACCESS MODE IS RANDOM
RECORD KEY IS VideoCode
ALTERNATE RECORD KEY IS VideoTitle
WITH DUPLICATES
FILE STATUS IS VideoStatus.

SELECT SeqVideoFile ASSIGN TO "SEQVIDEO.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD VideoFile.
01 VideoRecord.
02 VideoCode PIC 9(5).
02 VideoTitle PIC X(40).
02 VideoSupplierCode PIC 99.

FD SeqVideoFile.
01 SeqVideoRecord.
88 EndOfFile VALUE HIGH-VALUES.
02 SeqVideoCode PIC 9(5).
02 SeqVideoTitle PIC X(40).
02 SeqVideoSupplierCode PIC 99.

WORKING-STORAGE SECTION.
01 VideoStatus PIC X(2).

39
PROCEDURE DIVISION.
Begin.
OPEN INPUT SeqVideoFile.
OPEN OUTPUT VideoFile.

READ SeqVideoFile
AT END SET EndOfFile TO TRUE
END-READ.
PERFORM UNTIL EndOfFile
WRITE VideoRecord FROM SeqVideoRecord
INVALID KEY DISPLAY "VIDEO STATUS :- ", VideoStatus
END-WRITE
READ SeqVideoFile
AT END SET EndOfFile TO TRUE
END-READ
END-PERFORM.

CLOSE VideoFile, SeqVideoFile.


STOP RUN.
DirectReadIdx.cbl
Does a direct read on the Indexed file created by the previous example program. Allows the user to choose
which of the keys to use for the direct read.
  $ SET SOURCEFORMAT "FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. DirectReadIdx.
AUTHOR. Michael Coughlan.
* Demonstrates how to read an Indexed file directly on
* any of its keys.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT VideoFile ASSIGN TO "IDXVIDEO.DAT"
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS VideoCode
ALTERNATE RECORD KEY IS VideoTitle
WITH DUPLICATES
FILE STATUS IS VideoStatus.

DATA DIVISION.
FILE SECTION.

FD VideoFile.
01 VideoRecord.
02 VideoCode PIC 9(5).
02 VideoTitle PIC X(40).
02 SupplierCode PIC 99.

WORKING-STORAGE SECTION.
01 VideoStatus PIC X(2).
88 RecordFound VALUE "00".

40
01 RequiredKey PIC 9.
88 VideoCodeKey VALUE 1.
88 VideoTitleKey VALUE 2.

01 PrnVideoRecord.
02 PrnVideoCode PIC 9(5).
02 PrnVideoTitle PIC BBBBX(40).
02 PrnSupplierCode PIC BBBB99.

PROCEDURE DIVISION.
Begin.
OPEN INPUT VideoFile.

DISPLAY "Chose key VideoCode = 1, VideoTitle = 2 -> "


WITH NO ADVANCING.
ACCEPT RequiredKey.

IF VideoCodeKey
DISPLAY "Enter Video Code (5 digits) -> " WITH NO ADVANCING
ACCEPT VideoCode
READ VideoFile
KEY IS VideoCode
INVALID KEY DISPLAY "VIDEO STATUS :- ", VideoStatus
END-READ
END-IF

IF VideoTitleKey
DISPLAY "Enter Video Title (40 chars) -> " WITH NO ADVANCING
ACCEPT VideoTitle
READ VideoFile
KEY IS VideoTitle
INVALID KEY DISPLAY "VIDEO STATUS :- ", VideoStatus
END-READ
END-IF

IF RecordFound
MOVE VideoCode TO PrnVideoCode
MOVE VideoTitle TO PrnVideoTitle
MOVE SupplierCode TO PrnSupplierCode
DISPLAY PrnVideoRecord
END-IF.

CLOSE VideoFile.
STOP RUN.
SeqReadIdx.cbl
Reads the Indexed file sequentially on whichever key is chosen by the user. Displays all the records in the
file
$ SET SOURCEFORMAT "FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. SeqReadIdx.
AUTHOR. Michael Coughlan.
* Demonstrates how to read an Indexed file sequentially
* on any of its keys

ENVIRONMENT DIVISION.

41
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT VideoFile ASSIGN TO "IDXVIDEO.DAT"
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS VideoCode
ALTERNATE RECORD KEY IS VideoTitle
WITH DUPLICATES
FILE STATUS IS VideoStatus.

DATA DIVISION.
FILE SECTION.
FD VideoFile.
01 VideoRecord.
88 EndOfFile VALUE HIGH-VALUE.
02 VideoCode PIC 9(5).
02 VideoTitle PIC X(40).
02 SupplierCode PIC 99.

WORKING-STORAGE SECTION.
01 VideoStatus PIC X(2).

01 RequiredSequence PIC 9.
88 VideoCodeSequence VALUE 1.
88 VideoTitleSequence VALUE 2.

01 PrnVideoRecord.
02 PrnVideoCode PIC 9(5).
02 PrnVideoTitle PIC BBBBX(40).
02 PrnSupplierCode PIC BBBB99.

PROCEDURE DIVISION.
Begin.
OPEN INPUT VideoFile.

DISPLAY "Enter key : 1=VideoCode, 2=VideoTitle ->"


WITH NO ADVANCING.
ACCEPT RequiredSequence.

* First we must establish the key-of-reference (KOR).


* Since the default KOR is the primary key we don't need
* to do anything special to establish the VideoCode as the KOR.
* But to read the file in VideoTitle order we must establish
* the VideoTile as the KOR. We do this by using the VideoTitle
* in a direct READ or (as in this case) a START statement.
IF VideoTitleSequence
MOVE SPACES TO VideoTitle
START VideoFile KEY IS GREATER THAN VideoTitle
INVALID KEY DISPLAY "VIDEO STATUS :- ", VideoStatus
END-START
END-IF

* The READ..NEXT RECORD will read the file sequentially

42
* as if it ordered on whichever key has been
* established as the KOR.
READ VideoFile NEXT RECORD
AT END SET EndOfFile TO TRUE
END-READ.
PERFORM UNTIL EndOfFile
MOVE VideoCode TO PrnVideoCode
MOVE VideoTitle TO PrnVideoTitle
MOVE SupplierCode TO PrnSupplierCode
DISPLAY PrnVideoRecord
READ VideoFile NEXT RECORD
AT END SET EndOfFile TO TRUE
END-READ
END-PERFORM.

CLOSE VideoFile.
STOP RUN.
StudFees.cbl
Exam paper model answer. A program which applies a transaction file of student payments to a Student
Master File and which then produces a report showing those students whose fees are partially or wholly
outstanding. Read the program specification first. The required data files may be downloaded from there
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. DP196-93-Repeat-Exam.
AUTHOR. Michael Coughlan.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT Student-Payment-File ASSIGN TO "STUDPAY.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT Print-File ASSIGN TO "FEES.RPT".
SELECT Student-Master-File ASSIGN TO "STUDMAST.DAT"
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS SM-Student-Number
ALTERNATE RECORD KEY IS SM-Student-Name
WITH DUPLICATES
FILE STATUS IS SM-File-Status.

DATA DIVISION.
FILE SECTION.
FD Student-Payment-File.
01 SP-Rec.
88 End-Of-SPF VALUE HIGH-VALUES.
02 SP-Student-Number PIC 9(7).
02 SP-Payment PIC 9(4)V99.

FD Print-File.
01 Print-Line PIC X(76).

43
FD Student-Master-File.
01 SM-Rec.
88 End-Of-SMF VALUE HIGH-VALUES.
02 SM-Student-Number PIC 9(7).
02 SM-Student-Name PIC X(30).
02 FILLER PIC X(5).
02 SM-Fees-Owed PIC 9(4).
02 SM-Amount-Paid PIC 9(4)V99.

WORKING-STORAGE SECTION.
01 Heading1.
02 FILLER PIC X(24) VALUE SPACES.
02 FILLER PIC X(25)
VALUE "OUTSTANDING FEES REPORT".

01 Heading2.
02 FILLER PIC X(23) VALUE SPACES.
02 FILLER PIC X(27) VALUE ALL "-".

01 Heading3.
02 FILLER PIC X(30) VALUE " STUDENT NAME".
02 FILLER PIC X(14) VALUE "STUDENT NO.".
02 FILLER PIC X(9) VALUE "FEES".
02 FILLER PIC X(12) VALUE "AMT PAID".
02 FILLER PIC X(11) VALUE "AMT OUTSTND".

01 Detail-Line.
02 Prn-Student-Name PIC X(30).
02 Prn-Student-Number PIC BBX(7).
02 Prn-Fees PIC BBBBB$$,$$9.
02 Prn-Amt-Paid PIC BBB$$,$$9.99.
02 Prn-Amt-Outstnd PIC BBB$$,$$9.99.

01 Final-Total-Line.
02 FILLER PIC X(41) VALUE SPACES.
02 FILLER PIC X(20) VALUE "TOTAL OUTSTANDING = ".
02 Prn-Total-Outstnd PIC $$,$$$,$$9.99.

01 Miscellaneous-Items.
02 Total-Outstanding PIC 9(7)V99 VALUE ZEROS.
02 SM-File-Status PIC XX.
02 Amount-Outstanding PIC 9(4)V99.

PROCEDURE DIVISION.
Update-And-Report.
OPEN I-O Student-Master-File.
OPEN INPUT Student-Payment-File.
OPEN OUTPUT Print-File.
READ Student-Payment-File
AT END SET End-Of-SPF TO TRUE
END-READ.
PERFORM Update-Master-File UNTIL End-OF-SPF.
MOVE SPACES TO Print-Line.
WRITE Print-Line AFTER ADVANCING PAGE.

44
WRITE Print-Line FROM Heading1 AFTER ADVANCING 1 LINE.
WRITE Print-Line FROM Heading2 AFTER ADVANCING 1 LINE.
WRITE Print-Line FROM Heading3 AFTER ADVANCING 3 LINES.
MOVE SPACES TO Print-Line.
WRITE Print-Line AFTER ADVANCING 1 LINE.

MOVE LOW-VALUES TO SM-Student-Name.


START Student-Master-File
KEY IS GREATER THAN SM-Student-Name
INVALID KEY DISPLAY "Start Error FS = " SM-File-Status
END-START.
READ Student-Master-File NEXT RECORD
AT END SET End-Of-SMF TO TRUE
END-READ.
PERFORM Print-Outstanding-Fees-Rpt UNTIL End-OF-SMF.
MOVE Total-Outstanding TO Prn-Total-Outstnd.
WRITE Print-Line FROM Final-Total-Line AFTER ADVANCING 3 LINES.
CLOSE Student-Master-File, Print-File, Student-Payment-File.
STOP RUN.

Update-Master-File.
MOVE SP-Student-Number TO SM-Student-Number.
READ Student-Master-File
KEY IS SM-Student-Number
INVALID KEY DISPLAY "invalid read FS = " SM-File-Status
END-READ.
ADD SP-Payment TO SM-Amount-Paid.
REWRITE SM-Rec
INVALID KEY DISPLAY "Rewrite error fs = " SM-File-Status
END-REWRITE.
READ Student-Payment-File
AT END SET End-Of-SPF TO TRUE
END-READ.

Print-Outstanding-Fees-Rpt.
IF SM-Amount-Paid LESS THAN SM-Fees-Owed
SUBTRACT SM-Amount-Paid FROM SM-Fees-Owed GIVING Amount-Outstanding
ADD Amount-Outstanding TO Total-Outstanding
MOVE SM-Student-Name TO Prn-Student-Name
MOVE SM-Student-Number TO Prn-Student-Number
MOVE SM-Fees-Owed TO Prn-Fees
MOVE SM-Amount-Paid TO Prn-Amt-Paid
MOVE Amount-Outstanding TO Prn-Amt-Outstnd
WRITE Print-Line FROM Detail-Line
AFTER ADVANCING 1 LINE
END-IF.
READ Student-Master-File NEXT RECORD
AT END SET End-Of-SMF TO TRUE
END-READ.

Aroma96.cbl
Exam paper model answer. A program is required which will apply a file of sorted, validated transactions
to the Oil-Stock-File and then produce a report based on the contents of both the Oil-Details-File and the

45
Oil-Stock-File. The report writer must be used to produce the report which must be printed sequenced on
ascending Oil-Name.
Read the program specification first.
$ SET SOURCEFORMAT "FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. Aroma96exam.
AUTHOR. Michael Coughlan.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT Oil-Details-File ASSIGN TO "ODF.DAT"
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS Oil-Num-ODF
ALTERNATE RECORD KEY IS Oil-Name-ODF
WITH DUPLICATES
FILE STATUS IS ODF-Status.

SELECT Oil-Stock-File ASSIGN TO "OSF.DAT"


ORGANIZATION IS RELATIVE
ACCESS MODE IS DYNAMIC
RELATIVE KEY IS Rel-Rec-Num
FILE STATUS IS OSF-Status.

SELECT Trans-File ASSIGN TO "TRANS.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT Report-File ASSIGN TO "OILSTOCK.RPT".

SELECT Error-File ASSIGN TO "ERROR.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD Oil-Details-File.
01 ODF-Rec.
88 End-Of-ODF VALUE HIGH-VALUES.
02 Oil-Num-ODF PIC 9(4).
02 Oil-Name-ODF PIC X(20).
02 Unit-Size-ODF PIC 9(2).
02 Unit-Cost-ODF PIC 99V99.

FD Oil-Stock-File.
01 OSF-Rec.
02 Oil-Num-OSF PIC 9(4).
02 Qty-In-Stock-OSF PIC 9(5).

FD Trans-File.
01 Trans-Rec.
88 End-Of-Trans VALUE HIGH-VALUES.
02 Type-Code PIC 9.
88 Add-To-Stock VALUE 1.
88 Remove-From-Stock VALUE 2.

46
02 Oil-Num.
03 Rel-Rec-Num PIC 9(3).
03 FILLER PIC 9.
02 Qty PIC 9(5).

FD Error-File.
01 Error-Rec PIC X(10).

FD Report-File REPORT IS Oil-Stock-Report.

WORKING-STORAGE SECTION.
01 Status-Codes.
02 ODF-Status PIC X(2).
02 OSF-Status PIC X(2).
88 No-Error-Found VALUE "00".
88 Rec-Not-Found VALUE "23".

01 Stock-Value PIC 9(5)V99.

REPORT SECTION.
RD Oil-Stock-Report
CONTROLS ARE FINAL
Oil-Name-ODF
PAGE LIMIT IS 66
HEADING 2
FIRST DETAIL 8
LAST DETAIL 50
FOOTING 55.

01 TYPE IS REPORT HEADING.


02 LINE 2.
03 COLUMN 15 PIC X(18) VALUE "OIL STOCK REPORT".
02 LINE 3.
03 COLUMN 13 PIC X(22) VALUE ALL "-".

01 TYPE IS PAGE HEADING.


02 LINE 6.
03 COLUMN 03 PIC X(9) VALUE "OIL NAME".
03 COLUMN 23 PIC X(4) VALUE "OIL#".
03 COLUMN 29 PIC X(4) VALUE "SIZE".
03 COLUMN 36 PIC X(3) VALUE "QTY".
03 COLUMN 44 PIC X(11) VALUE "STOCK VALUE".

01 Stock-Detail-Line TYPE IS DETAIL.


02 LINE IS PLUS 2.
03 COLUMN 01 PIC X(20) SOURCE Oil-Name-ODF GROUP INDICATE.
03 COLUMN 23 PIC 9(4) SOURCE Oil-Num-ODF.
03 COLUMN 30 PIC 99 SOURCE Unit-Size-ODF.
03 COLUMN 35 PIC ZZ,ZZ9 SOURCE Qty-In-Stock-OSF.
03 COLUMN 44 PIC $$$,$$9.99 SOURCE Stock-Value.

01 TYPE IS CONTROL FOOTING Oil-Name-ODF NEXT GROUP PLUS 1.


02 LINE IS PLUS 2.
03 COLUMN 27 PIC X(15) VALUE "TOTAL OIL VALUE".

47
03 Oil-Val COLUMN 44 PIC $$$$,$$9.99 SUM Stock-Value.

01 TYPE IS CONTROL FOOTING FINAL.


02 LINE IS PLUS 3.
03 COLUMN 27 PIC X(17) VALUE "TOTAL STOCK VALUE".
03 COLUMN 46 PIC $$,$$$,$$9.99 SUM Oil-Val.

PROCEDURE DIVISION.
Begin.
OPEN I-O Oil-Details-File.
OPEN I-O Oil-Stock-File.
OPEN OUTPUT Error-File.
OPEN INPUT Trans-File.
READ Trans-File
AT END SET End-Of-Trans TO TRUE
END-READ.
PERFORM Process-Transactions UNTIL End-Of-Trans.

CLOSE Error-File.
CLOSE Trans-File.
OPEN OUTPUT Report-File.
INITIATE Oil-Stock-Report.

MOVE SPACES TO Oil-Name-ODF.


START Oil-Details-File
KEY IS GREATER THAN Oil-Name-ODF
INVALID KEY DISPLAY "Start Error FS = " ODF-Status
END-START.
READ Oil-Details-File NEXT RECORD
AT END SET End-Of-ODF TO TRUE
END-READ.
PERFORM Print-Stock-Report UNTIL End-Of-ODF.
TERMINATE Oil-Stock-Report.
CLOSE Oil-Details-File.
CLOSE Oil-Stock-File.
STOP RUN.

Process-Transactions.
READ Oil-Stock-File
INVALID KEY DISPLAY "OSF rec not found FS = " OSF-Status
END-READ.
IF No-Error-Found
EVALUATE TRUE
WHEN Add-To-Stock ADD Qty TO Qty-In-Stock-OSF
WHEN Remove-From-Stock SUBTRACT Qty FROM Qty-In-Stock-OSF
WHEN OTHER DISPLAY "Type code not 1 or 2 Rec = " Trans-Rec
END-EVALUATE
REWRITE OSF-Rec
INVALID KEY DISPLAY "Problem on REWRITE FS= " OSF-Status
END-REWRITE
ELSE IF Rec-Not-Found
WRITE Error-Rec FROM Trans-Rec
END-IF
END-IF.
READ Trans-File

48
AT END SET End-Of-Trans TO TRUE
END-READ.

Print-Stock-Report.
MOVE Oil-Num-ODF TO Oil-Num
READ Oil-Stock-File
INVALID KEY DISPLAY "Error on reading OSF SF= " OSF-Status
END-READ.
COMPUTE Stock-Value = Unit-Cost-ODF * Qty-In-Stock-OSF.
GENERATE Stock-Detail-Line.
READ Oil-Details-File NEXT RECORD
AT END SET End-Of-ODF TO TRUE
END-READ.

CALLing sub-programs
DriverProg.cbl
This program demonstrates the CALL verb by calling three external sub-programs.
The "MultiplyNums" sub-program demonstrates flow of control - from caller to called and back again - and
the use of parameters.
The "Fickle" sub-program demonstrates State Memory.
The "Steadfast" sub-program shows how a sub-program can use the IS INITIAL phrase to avoid State
Memory.
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. DriverProg.
AUTHOR. Michael Coughlan.
* This program demonstrates the use of the CALL verb
* it calls three external sub-programs that help to demonstrate
* some of the features of the CALL.
* The "MultiplyNums" sub-program takes five parameters. The first two
* are the numbers to be multiplied, the second two are strings to
* demonstrate that strings can be passed as parameters and the
* last is the returned result of multiplying the two numbers.
* The "Fickle" sub-program demonstrates a program that exhibits
* State Memory.
* The "Steadfast" sub-program demonstrates how a sub-program that
* uses the IS INITIAL phrase can avoid State Memory.

ENVIRONMENT DIVISION.
DATA DIVISION.

WORKING-STORAGE SECTION.
01 UserNumber PIC 99.

01 PrnResult PIC 9(6).


* field declared as COMP cannot be DISPLAYed
* it is necessary to move it to a DISPLAY field.
* DISPLAY is the default value for a field and
* need not be declared.

* Parameters must be either 01-level's or elementry

49
* data-items.
01 Parameters.
02 Number1 PIC 9(3).
02 Number2 PIC 9(3).
02 FirstString PIC X(19) VALUE "First parameter = ".
02 SecondString PIC X(19) VALUE "Second parameter = ".
02 Result PIC 9(6) COMP.
* I've made this a COMP field to demonstrate that COMP
* items can be passed as parameters but a COMP field cannot
* be DISPLAYed and so is moved to a DISPLAY field before DISPLAYing it.

PROCEDURE DIVISION.
Begin.
PERFORM CallMultiplyNums.
PERFORM CallFickle
PERFORM CallSteadfast

PERFORM MakeFickleSteadfast.

STOP RUN.

CallMultiplyNums.
DISPLAY "Input 2 numbers (3 digits each) to be multiplied"
DISPLAY "First number - " WITH NO ADVANCING
ACCEPT Number1
DISPLAY "Second number - " WITH NO ADVANCING
ACCEPT Number2.
DISPLAY "The first string is " FirstString.
DISPLAY "The second string is " SecondString.
DISPLAY ">>>>>>>>> Calling the sub-program now".

CALL "MultiplyNums"
USING BY CONTENT Number1, Number2, FirstString,
BY REFERENCE SecondString, Result.

* The USING phrase specifies the parameters to be passed to the


* sub-program. The order of the parameters is important as the
* sub-program recognizes them by relative location not by name
*
* Parameters should be passed BY CONTENT when you are not expecting
* them to get a value from the called program. We have not passed
* SecondString by content and you can see that its value is
* overwritten by the called program.

DISPLAY "Back in the main program now <<<<<<<<<<<".


MOVE Result to PrnResult.
DISPLAY Number1 " multiplied by " Number2 " is = " PrnResult.

DISPLAY "The first string is " FirstString.


DISPLAY "The second string is " SecondString.

CallFickle.

50
DISPLAY SPACE
DISPLAY "------------------- Calling Fickle ---------"
MOVE 10 TO UserNumber
CALL "Fickle" USING BY CONTENT UserNumber
MOVE 10 TO UserNumber
CALL "Fickle" USING BY CONTENT UserNumber
MOVE 10 TO UserNumber
CALL "Fickle" USING BY CONTENT UserNumber.
* Every time I call Fickle with the same value
* produces a different result. This is because
* it remembers its state from one call to the next.
* It has "State Memory".

CallSteadFast.
DISPLAY SPACE
DISPLAY "------------------- Calling Steadfast ---------"
MOVE 10 TO UserNumber
CALL "Steadfast" USING BY CONTENT UserNumber
MOVE 10 TO UserNumber
CALL "Steadfast" USING BY CONTENT UserNumber
MOVE 10 TO UserNumber
CALL "Steadfast" USING BY CONTENT UserNumber.
* Every time I call Steadfast with the same value
* it produces the same result. We have eliminated
* State Memory by using the IS INITIAL phrase in
* Steadfast

MakeFickleSteadfast.
DISPLAY SPACE
DISPLAY "----- Making fickle act like Steadfast -------"
CANCEL "Fickle"
MOVE 10 TO UserNumber
CALL "Fickle" USING BY CONTENT UserNumber

CANCEL "Fickle"
MOVE 10 TO UserNumber
CALL "Fickle" USING BY CONTENT UserNumber

CANCEL "Fickle"
MOVE 10 TO UserNumber
CALL "Fickle" USING BY CONTENT UserNumber.
* We can make Fickle act like Steadfast by using
* the CANCEL verb to set it into its initial state
* each time we call it

MultiplyNums.cbl
The "MultiplyNums" sub-program, called from the driver program above, demonstrates the flow of control
from the driver program to the called sub-program and back again. It uses numeric and string parameters
and demonstrates the BY REFERENCE (the default) and BY CONTENT parameter passing mechanisms.
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. MultiplyNums.
AUTHOR. Michael Coughlan.

51
* This sub-program is CALLed from a Cobol program.
* it requires 5 parameters.
* 2 to contain the numbers to be multiplied
* 2 to contain strings to be displayed
* 1 to return the result of the multiplication.

ENVIRONMENT DIVISION.
DATA DIVISION.
LINKAGE SECTION.
* Parameters passed to the subprogram must have corresponding
* entries in the LINKAGE SECTION of the CALLed subprogram but
* they don't have to be declared in any particular order in the
* LINKAGE SECTION.

01 Param1 PIC 9(3).


01 Param2 PIC 9(3).
01 Answer PIC 9(6) COMP.
01 StrA PIC X(20).
01 StrB PIC X(20).

PROCEDURE DIVISION USING Param1, Param2, StrA, StrB, Answer.


Begin.
* The order of the Parameters in the USING clause is vital.
* Parameters correspond by relative position not by name.
* i.e. the name of an Parameter does not have to be the same
* in the subprogram as it was in the main_program
* The CALLed program should adher to the same considerations of good
* programming as the main program. The only difference will be that
* the STOP RUN will be replaced by the EXIT PROGRAM statement.
DISPLAY ">>>>>>>>>>>>>>>>> In the sub-program"
DISPLAY StrA Param1
DISPLAY StrB Param2

MULTIPLY Param1 BY Param2 GIVING Answer.

MOVE "VALUE OVERWRITTEN" TO StrA


MOVE "VALUE OVERWRITTEN" TO StrB
* This is done to demonstrate the differece between passing
* BY CONTENT and passing BY REFERENCE. If you pass BY REFERENCE
* you give the called program the opportunity to corrupt your data.
* You should only pass BY REFERENCE if you require the called
* program to pass back data - as is the case with the result of
* the multiplication.

DISPLAY "<<<<<<<<<<<<<< Leaving sub-program now".


EXIT PROGRAM.

Fickle.cbl
Fickle is a sub-program called from DriverProg.cbl above. Fickle is a program that demonstrates State
Memory. Each time the program is called it remembers its state from the previous call.
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.

52
PROGRAM-ID. Fickle.
AUTHOR. Michael Coughlan.
* This sub-program is demonstrates State Memory.
* Each time the program is called it remembers its
* state from the previous call. We can get rid of
* State Memory by using the IS INITIAL phrase.

ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 RunningTotal PIC 9(4) VALUE 150.

LINKAGE SECTION.
01 Param1 PIC 99.

PROCEDURE DIVISION USING Param1.


Begin.
ADD Param1 TO RunningTotal.
DISPLAY "The total so far is " RunningTotal

EXIT PROGRAM.
Steadfast.cbl
Steadfast is a sub-program called from DriverProg.cbl above. Steadfast is identical to Fickle except that it
uses the IS INITIAL phrase to avoid State Memory.
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. Steadfast IS INITIAL.
AUTHOR. Michael Coughlan.
* This sub-program is demonstrates the use of the
* IS INITIAL phrase. Each time the program is called
* it is as if it had been called for the very first time.
* All data items are initialized to their VALUE clauses.

ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 RunningTotal PIC 9(4) VALUE 150.

LINKAGE SECTION.
01 Param1 PIC 99.

PROCEDURE DIVISION USING Param1.


Begin.
ADD Param1 TO RunningTotal.
DISPLAY "The total so far is " RunningTotal

EXIT PROGRAM.
DateDriver.cbl
A driver program for the date validation sub-program below. Accepts a date from the user, passes it to the
date validation sub-program and interprets and displays the result.
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. DateDriver.

53
AUTHOR. Michael Coughlan.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 FILLER PIC 9 VALUE 0.
88 EndOfInput VALUE 1.

01 InputDateIn PIC 9(8).

01 ValidationResult PIC 9.
88 DateIsValid VALUE 0.
88 DateNotNumeric VALUE 1.
88 YearContainsZeros VALUE 2.
88 MonthContainsZeros VALUE 3.
88 DayContainsZeros VALUE 4.
88 MonthGreaterThan12 VALUE 5.
88 DayTooGreatForMonth VALUE 6.

PROCEDURE DIVISION.
Begin.
DISPLAY "Input Date as DDMMYYYY > " WITH NO ADVANCING
ACCEPT InputDateIn

CALL "Validate"
USING InputDateIn, ValidationResult.

DISPLAY "RESULT = " ValidationResult


DISPLAY "DATE IS NOW = " InputDateIn
EVALUATE TRUE
WHEN DateIsValid DISPLAY "Date is valid."
WHEN DateNotNumeric DISPLAY "Date is not numeric."
WHEN YearContainsZeros DISPLAY "Year contains all zeros."
WHEN MonthContainsZeros DISPLAY "Month contains all zeros."
WHEN DayContainsZeros DISPLAY "Day contains all zeros."
WHEN MonthGreaterThan12 DISPLAY "Month too great."
WHEN DayTooGreatForMonth DISPLAY "Day too great for month."
END-EVALUATE.

STOP RUN.

ValiDate.cbl
A date validation sub-program. Takes a date parameter in the form DDMMYYYY and returns a code
indicating if the date was valid or not. If not valid, the code indicates why the date was not valid (e.g. day
to great for month).
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. Validate IS INITIAL.
AUTHOR. Michael Coughlan.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 MonthDayTable.

54
02 TableValues PIC X(24)
VALUE "312831303130313130313031".
02 FILLER REDEFINES TableValues.
03 DaysInMonth
OCCURS 12 TIMES PIC 99.

01 CurruptDate PIC 9(8).

01 LeapQuot PIC 9(4).


01 LeapRemain PIC 9(4).

01 FILLER PIC 9 VALUE ZERO.


88 LeapYear VALUE 1.

LINKAGE SECTION.
01 InputDateLA.
02 DayLA PIC 99.
02 MonthLA PIC 99.
88 MonthInvalid VALUE 13 THRU 99.
88 MonthIsFebruary VALUE 2.
02 YearLA PIC 9(4).

01 ValidationResultLB PIC 9.
88 DateIsValid VALUE 0.
88 DateNotNumeric VALUE 1.
88 YearContainsZeros VALUE 2.
88 MonthContainsZeros VALUE 3.
88 DayContainsZeros VALUE 4.
88 MonthGreaterThan12 VALUE 5.
88 DayTooGreatForMonth VALUE 6.

PROCEDURE DIVISION USING InputDateLA, ValidationResultLB.


Begin.
EVALUATE TRUE
WHEN InputDateLA NOT NUMERIC SET DateNotNumeric TO TRUE
WHEN YearLA EQUAL TO ZEROS SET YearContainsZeros TO TRUE
WHEN MonthLA EQUAL TO ZEROS SET MonthContainsZeros TO TRUE
WHEN DayLA EQUAL TO ZEROS SET DayContainsZeros TO TRUE
WHEN MonthInvalid SET MonthGreaterThan12 TO TRUE
WHEN OTHER PERFORM CheckForValidDay
END-EVALUATE

EXIT PROGRAM.

CheckForValidDay.
* Years evenly divisible by 4 are leap years, but
* years evenly divisible by 100 are not leap years, but
* years evenly divisible by 400 are leap years.

DIVIDE YearLA BY 400 GIVING LeapQuot REMAINDER LeapRemain.


IF LeapRemain = 0
SET LeapYear TO TRUE
ELSE

55
DIVIDE YearLA BY 100 GIVING LeapQuot REMAINDER LeapRemain
IF LeapRemain NOT = 0
DIVIDE YearLA BY 4 GIVING LeapQuot REMAINDER LeapRemain
IF LeapRemain = 0
SET LeapYear TO TRUE
END-IF
END-IF
END-IF

IF LeapYear AND MonthIsFebruary


MOVE 29 TO DaysInMonth(2)
END-IF
IF DayLA GREATER THAN DaysInMonth(MonthLA)
SET DayTooGreatForMonth TO TRUE
ELSE
SET DateIsValid TO TRUE
END-IF.

DayDiffDriver.cbl
A driver program that accepts two dates from the user and displays the difference in days between them.
This program uses the ValiDate.cbl sub-program above and also contains a number of contained sub-
programs
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. Validate IS INITIAL.
AUTHOR. Michael Coughlan.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 MonthDayTable.
02 TableValues PIC X(24)
VALUE "312831303130313130313031".
02 FILLER REDEFINES TableValues.
03 DaysInMonth
OCCURS 12 TIMES PIC 99.

01 CurruptDate PIC 9(8).

01 LeapQuot PIC 9(4).


01 LeapRemain PIC 9(4).

01 FILLER PIC 9 VALUE ZERO.


88 LeapYear VALUE 1.

LINKAGE SECTION.
01 InputDateLA.
02 DayLA PIC 99.
02 MonthLA PIC 99.
88 MonthInvalid VALUE 13 THRU 99.
88 MonthIsFebruary VALUE 2.
02 YearLA PIC 9(4).

01 ValidationResultLB PIC 9.

56
88 DateIsValid VALUE 0.
88 DateNotNumeric VALUE 1.
88 YearContainsZeros VALUE 2.
88 MonthContainsZeros VALUE 3.
88 DayContainsZeros VALUE 4.
88 MonthGreaterThan12 VALUE 5.
88 DayTooGreatForMonth VALUE 6.

PROCEDURE DIVISION USING InputDateLA, ValidationResultLB.


Begin.
EVALUATE TRUE
WHEN InputDateLA NOT NUMERIC SET DateNotNumeric TO TRUE
WHEN YearLA EQUAL TO ZEROS SET YearContainsZeros TO TRUE
WHEN MonthLA EQUAL TO ZEROS SET MonthContainsZeros TO TRUE
WHEN DayLA EQUAL TO ZEROS SET DayContainsZeros TO TRUE
WHEN MonthInvalid SET MonthGreaterThan12 TO TRUE
WHEN OTHER PERFORM CheckForValidDay
END-EVALUATE

EXIT PROGRAM.

CheckForValidDay.
* Years evenly divisible by 4 are leap years, but
* years evenly divisible by 100 are not leap years, but
* years evenly divisible by 400 are leap years.

DIVIDE YearLA BY 400 GIVING LeapQuot REMAINDER LeapRemain.


IF LeapRemain = 0
SET LeapYear TO TRUE
ELSE
DIVIDE YearLA BY 100 GIVING LeapQuot REMAINDER LeapRemain
IF LeapRemain NOT = 0
DIVIDE YearLA BY 4 GIVING LeapQuot REMAINDER LeapRemain
IF LeapRemain = 0
SET LeapYear TO TRUE
END-IF
END-IF
END-IF

IF LeapYear AND MonthIsFebruary


MOVE 29 TO DaysInMonth(2)
END-IF
IF DayLA GREATER THAN DaysInMonth(MonthLA)
SET DayTooGreatForMonth TO TRUE
ELSE
SET DateIsValid TO TRUE
END-IF.

$ set NESTCALL
$ SET SOURCEFORMAT "FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. DayDiffDriver.
AUTHOR. Michael Coughlan.
* This program gets the difference in days between two dates.
* It calls three contained subprograms and one external subprogram

57
* to do the actual work.
* The "GetDayDiff" program is included as a contained
* subprogram and is used to get the difference in days between
* two dates entered by the user.
* The dates entered by the user are validated by calling my "Validate"
* subprogram. The dates entered by the user and the date required by
* the "GetDayDiff" program are in different formats.
* The "EuroDateToSortDate" subprogram is used to convert from DDMMYYYY format
* to YYYYMMDD format and the "SortDateToEuroDate" is used to convert it back.

ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Dates.
02 FirstDate PIC X(8).
02 SecondDate PIC X(8).
02 FirstDatePrn PIC XX/XX/XXXX.
02 SecondDatePrn PIC XX/XX/XXXX.

01 DayDiffs.
02 DayDifference PIC S9(7).
02 DayDifferencePrn PIC ----,--9.

01 ValidationResult PIC 9.
88 DateIsValid VALUE 0.
88 DateIsNotValid VALUE 1 THRU 6.
88 DateNotNumeric VALUE 1.
88 YearContainsZeros VALUE 2.
88 MonthContainsZeros VALUE 3.
88 DayContainsZeros VALUE 4.
88 MonthGreaterThan12 VALUE 5.
88 DayTooGreatForMonth VALUE 6.

PROCEDURE DIVISION.
10START.
SET DateIsNotValid TO TRUE.
PERFORM GetValidFirstDate UNTIL DateIsValid.

SET DateIsNotValid TO TRUE.


PERFORM GetValidSecondDate UNTIL DateIsValid.

CALL "EuroDateToSortDate" USING FirstDate, FirstDate.


CALL "EuroDateToSortDate" USING SecondDate, SecondDate.

CALL "GetDayDiff" USING BY CONTENT FirstDate, SecondDate


BY REFERENCE DayDifference.

CALL "SortDateToEuroDate" USING FirstDate, FirstDate.


CALL "SortDateToEuroDate" USING SecondDate, SecondDate.
MOVE DayDifference TO DayDifferencePrn.
MOVE FirstDate TO FirstDatePrn.
MOVE SecondDate TO SecondDatePrn.
DISPLAY SPACES.
DISPLAY "The difference between " FirstDatePrn " and "

58
SecondDatePrn " is " DayDifferencePrn " days.".

STOP RUN.

GetValidFirstDate.
DISPLAY SPACES
DISPLAY "Enter the first date in DDMMYYYY format " WITH NO ADVANCING.
ACCEPT FirstDate.
CALL "Validate" USING BY CONTENT FirstDate,
BY REFERENCE ValidationResult.
IF DateIsNotValid
PERFORM DisplayErrorMessage
END-IF.

GetValidSecondDate.
DISPLAY SPACES
DISPLAY "Enter the second date in DDMMYYYY format " WITH NO ADVANCING.
ACCEPT SecondDate.
CALL "Validate" USING BY CONTENT SecondDate,
BY REFERENCE ValidationResult.
IF DateIsNotValid
PERFORM DisplayErrorMessage
END-IF.

DisplayErrorMessage.
DISPLAY "Invalid date . Return code = " ValidationResult
EVALUATE TRUE
WHEN DateNotNumeric DISPLAY "Date is not numeric."
WHEN YearContainsZeros DISPLAY "Year contains all zeros."
WHEN MonthContainsZeros DISPLAY "Month contains all zeros."
WHEN DayContainsZeros DISPLAY "Day contains all zeros."
WHEN MonthGreaterThan12 DISPLAY "Month to great."
WHEN DayTooGreatForMonth DISPLAY "Day to great for month."
END-EVALUATE.

IDENTIFICATION DIVISION.
PROGRAM-ID. EuroDateToSortDate.
AUTHOR. Michael Coughlan.
* Converts a date in DDMMYYYY format to one in YYYYMMDD

ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 YYYYDDMMTemp.
02 YYYYYear PIC XXXX.
02 YYYYMonth PIC XX.
02 YYYYDay PIC XX.

LINKAGE SECTION.

59
01 DDMMYYYYDate.
02 DDMMDay PIC XX.
02 DDMMMonth PIC XX.
02 DDMMYear PIC XXXX.

01 YYYYDDMMDate PIC X(8).

PROCEDURE DIVISION USING DDMMYYYYDate, YYYYDDMMDate.


10Start.
MOVE DDMMDay TO YYYYDay.
MOVE DDMMMonth TO YYYYMonth.
MOVE DDMMYear TO YYYYYear.
MOVE YYYYDDMMTEMP TO YYYYDDMMDate.
EXIT PROGRAM.

END PROGRAM EuroDateToSortDate.

IDENTIFICATION DIVISION.
PROGRAM-ID. SortDateToEuroDate.
AUTHOR. Michael Coughlan.
* Converts a date in YYYYMMDD format to one in DDMMYYYY

ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 DDMMYYYYTemp.
02 DDMMDay PIC XX.
02 DDMMMonth PIC XX.
02 DDMMYear PIC XXXX.

LINKAGE SECTION.
01 YYYYDDMMDate.
02 YYYYYear PIC XXXX.
02 YYYYMonth PIC XX.
02 YYYYDay PIC XX.

01 DDMMYYYYDate PIC X(8).

PROCEDURE DIVISION USING YYYYDDMMDate, DDMMYYYYDate.


10Start.
MOVE YYYYDay TO DDMMDay.
MOVE YYYYMonth TO DDMMMonth.
MOVE YYYYYear TO DDMMYear.
MOVE DDMMYYYYTEMP TO DDMMYYYYDate.
EXIT PROGRAM.

END PROGRAM SortDateToEuroDate.

IDENTIFICATION DIVISION.
PROGRAM-ID. GetDayDiff.
AUTHOR. Michael Coughlan.
* This module finds the difference in days between two

60
* Dates. The dates must be in the form YYYYMMDD.
* The first date passed is subtracted from the second
* Date and the difference is returned.

ENVIRONMENT DIVISION.
DATA DIVISION.
LINKAGE SECTION.
01 Date1 PIC 9(8).
01 Date2 PIC 9(8).
01 Difference PIC S9(7).

PROCEDURE DIVISION USING Date1, Date2, Difference.


Begin.
COMPUTE Difference =
FUNCTION INTEGER-OF-DATE(Date2)- FUNCTION INTEGER-OF-DATE(Date1)
EXIT PROGRAM.

END PROGRAM GetDayDiff.

END PROGRAM DayDriver.


ACME99.cbl
Exam paper model answer. A program is required which will process the Stock and Manufacturer files to
create an Orders file containing ordering information for all the parts that need to be re-ordered (i.e. where
the QtyInStock is less than the ReorderLevel). For EU countries only, the COSTOFITEMS and POSTAGE
fields of each Orders file record must be calculated. The Postage rate is obtained by calling an existing
program.
Read the program specification first.

INTRODUCTION

Acme Manufacturing Plc. manufactures a range of cheap catering equipment for the European market.
Some of the parts used are fabricated within the company, but most are standard units purchased from a
range of companies in Europe and Ireland.

General Description

A program is required which will process the Stock file and Manufacturer file to create an Orders file
containing ordering information for all the parts that need to be re-ordered (i.e. where the QtyInStock is less
than the ReorderLevel).
For each stock item that needs to be re-ordered the program will create a record in the Orders file and will
set an ONORDER flag in the Stock file to show that the item has been ordered.
Acme Manufacturing tries to pay all suppliers in EU countries in advance. For these countries, the
COSTOFITEMS and POSTAGE fields of each Orders file record must be calculated.
With the exception of the Republic of Ireland, postage rates for all EU countries are the same. The postage
rates are obtained by calling a program "PostageRate" with two parameters; the POSTNUMBER (In) and
the POSTCHARGE (In/Out). The POSTNUMBER is derived, as shown by the decision table below. The
POSTCHARGE is the value returned (in Euro and Cent :- max €99.99) by "PostageRate" for a particular
POSTNUMBER. Note, that if the total weight of the items ordered is greater than 50kg then the items
cannot be sent by post and the POSTAGE must be set to €0.00.
                   
WEIGHT TO
500  g Y Y

61
                   
1    kg Y Y
                   
3    kg Y Y
                   
5    kg Y Y
                   
10  kg Y Y
                   
50  kg Y  Y
                       
COUNTRY
           
Republic Y Y Y Y Y Y
           
Other EU Y Y Y Y Y Y

Post Number 1 2 3 4 5 6 7 8 9 10 11 12

File Descriptions

Orders file (Sequential)

Field Type Length Values

ITEMDESCRIPTION X 30 --

MANFNAME X 30 --

QTYREQUIRED 9 6 1 - 999999

COSTOFITEMS 9 7 0.00 - 99999.99

POSTAGE 9 4 0.00  - 99.99


The last two items are 0 for all non EU countries.
The QTYREQUIRED is obtained from the REORDERQTY field in the Stock File.
The COSTOFITEMS is the QTYREQUIRED multiplied by the ITEMCOST.

Stock File (Relative)

Field Type Length Values

STOCKNUMBER 9 5 10001 - 99999

62
MANFCODE X 4 AAAA- ZZZZ

ITEMDESCRIPTION X 30 --

QTYINSTOCK 9 6 1 - 999999

REORDERLEVEL 9 3 1 - 999

REORDERQTY 9 6 1 - 999999

ITEMCOST 9 5 0.00- 999.99

ITEMWEIGHT 9 5 1g- 99999g

ONORDER X 1 Y/N

Note: The relative record key is obtained by subtracting 10000 from the STOCKNUMBER.
 
Manufacturer File (Indexed)

Field Key Type Length Values

MANFCODE Primary X 4 AAAA -ZZZZ

MANFNAME ALT with Duplicates X 30 -

MANFADDRESS - X 70 -

Note. 
The constituent parts of the address are separated by commas, with the country name coming last. 
The country name for Ireland and Northern Ireland is always Ireland even though, for postage charge
purposes, Northern Ireland is treated as an Other EU country. 
The second last item in an Irish address is the county name.  This allows us to distinguish Northern Ireland
addresses from those in the Republic.   
e.g.  SMALL PARTS LTD.,15 SHORE ROAD,BALLYMENA,ANTRIM,IRELAND
Each constituent part of the address will immediately follow its preceding comma.
Addresses are always in upper case.
 
EU countries
Austria, Belgium, Denmark, England, Finland, France, Germany, Greece, Ireland, Italy, Luxembourg,
Portugal, Scotland, Spain, Sweden, Wales.
Northern Ireland counties
Antrim, Armagh, Derry, Down, Fermanagh, Tyrone.
$ SET SOURCEFORMAT"FREE"

63
IDENTIFICATION DIVISION.
PROGRAM-ID. ACME99.
AUTHOR. Michael Coughlan.
*CS431399R-EXAM.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT ORDER-FILE ASSIGN TO "ORDERS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

SELECT STOCK-FILE ASSIGN TO "STOCK.DAT"


ORGANIZATION IS RELATIVE
ACCESS MODE IS DYNAMIC
RELATIVE KEY IS STOCK-REC-POINTER-WB
FILE STATUS IS STOCK-STATUS-WB.

SELECT MANF-FILE ASSIGN TO "MANF.DAT"


ORGANIZATION IS INDEXED
ACCESS MODE IS RANDOM
RECORD KEY IS MANF-CODE-FC
ALTERNATE RECORD KEY IS MANF-NAME-FC
WITH DUPLICATES
FILE STATUS IS MANF-STATUS-WB.

DATA DIVISION.
FILE SECTION.
FD ORDER-FILE.
01 ORDER-REC-FA.
02 ITEM-DESC-FA PIC X(30).
02 MANF-NAME-FA PIC X(30).
02 QTY-REQUIRED-FA PIC 9(6).
02 COST-OF-ITEMS-FA PIC 9(5)V99.
02 POSTAGE-FA PIC 99V99.

FD STOCK-FILE.
01 STOCK-REC-FB.
02 STOCK-NUM-FB PIC 9(5).
02 MANF-CODE-FB PIC X(4).
02 ITEM-DESC-FB PIC X(30).
02 QTY-IN-STOCK-FB PIC 9(6).
02 REORDER-LEVEL-FB PIC 999.
02 REORDER-QTY-FB PIC 9(6).
02 ITEM-COST-FB PIC 9(5).
02 ITEM-WEIGHT-FB PIC 9(5).
02 ON-ORDER-FB PIC X.
88 NOT-ON-ORDER VALUE "N".
88 ON-ORDER VALUE "Y".

FD MANF-FILE.
01 MANF-REC-FC.
02 MANF-CODE-FC PIC X(4).
02 MANF-NAME-FC PIC X(30).
02 MANF-ADDRESS-FC PIC X(70).

64
WORKING-STORAGE SECTION.
01 CALL-ITEMS-WA.
02 POST-CHARGE-WA PIC 99V99.
02 POST-NUM-WA PIC 99.

01 FILE-DATA-WB.
02 STOCK-REC-POINTER-WB PIC 9(5).
02 STOCK-STATUS-WB PIC XX.
02 MANF-STATUS-WB PIC XX.
02 FILLER PIC 9 VALUE 0.
88 END-OF-FILE VALUE 1.

01 UNSTRING-DATA-WC.
02 UNSTRING-POINTER-WC PIC 99.
88 END-OF-ADDRESS VALUE 71.
02 HOLD-STRING-WC PIC X(10).
02 COUNTY-WC PIC X(9).
88 NORTHERN-COUNTY
VALUE "ANTRIM", "ARMAGH", "DERRY", "DOWN",
"FERMANAGH", "TYRONE".
02 COUNTRY-WC PIC X(10).
88 EEC-COUNTRY
VALUE "AUSTRIA", "BELGIUM", "DENMARK", "ENGLAND", "FINLAND",
"FRANCE", "GERMANY", "GREECE", "IRELAND", "ITALY",
"LUXEMBOURG", "PORTUGAL", "SCOTLAND", "SPAIN",
"SWEDEN", "WALES".
88 IRELAND VALUE "IRELAND".

02 COUNTRY-FLAGS-WC PIC 9.
88 OTHER-EEC VALUE 1.
88 REPUBLIC VALUE 0.

01 POSTAGE-DATA-WD.
02 TOTAL-WEIGHT-WD PIC 9(5).
88 OVER-WEIGHT VALUE 50001 THRU 99999.

PROCEDURE DIVISION.
CREATE-REORDER-FILE.
OPEN I-O STOCK-FILE.
OPEN INPUT MANF-FILE.
OPEN OUTPUT ORDER-FILE.
READ STOCK-FILE NEXT RECORD
AT END SET END-OF-FILE TO TRUE
END-READ.
PERFORM UNTIL END-OF-FILE
IF (QTY-IN-STOCK-FB NOT GREATER THAN REORDER-LEVEL-FB)
AND (NOT-ON-ORDER)
PERFORM CREATE-REORDER-RECORD
PERFORM UPDATE-STOCK-RECORD
END-IF

65
READ STOCK-FILE NEXT RECORD
AT END SET END-OF-FILE TO TRUE
END-READ
END-PERFORM.
CLOSE STOCK-FILE, MANF-FILE, ORDER-FILE.
STOP RUN.

CREATE-REORDER-RECORD.
MOVE MANF-CODE-FB TO MANF-CODE-FC.
READ MANF-FILE
KEY IS MANF-CODE-FC
INVALID KEY DISPLAY "CRR MANF STATUS = "
MANF-STATUS-WB "CODE = " MANF-CODE-FC
END-READ.
PERFORM EXTRACT-ADDRESS-ITEMS.

MOVE ZEROS TO POSTAGE-FA, COST-OF-ITEMS-FA.


IF EEC-COUNTRY
PERFORM GET-POSTAGE
MULTIPLY ITEM-COST-FB BY REORDER-QTY-FB
GIVING COST-OF-ITEMS-FA
MOVE POST-CHARGE-WA TO POSTAGE-FA
END-IF.

MOVE ITEM-DESC-FB TO ITEM-DESC-FA.


MOVE MANF-NAME-FC TO MANF-NAME-FA.
MOVE REORDER-QTY-FB TO QTY-REQUIRED-FA.
WRITE ORDER-REC-FA.

GET-POSTAGE.
IF IRELAND AND NOT NORTHERN-COUNTY
SET REPUBLIC TO TRUE
ELSE
SET OTHER-EEC TO TRUE
END-IF.
MULTIPLY ITEM-WEIGHT-FB BY REORDER-QTY-FB
GIVING TOTAL-WEIGHT-WD
ON SIZE ERROR MOVE 99999 TO TOTAL-WEIGHT-WD.

EVALUATE TOTAL-WEIGHT-WD ALSO REPUBLIC ALSO OTHER-EEC


WHEN 1 THRU 500 ALSO TRUE ALSO FALSE MOVE 1 TO POST-NUM-WA
WHEN 1 THRU 500 ALSO FALSE ALSO TRUE MOVE 2 TO POST-NUM-WA
WHEN 501 THRU 1000 ALSO TRUE ALSO FALSE MOVE 3 TO POST-NUM-WA
WHEN 501 THRU 1000 ALSO FALSE ALSO TRUE MOVE 4 TO POST-NUM-WA
WHEN 1001 THRU 3000 ALSO TRUE ALSO FALSE MOVE 5 TO POST-NUM-WA
WHEN 1001 THRU 3000 ALSO FALSE ALSO TRUE MOVE 6 TO POST-NUM-WA
WHEN 3001 THRU 5000 ALSO TRUE ALSO FALSE MOVE 7 TO POST-NUM-WA
WHEN 3001 THRU 5000 ALSO FALSE ALSO TRUE MOVE 8 TO POST-NUM-WA
WHEN 5001 THRU 10000 ALSO TRUE ALSO FALSE MOVE 9 TO POST-NUM-WA
WHEN 5001 THRU 10000 ALSO FALSE ALSO TRUE MOVE 10 TO POST-NUM-WA
WHEN 10001 THRU 50000 ALSO TRUE ALSO FALSE MOVE 11 TO POST-NUM-WA
WHEN 10001 THRU 50000 ALSO FALSE ALSO TRUE MOVE 12 TO POST-NUM-WA
WHEN 50001 THRU 99999 ALSO ANY ALSO ANY MOVE ZEROS
TO POST-CHARGE-WA
WHEN OTHER DISPLAY "EVALUATE WRONG:- WEIGHT = " TOTAL-WEIGHT-WD
" COUNTRY FLAG = " COUNTRY-FLAGS-WC

66
END-EVALUATE.
IF NOT OVER-WEIGHT
CALL "POSTAGE-RATE"
USING BY CONTENT POST-NUM-WA
BY REFERENCE POST-CHARGE-WA
END-IF.

UPDATE-STOCK-RECORD.
MOVE "Y" TO ON-ORDER-FB.
REWRITE STOCK-REC-FB
INVALID KEY DISPLAY "STOCK REWRITE STATUS = " STOCK-STATUS-WB
END-REWRITE.

EXTRACT-ADDRESS-ITEMS.
MOVE 1 TO UNSTRING-POINTER-WC.
PERFORM UNTIL END-OF-ADDRESS
MOVE HOLD-STRING-WC TO COUNTY-WC
UNSTRING MANF-ADDRESS-FC DELIMITED BY ","
INTO HOLD-STRING-WC
WITH POINTER UNSTRING-POINTER-WC
END-PERFORM.
MOVE HOLD-STRING-WC TO COUNTRY-WC.

*debugging displays
DISPLAY "COUNTY = " COUNTY-WC.
DISPLAY "COUNTRY = " COUNTRY-WC.

SFbyMail.cbl
Exam paper model answer. A program is required to apply the Orders file (containing customer orders) to
the indexed Book Stock file and to produce the Processed Orders file.
Read the program specification first.

Introduction

Science Fiction by Mail is a company which sells Science Fiction and Fantasy books through the Internet.
Customers view the book catalogues and place orders by connecting to the company’s web site. When an
order is placed, an Order-Number is assigned, and the details of the order are written to an Orders file
(ORDERS.DAT). Only already registered customers can place an order.
At the end of the day, the Orders file is processed, applying it to the Book Stock file and producing a
Processed Orders file.  The Processed Orders file is used by other programs (not required for this exam) to
bill the customers and to produce invoices and address labels.
For each book title required in an order, the Book Stock File must be updated by subtracting the Qty-
Required from the Qty-In-Stock.  When a book request cannot be filled because there is insufficient stock,
this must be indicated by writing zeros to the Quantity-Required field of the Processed-Orders record. The
Book Stock file must not be updated.
A program is required to apply the Orders file to the Book Stock file and produce the Processed Orders file.

File Descriptions

The Orders File (Sequential)

67
The Orders file is an  unsorted, validated, sequential file.  Each record may contain an order for up to 10
different book titles.  Where all ten titles are not requested the rest of the record is space filled.
The Book-Details are held in a ten element table.  Each element consists of the Book-Id
and the Qty-Required. The record description is as follows;

   Field Type Length Occurrence

Order-Number X 7 1

Customer-Id X 5 1

Book-Details Group - 10

      Book-Id X 5 -

      Qty-Required 9 2 -
In the following example record spaces have been inserted for convenience.

1234567 C1234  B1234 01  B2345 03  B3456 02

The order number in this record is 1234567, the Customer-Id is C1234 and 3 different titles have been
requested.  One copy of B1234, three copies of B2345 and two copies of B3456 have been ordered.
 

Book Stock File (Indexed)

The Book Stock file holds details of the company’s stock of books.  It is an indexed file
containing records with the following description;

Field Key type Type Length Value

Book-Id Primary X 5 -

Book-Title ALT X 20 -

Author-Id ALT with Duplicates 9 4 -

Qty-In-Stock -- 9 3 0-999

Copy-Price -- 9 4 01.50-99.99
 

Processed Orders File (Sequential)

requested in the Orders File, a


The Processed Orders file is a sequential file.   For each book title
record must be created in the Processed Orders File.  The record description is as follows;

68
Field Type Length Value

Order-Number X 7 -

Customer-Id X 5 -

Book-Title X 20 -

Qty-Required 9 2 0-99

Title-Cost 9 5 0.50-999.99

Title-Postage 9 4 1.50-99.99

Sub Programs

The Copy-Postage may be obtained  by calling two external subprograms.  These subprograms have
already been written and you may assume that they will be present in the same directory where your
program is run.

GetCustomerAddress is a subprogram that takes two parameters


            IN        Customer-Id                 PIC X(5)
            OUT    Cust-Address               PIC X(40)

Cust-Address contains the customer address. The parts of the customer address are separated from one
another by commas.   The last item in the customer address is a two character Country-Code.  This code
must be extracted from the customer address and then used to obtain the Copy-Postage (cost of posting one
book to the customer).
Example address = 13 Winchester Drive, Castletroy, Limerick, Ireland, IE
 

GetPostage is a subprogram that takes two parameters


            IN        Country-Code              PIC XX
            OUT    Copy-Postage              PIC 99V99

$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. SFbyMail.
AUTHOR. Michael Coughlan.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.

SELECT BookStockFile ASSIGN TO "BookStock.DAT"


ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS Book-Id-BSF
ALTERNATE RECORD KEY IS Book-Title-BSF

69
ALTERNATE RECORD KEY IS Author-Id-BSF
WITH DUPLICATES
FILE STATUS IS BookStatus.

SELECT ProcessedOrdersFile ASSIGN TO "ProcessedOrders.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT OrdersFile ASSIGN TO "Orders.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD BookStockFile.
01 BookStockRec.
02 Book-Id-BSF PIC X(5).
02 Book-Title-BSF PIC X(30).
02 Author-Id-BSF PIC 9(4).
02 Qty-In-Stock-BSF PIC 999.
02 Copy-Price-BSF PIC 99V99.

FD ProcessedOrdersFile.
01 ProcessedOrdersRec.
02 Order-Number-POF PIC X(7).
02 Customer-Id-POF PIC X(5).
02 Book-Title-POF PIC X(30).
02 Qty-Required-POF PIC 99.
02 Title-Cost-POF PIC 999V99.
02 Title-Postage-POF PIC 99V99.

FD OrdersFile.
01 OrdersRec.
88 EndOfOrders VALUE HIGH-VALUES.
02 Order-Number PIC X(7).
02 Customer-Id PIC X(5).
02 Book-Details OCCURS 10 TIMES.
03 Book-Id PIC X(5).
03 Qty-Required PIC 99.

WORKING-STORAGE SECTION.
01 BookStatus PIC XX.
01 BookNum PIC 99.
01 Copy-Postage PIC 99V99.
01 Cust-Address PIC X(40).
01 UnstringPtr PIC 99.
88 EndOfAddress VALUE 41.
01 Country-Code PIC XX.

PROCEDURE DIVISION.
Begin.
OPEN INPUT OrdersFile.
OPEN I-O BookStockFile.
OPEN OUTPUT ProcessedOrdersFile.

READ OrdersFile

70
AT END SET EndOfOrders TO TRUE
END-READ.
PERFORM Process-Orders UNTIL EndOfOrders
CLOSE OrdersFile
BookStockFile
ProcessedOrdersFile.
STOP RUN.

Process-Orders.
PERFORM GetCopyPostage
PERFORM VARYING BookNum FROM 1 BY 1
UNTIL BookNum> 10 OR Book-Id(BookNum) = SPACES
MOVE Book-Id(BookNum) TO Book-Id-BSF
READ BookStockFile
KEY is Book-Id-BSF
INVALID KEY
DISPLAY "Error in ProcessOrders1"
END-READ
IF Qty-Required(BookNum) > Qty-In-Stock-BSF
MOVE ZEROS TO Qty-Required-POF
ELSE
SUBTRACT Qty-Required(BookNum)FROM Qty-In-Stock-BSF
MOVE Qty-Required(BookNum) TO Qty-Required-POF
REWRITE BookStockRec
INVALID KEY DISPLAY "Error ProcessOrders2"
END-REWRITE
END-IF
PERFORM CreateProcessedOrder
END-PERFORM
READ OrdersFile
AT END SET EndOfOrders TO TRUE
END-READ.

CreateProcessedOrder.
MOVE Order-Number TO Order-Number-POF
MOVE Customer-Id TO Customer-ID-POF
MOVE Book-Title-BSF TO Book-Title-POF
COMPUTE Title-Cost-POF = Qty-Required-POF * Copy-Price-BSF
COMPUTE Title-Postage-POF = Qty-Required-POF * Copy-Postage
WRITE ProcessedOrdersRec.

GetCopyPostage.
CALL "GetCustomerAddress" USING BY CONTENT Customer-Id
BY REFERENCE Cust-Address
MOVE 1 TO UnstringPtr
PERFORM UNTIL EndOfAddress
UNSTRING Cust-Address
Delimited BY "," OR ALL SPACES
INTO Country-Code
WITH POINTER UnstringPtr
END-UNSTRING
END-PERFORM

CALL "GetPostage" USING BY CONTENT Country-Code


BY REFERENCE Copy-Postage.

71
String handling
RefMod.cbl
Solves a number of string handling tasks such as : - Extracting a substring from a string given the start
position and length of the substring.
Extracting the first x number of chars from a string.
Extracting the last x number of chars from a string.
Removing trailing blanks from a string.
Removing leading blanks from a string.
Finding the location of the first occurrence of any of a substring's chars in a string
  $ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. RefModification.
AUTHOR. Michael Coughlan.
* An example program using Reference Modification, Intrinsic Functions
* and the INSPECT.
* The program solves a number of tasks suggested by Judy Yaeger in her
* article "Character Manipulation Using COBOL" where she attempted to show
* the limitations of COBOL string handling.

DATA DIVISION.
WORKING-STORAGE SECTION.
01 xStr PIC X(50) VALUE " This is the first source string".
01 xStr2 PIC X(32) VALUE "This is the second source string".
01 StrSize PIC 99 VALUE 32.
01 CharCount PIC 99 VALUE ZEROS.
01 EndCount PIC 99 VALUE ZEROS.
01 yStr PIC X(4) VALUE SPACES.
01 CharPos PIC 99 VALUE ZEROS.
01 StrLength PIC 99 VALUE ZEROS.

PROCEDURE DIVISION.
Begin.
* Task1 substring(xStr, StartPos, Length)
* Extract a substring from a string given the StartPos and Length.
* Solution - use reference modification to get the substring.
* In this example we get 3 characters starting at position 9
DISPLAY "Task1 = " xStr(9:3)

* Task2 prefix(xStr,Length)
* Extract the first Length number of chars from a string
* Solution - use reference modification starting at position 1.
* In this example we get the first 7 characters
DISPLAY "Task2 = " xStr(1:7)

* Task3 suffix(xStr,Length)
* Extract the last Length number of chars from a string
* Solution - use reference modification with start of substring

72
* defined as the FullStringLength - SubStringLength + 1
* In this example we get the last 13 characters.
MOVE 13 TO StrLength
DISPLAY "Task3 = " xStr2((StrSize - StrLength) + 1:StrLength)

* Task4: trimblank(xStr)
* Remove trailing blanks from a string
* Solution 1
* Use the REVERSE intrinsic function to reverse the string
* then use the INSPECT tallying to count the number of spaces at the
* begining of the reversed string. The substring length is then the
* FullSringLength - CharCount.
* Use reference modification of get the substring.
DISPLAY "Task4 Before = " xStr "<<<<<<"
MOVE 0 TO CharCount
INSPECT FUNCTION REVERSE(xStr) TALLYING CharCount
FOR LEADING SPACES
DISPLAY "Task4 After = "xStr(1:50 - CharCount) "<<<<<<<".

* Solution 2
* Use reference modification and the PERFORM..VARYING to
* keep reducing the size of the substring until a non space character
* is encountered. Then use reference modification to get the substring.
PERFORM VARYING CharCount FROM 50 BY -1
UNTIL xStr(CharCount:1) NOT = SPACE
END-PERFORM
DISPLAY "Task4 After = "xStr(1:CharCount) "<<<<<<<".

* Task5 Left_trimblank(xStr)
* Remove leading blanks from a string.
* Solution - Use the inspect to count the leading blanks and reference
* modification to get the substring from the point indicated by CharCount
* and for FullStrLength - CharCount characters.
MOVE 1 TO CharCount.
INSPECT xStr TALLYING CharCount FOR LEADING SPACES
DISPLAY "Task5 =" xStr(CharCount: 50 - CharCount)

* Task6 index(xStr,yStr)
* Find the location of the first occurrence of substring yStr in xStr.
* Solution - Use the INSPECT..TALLYING to count the characters before
* the first occurrence of the substring. CharCount has the location.
* In this example we get the position of the substring "source".
MOVE 1 TO CharCount
INSPECT xStr TALLYING CharCount for CHARACTERS
BEFORE INITIAL "source".
DISPLAY "Task6 First occurrence is in char position " CharCount

* Task7 cindex(xStr,yStr)
* Find the location of the first occurrence of any of the characters
* in substring xStr, in string yStr
* Solution - Use the PERFORM..VARYING and reference modification to
* locate each of the characters in the yString. Then use the INSPECT to
* find the position of each in the xString. Return whichever is the least.
MOVE "fred" TO yStr
MOVE 51 TO EndCount

73
PERFORM VARYING CharPos FROM 1 BY 1 UNTIL CharPos > 4
MOVE 1 TO CharCount
INSPECT xStr TALLYING CharCount FOR CHARACTERS
BEFORE INITIAL yStr(CharPos:1)
IF CharCount < EndCount MOVE CharCount TO EndCount
END-IF
END-PERFORM
DISPLAY "Task7 First occurrence is in char position " EndCount
DISPLAY "The character is " xStr(EndCount:1)
STOP RUN.
UnstringFileEg.cbl

An example showing the unpacking of comma separated records and the size validation
of the unpacked fields.

$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. UnstringFileEg.
AUTHOR. Michael Coughlan.
* Example showing the unpacking of comma separated records
* and the size validation of the unpacked fields.
* In this example we have only implemented unpacking
* an InsertSupplier record.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT VarLengthRecFile ASSIGN TO "VarLen.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD VarLengthRecFile.
01 VarLenRec.
88 EndOfFile VALUE HIGH-VALUES.
02 TypeCode PIC XX.
88 DeleteSupplier VALUE "1,".
88 DeleteVideo VALUE "2,".
88 InsertVideo VALUE "3,".
88 InsertSupplier VALUE "4,".
88 ValidTypeCode VALUE "1,", "2,", "3,","4,".

02 RemainingRec PIC X(78).

WORKING-STORAGE SECTION.
01 InsertSupplierRec.
02 TransType PIC 9.
02 TransDate PIC X(8).
02 Supplier-Code PIC XX.
02 Supplier-Name PIC X(20).
02 Supplier-Address PIC X(50).

* These counts allow us to detect if there are too many chars

74
* in a particular field. For instance the date field should be
* 8 characters in size.
01 InsertSupplierCounts.
02 DateCount PIC 99.
88 ValidDate VALUE 8.
02 SuppCodeCount PIC 99.
88 ValidSuppCode VALUE 1 THRU 2.
02 SuppNameCount PIC 99.
88 ValidSuppName VALUE 1 THRU 20.
02 SuppAdrCount PIC 99.
88 ValidSuppAdr VALUE 1 THRU 50.

01 StringEnd PIC 99.

PROCEDURE DIVISION.
Begin.
OPEN INPUT VarLengthRecFile
READ VarLengthRecFile
AT END SET EndOfFile TO TRUE
END-READ
PERFORM UNTIL EndOfFile
MOVE ZEROS TO InsertSupplierCounts
* First find the actual length of the record
PERFORM VARYING StringEnd FROM 78 BY -1
UNTIL RemainingRec(StringEnd:1) NOT = SPACE
END-PERFORM
IF InsertSupplier
UNSTRING RemainingRec(1:StringEnd) DELIMITED BY ","
INTO TransDate COUNT IN DateCount
Supplier-Code COUNT IN SuppCodeCount
Supplier-Name COUNT IN SuppNameCount
Supplier-Address COUNT IN SuppAdrCount
END-UNSTRING
PERFORM CheckForErrors
ELSE
IF NOT ValidTypeCode
DISPLAY SPACE
DISPLAY "Record = " VarLenRec(1:70)
DISPLAY "Type code is not valid"
END-IF
END-IF
READ VarLengthRecFile
AT END SET EndOfFile TO TRUE
END-READ
END-PERFORM
CLOSE VarLengthRecFile
STOP RUN.

CheckForErrors.
DISPLAY SPACE
DISPLAY "Record = " VarLenRec(1:70)
IF NOT ValidDate DISPLAY "Date Size Error" END-IF
IF NOT ValidSuppCode DISPLAY "Supplier Code Error" END-IF
IF NOT ValidSuppName DISPLAY "Supplier name Error" END-IF

75
IF NOT ValidSuppAdr DISPLAY "Supplier address Error" END-IF.

FileConv.Cbl

Exam paper model answer. A program is required to convert the unsorted Client-Names
file of free-format, variable length, records into a sorted file of fixed length records. The
sorted file must be sorted into ascending Client-Name within ascending County-Name. In
addition to converting and sorting the file, the program must ensure that the county name
is valid and must convert it to a county number.
Read the program specification first.

Introduction

A program is required to convert the unsorted Client-Names file of free-format, variable length, records
into a sorted file of fixed length records. The sorted file must be sorted into ascending Client-Name within
ascending County-Name. In addition to converting and sorting the file, the program must ensure that the
county name is valid and must convert it to a county number.

File Descriptions

The Client-Names File (input)

The records of the Client-Names file are unsorted, free-format, variable length records where the fields are
separated by commas. While the fields do not occupy specific character positions, they are in a specific
order. The Client-Name is first, the Client-Address is next and the Client-Number is last. The fields also
have a maximum size. The Client-Name is a maximum of 35 characters, the Address is a maximum of 60
characters long and the Client-Number is always 4 digits long.
The constituent parts of the fields are separated by one or more spaces. The fields may be upper case or
lower case or a mixture of these. In the Address field the County Name will always be the last part of the
address.
Some example records are;
Michael Terence Ryan,34 Winchester Drive Dublin 3 Co. Dublin,0123
MARY TYLER MOORE,THIS IS AN INVALID ADDRESS,1432
Fred James Hoyle,17 Starry Lane Cork Co. Cork,0012
 

The Sorted-Clients File (output)

The Sorted-Clients file is produced from the unsorted Client-Names file. The records of
the file must be fixed length records held in ascending Client-Name within ascending
County-Num. Each record has the following description.
Field Type Length Value
Client-Name X 30 --
Client-Address X 45 --
County-Num 9 2 1-32
Client-Num 9 4 0001-9999

This file only contains records with valid county names. Records with invalid county names must be
written to an error file.

76
The Client-Name in the sorted file must have the surname first so that the sorting will be done correctly.
Some sample records are;
Hoyle Fred James 17 Starry Lane Cork Co. CORK 060012
Ryan Michael Terence 34 Winchester Drive Dubline 7 Co. Dublin 090123

The Error File

Any records that are found to contain invalid county names are sent to an Error File. This fle has the same
format as the input file
An example error record is;

Mary Tyler Moore,This is an invalid address,1435

Appendix

The names, and corresponding county numbers, of the 32 counties of Ireland are given in
the table below.
County Num County Name

1 Antrim

2 Armagh

3 Carlow

4 Cavan

5 Clare

6 Cork

7 Derry

8 Donegal

9 Down

10 Dublin

11 Fermanagh

12 Galway

77
13 Kerry

14 Kildare

15 Kilkenny

16 Laois

17 Leitrim

18 Limerick

19 Longford

20 Louth

21 Mayo

22 Meath

23 Monaghan

24 Offaly

25 Roscommon

26 Sligo

27 Tipperary

28 Tyrone

29 Westmeath

30 Waterford

31 Wexford

32 Wicklow
 

78
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. TERMINAL-EXAM.
AUTHOR. Michael Coughlan.
*Originally written for VAX COBOL 1990
*Converted to Microfocus COBOL 2002

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT UNSORTED-NAMES ASSIGN TO "CLIENTS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

SELECT WORK-FILE ASSIGN TO "TEMP.DAT".

SELECT SORTED-NAMES ASSIGN TO "SCLIENTS.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT ERROR-FILE ASSIGN TO "ERROR.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.

FD UNSORTED-NAMES.
01 UNSORTED-REC PIC X(99).

SD WORK-FILE.
01 WORK-REC.
02 CLIENT-NAME PIC X(35).
02 CLIENT-ADDRESS PIC X(60).
02 COUNTY-NO PIC 99.
02 CLIENT-NO PIC 9999.

FD SORTED-NAMES.
01 SORTED-REC PIC X(101).

FD ERROR-FILE.
01 ERROR-REC PIC X(99).

WORKING-STORAGE SECTION.
01 COUNTY-TABLE.
02 COUNTY-VALUES.
03 FILLER PIC X(11) VALUE "ANTRIM".
03 FILLER PIC X(11) VALUE "ARMAGH".
03 FILLER PIC X(11) VALUE "CARLOW".
03 FILLER PIC X(11) VALUE "CAVAN".
03 FILLER PIC X(11) VALUE "CLARE".
03 FILLER PIC X(11) VALUE "CORK".
03 FILLER PIC X(11) VALUE "DERRY".
03 FILLER PIC X(11) VALUE "DONEGAL".
03 FILLER PIC X(11) VALUE "DOWN".
03 FILLER PIC X(11) VALUE "DUBLIN".
03 FILLER PIC X(11) VALUE "FERMANAGH".
03 FILLER PIC X(11) VALUE "GALWAY".
03 FILLER PIC X(11) VALUE "KERRY".

79
03 FILLER PIC X(11) VALUE "KILDARE".
03 FILLER PIC X(11) VALUE "KILKENNY".
03 FILLER PIC X(11) VALUE "LAOIS".
03 FILLER PIC X(11) VALUE "LEITRIM".
03 FILLER PIC X(11) VALUE "LIMERICK".
03 FILLER PIC X(11) VALUE "LONGFORD".
03 FILLER PIC X(11) VALUE "LOUTH".
03 FILLER PIC X(11) VALUE "MAYO".
03 FILLER PIC X(11) VALUE "MEATH".
03 FILLER PIC X(11) VALUE "MONAGHAN".
03 FILLER PIC X(11) VALUE "OFFALY".
03 FILLER PIC X(11) VALUE "ROSCOMMON".
03 FILLER PIC X(11) VALUE "SLIGO".
03 FILLER PIC X(11) VALUE "TIPPERARY".
03 FILLER PIC X(11) VALUE "TYRONE".
03 FILLER PIC X(11) VALUE "WATERFORD".
03 FILLER PIC X(11) VALUE "WESTMEATH".
03 FILLER PIC X(11) VALUE "WEXFORD".
03 FILLER PIC X(11) VALUE "WICKLOW".
02 FILLER REDEFINES COUNTY-VALUES.
03 COUNTY-NAME OCCURS 32 TIMES
ASCENDING KEY COUNTY-NAME
INDEXED BY COUNTY-NUM
PIC X(11).

01 FILLER PIC 9 VALUE 0.


88 END-OF-FILE VALUE 1.

01 LOWER-CASE PIC X(26)


VALUE "abcdefghijklmnopqrstuvwxyz".

01 UPPER-CASE PIC X(26)


VALUE "ABCDEFGHIJKLMNOPQRSTUVWXYZ".

01 HOLD-ITEMS.
02 HOLD-CLIENT PIC X(35).
02 HOLD-NAME PIC X(35).
02 HOLD-COUNTY PIC X(11).
02 HOLD-CLIENT-NO PIC X(4).

01 PTR-ITEMS.
02 UNSTR-PTR PIC 99.
88 END-OF-ADDRESS VALUE 61.
88 END-OF-NAME VALUE 36.
02 STR-PTR PIC 99.
02 NAME-END PIC 99.

PROCEDURE DIVISION.
CONVERT-FILE.
SORT WORK-FILE ON ASCENDING COUNTY-NO, CLIENT-NAME
INPUT PROCEDURE IS CONVERT-RECORDS
GIVING SORTED-NAMES.
STOP RUN.

CONVERT-RECORDS.

80
OPEN INPUT UNSORTED-NAMES
OPEN OUTPUT ERROR-FILE
READ UNSORTED-NAMES
AT END SET END-OF-FILE TO TRUE
END-READ
PERFORM UNPACK-RECORDS UNTIL END-OF-FILE
CLOSE ERROR-FILE
CLOSE UNSORTED-NAMES.

UNPACK-RECORDS.
MOVE SPACES TO WORK-REC
MOVE 1 TO UNSTR-PTR.

UNSTRING UNSORTED-REC
DELIMITED BY ","
INTO HOLD-CLIENT, CLIENT-ADDRESS, HOLD-CLIENT-NO
MOVE HOLD-CLIENT-NO TO CLIENT-NO.

PERFORM UNTIL END-OF-ADDRESS


UNSTRING CLIENT-ADDRESS DELIMITED BY ALL SPACES
INTO HOLD-COUNTY
WITH POINTER UNSTR-PTR

END-PERFORM

INSPECT HOLD-COUNTY CONVERTING LOWER-CASE TO UPPER-CASE.


SEARCH ALL COUNTY-NAME
AT END WRITE ERROR-REC FROM UNSORTED-REC
WHEN COUNTY-NAME(COUNTY-NUM) = HOLD-COUNTY
SET COUNTY-NO TO COUNTY-NUM
PERFORM RESTRUCTURE-NAME
RELEASE WORK-REC
END-SEARCH
MOVE SPACES TO UNSORTED-REC
READ UNSORTED-NAMES
AT END SET END-OF-FILE TO TRUE
END-READ.

RESTRUCTURE-NAME.
MOVE 1 TO UNSTR-PTR, STR-PTR.
PERFORM UNTIL END-OF-NAME
MOVE UNSTR-PTR TO NAME-END
UNSTRING HOLD-CLIENT DELIMITED BY ALL SPACES
INTO HOLD-NAME
WITH POINTER UNSTR-PTR
END-PERFORM

STRING HOLD-NAME DELIMITED BY SPACES


SPACE DELIMITED BY SIZE
INTO CLIENT-NAME
WITH POINTER STR-PTR.

MOVE 1 TO UNSTR-PTR
PERFORM UNTIL UNSTR-PTR >= NAME-END
UNSTRING HOLD-CLIENT DELIMITED BY SPACES
INTO HOLD-NAME

81
WITH POINTER UNSTR-PTR
STRING HOLD-NAME DELIMITED BY SPACES
SPACE DELIMITED BY SIZE
INTO CLIENT-NAME
WITH POINTER STR-PTR
END-PERFORM.

The COBOL Report Writer


COBOL Tables
MonthTable.cbl

This program counts the number of students born in each month and displays the result.
The program uses a pre-filled table of month names.
This program is the solution to one of the programming exercises.
Read the program specification first

Introduction

A program is required which will process the Students File (Students.Dat) and will count the number
students born on each month of the year and will display the results to January to December order.
 Download Students.Dat and save it to the WorkArea directory on the drive D:
 

Student File Description

order.
The Students File is a sequential file held in ascending StudentId
Each record of the students file contains the following items;
Field Type Length Value
Student Id 9 7 0-9999999
Student Name Group
Surname X 8 -
Initials X 2 -
DateOfBirth Group
Year 9 4 0000-9999
Month 9 2 01-12
Day 9 2 01-31
Course Code X 4 -
Gender X 1 M/F
 
Example Run
 Month    StudCount
January        2
February       2
March          3

82
April          4
May            1
June           0
July           2
August         1
September      4
October        5
November       3
December       5
Use Edited picture clauses and the zero suppression symbol to produce the output as shown.
 

Suggested Approaches.

The main problem that we face here is that the results must be displayed in MonthName order but the file is
held in StudentId order.
A tables based solution is a good idea here.  We can use the month number as a direct index into the month
table.
 
$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. MonthTable.
AUTHOR. Michael Coughlan.
* This program counts the number of students born in each month and
* displays the result.

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT StudentFile ASSIGN TO "STUDENTS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.
FD StudentFile.
01 StudentDetails.
88 EndOfStudentFile VALUE HIGH-VALUES.
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.

WORKING-STORAGE SECTION.
01 MonthTable.
02 TableValues.
03 FILLER PIC X(18) VALUE "January February".
03 FILLER PIC X(18) VALUE "March April".
03 FILLER PIC X(18) VALUE "May June".
03 FILLER PIC X(18) VALUE "July August".

83
03 FILLER PIC X(18) VALUE "SeptemberOctober".
03 FILLER PIC X(18) VALUE "November December".
02 FILLERh REDEFINES TableValues.
03 Month OCCURS 12 TIMES PIC X(9).

01 MonthCount OCCURS 12 TIMES PIC 999 VALUE ZEROS.

01 MonthIdx PIC 999.

01 HeadingLine PIC X(19) VALUE " Month StudCount".

01 DisplayLine.
02 PrnMonth PIC X(9).
02 FILLER PIC X(4) VALUE SPACES.
02 PrnStudentCount PIC ZZ9.

PROCEDURE DIVISION.
Begin.
OPEN INPUT StudentFile
READ StudentFile
AT END SET EndOfStudentFile TO TRUE
END-READ
PERFORM UNTIL EndOfStudentFile
ADD 1 TO MonthCount(MOBirth)
READ StudentFile
AT END SET EndOfStudentFile TO TRUE
END-READ
END-PERFORM

DISPLAY HeadingLine
PERFORM VARYING MonthIdx FROM 1 BY 1 UNTIL MonthIdx > 12
MOVE Month(MonthIdx) TO PrnMonth
MOVE MonthCount(MonthIdx) TO PrnStudentCount
DISPLAY DisplayLine
END-PERFORM.

CLOSE StudentFile
STOP RUN.
FlyByNight.cbl

Exam paper model answer. A program is required which will read the Booking Master
file to produce a Summary file sequenced upon ascending Destination-Name.
Read the program specification first

$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. DP173EXAM1986.
AUTHOR. Michael Coughlan

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT BOOKING-FILE ASSIGN TO "BOOKING.DAT"

84
ORGANIZATION IS LINE SEQUENTIAL.
SELECT WORK-FILE ASSIGN TO "WORK.DAT".
SELECT SORTED-FILE ASSIGN TO "BOOKSORT.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT SUMMARY-FILE ASSIGN TO "SUMMARY.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

DATA DIVISION.
FILE SECTION.

FD BOOKING-FILE.
01 CUSTOMER-RECORD-FA.
02 CUST-NAME-FA PIC X(30).
02 DEST-NAME-FA PIC X(20).
02 BOOKING-CHARGE-FA PIC 9(5)V99.
02 NUM-OF-MALES-FA PIC 99.
02 NUM-OF-FEMALES-FA PIC 99.
02 NUM-OF-CHILDREN-FA PIC 99.
02 CATEGORY-FA PIC X.
88 TOURIST VALUE "T".

SD WORK-FILE.
01 WORK-RECORD-FB.
02 FILLER PIC X(30).
02 DEST-NAME-FB PIC X(20).
02 FILLER PIC X(14).

FD SORTED-FILE.
01 CUSTOMER-RECORD-FC.
02 CUST-NAME-FC PIC X(30).
02 DEST-NAME-FC PIC X(20).
02 BOOKING-CHARGE-FC PIC 9(5)V99.
02 NUM-OF-MALES-FC PIC 99.
02 NUM-OF-FEMALES-FC PIC 99.
02 NUM-OF-CHILDREN-FC PIC 99.
02 CATEGORY-FC PIC X.

FD SUMMARY-FILE.
01 SUMMARY-RECORD-FD.
02 DEST-NAME-FD PIC X(20).
02 TOTAL-RECEIPTS-FD PIC 9(8)V99.
02 TOTAL-MALES-FD PIC 9(6).
02 TOTAL-FEMALES-FD PIC 9(6).
02 TOTAL-CHILDREN-FD PIC 9(6).

WORKING-STORAGE SECTION.
01 FLAGS-WA.
02 IS-IT-END-OF-FILE PIC 9 VALUE ZERO.
88 END-OF-FILE VALUE 1.

85
88 NOT-END-OF-FILE VALUE 0.

01 LOC-SURCHARGE-VALUES-WB.
02 FILLER PIC X(39)
VALUE "AFGHANISTAN50CAMBODIA 24CORSICA 18".
02 FILLER PIC X(39)
VALUE "EL SALVADOR85HAITI 21HONDURAS 23".
02 FILLER PIC X(39)
VALUE "ISRAEL 11IRAN 57IRAQ 33".
02 FILLER PIC X(39)
VALUE "LAOS 13LEBANON 90LIBYA 20".
02 FILLER PIC X(39)
VALUE "NICARAGUA 47SARDINIA 25SICILY 20".
02 FILLER PIC X(26)
VALUE "SPAIN 05SURINAM 07".

01 LOC-SURCHARGE-TABLE-WB REDEFINES LOC-SURCHARGE-VALUES-WB.


02 LOCATION-GROUP-WB
OCCURS 17 TIMES INDEXED BY LOC-PTR.
03 LOCATION-WB PIC X(11).
03 SURCHARGE-WB PIC 99.

01 MISC-VARIABLES-WC.
02 SURCHARGE-WC PIC 9(4)V99.
02 HOLD-DEST-WC PIC X(20).

PROCEDURE DIVISION.
MAIN SECTION.
10-START.
SORT WORK-FILE
ON ASCENDING DEST-NAME-FB
INPUT PROCEDURE IS SELECT-TOURISTS
GIVING SORTED-FILE.

OPEN INPUT SORTED-FILE.


OPEN OUTPUT SUMMARY-FILE.

READ SORTED-FILE
AT END SET END-OF-FILE TO TRUE.
PERFORM 20-CREATE-SUMMARY-FILE
UNTIL END-OF-FILE.

CLOSE SORTED-FILE
SUMMARY-FILE.
STOP RUN.

20-CREATE-SUMMARY-FILE.
MOVE ZEROS TO SUMMARY-RECORD-FD.
MOVE DEST-NAME-FC TO DEST-NAME-FD.
PERFORM 30-PROCESS-DESTINATION-RECS
UNTIL DEST-NAME-FC NOT EQUAL TO DEST-NAME-FD
OR END-OF-FILE.

SET LOC-PTR TO 1.

86
SEARCH LOCATION-GROUP-WB
AT END DISPLAY DEST-NAME-FD " NOT HOSTILE"
WHEN LOCATION-WB(LOC-PTR) = DEST-NAME-FD
COMPUTE SURCHARGE-WC ROUNDED
= (TOTAL-RECEIPTS-FD / 100) * SURCHARGE-WB(LOC-PTR)
ADD SURCHARGE-WC TO TOTAL-RECEIPTS-FD.

WRITE SUMMARY-RECORD-FD.

30-PROCESS-DESTINATION-RECS.
ADD BOOKING-CHARGE-FC TO TOTAL-RECEIPTS-FD.
ADD NUM-OF-MALES-FC TO TOTAL-MALES-FD.
ADD NUM-OF-FEMALES-FC TO TOTAL-FEMALES-FD.
ADD NUM-OF-CHILDREN-FC TO TOTAL-CHILDREN-FD
READ SORTED-FILE
AT END SET END-OF-FILE TO TRUE.

SELECT-TOURISTS SECTION.
BEGIN.
OPEN INPUT BOOKING-FILE.
READ BOOKING-FILE
AT END SET END-OF-FILE TO TRUE.
PERFORM UNTIL END-OF-FILE
IF TOURIST THEN
INSPECT DEST-NAME-FA CONVERTING
"abcdefghijklmnopqrstuvwxyz"
TO
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
RELEASE WORK-RECORD-FB FROM CUSTOMER-RECORD-FA
END-IF
READ BOOKING-FILE
AT END SET END-OF-FILE TO TRUE
END-READ
END-PERFORM.
SET NOT-END-OF-FILE TO TRUE.
CLOSE BOOKING-FILE.

USSRship.cbl

Exam paper model answer. A program is required to produce a report detailing the major
vessels (Vessels of tonnage 3,500 or greater and all submarines) in each of oceans and
major seas of the world.
Read the program specification first.

Introduction

The FlyByNight travel agency sends its customers all over the world. For each booking a record is created
in the Booking Master file (BOOKING.DAT). Each customer booking is assigned (as part of the
record) a category indicating the primary reason for the booking (i.e. Sport, Tourism,
Business, Personal and Other). The file is unsorted and each record has the following
description;

87
Field Type Length Value
Customer-Name X 30 upper & lower case
Destination-Name X 20 upper & lower case
Booking-Charge N 7 10.00 - 99999.99
Num-Of-Males N 2 0 - 99
Num-Of-Females N 2 0 - 99
Num-Of-Children N 2 0 - 99
Category X 1 S/T/B/P/O
 

The Task

A program is required which will read the Booking Master file to produce a Summary
file sequenced upon ascending Destination-Name. Each record in this file will be a
summary of all the Tourist records in the Booking file which list a particular location as
their destination. The record will show the Destination-Name, the Total-Receipts from
tourists travelling to that destination and the Total-Males, Total-Females and Total-
Children who make up that tourist population. Each record in the Summary file has the
description shown below;
Field Type Length Value
Destination-Name X 20 upper case only
Total-Receipts N 10 10.00 - 99999999.99
Total-Males N 6 0 - 999999
Total-Females N 6 0 - 999999
Total-Children N 6 0 - 999999
 

The Danger Levy

As well as the Booking-Charge, tourists travelling to some destinations will incur an additional insurance
charge. This will be levied as a percentage of the Booking-Charge and will be added to it to give a Total-
Charge for the booking (e.g. Charge = $250.00, Percentage Insurance = 15%, Total-Charge = $287.50).
Listed below are affected countries as well as the insurance charges that travelling to them will incur.
Afghanistan 50%, Cambodia 24%, Corsica 18%, El Salvador 85%,
Haiti 21%, Honduras 23%, Israel 11%, Iran 57%, Iraq 33%,
Note that the Destination-Name in the Booking Master File may be all upper case or all lower case or a
mixture. Note also that "France" is not equal to "FRANCE".

Suggested Procedure

Sort the Booking Master file into Destination-Name order, eliminating all non-tourist records and changing
the Destination-Name to upper case before the actual sort is done.
For each group of records for a particular Destination;

Sum all the Males, Females and Children.


Sum all the Booking-Charges.

88
When all the records for the group have been processed check to see if the destination is
in the insurance surcharge group. If it is, work out the insurance charge and add it to the
Total-Booking-Charges giving the Total-Receipts.
Set up the output record and write it to the Summary File.

$ SET SOURCEFORMAT"FREE"
IDENTIFICATION DIVISION.
PROGRAM-ID. DP173EXAM.
AUTHOR. Michael Coughlan.
*Originally written for VAX COBOL 1983
*Converted to Microfocus COBOL 2002#
*One of a series of "Big Brother" or security based specs
* as we approached 1984

ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT VESSEL-FILE ASSIGN TO "UVMF.DAT"
ORGANIZATION IS LINE SEQUENTIAL.

SELECT WORK-FILE ASSIGN TO "WORK.DAT".

SELECT SORTED-FILE ASSIGN TO "SORTED.DAT"


ORGANIZATION IS LINE SEQUENTIAL.

SELECT PRINT-FILE ASSIGN TO "USSRSHIP.RPT".

DATA DIVISION.
FILE SECTION.

FD VESSEL-FILE.
01 FA-VESSEL-RECORD.
02 FA-VESSEL-NAME PIC X(20).
02 FA-VESSEL-TYPE PIC 99.
88 SUBMARINE VALUE 5,6.
02 FA-TONNAGE PIC 9(6).
88 MAJOR-VESSEL VALUE 3500 THRU 999999.
02 FA-CREW PIC 9(5).
02 FA-LOCATION-CODE PIC X.

SD WORK-FILE.
01 FB-WORK-RECORD.
02 FILLER PIC X(20).
02 FB-VESSEL-TYPE PIC 99.
02 FILLER PIC 9(6).
02 FILLER PIC 9(5).
02 FB-LOCATION-CODE PIC X.

89
FD SORTED-FILE.
01 FC-VESSEL-RECORD.
02 FC-VESSEL-NAME PIC X(20).
02 FC-TYPE PIC 99.
02 FC-TONNAGE PIC 9(6).
02 FC-CREW PIC 9(5).
02 FC-LOCATION PIC 9.

FD PRINT-FILE.
01 FD-PRINT-RECORD PIC X(97).

WORKING-STORAGE SECTION.
01 WA-DETAIL-LINE.
02 WA-PRINT-LOCATION PIC X(17).
02 WA-PRINT-FUNCTION PIC BBX(22).
02 WA-PRINT-NAME PIC BBX(20).
02 WA-PRINT-TONNAGE PIC BBBBZZZ,ZZ9.
02 WA-PRINT-CREW PIC BBZZ,ZZ9.
02 WA-PRINT-MONTHLY-COST PIC BBB$$$,$$$,$$9.

01 WB-MAIN-HEADING.
02 FILLER PIC X(25) VALUE SPACES.
02 FILLER PIC X(42)
VALUE "U.S.S.R. NAVAL VESSEL INVENTORY REPORT".

01 WC-TITLES.
02 FILLER PIC X(47)
VALUE " LOCATION NAME VESSEL FUNCTION ".
02 FILLER PIC X(50)
VALUE "VESSEL NAME TONNAGE CREW MONTHLY COST".

01 WD-NAME-TABLE.
02 WD-TABLE-VALUES.
03 FILLER PIC X(22) VALUE "AIRCRAFT CARRIER ".
03 FILLER PIC X(22) VALUE "CRUISER/BATTLESHIP ".
03 FILLER PIC X(22) VALUE "DESTROYER ".
03 FILLER PIC X(22) VALUE "FRIGATE ".
03 FILLER PIC X(22) VALUE "NUCLEAR SUBMARINE ".
03 FILLER PIC X(22) VALUE "CONVENTIONAL SUBMARINE".
03 FILLER PIC X(22) VALUE "ASSAULT SHIP ".
03 FILLER PIC X(22) VALUE "SUPPLY SHIP ".
03 FILLER PIC X(22) VALUE "CORVETTE ".
03 FILLER PIC X(22) VALUE "MINE LAYER/HUNTER ".
03 FILLER PIC X(22) VALUE "FAST ATTACK CRAFT ".
03 FILLER PIC X(22) VALUE "COSTAL PATROL CRAFT ".

02 FILLER REDEFINES WD-TABLE-VALUES.

90
03 WD-VESSEL-FUNCTION PIC X(22) OCCURS 12 TIMES.

01 WE-RATE-TABLE.
02 WE-TABLE-VALUES.
03 FILLER PIC X(48)
VALUE "261023502050099925502510078906320770087007500636".
03 FILLER PIC X(48)
VALUE "256023000960098624362400071006110720083307100606".
03 FILLER PIC X(48)
VALUE "240020100960086022002386067005500700080006850596".
03 FILLER PIC X(48)
VALUE "258623352100099624862435076006050750085007400620".
03 FILLER PIC X(48)
VALUE "250021850900091024002336069605860716083006960610".

02 FILLER REDEFINES WE-TABLE-VALUES.


03 WE-LOCATION OCCURS 5 TIMES.
04 WE-VESSEL-TYPE OCCURS 12 TIMES.
05 WE-MONTHLY-RATE PIC 9(4).

01 WF-LOCATION-TABLE.
02 WF-TABLE-VALUES.
03 FILLER PIC X(17) VALUE "THE PACIFIC ".
03 FILLER PIC X(17) VALUE "THE ATLANTIC ".
03 FILLER PIC X(17) VALUE "THE MEDITERRANEAN".
03 FILLER PIC X(17) VALUE "THE INDIAN OCEAN ".
03 FILLER PIC X(17) VALUE "THE OTHER SEAS ".

02 FILLER REDEFINES WF-TABLE-VALUES.


03 WF-LOCATION PIC X(17) OCCURS 5 TIMES.

01 WG-FLAGS.
02 IS-IT-END-OF-FILE PIC X(3).
88 END-OF-FILE VALUE "YES".

01 WH-OTHER-VARIABLES.
02 WH-PREVIOUS-TYPE PIC 99.
02 WH-PREVIOUS-LOCATION PIC X.
02 WH-MONTHLY-TOTAL PIC 9(8).

PROCEDURE DIVISION.
MAIN SECTION.
10-START.
SORT WORK-FILE
ON ASCENDING KEY FB-LOCATION-CODE
FB-VESSEL-TYPE
INPUT PROCEDURE IS SELECT-MAJOR-SHIPS
GIVING SORTED-FILE.

91
OPEN INPUT SORTED-FILE.
OPEN OUTPUT PRINT-FILE.
READ SORTED-FILE
AT END MOVE "YES" TO IS-IT-END-OF-FILE.
MOVE SPACES TO FD-PRINT-RECORD.
WRITE FD-PRINT-RECORD AFTER ADVANCING PAGE.
WRITE FD-PRINT-RECORD FROM WB-MAIN-HEADING
AFTER ADVANCING 1 LINES.
WRITE FD-PRINT-RECORD FROM WC-TITLES
AFTER ADVANCING 3 LINES.
PERFORM 20-PRODUCE-REPORT
UNTIL END-OF-FILE.
CLOSE PRINT-FILE
SORTED-FILE.
STOP RUN.

20-PRODUCE-REPORT.
MOVE FC-LOCATION TO WH-PREVIOUS-LOCATION.
MOVE WF-LOCATION(FC-LOCATION) TO WA-PRINT-LOCATION.
PERFORM 30-PRODUCE-REPORT-FOR-LOCATION
UNTIL FC-LOCATION NOT EQUAL TO WH-PREVIOUS-LOCATION
OR
END-OF-FILE.

30-PRODUCE-REPORT-FOR-LOCATION.
MOVE FC-TYPE TO WH-PREVIOUS-TYPE.
MOVE WD-VESSEL-FUNCTION(FC-TYPE) TO WA-PRINT-FUNCTION.
PERFORM 40-PRODUCE-FUNCTION-REPORT
UNTIL FC-TYPE NOT EQUAL TO WH-PREVIOUS-TYPE
OR
FC-LOCATION NOT EQUAL TO WH-PREVIOUS-LOCATION
OR
END-OF-FILE.

40-PRODUCE-FUNCTION-REPORT.
MULTIPLY FC-CREW BY WE-MONTHLY-RATE(FC-LOCATION, FC-TYPE)
GIVING WH-MONTHLY-TOTAL.
MOVE WH-MONTHLY-TOTAL TO WA-PRINT-MONTHLY-COST.
MOVE FC-CREW TO WA-PRINT-CREW.
MOVE FC-TONNAGE TO WA-PRINT-TONNAGE.
MOVE FC-VESSEL-NAME TO WA-PRINT-NAME.
WRITE FD-PRINT-RECORD FROM WA-DETAIL-LINE
AFTER ADVANCING 2 LINES.
MOVE SPACES TO WA-DETAIL-LINE.
READ SORTED-FILE
AT END MOVE "YES" TO IS-IT-END-OF-FILE.

SELECT-MAJOR-SHIPS SECTION.
10-START-PROCEDURE.
OPEN INPUT VESSEL-FILE.

92
READ VESSEL-FILE
AT END MOVE "YES" TO IS-IT-END-OF-FILE.
PERFORM 20-GET-MAJOR-VESSELS UNTIL END-OF-FILE.
CLOSE VESSEL-FILE.
MOVE "NO" TO IS-IT-END-OF-FILE.
GO TO 30-EXIT-SELECT-MAJOR-SHIPS.

20-GET-MAJOR-VESSELS.
IF SUBMARINE OR MAJOR-VESSEL
RELEASE FB-WORK-RECORD
FROM FA-VESSEL-RECORD.
READ VESSEL-FILE
AT END MOVE "YES" TO IS-IT-END-OF-FILE.

30-EXIT-SELECT-MAJOR-SHIPS.
EXIT.

93

You might also like