FILE STATUS handling in COBOL

FILE STATUS (error handling)
===========================

A number of errors can occur that result from file input/output that
programmer may wish to be able to deal with in order to avoid
unexpected program termination.


Run time errors can arise quite easily from a file not being available
to open, or if present the data is corrupted. Furthermore, what if
there is no more disk space available or not enough space has been
allocated to allow for addtition of new data. Other errors, such as
attempting to close a file that isn't open, or to read a file opened
for output only, may well derive from logical errors (that is,
programming mistakes) but can be dealt with nonetheless when
debugging. These kinds of errors will normally result in termination
of the program run, whereas using File Status can allow the programmer
to deal with any such problems without the program run stopping and
returning to the operating system.

File Status Codes are made of two digits, the first indicates one one
of 5 classes:

0 ----> Input/output operation successful
1 ----> File "at end" condition
2 ----> Invalid key
3 ----> Permanent I/O error
4 ----> Logic error

The second digit refers to the particular case within the class. Here
are examples common to both Microfocus and Fujitsu compilers (although
there are more besides). I would check your compiler documentation.
----------------------------------------------------------------------------------------
Code Meaning
----------------------------------------------------------------------------------------
00 ---> Input/output operation successful
02 ---> Duplicate record key found (READ ok)
04 ---> Length of record too large (READ ok)
10 ---> File AT END
14 ---> "The valid digits of a read relative record
number are greater than the size of the relative
key item of the file."
16 ---> Program tries to read file already AT END
22 ---> Program attempts to write a record
with a key that already exists
23 ---> Record not found
24 ---> Program attempts to write record to a disk that is full
30 ---> Input/output operation unsuccessful,
no further information available
34 ---> Program attempts to write record to a disk that is full
35 ---> Program tries to open non-existant file
for INPUT, I-O or EXTEND
37 ---> Program tries to open line sequential file in I-O mode
41 ---> Program tries to open file that is already open
42 ---> Program tries to close file that is not open
43 ---> Program tries to delete or rewrite a record
that has not been read
44 ---> Program tries to write or rewrite a record of incorrect length
46 ---> Program tries to read a record where the previous read or
START has failed or the AT END condition
has occurred
47 ---> Program tries to read a record from a file opened
in the incorrect mode
48 ---> Program tries to write a record from a file opened
in the
incorrect mode
49 ---> Program tries to delete or rewrite a record from a file opened
in
the incorrect mode
-------------------------------------------------------------------------------------------
To use these codes you need to include the FILE STATUS clause in the
SELECT statement of the environment division:

SELECT TEST-FILE ASSIGN TO 'TEST-DATA.DAT'
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS W-STATUS.

Of course W-STATUS could any user name you like. It must however be
defined in working storage as PIC XX, i.e. as alpha numeric and not
numeric. So, if during a program run a certain input/output error
occurs, rather than the program terminate, the program will simply
produce an error status.

code:

*
Here a possible danger of too big a record being moved into W-RECORD
READ RECORD-IN INTO W-RECORD
IF W-STATUS = "04" THEN
DISPLAY "Over-sized record has been read"
SET REC-XS-FLAG TO TRUE
END-IF


Another example might be, when reading from an indexed file:
READ IN-FILE
IF W-STATUS = "23" THEN
DISPLAY "Record not found"
ELSE PERFORM MAIN-PROCESS


You could have easily have written:
READ IN-FILE
INVALID KEY
DISPLAY "Record not found"
NOT INVALID KEY PERFORM MAIN-PROCESS
END-READ


So consider which is the best option and remember not to try and do both.

File handling in COBOL - II

==================
SORT and MERGE
==================
If you wished to take a file of unordered records and produce a new
file of these records sorted into ascending or descending order of a
field you would use SORT.

The League table program in the Sample code section uses this utility
to generate a league table from updated records from a data file,
sorted principally by descending points.

Consider this segment of code from this program:


000050 ENVIRONMENT DIVISION.
000060 INPUT-OUTPUT SECTION.
000070 FILE-CONTROL.
000080 SELECT TEAM-REC-IN ASSIGN TO "INPUT.REC"
000090 ORGANIZATION IS SEQUENTIAL.
000100 SELECT WORK-FILE ASSIGN TO SORTWK01.
000110 SELECT SORT-OUT ASSIGN TO "SORTED.REC"
000120 ORGANIZATION IS SEQUENTIAL.
000130 SELECT PRINT-FILE ASSIGN TO "PRINTOUT.TXT".
000140
000150 000160 DATA DIVISION.
000170 FILE SECTION.
000180 FD TEAM-REC-IN.
000190 01 TEAM-REC.
000200 03 TEAM-CODE PIC XXX.
000210 03 TEAM-NAME PIC X(20).
000220 03 PLAYED PIC 99.
000230 03 GOALS-FOR PIC 99.
000240 03 GOALS-AGST PIC 99.
000250 03 G-WON PIC 99.
000260 03 G-LOST PIC 99.
000270 03 G-DRAWN PIC 99.
000280 03 GOAL-DIFF PIC S99 SIGN LEADING SEPARATE.
000290 03 POINTS PIC 99.
000300 000310 SD WORK-FILE.
000320 01 WORK-REC.
000330 03 TEAM-CODE-KEY PIC XXX.
000340 03 PIC X(22).
000350 03 GF-KEY PIC 99.
000360 03 PIC X(8).
000370 03 GD-KEY PIC S99 SIGN LEADING SEPARATE.
000380 03 POINTS-KEY PIC 99.


In addition to the FD for the TEAM-REC-IN (the main data file) there
is also a WORK-FILE that the computer uses for sorting. Here it is
assigned to SORTWK01, required for the Fujitsu COBOL compiler, but for
MicroFocus you might code ASSIGN TO DISK or even ASSIGN TO
"B:TEMPFILE".

The WORK-FILE does not have a FD descriptor, but rather, has a sort
descriptor SD.


003310 SORT-TABLE.
003320 SORT WORK-FILE
003330 ON DESCENDING KEY POINTS-KEY GD-KEY GF-KEY
003340 USING TEAM-REC-IN
003350 GIVING SORT-OUT.

The SORT-TABLE paragraph then sorts the data file TEAM-REC-IN as shown
above. Note that the SORT verb is followed by WORK-FILE and that
TEAM-REC-IN is refered to with USING...

Since it is common for two teams to have the same number of points
then, the DESCENDING KEY first attempts to sort by points (POINTS-KEY)
but if these match then they are than sorted by goal difference
(GD-KEY) and then by goals scored (GF-KEY). If these all match then
the teams will be placed as the appear from the data file (for
TEAM-REC-IN I placed them in alphabetical order).

SORT-OUT is the destination of the sorted data where the new league
table would appear.

Note, a file that is to be sorted if already open, must be closed
prior to sorting. THE SORT STATEMENT WILL AUTOMATICALLY OPEN THE
UNSORTED FILE WHEN EXECUTED.

===========
MERGE
===========
To merge two sorted files into a single sorted file, the MERGE
statement is used:


MERGE WORK-FILE
ON ASCENDING KEY CUS-CODE-KEY
USING FILE-A
FILE-B
GIVING MERGED-FILE

You can merge more than 2 files if you wish. An SD would be required
as used with a SORT


----------------------------------------------------------------------------------------------------------
=============================
INPUT and OUTPUT PROCEDURE
==============================

The SORT statement above sorted all the records in the file into a new file.

But if you wanted to produce a sorted file that only contained, for
example, product numbers which begin with a '1', you would use an
INPUT PROCEDURE.

The record FD might be:

FD UNSORTED-FILE.
01 UNSORTED-RECORD.
03 1ST-DIGIT-OF-CODE PIC 9.
03 PIC X(20).


The description gives the minimum detail required. Now some procedure division:

PROCEDURE DIVISION.
SORT-SELECT.
SORT WORK-FILE
ON DESCENDING KEY PRODUCT-NO
INPUT PROCEDURE SELECT-PROD-CODE
GIVING SORTED-CODES-FILE
STOP RUN.


The INPUT PROCEDURE clause acts like a PERFORM, indicating the logic
to go to a different paragraph (i.e. procedure).

So the paragraph SELECT-PROD-CODE might be like this:

SELECT-PROD-CODE.
OPEN INPUT UNSORTED-DATA-FILE
PERFORM UNTIL END-OF-FILE
READ UNSORTED-DATA-FILE
AT END MOVE
'Y' TO EOF-FLAG
NOT AT END
IF 1ST-DIGIT-OF-CODE = 1 THEN
MOVE UNSORTED-RECORD TO WORK-REC
RELEASE WORK-REC
END-IF
END-READ
END-PERFORM
CLOSE UNSORTED-DATA-FILE


When the if condition is true, the record is moved to the work-file
(WORK-REC is the level 01 name) by the RELEASE verb, even though the
MOVE verb appears first (I dunno why..!). Unlike a simple SORT, you DO
have to OPEN the unsorted file prior to an input procedure.

OUTPUT PROCEDURE


If you just want to print specific sorted fields you would use an
OUTPUT PROCEDURE. Based on the above example:

PROCEDURE DIVISION.
PRINT-SORT-REC.
SORT WORK-FILE
ON DESCENDING KEY PRODUCT-NO
USING UNSORTED-RECORD
OUTPUT PROCEDURE PRINT-SELECT-PROD-CODE
STOP RUN.


The INPUT PROCEDURE clause acts like a PERFORM, indicating the logic
to go to a different paragraph (i.e. procedure).

So the paragraph SELECT-PROD-CODE might be like this:

SELECT-PROD-CODE.
OPEN OUTPUT PRINT-FILE
PERFORM UNTIL END-OF-FILE
RETURN UNSORTED-DATA-FILE
AT END MOVE 'Y' TO EOF-FLAG
NOT AT END
{move fields
in SD sort group to print fields}...
WRITE PRINT-RECORD FROM
{print group}
END-RETURN
END-PERFORM
CLOSE PRINT-FILE.


Instead of READ you use RETURN and then WRITE the record
to the printer rather than RELEASE the record to a file.

You can combine INPUT and OUTPUT procedures into the same sort
statement by replacing both the USING and GIVING statements:


SORT WORK-FILE ON DESCENDING KEY PRODUCT-NO
INPUT PROCEDURE SELECT-PROD-CODE
OUTPUT PROCEDURE PRINT-SELECT-PROD-CODE
STOP RUN.


------------------------------------------------------------------------------------------------------

FILE Handling in COBOL

File Handling
===============

This section outlines how data can read from and written to files, how
records are organized within a file and how records can be manipulated
(e.g. sorting, merging).


1)Reading and Writing
-----------------------------
In order to either read, alter or create a new file, we must first
open it (even if it doesn't even exist yet). In doing so, a open mode
must be defined.

To simply read data from an existing file it would be opened in INPUT
mode. In this mode, the file is read-only and cannot be altered in any
way.
If writing to new file, i.e. creating one (or overwriting an existing
file so be careful) the new file would be opened in OUTPUT mode. You
cannot read data from a file opened in OUTPUT mode.
EXTEND mode allows for records to be added to the end of an existing file.
I-O mode is for input and output access to the file, such as when you
wish to update a record, or delete a record.

When a file is no longer required, the file needs to be closed again
(using CLOSE). You can open and close a file as often as you like
during a program run, although bear in mind that each time you open a
file the computer will read from the first record onwards (in INPUT
and I-O mode) or will overwrite in OUTPUT mode.

OPEN {INPUT or OUTPUT or I-O or EXTEND} {filename-1}...
{INPUT or OUTPUT or I-O or EXTEND} {filename-2}...


e.g.


OPEN INPUT DATA-1-FILE DATA-2-FILE
OUTPUT NEW-DATA-FILE

CLOSE DATA-1-FILE DATA-2-FILE NEW-DATA-FILE

READ
=============
The READ statement will read the data from a file, taking precisely
the data that is defined in the file descriptor (FD) in the data
division (file section) (see The Four Divisions section).
The format is:


READ {FD filename}
AT END {statements}
NOT AT END {statements}
END-READ

Since a file would likely contain more than one record, the READ
statement is often contained within a PERFORM loop:


IDENTIFICATION DIVISION.
PROGRAM-ID. READ-EXAMPLE.
AUTHOR ZINGMATTER.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
ASSIGN IN-FILE TO 'A:CUSTOMER.DAT'
ORGANIZATION IS LINE SEQUENTIAL.
ASSIGN PRINT-FILE TO PRINTER.
DATA DIVISION.
FILE SECTION.
FD IN-FILE.
01 CUSTOMER-DETAILS.
03 CUS-NAME PIC X(20).
03 CUS-NUM PIC 9(6).

FD PRINT-FILE.
01 PRINT-REC PIC X(60).

WORKING-STORAGE SECTION.
01 EOF-FLAG PIC X.
88 END-OF-IN-FILE VALUE 'Y'.
01 P-CUS-DETAILS
03 PIC X(5) VALUE SPACES.
03 P-NAME PIC X(25).
03 P-NUM PIC Z(5)9.

PROCEDURE DIVISION.
MAIN-PARAGRAPH.
OPEN INPUT IN-FILE
***********************"Prime" read
READ IN-FILE
AT END MOVE 'Y' TO EOF-FLAG
NOT AT END PERFORM PRINT-DETAILS
END-READ
***********Main reading loop
PERFORM UNTIL END-OF-IN-FILE
READ IN-FILE
AT END MOVE 'Y' TO EOF-FLAG
NOT AT END PERFORM PRINT-DETAILS
END-READ
END-PERFORM
STOP RUN.

PRINT-DETAILS.
MOVE CUS-NAME TO P-NAME
MOVE CUS-NUM TO P-NUM
WRITE PRINT-REC FROM P-CUS-DETAILS AFTER 1 LINE.


* A record containing a customer name (CUS-NAME) and the customer
number (CUS-NUM) are read from a file customer.dat assign to IN-FILE.

* The file is opened for INPUT (i.e. read-only).

* The "prime read" refered to in the comment is the initial read of
IN-FILE that allows for the possibility that the file contains no
records.

* The AT END clause tests for the end of file condition. When true, a
series of statements can then be executed. Likewise, the NOT AT END
clause allows for a series of statements to be executed when this
condition is true. In the above example, when the file contains no
more records (i.e. is at the end of the file) 'Y' is moved to
EOF-FLAG, thereby making the condition name condition (END-OF-IN-FILE)
true. When not at the end of the file, a record is read into memory
and the paragraph PRINT-DETAILS is executed.

* The statements between PERFORM UNTIL... and END-PERFORM are executed
until the END-OF-IN-FILE condition is true (when the AT END of the
read statement is true).

If you want to place data from a record into an item in
WORKING-STORAGE (in addition to the memory space already allocated to
the same data defined in the data division - so not much call for it),
then use READ ... INTO. i.e:


READ IN-FILE INTO W-RECORD-IN


2) REWRITE, DELETE, and EXTEND
==============================

In order to ammend a record in a file, such as to update data (see
League Table Program in sample programs section), to delete a record
altogther, or to add a record to the end of a file, you can use
REWRITE, DELETE or EXTEND, respectively.

However, to use REWRITE or DELETE you must open the file using I-O
mode. Also, DELETE can only be used on files with RELATIVE or INDEXED
organization (see example below).

RELATIVE and INDEXED files are discussed in the following section

The format of the DELETE statement is:

DELETE filename
ON INVALID KEY
{statements}
NOT ON INVALID KEY
{statements}

END-DELETE


ON INVALID KEY means the record was not found, so you might want to
display an error message

e.g. DISPLAY 'RECORD NOT FOUND'

To REWRITE you can refer to the level 01 name to change the record
with the ammended field:

FD IN-FILE
01 RECORD-IN.
03 IN-NAME PIC X(20).
03 IN-ADDRESS PIC X(60).

PROCEDURE DIVISION.
MAIN-PARAGRAPH.
:

OPEN I-O IN-FILE
:

READ IN-FILE

IF IN-NAME = 'BILLY NOMATES' THEN
MOVE 'JIMMY MOREPALS' TO IN-NAME
REWRITE RECORD-IN
ELSE
DISPLAY IN-NAME
END-IF
:

To EXTEND you must open the file in EXTEND mode:

OPEN EXTEND IN-FILE
:

DISPLAY 'Type in new name'
ACCEPT NEW-NAME
MOVE NEW-NAME TO IN-NAME
EXTEND IN-FILE

DISPLAY 'Type in new address'
ACCEPT NEW-ADDRESS
MOVE NEW-ADDRESS TO IN-ADDRESS
EXTEND IN-FILE
:

Here is a sample program that deletes a record from an INDEXED file
using the DELETE statement, followed by deletion of a record that does
not use the DELETE statement but writes the whole file (less the
record to be deleted) to a temporary file. The program asks for a six
digit code that identifies the record to be removed from the file. If
you want to try this program then you'll need to create a couple of
test files: TESTDATA1.DAT and TESTDATA2.TXT.

TESTDATA1.DAT needs to be an indexed file. To create this you'll need
to compile and run the Create INDEXED file program and Read INDEXED
file program (both in the Sample Code section).

TESTDATA2.TXT should be LINE SEQUENTIAL and of the form:

CODE--SOME ENTRY OF 43 CHARACTERS
123456abc----------**********----------**********
:
:


Sample program :-
-------------------
IDENTIFICATION DIVISION.
PROGRAM-ID. DELETION-EXAMPLE.
AUTHOR. TIM-R-P-BROWN.
* Program that deletes a record from a
000050* file where the specified record ID code is entered
000060* by the user. 2 differing methods are used.
000070
000080 ENVIRONMENT DIVISION.
000090
000100 INPUT-OUTPUT SECTION.
000110 FILE-CONTROL.
000120 000130 SELECT IN-FILE-1 ASSIGN TO 'TESTDATA1.DAT'
000140 ORGANIZATION IS INDEXED
000150 ACCESS MODE IS DYNAMIC
000160 RECORD KEY IS RECORD-CODE-1.
000170 SELECT IN-FILE-2 ASSIGN TO 'TESTDATA2.TXT'
000180 ORGANIZATION IS LINE SEQUENTIAL.
000190 SELECT TEMP-FILE ASSIGN TO 'TEMP.TXT'
000200 ORGANIZATION IS LINE SEQUENTIAL.
000210 000220 DATA DIVISION.
000230 FILE SECTION.
000240 000250 FD IN-FILE-1.
000260 01 RECORD-1.
000270 03 RECORD-CODE-1 PIC X(6).
000280 03 RECORD-DETAILS-1 PIC X(43).
000290 000300 FD IN-FILE-2.
000310 01 RECORD-2.
000320 03 RECORD-CODE-2 PIC X(6).
000330 03 RECORD-DETAILS-2 PIC X(43).
000340 000350 FD TEMP-FILE.
000360 01 TEMP-RECORD.
000370 03 TEMP-CODE PIC X(6).
000380 03 TEMP-DETAILS PIC X(43).
000390 000400
000410 000420 WORKING-STORAGE SECTION.
000430 000440 01 END-OF-FILE-FLAG PIC X VALUE 'N'.
000450 88 EOF VALUE 'Y'.
000460 000470 01 REC-DELETE-FLAG PIC X VALUE 'N'.
000480 88 RECORD-DELETED VALUE 'Y'.
000490
000500 01 DEL-CODE PIC X(6) VALUE SPACES.
000510 000520
000530
000540 PROCEDURE DIVISION.
000550 000560 MAIN-PARAGRAPH.
000570 000580 PERFORM FIRST-METHOD
000590 MOVE 'Y' TO END-OF-FILE-FLAG
000600 PERFORM SECOND-METHOD
000610 STOP RUN.
000620 000630***********************************************************
000640 000650 FIRST-METHOD.
000660* Paragraph that uses the DELETE to remove a record
000670 000680 DISPLAY 'Enter 6 digit code of record to be deleted'
000690 ACCEPT RECORD-CODE-1
000700 OPEN I-O IN-FILE-1
000710 000720 000730 DELETE IN-FILE-1
000740 INVALID KEY DISPLAY 'RECORD NOT FOUND'
000750
000760 END-DELETE
000770
000780
000790 CLOSE IN-FILE-1.
000800 000810***********************************************************
000820 000830 SECOND-METHOD.
000840* Paragraph that writes to a temporary file without
000850* including the record to be deleted
000860 000870 DISPLAY 'Enter 6 digit code of record to be deleted'
000880 ACCEPT DEL-CODE
000890 OPEN INPUT IN-FILE-2
000900 OUTPUT TEMP-FILE
000910 000920 MOVE 'N' TO REC-DELETE-FLAG
000930 MOVE 'N' TO END-OF-FILE-FLAG
000940 000950*----first write all records (except the selected one) to
000960*----the temporary file
000970 PERFORM UNTIL EOF
000980 READ IN-FILE-2
000990 AT END SET EOF TO TRUE
001000 NOT AT END
001010 IF RECORD-CODE-2 = DEL-CODE THEN
001020 SET RECORD-DELETED TO TRUE
001030 ELSE
001040 WRITE TEMP-RECORD FROM RECORD-2
001050 END-IF
001060 END-READ
001070 END-PERFORM
001080 001090 001100 001110 IF NOT RECORD-DELETED THEN
001120 DISPLAY 'Record not found'
001130 END-IF
001140 001150 CLOSE IN-FILE-2 TEMP-FILE
001160 001170 MOVE 'N' TO END-OF-FILE-FLAG
001180 001190*----now read all records from temp-file to a new 'TESTDATA-2.TXT'
001200*----This is virtually the same as just renaming the temporary file
001210*----when you think about it, just done the COBOL way!
001220 OPEN INPUT TEMP-FILE
001230 OUTPUT IN-FILE-2
001240*---------the original 'TESTDATA-2.TXT' will be overwritten-----*
001250 001260 PERFORM UNTIL EOF
001270 READ TEMP-FILE
001280 AT END SET EOF TO TRUE
001290 NOT AT END
001300 WRITE RECORD-2 FROM TEMP-RECORD
001310 END-READ
001320 END-PERFORM
001330 001340 CLOSE TEMP-FILE IN-FILE-2.
001350 001360***********************************************************
001370***********************************************************

Common COBOL verbs / Statements - II

=============
# Arithmetic
=============

To perform arithmetic calculations there are two ways of going about doing this:

using the ADD, SUBTRACT, MULITPLY, DIVIDE verbs, or using the COMPUTE
verb as seen already. The formats for the first group are as follows:
[square brackets indicate optional words]


ADD {identifier-1 or literal}... TO {identifier-2 or literal}...
[GIVING {identifier-3}]
[NOT] [ON SIZE ERROR {statements}]
[END-ADD]

Examples:
ADD NUM-A TO NUM-B GIVING NUM-TOTAL-1
ADD NUM-A, 20 TO NUM-B GIVING NUM-TOTAL-2
ADD 3 TO NUM-TOTAL-3

When the word GIVING is not used (as in the third example) the
identifier that follows 'TO' is where the result of the addition. This
also applies to SUBTRACT and MULTIPLY. ON SIZE ERROR is a conditional,
whereby if the result of the calculation is larger than the PIC
description (i.e. the result is truncated either at the leading end or
the decimal places). On such an occasion a series of statements can be
executed. The use of ON SIZE ERROR means that a scope terminator is
required (END-ADD). The second example adds both NUM-A and 20 to
NUM-B.


SUBTRACT {identifier-1 or literal}... FROM {identifier-2 or literal}...
[GIVING {identifier-3}]
[NOT] [ON SIZE ERROR {statements}]
[END-SUBTRACT]

Examples:
SUBTRACT 200 FROM NUM-C GIVING NUM-D
ON SIZE ERROR DISPLAY 'NUM-D is out of range'
END-SUBTRACT
SUBTRACT NUM-F FROM 20 ** this won't work! **

The second example is illegal because, in the absence of a receiving
identifier after GIVING, the result of the subtraction has nowhere to
go (20 is a literal). The same would apply to ADD and MULTIPLY.


MULTIPLY {identifier-1 or literal}... BY {identifier-2 or literal}...
[GIVING {identifier-3}][ROUNDED]
[NOT] [ON SIZE ERROR {statements}]
[END-MULTIPLY]

Examples:
MULTIPLY NUM-G BY 20 GIVING NUM-F
MULTIPLY 20 BY NUM-G

DIVIDE {identifier-1 or literal} BY {identifier-2 or literal}...
GIVING {identifier-3} [ROUNDED] [REMAINDER {identifier-4}]
[NOT] [ON SIZE ERROR {statements}]
[END-DIVIDE]

Examples:
DIVIDE NUM-H BY 3 GIVING NUM-I REMAINDER NUM-REMAIN
DIVIDE NUM-Y BY 3 GIVING NUM-K ROUNDED

The DIVIDE statement differs from the previous 3 in that GIVING is
required. Also, the remainder of the division (e.g. 7 divided by 3
equals 3 remainder 1) can be stored in an identifier. The ROUNDED
option, which is also available for the MULTIPLY statement, will round
to the nearest significant decimal place, defined by the PIC clause.
E.g.:


000100 77 NUM-A PIC 99 VALUE 10.
000200 77 NUM-B PIC 9V99.
002000 DIVIDE NUM-A BY 3 GIVING NUM-B
002010 ON SIZE-ERROR DISPLAY 'RESULT IS TRUNCATED'
002020 END-DIVIDE
002030
002040 DIVIDE NUM-A BY 3 GIVING NUM-B ROUNDED
002050 ON SIZE-ERROR DISPLAY 'RESULT IS TRUNCATED'
002020 END-DIVIDE

The first DIVIDE statement will result in a size error (20 / 3 =
6.66666..) as NUM-B will contain 6.66 but will have truncated the
rest. This does not apply to the second DIVIDE statement since it has
been rounded to fit the pic description 9V99, and so in this case
NUM-B will contain 6.67.


DIVIDE {identifier-1 or literal} INTO {identifier-2 or literal}...
GIVING {identifier-3} [ROUNDED] [REMAINDER {identifier-4}]
[NOT] [ON SIZE ERROR {statements}]
[END-DIVIDE]

Examples:
DIVIDE 3 INTO NUM-Y GIVING NUM-K ROUNDED
This differs from the previous DIVIDE statement only in the order of
numerator and denominator (both mean NUM-Y / 3).


COMPUTE

As previously seen in earlier sections, COMPUTE can be used to do
arithmetic calculations. The format is:


COMPUTE {identifier-1} [ROUNDED] = arithmetic expression
[NOT] [ON SIZE ERROR {statements}] [END-COMPUTE]


with the operations:


+ add
- subtract
* multiply
/ divide
** to the power of

Note that brackets need to be used for complex calculations where
signs have presidence over each other, for example: 2 + 3 * 2 equals 8
(and not 10) since 3 * 2 is calculated before the addition
-----------------------------------------------------------------------------------------

==========
# Strings
==========

STRING {identifier-1 or literal-1} DELIMITED BY {identifier-2 or
literal-2 or SIZE}...
INTO {identifier-3}
ON OVERFLOW [statements]
&NOT ON OVERFLOW [statements]
END-STRING


STRING will move a series of strings into a destination string (from
left to right without space filling). If the destination string is not
large enough to hold all the source strings then this can be detected
and acted on by the ON OVERFLOW condition. The DELIMITED word
specifies the source string characters to be used:


01 W-DAY PIC XXX VALUE 'MON'.

01 W-MONTH PIC XXX VALUE '5 '.

01 W-YEAR PIC XXXX VALUE '2000;'.

: STRING W-DAY DELIMITED BY SIZE

'/' DELIMITED BY SIZE

W-MONTH DELIMITED BY SPACES

'/' DELIMITED BY SIZE

W-YEAR DELIMITED BY ';'

INTO DATE-STRING

END-STRING

The item DATE-STRING will contain "MON/5/2000".
===============
UNSTRING
===============

UNSTRING {identifier-1 or literal-1} DELIMITED BY {identifier-2 or
literal-2 or SIZE}...
INTO {identifier-3 COUNT IN identifier-4}...
TALLYING IN {identifier-5}
ON OVERFLOW [statements]
NOT ON OVERFLOW [statements]
END-UNSTRING

UNSTRING allows you to break up a string into small strings placed
into new items:

01 W-LONG-STRING PIC X(50) VALUE 'Name;Address;Post Code'.

UNSTRING W-LONG-STRING DELIMITED BY ';'

INTO W-NAME COUNT IN CHARS-NAME

W-ADDRESS COUNT IN CHARS-ADDR

W-POST-CODE COUNT IN CHARS-PCODE

TALLYING IN NUM-STRINGS-OUT

END-UNSTRING


Here then string 'Name' will be placed into W-NAME, containing 4
characters, thus CHARS-NAME will contain the value of 4. Likewise for
W-ADDRESS ('Address') CHARS-ADDR (7) etc... Notice how the ; character
has been lost. Any character, including spaces can be used as a
delimiter. TALLYING IN will count the number of items that were filled
by the UNSTRING operation, in this case NUM-STRINGS-OUT will contain
the value 3. Lastly, the ON OVERFLOW detects when each target of the
UNSTRING operation has been used but there remains unused characters
in the source string, e.g. if W-LONG-STRING contained
'Name;Address;Post Code;Country'.

=============
INSPECT
=============

INSPECT {identifier-1} REPLACING CHARACTERS BY {identifier-2 or literal-1}
{BEFORE or AFTER} [INITIAL {identifier-3 or literal-2}]
{ALL or LEADING or FIRST} {identifier-4 or literal-3}
BY {identifier-5 or literal-4} {BEFORE or AFTER} INITIAL
{identifier-6 or literal-5}


This form of INSPECT allows you to change characters within a string
using the various options above.

INSPECT {identifier-1} TALLYING {identifier-2}
{BEFORE or AFTER} [INITIAL {identifier-3 or literal-2}]
{ALL or LEADING or FIRST} {identifier-4 or literal-3}
BY {identifier-5 or literal-4} {BEFORE or AFTER} INITIAL
{identifier-6 or literal-5}


Here the source string is inspected and a tally of the number of
characters defined (using the subsequent options) is held in
{identifier-2}.

------------------------------------------------------------------------------------------------------
=========
# Write
=========


To output data to the printer or to a file, the verb WRITE is used. It
would be of the form:

WRITE {level 01 name of file/printer FD}

For example:

000100 ENVIRONMENT DIVISION.
000200 INPUT-OUTPUT SECTION.
000300 FILE-CONTROL.
000400 ASSIGN PRINT-FILE TO PRINTER.
000500 DATA DIVISION.
000600 FILE SECTION.
000700 FD PRINT-FILE.
000800 01 P-DATA PIC X(80).
: 000900 WORKING-STORAGE SECTION.
001000 01 DATA-NUMBER PIC 9(6) VALUE 123456.
001100 01 PRINT-NUMBER PIC X(6).
: 010900*in procedure division
011100 MOVE DATA-NUMBER TO PRINT-NUMBER
011200 MOVE PRINT-NUMBER TO P-DATA
011300 WRITE P-DATA

To simplify things the word FROM can be used to save always having to
first MOVE the data (PRINT-NUMBER) into the printing item (P-DATA
above). So, line 011200 and 011300 can simply be written as:

011100 WRITE P-DATA FROM PRINT-NUMBER


In addition to WRITE, the is also REWRITE and DELETE which are used to
update records within files that have been opened in I-O mode (see the
following section). When using DELETE you must first read the record
that is to be deleted. Also, when deleting a record you refer to the
FILE NAME rather than the record name:

000300 FD IN-FILE.
000400 01 CUST-RECORD.
000500 03 C-NAME PIC X(20).
000600 03 C-NUMBER PIC 9(6).
001000* in procedure division.
001100 READ IN-FILE.
001200 NOT AT END.
001300 IF C-NUMBER = 123456 THEN
001400 DELETE IN-FILE
001500 ELSE MOVE C-NUMBER TO W-DATA-STORE
001600 END-IF
001700 END-READ
--------------------------------------------------------------------------------------------------------
==================
# Scope Terminators
==================


In the section COBOL basics I mentioned the full stop (period). This
is what can be described as a scope terminator. Many COBOL verbs have
their own scope terminator, for example, END-IF, END-READ, END-PERFORM
etc... The purpose of a scope terminator is to define when a verb's
scope (i.e. associated logic) is finished.


For example:

READ IN-FILE
AT END MOVE 'Y' TO EOF FLAG
NOT AT END
IF REC-IN = 'Z' THEN
PERFORM PROCEDURE-X
END-IF
END-READ


In the above example END-READ defines the scope of the READ statement
since there is a condition involved (AT END of the file, or NOT AT END
of the file), while END-IF defines then end of the IF condition, i.e.
END-READ and END-IF define their scope. Any code that follows the read
statement will apply regardless of the READ condition (which is what
you would want in the above example). Without END-READ the subsequent
code would only be performed while NOT AT END is true: some nasty bugs
could ensue! Things become even more scary if you forget to use END-IF
or END-PERFORM (especially when looping). There's a good chance the
compiler might pick up the error.

However, a period is also a scope terminator. You might also code:


READ IN-FILE
AT END MOVE 'Y' TO EOF FLAG
NOT AT END
PERFORM UNTIL REC-IN = 'A'
IF REC-IN = 'Z' THEN
PERFORM PROCEDURE-X.
END-PERFORM

This would have the same effect as the first example (assuming the
compiler doesn't complain). Some people do use periods in place of
END-IF etc (note: I'm not sure you allowed to replace END-PERFORM
however). Problems may arise when you forget to use a scope terminator
somewhere and there's a period somewhere further down the code then
the compiler might just get confused.

It is important to realise that the period will terminate all ongoing
conditions. So in the above example, the period will act as both an
END-IF, END-PERFORM and END-READ.

Look at this paragraph:


000090*this works, using period scope terminators
000100 PARAGRAPH-ABC.
000200 MOVE 0 TO N
000300 PERFORM UNTIL N > 10
000400 COMPUTE N = N + 1
000500 DISPLAY N.
000600
000700 PERFORM PROCEDURE-Y N TIMES
000800 PERFORM UNTIL END-OF-FILE
000900 READ IN-FILE
001000 AT END MOVE 'Y' TO EOF-FLAG
001100 NOT AT END
001200 ADD VALUE-FROM-RECORD TO N GIVING X.
001300 001400 END-PERFORM
001500 DISPLAY X.


In the first example, the code will display numbers 1 to 10. It will
then perform PROCEDURE-Y 11 times. Finally, the numbers coming from
the IN-FILE (VALUE-FROM-RECORD) will be added to 11 giving X, which is
then displayed.

But what if we were to forget to put a period at the end of line 500?

000090*this has a syntax error
000100 PARAGRAPH-ABC.
000200 MOVE 0 TO N.
000300 PERFORM UNTIL N > 10
000400 COMPUTE N = N + 1
000500 DISPLAY N
000600 000700 PERFORM PROCEDURE-Y N TIMES.
000800 PERFORM UNTIL END-OF-FILE
000900 READ IN-FILE
001000 AT END MOVE 'Y' TO EOF-FLAG
001100 NOT AT END
001200 ADD VALUE-FROM-RECORD TO N GIVING X.
001300 001400 END-PERFORM
001500 DISPLAY X.


Now, the period on line 700 will terminate the scope of the PERFORM
statement on line 300. This means that PROCEDURE-Y gets performed
1+2+3+4+5+6+7+8+9+10+11 times (that's 66 times!). Oh dear.

In fact, when I tried to test these code fragments by compiling [on
the Fujitsu COBOL v3] it complained bitterly! The compiler was
particularly bothered by the lack of END-PERFORMS.

I was taught to only use 2 periods in any paragraph: the first after
the paragraph name, the second (and last) at the end of the paragraph.
So always use the verb's own scope terminator. More typing but less
headaches in my humble opinion. Here's what the above code would look
like when following this advice:


000090*using just 2 periods
000100 PARAGRAPH-ABC.
000200 MOVE 0 TO N
000300 PERFORM UNTIL N > 10
000400 COMPUTE N = N + 1
000500 DISPLAY N
000600 END-PERFORM
000700 PERFORM PROCEDURE-Y N TIMES
000800 PERFORM UNTIL END-OF-FILE
000900 READ IN-FILE
001000 AT END MOVE 'Y' TO EOF-FLAG
001100 NOT AT END
001200 ADD VALUE-FROM-RECORD TO N GIVING X
001300 END-READ
001400 END-PERFORM
001500 DISPLAY X.


Many of the commands described in this section have already been used
in earlier sections but here their description will be shown alongside
related commands, clauses and verbs. It should be noted that a command
probably is a verb, while a clause is a collection of COBOL words
without a verb.

Common COBOL verbs/ statements -- I

Many of the commands described in this section have already been used in earlier sections but here their description will be shown alongside related commands, clauses and verbs. It should be noted that a command probably is a verb, while a clause is a collection of COBOL words without a verb.

=======================
# ACCEPT and DISPLAY
=======================

To enter data via the console during a program run, use the ACCEPT verb, e.g:
ACCEPT W-DATA-IN

To display data on the console during a run use the DISPLAY verb, i.e:
DISPLAY W-DATA-OUT

To place text with the outputed data you would code:
DISPLAY 'Inputed data is ' W-DATA-OUT

=========
# Move
=========
The format is:

MOVE [literal-1 or identifier-1] TO [identifier-2] ...


The MOVE statement has already been extensively used in the examples in the Defining Data section. A couple of features have not been described yet: CORRESPONDING (abreviation CORR) and the qualification OF or IN. The elipsis (...) means more of the same, i.e. above [identifier-2] [identifier-3] [identifier-4]...and so on.

To move a group of items from one field description to another:


03 DATE-IN.
05 W-DAY PIC 99.
05 W-MONTH PIC 99.
05 W-YEAR PIC 99.

03 DATE-OUT.
05 W-DAY PIC 99.
05 PIC X VALUE '/'.
05 W-MONTH PIC 99.
05 PIC X VALUE '/'.
05 W-YEAR PIC 99.



If you were to code: MOVE DATE-IN TO DATE-OUT you would end up with the 6 characters of DATE-IN appearing in the first 6 positions of DATE-OUT, including over-written fillers. To get the contents of W-DAY of DATE-IN into W-DAY of DATE-OUT (and the same for the other two items) you could either move them individually, or you could simply code: MOVE CORRESPONDING DATE-IN TO DATE-OUT. To do this the items must have the same name spelling and must be of the same level (here they are both level 03). They don't have to be in the same level 01 group.

Of course, this does present the programmer with a potential problem, this being that if elsewhere in the program you were to code, say, ADD 12 to W-MONTH, the compiler would report a syntax error since it W-MONTH appears twice in the data division and doesn't know which one you mean. To remedy this, you have to qualify the item, i.e. state which group W-MONTH you mean, i.e. :

MOVE 12 TO W-MONTH IN DATE-OUT.

You could use the word OF instead of IN here to the same effect.


Reference modification
-----------------------------------

To access specific characters within a string you can use a reference modifier.

STRING-ITEM (startPosition:Length)

The start position is the nth character of the STRING-ITEM. For MicroFocus compilers at least, the length can be omitted if you want all characters to the end of the string.
e.g.

WORKING-STORAGE SECTION.

01 STRING-1 PIC X(10) VALUE 'ABCDEFGHIJ'.
01 STRING-2 PIC X(10) VALUE SPACES.
01 STRING-3 PIC X(10) VALUE SPACES.
01 STRING-4 PIC X(10) VALUE SPACES.
01 STRING-5 PIC X(10) VALUE SPACES.
01 STRING-6 PIC X(10) VALUE SPACES.

: : in procedure division:

MOVE STRING-1(2:6) TO STRING-2
MOVE STRING-1(1:9) TO STRING-3
MOVE STRING-1(6) TO STRING-4
MOVE STRING-1(5:1) TO STRING-5
MOVE STRING-1(3:3) TO STRING-6

Then:
STRING-2 will contain characters 2 to 6, i.e. : "BCDEFG "
STRING-3 will contain characters 1 to 9, i.e. : "ABCDEFGHI "
STRING-4 will contain characters 6 to the end of STRING-1, i.e. : "FGHIJ "
STRING-5 will contain character 5 only, i.e. : "E "
STRING-6 will contain characters 3 to 5, i.e. : "CDE "

===============
# Perform
===============

The PERFORM verb is one of the most important in COBOL (alongside MOVE).

PERFORM has already been encountered in the Four Divisions section, where it was used to call paragraphs from within a control paragraph. Of course, it doesn't have to be a control (or main) paragraph.


000290 PROCEDURE DIVISION.
000300 XYZ-PARAGRAPH.
000310 PERFORM FIRST-PROCESS
000320 PERFORM SECOND-PARAGRAPH
000330 STOP RUN.

002000 FIRST-PROCESS.
002010 [statements]
[last statement].


In the above code, the paragraph FIRST-PROCESS is executed. When the full stop at the end of this paragraph is encountered the logic will return to XYZ-PARAGRAPH at the next line, i.e. line 320. This is called an Out-of-Line PERFORM.

The PERFORM verb can form the bases of a repetitive loop (or sub-routine) until a certin condition has been met.

For Example:

000290 PROCEDURE DIVISION.
000300 XYZ-PARAGRAPH.
000310 PERFORM COUNT-PROCESS UNTIL W-COUNTER > 10
000320 STOP RUN.
001000
002000 COUNT-PROCESS.
002010 COMPUTE W-COUNTER = W-COUNTER + 1
002020 DISPLAY 'Number of loops is ' W-COUNTER.


In the above code, COUNT-PROCESS is executed until the value of W-COUNT has reached 11.

The format for an Out-of-Line PERFORM is:


PERFORM [paragraph-name] UNTIL [condition]

An In-Line PERFORM, rather than execute a paragraph (aka procedure), allows for the repeated execution of a series of commands. The format for an In-Line PERFORM is:


PERFORM UNTIL
{action}...
END-PERFORM


Example:

000290 PROCEDURE DIVISION.
000300 XYZ-PARAGRAPH.
000305 MOVE ZERO TO W-COUNTER
000310 PERFORM UNTIL W-COUNTER > 10
000320 COMPUTE W-COUNTER = W-COUNTER + 1
000330 DISPLAY 'This is loop number: ' W-COUNTER
000340 END-PERFORM
000350 DISPLAY 'Counter is now equal to: ' W-COUNTER
000360 STOP RUN.


END-PERFORM defines the scope of the PERFORM loop, and is a Scope terminator. Other such scope terminators exist for other commands that will be described further on. The code above will loop 11 times (showning numbers 1 to 11). This is because when W-COUNTER is equal to 10, the condition (W-COUNTER) is still false. 1 is then added, and W-COUNTER is displayed as 11, and now when W-COUNTER is tested the condition will be true and the logic will then jump to the statement that immediately follows END-PERFORM.

This type of PEFORM tests the condition before the following statements are allowed to proceed. Using WITH TEST can be used to define when the test is done:


000290 PROCEDURE DIVISION.
000300 XYZ-PARAGRAPH.
000305 MOVE ZERO TO W-COUNTER
000310 PERFORM WITH TEST AFTER UNTIL W-COUNTER > 10
000320 COMPUTE W-COUNTER = W-COUNTER + 1
000330 DISPLAY 'This is loop number: ' W-COUNTER
000340 END-PERFORM
000350 DISPLAY 'Counter is now equal to: ' W-COUNTER
000360 STOP RUN.


Now the condition is tested after the commands within the PERFORM..END-PERFORM loop has be executed once. (WITH TEST BEFORE has same effect as initial example).

If you wanted to loop a desired number of times you could use TIMES


PERFORM 5 TIMES
COMPUTE W-NUMBER = XYZ * 3
END-PERFORM


The format is:

PERFORM {identifier or literal} TIMES
{action}...
END-PERFORM


To have a loop using an increment (such as a 'for..do' loop in Pascal or FOR in BASIC), the PERFORM VARYING statement is used.

The Format is:


PERFORM {paragraph-name if out-of-line} VARYING {identifier-1}
FROM {identifier-2 or literal} BY {identifier-3 or literal}
UNTIL {condition}
END-PERFORM

Look at the example given below:


000290 PROCEDURE DIVISION.
000300 XYZ-PARAGRAPH.
000310 PERFORM VARYING W-COUNTER FROM 1 BY 2
000320 UNTIL W-COUNTER > 10
000330 DISPLAY 'This is loop number: ' W-COUNTER
000340 END-PERFORM
000350 DISPLAY 'Counter is now equal to: ' W-COUNTER
000360 STOP RUN.


This code will display:

This is loop number: 1
This is loop number: 3
This is loop number: 5
This is loop number: 7
This is loop number: 9
Counter is now equal to: 11

This because with each loop, W-COUNTER has increased from 1 by increments of 2. When W-COUNT was equal to 11 then the condition W-COUNTER > 10 is now true and so the loop is exited. If you wanted to count downwards you could code:

PERFORM VARYING W-COUNTER FROM 20 BY -1
UNTIL W-COUNTER < ZERO.

The last thing to mention is PERFORM..THRU. If a program had a series of paragraphs, just for the sake of argument, called PROCESS-1, PROCESS-2, PROCESS-3 and PROCESS-4, then if you wished to execute these paragraphs in the order that they are written you could code: PERFORM PROCESS-1 THRU PROCESS-4 with any out-of-line loops and conditions you might want. Seemingly, this is not good programming practise so is generally avoided.


===============
# If..Then..Else
===============

Another fundamental part of programming logic is the ability to offer a choice of what to do that depends on the conditions asked of.

The format is:

IF {identifier-1} {condition} {identifier-2 or literal} ...
THEN {statements}
[ELSE {statements}]
END-IF


example:
IF X = Y THEN
MOVE 1 TO Y-COUNTER
ELSE
MOVE 1 TO X-COUNTER
END-IF


ELSE is used if an alternative statement is to be executed if the first condition is false. If there was only to be action if X = Y then the ELSE would be ommitted.

The END-IF terminates the IF statement. All that lies between IF and END-IF will depend on the conditions being tested.

Multiple conditions can be tested, i.e. IF (X = Y) AND (Y < 100) THEN ..


-----------------------------------------------------------------------------------------
===========
# Conditions
===========

There are four types of conditions that could be tested either in a PERFORM, IF..THEN, or EVALUATE (see next section), these being:


1. Class conditions
2. Relational conditions
3. Sign conditions
4. Condition-name conditions

Class conditions test where an item is NUMERIC, ALPHABETIC, ALPHABETIC-LOWER, or ALPHABETIC-HIGHER (as in lower or upper case).

Relational conditions allow comparisons, i.e: GREATER THAN, LESS THAN, EQUAL TO or their sign equivalent: " > ", " < ", " = ", respectively.

Sign conditions test whether an item IS POSITIVE, IS NEGATIVE, or IS NOT ZERO. (note 'IS' is optional)

Condition-name conditions are as described in the section, where a named condition is defined in the data division using a level 88 description.

Conditions can be combined using AND, OR, AND NOT, OR NOT, and brackets. The most common combinations would probably be GREATER THAN OR EQUAL TO and LESS THAN OR EQUAL TO, which can simply be written >= and <= respectively. Also, NOT EQUAL TO would be <> although I find the Fujitsu compiler rejects '<>' so I just use 'NOT = ' instead.

More complex combination's can be achieved with the use of brackets. eg.


IF ( X > Y ) AND ( ( Y + 10 < Z ) OR ( X - 10 > Z ) ) THEN ...

Remember:
[true] AND [false] = FALSE
[true] AND [true] = TRUE
[true] OR [false] = TRUE
[true] OR [true] = TRUE
NOT [true] = FALSE
NOT [false] = TRUE


Alpha-numeric comparisons can also be made that relate to their ASCII character value, so 'A' < 'Z' etc...
------------------------------------------------------------------------------------------------------------------------------
=========
# Evaluate
=========

If there are a large number of conditional alternatives, then using a large number of nested IF statements can be messy:


IF A = 1 THEN PERFORM PARA-1
ELSE
IF A = 2 THEN PERFORM PARA-2
ELSE
IF A = 3 THEN PERFORM PARA-3
ELSE
IF A = 4 THEN PERFORM PARA-4
END-IF
END-IF
END-IF
END-IF



The above example only tested four possible values for 'A'. Suppose there were ten or twenty? This is where the EVALUATE statement is of great use. The format is:


TABLE Handling in cobol

Also known as an array in other languages like 'C', a table is a group
of data associated with a single item name.

To identify pieces data (elements) within that table the item is given
a subscript number which follows the name.

W-NAME (elements) Subscript
-----------------------------------------------------
Smith 1
Jones 2
MacDoon 3
Walker 4
O'Leary 5
----------------------------------------------------
So, DISPLAY W-NAME (2) will give "Jones".

A 2-dimensional table uses two subscripts:
So element (2, 4) will contain "1.1".

To define the W-NAME (1-dimensional) table in the data division:

01 W-NAME PIC X(10) OCCURS 5 TIMES.


The word TIMES is optional. Also, the PIC clause can also be written
after the OCCURS ... clause.

To define the SALES-TABLE (2-dimensional) table, just add another
level to the group. Hence:

Tables

01 SALES-TABLE.
03 BRANCH-NO OCCURS 4.
05 MONTHLY-SALES OCCURS 4 PIC 9V9.

Notice how only the top level 05 contains the PIC clause. Level 01
describes a whole table made up of 4 items (level 03) containing 4
elements (level 05).

Table can be multi-dimensional, but always the last level will be the
identifier name that is associated with the subscripts and will have
the PIC clause.

For the use of tables, see the League Table Program in the Sample Code section.

Finally, don't try to refer to a table element that is of a greater
value than that defined in the data division, i.e. W-NAME (6) will
cause a runtime error and terminate the program. It should be obvious
that a subscript should be a numeric literal or an identifier that is
numeric.

The use of identifiers as subscripts is where tables are of most use,
i.e. MONTHLY-SALES (INPUT-BRANCH, INPUT-MONTH).

Accept and Display DATA in COBOL

Much of how that data will look, such as in a report, is defined in
the data division.

The following code is taken from a full program given in the Sample
code section should illustrate how a printed report is defined in the
data division. If writing to a file it would be virtually identical
(see Sample code section for an example of this).

If you wished to print a report in the form of a table then you would
first have to assign an identifier name to the printer in the
environment division using the select clause.
Printing and Writing Data

000110 ENVIRONMENT DIVISION.
000120 INPUT-OUTPUT SECTION.
000130 FILE-CONTROL.
000140
000210 SELECT PRINT-FILE ASSIGN TO PRINTER.
000220
000230
000240 DATA DIVISION.
000250 FILE SECTION.
000580 FD PRINT-FILE.
000590 01 REPORT-OUT PIC X(80).
000630 WORKING-STORAGE SECTION.
000640
001040 01 PRINT-HEADERS.
001050 03 P-TITLE.
001060 05 P-TITLE-TXT PIC X(49) VALUE
001070 ' Batch Control Program - Error Report. Page:'.
001080 05 P-PAGE-NO PIC Z9 VALUE ZERO.
001090 03 COL-HEAD-1 PIC X(31)
001100 VALUE ' PART CUST/ DATE QUANT'.
001110 03 COL-HEAD-2 PIC X(24)
001120 VALUE ' NO SUP NO SUP/REC'.
001130
001140 01 PRINT-LINE.
001150 03 P-PART-NO PIC X(8).
001160 03 PIC X VALUE SPACE.
001170 03 P-CUS-SUP-NO PIC X(6).
001180 03 PIC XX VALUE SPACES.
001190 03 P-DATE-S-D. 001200 05 P-DATE-1 PIC XX.
001210 05 PIC X VALUE '/'.
001220 05 P-DATE-2 PIC XX.
001230 05 PIC X VALUE '/'.
001240 05 P-DATE-3 PIC XX.
001250 03 PIC X VALUE SPACE.
001260 03 P-QUANT PIC Z(4)9.
001270
001280 01 P-FOOTER.
001290 03 TOT-REC-TXT PIC X(21)
001300 VALUE 'Total record number: '.
001310 03 P-REC-COUNT PIC ZZ9 VALUE ZERO.
001320
001330 01 P-BATCH-REC.
001340 03 BAT-TITLE PIC X(38)
001350 VALUE ' HASH TOTALS IN BATCH CONTROL RECORD'.
001360 03 BATCH-SOURCE PIC X(29) VALUE SPACES
001370 03 P-BAT-CUS-SUPP.
001380 05 BAT-CUS-SUP PIC X(25)
001390 VALUE ' CUSTOMER/SUPPLIER NOS: '.
001400 05 BAT-C-S-N-TOT PIC Z(7)9.
001410 03 P-BAT-DATE.
001420 05 BAT-DATE PIC X(9)
001430 VALUE ' DATES: '.
001440 05 BAT-D-S-D-TOT PIC Z(7)9.
001450 03 P-BAT-QUANT.
001460 05 BAT-QUANT PIC X(14)
001470 VALUE ' QUANTITIES: '.
001480 05 BAT-Q-TOT PIC Z(7)9.
001490 03 P-BAT-PART.
001500 05 BAT-PART PIC X(12)
001510 VALUE ' PART NOS: '.
001520 05 BAT-P-N-TOT PIC Z(7)9.

DIVISIONS in COBOL

The following are the Four Divisions of COBOL :

COBOL program code is divided into four basic division:
IDENTIFICATION, ENVIRONMENT, DATA, and PROCEDURE divisions. The
identification division is required, but in theory the others are not
absolute (although you won't have much of a program without any
procedures or data!).

=======================
The IDENTIFICATION DIVISION
=======================

The identification division tells the computer the name of the program
and supplies other documentation concerning the program's author, when
it was written, when it was compiled, who it is intended for...etc. In
fact, only the program name is required by the compiler.

Syntax:-

000100 IDENTIFICATION DIVISION.
000110 PROGRAM-ID. EXAMPLE-1-PROG.
000120 AUTHOR. ZINGMATTER.
000130 INSTALLATION. XYZ GROUP.
000140 DATE-WRITTEN. 17/5/00.
000150 DATE-COMPILED.
000160 SECURITY. LOCAL GROUP.

Note:

* The use of full stops is important. Throughout these pages, note
where they are positioned

* The first words (PROGRAM-ID, AUTHOR etc..) are written in area A,
the details are in
area B

* The DATE-COMPILED detail is written automatically by the compiler


=======================
The Environment Division
=======================
Syntax :-
000260 ENVIRONMENT DIVISION.
000270 CONFIGURATION SECTION.
000280 SOURCE-COMPUTER. IBM PC.
000290 OBJECT-COMPUTER. IBM PC.
000300 INPUT-OUTPUT SECTION.

000310 FILE-CONTROL.
000320 SELECT INPUT-FILE ASSIGN TO 'input.dat'
000330 ORGANIZATION IS LINE SEQUENTIAL.
000340 SELECT PRINT-FILE ASSIGN TO PRINTER.

Notes :-
* You probably wouldn't need to bother with the configuration section.
* The DIVISION and SECTION words are written into area A but the SELECT
clause should be in area B.
* The full stop doesn't appear in the SELECT clause until after the
ORGANIZATION
has been specified.
* INPUT-FILE and PRINT-FILE are user-defined names that are used in
the program
to refer to 'input.dat' and the printer, respectively. If the
input.dat file was on a different disk drive, within a directory
structure, then you could write:
...ASSIGN TO 'D:datafiles/data/input.dat'.
* Line 000330 describes the structure or form of the data written in
'input.dat' file. In this case, each record is on a new line in the
file (see
* File Handling section for details). The printer also is assigned
but the organization doesn't have to be secified.
* For the SELECT clause, if no organization is defined the computer
defaults to SEQUENTIAL organization (i.e. each record appears in a
long string with no line breaks.


=======================
The Data Division
=======================

The data division is where memory space in the computer is allocated
to data and identifiers that are to be used by the program.

Two important sections of this division are the FILE SECTION and the
WORKING-STORAGE SECTION. The file section is used to define the
structure, size and type of the data that will be read from or written
to a file.

Suppose the 'input.dat' file (described above) contains a series of
records about a companies customers, giving details of name, address,
and customer number. If you were to open 'input.dat' with a text
editor you would see each record on a new line like this:

Joe Bloggs 20Shelly Road Bigtown 023320
John Dow 15Keats Avenue Nowheresville042101
Jock MacDoon05Elliot Drive Midwich 100230

etc...


The different pieces of data need to be defined so that the program
can read a record at a time, placing each piece of information into
the right area of memory (which will be labelled by an identifier).

The file section for this may look like this:

000400 DATA DIVISION.
000410 FILE SECTION.
000420
000430 FD INPUT-FILE.
000440 01 CUSTOMER-DATA.
000450 03 NAME PIC X(12).
000460 03 ADDRESS.
000470 05 HOUSE-NUMBER PIC 99.
000480 05 STREET PIC X(19).
000490 05 CITY PIC X(13).
000500 03 CUST-NUMBER PIC 9(6).


Notes:

* 'FD' stands for File Descriptor, and names the file, INPUT-FILE
(assigned in the environment division), and describes the exact
structure of the data in each record. All records in this file MUST be
of exactly the same structure.

* '01 CUSTOMER-DATA' is the group name and refers to all of the
single record that is read into the computer memory from the file. The
higher numbers (levels), 03.. and 05.. will contain the indivual
fields of the record.

* Both FD and 01 are written in area A while higher levels are in area B.
* Level 01 is sub-grouped into level 03 fields. Notice that one of
the level 03 sub-groups is itself sub-grouped into level 05. The
sub-grouping could continue upwards as required to 07, 09 etc.. These
numbers (except level 01) could as easily be 02, 03, 04 ...or any
increasing number scale. There are some numbers (i.e. 66, 77 and 88)
which actually have other uses but these will be discussed in the
Defining Data section.

* The PIC (short for PICTURE) clause indicates the size and type of
data that that field contains. For example, in line 000450, the data
name (identifier) NAME has been defined as holding 12 characters of
alphnumeric data. It could have been written as PIC XXXXXXXXXXXX be
that's a pain. 'X' means alphnumeric and can contain any ASCII
character. However, even if it contained '2' you could not do any
calculations on this as the information is stored as the ASCII code
for the character '2', rather than the actual number 2. Line 000470
defines HOUSE-NUMBER as PIC 9(2), which can hold a 2-digit number.

You can do calculations with this since '9' is used to denote a numeric field.


* Notice how the group names (CUSTOMER-DATA and ADDRESS) do not have
PIC descriptions. This is because the higher level field descriptions
when added together will be the size of the group name, i.e.
CUSTOMER-NUMBER will hold 46 characters which turns out to be the size
of each record (spaces are included). You can refer to these group
names but when doing so all data will be treated as alphanumeric and
cannot be used for calculations, even if all of the higher group items
are numeric.


The WORKING-STORAGE SECTION of the data division is for defining data
that is to be stored in temporary memory, i.e. during program
run-time. Effectively, this is where, for example, an identifier is
defined that will hold the result of a calculation.

000500 DATA DIVISION.
000510 WORKING-STORAGE SECTION.
000520
000530 01 RECORD-COUNTER PIC 9(5).

Also see the 'Hello World program. In that case the string to be
displayed on the screen is actually defined in working-storage using
the VALUE clause (01 TEXT-OUT PIC X(12) VALUE 'Hello World!'). The
same can be done for numeric data e.g.:


000800 01 TOTALS-IN.
000810 03 1ST-NO PIC 99 VALUE ZERO.
000820 03 2ND-NO PIC 999 VALUE 100.


The equivalent to filling an item such as 1ST-NO (above) with zeroes,
is filling an alphanumeric (PIC X) item with spaces e.g. 01 MESSAGE
PIC X(12) VALUE SPACES.


=======================
The Procedure Division
=======================
COBOL is a modular language, in that a program is usually broken up
into units described as paragraphs.


000900 PROCEDURE DIVISION.
000910 CONTROL-PARAGRAPH.
000920 PERFORM READ-DATA-FILE
000930 PERFORM CALULATE-PRICES
000940 PERFORM PRINT-PRICE-REPORT
000950 STOP RUN.

The PERFORM statement is used to 'call' other paragraphs to do each
task. These paragraphs would appear in the same coding and are part of
the same program. In the above example, the program would consist of
four paragraphs: the CONTROL-PARAGRAPH and the three called from
within it. All of the paragraph names are user-defined. Even if a
program only has one paragraph, it must still have a name. The 'Hello
World' program has a paragraph name MAIN-PARAGRAPH. Regarding
punctuation, as a rule there should only be two full stops in any
paragraph; one after the paragraph name and the other at the end of
the paragraph.

Sub-programs
==========
A program may also refer to a different program, called a sub-program.
A sub-program is an entirely different program from the calling
program, with its own divisions etc... with the exception that it does
not end with STOP RUN (which would return you to the operating
system), but with EXIT PROGRAM. The sub-program is a module, rather
than a subroutine which is what a paragraph could be described as. The
verb CALL is used to activate the sub-program:


000800 DATA DIVISION.
000810 WORKING-STORAGE SECTION.
000820 01 W-DATE-IN PIC 9(6).
000850 LINKAGE SECTION.
000860 01 L-DATE-IN.
000870 03 DAY PIC 99.
000880 03 MONTH PIC 99.
000890 03 YEAR PIC 99.
000900 PROCEDURE DIVISION.
000910 CONTROL-PARAGRAPH.
000920 PERFORM READ-FILE
000930 CALL "VALIDATE-DATE" USING L-DATE-IN
001950 STOP RUN.
003000 IDENTIFICATION DIVISION.
003010 PROGRAM-ID. VALIDATE-DATE.
003020 ...........
............etc.....
003500 PRODECURE DIVISION USING L-DATE-IN.
004000 EXIT PROGRAM.


In the above code, a sub-program is called, named VALIDATE-DATE

In order to use data from the calling program in the sub-program the
calling program uses a section in the data division called the LINKAGE
SECTION. The item W-DATE-IN in the calling program occupies the same
memory address as the sub-program's item L-DATE-IN, so the number
placed in W-DATE-IN item using the VALUE clause is also in L-DATE-IN.
Note: you cannot use VALUE in the linkage section.

The procedure division of the sub-program requiring the use of linkage
section defined data must say so by: PROCEDURE DIVISION USING
...[linkage section items to be used] also refered to by the CALL ...
USING. See lines 000930 and 3500 above.

In the above example, what is being called ("VALIDATE-DATE") is a
literal. This means that you could use an identifier instead, allowing
you a choice between sub-programs depending on what the literal had
been previously defined as. For example, if a record was of type "A"
then you may want to process that record using sub-program
PROCESS-A-REC, but if a type "B" record the use PROCESS-B-REC.
The logic might be as follows:

0003000 IF RECORD-TYPE = "A" THEN
0003010 MOVE "PROCESS-A-REC" TO SUB-PROG
0003020 ELSE MOVE "PROCESS-B-REC" TO SUB-PROG
0003030 CALL SUB-PROG USING L-REC-DATA


Although I haven't described the various commands of the procedure
division the above code is fairly clear...if a marker called
RECORD-TYPE has been set as "A" then place (i.e. MOVE) the string
"PROCESS-A-REC" into the area of memory labelled as SUB-PROG (so now
SUB-PROG contains this string). Otherwise (i.e. ELSE) it is assumed
that the only other type there is can be "B" type and so
"PROCESS-B-REC" is MOVEd into SUB-PROG. Depending on what the item
SUB-PROG contains the desired sub-program will be called.

BASICS of COBOL

The below given three important categories required :-
BASICS :-

1) Coding Areas
2) Syntax
3) The Hello World Program

-----------------
Coding Areas
-----------------

If you look at the COBOL coding in later sections (e.g. League Table
program in the Sample code section) the specific positions of coding
elements are important for the compiler to understand. Essentially,
the first 6 spaces are ignored by the compiler and are usually used by
the programmer for line numbers. These numbers arenot the same as
those in BASIC where the line number is used as part of the logic
(e.g. GOTO 280, sending the logic to line 280).

The seventh position is called the continuation area. Only certain
characters ever appear here, these being:
* (asterisk), / (solidus or forward slash), or - (hyphen).
The asterisk is used to precede a comment, i.e. all that follows is
ignored by the compiler. The solidus is used to indicate a page break
when printing coding from the compiler, but it too can be used as
comment since the rest of the line is ignored by the compiler. The
hyphen is used as a continuation marker, i.e. when a quoted literal
needs to be extended over to the next line. It is not for continuing a
statement onto the next line (this is unnecessary*) and also cannot be
used to continue a COBOL word. (*You can write any COBOL statement
over as many lines as you like, so long as you stay in the correct
coding region and don't split strings.)

Sample :-
----------
000200*Here is a comment.
000210/A new line for printing and a comment.
000220
:
000340 DISPLAY 'This might be a very long string that
000350- 'needs to be continued onto the next line'


Positions 8 to 11 and 12 to 72 are called area A and area B,
respectively. These are used in specific instances that will be
detailed in later sections.


Summary
Positions Description
------------------------------------

1 to 6 ----> line code

7 -----> continuation area

8 to 11 -----> area A

12 to 72 ------> area B
-------------------------------------------


---------------
2) Syntax
--------------

Identifier names
================
User-defined names must conform to the following rules:

* Must only consist of alphabetic and numeric characters and/or hyphens
* The name must contain at least one alphabetic character
* Must be no more than 30 characters
* When using hyphens, they must not appear at the beginning or end
of the name

Some examples of legal names:

A123
RecordCount-1
WAGE-IN
Tot-2-out

Like all COBOL code, the compiler will not distinguish between upper
and lower case letters (except within quotes).

Lastly, COBOL has a large list of reserved words that cannot be used
as identifier names. A list of COBOL reserved words is given
elsewhere.

Punctuation
=============
The full stop (period) is the most important punctuation mark used,
and its use will be detailed later (see Scope terminators). Generally,
every line of the IDENTIFICATION, ENVIRONMENT, and DATA DIVISION end
in a period.

Quotation marks, either single or double, are used to surround quoted
literals (and when calling a sub-program). However, donât mix them
when surrounding the literal, e.g.

" This is bad â

" but this is ok "

Commas and semi-colons are also used to separate lists of identifiers,
e.g.
MOVE 2 TO DATA-ITEM-1, DATA-ITEM-2, DATA-ITEM-3
A space must follow the comma/semi-colon. They are optional however,
and a space would suffice, but it does add to clarity.


Spelling
=========
Since COBOL was developed in the USA, the spelling of words is
American, e.g. INITIALIZE or ORGANIZATION (using Z rather than S).
Brits be warned!

In many cases, abbreviations and alternative spellings are available
(see reserved word list), e.g. ZERO ZEROS ZEROES all mean the same
thing. Likewise, LINE and LINES, PICTURE and PIC, THROUGH and THRU.

----------------------
Sample Program
----------------------

As is traditional for all introductory lessons for a programming
language, here's a 'Hello World' program:


================== The 'Hello World' Program ==============================


000010 IDENTIFICATION DIVISION.
000020 PROGRAM-ID. HELLO-WORLD-PROG.
000030 AUTHOR. TIMOTHY R P BROWN.
000040*The standard Hello world program
000050 000060 ENVIRONMENT DIVISION.
000070 000080 DATA DIVISION
000090 WORKING-STORAGE SECTION.
000100 01 TEXT-OUT PIC X(12) VALUE 'Hello World!'.
000110 000120 PROCEDURE DIVISION.
000130 MAIN-PARAGRAPH.
000140 DISPLAY TEXT-OUT
000150 STOP RUN.

INTRODUCTION to COBOL

COBOL is a third-generation programming language, and one of the
oldest programming languages still in active use. Its name is an
acronym, for Common Business Oriented Language, defining its primary
domain in business, finance, and administrative systems for companies
and governments.

The COBOL 2002 standard includes support for object-oriented
programming and other modern language features.

COBOL programs are in use globally in governmental and military
agencies, in commercial enterprises, and on operating systems such as
IBM's z/OS, Microsoft's Windows, and the Unix/Linux families. In the
late 1990s, the Gartner Group, a data-processing industry research
organization, estimated that of the 300 billion lines of computer code
that existed, eighty percent — or 240 billion lines — were COBOL. They
also reported that more than half of all new mission-critical
applications were still being created using COBOL — an estimated
5,000,000,000 net new lines of COBOL code annually.

Near the end of the twentieth century the year 2000 problem was the
focus of significant COBOL programming effort, sometimes by the same
programmers who had designed the systems decades before. The
particular level of effort required for COBOL code has been attributed
both to the large amount of business-oriented COBOL, as COBOL is by
design a business language and business applications use dates
heavily, and to constructs of the COBOL language such as the PICTURE
clause, which can be used to define fixed-length numeric fields,
including two-digit fields for years.

COBOL programmers are still in the game

COBOL programmers back in the game
compiled from the post by ITworld


You're wrong if you think COBOL programmers are doomed to go the way of the Edsel. Despite predictions to the contrary, the world kept revolving around its axis after Y2K. Yet, the job market for COBOL programmers suddenly plunged -- and so did their salaries. However, this decline has since been stemmed thanks to the Internet's transition into a sprawling shopping mall selling everything from toothbrushes to tractors.

In the late 1990s, organizations fired up Y2K remediation projects and sought COBOL programmers to immunize legacy (database management systems running on mainframes or minicomputers) business applications against Y2K-related problems. Today, companies are finding that they need help integrating these legacy systems with new applications.

A couple of years ago Bill Lockhart, 63, a veteran COBOL programmer from Los Altos, Calif., was hard pressed to find a company that would take advantage of his more than 30 years of experience. His experience as a COBOL programmer dates to 1966 when he worked as a systems programmer. More recently, as a database specialist, he worked on several assignments for IBM writing in COBOL, PL/I, REXX, and assembly language.

"The tables have turned," chuckles Lockhart. "IT industries need my COBOL skills to get going on the Web."

Most of the world's business data, approximately 75 to 85 percent, is written in COBOL," adds Bill Payson, president and CEO of Senior Techs, an Internet-based job bank for experienced IT professionals in Campbell, Calif. "That translates to some hundreds of billions of lines of code."

COBOL is used in some manner by almost all Fortune 500 companies. Many of these companies have a large pool of COBOL-based applications that are primary business systems. E-business requires these systems to be integrated and connected to the outside world.

"With the future of all commerce linked to the Internet, companies with massive databases know that success depends on the ability to move data in and out of the Internet," Payson explains.

Paul Halpern, director of traditional development solutions at Merant, a Web-enabling training company in Mountain View, Calif., maintains that, "If all the COBOL programs stopped working, the US economy would collapse." And he points out: "Nine out of ten of the top Internet brokers use COBOL with CICS [Customer Information Control Systems]. Chances are that when you use an ATM card you are starting a COBOL/CICS process. An IBM report published last year indicates 30 billion COBOL/CICS transactions are executed worldwide each day, more than the total number of Web pages hit each day."

COBOL skills future in DEMAND

COBOL skills needed in the future

An article -- By Matt Stansberry, News Editor


To paraphrase German philosopher Friedrich Nietzsche, COBOL is dead. Or at least that's what some people in the IT world believe. It's a legacy language with relatively little new development taking place.

But the growth of the mainframe of late, combined with the staggering amount of COBOL running currently, has some experts are questioning whether the 800-pound gorilla is really dead. So Rockville, Md.-based Micro Focus International Ltd. decided to poke it with a stick to find out.

According to preliminary results of Micro Focus' survey of 750 mainframers in the U.S. and Canada, 41% name COBOL as a principal programming language by an approximate 25% margin over Java, the next most popular language. Preliminary results also find 52% of mainframe applications are still written in COBOL. ((Content component not found.))

The survey also found the median age of the COBOL programmer is 45-49, leading to the belief that there will be a growing knowledge shortage of COBOL programmers in the next decade.

Which raises the question: If your son or daughter were enrolled in a computer science program, would you encourage him or her to take classes in COBOL?

As it happens, Mark Lillycrop, CEO of U.K.-based Arcati Research and Publishing, has a nephew that is a first-year computer science student, and he has been encouraging him to pursue mainframe skills.

"COBOL is like an invisible giant. There's reported to be 180 billion-200 billion lines of code out there, processing 75% of commercial business. Few companies are keen to throw away the hundreds or thousands of man-years that have been invested in mature, high-performance COBOL code. Instead, they are integrating and building bridges between COBOL, .NET and J2EE [Java 2 Platform, Enterprise Edition], using service-oriented architectures to preserve the strengths of the legacy code while benefiting from Web-oriented development tools," Lillycrop said.

Ron Kizior, assistant professor Loyola University Chicago School of Business, ISOM area, worked on the Micro Focus survey. According to Kizior, the aspect that surprised him the most was the small number of mainframe shops that had gone to the Web. He'd expected up to 40%, but the numbers showed only 10%.

Despite that small number, Lillycrop and Kizior said the ability to integrate COBOL with Web-oriented development tools would be the skill to have in the future.

"It's not enough to know COBOL; the real winners are those who understand how to integrate with newer technologies. Some of the more enlightened universities are trying to get to grips with this emerging requirement, and are bringing the necessary mainframe components back onto the syllabus," Lillycrop said.



Loyola University Chicago is offering workshops on COBOL integration with .NET this summer, according to Kizior. He said it's harder to convince university administrators to consider COBOL than it is to persuade students.

"COBOL gives you a better understanding of what programming is. It's like taking the classics. It gives you a well-rounded background," Kizior said.

COBOL will be at the center of the enterprise for many years to come, with a huge ongoing support requirement. According to Lillycrop, when the current population of 50-something COBOL specialists finally retire, people with the right combination of skills will be able to name their price.